├── .browserslistrc
├── .editorconfig
├── .env.development
├── .env.production
├── .env.production.sit
├── .env.production.uat
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── LICENSE
├── README.md
├── babel.config.js
├── docker
├── Dockerfile
├── docker-compose.yaml
└── pig-ui.conf
├── docs
└── screen
│ ├── pig-home.png
│ ├── pig-login.png
│ └── pig-menus.png
├── package.json
├── public
├── cdn
│ ├── animate
│ │ └── 3.5.2
│ │ │ └── animate.css
│ ├── avue
│ │ └── avue.css
│ └── store
│ │ └── 1.3.20
│ │ └── store.js
├── favicon.ico
├── img
│ └── logo.png
├── index.html
└── svg
│ └── loading-spin.svg
├── src
├── App.vue
├── api
│ ├── admin
│ │ ├── client.js
│ │ ├── dept.js
│ │ ├── dict.js
│ │ ├── log.js
│ │ ├── menu.js
│ │ ├── role.js
│ │ ├── token.js
│ │ └── user.js
│ ├── gen
│ │ ├── form.js
│ │ └── gen.js
│ └── login.js
├── background.js
├── components
│ ├── basic-container
│ │ └── main.vue
│ ├── editor
│ │ ├── LICENSE
│ │ └── index.vue
│ ├── error-page
│ │ ├── 403.vue
│ │ ├── 404.vue
│ │ └── 500.vue
│ └── iframe
│ │ └── main.vue
├── config
│ └── env.js
├── const
│ ├── crud
│ │ ├── admin
│ │ │ ├── client.js
│ │ │ ├── dict.js
│ │ │ ├── log.js
│ │ │ ├── role.js
│ │ │ ├── token.js
│ │ │ └── user.js
│ │ └── gen
│ │ │ ├── form.js
│ │ │ └── gen.js
│ ├── errorCode.js
│ ├── iconList.js
│ └── website.js
├── error.js
├── filters
│ └── index.js
├── main.js
├── mixins
│ └── color.js
├── page
│ ├── index
│ │ ├── index.vue
│ │ ├── layout.vue
│ │ ├── logo.vue
│ │ ├── sidebar
│ │ │ ├── config.js
│ │ │ ├── index.vue
│ │ │ └── sidebarItem.vue
│ │ ├── tags.vue
│ │ └── top
│ │ │ ├── index.vue
│ │ │ └── top-menu.vue
│ ├── login
│ │ ├── index.vue
│ │ └── userlogin.vue
│ └── wel.vue
├── permission.js
├── router
│ ├── avue-router.js
│ ├── axios.js
│ ├── page
│ │ └── index.js
│ ├── router.js
│ └── views
│ │ └── index.js
├── store
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── common.js
│ │ ├── tags.js
│ │ └── user.js
├── styles
│ ├── animate
│ │ └── vue-transition.scss
│ ├── common.scss
│ ├── element-ui.scss
│ ├── login.scss
│ ├── media.scss
│ ├── mixin.scss
│ ├── normalize.scss
│ ├── sidebar.scss
│ ├── tags.scss
│ ├── top.scss
│ └── variables.scss
├── util
│ ├── admin.js
│ ├── date.js
│ ├── store.js
│ ├── util.js
│ └── validate.js
└── views
│ ├── admin
│ ├── client
│ │ └── index.vue
│ ├── dept
│ │ └── index.vue
│ ├── dict
│ │ └── index.vue
│ ├── log
│ │ └── index.vue
│ ├── menu
│ │ ├── index.vue
│ │ └── menu-form.vue
│ ├── role
│ │ └── index.vue
│ ├── token
│ │ └── index.vue
│ └── user
│ │ ├── index.vue
│ │ └── info.vue
│ └── gen
│ ├── datasource.vue
│ ├── design.vue
│ ├── form.vue
│ ├── index.vue
│ └── preview.vue
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VUE_APP_NODE_ENV=dev
3 | VUE_APP_API_URL='http://pig-gateway:9999'
4 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_NODE_ENV=prod
3 | VUE_APP_API_URL='http://pig-gateway:9999'
4 |
--------------------------------------------------------------------------------
/.env.production.sit:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_NODE_ENV=prod:sit
3 | VUE_APP_API_URL='http://pig-gateway:9999'
4 |
--------------------------------------------------------------------------------
/.env.production.uat:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VUE_APP_NODE_ENV=prod:uat
3 | VUE_APP_API_URL='http://pig-gateway:9999'
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | "plugin:vue/essential"
8 | ],
9 | rules: {
10 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
11 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
12 | },
13 | parserOptions: {
14 | parser: 'babel-eslint'
15 | }
16 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /tests/e2e/videos/
6 | /tests/e2e/screenshots/
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw*
25 |
26 | # Lock File
27 | package-lock.json
28 | yarn.lock
29 |
30 | #Electron-builder output
31 | /dist_electron
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## pig-ui electron 版本
2 |
3 | 此项目是 [pig-ui](https://github.com/pig-mesh/pig-ui) 的`electron`移植版
4 |
5 |
6 | ### 开发环境
7 |
8 | 安装依赖
9 |
10 | ```shell script
11 | yarn
12 | ```
13 | 或者
14 | ```shell script
15 | npm i
16 | ```
17 |
18 | 修改`.env.development`文件中的`VUE_APP_API_URL`参数,它表示后端服务的地址。然后可以跑起来了:
19 |
20 | ```shell script
21 | yarn electron:dev
22 | ```
23 |
24 | > 启动过程可能有点慢,需要等一会。
25 |
26 |
27 | ### 打包
28 |
29 | 打包预设了3种环境:
30 |
31 | - 集成测试 `prod:sit`
32 | - 验收测试 `prod:uat`
33 | - 生产环境 `prod`
34 |
35 | 对应的配置文件`.env.development.sit`、.env.development.uat`、.env.development`,你需要修改里面的`VUE_APP_API_URL`参数,填上服务端地址。
36 |
37 | 根据你的需要进行打包:
38 |
39 | ```shell script
40 | yarn electron:build:sit
41 | yarn electron:build:uat
42 | yarn electron:build:prod
43 | ```
44 |
45 | ### 命令行参数
46 |
47 | `--url ${URL}` 以外部URL启动,比如 `pig-ui.exe --url https://pigx.pig4cloud.com/` 一般用于测试。
48 |
49 | ### 效果演示
50 |
51 | 
52 |
53 | 
54 |
55 | 
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx
2 |
3 | COPY ./dist /data
4 |
5 | RUN rm /etc/nginx/conf.d/default.conf
6 |
7 | ADD pig-ui.conf /etc/nginx/conf.d/
8 |
9 | RUN /bin/bash -c 'echo init ok'
--------------------------------------------------------------------------------
/docker/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | pig-ui:
4 | build:
5 | context: .
6 | restart: always
7 | container_name: pig-ui
8 | image: pig-ui
9 | networks:
10 | - pig_default
11 | external_links:
12 | - pig-gateway
13 | ports:
14 | - 80:80
15 |
16 | # 加入到后端网络, 默认为 pig_default | docker network ls 查看
17 | networks:
18 | pig_default:
19 | external: true
--------------------------------------------------------------------------------
/docker/pig-ui.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | # 打包好的dist目录文件,放置到这个目录下
6 | root /data/;
7 |
8 | location ~* ^/(code|auth|admin|gen) {
9 | proxy_pass http://pig-gateway:9999;
10 | #proxy_set_header Host $http_host;
11 | proxy_connect_timeout 15s;
12 | proxy_send_timeout 15s;
13 | proxy_read_timeout 15s;
14 | proxy_set_header X-Forwarded-Proto http;
15 | proxy_set_header X-Real-IP $remote_addr;
16 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
17 | }
18 | }
--------------------------------------------------------------------------------
/docs/screen/pig-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pig-mesh/pig-ui-electron/c4dc926b4cccf38aa588c7473da777ac85563443/docs/screen/pig-home.png
--------------------------------------------------------------------------------
/docs/screen/pig-login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pig-mesh/pig-ui-electron/c4dc926b4cccf38aa588c7473da777ac85563443/docs/screen/pig-login.png
--------------------------------------------------------------------------------
/docs/screen/pig-menus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pig-mesh/pig-ui-electron/c4dc926b4cccf38aa588c7473da777ac85563443/docs/screen/pig-menus.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pig-ui",
3 | "version": "3.2.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "vue-cli-service build",
7 | "lint": "vue-cli-service lint",
8 | "dev": "vue-cli-service serve",
9 | "electron:build:prod": "vue-cli-service electron:build --mode production",
10 | "electron:build:sit": "vue-cli-service electron:build --mode production.sit",
11 | "electron:build:uat": "vue-cli-service electron:build --mode production.uat",
12 | "electron:dev": "vue-cli-service electron:serve",
13 | "postinstall": "electron-builder install-app-deps",
14 | "postuninstall": "electron-builder install-app-deps",
15 | "pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org "
16 | },
17 | "main": "background.js",
18 | "dependencies": {
19 | "@riophae/vue-treeselect": "^0.4.0",
20 | "@smallwei/avue": "2.6.18",
21 | "@sscfaith/avue-form-design": "1.3.12",
22 | "avue-plugin-ueditor": "^0.0.6",
23 | "axios": "0.19.0",
24 | "babel-polyfill": "^6.26.0",
25 | "classlist-polyfill": "^1.2.0",
26 | "codemirror": "^5.58.1",
27 | "crypto-js": "^3.1.9-1",
28 | "element-ui": "^2.13.2",
29 | "nprogress": "^0.2.0",
30 | "script-loader": "^0.7.2",
31 | "vue": "^2.6.10",
32 | "vue-axios": "^2.1.4",
33 | "vue-router": "^3.1.3",
34 | "vuex": "^3.2.0"
35 | },
36 | "devDependencies": {
37 | "@vue/cli-plugin-babel": "^3.12.0",
38 | "@vue/cli-service": "^3.12.0",
39 | "chai": "^4.2.0",
40 | "electron": "^9.0.0",
41 | "electron-devtools-installer": "^3.1.0",
42 | "node-sass": "^4.12.0",
43 | "sass-loader": "^8.0.0",
44 | "vue-cli-plugin-electron-builder": "~2.0.0-rc.4",
45 | "vue-template-compiler": "^2.6.10"
46 | },
47 | "lint-staged": {
48 | "*.js": [
49 | "vue-cli-service lint",
50 | "git add"
51 | ],
52 | "*.vue": [
53 | "vue-cli-service lint",
54 | "git add"
55 | ]
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/public/cdn/avue/avue.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #app {
4 | height: 100%;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | .avue-home {
10 | background-color: #303133;
11 | height: 100%;
12 | display: flex;
13 | flex-direction: column;
14 | }
15 |
16 | .avue-home__main {
17 | user-select: none;
18 | width: 100%;
19 | flex-grow: 1;
20 | display: flex;
21 | justify-content: center;
22 | align-items: center;
23 | flex-direction: column;
24 | }
25 |
26 | .avue-home__footer {
27 | width: 100%;
28 | flex-grow: 0;
29 | text-align: center;
30 | padding: 1em 0;
31 | }
32 |
33 | .avue-home__footer > a {
34 | font-size: 12px;
35 | color: #ABABAB;
36 | text-decoration: none;
37 | }
38 |
39 | .avue-home__loading {
40 | height: 32px;
41 | width: 32px;
42 | margin-bottom: 20px;
43 | }
44 |
45 | .avue-home__title {
46 | color: #FFF;
47 | font-size: 14px;
48 | margin-bottom: 10px;
49 | }
50 |
51 | .avue-home__sub-title {
52 | color: #ABABAB;
53 | font-size: 12px;
54 | }
55 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pig-mesh/pig-ui-electron/c4dc926b4cccf38aa588c7473da777ac85563443/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pig-mesh/pig-ui-electron/c4dc926b4cccf38aa588c7473da777ac85563443/public/img/logo.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | pig微服务快速开发框架
16 |
17 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |

32 |
33 | 正在加载资源
34 |
35 |
36 | 初次加载资源可能需要较多时间 请耐心等待
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/public/svg/loading-spin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
20 |
27 |
--------------------------------------------------------------------------------
/src/api/admin/client.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList (query) {
21 | return request({
22 | url: '/admin/client/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function addObj (obj) {
29 | return request({
30 | url: '/admin/client',
31 | method: 'post',
32 | data: obj
33 | })
34 | }
35 |
36 | export function getObj (id) {
37 | return request({
38 | url: '/admin/client/' + id,
39 | method: 'get'
40 | })
41 | }
42 |
43 | export function delObj (id) {
44 | return request({
45 | url: '/admin/client/' + id,
46 | method: 'delete'
47 | })
48 | }
49 |
50 | export function putObj (obj) {
51 | return request({
52 | url: '/admin/client',
53 | method: 'put',
54 | data: obj
55 | })
56 | }
57 |
--------------------------------------------------------------------------------
/src/api/admin/dept.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchDeptTree (query) {
21 | return request({
22 | url: '/admin/dept/user-tree',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function fetchTree (query) {
29 | return request({
30 | url: '/admin/dept/tree',
31 | method: 'get',
32 | params: query
33 | })
34 | }
35 |
36 | export function addObj (obj) {
37 | return request({
38 | url: '/admin/dept',
39 | method: 'post',
40 | data: obj
41 | })
42 | }
43 |
44 | export function getObj (id) {
45 | return request({
46 | url: '/admin/dept/' + id,
47 | method: 'get'
48 | })
49 | }
50 |
51 | export function delObj (id) {
52 | return request({
53 | url: '/admin/dept/' + id,
54 | method: 'delete'
55 | })
56 | }
57 |
58 | export function putObj (obj) {
59 | return request({
60 | url: '/admin/dept',
61 | method: 'put',
62 | data: obj
63 | })
64 | }
65 |
66 | export function getdetails (obj) {
67 | return request({
68 | url: '/admin/dept/details/' + obj,
69 | method: 'get'
70 | })
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/api/admin/dict.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList(query) {
21 | return request({
22 | url: '/admin/dict/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function fetchItemList(query) {
29 | return request({
30 | url: '/admin/dict/item/page',
31 | method: 'get',
32 | params: query
33 | })
34 | }
35 |
36 | export function addItemObj(obj) {
37 | return request({
38 | url: '/admin/dict/item',
39 | method: 'post',
40 | data: obj
41 | })
42 | }
43 |
44 | export function getItemObj(id) {
45 | return request({
46 | url: '/admin/dict/item/' + id,
47 | method: 'get'
48 | })
49 | }
50 |
51 | export function delItemObj(id) {
52 | return request({
53 | url: '/admin/dict/item/' + id,
54 | method: 'delete'
55 | })
56 | }
57 |
58 | export function putItemObj(obj) {
59 | return request({
60 | url: '/admin/dict/item',
61 | method: 'put',
62 | data: obj
63 | })
64 | }
65 |
66 | export function addObj(obj) {
67 | return request({
68 | url: '/admin/dict/',
69 | method: 'post',
70 | data: obj
71 | })
72 | }
73 |
74 | export function getObj(id) {
75 | return request({
76 | url: '/admin/dict/' + id,
77 | method: 'get'
78 | })
79 | }
80 |
81 | export function delObj(row) {
82 | return request({
83 | url: '/admin/dict/' + row.id,
84 | method: 'delete'
85 | })
86 | }
87 |
88 | export function putObj(obj) {
89 | return request({
90 | url: '/admin/dict/',
91 | method: 'put',
92 | data: obj
93 | })
94 | }
95 |
96 | export function remote(type) {
97 | return request({
98 | url: '/admin/dict/type/' + type,
99 | method: 'get'
100 | })
101 | }
102 |
--------------------------------------------------------------------------------
/src/api/admin/log.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList (query) {
21 | return request({
22 | url: '/admin/log/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function delObj (id) {
29 | return request({
30 | url: '/admin/log/' + id,
31 | method: 'delete'
32 | })
33 | }
34 |
35 | export function addObj (obj) {
36 | return request({
37 | url: '/admin/log',
38 | method: 'post',
39 | data: obj
40 | })
41 | }
42 |
43 | export function getObj (id) {
44 | return request({
45 | url: '/admin/log/' + id,
46 | method: 'get'
47 | })
48 | }
49 |
50 | export function putObj (obj) {
51 | return request({
52 | url: '/admin/log',
53 | method: 'put',
54 | data: obj
55 | })
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/api/admin/menu.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function getMenu(id) {
21 | return request({
22 | url: '/admin/menu',
23 | params: {parentId: id},
24 | method: 'get'
25 | })
26 | }
27 |
28 | export function fetchMenuTree(lazy, parentId) {
29 | return request({
30 | url: '/admin/menu/tree',
31 | method: 'get',
32 | params: {lazy: lazy, parentId: parentId}
33 | })
34 | }
35 |
36 | export function addObj(obj) {
37 | return request({
38 | url: '/admin/menu',
39 | method: 'post',
40 | data: obj
41 | })
42 | }
43 |
44 | export function getObj(id) {
45 | return request({
46 | url: '/admin/menu/' + id,
47 | method: 'get'
48 | })
49 | }
50 |
51 | export function delObj(id) {
52 | return request({
53 | url: '/admin/menu/' + id,
54 | method: 'delete'
55 | })
56 | }
57 |
58 | export function putObj(obj) {
59 | return request({
60 | url: '/admin/menu',
61 | method: 'put',
62 | data: obj
63 | })
64 | }
65 |
--------------------------------------------------------------------------------
/src/api/admin/role.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList (query) {
21 | return request({
22 | url: '/admin/role/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function deptRoleList () {
29 | return request({
30 | url: '/admin/role/list',
31 | method: 'get'
32 | })
33 | }
34 |
35 | export function getObj (id) {
36 | return request({
37 | url: '/admin/role/' + id,
38 | method: 'get'
39 | })
40 | }
41 |
42 | export function addObj (obj) {
43 | return request({
44 | url: '/admin/role',
45 | method: 'post',
46 | data: obj
47 | })
48 | }
49 |
50 | export function putObj (obj) {
51 | return request({
52 | url: '/admin/role',
53 | method: 'put',
54 | data: obj
55 | })
56 | }
57 |
58 | export function delObj (id) {
59 | return request({
60 | url: '/admin/role/' + id,
61 | method: 'delete'
62 | })
63 | }
64 |
65 | export function permissionUpd (roleId, menuIds) {
66 | return request({
67 | url: '/admin/role/menu',
68 | method: 'put',
69 | data: {
70 | roleId: roleId,
71 | menuIds: menuIds
72 | }
73 | })
74 | }
75 |
76 | export function fetchRoleTree (roleName) {
77 | return request({
78 | url: '/admin/menu/tree/' + roleName,
79 | method: 'get'
80 | })
81 | }
82 |
--------------------------------------------------------------------------------
/src/api/admin/token.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList (query) {
21 | return request({
22 | url: '/admin/token/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function delObj (token) {
29 | return request({
30 | url: '/admin/token/' + token,
31 | method: 'delete'
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/src/api/admin/user.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList (query) {
21 | return request({
22 | url: '/admin/user/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function addObj (obj) {
29 | return request({
30 | url: '/admin/user',
31 | method: 'post',
32 | data: obj
33 | })
34 | }
35 |
36 | export function getObj (id) {
37 | return request({
38 | url: '/admin/user/' + id,
39 | method: 'get'
40 | })
41 | }
42 |
43 | export function delObj (id) {
44 | return request({
45 | url: '/admin/user/' + id,
46 | method: 'delete'
47 | })
48 | }
49 |
50 | export function putObj (obj) {
51 | return request({
52 | url: '/admin/user',
53 | method: 'put',
54 | data: obj
55 | })
56 | }
57 |
58 | export function getDetails (obj) {
59 | return request({
60 | url: '/admin/user/details/' + obj,
61 | method: 'get'
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/src/api/gen/form.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, test All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: test
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList(query) {
21 | return request({
22 | url: '/gen/form/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function addObj(obj) {
29 | return request({
30 | url: '/gen/form',
31 | method: 'post',
32 | data: obj
33 | })
34 | }
35 |
36 | export function getObj(id) {
37 | return request({
38 | url: '/gen/form/' + id,
39 | method: 'get'
40 | })
41 | }
42 |
43 | export function delObj(id) {
44 | return request({
45 | url: '/gen/form/' + id,
46 | method: 'delete'
47 | })
48 | }
49 |
50 | export function putObj(obj) {
51 | return request({
52 | url: '/gen/form',
53 | method: 'put',
54 | data: obj
55 | })
56 | }
57 |
--------------------------------------------------------------------------------
/src/api/gen/gen.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, test All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng
16 | */
17 |
18 | import request from '@/router/axios'
19 |
20 | export function fetchList(query) {
21 | return request({
22 | url: '/gen/generator/page',
23 | method: 'get',
24 | params: query
25 | })
26 | }
27 |
28 | export function preview(table) {
29 | return request({
30 | url: '/gen/generator/preview',
31 | method: 'get',
32 | params: table
33 | })
34 | }
35 |
36 | export function fetchDsList(query) {
37 | return request({
38 | url: '/gen/dsconf/page',
39 | method: 'get',
40 | params: query
41 | })
42 | }
43 |
44 | export function fetchSelectDsList() {
45 | return request({
46 | url: '/gen/dsconf/list',
47 | method: 'get'
48 | })
49 | }
50 |
51 | export function addObj(obj) {
52 | return request({
53 | url: '/gen/dsconf/',
54 | method: 'post',
55 | data: obj
56 | })
57 | }
58 |
59 | export function getObj(id) {
60 | return request({
61 | url: '/gen/dsconf/' + id,
62 | method: 'get'
63 | })
64 | }
65 |
66 | export function delObj(id) {
67 | return request({
68 | url: '/gen/dsconf/' + id,
69 | method: 'delete'
70 | })
71 | }
72 |
73 | export function putObj(obj) {
74 | return request({
75 | url: '/gen/dsconf/',
76 | method: 'put',
77 | data: obj
78 | })
79 | }
80 |
81 | export function handleDown(table) {
82 | return request({
83 | url: '/gen/generator/code',
84 | method: 'post',
85 | data: table,
86 | responseType: 'arraybuffer'
87 | }).then((response) => { // 处理返回的文件流
88 | const blob = new Blob([response.data], { type: 'application/zip' })
89 | const filename = table.tableName + '.zip'
90 | const link = document.createElement('a')
91 | link.href = URL.createObjectURL(blob)
92 | link.download = filename
93 | document.body.appendChild(link)
94 | link.click()
95 | window.setTimeout(function () {
96 | URL.revokeObjectURL(blob)
97 | document.body.removeChild(link)
98 | }, 0)
99 | })
100 | }
101 |
102 |
103 | export function getForm(tableName, dsName) {
104 | return request({
105 | url: '/gen/form/info',
106 | params: { tableName: tableName, dsName: dsName },
107 | method: 'get'
108 | })
109 | }
110 |
111 | export function postForm(formInfo, tableName, dsId) {
112 | return request({
113 | url: '/gen/form/',
114 | method: 'post',
115 | data: Object.assign({ formInfo, tableName, dsId })
116 | })
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/src/api/login.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 | import request from '@/router/axios'
18 | const scope = 'server'
19 |
20 | export const loginByUsername = (username, password, code, randomStr) => {
21 | const grant_type = 'password'
22 |
23 | return request({
24 | url: '/auth/oauth/token',
25 | headers: {
26 | isToken:false,
27 | 'Authorization': 'Basic cGlnOnBpZw=='
28 | },
29 | method: 'post',
30 | params: { username, password, randomStr, code, grant_type, scope }
31 | })
32 | }
33 |
34 | export const refreshToken = (refresh_token) => {
35 | const grant_type = 'refresh_token'
36 | return request({
37 | url: '/auth/oauth/token',
38 | headers: {
39 | 'isToken': false,
40 | 'Authorization': 'Basic cGlnOnBpZw==',
41 | },
42 | method: 'post',
43 | params: { refresh_token, grant_type, scope }
44 | })
45 | }
46 |
47 | export const getUserInfo = () => {
48 | return request({
49 | url: '/admin/user/info',
50 | method: 'get'
51 | })
52 | }
53 |
54 | export const logout = () => {
55 | return request({
56 | url: '/auth/token/logout',
57 | method: 'delete'
58 | })
59 | }
60 |
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import { app, protocol, BrowserWindow } from 'electron'
4 | import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
5 | import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
6 | const isDevelopment = process.env.NODE_ENV !== 'production'
7 | const parseArgs = require('minimist')
8 | const args = parseArgs(process.argv.slice(1), {string: ['url']})
9 | // Keep a global reference of the window object, if you don't, the window will
10 | // be closed automatically when the JavaScript object is garbage collected.
11 | let win
12 |
13 | // Scheme must be registered before the app is ready
14 | protocol.registerSchemesAsPrivileged([
15 | { scheme: 'app', privileges: { secure: true, standard: true } }
16 | ])
17 |
18 | function createWindow() {
19 | // Create the browser window.
20 | win = new BrowserWindow({
21 | width: 1440,
22 | height: 900,
23 | webPreferences: {
24 | // Use pluginOptions.nodeIntegration, leave this alone
25 | // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
26 | nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
27 | webSecurity: false
28 | }
29 | })
30 | let url = args.url
31 | if (process.env.WEBPACK_DEV_SERVER_URL) {
32 | // Load the url of the dev server if in development mode
33 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
34 | if (!process.env.IS_TEST) win.webContents.openDevTools()
35 | } else {
36 | if(url) {
37 | console.log(`load form url ${url}`)
38 | win.loadURL(url)
39 | } else {
40 | createProtocol('app')
41 | // Load the index.html when not in development
42 | win.loadURL('app://./index.html')
43 | }
44 | }
45 |
46 | win.on('closed', () => {
47 | win = null
48 | })
49 | }
50 |
51 | // Quit when all windows are closed.
52 | app.on('window-all-closed', () => {
53 | // On macOS it is common for applications and their menu bar
54 | // to stay active until the user quits explicitly with Cmd + Q
55 | if (process.platform !== 'darwin') {
56 | app.quit()
57 | }
58 | })
59 |
60 | app.on('activate', () => {
61 | // On macOS it's common to re-create a window in the app when the
62 | // dock icon is clicked and there are no other windows open.
63 | if (win === null) {
64 | createWindow()
65 | }
66 | })
67 |
68 | // This method will be called when Electron has finished
69 | // initialization and is ready to create browser windows.
70 | // Some APIs can only be used after this event occurs.
71 | app.on('ready', async () => {
72 | if (isDevelopment && !process.env.IS_TEST) {
73 | // Install Vue Devtools
74 | try {
75 | await installExtension(VUEJS_DEVTOOLS)
76 | } catch (e) {
77 | console.error('Vue Devtools failed to install:', e.toString())
78 | }
79 | }
80 | createWindow()
81 | })
82 |
83 | // Exit cleanly on request from parent process in development mode.
84 | if (isDevelopment) {
85 | if (process.platform === 'win32') {
86 | process.on('message', (data) => {
87 | if (data === 'graceful-exit') {
88 | app.quit()
89 | }
90 | })
91 | } else {
92 | process.on('SIGTERM', () => {
93 | app.quit()
94 | })
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/components/basic-container/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
21 |
22 |
41 |
--------------------------------------------------------------------------------
/src/components/editor/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
62 |
63 |
79 |
--------------------------------------------------------------------------------
/src/components/error-page/403.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 4
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | You don't have permission
14 |
15 | 返回首页
16 | 返回上一页
17 |
18 |
19 |
20 |
21 |
22 |
23 |
38 |
130 |
--------------------------------------------------------------------------------
/src/components/error-page/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 4
6 | 04
7 | YOU LOOK LOST
8 |
9 | 返回首页
10 | 返回上一页
11 |
12 |
13 |
14 |
15 |
16 |
17 |
32 |
92 |
--------------------------------------------------------------------------------
/src/components/error-page/500.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 5
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Oops! the server is wrong
15 |
16 | 返回首页
17 | 返回上一页
18 |
19 |
20 |
21 |
22 |
23 |
24 |
39 |
112 |
113 |
--------------------------------------------------------------------------------
/src/components/iframe/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
12 |
13 |
14 |
15 |
16 |
120 |
121 |
--------------------------------------------------------------------------------
/src/config/env.js:
--------------------------------------------------------------------------------
1 | // 配置编译环境和线上环境之间的切换
2 |
3 | const env = process.env
4 | const baseUrl = env.VUE_APP_API_URL
5 | // 图表库为avue和pig2套地址
6 | const iconfontVersion = ['567566_qo5lxgtishg', '667895_v7uduh4zui']
7 | const iconfontUrl = `https://at.alicdn.com/t/font_$key.css`
8 | const codeUrl = `${env.VUE_APP_API_URL}/code`
9 | console.log(env)
10 | export {
11 | baseUrl,
12 | iconfontUrl,
13 | iconfontVersion,
14 | codeUrl,
15 | env
16 | }
17 |
--------------------------------------------------------------------------------
/src/const/crud/admin/client.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | import {getObj} from '@/api/admin/client'
19 |
20 | const DIC = {
21 | vaild: [{
22 | label: '否',
23 | value: 'false'
24 | }, {
25 | label: '是',
26 | value: 'true'
27 | }]
28 | }
29 |
30 | var validateClient = (rule, value, callback) => {
31 | getObj(value).then(response => {
32 | if (window.boxType === 'edit') {
33 | return callback()
34 | }
35 | const result = response.data.data
36 | if (result.length !== 0) {
37 | callback(new Error('客户端已存在'))
38 | } else {
39 | callback()
40 | }
41 | })
42 | }
43 |
44 | export const tableOption = {
45 | border: true,
46 | index: true,
47 | indexLabel: '序号',
48 | stripe: true,
49 | menuAlign: 'center',
50 | searchMenuSpan: 6,
51 | align: 'center',
52 | column: [{
53 | width: 150,
54 | label: '编号',
55 | prop: 'clientId',
56 | align: 'center',
57 | sortable: true,
58 | rules: [{
59 | required: true,
60 | message: '请输入clientId',
61 | trigger: 'blur'
62 | }, {validator: validateClient, trigger: 'blur'}]
63 | }, {
64 | label: '密钥',
65 | prop: 'clientSecret',
66 | align: 'center',
67 | sortable: true,
68 | overHidden: true,
69 | width: 120,
70 | rules: [{
71 | required: true,
72 | message: '请输入clientSecret',
73 | trigger: 'blur'
74 | }]
75 | }, {
76 | label: '域',
77 | prop: 'scope',
78 | align: 'center',
79 | rules: [{
80 | required: true,
81 | message: '请输入scope',
82 | trigger: 'blur'
83 | }]
84 | }, {
85 | label: '授权模式',
86 | prop: 'authorizedGrantTypes',
87 | align: 'center',
88 | overHidden: true,
89 | rules: [{
90 | required: true,
91 | message: '请输入授权模式',
92 | trigger: 'blur'
93 | }]
94 | }, {
95 | label: '回调地址',
96 | prop: 'webServerRedirectUri',
97 | align: 'center',
98 | hide: true
99 | }, {
100 | label: '权限',
101 | prop: 'authorities',
102 | align: 'center',
103 | hide: true
104 | }, {
105 | label: '自动放行',
106 | prop: 'autoapprove',
107 | align: 'center',
108 | type: 'radio',
109 | border: true,
110 | dicData: DIC.vaild,
111 | rules: [{
112 | required: true,
113 | message: '请选择是否放行',
114 | trigger: 'blur'
115 | }]
116 | }, {
117 | label: '令牌时效',
118 | prop: 'accessTokenValidity',
119 | align: 'center',
120 | }, {
121 | label: '刷新时效',
122 | prop: 'refreshTokenValidity',
123 | align: 'center',
124 | }, {
125 | label: '扩展信息',
126 | prop: 'additionalInformation',
127 | align: 'center',
128 | hide: true
129 | }, {
130 | label: '资源ID',
131 | prop: 'resourceIds',
132 | align: 'center',
133 | hide: true
134 | }]
135 | }
136 |
--------------------------------------------------------------------------------
/src/const/crud/admin/dict.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 | export const tableOption = {
18 | border: true,
19 | index: true,
20 | indexLabel: '序号',
21 | stripe: true,
22 | menuAlign: 'center',
23 | align: 'center',
24 | refreshBtn: false,
25 | showClomnuBtn: false,
26 | searchMenuSpan: 6,
27 | searchSize: 'mini',
28 | column: [{
29 | label: '类型',
30 | prop: 'type',
31 | 'search': true,
32 | editDisabled: true,
33 | rules: [{
34 | required: true,
35 | message: '请输入字典类型',
36 | trigger: 'blur'
37 | }]
38 | }, {
39 | label: '描述',
40 | prop: 'description',
41 | rules: [{
42 | required: true,
43 | message: '请输入字典描述',
44 | trigger: 'blur'
45 | }]
46 | }, {
47 | label: '字典类型',
48 | prop: 'system',
49 | type: 'select',
50 | dicUrl: '/admin/dict/type/dict_type',
51 | rules: [{
52 | required: true,
53 | message: '请输入字典类型',
54 | trigger: 'blur'
55 | }],
56 | search: true
57 | }, {
58 | label: '备注信息',
59 | prop: 'remarks'
60 | }, {
61 | width: 150,
62 | label: '创建时间',
63 | prop: 'createTime',
64 | type: 'datetime',
65 | addDisplay: false,
66 | editDisabled: true,
67 | format: 'yyyy-MM-dd HH:mm',
68 | valueFormat: 'yyyy-MM-dd HH:mm:ss'
69 | }]
70 | }
71 |
72 | export const tableDictItemOption = {
73 | border: true,
74 | index: true,
75 | indexLabel: '序号',
76 | stripe: true,
77 | menuAlign: 'center',
78 | align: 'center',
79 | refreshBtn: false,
80 | showClomnuBtn: false,
81 | searchSize: 'mini',
82 | column: [{
83 | label: '类型',
84 | prop: 'type',
85 | addDisabled: true,
86 | editDisabled: true
87 | }, {
88 | width: 150,
89 | label: '数据值',
90 | prop: 'value',
91 | rules: [{
92 | required: true,
93 | message: '请输入数据值',
94 | trigger: 'blur'
95 | }]
96 | }, {
97 | label: '标签名',
98 | prop: 'label',
99 | rules: [{
100 | required: true,
101 | message: '请输入标签名',
102 | trigger: 'blur'
103 | }]
104 | }, {
105 | label: '描述',
106 | prop: 'description',
107 | rules: [{
108 | required: true,
109 | message: '请输入字典描述',
110 | trigger: 'blur'
111 | }]
112 | }, {
113 | label: '排序',
114 | prop: 'sort',
115 | type: 'number',
116 | rules: [{
117 | required: true,
118 | message: '请输入排序',
119 | trigger: 'blur'
120 | }]
121 | }, {
122 | label: '备注信息',
123 | prop: 'remarks'
124 | }]
125 | }
126 |
--------------------------------------------------------------------------------
/src/const/crud/admin/log.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 | export const tableOption = {
18 | border: true,
19 | index: true,
20 | indexLabel: '序号',
21 | stripe: true,
22 | menuAlign: 'center',
23 | menuWidth: 150,
24 | align: 'center',
25 | refreshBtn: true,
26 | searchMenuSpan: 6,
27 | showClomnuBtn: false,
28 | searchSize: 'mini',
29 | addBtn: false,
30 | editBtn: false,
31 | viewBtn: true,
32 | props: {
33 | label: 'label',
34 | value: 'value'
35 | },
36 | column: [{
37 | label: '类型',
38 | prop: 'type',
39 | type: 'select',
40 | dicUrl: '/admin/dict/type/log_type',
41 | search: true
42 | }, {
43 | label: '标题',
44 | prop: 'title'
45 | }, {
46 | label: 'IP地址',
47 | prop: 'remoteAddr'
48 | }, {
49 | label: '请求方式',
50 | prop: 'method'
51 | }, {
52 | label: '客户端',
53 | prop: 'serviceId'
54 | }, {
55 | width: 80,
56 | label: '请求时间',
57 | prop: 'time'
58 | }, {
59 | width: 150,
60 | label: '创建时间',
61 | prop: 'createTime',
62 | type: 'datetime',
63 | format: 'yyyy-MM-dd HH:mm',
64 | valueFormat: 'yyyy-MM-dd HH:mm:ss',
65 | search: true,
66 | searchRange: true
67 | }, {
68 | width: 180,
69 | label: '异常日志',
70 | prop: 'exception',
71 | hide: true
72 | }]
73 | }
74 |
--------------------------------------------------------------------------------
/src/const/crud/admin/role.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 | export const tableOption = {
18 | border: true,
19 | index: true,
20 | indexLabel: '序号',
21 | stripe: true,
22 | menuAlign: 'center',
23 | editBtn: false,
24 | delBtn: false,
25 | searchMenuSpan: 6,
26 | align: 'center',
27 | addBtn: false,
28 | viewBtn:true,
29 | column: [{
30 | label: '角色名称',
31 | prop: 'roleName',
32 | span: 24,
33 | rules: [{
34 | required: true,
35 | message: '角色名称不能为空',
36 | trigger: 'blur'
37 | },
38 | {
39 | min: 3,
40 | max: 20,
41 | message: '长度在 3 到 20 个字符',
42 | trigger: 'blur'
43 | }]
44 | }, {
45 | width: 120,
46 | label: '角色标识',
47 | prop: 'roleCode',
48 | span: 24,
49 | editDisabled: true,
50 | rules: [{
51 | required: true,
52 | message: '角色标识不能为空',
53 | trigger: 'blur'
54 | },
55 | {
56 | min: 3,
57 | max: 20,
58 | message: '长度在 3 到 20 个字符',
59 | trigger: 'blur'
60 | }
61 | ]
62 | }, {
63 | width: 150,
64 | label: '角色描述',
65 | prop: 'roleDesc',
66 | overHidden: true,
67 | span: 24,
68 | rules: [{
69 | required: true,
70 | message: '角色描述不能为空',
71 | trigger: 'blur'
72 | },
73 | {
74 | min: 3,
75 | max: 100,
76 | message: '长度在 3 到 100 个字符',
77 | trigger: 'blur'
78 | }]
79 | }, {
80 | label: '创建时间',
81 | prop: 'createTime',
82 | type: 'datetime',
83 | format: 'yyyy-MM-dd HH:mm',
84 | valueFormat: 'yyyy-MM-dd HH:mm:ss',
85 | editDisplay: false,
86 | addDisplay: false,
87 | span: 24
88 | }]
89 | }
90 |
--------------------------------------------------------------------------------
/src/const/crud/admin/token.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 |
18 | export const tableOption = {
19 | border: true,
20 | index: true,
21 | indexLabel: '序号',
22 | stripe: true,
23 | menuAlign: 'center',
24 | align: 'center',
25 | searchMenuSpan: 6,
26 | viewBtn: true,
27 | addBtn: false,
28 | editBtn: false,
29 | column: [{
30 | label: '用户ID',
31 | prop: 'user_id',
32 | align: 'center'
33 | }, {
34 | label: '用户名',
35 | prop: 'username',
36 | align: 'center'
37 | }, {
38 | label: '令牌',
39 | prop: 'access_token',
40 | align: 'center',
41 | overHidden: true
42 | }, {
43 | label: '类型',
44 | prop: 'token_type',
45 | align: 'center'
46 | }, {
47 | label: '过期时间',
48 | prop: 'expires_in',
49 | align: 'center'
50 | }]
51 | }
52 |
--------------------------------------------------------------------------------
/src/const/crud/admin/user.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, lengleng All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: lengleng (wangiegie@gmail.com)
16 | */
17 | import {getDetails} from '@/api/admin/user'
18 |
19 | const validateUsername = (rule, value, callback) => {
20 | if (!value) {
21 | return callback(new Error('请输入用户名'))
22 | }
23 | getDetails(value).then(response => {
24 | if (window.boxType === 'edit') callback()
25 | let result = response.data.data
26 | if (result !== null) {
27 | callback(new Error('用户名已经存在'))
28 | } else {
29 | callback()
30 | }
31 | })
32 | }
33 |
34 | // 设置密码校验规则
35 | const checkPassword = (rule, value, callback) => {
36 | if (window.boxType === 'edit') {
37 | return callback()
38 | }
39 | if (!value) {
40 | callback(new Error('请输入密码'))
41 | } else {
42 | callback()
43 | }
44 | }
45 |
46 | // 设置手机号的验证规则
47 | const checkPhone = (rule, value, callback) => {
48 | if (!value) {
49 | callback(new Error('请输入联系方式'))
50 | } else {
51 | const reg = /^1[3|4|5|7|8][0-9]\d{8}$/
52 | if (reg.test(value)) {
53 | callback()
54 | } else {
55 | return callback(new Error('请输入正确的电话'))
56 | }
57 | }
58 | }
59 |
60 | export const tableOption = {
61 | border: true,
62 | index: true,
63 | indexLabel: '序号',
64 | stripe: true,
65 | menuAlign: 'center',
66 | searchMenuSpan: 6,
67 | editBtn: false,
68 | delBtn: false,
69 | align: 'center',
70 | addBtn: false,
71 | column: [{
72 | fixed: true,
73 | label: 'id',
74 | prop: 'userId',
75 | span: 24,
76 | hide: true,
77 | editDisplay: false,
78 | addDisplay: false
79 | }, {
80 | fixed: true,
81 | label: '用户名',
82 | prop: 'username',
83 | editDisabled: true,
84 | slot: true,
85 | search: true,
86 | span: 24,
87 | rules: [{
88 | required: true,
89 | message: '请输入用户名'
90 | },
91 | {
92 | min: 3,
93 | max: 20,
94 | message: '长度在 3 到 20 个字符',
95 | trigger: 'blur'
96 | },
97 | {validator: validateUsername, trigger: 'blur'}
98 | ]
99 | }, {
100 | label: '密码',
101 | prop: 'password',
102 | type: 'password',
103 | value: '',
104 | hide: true,
105 | span: 24,
106 | rules: [{validator: checkPassword, trigger: 'blur'}]
107 | }, {
108 | label: '所属部门',
109 | prop: 'deptId',
110 | formslot: true,
111 | slot: true,
112 | span: 24,
113 | hide: true,
114 | rules: [{
115 | required: true,
116 | message: '请选择部门',
117 | trigger: 'change'
118 | }]
119 | }, {
120 | label: '手机号',
121 | prop: 'phone',
122 | value: '',
123 | span: 24,
124 | rules: [{
125 | required: true,
126 | message: '手机号不能为空',
127 | trigger: 'blur'
128 | }, {
129 | validator: checkPhone,
130 | trigger: 'blur'
131 | }]
132 | }, {
133 | label: '角色',
134 | prop: 'role',
135 | formslot: true,
136 | slot: true,
137 | overHidden: true,
138 | span: 24,
139 | rules: [{
140 | required: true,
141 | message: '请选择角色',
142 | trigger: 'blur'
143 | }]
144 | }, {
145 | label: '部门',
146 | prop: 'deptName',
147 | overHidden: true,
148 | addDisplay: false,
149 | editDisplay: false,
150 | span: 24,
151 | }, {
152 | label: '状态',
153 | prop: 'lockFlag',
154 | type: 'radio',
155 | slot: true,
156 | border: true,
157 | span: 24,
158 | rules: [{
159 | required: true,
160 | message: '请选择状态',
161 | trigger: 'blur'
162 | }],
163 | dicData: [{
164 | label: '有效',
165 | value: '0'
166 | }, {
167 | label: '锁定',
168 | value: '9'
169 | }]
170 | }, {
171 | width: 120,
172 | label: '创建时间',
173 | prop: 'createTime',
174 | type: 'datetime',
175 | format: 'yyyy-MM-dd',
176 | editDisabled: true,
177 | addDisplay: false,
178 | span: 24
179 | }]
180 | }
181 |
--------------------------------------------------------------------------------
/src/const/crud/gen/form.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, test All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: test
16 | */
17 |
18 | export const tableOption = {
19 | border: true,
20 | index: true,
21 | indexLabel: '序号',
22 | stripe: true,
23 | menuAlign: 'center',
24 | align: 'center',
25 | viewBtn: true,
26 | editBtn: false,
27 | addBtn: false,
28 | searchMenuSpan: 6,
29 | column: [
30 | {
31 | label: 'ID',
32 | prop: 'id',
33 | hide: true,
34 | },
35 | {
36 | label: '表名称',
37 | prop: 'tableName'
38 | },
39 | {
40 | label: '创建时间',
41 | prop: 'createTime',
42 | type: 'datetime',
43 | format: 'yyyy-MM-dd HH:mm:ss',
44 | valueFormat: 'yyyy-MM-dd HH:mm:ss'
45 | },
46 | {
47 | label: '表单信息',
48 | prop: 'formInfo',
49 | overHidden: true,
50 | width: 500,
51 | type: 'textarea',
52 | minRows: 3,
53 | row: true,
54 | span: 24
55 | }
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/src/const/crud/gen/gen.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018-2025, test All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions are met:
6 | *
7 | * Redistributions of source code must retain the above copyright notice,
8 | * this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | * Neither the name of the pig4cloud.com developer nor the names of its
13 | * contributors may be used to endorse or promote products derived from
14 | * this software without specific prior written permission.
15 | * Author: test
16 | */
17 |
18 | /**
19 | *
20 | * @param {校验数据源名} rule
21 | * @param {*} value
22 | * @param {*} callback
23 | */
24 | var validateDsName = (rule, value, callback) => {
25 | var re = /(?=.*[a-z])(?=.*_)/;
26 | if (value && (!(re).test(value))) {
27 | callback(new Error('数据源名称不合法, 组名_数据源名形式'))
28 | } else {
29 | callback()
30 | }
31 | }
32 |
33 | export const tableOption = {
34 | selection: true,
35 | border: true,
36 | index: true,
37 | stripe: true,
38 | menuAlign: 'center',
39 | align: 'center',
40 | addBtn: false,
41 | editBtn: false,
42 | delBtn: false,
43 | searchMenuSpan: 6,
44 | column: [{
45 | label: '表名称',
46 | prop: 'tableName',
47 | align: 'center'
48 | }, {
49 | label: '表注释',
50 | prop: 'tableComment',
51 | align: 'center'
52 | }, {
53 | label: '表编码',
54 | prop: 'tableCollation',
55 | align: 'center'
56 | }, {
57 | label: '索引',
58 | prop: 'engine',
59 | align: 'center'
60 | }, {
61 | type: 'datetime',
62 | valueFormat: 'timestamp',
63 | format: 'yyyy-MM-dd hh:mm:ss',
64 | label: '创建时间',
65 | prop: 'createTime',
66 | align: 'center'
67 | }]
68 | }
69 |
70 | export const formOption = {
71 | submitBtn: false,
72 | emptyBtn: false,
73 | submitText: '生成',
74 | column: [
75 | {
76 | label: '表名称',
77 | prop: 'tableName',
78 | disabled: true
79 | }, {
80 | label: '包名',
81 | prop: 'packageName',
82 | placeholder: '可为空,加载系统默认配置'
83 | }, {
84 | label: '作者',
85 | prop: 'author',
86 | placeholder: '可为空,加载系统默认配置'
87 | }, {
88 | label: '模块',
89 | prop: 'moduleName',
90 | placeholder: '可为空,加载系统默认配置'
91 | }, {
92 | label: '表前缀',
93 | prop: 'tablePrefix',
94 | placeholder: '可为空,加载系统默认配置'
95 | }, {
96 | label: '注释',
97 | prop: 'comments',
98 | placeholder: '可为空,加载表备注'
99 | }
100 | ]
101 | }
102 | export const formBatchOption = {
103 | submitText: '生成',
104 | column: [
105 | {
106 | label: '表名称',
107 | prop: 'tableName',
108 | disabled: true,
109 | minRows: 2,
110 | type: 'textarea',
111 | row: true,
112 | span: 24
113 | },
114 | {
115 | label: '包名',
116 | prop: 'packageName',
117 | placeholder: '可为空,加载系统默认配置'
118 | }, {
119 | label: '作者',
120 | prop: 'author',
121 | placeholder: '可为空,加载系统默认配置'
122 | }, {
123 | label: '模块',
124 | prop: 'moduleName',
125 | placeholder: '可为空,加载系统默认配置'
126 | }, {
127 | label: '注释',
128 | prop: 'comments',
129 | placeholder: '可为空,加载表备注'
130 | }
131 | ]
132 | }
133 |
134 | export const tableDsOption = {
135 | border: true,
136 | index: true,
137 | indexLabel: '序号',
138 | stripe: true,
139 | menuAlign: 'center',
140 | align: 'center',
141 | column: [
142 | {
143 | label: '主键',
144 | prop: 'id',
145 | hide: true,
146 | addDisplay: false,
147 | editDisplay: false
148 | },
149 | {
150 | label: '名称',
151 | prop: 'name',
152 | rules: [
153 | { required: true, message: '请输入名称', trigger: 'blur' },
154 | { max: 32, message: '长度在 32 个字符', trigger: 'blur' },
155 | { validator: validateDsName, trigger: 'blur' }
156 | ]
157 | },
158 | {
159 | label: 'jdbcUrl',
160 | prop: 'url',
161 | type: 'textarea',
162 | span: 24,
163 | row: true,
164 | minRows: 2,
165 | overHidden: true,
166 | rules: [
167 | { required: true, message: '请输入jdbcUrl', trigger: 'blur' }
168 | ]
169 | },
170 | {
171 | label: '用户名',
172 | prop: 'username',
173 | rules: [
174 | { required: true, message: '请输入用户名', trigger: 'blur' },
175 | { max: 32, message: '长度在 32 个字符', trigger: 'blur' }
176 | ]
177 | },
178 | {
179 | label: '密码',
180 | prop: 'password',
181 | rules: [
182 | { required: true, message: '请输入密码', trigger: 'blur' },
183 | { max: 32, message: '长度在 32 个字符', trigger: 'blur' }
184 | ]
185 | },
186 | {
187 | label: '创建时间',
188 | prop: 'createDate',
189 | addDisplay: false,
190 | editDisplay: false,
191 | overHidden: true
192 | },
193 | {
194 | label: '更新时间',
195 | prop: 'updateDate',
196 | overHidden: true,
197 | addDisplay: false,
198 | editDisplay: false
199 | }
200 | ]
201 | }
202 |
--------------------------------------------------------------------------------
/src/const/errorCode.js:
--------------------------------------------------------------------------------
1 | export default {
2 | '000': '操作太频繁,请勿重复请求',
3 | '401': '当前操作没有权限',
4 | '403': '当前操作没有权限',
5 | '404': '资源不存在',
6 | '417': '未绑定登录账号,请使用密码登录后绑定',
7 | '423': '演示环境不能操作,如需了解联系冷冷',
8 | '426': '用户名不存在或密码错误',
9 | '428': '验证码错误,请重新输入',
10 | '429': '请求过频繁',
11 | '479': '演示环境,没有权限操作',
12 | 'default': '系统未知错误,请反馈给管理员'
13 | }
14 |
--------------------------------------------------------------------------------
/src/const/iconList.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | label: '阿里云图标',
4 | list: [
5 | 'icon-quanxianguanli',
6 | 'icon-yonghuguanli',
7 | 'icon-jiaoseguanli',
8 | 'icon-web-icon-',
9 | 'icon-xitongguanli',
10 | 'icon-rizhiguanli',
11 | 'icon-navicon-zdgl',
12 | 'icon-weibiaoti46',
13 | 'icon-miyue',
14 | 'icon-shouji',
15 | 'icon-miyue',
16 | 'icon-denglvlingpai',
17 | 'icon-luyou',
18 | 'icon-msnui-supervise',
19 | 'icon-server',
20 | 'icon-wendang',
21 | 'icon-gtsquanjushiwufuwuGTS',
22 | 'icon-caidanguanli',
23 | 'icon-guanwang',
24 | 'icon-guanwangfangwen',
25 | 'icon-guiji',
26 | 'icon-fensiguanli',
27 | 'icon-gongzhonghao',
28 | 'icon-anniu_weixincaidanlianjie',
29 | 'icon-weixincaidan',
30 | 'icon-xiaoxiguanli',
31 | 'icon-zhexiantu',
32 | 'icon-canshu',
33 | 'icon-erji-zuhushouye',
34 | 'icon-pay6zhifu',
35 | 'icon-zhifuqudaoguanli',
36 | 'icon-dingdan',
37 | 'icon-tuikuan',
38 | 'icon-webicon14',
39 | 'icon-shouyintai',
40 | 'icon-wenjianguanli',
41 | 'icon-mysql',
42 | 'icon-shejiyukaifa-',
43 | 'icon-record',
44 | 'icon-biaodanbiaoqian'
45 | ]
46 | }
47 | ]
48 |
--------------------------------------------------------------------------------
/src/const/website.js:
--------------------------------------------------------------------------------
1 | export default {
2 | title: 'Pig',
3 | logo: 'Pig',
4 | key: 'pig', //配置主键,目前用于存储
5 | indexTitle: 'pig 快速开发框架',
6 | whiteList: ['/login', '/404', '/401', '/lock'], // 配置无权限可以访问的页面
7 | whiteTagList: ['/login', '/404', '/401', '/lock' ], // 配置不添加tags页面 ('/advanced-router/mutative-detail/*'——*为通配符)
8 | lockPage: '/lock',
9 | tokenTime: 6000,
10 | infoTitle: 'pig 快速开发框架',
11 | statusWhiteList: [428],
12 | // 配置首页不可关闭
13 | isFirstPage: false,
14 | fistPage: {
15 | label: '首页',
16 | value: '/wel/index',
17 | params: {},
18 | query: {},
19 | group: [],
20 | close: false
21 | },
22 | // 配置菜单的属性
23 | menu: {
24 | props: {
25 | label: 'label',
26 | path: 'path',
27 | icon: 'icon',
28 | children: 'children'
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/error.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.config.errorHandler = function (err, vm, info) {
4 | Vue.nextTick(() => {
5 | if (process.env.NODE_ENV === 'development') {
6 | console.group('>>>>>> 错误信息 >>>>>>')
7 | console.log(info)
8 | console.groupEnd()
9 | console.group('>>>>>> Vue 实例 >>>>>>')
10 | console.log(vm)
11 | console.groupEnd()
12 | console.group('>>>>>> Error >>>>>>')
13 | console.log(err)
14 | console.groupEnd()
15 | }
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | function pluralize (time, label) {
2 | if (time === 1) {
3 | return time + label
4 | }
5 | return time + label + 's'
6 | }
7 |
8 | /**
9 | * 日期格式化
10 | */
11 | export function dateFormat (date) {
12 | let format = 'yyyy-MM-dd hh:mm:ss'
13 | if (date != 'Invalid Date') {
14 | var o = {
15 | 'M+': date.getMonth() + 1, // month
16 | 'd+': date.getDate(), // day
17 | 'h+': date.getHours(), // hour
18 | 'm+': date.getMinutes(), // minute
19 | 's+': date.getSeconds(), // second
20 | 'q+': Math.floor((date.getMonth() + 3) / 3), // quarter
21 | 'S': date.getMilliseconds() // millisecond
22 | }
23 | if (/(y+)/.test(format)) {
24 | format = format.replace(RegExp.$1,
25 | (date.getFullYear() + '').substr(4 - RegExp.$1.length))
26 | }
27 | for (var k in o) {
28 | if (new RegExp('(' + k + ')').test(format)) {
29 | format = format.replace(RegExp.$1,
30 | RegExp.$1.length == 1 ? o[k]
31 | : ('00' + o[k]).substr(('' + o[k]).length))
32 | }
33 | }
34 | return format
35 | }
36 | return ''
37 | }
38 |
39 | export function timeAgo (time) {
40 | const between = Date.now() / 1000 - Number(time)
41 | if (between < 3600) {
42 | return pluralize(~~(between / 60), ' minute')
43 | } else if (between < 86400) {
44 | return pluralize(~~(between / 3600), ' hour')
45 | } else {
46 | return pluralize(~~(between / 86400), ' day')
47 | }
48 | }
49 |
50 | export function parseTime (time, cFormat) {
51 | if (arguments.length === 0) {
52 | return null
53 | }
54 |
55 | if ((time + '').length === 10) {
56 | time = +time * 1000
57 | }
58 |
59 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
60 | let date
61 | if (typeof time === 'object') {
62 | date = time
63 | } else {
64 | date = new Date(parseInt(time))
65 | }
66 | const formatObj = {
67 | y: date.getFullYear(),
68 | m: date.getMonth() + 1,
69 | d: date.getDate(),
70 | h: date.getHours(),
71 | i: date.getMinutes(),
72 | s: date.getSeconds(),
73 | a: date.getDay()
74 | }
75 | const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
76 | let value = formatObj[key]
77 | if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
78 | if (result.length > 0 && value < 10) {
79 | value = '0' + value
80 | }
81 | return value || 0
82 | })
83 | return time_str
84 | }
85 |
86 | export function formatTime (time, option) {
87 | time = +time * 1000
88 | const d = new Date(time)
89 | const now = Date.now()
90 |
91 | const diff = (now - d) / 1000
92 |
93 | if (diff < 30) {
94 | return '刚刚'
95 | } else if (diff < 3600) { // less 1 hour
96 | return Math.ceil(diff / 60) + '分钟前'
97 | } else if (diff < 3600 * 24) {
98 | return Math.ceil(diff / 3600) + '小时前'
99 | } else if (diff < 3600 * 24 * 2) {
100 | return '1天前'
101 | }
102 | if (option) {
103 | return parseTime(time, option)
104 | } else {
105 | return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
106 | }
107 | }
108 |
109 | /* 数字 格式化 */
110 | export function nFormatter (num, digits) {
111 | const si = [
112 | { value: 1E18, symbol: 'E' },
113 | { value: 1E15, symbol: 'P' },
114 | { value: 1E12, symbol: 'T' },
115 | { value: 1E9, symbol: 'G' },
116 | { value: 1E6, symbol: 'M' },
117 | { value: 1E3, symbol: 'k' }
118 | ]
119 | for (let i = 0; i < si.length; i++) {
120 | if (num >= si[i].value) {
121 | return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
122 | }
123 | }
124 | return num.toString()
125 | }
126 |
127 | export function html2Text (val) {
128 | const div = document.createElement('div')
129 | div.innerHTML = val
130 | return div.textContent || div.innerText
131 | }
132 |
133 | export function toThousandslsFilter (num) {
134 | return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
135 | }
136 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import 'babel-polyfill'
2 | import 'classlist-polyfill'
3 | import Vue from 'vue'
4 | import axios from './router/axios'
5 | import VueAxios from 'vue-axios'
6 | import App from './App'
7 | import ElementUI from 'element-ui'
8 | import 'element-ui/lib/theme-chalk/index.css'
9 | import Avue from '@smallwei/avue'
10 | import '@smallwei/avue/lib/index.css'
11 | import AvueFormDesign from '@sscfaith/avue-form-design'
12 | import './permission' // 权限
13 | import './error' // 日志
14 | import router from './router/router'
15 | import store from './store'
16 | import { loadStyle } from './util/util'
17 | import * as urls from '@/config/env'
18 | import {
19 | iconfontUrl,
20 | iconfontVersion
21 | } from '@/config/env'
22 | import * as filters from './filters' // 全局filter
23 | import './styles/common.scss'
24 | import basicContainer from './components/basic-container/main'
25 |
26 | window.axios = axios
27 | Vue.use(VueAxios, axios)
28 |
29 | Vue.use(ElementUI, {
30 | size: 'small',
31 | menuType: 'text'
32 | })
33 |
34 | Vue.use(Avue, {
35 | size: 'small',
36 | menuType: 'text'
37 | })
38 |
39 | Vue.use(router)
40 |
41 | Vue.use(AvueFormDesign);
42 |
43 | // 注册全局容器
44 | Vue.component('basicContainer', basicContainer)
45 |
46 | // 加载相关url地址
47 | Object.keys(urls).forEach(key => {
48 | Vue.prototype[key] = urls[key]
49 | })
50 |
51 | //加载过滤器
52 | Object.keys(filters).forEach(key => {
53 | Vue.filter(key, filters[key])
54 | })
55 |
56 | // 动态加载阿里云字体库
57 | iconfontVersion.forEach(ele => {
58 | console.log(iconfontUrl.replace('$key', ele))
59 | loadStyle(iconfontUrl.replace('$key', ele))
60 | })
61 |
62 | Vue.config.productionTip = false
63 |
64 | new Vue({
65 | router,
66 | store,
67 | render: h => h(App)
68 | }).$mount('#app')
69 |
--------------------------------------------------------------------------------
/src/mixins/color.js:
--------------------------------------------------------------------------------
1 | import { mapGetters } from "vuex";
2 | const version = require("element-ui/package.json").version; // element-ui version from node_modules
3 | const ORIGINAL_THEME = "#409EFF"; // default color
4 | export default function () {
5 | return {
6 | data() {
7 | return {
8 | themeVal: ORIGINAL_THEME
9 | }
10 | },
11 | created() {
12 | this.themeVal = this.theme;
13 | },
14 | watch: {
15 | themeVal(val, oldVal) {
16 | this.$store.commit("SET_THEME", val);
17 | this.updateTheme(val, oldVal);
18 | }
19 | },
20 | computed: {
21 | ...mapGetters(["theme"])
22 | },
23 | methods: {
24 | updateTheme(val, oldVal) {
25 | if (typeof val !== "string") return;
26 | const head = document.getElementsByTagName("head")[0];
27 | const themeCluster = this.getThemeCluster(val.replace("#", ""));
28 | const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
29 | const getHandler = (variable, id) => {
30 | return () => {
31 | const originalCluster = this.getThemeCluster(
32 | ORIGINAL_THEME.replace("#", "")
33 | );
34 | const newStyle = this.updateStyle(
35 | this[variable],
36 | originalCluster,
37 | themeCluster
38 | );
39 |
40 | let styleTag = document.getElementById(id);
41 | if (!styleTag) {
42 | styleTag = document.createElement("style");
43 | styleTag.setAttribute("id", id);
44 | head.appendChild(styleTag);
45 | }
46 | styleTag.innerText = newStyle;
47 | };
48 | };
49 |
50 | const chalkHandler = getHandler("chalk", "chalk-style");
51 |
52 | if (!this.chalk) {
53 | const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
54 | this.getCSSString(url, chalkHandler, "chalk");
55 | } else {
56 | chalkHandler();
57 | }
58 |
59 | const link = [].slice.call(
60 | document.getElementsByTagName("head")[0].getElementsByTagName("link")
61 | );
62 | for (let i = 0; i < link.length; i++) {
63 | const style = link[i];
64 | if (style.href.includes('css')) {
65 | this.getCSSString(style.href, innerText => {
66 | const originalCluster = this.getThemeCluster(
67 | ORIGINAL_THEME.replace("#", "")
68 | );
69 | const newStyle = this.updateStyle(
70 | innerText,
71 | originalCluster,
72 | themeCluster
73 | );
74 | let styleTag = document.getElementById(i);
75 | if (!styleTag) {
76 | styleTag = document.createElement("style");
77 | styleTag.id = i;
78 | styleTag.innerText = newStyle;
79 | head.appendChild(styleTag);
80 | }
81 | });
82 | }
83 | }
84 |
85 | const styles = [].slice.call(document.querySelectorAll("style"))
86 |
87 | styles.forEach(style => {
88 | const {
89 | innerText
90 | } = style;
91 | if (typeof innerText !== "string") return;
92 | style.innerText = this.updateStyle(
93 | innerText,
94 | originalCluster,
95 | themeCluster
96 | );
97 | });
98 | },
99 | updateStyle(style, oldCluster, newCluster) {
100 | let newStyle = style;
101 | oldCluster.forEach((color, index) => {
102 | newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
103 | });
104 | return newStyle;
105 | },
106 |
107 | getCSSString(url, callback, variable) {
108 | const xhr = new XMLHttpRequest();
109 | xhr.onreadystatechange = () => {
110 | if (xhr.readyState === 4 && xhr.status === 200) {
111 | if (variable) {
112 | this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
113 | }
114 | callback(xhr.responseText);
115 | }
116 | };
117 | xhr.open("GET", url);
118 | xhr.send();
119 | },
120 |
121 | getThemeCluster(theme) {
122 | const tintColor = (color, tint) => {
123 | let red = parseInt(color.slice(0, 2), 16);
124 | let green = parseInt(color.slice(2, 4), 16);
125 | let blue = parseInt(color.slice(4, 6), 16);
126 |
127 | if (tint === 0) {
128 | // when primary color is in its rgb space
129 | return [red, green, blue].join(",");
130 | } else {
131 | red += Math.round(tint * (255 - red));
132 | green += Math.round(tint * (255 - green));
133 | blue += Math.round(tint * (255 - blue));
134 |
135 | red = red.toString(16);
136 | green = green.toString(16);
137 | blue = blue.toString(16);
138 |
139 | return `#${red}${green}${blue}`;
140 | }
141 | };
142 |
143 | const shadeColor = (color, shade) => {
144 | let red = parseInt(color.slice(0, 2), 16);
145 | let green = parseInt(color.slice(2, 4), 16);
146 | let blue = parseInt(color.slice(4, 6), 16);
147 |
148 | red = Math.round((1 - shade) * red);
149 | green = Math.round((1 - shade) * green);
150 | blue = Math.round((1 - shade) * blue);
151 |
152 | red = red.toString(16);
153 | green = green.toString(16);
154 | blue = blue.toString(16);
155 |
156 | return `#${red}${green}${blue}`;
157 | };
158 |
159 | const clusters = [theme];
160 | for (let i = 0; i <= 9; i++) {
161 | clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
162 | }
163 | clusters.push(shadeColor(theme, 0.1));
164 | return clusters;
165 | }
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/page/index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
111 |
--------------------------------------------------------------------------------
/src/page/index/layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/page/index/logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | {{website.logo}}
8 |
9 |
10 |
11 |
12 | {{website.indexTitle}}
14 |
15 |
16 |
17 |
18 |
19 |
33 |
34 |
--------------------------------------------------------------------------------
/src/page/index/sidebar/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | propsDefault: {
3 | label: 'label',
4 | path: 'path',
5 | icon: 'icon',
6 | children: 'children'
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/page/index/sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
51 |
53 |
54 |
--------------------------------------------------------------------------------
/src/page/index/sidebar/sidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
40 |
41 |
121 |
122 |
--------------------------------------------------------------------------------
/src/page/index/tags.vue:
--------------------------------------------------------------------------------
1 |
2 |
42 |
43 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/src/page/index/top/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
17 |
18 |
22 |
23 |
27 |
28 |
30 |
31 |
32 |
33 |
34 | {{userInfo.username}}
35 |
36 |
37 |
38 |
39 | 首页
40 |
41 |
42 | 个人信息
43 |
44 | 退出系统
46 |
47 |
48 |
49 |
50 |
51 |
52 |
113 |
114 |
116 |
--------------------------------------------------------------------------------
/src/page/index/top/top-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
63 |
--------------------------------------------------------------------------------
/src/page/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

8 |
{{website.infoTitle}}
9 |
©2021 v3.2.0
10 |
11 |
16 |
17 |
18 |
19 |
49 |
50 |
--------------------------------------------------------------------------------
/src/page/login/userlogin.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
16 |
17 |
18 |
19 |
25 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
41 |
43 |
44 |
45 |
46 |
47 |
{{code.value}}
50 |
![]()
54 |
55 |
56 |
57 |
58 |
59 |
60 | 登录
63 |
64 |
65 |
66 |
67 |
139 |
140 |
142 |
--------------------------------------------------------------------------------
/src/page/wel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 基于Spring Cloud 2020
17 | 基于Spring Boot 2.4.5
18 |
19 |
20 | 支持docker部署
21 | 支持Rancher2 + Kubernetes部署
22 |
23 |
24 | 基于Spring Security OAuth 2.0 深度定制
25 | 完美兼容2.X,优化集群部署,提升性能
26 |
27 |
28 | 深度定制 Spring Cloud Alibaba 便于开发使用
29 | 完善监控流程,支持微服务全组件接入监控
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
109 |
110 |
161 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 全站权限配置
3 | *
4 | */
5 | import router from './router/router'
6 | import store from '@/store'
7 | import {validatenull} from '@/util/validate'
8 | import NProgress from 'nprogress' // progress bar
9 | import 'nprogress/nprogress.css' // progress bar style
10 | NProgress.configure({showSpinner: false})
11 |
12 | /**
13 | * 导航守卫,相关内容可以参考:
14 | * https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
15 | */
16 | router.beforeEach((to, from, next) => {
17 | // 缓冲设置
18 | if (to.meta.keepAlive === true && store.state.tags.tagList.some(ele => {
19 | return ele.value === to.fullPath
20 | })) {
21 | to.meta.$keepAlive = true
22 | } else {
23 | NProgress.start()
24 | if (to.meta.keepAlive === true && validatenull(to.meta.$keepAlive)) {
25 | to.meta.$keepAlive = true
26 | } else {
27 | to.meta.$keepAlive = false
28 | }
29 | }
30 | const meta = to.meta || {}
31 | if (store.getters.access_token) {
32 | if (to.path === '/login') {
33 | next({path: '/'})
34 | } else {
35 | // NOTE: 当用户角色不存在时,会存在无限请求用户信息接口的问题
36 | if (store.getters.roles.length === 0) {
37 | store.dispatch('GetUserInfo').then(() => {
38 | next()
39 | }).catch(() => {
40 | store.dispatch('FedLogOut').then(() => {
41 | next({path: '/login'})
42 | })
43 | })
44 | } else {
45 | const value = to.query.src || to.fullPath
46 | const label = to.query.name || to.name
47 | if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) {
48 | store.commit('ADD_TAG', {
49 | label: label,
50 | value: value,
51 | params: to.params,
52 | query: to.query,
53 | group: router.$avueRouter.group || []
54 | })
55 | }
56 | next()
57 | }
58 | }
59 | } else {
60 | if (meta.isAuth === false) {
61 | next()
62 | } else {
63 | next('/login')
64 | }
65 | }
66 | })
67 |
68 | router.afterEach(() => {
69 | NProgress.done()
70 | const title = store.getters.tag.label
71 | router.$avueRouter.setTitle(title)
72 | })
73 |
--------------------------------------------------------------------------------
/src/router/avue-router.js:
--------------------------------------------------------------------------------
1 | const RouterPlugin = function() {
2 | this.$router = null
3 | this.$store = null
4 | }
5 | RouterPlugin.install = function(router, store) {
6 | this.$router = router
7 | this.$store = store
8 | function isURL(s) {
9 | return /^http[s]?:\/\/.*/.test(s)
10 | }
11 | function objToform(obj) {
12 | const result = []
13 | Object.keys(obj).forEach(ele => {
14 | result.push(`${ele}=${obj[ele]}`)
15 | })
16 | return result.join('&')
17 | }
18 | this.$router.$avueRouter = {
19 | // 全局配置
20 | $website: this.$store.getters.website,
21 | $defaultTitle: 'pig微服务快速开发框架',
22 | routerList: [],
23 | group: '',
24 | safe: this,
25 | // 设置标题
26 | setTitle: function(title) {
27 | title = title ? `${title}——${this.$defaultTitle}` : this.$defaultTitle
28 | document.title = title
29 | },
30 | closeTag: (value) => {
31 | const tag = value || this.$store.getters.tag
32 | this.$store.commit('DEL_TAG', tag)
33 | },
34 | // 处理路由
35 | getPath: function(params) {
36 | const { src } = params
37 | let result = src || '/'
38 | if (src.includes('http') || src.includes('https')) {
39 | result = `/myiframe/urlPath?${objToform(params)}`
40 | }
41 | return result
42 | },
43 | // 正则处理路由
44 | vaildPath: function(list, path) {
45 | let result = false
46 | list.forEach(ele => {
47 | if (new RegExp('^' + ele + '.*', 'g').test(path)) {
48 | result = true
49 | }
50 | })
51 | return result
52 | },
53 | // 设置路由值
54 | getValue: function(route) {
55 | let value = ''
56 | if (route.query.src) {
57 | value = route.query.src
58 | } else {
59 | value = route.path
60 | }
61 | return value
62 | },
63 | // 动态路由
64 | formatRoutes: function(aMenu = [], first) {
65 | const aRouter = []
66 | const propsConfig = this.$website.menu.props
67 | const propsDefault = {
68 | label: propsConfig.label || 'label',
69 | path: propsConfig.path || 'path',
70 | icon: propsConfig.icon || 'icon',
71 | children: propsConfig.children || 'children',
72 | meta: propsConfig.meta || 'meta'
73 | }
74 | if (aMenu.length === 0) return
75 | for (let i = 0; i < aMenu.length; i++) {
76 | const oMenu = aMenu[i]
77 | if (this.routerList.includes(oMenu[propsDefault.path])) return
78 | const path = (() => {
79 | if (!oMenu[propsDefault.path]) {
80 | return
81 | } else if (first) {
82 | return oMenu[propsDefault.path].replace('/index', '')
83 | } else {
84 | return oMenu[propsDefault.path]
85 | }
86 | })()
87 |
88 | //特殊处理组件
89 | const component = 'views' + oMenu.path
90 |
91 | const name = oMenu[propsDefault.label]
92 |
93 | const icon = oMenu[propsDefault.icon]
94 |
95 | const children = oMenu[propsDefault.children]
96 |
97 | const meta = {
98 | keepAlive: Number(oMenu['keepAlive']) === 1
99 | }
100 | const isChild = children.length !== 0
101 | const oRouter = {
102 | path: path,
103 | component(resolve) {
104 | // 判断是否为首路由
105 | if (first) {
106 | require(['../page/index'], resolve)
107 |
108 | // 判断是否为多层路由
109 | } else if (isChild && !first) {
110 | require(['../page/index/layout'], resolve)
111 |
112 | // 判断是否为最终的页面视图
113 | } else {
114 | require([`../${component}.vue`], resolve)
115 | }
116 | },
117 | name: name,
118 | icon: icon,
119 | meta: meta,
120 | redirect: (() => {
121 | if (!isChild && first && !isURL(path)) return `${path}/index`
122 | else return ''
123 | })(),
124 | // 处理是否为一级路由
125 | children: !isChild ? (() => {
126 | if (first) {
127 | if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index`
128 | return [{
129 | component(resolve) { require([`../${component}.vue`], resolve) },
130 | icon: icon,
131 | name: name,
132 | meta: meta,
133 | path: 'index'
134 | }]
135 | }
136 | return []
137 | })() : (() => {
138 | return this.formatRoutes(children, false)
139 | })()
140 | }
141 | aRouter.push(oRouter)
142 | }
143 | if (first) {
144 | if (!this.routerList.includes(aRouter[0][propsDefault.path])) {
145 | this.safe.$router.addRoutes(aRouter)
146 | this.routerList.push(aRouter[0][propsDefault.path])
147 | }
148 | } else {
149 | return aRouter
150 | }
151 | }
152 | }
153 | }
154 | export default RouterPlugin
155 |
--------------------------------------------------------------------------------
/src/router/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import {serialize} from '@/util/util'
3 | import NProgress from 'nprogress' // progress bar
4 | import errorCode from '@/const/errorCode'
5 | import router from "@/router/router"
6 | import {Message} from 'element-ui'
7 | import 'nprogress/nprogress.css'
8 | import qs from 'qs'
9 | import store from "@/store"; // progress bar style
10 | import {baseUrl} from '@/config/env'
11 | axios.defaults.timeout = 30000
12 | axios.defaults.baseURL = baseUrl
13 | // 返回其他状态吗
14 | axios.defaults.validateStatus = function (status) {
15 | return status >= 200 && status <= 500 // 默认的
16 | }
17 | // 跨域请求,允许保存cookie
18 | axios.defaults.withCredentials = true
19 | // NProgress Configuration
20 | NProgress.configure({
21 | showSpinner: false
22 | })
23 |
24 | // HTTPrequest拦截
25 | axios.interceptors.request.use(config => {
26 | NProgress.start() // start progress bar
27 | const isToken = (config.headers || {}).isToken === false
28 | let token = store.getters.access_token
29 | if (token && !isToken) {
30 | config.headers['Authorization'] = 'Bearer ' + token// token
31 | }
32 | // headers中配置serialize为true开启序列化
33 | if (config.methods === 'post' && config.headers.serialize) {
34 | config.data = serialize(config.data)
35 | delete config.data.serialize
36 | }
37 |
38 | // 处理get 请求的数组 springmvc 可以处理
39 | if (config.method === 'get') {
40 | config.paramsSerializer = function (params) {
41 | return qs.stringify(params, { arrayFormat: 'repeat' })
42 | }
43 | }
44 |
45 | return config
46 | }, error => {
47 | return Promise.reject(error)
48 | })
49 |
50 |
51 | // HTTPresponse拦截
52 | axios.interceptors.response.use(res => {
53 | NProgress.done()
54 | const status = Number(res.status) || 200
55 | const message = res.data.msg || errorCode[status] || errorCode['default']
56 | if (status === 401) {
57 | store.dispatch('FedLogOut').then(() => {
58 | router.push({path: '/login'})
59 | })
60 | return
61 | }
62 |
63 | if (status !== 200 || res.data.code === 1) {
64 | Message({
65 | message: message,
66 | type: 'error'
67 | })
68 | return Promise.reject(new Error(message))
69 | }
70 |
71 | return res
72 | }, error => {
73 | NProgress.done()
74 | return Promise.reject(new Error(error))
75 | })
76 |
77 | export default axios
78 |
--------------------------------------------------------------------------------
/src/router/page/index.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/page/index/'
2 | export default [{
3 | path: '/login',
4 | name: '登录页',
5 | component: () =>
6 | import ( /* webpackChunkName: "page" */ '@/page/login/index'),
7 | meta: {
8 | keepAlive: true,
9 | isTab: false,
10 | isAuth: false
11 | }
12 | },
13 | {
14 | path: '/404',
15 | component: () =>
16 | import ( /* webpackChunkName: "page" */ '@/components/error-page/404'),
17 | name: '404',
18 | meta: {
19 | keepAlive: true,
20 | isTab: false,
21 | isAuth: true
22 | }
23 |
24 | },
25 | {
26 | path: '/403',
27 | component: () =>
28 | import ( /* webpackChunkName: "page" */ '@/components/error-page/403'),
29 | name: '403',
30 | meta: {
31 | keepAlive: true,
32 | isTab: false,
33 | isAuth: false
34 | }
35 | },
36 | {
37 | path: '/500',
38 | component: () =>
39 | import ( /* webpackChunkName: "page" */ '@/components/error-page/500'),
40 | name: '500',
41 | meta: {
42 | keepAlive: true,
43 | isTab: false,
44 | isAuth: false
45 | }
46 | },
47 | {
48 | path: '/',
49 | name: '主页',
50 | redirect: '/wel'
51 | },
52 | {
53 | path: '/myiframe',
54 | component: Layout,
55 | redirect: '/myiframe',
56 | children: [{
57 | path: ":routerPath",
58 | name: 'iframe',
59 | component: () =>
60 | import ( /* webpackChunkName: "page" */ '@/components/iframe/main'),
61 | props: true
62 | }]
63 | },
64 | {
65 | path: '*',
66 | redirect: '/404',
67 | }
68 | ]
69 |
--------------------------------------------------------------------------------
/src/router/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import PageRouter from './page/'
4 | import ViewsRouter from './views/'
5 | import AvueRouter from './avue-router'
6 | import Store from '../store/'
7 | Vue.use(VueRouter)
8 | let Router = new VueRouter({
9 | scrollBehavior (to, from, savedPosition) {
10 | if (savedPosition) {
11 | return savedPosition
12 | } else {
13 | if (from.meta.keepAlive) {
14 | from.meta.savedPosition = document.body.scrollTop
15 | }
16 | return {
17 | x: 0,
18 | y: to.meta.savedPosition || 0
19 | }
20 | }
21 | },
22 | routes: [].concat([])
23 | })
24 | AvueRouter.install(Router, Store)
25 | Router.$avueRouter.formatRoutes(Store.state.user.menu, true)
26 | Router.addRoutes([...PageRouter, ...ViewsRouter])
27 | export default Router
28 |
--------------------------------------------------------------------------------
/src/router/views/index.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/page/index/'
2 | export default [{
3 | path: '/wel',
4 | component: Layout,
5 | redirect: '/wel/index',
6 | children: [{
7 | path: 'index',
8 | name: '首页',
9 | component: () =>
10 | import ( /* webpackChunkName: "views" */ '@/page/wel')
11 | }]
12 | }, {
13 | path: '/info',
14 | component: Layout,
15 | redirect: '/info/index',
16 | children: [{
17 | path: 'index',
18 | name: '个人信息',
19 | component: () =>
20 | import ( /* webpackChunkName: "page" */ '@/views/admin/user/info'),
21 | }]
22 | }]
23 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 | tag: state => state.tags.tag,
3 | website: state => state.common.website,
4 | userInfo: state => state.user.userInfo,
5 | theme: state => state.common.theme,
6 | themeName: state => state.common.themeName,
7 | isShade: state => state.common.isShade,
8 | isCollapse: state => state.common.isCollapse,
9 | keyCollapse: (state, getters) => getters.screen > 1 ? getters.isCollapse : false,
10 | screen: state => state.common.screen,
11 | isLock: state => state.common.isLock,
12 | isFullScreen: state => state.common.isFullScreen,
13 | lockPasswd: state => state.common.lockPasswd,
14 | tagList: state => state.tags.tagList,
15 | tagWel: state => state.tags.tagWel,
16 | access_token: state => state.user.access_token,
17 | refresh_token: state => state.user.refresh_token,
18 | expires_in: state => state.user.expires_in,
19 | roles: state => state.user.roles,
20 | permissions: state => state.user.permissions,
21 | menu: state => state.user.menu,
22 | menuAll: state => state.user.menuAll
23 | }
24 | export default getters
25 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import user from './modules/user'
4 | import common from './modules/common'
5 | import tags from './modules/tags'
6 | import getters from './getters'
7 |
8 | Vue.use(Vuex)
9 | const store = new Vuex.Store({
10 | modules: {
11 | user,
12 | common,
13 | tags
14 | },
15 | getters
16 | })
17 |
18 | export default store
19 |
--------------------------------------------------------------------------------
/src/store/modules/common.js:
--------------------------------------------------------------------------------
1 | import { getStore, removeStore, setStore } from '@/util/store'
2 | import website from '@/const/website'
3 | const common = {
4 |
5 | state: {
6 | isCollapse: false,
7 | isFullScreen: false,
8 | isShade: false,
9 | screen: -1,
10 | isLock: getStore({ name: 'isLock' }) || false,
11 | showTag: true,
12 | showCollapse: true,
13 | showFullScren: true,
14 | website: website
15 | },
16 | actions: {},
17 | mutations: {
18 | SET_SHADE: (state, active) => {
19 | state.isShade = active
20 | },
21 | SET_COLLAPSE: (state) => {
22 | state.isCollapse = !state.isCollapse
23 | },
24 | SET_FULLSCREN: (state) => {
25 | state.isFullScreen = !state.isFullScreen
26 | },
27 | SET_SHOWCOLLAPSE: (state, active) => {
28 | state.showCollapse = active
29 | setStore({
30 | name: 'showCollapse',
31 | content: state.showCollapse
32 | })
33 | },
34 | SET_SHOWTAG: (state, active) => {
35 | state.showTag = active
36 | setStore({
37 | name: 'showTag',
38 | content: state.showTag
39 | })
40 | },
41 | SET_SHOWMENU: (state, active) => {
42 | state.showMenu = active
43 | setStore({
44 | name: 'showMenu',
45 | content: state.showMenu
46 | })
47 | },
48 | SET_SHOWLOCK: (state, active) => {
49 | state.showLock = active
50 | setStore({
51 | name: 'showLock',
52 | content: state.showLock
53 | })
54 | },
55 | SET_SHOWSEARCH: (state, active) => {
56 | state.showSearch = active
57 | setStore({
58 | name: 'showSearch',
59 | content: state.showSearch
60 | })
61 | },
62 | SET_SHOWFULLSCREN: (state, active) => {
63 | state.showFullScren = active
64 | setStore({
65 | name: 'showFullScren',
66 | content: state.showFullScren
67 | })
68 | },
69 | SET_SHOWDEBUG: (state, active) => {
70 | state.showDebug = active
71 | setStore({
72 | name: 'showDebug',
73 | content: state.showDebug
74 | })
75 | },
76 | SET_SHOWTHEME: (state, active) => {
77 | state.showTheme = active
78 | setStore({
79 | name: 'showTheme',
80 | content: state.showTheme
81 | })
82 | },
83 | SET_SHOWCOLOR: (state, active) => {
84 | state.showColor = active
85 | setStore({
86 | name: 'showColor',
87 | content: state.showColor
88 | })
89 | },
90 | SET_LOCK: (state) => {
91 | state.isLock = true
92 | setStore({
93 | name: 'isLock',
94 | content: state.isLock,
95 | type: 'session'
96 | })
97 | },
98 | SET_SCREEN: (state, screen) => {
99 | state.screen = screen
100 | },
101 | SET_THEME: (state, color) => {
102 | state.theme = color
103 | setStore({
104 | name: 'theme',
105 | content: state.theme
106 | })
107 | },
108 | SET_THEME_NAME: (state, themeName) => {
109 | state.themeName = themeName
110 | setStore({
111 | name: 'themeName',
112 | content: state.themeName
113 | })
114 | },
115 | SET_LOCK_PASSWD: (state, lockPasswd) => {
116 | state.lockPasswd = lockPasswd
117 | setStore({
118 | name: 'lockPasswd',
119 | content: state.lockPasswd,
120 | type: 'session'
121 | })
122 | },
123 | CLEAR_LOCK: (state) => {
124 | state.isLock = false
125 | state.lockPasswd = ''
126 | removeStore({
127 | name: 'lockPasswd'
128 | })
129 | removeStore({
130 | name: 'isLock'
131 | })
132 | }
133 | }
134 | }
135 | export default common
136 |
--------------------------------------------------------------------------------
/src/store/modules/tags.js:
--------------------------------------------------------------------------------
1 | import { getStore, setStore } from '@/util/store'
2 | import { diff } from '@/util/util'
3 | import website from '@/const/website'
4 |
5 | const isFirstPage = website.isFirstPage
6 | const tagWel = website.fistPage
7 | const tagObj = {
8 | label: '', // 标题名称
9 | value: '', // 标题的路径
10 | params: '', // 标题的路径参数
11 | query: '', // 标题的参数
12 | group: [] // 分组
13 | }
14 |
15 | // 处理首个标签
16 | function setFistTag (list) {
17 | if (list.length == 1) {
18 | list[0].close = false
19 | } else {
20 | list.forEach(ele => {
21 | if (ele.value === tagWel.value && isFirstPage === false) {
22 | ele.close = false
23 | } else {
24 | ele.close = true
25 | }
26 | })
27 | }
28 | }
29 |
30 | const navs = {
31 | state: {
32 | tagList: getStore({ name: 'tagList' }) || [],
33 | tag: getStore({ name: 'tag' }) || tagObj,
34 | tagWel: tagWel
35 | },
36 | actions: {},
37 | mutations: {
38 | ADD_TAG: (state, action) => {
39 | state.tag = action
40 | setStore({ name: 'tag', content: state.tag, type: 'session' })
41 | if (state.tagList.some(ele => diff(ele, action))) return
42 | state.tagList.push(action)
43 | setFistTag(state.tagList)
44 | setStore({ name: 'tagList', content: state.tagList, type: 'session' })
45 | },
46 | DEL_TAG: (state, action) => {
47 | state.tagList = state.tagList.filter(item => {
48 | return !diff(item, action)
49 | })
50 | setFistTag(state.tagList)
51 | setStore({ name: 'tagList', content: state.tagList, type: 'session' })
52 | },
53 | DEL_ALL_TAG: (state) => {
54 | state.tagList = [state.tagWel]
55 | setStore({ name: 'tagList', content: state.tagList, type: 'session' })
56 | },
57 | DEL_TAG_OTHER: (state) => {
58 | state.tagList = state.tagList.filter(item => {
59 | if (item.value === state.tag.value) {
60 | return true;
61 | } else if (!website.isFirstPage && item.value === website.fistPage.value) {
62 | return true;
63 | }
64 | })
65 | setFistTag(state.tagList)
66 | setStore({ name: 'tagList', content: state.tagList, type: 'session' })
67 | }
68 | }
69 | }
70 | export default navs
71 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | import {getStore, setStore} from '@/util/store'
2 | import {isURL, validatenull} from '@/util/validate'
3 | import {getUserInfo, loginByUsername, logout, refreshToken} from '@/api/login'
4 | import {deepClone, encryption} from '@/util/util'
5 | import webiste from '@/const/website'
6 | import {getMenu} from '@/api/admin/menu'
7 |
8 | function addPath(ele, first) {
9 | const menu = webiste.menu
10 | const propsConfig = menu.props
11 | const propsDefault = {
12 | label: propsConfig.label || 'name',
13 | path: propsConfig.path || 'path',
14 | icon: propsConfig.icon || 'icon',
15 | children: propsConfig.children || 'children'
16 | }
17 | const icon = ele[propsDefault.icon]
18 | ele[propsDefault.icon] = validatenull(icon) ? menu.iconDefault : icon
19 | const isChild = ele[propsDefault.children] && ele[propsDefault.children].length !== 0
20 | if (!isChild) ele[propsDefault.children] = []
21 | if (!isChild && first && !isURL(ele[propsDefault.path])) {
22 | ele[propsDefault.path] = ele[propsDefault.path] + '/index'
23 | } else {
24 | ele[propsDefault.children].forEach(child => {
25 | addPath(child)
26 | })
27 | }
28 | }
29 |
30 | const user = {
31 | state: {
32 | userInfo: {},
33 | permissions: {},
34 | roles: [],
35 | menu: getStore({
36 | name: 'menu'
37 | }) || [],
38 | menuAll: [],
39 | expires_in: getStore({
40 | name: 'expires_in'
41 | }) || '',
42 | access_token: getStore({
43 | name: 'access_token'
44 | }) || '',
45 | refresh_token: getStore({
46 | name: 'refresh_token'
47 | }) || ''
48 | },
49 | actions: {
50 | // 根据用户名登录
51 | LoginByUsername({commit}, userInfo) {
52 | const user = encryption({
53 | data: userInfo,
54 | key: 'thanks,pig4cloud',
55 | param: ['password']
56 | })
57 | return new Promise((resolve, reject) => {
58 | loginByUsername(user.username, user.password, user.code, user.randomStr).then(response => {
59 | const data = response.data
60 | commit('SET_ACCESS_TOKEN', data.access_token)
61 | commit('SET_REFRESH_TOKEN', data.refresh_token)
62 | commit('SET_EXPIRES_IN', data.expires_in)
63 | commit('CLEAR_LOCK')
64 | resolve()
65 | }).catch(error => {
66 | reject(error)
67 | })
68 | })
69 | },
70 | GetUserInfo({commit}) {
71 | return new Promise((resolve, reject) => {
72 | getUserInfo().then((res) => {
73 | const data = res.data.data || {}
74 | commit('SET_USER_INFO', data.sysUser)
75 | commit('SET_ROLES', data.roles || [])
76 | commit('SET_PERMISSIONS', data.permissions || [])
77 | resolve(data)
78 | }).catch((err) => {
79 | reject()
80 | })
81 | })
82 | },
83 | // 刷新token
84 | RefreshToken({commit, state}) {
85 | return new Promise((resolve, reject) => {
86 | refreshToken(state.refresh_token).then(response => {
87 | const data = response.data
88 | commit('SET_ACCESS_TOKEN', data.access_token)
89 | commit('SET_REFRESH_TOKEN', data.refresh_token)
90 | commit('SET_EXPIRES_IN', data.expires_in)
91 | commit('CLEAR_LOCK')
92 | resolve()
93 | }).catch(error => {
94 | reject(error)
95 | })
96 | })
97 | },
98 | // 登出
99 | LogOut({commit}) {
100 | return new Promise((resolve, reject) => {
101 | logout().then(() => {
102 | commit('SET_MENU', [])
103 | commit('SET_PERMISSIONS', [])
104 | commit('SET_USER_INFO', {})
105 | commit('SET_ACCESS_TOKEN', '')
106 | commit('SET_REFRESH_TOKEN', '')
107 | commit('SET_EXPIRES_IN', '')
108 | commit('SET_ROLES', [])
109 | commit('DEL_ALL_TAG')
110 | commit('CLEAR_LOCK')
111 | resolve()
112 | }).catch(error => {
113 | reject(error)
114 | })
115 | })
116 | },
117 | // 注销session
118 | FedLogOut({commit}) {
119 | return new Promise(resolve => {
120 | commit('SET_MENU', [])
121 | commit('SET_PERMISSIONS', [])
122 | commit('SET_USER_INFO', {})
123 | commit('SET_ACCESS_TOKEN', '')
124 | commit('SET_REFRESH_TOKEN', '')
125 | commit('SET_ROLES', [])
126 | commit('DEL_ALL_TAG')
127 | commit('CLEAR_LOCK')
128 | resolve()
129 | })
130 | },
131 | // 获取系统菜单
132 | GetMenu({commit}, obj) {
133 | return new Promise(resolve => {
134 | getMenu(obj.id).then((res) => {
135 | const data = res.data.data
136 | let menu = deepClone(data)
137 | menu.forEach(ele => {
138 | addPath(ele)
139 | })
140 | let type = obj.type
141 | commit('SET_MENU', {type, menu})
142 | resolve(menu)
143 | })
144 | })
145 | }
146 |
147 | },
148 | mutations: {
149 | SET_ACCESS_TOKEN: (state, access_token) => {
150 | state.access_token = access_token
151 | setStore({
152 | name: 'access_token',
153 | content: state.access_token,
154 | type: 'session'
155 | })
156 | },
157 | SET_EXPIRES_IN: (state, expires_in) => {
158 | state.expires_in = expires_in
159 | setStore({
160 | name: 'expires_in',
161 | content: state.expires_in,
162 | type: 'session'
163 | })
164 | },
165 | SET_REFRESH_TOKEN: (state, rfToken) => {
166 | state.refresh_token = rfToken
167 | setStore({
168 | name: 'refresh_token',
169 | content: state.refresh_token,
170 | type: 'session'
171 | })
172 | },
173 | SET_USER_INFO: (state, userInfo) => {
174 | state.userInfo = userInfo
175 | },
176 | SET_MENU: (state, params = {}) => {
177 | let {menu, type} = params;
178 | if (type !== false) state.menu = menu
179 | setStore({
180 | name: 'menu',
181 | content: menu,
182 | type: 'session'
183 | })
184 | },
185 | SET_MENU_ALL: (state, menuAll) => {
186 | state.menuAll = menuAll
187 | },
188 | SET_ROLES: (state, roles) => {
189 | state.roles = roles
190 | },
191 | SET_PERMISSIONS: (state, permissions) => {
192 | const list = {}
193 | for (let i = 0; i < permissions.length; i++) {
194 | list[permissions[i]] = true
195 | }
196 | state.permissions = list
197 | }
198 | }
199 |
200 | }
201 | export default user
202 |
--------------------------------------------------------------------------------
/src/styles/animate/vue-transition.scss:
--------------------------------------------------------------------------------
1 | // 过渡动画 横向渐变
2 | .fade-transverse-leave-active,
3 | .fade-transverse-enter-active {
4 | transition: all .5s;
5 | }
6 |
7 | .fade-transverse-enter {
8 | opacity: 0;
9 | transform: translateX(-30px);
10 | }
11 |
12 | .fade-transverse-leave-to {
13 | opacity: 0;
14 | transform: translateX(30px);
15 | }
16 |
17 | // 过渡动画 缩放渐变
18 | .fade-scale-leave-active,
19 | .fade-scale-enter-active {
20 | transition: all .5s;
21 | }
22 |
23 | .fade-scale-enter {
24 | opacity: 0;
25 | transform: scale(1.2);
26 | }
27 |
28 | .fade-scale-leave-to {
29 | opacity: 0;
30 | transform: scale(0.8);
31 | }
32 |
33 | @-webkit-keyframes animate-cloud {
34 | from {
35 | background-position: 600px 100%;
36 | }
37 | to {
38 | background-position: 0 100%;
39 | }
40 | }
41 | @-moz-keyframes animate-cloud {
42 | from {
43 | background-position: 600px 100%;
44 | }
45 | to {
46 | background-position: 0 100%;
47 | }
48 | }
49 | @-ms-keyframes animate-cloud {
50 | from {
51 | background-position: 600px 100%;
52 | }
53 | to {
54 | background-position: 0 100%;
55 | }
56 | }
57 | @-o-keyframes animate-cloud {
58 | from {
59 | background-position: 600px 100%;
60 | }
61 | to {
62 | background-position: 0 100%;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/styles/common.scss:
--------------------------------------------------------------------------------
1 | // 全局变量
2 | @import './variables.scss';
3 | // ele样式覆盖
4 | @import './element-ui.scss';
5 | // 顶部右侧显示
6 | @import './top.scss';
7 | // 导航标签
8 | @import './tags.scss';
9 | // 工具类函数
10 | @import './mixin.scss';
11 | // 侧面导航栏
12 | @import './sidebar.scss';
13 | // 动画
14 | @import './animate/vue-transition.scss';
15 | //适配
16 | @import './media.scss';
17 | //通用配置
18 | @import './normalize.scss';
19 |
20 | a {
21 | text-decoration: none;
22 | color: #333;
23 | }
24 |
25 | * {
26 | outline: none;
27 | }
28 |
29 | // 关于 图标 CSS 的设置
30 | [class^="icon-"] {
31 | font-family: "iconfont" !important;
32 | /* 以下内容参照第三方图标库本身的规则 */
33 | font-size: 18px !important;
34 | font-style: normal;
35 | -webkit-font-smoothing: antialiased;
36 | -moz-osx-font-smoothing: grayscale;
37 | }
38 |
39 | .avue-input-icon__item i, .avue-crud__icon--small {
40 | font-family: "iconfont" !important;
41 | /* 以下内容参照第三方图标库本身的规则 */
42 | font-size: 24px !important;
43 | font-style: normal;
44 | -webkit-font-smoothing: antialiased;
45 | -moz-osx-font-smoothing: grayscale;
46 | }
47 |
48 | .el-menu-item [class^=icon-] {
49 | margin-right: 5px;
50 | width: 24px;
51 | text-align: center;
52 | font-size: 18px;
53 | vertical-align: middle;
54 | }
55 |
56 | .el-submenu [class^=icon-] {
57 | vertical-align: middle;
58 | margin-right: 5px;
59 | width: 24px;
60 | text-align: center;
61 | font-size: 18px;
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | .el-dropdown-menu__item {
2 | font-size: 12px !important;
3 | line-height: 28px !important;
4 | }
5 |
6 | .el-card.is-always-shadow {
7 | box-shadow: none;
8 | border: none !important;
9 | }
10 |
11 | .el-scrollbar__view {
12 | height: 100%;
13 | }
14 |
15 | .el-menu--horizontal {
16 | border-bottom: none !important;
17 | }
18 |
19 | .el-menu {
20 | border-right: none !important;
21 | }
22 |
23 | .el-menu--display,
24 | .el-menu--display + .el-submenu__icon-arrow {
25 | display: none;
26 | }
27 |
28 | .el-dropdown-menu__item--divided:before,
29 | .el-menu,
30 | .el-menu--horizontal > .el-menu-item:not(.is-disabled):focus,
31 | .el-menu--horizontal > .el-menu-item:not(.is-disabled):hover,
32 | .el-menu--horizontal > .el-submenu .el-submenu__title:hover {
33 | background-color: transparent;
34 | }
35 |
36 | .el-message__icon,
37 | .el-message__content {
38 | display: inline-block;
39 | }
40 |
41 | .el-date-editor .el-range-input,
42 | .el-date-editor .el-range-separator {
43 | height: auto;
44 | overflow: hidden;
45 | }
46 |
47 | .el-dialog__wrapper {
48 | z-index: 2048;
49 | }
50 |
51 |
52 | .el-col {
53 | margin-bottom: 8px;
54 | }
55 |
56 | .el-main {
57 | padding: 0 !important;
58 | }
59 |
60 | .el-dropdown-menu__item--divided:before, .el-menu, .el-menu--horizontal > .el-menu-item:not(.is-disabled):focus, .el-menu--horizontal > .el-menu-item:not(.is-disabled):hover, .el-menu--horizontal > .el-submenu .el-submenu__title:hover {
61 | background-color: transparent !important;
62 | }
63 |
--------------------------------------------------------------------------------
/src/styles/login.scss:
--------------------------------------------------------------------------------
1 |
2 | .login-container {
3 | display: flex;
4 | align-items: center;
5 | position: relative;
6 | width: 100%;
7 | height: 100%;
8 | margin: 0 auto;
9 | background: #f8f8f9;
10 | animation: animate-cloud 20s linear infinite;
11 | }
12 |
13 | .login-weaper {
14 | margin: 0 auto;
15 | width: 1000px;
16 | box-shadow: -4px 5px 10px rgba(0, 0, 0, 0.4);
17 | }
18 |
19 | .login-left,
20 | .login-border {
21 | position: relative;
22 | min-height: 500px;
23 | align-items: center;
24 | display: flex;
25 | }
26 |
27 | .login-left {
28 | border-top-left-radius: 5px;
29 | border-bottom-left-radius: 5px;
30 | justify-content: center;
31 | flex-direction: column;
32 | background-color: #409EFF;
33 | color: #fff;
34 | float: left;
35 | width: 50%;
36 | position: relative;
37 | }
38 |
39 | .login-left .img {
40 | width: 140px;
41 | }
42 |
43 | .login-time {
44 | position: absolute;
45 | left: 25px;
46 | top: 25px;
47 | width: 100%;
48 | color: #fff;
49 | font-weight: 200;
50 | opacity: 0.9;
51 | font-size: 18px;
52 | overflow: hidden;
53 | }
54 |
55 | .login-left .title {
56 | margin-top: 60px;
57 | text-align: center;
58 | color: #fff;
59 | font-weight: 300;
60 | letter-spacing: 2px;
61 | font-size: 25px;
62 | }
63 |
64 | .login-border {
65 | border-left: none;
66 | border-top-right-radius: 5px;
67 | border-bottom-right-radius: 5px;
68 | color: #fff;
69 | background-color: #fff;
70 | width: 50%;
71 | float: left;
72 | box-sizing: border-box;
73 | }
74 |
75 | .login-main {
76 | margin: 0 auto;
77 | width: 65%;
78 | box-sizing: border-box;
79 | }
80 |
81 | .login-main > h3 {
82 | margin-bottom: 20px;
83 | }
84 |
85 | .login-main > p {
86 | color: #76838f;
87 | }
88 |
89 | .login-title {
90 | color: #333;
91 | margin-bottom: 40px;
92 | font-weight: 500;
93 | font-size: 22px;
94 | text-align: center;
95 | letter-spacing: 4px;
96 | }
97 |
98 | .login-select {
99 | input {
100 | color: #333;
101 | font-size: 18px;
102 | font-weight: 400;
103 | border: none;
104 | text-align: center;
105 | }
106 | }
107 |
108 | .login-menu {
109 | margin-top: 40px;
110 | width: 100%;
111 | text-align: center;
112 |
113 | a {
114 | color: #999;
115 | font-size: 12px;
116 | margin: 0px 8px;
117 | }
118 | }
119 |
120 | .login-submit {
121 | width: 100%;
122 | height: 45px;
123 | border: 1px solid #409eff;
124 | background: none;
125 | font-size: 18px;
126 | letter-spacing: 2px;
127 | font-weight: 300;
128 | color: #409eff;
129 | cursor: pointer;
130 | margin-top: 30px;
131 | font-family: "neo";
132 | transition: 0.25s;
133 | }
134 |
135 | .login-form {
136 | margin: 10px 0;
137 |
138 | i {
139 | color: #333;
140 | }
141 |
142 | .el-form-item__content {
143 | width: 100%;
144 | }
145 |
146 | .el-form-item {
147 | margin-bottom: 12px;
148 | }
149 |
150 | .el-input {
151 | input {
152 | padding-bottom: 10px;
153 | text-indent: 5px;
154 | background: transparent;
155 | border: none;
156 | border-radius: 0;
157 | color: #333;
158 | border-bottom: 1px solid rgb(235, 237, 242);
159 | }
160 |
161 | .el-input__prefix {
162 | i {
163 | padding: 0 5px;
164 | font-size: 16px !important;
165 | }
166 | }
167 | }
168 | }
169 |
170 | .login-code {
171 | display: flex;
172 | align-items: center;
173 | justify-content: space-around;
174 | margin: 0 0 0 10px;
175 | }
176 |
177 | .login-code-img {
178 | margin-top: 2px;
179 | width: 100px;
180 | height: 38px;
181 | background-color: #fdfdfd;
182 | border: 1px solid #f0f0f0;
183 | color: #333;
184 | font-size: 14px;
185 | font-weight: bold;
186 | letter-spacing: 5px;
187 | line-height: 38px;
188 | text-indent: 5px;
189 | text-align: center;
190 | }
191 |
192 |
--------------------------------------------------------------------------------
/src/styles/media.scss:
--------------------------------------------------------------------------------
1 | .avue-left,
2 | .avue-header,
3 | .avue-top,
4 | .avue-logo,
5 | .avue-layout
6 | .login-logo,
7 | .avue-main {
8 | transition: all .3s;
9 | }
10 | .avue-contail {
11 | width: 100%;
12 | height: 100%;
13 | background: #f0f2f5;
14 | background-size: 100%;
15 | background-repeat: no-repeat;
16 | }
17 |
18 |
19 | .avue-left {
20 | position: fixed;
21 | left: 0;
22 | top: 0;
23 | width: 240px;
24 | height: 100%;
25 | z-index: 1025;
26 | }
27 |
28 | .avue--collapse {
29 | .avue-left,
30 | .avue-logo {
31 | width: 60px;
32 | }
33 | .avue-header {
34 | padding-left: 60px;
35 | }
36 | .avue-main {
37 | width: calc(100% - 60px);
38 | left: 60px;
39 | }
40 | }
41 |
42 | .avue-header {
43 | padding-left: 240px;
44 | width: 100%;
45 | background-color: #fff;
46 | box-sizing: border-box;
47 | }
48 |
49 | .avue-main {
50 | position: absolute;
51 | left: 240px;
52 | padding: 0;
53 | padding-bottom: 20px;
54 | width: calc(100% - 240px);
55 | height: calc(100% - 70px);
56 | box-sizing: border-box;
57 | overflow: hidden;
58 | }
59 |
60 | .avue-view {
61 | padding-bottom: 22px;
62 | width: 100%;
63 | box-sizing: border-box;
64 | }
65 |
66 | .avue-footer {
67 | margin: 0 auto;
68 | padding: 0 22px;
69 | width: 1300px;
70 | display: flex;
71 | align-items: center;
72 | justify-content: space-between;
73 | .logo {
74 | margin-left: -50px;
75 | }
76 | .copyright {
77 | color: #666;
78 | line-height: 1.5;
79 | font-size: 12px;
80 | }
81 | }
82 |
83 | .avue-shade {
84 | position: fixed;
85 | display: none;
86 | width: 100%;
87 | height: 100%;
88 | left: 0;
89 | right: 0;
90 | top: 0;
91 | bottom: 0;
92 | background-color: rgba(0, 0, 0, .3);
93 | z-index: 1024;
94 | &--show {
95 | display: block;
96 | }
97 | }
98 |
99 | @media screen and (max-width: 992px) {
100 | $width: 240px;
101 | // ele的自适应
102 | .el-dialog,
103 | .el-message-box {
104 | width: 98% !important;
105 | }
106 | //登录页面
107 | .login-left {
108 | display: none !important;
109 | }
110 | .login-logo {
111 | padding-top: 30px !important;
112 | margin-left: -30px;
113 | }
114 | .login-weaper{
115 | margin: 0 auto;
116 | width: 96% !important;
117 | }
118 | .login-border {
119 | border-radius: 5px;
120 | padding: 40px;
121 | margin: 0 auto;
122 | float: none !important;
123 | width: 100% !important;
124 | }
125 | .login-main {
126 | width: 100% !important;
127 | }
128 | //主框架
129 | .avue-tags {
130 | display: none;
131 | }
132 | .avue-left,
133 | .avue-logo {
134 | left: -$width;
135 | }
136 | .avue-main {
137 | left: 0;
138 | width: 100%;
139 | }
140 | .avue-header {
141 | margin-bottom: 15px;
142 | padding-left: 15px;
143 | }
144 | .top-bar__item {
145 | display: none;
146 | }
147 | .avue--collapse {
148 | .avue-left,
149 | .avue-logo {
150 | width: $width;
151 | left: 0;
152 | }
153 | .avue-main {
154 | left: $width;
155 | width: 100%;
156 | }
157 | .avue-header {
158 | padding: 0;
159 | transform: translate3d(230px, 0, 0);
160 | }
161 | .avue-shade {
162 | display: block;
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin clearfix {
2 | &:after {
3 | content: "";
4 | display: table;
5 | clear: both;
6 | }
7 | }
8 |
9 | @mixin scrollBar {
10 | ::-webkit-scrollbar-track-piece {
11 | background-color: transparent;
12 | }
13 | ::-webkit-scrollbar {
14 | width: 7px;
15 | height: 7px;
16 | background-color: transparent;
17 | }
18 | ::-webkit-scrollbar-thumb {
19 | border-radius: 5px;
20 | background-color: hsla(220, 4%, 58%, .3);
21 | }
22 | }
23 |
24 | @mixin radius($width, $size, $color) {
25 | width: $width;
26 | height: $width;
27 | line-height: $width;
28 | border-radius: $width;
29 | text-align: center;
30 | border-width: $size;
31 | border-style: solid;
32 | border-color: $color;
33 | }
34 |
35 | @mixin relative {
36 | position: relative;
37 | width: 100%;
38 | height: 100%;
39 | }
40 |
41 | @mixin pct($pct) {
42 | width: #{$pct};
43 | position: relative;
44 | margin: 0 auto;
45 | }
46 |
47 | @mixin triangle($width, $height, $color, $direction) {
48 | $width: $width/2;
49 | $color-border-style: $height solid $color;
50 | $transparent-border-style: $width solid transparent;
51 | height: 0;
52 | width: 0;
53 | @if $direction==up {
54 | border-bottom: $color-border-style;
55 | border-left: $transparent-border-style;
56 | border-right: $transparent-border-style;
57 | }
58 | @else if $direction==right {
59 | border-left: $color-border-style;
60 | border-top: $transparent-border-style;
61 | border-bottom: $transparent-border-style;
62 | }
63 | @else if $direction==down {
64 | border-top: $color-border-style;
65 | border-left: $transparent-border-style;
66 | border-right: $transparent-border-style;
67 | }
68 | @else if $direction==left {
69 | border-right: $color-border-style;
70 | border-top: $transparent-border-style;
71 | border-bottom: $transparent-border-style;
72 | }
73 | }
--------------------------------------------------------------------------------
/src/styles/sidebar.scss:
--------------------------------------------------------------------------------
1 | .avue-sidebar {
2 | user-select: none;
3 | position: relative;
4 | padding-top: 74px;
5 | height: 100%;
6 | position: relative;
7 | background-color: #20222a;
8 | transition: width .2s;
9 | box-sizing: border-box;
10 | box-shadow: 2px 0 6px rgba(0,21,41,.35);
11 | &--tip{
12 | width:90%;
13 | height: 140px;
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 | border-radius: 5px;
18 | position: absolute;
19 | top:5px;
20 | left:5%;
21 | color:#ccc;
22 | z-index: 2;
23 | text-align: center;
24 | font-size: 14px;
25 | background-color: rgba(0,0,0,.4);
26 | }
27 | .el-menu-item,
28 | .el-submenu__title {
29 | font-size: 14px;
30 | height: 56px;
31 | line-height: 56px;
32 | }
33 | .el-menu-item {
34 | span,i{
35 | color:rgba(255, 255, 255, 0.7);
36 | }
37 | &:hover {
38 | background-color: transparent;
39 | color: #fff;
40 | span,
41 | i {
42 | color: #fff;
43 | }
44 | }
45 | &.is-active {
46 | background-color: rgba(0, 0, 0, .8);
47 | span,
48 | i {
49 | color: #fff;
50 | }
51 | &:hover {
52 | background-color: rgba(0, 0, 0, .8);
53 | }
54 | &::before {
55 | content: " ";
56 | top: 0;
57 | left: 0;
58 | bottom: 0;
59 | width: 4px;
60 | background: $mainBg;
61 | position: absolute
62 | }
63 | }
64 | }
65 | .el-submenu__title {
66 | span,i{
67 | color:rgba(255, 255, 255, 0.7);
68 | }
69 | &:hover {
70 | i,
71 | span {
72 | color: #fff;
73 | }
74 | background-color:transparent ;
75 | }
76 | }
77 | .el-submenu .el-menu-item {
78 | height: 50px;
79 | line-height: 50px;
80 | span,i{
81 | color:rgba(255, 255, 255, 0.7);
82 | }
83 | &.is-active {
84 | background-color: rgba(0, 0, 0, .8);
85 | span,
86 | i {
87 | color: #fff
88 | }
89 | &:hover {
90 | background-color: rgba(0, 0, 0, .8);
91 | }
92 | }
93 | &:hover {
94 | background-color: transparent;
95 | span,
96 | i {
97 | color: #fff;
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/src/styles/tags.scss:
--------------------------------------------------------------------------------
1 |
2 |
3 | .avue-tags {
4 | user-select: none;
5 | position: relative;
6 | padding: 0 10px;
7 | margin-bottom: 10px;
8 | box-sizing: border-box;
9 | overflow: hidden;
10 | border-top: 1px solid #f6f6f6;
11 | background-color: #fff;
12 | box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .05);
13 | .el-tabs--card>.el-tabs__header {
14 | margin: 0;
15 | }
16 | .el-tabs--card>.el-tabs__header .el-tabs__nav,
17 | .el-tabs--card>.el-tabs__header .el-tabs__item,
18 | .el-tabs--card>.el-tabs__header {
19 | border: none;
20 | }
21 | .el-tabs--card>.el-tabs__header .el-tabs__item:first-child {
22 | border-left-width: 1px
23 | }
24 | .el-tabs--card>.el-tabs__header .el-tabs__item {
25 | margin: 0 3px;
26 | height: 40px;
27 | line-height:40px;
28 | font-size: 13px;
29 | font-weight: normal;
30 | color: #ccc;
31 | &.is-active {
32 | color: #409EFF;
33 | border-bottom: 3px solid #409EFF;
34 | }
35 | }
36 | .el-tabs__nav-prev,
37 | .el-tabs__nav-next {
38 | width: 20px;
39 | line-height: 34px;
40 | font-size: 18x;
41 | text-align: center;
42 | }
43 | &__box {
44 | position: relative;
45 | box-sizing: border-box;
46 | padding-right: 106px;
47 | width: 100%;
48 | &--close {
49 | .el-tabs__item {
50 | &:first-child {
51 | padding: 0 20px !important;
52 | .el-icon-close {
53 | display: none;
54 | }
55 | }
56 | }
57 | }
58 | }
59 | &__contentmenu{
60 | position: fixed;
61 | width:120px;
62 | background-color: #fff;
63 | z-index:1024;
64 | border-radius: 5px;
65 | box-shadow: 1px 2px 10px #ccc;
66 | .item{
67 | cursor: pointer;
68 | font-size: 14px;
69 | padding: 8px 20px 8px 15px;
70 | color: #606266;
71 | &:first-child{
72 | border-top-left-radius: 5px;
73 | border-top-right-radius: 5px;
74 | }
75 | &:last-child{
76 | border-bottom-left-radius: 5px;
77 | border-bottom-right-radius: 5px;
78 | }
79 | &:hover{
80 | background-color: #409EFF;
81 | color:#fff;
82 | }
83 | }
84 | }
85 | &__menu {
86 | position: absolute !important;
87 | top: 3px;
88 | right: 0;
89 | padding: 1px 0 0 15px;
90 | box-sizing: border-box;
91 | }
92 | }
--------------------------------------------------------------------------------
/src/styles/top.scss:
--------------------------------------------------------------------------------
1 | .avue-top {
2 | padding: 0 20px;
3 | position: relative;
4 | box-shadow: 0 1px 4px rgba(0,21,41,.08);
5 | color: rgba(0, 0, 0, .65);
6 | font-size: 28px;
7 | height: 64px;
8 | box-sizing: border-box;
9 | white-space: nowrap;
10 | .el-menu-item{
11 | i,span{
12 | font-size: 13px;
13 | }
14 | }
15 | }
16 | .avue-breadcrumb {
17 | height: 100%;
18 | i{
19 | font-size: 30px !important;
20 | }
21 | &--active {
22 | transform:rotate(90deg);
23 | }
24 | }
25 |
26 | .top-menu {
27 | box-sizing: border-box;
28 | .el-menu-item {
29 | padding: 0 10px;
30 | border:none !important;
31 | }
32 | }
33 |
34 | .top-search {
35 | line-height: 64px;
36 | position: absolute !important;
37 | left: 20px;
38 | top:0;
39 | width: 400px !important;
40 | .el-input__inner {
41 | font-size: 13px;
42 | border: none;
43 | background-color: transparent;
44 | }
45 | }
46 |
47 | .top-bar__img {
48 | margin: 0 8px 0 5px;
49 | padding: 2px;
50 | width: 30px;
51 | height: 30px;
52 | border-radius: 100%;
53 | box-sizing: border-box;
54 | border: 1px solid #eee;
55 | vertical-align: middle;
56 | }
57 |
58 | .top-bar__left,
59 | .top-bar__right {
60 | height: 64px;
61 | position: absolute;
62 | top: 0;
63 | i{
64 | line-height: 64px;
65 | }
66 | }
67 |
68 | .top-bar__left {
69 | left: 20px;
70 | }
71 |
72 | .top-bar__right {
73 | right: 20px;
74 | display: flex;
75 | align-items: center;
76 | }
77 |
78 | .top-bar__item {
79 | position: relative;
80 | display: inline-block;
81 | height: 64px;
82 | margin:0 10px;
83 | font-size: 16px;
84 | &--show {
85 | display: inline-block !important;
86 | }
87 | .el-badge__content.is-fixed{
88 | top:12px;
89 | right: 5px;
90 | }
91 | }
92 |
93 | .top-bar__title {
94 | height: 100%;
95 | padding:0 40px;
96 | box-sizing: border-box;
97 | overflow: hidden;
98 | text-overflow: ellipsis;
99 | white-space: nowrap;
100 | font-size: inherit;
101 | font-weight: 400;
102 | }
103 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | //main
2 | $mainBg: #409eff;
3 |
--------------------------------------------------------------------------------
/src/util/admin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | getScreen: function () {
3 | var width = document.body.clientWidth
4 | if (width >= 1200) {
5 | return 3 // 大屏幕
6 | } else if (width >= 992) {
7 | return 2 // 中屏幕
8 | } else if (width >= 768) {
9 | return 1 // 小屏幕
10 | } else {
11 | return 0 // 超小屏幕
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/util/date.js:
--------------------------------------------------------------------------------
1 | export const calcDate = (date1, date2) => {
2 | var date3 = date2 - date1
3 |
4 | var days = Math.floor(date3 / (24 * 3600 * 1000))
5 |
6 | var leave1 = date3 % (24 * 3600 * 1000) // 计算天数后剩余的毫秒数
7 | var hours = Math.floor(leave1 / (3600 * 1000))
8 |
9 | var leave2 = leave1 % (3600 * 1000) // 计算小时数后剩余的毫秒数
10 | var minutes = Math.floor(leave2 / (60 * 1000))
11 |
12 | var leave3 = leave2 % (60 * 1000) // 计算分钟数后剩余的毫秒数
13 | var seconds = Math.round(date3 / 1000)
14 | return {
15 | leave1,
16 | leave2,
17 | leave3,
18 | days: days,
19 | hours: hours,
20 | minutes: minutes,
21 | seconds: seconds
22 | }
23 | }
24 |
25 | /**
26 | * 日期格式化
27 | */
28 | export function dateFormat(date) {
29 | let format = 'yyyy-MM-dd hh:mm:ss';
30 | if (date != 'Invalid Date') {
31 | var o = {
32 | "M+": date.getMonth() + 1, //month
33 | "d+": date.getDate(), //day
34 | "h+": date.getHours(), //hour
35 | "m+": date.getMinutes(), //minute
36 | "s+": date.getSeconds(), //second
37 | "q+": Math.floor((date.getMonth() + 3) / 3), //quarter
38 | "S": date.getMilliseconds() //millisecond
39 | }
40 | if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
41 | (date.getFullYear() + "").substr(4 - RegExp.$1.length));
42 | for (var k in o)
43 | if (new RegExp("(" + k + ")").test(format))
44 | format = format.replace(RegExp.$1,
45 | RegExp.$1.length == 1 ? o[k] :
46 | ("00" + o[k]).substr(("" + o[k]).length));
47 | return format;
48 | }
49 | return '';
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/util/store.js:
--------------------------------------------------------------------------------
1 | import {
2 | validatenull
3 | } from '@/util/validate'
4 | import website from '@/const/website'
5 |
6 | const keyName = website.key + '-';
7 | /**
8 | * 存储localStorage
9 | */
10 | export const setStore = (params = {}) => {
11 | let {
12 | name,
13 | content,
14 | type,
15 | } = params;
16 | name = keyName + name
17 | let obj = {
18 | dataType: typeof (content),
19 | content: content,
20 | type: type,
21 | datetime: new Date().getTime()
22 | }
23 | if (type) window.sessionStorage.setItem(name, JSON.stringify(obj));
24 | else window.localStorage.setItem(name, JSON.stringify(obj));
25 | }
26 | /**
27 | * 获取localStorage
28 | */
29 |
30 | export const getStore = (params = {}) => {
31 | let {
32 | name,
33 | debug
34 | } = params;
35 | name = keyName + name
36 | let obj = {},
37 | content;
38 | obj = window.sessionStorage.getItem(name);
39 | if (validatenull(obj)) obj = window.localStorage.getItem(name);
40 | if (validatenull(obj)) return;
41 | try {
42 | obj = JSON.parse(obj);
43 | } catch{
44 | return obj;
45 | }
46 | if (debug) {
47 | return obj;
48 | }
49 | if (obj.dataType == 'string') {
50 | content = obj.content;
51 | } else if (obj.dataType == 'number') {
52 | content = Number(obj.content);
53 | } else if (obj.dataType == 'boolean') {
54 | content = eval(obj.content);
55 | } else if (obj.dataType == 'object') {
56 | content = obj.content;
57 | }
58 | return content;
59 | }
60 | /**
61 | * 删除localStorage
62 | */
63 | export const removeStore = (params = {}) => {
64 | let {
65 | name,
66 | type
67 | } = params;
68 | name = keyName + name
69 | if (type) {
70 | window.sessionStorage.removeItem(name);
71 | } else {
72 | window.localStorage.removeItem(name);
73 | }
74 |
75 | }
76 |
77 | /**
78 | * 获取全部localStorage
79 | */
80 | export const getAllStore = (params = {}) => {
81 | let list = [];
82 | let {
83 | type
84 | } = params;
85 | if (type) {
86 | for (let i = 0; i <= window.sessionStorage.length; i++) {
87 | list.push({
88 | name: window.sessionStorage.key(i),
89 | content: getStore({
90 | name: window.sessionStorage.key(i),
91 | type: 'session'
92 | })
93 | })
94 | }
95 | } else {
96 | for (let i = 0; i <= window.localStorage.length; i++) {
97 | list.push({
98 | name: window.localStorage.key(i),
99 | content: getStore({
100 | name: window.localStorage.key(i),
101 | })
102 | })
103 |
104 | }
105 | }
106 | return list;
107 |
108 | }
109 |
110 | /**
111 | * 清空全部localStorage
112 | */
113 | export const clearStore = (params = {}) => {
114 | let { type } = params;
115 | if (type) {
116 | window.sessionStorage.clear();
117 | } else {
118 | window.localStorage.clear()
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/util/validate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 邮箱
3 | * @param {*} s
4 | */
5 | export function isEmail (s) {
6 | return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s)
7 | }
8 |
9 | /**
10 | * 手机号码
11 | * @param {*} s
12 | */
13 | export function isMobile (s) {
14 | return /^1[0-9]{10}$/.test(s)
15 | }
16 |
17 | /**
18 | * 电话号码
19 | * @param {*} s
20 | */
21 | export function isPhone (s) {
22 | return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
23 | }
24 |
25 | /**
26 | * URL地址
27 | * @param {*} s
28 | */
29 | export function isURL (s) {
30 | return /^http[s]?:\/\/.*/.test(s)
31 | }
32 |
33 | export function isvalidUsername (str) {
34 | const valid_map = ['admin', 'editor']
35 | return valid_map.indexOf(str.trim()) >= 0
36 | }
37 |
38 | /* 合法uri */
39 | export function validateURL (textval) {
40 | const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
41 | return urlregex.test(textval)
42 | }
43 |
44 | /* 小写字母 */
45 | export function validateLowerCase (str) {
46 | const reg = /^[a-z]+$/
47 | return reg.test(str)
48 | }
49 |
50 | /* 大写字母 */
51 | export function validateUpperCase (str) {
52 | const reg = /^[A-Z]+$/
53 | return reg.test(str)
54 | }
55 |
56 | /* 大小写字母 */
57 | export function validatAlphabets (str) {
58 | const reg = /^[A-Za-z]+$/
59 | return reg.test(str)
60 | }
61 |
62 | /* 验证pad还是pc */
63 | export const vaildatePc = function () {
64 | const userAgentInfo = navigator.userAgent
65 | const Agents = ['Android', 'iPhone',
66 | 'SymbianOS', 'Windows Phone',
67 | 'iPad', 'iPod'
68 | ]
69 | let flag = true
70 | for (var v = 0; v < Agents.length; v++) {
71 | if (userAgentInfo.indexOf(Agents[v]) > 0) {
72 | flag = false
73 | break
74 | }
75 | }
76 | return flag
77 | }
78 |
79 | /**
80 | * validate email
81 | * @param email
82 | * @returns {boolean}
83 | */
84 | export function validateEmail (email) {
85 | const re = /^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
86 | return re.test(email)
87 | }
88 |
89 | /**
90 | * 判断身份证号码
91 | */
92 | export function cardid (code) {
93 | let list = []
94 | let result = true
95 | let msg = ''
96 | var city = {
97 | 11: '北京',
98 | 12: '天津',
99 | 13: '河北',
100 | 14: '山西',
101 | 15: '内蒙古',
102 | 21: '辽宁',
103 | 22: '吉林',
104 | 23: '黑龙江 ',
105 | 31: '上海',
106 | 32: '江苏',
107 | 33: '浙江',
108 | 34: '安徽',
109 | 35: '福建',
110 | 36: '江西',
111 | 37: '山东',
112 | 41: '河南',
113 | 42: '湖北 ',
114 | 43: '湖南',
115 | 44: '广东',
116 | 45: '广西',
117 | 46: '海南',
118 | 50: '重庆',
119 | 51: '四川',
120 | 52: '贵州',
121 | 53: '云南',
122 | 54: '西藏 ',
123 | 61: '陕西',
124 | 62: '甘肃',
125 | 63: '青海',
126 | 64: '宁夏',
127 | 65: '新疆',
128 | 71: '台湾',
129 | 81: '香港',
130 | 82: '澳门',
131 | 91: '国外 '
132 | }
133 | if (!validatenull(code)) {
134 | if (code.length == 18) {
135 | if (!code || !/(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(code)) {
136 | msg = '证件号码格式错误'
137 | } else if (!city[code.substr(0, 2)]) {
138 | msg = '地址编码错误'
139 | } else {
140 | // 18位身份证需要验证最后一位校验位
141 | code = code.split('')
142 | // ∑(ai×Wi)(mod 11)
143 | // 加权因子
144 | var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
145 | // 校验位
146 | var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2, 'x']
147 | var sum = 0
148 | var ai = 0
149 | var wi = 0
150 | for (var i = 0; i < 17; i++) {
151 | ai = code[i]
152 | wi = factor[i]
153 | sum += ai * wi
154 | }
155 | if (parity[sum % 11] != code[17]) {
156 | msg = '证件号码校验位错误'
157 | } else {
158 | result = false
159 | }
160 | }
161 | } else {
162 | msg = '证件号码长度不为18位'
163 | }
164 | } else {
165 | msg = '证件号码不能为空'
166 | }
167 | list.push(result)
168 | list.push(msg)
169 | return list
170 | }
171 |
172 | /**
173 | * 判断手机号码是否正确
174 | */
175 | export function isvalidatemobile (phone) {
176 | let list = []
177 | let result = true
178 | let msg = ''
179 | var isPhone = /^0\d{2,3}-?\d{7,8}$/
180 | // 增加134 减少|1349[0-9]{7},增加181,增加145,增加17[678]
181 | if (!validatenull(phone)) {
182 | if (phone.length == 11) {
183 | if (isPhone.test(phone)) {
184 | msg = '手机号码格式不正确'
185 | } else {
186 | result = false
187 | }
188 | } else {
189 | msg = '手机号码长度不为11位'
190 | }
191 | } else {
192 | msg = '手机号码不能为空'
193 | }
194 | list.push(result)
195 | list.push(msg)
196 | return list
197 | }
198 |
199 | /**
200 | * 判断姓名是否正确
201 | */
202 | export function validatename (name) {
203 | var regName = /^[\u4e00-\u9fa5]{2,4}$/
204 | if (!regName.test(name)) return false
205 | return true
206 | }
207 |
208 | /**
209 | * 判断是否为整数
210 | */
211 | export function validatenum (num, type) {
212 | let regName = /[^\d.]/g
213 | if (type == 1) {
214 | if (!regName.test(num)) return false
215 | } else if (type == 2) {
216 | regName = /[^\d]/g
217 | if (!regName.test(num)) return false
218 | }
219 | return true
220 | }
221 |
222 | /**
223 | * 判断是否为小数
224 | */
225 | export function validatenumord (num, type) {
226 | let regName = /[^\d.]/g
227 | if (type == 1) {
228 | if (!regName.test(num)) return false
229 | } else if (type == 2) {
230 | regName = /[^\d.]/g
231 | if (!regName.test(num)) return false
232 | }
233 | return true
234 | }
235 |
236 | /**
237 | * 判断是否为空
238 | */
239 | export function validatenull (val) {
240 | if (typeof val === 'boolean') {
241 | return false
242 | }
243 | if (typeof val === 'number') {
244 | return false
245 | }
246 | if (val instanceof Array) {
247 | if (val.length == 0) return true
248 | } else if (val instanceof Object) {
249 | if (JSON.stringify(val) === '{}') return true
250 | } else {
251 | if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true
252 | return false
253 | }
254 | return false
255 | }
256 |
--------------------------------------------------------------------------------
/src/views/admin/client/index.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
38 |
39 |
40 |
127 |
128 |
130 |
131 |
--------------------------------------------------------------------------------
/src/views/admin/log/index.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
36 |
37 |
38 |
106 |
--------------------------------------------------------------------------------
/src/views/admin/menu/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 | 添加
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 菜单
30 | 按钮
31 |
32 |
33 |
34 |
35 | 关闭
36 | 开启
37 |
38 |
39 |
40 |
41 |
42 | 添加
47 |
48 | 修改
52 |
53 | 删除
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
119 |
--------------------------------------------------------------------------------
/src/views/admin/menu/menu-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 | 菜单
11 | 按钮
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | 否
48 | 是
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
175 |
--------------------------------------------------------------------------------
/src/views/admin/token/index.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
35 |
36 |
37 |
99 |
100 |
--------------------------------------------------------------------------------
/src/views/gen/datasource.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
37 |
38 |
39 |
126 |
127 |
129 |
130 |
--------------------------------------------------------------------------------
/src/views/gen/design.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
53 |
69 |
--------------------------------------------------------------------------------
/src/views/gen/form.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
37 |
38 |
39 |
132 |
133 |
135 |
--------------------------------------------------------------------------------
/src/views/gen/preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
38 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 配置该文件可以参考:
3 | * https://cli.vuejs.org/zh/config/#%E7%9B%AE%E6%A0%87%E6%B5%8F%E8%A7%88%E5%99%A8
4 | *
5 | */
6 | const url = process.env.VUE_APP_API_URL
7 | // 基础路径,发布前修改这里,当前配置打包出来的资源都是相对路径
8 | let publicPath = './'
9 | module.exports = {
10 | publicPath: publicPath,
11 | lintOnSave: true,
12 | productionSourceMap: false,
13 | css: {
14 | // 忽略 CSS order 顺序警告
15 | extract: { ignoreOrder: true }
16 | },
17 | chainWebpack: config => {
18 | const entry = config.entry('app')
19 | entry
20 | .add('babel-polyfill')
21 | .end()
22 | entry
23 | .add('classlist-polyfill')
24 | .end()
25 | },
26 | // 配置转发代理
27 | devServer: {
28 | proxy: {
29 | '/': {
30 | target: url,
31 | ws: true,
32 | pathRewrite: {
33 | '^/': '/'
34 | }
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------