├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── deploy.sh ├── package.json ├── public ├── index.html └── logo │ └── umi-soft.svg ├── src ├── App.vue ├── api │ ├── login.js │ └── system-management │ │ ├── dept.js │ │ ├── deptRole.js │ │ ├── dictionary.js │ │ ├── group.js │ │ ├── menu.js │ │ ├── menuRole.js │ │ ├── menuSecurity.js │ │ ├── role.js │ │ ├── roleGroup.js │ │ ├── security.js │ │ ├── user.js │ │ ├── userDept.js │ │ ├── userGroup.js │ │ ├── userGroupRoleGroup.js │ │ ├── userRole.js │ │ └── userRoleGroup.js ├── assets │ ├── custom-theme │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ └── index.css │ └── images │ │ ├── 404.png │ │ ├── 404_cloud.png │ │ └── avatar.jpeg ├── components │ ├── Abbreviation │ │ └── index.vue │ ├── Breadcrumb │ │ └── index.vue │ ├── ErrorPage │ │ ├── 401.vue │ │ └── 404.vue │ ├── Hamburger │ │ └── index.vue │ ├── Redirect │ │ └── index.vue │ ├── Screenfull │ │ └── index.vue │ ├── ScrollPane │ │ └── index.vue │ └── SvgIcon │ │ └── index.vue ├── directive │ ├── clipboard │ │ ├── clipboard.js │ │ └── index.js │ ├── el-dragDialog │ │ ├── drag.js │ │ └── index.js │ └── permission │ │ ├── index.js │ │ └── permission.js ├── filters │ └── index.js ├── icons │ ├── index.js │ ├── svg │ │ ├── 404.svg │ │ ├── add.svg │ │ ├── captcha.svg │ │ ├── check.svg │ │ ├── del.svg │ │ ├── dept.svg │ │ ├── dictionary-multi.svg │ │ ├── dictionary-setting.svg │ │ ├── dictionary-single.svg │ │ ├── dictionary-type.svg │ │ ├── edit.svg │ │ ├── eye.svg │ │ ├── group.svg │ │ ├── index.svg │ │ ├── java.svg │ │ ├── menu-setting.svg │ │ ├── menu.svg │ │ ├── password.svg │ │ ├── role-setting.svg │ │ ├── security.svg │ │ ├── setting.svg │ │ ├── user-group.svg │ │ ├── user-role.svg │ │ ├── user-setting.svg │ │ ├── user.svg │ │ └── utils.svg │ └── svgo.yml ├── main.js ├── mock │ ├── MockDB.js │ ├── index.js │ ├── login.js │ ├── system-management │ │ ├── dept.js │ │ ├── deptRole.js │ │ ├── dictionary.js │ │ ├── group.js │ │ ├── menu.js │ │ ├── menuRole.js │ │ ├── menuSecurity.js │ │ ├── role.js │ │ ├── roleGroup.js │ │ ├── security.js │ │ ├── user.js │ │ ├── userDept.js │ │ ├── userGroup.js │ │ ├── userGroupRoleGroup.js │ │ ├── userRole.js │ │ └── userRoleGroup.js │ └── utils.js ├── permission.js ├── router │ ├── index.js │ └── modules │ │ ├── CodeGenerator.js │ │ └── SystemManagement.js ├── store │ ├── getters.js │ ├── index.js │ └── modules │ │ ├── app.js │ │ ├── dictionaries.js │ │ ├── permission.js │ │ ├── tagsView.js │ │ └── user.js ├── styles │ ├── element-ui.scss │ ├── index.scss │ ├── mixin.scss │ └── transition.scss ├── utils │ ├── auth.js │ ├── clipboard.js │ ├── index.js │ ├── openWindow.js │ ├── permission.js │ ├── request.js │ ├── scrollTo.js │ └── validate.js └── views │ ├── code-generator │ └── main.vue │ ├── common │ ├── components │ │ ├── auditInfo │ │ │ └── auditInfo.vue │ │ ├── buttons │ │ │ ├── ButtonRight.vue │ │ │ └── NewLineButtonRight.vue │ │ ├── dictionaryTranslates │ │ │ └── State.vue │ │ ├── formItemViews │ │ │ ├── InputItemView.vue │ │ │ └── TextItemView.vue │ │ ├── layouts │ │ │ ├── FlexCenter.vue │ │ │ ├── FlexLeft.vue │ │ │ └── FlexRight.vue │ │ ├── paginations │ │ │ └── pagination.vue │ │ └── selects │ │ │ └── SelectRight.vue │ ├── index.js │ └── mixins │ │ ├── BaseEditForm.js │ │ └── BaseQueryPageForm.js │ ├── dashboard │ └── index.vue │ ├── layout │ ├── LeftAccordionSidebar │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ ├── Sidebar │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ ├── TagsView.vue │ │ │ └── index.js │ │ └── index.vue │ └── MenuGroup │ │ └── index.vue │ ├── login │ └── index.vue │ └── system-management │ ├── dept │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ ├── dictionary-type │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ ├── dictionary │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── mixins.js │ ├── multiMain.vue │ ├── multiQuery.vue │ ├── singleMain.vue │ └── singleQuery.vue │ ├── group │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ ├── menu │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ ├── role │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ ├── security │ ├── add.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ └── query.vue │ └── user │ ├── add.vue │ ├── batchEdit.vue │ ├── check.vue │ ├── edit.vue │ ├── main.vue │ ├── mixins.js │ ├── myself │ └── modify.vue │ └── query.vue └── vue.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | test/unit/coverage 10 | test/e2e/reports 11 | selenium-debug.log 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | 21 | package-lock.json 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present PanJiaChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | vue 4 | 5 | 6 | element-ui 7 | 8 | 9 | Build Status 10 | 11 | 12 | license 13 | 14 | 15 | GitHub release 16 | 17 |

18 | 19 | ## Getting started 20 | 21 | ```bash 22 | # clone the project 23 | git clone https://github.com/umi-soft/element-admin.git 24 | 25 | # install dependency 26 | npm install 27 | 28 | # develop 29 | npm run dev 30 | ``` 31 | 32 | ## Build 33 | 34 | ```bash 35 | # build for test environment 36 | npm run build:sit 37 | 38 | # build for production environment 39 | npm run build:prod 40 | ``` 41 | 42 | ## Online 43 | [Preview](http://umi-soft.github.io/element-admin) 44 | 45 | ## Browsers support 46 | 47 | Modern browsers and Internet Explorer 10+. 48 | 49 | | [IE / Edge](http://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | 50 | | --------- | --------- | --------- | --------- | 51 | | IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions 52 | 53 | ## 2.x计划 54 | 55 | - 提供更多的页面布局模板,目前仅一种模板 56 | - 提供后端spring-boot开源工程 57 | - 微调数据库字段设计,比如废弃state字段,flag字段调整为deleted,增加后端API安全资源表等等 58 | - 升级vue-cli至3.x 59 | 60 | ## License 61 | 62 | [MIT](https://github.com/umi-soft/element-admin/blob/master/LICENSE) 63 | 64 | Copyright (c) 2018-present [一路向北](https://umi-soft.github.com) 65 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run build:prod 8 | 9 | # 进入生成的文件夹 10 | cd dist 11 | 12 | #创建.nojekyll 防止Github Pages build错误 13 | touch .nojekyll 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | git push -f "https://github.com/umi-soft/element-admin.git" master:gh-pages 20 | 21 | cd - 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "element-admin", 3 | "version": "1.0.5", 4 | "description": "基础", 5 | "author": "胡杰", 6 | "license": "MIT", 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "build": "vue-cli-service build", 10 | "lint": "vue-cli-service lint", 11 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" 12 | }, 13 | "lint-staged": { 14 | "src/**/*.{js,vue}": [ 15 | "eslint --fix", 16 | "git add" 17 | ] 18 | }, 19 | "keywords": [ 20 | "vue", 21 | "element-ui", 22 | "admin", 23 | "element-admin" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/umi-soft/element-admin.git" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/umi-soft/element-admin/issues" 31 | }, 32 | "dependencies": { 33 | "axios": "0.18.0", 34 | "clipboard": "1.7.1", 35 | "element-ui": "2.4.6", 36 | "es6-uuid": "^1.0.1", 37 | "js-cookie": "2.2.0", 38 | "lodash": "^4.17.11", 39 | "mockjs": "1.0.1-beta3", 40 | "normalize.css": "7.0.0", 41 | "nprogress": "0.2.0", 42 | "path-to-regexp": "^2.4.0", 43 | "qs": "^6.6.0", 44 | "screenfull": "3.3.3", 45 | "svg-sprite-loader": "^4.1.3", 46 | "svgo": "1.0.5", 47 | "vue": "^2.5.22", 48 | "vue-count-to": "1.0.13", 49 | "vue-router": "3.0.1", 50 | "vue-splitpane": "1.0.2", 51 | "vuex": "3.0.1" 52 | }, 53 | "devDependencies": { 54 | "@vue/cli-plugin-babel": "^3.4.0", 55 | "@vue/cli-plugin-eslint": "^3.4.0", 56 | "@vue/cli-service": "^3.4.0", 57 | "babel-eslint": "^10.0.1", 58 | "eslint": "^5.8.0", 59 | "eslint-plugin-vue": "^5.0.0", 60 | "node-sass": "^4.11.0", 61 | "sass-loader": "^7.1.0", 62 | "vue-template-compiler": "^2.5.21" 63 | }, 64 | "eslintConfig": { 65 | "root": true, 66 | "env": { 67 | "node": true 68 | }, 69 | "extends": [ 70 | "plugin:vue/essential", 71 | "eslint:recommended" 72 | ], 73 | "rules": { 74 | "no-console": "off", 75 | "vue/no-use-v-if-with-v-for": "off" 76 | }, 77 | "parserOptions": { 78 | "parser": "babel-eslint" 79 | } 80 | }, 81 | "postcss": { 82 | "plugins": { 83 | "autoprefixer": {} 84 | } 85 | }, 86 | "engines": { 87 | "node": ">= 6.0.0", 88 | "npm": ">= 3.0.0" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | UMI-SOFT 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/auth/' 4 | 5 | export function captcha() { 6 | return request({ 7 | url: base_url + 'captcha', 8 | method: 'get' 9 | }) 10 | } 11 | 12 | export function loginByLoginName(data) { 13 | return request({ 14 | url: base_url + 'login', 15 | method: 'post', 16 | data 17 | }) 18 | } 19 | 20 | export function getUserInfo(token) { 21 | return request({ 22 | url: base_url + 'user-authorities', 23 | method: 'get', 24 | data: { token } 25 | }) 26 | } 27 | 28 | export function getRouterRoles(token) { 29 | return request({ 30 | url: base_url + 'system-authorities', 31 | method: 'get', 32 | data: { token } 33 | }) 34 | } 35 | 36 | export function logout(token) { 37 | return request({ 38 | url: base_url + 'logout', 39 | method: 'get', 40 | data: { token } 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /src/api/system-management/dept.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/dept/' 4 | 5 | export function queryAllDepts(data) { 6 | return request({ 7 | url: base_url + 'query-all', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryAllTreeDepts(id) { 14 | return request({ 15 | url: base_url + 'query-all-tree', 16 | method: 'get', 17 | data: { id } 18 | }) 19 | } 20 | 21 | export function queryDeptById(id) { 22 | return request({ 23 | url: base_url + 'query-by-id', 24 | method: 'get', 25 | data: { id } 26 | }) 27 | } 28 | 29 | export function addDept(data) { 30 | return request({ 31 | url: base_url + 'add', 32 | method: 'post', 33 | data 34 | }) 35 | } 36 | 37 | export function editDept(data) { 38 | return request({ 39 | url: base_url + 'edit', 40 | method: 'post', 41 | data 42 | }) 43 | } 44 | 45 | export function delDept(id) { 46 | return request({ 47 | url: base_url + 'del', 48 | method: 'post', 49 | data: { id } 50 | }) 51 | } 52 | 53 | export function queryAllDeptUsers(id) { 54 | return request({ 55 | url: base_url + 'all-users', 56 | method: 'get', 57 | data: { id } 58 | }) 59 | } 60 | 61 | export function queryAllDeptRoles(id) { 62 | return request({ 63 | url: base_url + 'all-roles', 64 | method: 'get', 65 | data: { id } 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /src/api/system-management/deptRole.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/dept-role/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function delByEntityMapping(data) { 14 | return request({ 15 | url: base_url + 'del-by-entity-mapping', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/api/system-management/dictionary.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/dictionary/' 4 | 5 | export function queryPageDictionaries(data) { 6 | return request({ 7 | url: base_url + 'query-page', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryAllDictionaries(data) { 14 | return request({ 15 | url: base_url + 'query-all', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function queryDictionaryById(id) { 22 | return request({ 23 | url: base_url + 'query-by-id', 24 | method: 'get', 25 | data: { id } 26 | }) 27 | } 28 | 29 | export function addDictionary(data) { 30 | return request({ 31 | url: base_url + 'add', 32 | method: 'post', 33 | data 34 | }) 35 | } 36 | 37 | export function editDictionary(data) { 38 | return request({ 39 | url: base_url + 'edit', 40 | method: 'post', 41 | data 42 | }) 43 | } 44 | 45 | export function delDictionary(id) { 46 | return request({ 47 | url: base_url + 'del', 48 | method: 'post', 49 | data: { id } 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /src/api/system-management/group.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/group/' 4 | 5 | export function queryPageGroups(data) { 6 | return request({ 7 | url: base_url + 'query-page', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryAllGroups(data) { 14 | return request({ 15 | url: base_url + 'query-all', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function queryGroupById(id) { 22 | return request({ 23 | url: base_url + 'query-by-id', 24 | method: 'get', 25 | data: { id } 26 | }) 27 | } 28 | 29 | export function addGroup(data) { 30 | return request({ 31 | url: base_url + 'add', 32 | method: 'post', 33 | data 34 | }) 35 | } 36 | 37 | export function editGroup(data) { 38 | return request({ 39 | url: base_url + 'edit', 40 | method: 'post', 41 | data 42 | }) 43 | } 44 | 45 | export function delGroup(id) { 46 | return request({ 47 | url: base_url + 'del', 48 | method: 'post', 49 | data: { id } 50 | }) 51 | } 52 | 53 | export function queryAllRoleGroupUsers(id) { 54 | return request({ 55 | url: base_url + 'all-role-group-users', 56 | method: 'get', 57 | data: { id } 58 | }) 59 | } 60 | 61 | export function queryAllUserGroupUsers(id) { 62 | return request({ 63 | url: base_url + 'all-user-group-users', 64 | method: 'get', 65 | data: { id } 66 | }) 67 | } 68 | 69 | export function queryAllRoleGroups(id) { 70 | return request({ 71 | url: base_url + 'all-role-groups', 72 | method: 'get', 73 | data: { id } 74 | }) 75 | } 76 | 77 | export function queryAllUserGroups(id) { 78 | return request({ 79 | url: base_url + 'all-user-groups', 80 | method: 'get', 81 | data: { id } 82 | }) 83 | } 84 | 85 | export function queryAllGroupRoles(id) { 86 | return request({ 87 | url: base_url + 'all-roles', 88 | method: 'get', 89 | data: { id } 90 | }) 91 | } 92 | -------------------------------------------------------------------------------- /src/api/system-management/menuRole.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/menu-role/' 4 | 5 | export function delByEntityMapping(data) { 6 | return request({ 7 | url: base_url + 'del-by-entity-mapping', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/api/system-management/menuSecurity.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/menu-security/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function delByEntityMapping(data) { 14 | return request({ 15 | url: base_url + 'del-by-entity-mapping', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/api/system-management/role.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/role/' 4 | 5 | export function queryPageRoles(data) { 6 | return request({ 7 | url: base_url + 'query-page', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryAllRoles(data) { 14 | return request({ 15 | url: base_url + 'query-all', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function queryRoleById(id) { 22 | return request({ 23 | url: base_url + 'query-by-id', 24 | method: 'get', 25 | data: { id } 26 | }) 27 | } 28 | 29 | export function addRole(data) { 30 | return request({ 31 | url: base_url + 'add', 32 | method: 'post', 33 | data 34 | }) 35 | } 36 | 37 | export function editRole(data) { 38 | return request({ 39 | url: base_url + 'edit', 40 | method: 'post', 41 | data 42 | }) 43 | } 44 | 45 | export function delRole(id) { 46 | return request({ 47 | url: base_url + 'del', 48 | method: 'post', 49 | data: { id } 50 | }) 51 | } 52 | 53 | export function queryAllRoleMenus(id) { 54 | return request({ 55 | url: base_url + 'all-menus', 56 | method: 'get', 57 | data: { id } 58 | }) 59 | } 60 | 61 | export function queryAllRoleUsers(id) { 62 | return request({ 63 | url: base_url + 'all-users', 64 | method: 'get', 65 | data: { id } 66 | }) 67 | } 68 | 69 | export function queryAllRoleDepts(id) { 70 | return request({ 71 | url: base_url + 'all-depts', 72 | method: 'get', 73 | data: { id } 74 | }) 75 | } 76 | 77 | export function queryAllRoleGroups(id) { 78 | return request({ 79 | url: base_url + 'all-role-groups', 80 | method: 'get', 81 | data: { id } 82 | }) 83 | } 84 | -------------------------------------------------------------------------------- /src/api/system-management/roleGroup.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/role-group/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function delByEntityMapping(data) { 22 | return request({ 23 | url: base_url + 'del-by-entity-mapping', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/api/system-management/security.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/security/' 4 | 5 | export function queryPage(data) { 6 | return request({ 7 | url: base_url + 'query-page', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryAll(data) { 14 | return request({ 15 | url: base_url + 'query-all', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function queryById(id) { 22 | return request({ 23 | url: base_url + 'query-by-id', 24 | method: 'get', 25 | data: { id } 26 | }) 27 | } 28 | 29 | export function add(data) { 30 | return request({ 31 | url: base_url + 'add', 32 | method: 'post', 33 | data 34 | }) 35 | } 36 | 37 | export function edit(data) { 38 | return request({ 39 | url: base_url + 'edit', 40 | method: 'post', 41 | data 42 | }) 43 | } 44 | 45 | export function del(id) { 46 | return request({ 47 | url: base_url + 'del', 48 | method: 'post', 49 | data: { id } 50 | }) 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/api/system-management/user.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user/' 4 | 5 | export function queryPageUsers(data) { 6 | return request({ 7 | url: base_url + 'query-page', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function queryUserById(id) { 14 | return request({ 15 | url: base_url + 'query-by-id', 16 | method: 'get', 17 | data: { id } 18 | }) 19 | } 20 | 21 | export function checkLoginName(data) { 22 | return request({ 23 | url: base_url + 'check-login-name', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | 29 | export const uploadAvatar = base_url + 'upload-avatar' 30 | export const previewAvatar = base_url + 'avatar/' 31 | 32 | export function addUser(data) { 33 | return request({ 34 | url: base_url + 'add', 35 | method: 'post', 36 | data 37 | }) 38 | } 39 | 40 | export function editUser(data) { 41 | return request({ 42 | url: base_url + 'edit', 43 | method: 'post', 44 | data 45 | }) 46 | } 47 | 48 | export function editUserPassword(data) { 49 | return request({ 50 | url: base_url + 'edit-password', 51 | method: 'post', 52 | data 53 | }) 54 | } 55 | 56 | export function delUser(id) { 57 | return request({ 58 | url: base_url + 'del', 59 | method: 'post', 60 | data: { id } 61 | }) 62 | } 63 | 64 | export function queryAllUserRoles(params) { 65 | return request({ 66 | url: base_url + 'all-roles', 67 | method: 'get', 68 | data: params 69 | }) 70 | } 71 | 72 | export function queryAllUserDepts(params) { 73 | return request({ 74 | url: base_url + 'all-depts', 75 | method: 'get', 76 | data: params 77 | }) 78 | } 79 | 80 | export function queryAllUserGroups(params) { 81 | return request({ 82 | url: base_url + 'all-user-groups', 83 | method: 'get', 84 | data: params 85 | }) 86 | } 87 | 88 | export function queryAllUserRoleGroups(params) { 89 | return request({ 90 | url: base_url + 'all-role-groups', 91 | method: 'get', 92 | data: params 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /src/api/system-management/userDept.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user-dept/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function delByEntityMapping(data) { 22 | return request({ 23 | url: base_url + 'del-by-entity-mapping', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/api/system-management/userGroup.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user-group/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function delByEntityMapping(data) { 22 | return request({ 23 | url: base_url + 'del-by-entity-mapping', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/api/system-management/userGroupRoleGroup.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user-group-role-group/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function delByEntityMapping(data) { 14 | return request({ 15 | url: base_url + 'del-by-entity-mapping', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /src/api/system-management/userRole.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user-role/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function delByEntityMapping(data) { 22 | return request({ 23 | url: base_url + 'del-by-entity-mapping', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/api/system-management/userRoleGroup.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | const base_url = '/admin/user-role-group/' 4 | 5 | export function add(data) { 6 | return request({ 7 | url: base_url + 'add', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | export function reset(data) { 14 | return request({ 15 | url: base_url + 'reset', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | export function delByEntityMapping(data) { 22 | return request({ 23 | url: base_url + 'del-by-entity-mapping', 24 | method: 'post', 25 | data 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/assets/custom-theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umi-soft/element-admin/3c1b9b3fa74526df81c00a6c4685cac656b0efff/src/assets/custom-theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/assets/custom-theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umi-soft/element-admin/3c1b9b3fa74526df81c00a6c4685cac656b0efff/src/assets/custom-theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/assets/images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umi-soft/element-admin/3c1b9b3fa74526df81c00a6c4685cac656b0efff/src/assets/images/404.png -------------------------------------------------------------------------------- /src/assets/images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umi-soft/element-admin/3c1b9b3fa74526df81c00a6c4685cac656b0efff/src/assets/images/404_cloud.png -------------------------------------------------------------------------------- /src/assets/images/avatar.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umi-soft/element-admin/3c1b9b3fa74526df81c00a6c4685cac656b0efff/src/assets/images/avatar.jpeg -------------------------------------------------------------------------------- /src/components/Abbreviation/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 48 | 49 | 56 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 44 | 45 | 57 | -------------------------------------------------------------------------------- /src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | 39 | 53 | -------------------------------------------------------------------------------- /src/components/Redirect/index.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/components/Screenfull/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 68 | 69 | 79 | -------------------------------------------------------------------------------- /src/components/ScrollPane/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 41 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /src/directive/clipboard/clipboard.js: -------------------------------------------------------------------------------- 1 | // Inspired by https://github.com/Inndy/vue-clipboard2 2 | const Clipboard = require('clipboard') 3 | if (!Clipboard) { 4 | throw new Error('you should npm install `clipboard` --save at first ') 5 | } 6 | 7 | export default { 8 | bind(el, binding) { 9 | if (binding.arg === 'success') { 10 | el._v_clipboard_success = binding.value 11 | } else if (binding.arg === 'error') { 12 | el._v_clipboard_error = binding.value 13 | } else { 14 | const clipboard = new Clipboard(el, { 15 | text() { return binding.value }, 16 | action() { return binding.arg === 'cut' ? 'cut' : 'copy' } 17 | }) 18 | clipboard.on('success', e => { 19 | const callback = el._v_clipboard_success 20 | callback && callback(e) // eslint-disable-line 21 | }) 22 | clipboard.on('error', e => { 23 | const callback = el._v_clipboard_error 24 | callback && callback(e) // eslint-disable-line 25 | }) 26 | el._v_clipboard = clipboard 27 | } 28 | }, 29 | update(el, binding) { 30 | if (binding.arg === 'success') { 31 | el._v_clipboard_success = binding.value 32 | } else if (binding.arg === 'error') { 33 | el._v_clipboard_error = binding.value 34 | } else { 35 | el._v_clipboard.text = function() { return binding.value } 36 | el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' } 37 | } 38 | }, 39 | unbind(el, binding) { 40 | if (binding.arg === 'success') { 41 | delete el._v_clipboard_success 42 | } else if (binding.arg === 'error') { 43 | delete el._v_clipboard_error 44 | } else { 45 | el._v_clipboard.destroy() 46 | delete el._v_clipboard 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/directive/clipboard/index.js: -------------------------------------------------------------------------------- 1 | import Clipboard from './clipboard' 2 | 3 | const install = function(Vue) { 4 | Vue.directive('Clipboard', Clipboard) 5 | } 6 | 7 | if (window.Vue) { 8 | window.clipboard = Clipboard 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | Clipboard.install = install 13 | export default Clipboard 14 | -------------------------------------------------------------------------------- /src/directive/el-dragDialog/drag.js: -------------------------------------------------------------------------------- 1 | export default{ 2 | bind(el, binding, vnode) { 3 | const dialogHeaderEl = el.querySelector('.el-dialog__header') 4 | const dragDom = el.querySelector('.el-dialog') 5 | dialogHeaderEl.style.cssText += ';cursor:move;' 6 | dragDom.style.cssText += ';top:0px;' 7 | 8 | // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); 9 | const getStyle = (function() { 10 | if (window.document.currentStyle) { 11 | return (dom, attr) => dom.currentStyle[attr] 12 | } else { 13 | return (dom, attr) => getComputedStyle(dom, false)[attr] 14 | } 15 | })() 16 | 17 | dialogHeaderEl.onmousedown = (e) => { 18 | // 鼠标按下,计算当前元素距离可视区的距离 19 | const disX = e.clientX - dialogHeaderEl.offsetLeft 20 | const disY = e.clientY - dialogHeaderEl.offsetTop 21 | 22 | const dragDomWidth = dragDom.offsetWidth 23 | const dragDomHeight = dragDom.offsetHeight 24 | 25 | const screenWidth = document.body.clientWidth 26 | const screenHeight = document.body.clientHeight 27 | 28 | const minDragDomLeft = dragDom.offsetLeft 29 | const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth 30 | 31 | const minDragDomTop = dragDom.offsetTop 32 | const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight 33 | 34 | // 获取到的值带px 正则匹配替换 35 | let styL = getStyle(dragDom, 'left') 36 | let styT = getStyle(dragDom, 'top') 37 | 38 | if (styL.includes('%')) { 39 | styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100) 40 | styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100) 41 | } else { 42 | styL = +styL.replace(/\px/g, '') 43 | styT = +styT.replace(/\px/g, '') 44 | } 45 | 46 | document.onmousemove = function(e) { 47 | // 通过事件委托,计算移动的距离 48 | let left = e.clientX - disX 49 | let top = e.clientY - disY 50 | 51 | // 边界处理 52 | if (-(left) > minDragDomLeft) { 53 | left = -minDragDomLeft 54 | } else if (left > maxDragDomLeft) { 55 | left = maxDragDomLeft 56 | } 57 | 58 | if (-(top) > minDragDomTop) { 59 | top = -minDragDomTop 60 | } else if (top > maxDragDomTop) { 61 | top = maxDragDomTop 62 | } 63 | 64 | // 移动当前元素 65 | dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` 66 | 67 | // emit onDrag event 68 | vnode.child.$emit('dragDialog') 69 | } 70 | 71 | document.onmouseup = function(e) { 72 | document.onmousemove = null 73 | document.onmouseup = null 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/directive/el-dragDialog/index.js: -------------------------------------------------------------------------------- 1 | import drag from './drag' 2 | 3 | const install = function(Vue) { 4 | Vue.directive('el-drag-dialog', drag) 5 | } 6 | 7 | if (window.Vue) { 8 | window['el-drag-dialog'] = drag 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | drag.install = install 13 | export default drag 14 | -------------------------------------------------------------------------------- /src/directive/permission/index.js: -------------------------------------------------------------------------------- 1 | import permission from './permission' 2 | 3 | const install = function(Vue) { 4 | Vue.directive('permission', permission) 5 | } 6 | 7 | if (window.Vue) { 8 | window['permission'] = permission 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | permission.install = install 13 | export default permission 14 | -------------------------------------------------------------------------------- /src/directive/permission/permission.js: -------------------------------------------------------------------------------- 1 | 2 | import store from '@/store' 3 | 4 | export default{ 5 | inserted(el, binding, vnode) { 6 | const { value } = binding 7 | const roles = store.getters && store.getters.roles 8 | 9 | if (value && value instanceof Array && value.length > 0) { 10 | const permissionRoles = value 11 | 12 | const hasPermission = roles.some(role => { 13 | return permissionRoles.includes(role) 14 | }) 15 | 16 | if (!hasPermission) { 17 | el.parentNode && el.parentNode.removeChild(el) 18 | } 19 | } else { 20 | throw new Error('权限不足') 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/filters/index.js: -------------------------------------------------------------------------------- 1 | import StoreDictionaries from '@/store/modules/dictionaries' 2 | 3 | // set function parseTime,formatTime to filter 4 | export { parseTime, formatTime } from '@/utils' 5 | 6 | /** 7 | * @param number 8 | * @param prefix 单位 ,如minute 9 | * @param suffix 复数单位结尾,默认是's' 10 | * @returns 为数值增加单位 11 | */ 12 | function pluralize(number, prefix, suffix = 's') { 13 | if (number === 1) { 14 | return number + prefix 15 | } 16 | return number + prefix + suffix 17 | } 18 | 19 | /** 20 | * @param date 秒数(通常为后端时间戳)或Date对象 21 | * @returns {计算与当前时间差,并增加单位} 22 | */ 23 | export function timeAgo(date) { 24 | let time = date 25 | if (typeof date === 'object') { 26 | time = date.getTime() / 1000 27 | } 28 | const between = Date.now() / 1000 - Number(time) 29 | if (between < 3600) { 30 | return pluralize(~~(between / 60), ' minute') 31 | } else if (between < 86400) { 32 | return pluralize(~~(between / 3600), ' hour') 33 | } else { 34 | return pluralize(~~(between / 86400), ' day') 35 | } 36 | } 37 | 38 | /** 39 | * 40 | * @param num 41 | * @param digits 42 | * @returns {string} 数字格式化 43 | */ 44 | export function numberFormatter(num, digits) { 45 | const si = [ 46 | { value: 1E18, symbol: 'E' }, 47 | { value: 1E15, symbol: 'P' }, 48 | { value: 1E12, symbol: 'T' }, 49 | { value: 1E9, symbol: 'G' }, 50 | { value: 1E6, symbol: 'M' }, 51 | { value: 1E3, symbol: 'k' } 52 | ] 53 | for (let i = 0; i < si.length; i++) { 54 | if (num >= si[i].value) { 55 | return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol 56 | } 57 | } 58 | return num.toString() 59 | } 60 | 61 | export function toThousandFilter(num) { 62 | return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')) 63 | } 64 | 65 | export function translateTrueOrFalse(state) { 66 | const dictionaries = StoreDictionaries.state.trueOrFalse 67 | const index = dictionaries.findIndex(item => { return '' + state === item.key + '' }) 68 | return index === -1 ? '' : dictionaries[index].value 69 | } 70 | 71 | export function translateGender(state) { 72 | const dictionaries = StoreDictionaries.state.gender 73 | const index = dictionaries.findIndex(item => { return '' + state === item.key + '' }) 74 | return index === -1 ? '' : dictionaries[index].value 75 | } 76 | 77 | export function translateDicCategory(category) { 78 | const dictionaries = StoreDictionaries.state.dictionaryCategory 79 | const index = dictionaries.findIndex(item => { return '' + category === item.key + '' }) 80 | return index === -1 ? '' : dictionaries[index].value 81 | } 82 | -------------------------------------------------------------------------------- /src/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import SvgIcon from '@/components/SvgIcon'// svg组件 3 | 4 | // register globally 5 | Vue.component('svg-icon', SvgIcon) 6 | 7 | const req = require.context('./svg', false, /\.svg$/) 8 | const requireAll = requireContext => requireContext.keys().map(requireContext) 9 | requireAll(req) 10 | -------------------------------------------------------------------------------- /src/icons/svg/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/captcha.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/del.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/dept.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/dictionary-multi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | background 7 | 8 | 9 | 10 | Layer 1 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/icons/svg/dictionary-single.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/dictionary-type.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/group.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/index.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/java.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/menu-setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/role-setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/security.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/user-group.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/user-setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svg/utils.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/icons/svgo.yml: -------------------------------------------------------------------------------- 1 | # replace default config 2 | 3 | # multipass: true 4 | # full: true 5 | 6 | plugins: 7 | 8 | # - name 9 | # 10 | # or: 11 | # - name: false 12 | # - name: true 13 | # 14 | # or: 15 | # - name: 16 | # param1: 1 17 | # param2: 2 18 | 19 | - removeAttrs: 20 | attrs: 21 | - 'fill' 22 | - 'fill-rule' 23 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import 'normalize.css/normalize.css' 4 | 5 | import Element from 'element-ui' 6 | import 'element-ui/lib/theme-chalk/index.css' 7 | 8 | import '@/styles/index.scss' 9 | 10 | import App from './App' 11 | import router from './router' 12 | import store from './store' 13 | 14 | import './icons' 15 | import './permission' 16 | import './mock' 17 | 18 | import components from './views/common' 19 | import * as filters from './filters' 20 | 21 | Vue.use(Element, { 22 | size: 'small' 23 | }) 24 | 25 | // 全局注册组件 26 | Object.keys(components).forEach(key => { 27 | Vue.component(key, components[key]) 28 | }) 29 | 30 | // 全局注册指令 31 | Object.keys(filters).forEach(key => { 32 | Vue.filter(key, filters[key]) 33 | }) 34 | 35 | Vue.config.productionTip = false 36 | 37 | new Vue({ 38 | el: '#app', 39 | router, 40 | store, 41 | render: h => h(App) 42 | }) 43 | -------------------------------------------------------------------------------- /src/mock/login.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import * as MockDB from './MockDB' 3 | 4 | let captcha = null 5 | 6 | export default { 7 | captcha: config => { 8 | console.log(config) 9 | captcha = Mock.mock({ 'number|1000-9999': 1000 }).number 10 | return { 11 | code: 1, 12 | data: Mock.Random.dataImage('448x47', captcha) 13 | } 14 | }, 15 | loginByLoginName: config => { 16 | console.log(config) 17 | const params = JSON.parse(config.body) 18 | let token = null 19 | if ('' + captcha !== '' + params.captcha) { 20 | return { 21 | code: 1, 22 | data: { 23 | result: 2, 24 | message: '验证码错误' 25 | } 26 | } 27 | } 28 | if ((params.loginName === MockDB.simple.user.loginName && params.password !== MockDB.simple.user.password) || (params.loginName === MockDB.admin.user.loginName && params.password !== MockDB.admin.user.password)) { 29 | return { 30 | code: 1, 31 | data: { 32 | result: 3, 33 | message: '用户名或密码错误' 34 | } 35 | } 36 | } 37 | if (params.loginName === 'admin') { 38 | token = MockDB.admin.token 39 | } else { 40 | token = MockDB.simple.token 41 | } 42 | return { 43 | code: 1, 44 | data: { 45 | result: 1, 46 | message: '登录成功', 47 | token: token 48 | } 49 | } 50 | }, 51 | getUserInfo: config => { 52 | console.log(config) 53 | return { 54 | code: 1, 55 | data: MockDB.admin 56 | } 57 | }, 58 | getRouterRoles: () => { 59 | const routerRoles = new Map() 60 | routerRoles.set('90a127ce319d5d93b3b49c697cfa138f', ['simple']) 61 | // routerRoles.set('323c76618c6b56109bd490baf0d00902', ['simple']) 62 | routerRoles.set('f33d83225bef590d81f61a5afcbbca14', ['simple', 'others']) 63 | routerRoles.set('3de22ff390ab5d06bafcce547ff780bb', ['simple', 'others']) 64 | // routerRoles.set('8bdc5038a6585fd2b5d3ef7b1e4bf4e1', ['simple']) 65 | return { 66 | code: 1, 67 | data: routerRoles 68 | } 69 | }, 70 | logout: () => { 71 | return { 72 | code: 1 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/mock/system-management/deptRole.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.deptRoles.splice(MockDB.deptRoles.findIndex(item => { 8 | return item.roleId === params.roleId && item.deptId === params.deptId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: '' 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.deptRoles.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/mock/system-management/dictionary.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { param2Obj, deepMerge, deepClone, fieldQueryLike, sortArray } from '@/utils' 3 | import * as MockDB from '../MockDB' 4 | 5 | export default { 6 | queryPage: config => { 7 | console.log(config) 8 | const params = JSON.parse(config.body) 9 | const query = {} 10 | params.filters.forEach(filter => { 11 | query[filter.field] = filter.value 12 | }) 13 | const queryResult = deepClone(fieldQueryLike(MockDB.dictionaries, query)) 14 | params.sorts.forEach(sort => { 15 | // 前端目前无法实现多字段排序,因此排序以最后一个字段为准 16 | sortArray(queryResult, sort.field, sort.value === 'desc') 17 | }) 18 | return { 19 | code: 1, 20 | message: '', 21 | data: { 22 | total: queryResult.length, 23 | pageSize: params.pageSize, 24 | page: params.page, 25 | list: queryResult.slice((params.page - 1) * params.pageSize, params.page * params.pageSize) 26 | } 27 | } 28 | }, 29 | queryAll: config => { 30 | console.log(config) 31 | const params = JSON.parse(config.body) 32 | const query = {} 33 | params.filters.forEach(filter => { 34 | query[filter.field] = filter.value 35 | }) 36 | const queryResult = deepClone(fieldQueryLike(MockDB.dictionaries, query)) 37 | params.sorts.forEach(sort => { 38 | // 前端目前无法实现多字段排序,因此排序以最后一个字段为准 39 | sortArray(queryResult, sort.field, sort.value === 'desc') 40 | }) 41 | return { 42 | code: 1, 43 | message: '操作成功', 44 | data: queryResult 45 | } 46 | }, 47 | queryById: config => { 48 | console.log(config) 49 | const params = param2Obj(config.url) 50 | const dictionary = MockDB.dictionaries[MockDB.dictionaries.findIndex(item => { return item.id === params.id })] 51 | return { 52 | code: 1, 53 | message: '操作成功', 54 | data: dictionary 55 | } 56 | }, 57 | add: config => { 58 | console.log(config) 59 | const params = JSON.parse(config.body) 60 | const dictionary = Mock.mock(MockDB.dictionaryMockConfig) 61 | params.id = dictionary.id 62 | deepMerge(dictionary, params) 63 | MockDB.dictionaries.push(dictionary) 64 | return { 65 | code: 1, 66 | message: '操作成功', 67 | data: {} 68 | } 69 | }, 70 | edit: config => { 71 | console.log(config) 72 | const params = JSON.parse(config.body) 73 | const dictionary = MockDB.dictionaries[MockDB.dictionaries.findIndex(item => { return item.id === params.id })] 74 | deepMerge(dictionary, params) 75 | return { 76 | code: 1, 77 | message: '操作成功', 78 | data: {} 79 | } 80 | }, 81 | del: config => { 82 | console.log(config) 83 | const params = JSON.parse(config.body) 84 | MockDB.dictionaries.splice(MockDB.dictionaries.findIndex(item => { return item.id === params.id }), 1) 85 | return { 86 | code: 1, 87 | message: '操作成功', 88 | data: {} 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/mock/system-management/menu.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { deepMerge, param2Obj } from '@/utils' 3 | import { asyncMenuMap } from '@/router' 4 | import * as MockDB from '../MockDB' 5 | 6 | function createMenu(router, parentId, menus) { 7 | const menu = {} 8 | menu.id = router.name 9 | menu.parentId = parentId 10 | menu.deleted = 0 11 | menu.sortNum = router.meta.sortNum 12 | menu.name = router.meta.title 13 | menu.icon = router.meta.icon 14 | menu.remark = Mock.mock('@cparagraph(1, 3)') 15 | menu.createdBy = Mock.mock('@id') 16 | menu.createdDate = Mock.mock('@date(\'T\')') 17 | menu.modifiedBy = Mock.mock('@id') 18 | menu.modifiedDate = Mock.mock('@date(\'T\')') 19 | 20 | if (router.children && router.children.length > 0) { 21 | router.children.forEach(children => { 22 | createMenu(children, router.name, menus) 23 | }) 24 | } 25 | menus.push(menu) 26 | } 27 | 28 | export default { 29 | queryAll: config => { 30 | console.log(config) 31 | return { 32 | code: 1, 33 | message: '操作成功', 34 | data: MockDB.menus 35 | } 36 | }, 37 | queryById: config => { 38 | console.log(config) 39 | const params = param2Obj(config.url) 40 | const menu = MockDB.menus[MockDB.menus.findIndex(item => { return item.id === params.id })] 41 | return { 42 | code: 1, 43 | message: '操作成功', 44 | data: menu 45 | } 46 | }, 47 | edit: config => { 48 | console.log(config) 49 | const params = JSON.parse(config.body) 50 | const menu = MockDB.menus[MockDB.menus.findIndex(item => { return item.id === params.id })] 51 | deepMerge(menu, params) 52 | return { 53 | code: 1, 54 | message: '操作成功', 55 | data: {} 56 | } 57 | }, 58 | 59 | sync: config => { 60 | console.log(config) 61 | asyncMenuMap.forEach(router => createMenu(router, null, MockDB.menus)) 62 | return { 63 | code: 1, 64 | message: '操作成功', 65 | data: {} 66 | } 67 | }, 68 | queryAllMenuSecurities: config => { 69 | console.log(config) 70 | const params = param2Obj(config.url) 71 | const tempResult = MockDB.menuSecurities.filter(item => { return item.menuId === params.id }) 72 | return { 73 | code: 1, 74 | message: '操作成功', 75 | data: MockDB.securities.filter(security => { 76 | return tempResult.findIndex(item => { return security.id === item.securityId }) !== -1 77 | }) 78 | } 79 | }, 80 | queryMenuRoles: config => { 81 | console.log(config) 82 | const params = param2Obj(config.url) 83 | if (MockDB.roleMenus.findIndex(item => { return item.menuId === params.id }) === -1) { 84 | // 生成几个role 85 | for (let i = 0; i < 5; i++) { 86 | const role = Mock.mock(MockDB.roleMockConfig) 87 | MockDB.roles.push(role) 88 | MockDB.roleMenus.push({ 89 | menuId: params.id, 90 | roleId: role.id 91 | }) 92 | } 93 | } 94 | const roleMenusResult = MockDB.roleMenus.filter(item => { return params.id === item.menuId }) 95 | return { 96 | code: 1, 97 | message: '操作成功', 98 | data: MockDB.roles.filter(role => { 99 | return roleMenusResult.findIndex(menuRole => { return role.id === menuRole.roleId }) !== -1 100 | }) 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/mock/system-management/menuRole.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.roleMenus.splice(MockDB.roleMenus.findIndex(item => { 8 | return item.menuId === params.menuId && item.roleId === params.roleId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: {} 14 | } 15 | }, 16 | reset: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.roleMenus.forEach(() => { 20 | MockDB.roleMenus.splice(MockDB.roleMenus.findIndex(item => { 21 | return item.roleId === params.roleId 22 | }), 1) 23 | }) 24 | params.menuIds.forEach(menuId => { 25 | MockDB.roleMenus.push({ 26 | roleId: params.roleId, 27 | menuId 28 | }) 29 | }) 30 | return { 31 | code: 1, 32 | message: '操作成功', 33 | data: '' 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/mock/system-management/menuSecurity.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | add: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.menuSecurities.push(params) 8 | return { 9 | code: 1, 10 | message: '操作成功', 11 | data: params 12 | } 13 | }, 14 | delByEntityMapping: config => { 15 | console.log(config) 16 | const params = JSON.parse(config.body) 17 | MockDB.menuSecurities.splice(MockDB.menuSecurities.findIndex(item => { 18 | return item.menuId === params.menuId && item.securityId === params.securityId 19 | }), 1) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: '' 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/mock/system-management/roleGroup.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.roleGroups.splice(MockDB.roleGroups.findIndex(item => { 8 | return item.roleId === params.roleId && item.groupId === params.groupId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: '' 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.roleGroups.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/mock/system-management/security.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { param2Obj, deepMerge, deepClone, fieldQueryLike, sortArray } from '@/utils' 3 | import * as MockDB from '../MockDB' 4 | 5 | export default { 6 | queryPage: config => { 7 | console.log(config) 8 | const params = JSON.parse(config.body) 9 | const query = {} 10 | params.filters.forEach(filter => { 11 | query[filter.field] = filter.value 12 | }) 13 | const queryResult = deepClone(fieldQueryLike(MockDB.securities, query)) 14 | params.sorts.forEach(sort => { 15 | // 前端目前无法实现多字段排序,因此排序以最后一个字段为准 16 | sortArray(queryResult, sort.field, sort.value === 'desc') 17 | }) 18 | return { 19 | code: 1, 20 | message: '', 21 | data: { 22 | total: queryResult.length, 23 | pageSize: params.pageSize, 24 | page: params.page, 25 | list: queryResult.slice((params.page - 1) * params.pageSize, params.page * params.pageSize) 26 | } 27 | } 28 | }, 29 | queryAll: config => { 30 | console.log(config) 31 | const params = JSON.parse(config.body) 32 | const query = {} 33 | params.filters.forEach(filter => { 34 | query[filter.field] = filter.value + '' 35 | }) 36 | console.log(query) 37 | const queryResult = deepClone(fieldQueryLike(MockDB.securities, query)) 38 | params.sorts.forEach(sort => { 39 | // 前端目前无法实现多字段排序,因此排序以最后一个字段为准 40 | sortArray(queryResult, sort.field, sort.value === 'desc') 41 | }) 42 | return { 43 | code: 1, 44 | message: '操作成功', 45 | data: queryResult 46 | } 47 | }, 48 | queryById: config => { 49 | console.log(config) 50 | const params = param2Obj(config.url) 51 | const security = MockDB.securities[MockDB.securities.findIndex(item => { return item.id === params.id })] 52 | return { 53 | code: 1, 54 | message: '操作成功', 55 | data: security 56 | } 57 | }, 58 | add: config => { 59 | console.log(config) 60 | const params = JSON.parse(config.body) 61 | const security = Mock.mock(MockDB.securityMockConfig) 62 | params.id = security.id 63 | deepMerge(security, params) 64 | MockDB.securities.push(security) 65 | return { 66 | code: 1, 67 | message: '操作成功', 68 | data: security 69 | } 70 | }, 71 | edit: config => { 72 | console.log(config) 73 | const params = JSON.parse(config.body) 74 | const security = MockDB.securities[MockDB.securities.findIndex(item => { return item.id === params.id })] 75 | deepMerge(security, params) 76 | return { 77 | code: 1, 78 | message: '操作成功', 79 | data: {} 80 | } 81 | }, 82 | del: config => { 83 | console.log(config) 84 | const params = JSON.parse(config.body) 85 | MockDB.securities.splice(MockDB.securities.findIndex(item => { return item.id === params.id }), 1) 86 | return { 87 | code: 1, 88 | message: '操作成功', 89 | data: {} 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/mock/system-management/userDept.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.deptUsers.splice(MockDB.deptUsers.findIndex(item => { 8 | return item.userId === params.userId && item.deptId === params.deptId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: '' 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.deptUsers.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | }, 26 | reset: config => { 27 | console.log(config) 28 | const params = JSON.parse(config.body) 29 | const newDeptUsers = MockDB.deptUsers.filter(item => { 30 | let found = false 31 | for (let i = 0; i < params.length; i++) { 32 | if (item.userId === params[i].userId) { 33 | found = true 34 | break 35 | } 36 | } 37 | return !found 38 | }) 39 | MockDB.deptUsers.splice(0, MockDB.deptUsers.length) 40 | newDeptUsers.forEach(item => { 41 | MockDB.deptUsers.push(item) 42 | }) 43 | params.forEach(item => { 44 | MockDB.deptUsers.push(item) 45 | }) 46 | return { 47 | code: 1, 48 | message: '操作成功', 49 | data: params 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/mock/system-management/userGroup.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.userGroups.splice(MockDB.userGroups.findIndex(item => { 8 | return item.userId === params.userId && item.groupId === params.groupId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: '' 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.userGroups.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | }, 26 | reset: config => { 27 | console.log(config) 28 | const params = JSON.parse(config.body) 29 | const newGroupUsers = MockDB.userGroups.filter(item => { 30 | let found = false 31 | for (let i = 0; i < params.length; i++) { 32 | if (item.userId === params[i].userId) { 33 | found = true 34 | break 35 | } 36 | } 37 | return !found 38 | }) 39 | MockDB.userGroups.splice(0, MockDB.userGroups.length) 40 | newGroupUsers.forEach(item => { 41 | MockDB.userGroups.push(item) 42 | }) 43 | params.forEach(item => { 44 | MockDB.userGroups.push(item) 45 | }) 46 | return { 47 | code: 1, 48 | message: '操作成功', 49 | data: params 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/mock/system-management/userGroupRoleGroup.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.userGroupRoleGroups.splice(MockDB.userGroupRoleGroups.findIndex(item => { 8 | return item.userGroupId === params.userGroupId && item.roleGroupId === params.roleGroupId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: {} 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.userGroupRoleGroups.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/mock/system-management/userRole.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.userRoles.splice(MockDB.userRoles.findIndex(item => { 8 | return item.userId === params.userId && item.roleId === params.roleId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: '' 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.userRoles.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | }, 26 | reset: config => { 27 | console.log(config) 28 | const params = JSON.parse(config.body) 29 | const newUserRoles = MockDB.userRoles.filter(item => { 30 | let found = false 31 | for (let i = 0; i < params.length; i++) { 32 | if (item.userId === params[i].userId) { 33 | found = true 34 | break 35 | } 36 | } 37 | return !found 38 | }) 39 | MockDB.userRoles.splice(0, MockDB.userRoles.length) 40 | newUserRoles.forEach(item => { 41 | MockDB.userRoles.push(item) 42 | }) 43 | params.forEach(item => { 44 | MockDB.userRoles.push(item) 45 | }) 46 | return { 47 | code: 1, 48 | message: '操作成功', 49 | data: params 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/mock/system-management/userRoleGroup.js: -------------------------------------------------------------------------------- 1 | import * as MockDB from '../MockDB' 2 | 3 | export default { 4 | delByEntityMapping: config => { 5 | console.log(config) 6 | const params = JSON.parse(config.body) 7 | MockDB.userRoleGroups.splice(MockDB.userRoleGroups.findIndex(item => { 8 | return item.userId === params.userId && item.userRoleId === params.userRoleId 9 | }), 1) 10 | return { 11 | code: 1, 12 | message: '操作成功', 13 | data: {} 14 | } 15 | }, 16 | add: config => { 17 | console.log(config) 18 | const params = JSON.parse(config.body) 19 | MockDB.userRoleGroups.push(params) 20 | return { 21 | code: 1, 22 | message: '操作成功', 23 | data: params 24 | } 25 | }, 26 | reset: config => { 27 | console.log(config) 28 | const params = JSON.parse(config.body) 29 | const newUserRoleGroups = MockDB.userRoleGroups.filter(item => { 30 | let found = false 31 | for (let i = 0; i < params.length; i++) { 32 | if (item.userId === params[i].userId) { 33 | found = true 34 | break 35 | } 36 | } 37 | return !found 38 | }) 39 | MockDB.userRoleGroups.splice(0, MockDB.userRoleGroups.length) 40 | newUserRoleGroups.forEach(item => { 41 | MockDB.userRoleGroups.push(item) 42 | }) 43 | params.forEach(item => { 44 | MockDB.userRoleGroups.push(item) 45 | }) 46 | return { 47 | code: 1, 48 | message: '操作成功', 49 | data: params 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/mock/utils.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | 3 | const id = [] 4 | for (let i = 0; i < 1000; i++) { 5 | id.push(Mock.mock('@id')) 6 | } 7 | 8 | export default { 9 | state: [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], 10 | deleted: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], 11 | id: id 12 | } 13 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | import router from './router' 2 | import store from './store' 3 | import { Message } from 'element-ui' 4 | import NProgress from 'nprogress' // 进度条组件 5 | import 'nprogress/nprogress.css'// 进度条样式 6 | import { getToken, hasPermission } from '@/utils/auth' // 从cookie中获取用户信息 7 | 8 | NProgress.configure({ showSpinner: false })// NProgress Configuration 9 | 10 | router.beforeEach((to, from, next) => { 11 | NProgress.start() // 开始进度条 12 | if (getToken()) { // 判断是否已存在token信息 13 | if (to.path.indexOf('/login') === 0) { 14 | next({ path: '/' }) 15 | NProgress.done() // 部分页面可能不会触发路由afterEach钩子 16 | } else { 17 | if (store.getters.user === null) { // 判断当前用户是否已拉取完用户信息 18 | store.dispatch('GetUserInfo').then(data => { // 拉取用户信息 19 | const roles = data.roles // 必须是数组结构 20 | store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表 21 | router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表 22 | next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record 23 | }) 24 | }).catch((err) => { 25 | store.dispatch('FedLogOut').then(() => { 26 | Message.error(err || '登录失败') 27 | next({ path: '/' }) 28 | }) 29 | }) 30 | } else { 31 | // 没有动态改变权限的需求可直接next() 删除下方权限判断 32 | if (hasPermission(store.getters.roles, to)) { 33 | next() 34 | } else { 35 | next({ path: '/401', replace: true, query: { noGoBack: true }}) 36 | } 37 | } 38 | } 39 | } else { 40 | if (to.path.indexOf('/login') === 0) { 41 | next() 42 | } else { 43 | next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页 44 | NProgress.done() // 防止当前页面与to相同,导致afterEach钩子未触发 45 | } 46 | } 47 | }) 48 | 49 | router.afterEach(() => { 50 | NProgress.done() // finish progress bar 51 | }) 52 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | /** 7 | * Layout,建议在一级路由中应用不同的布局 8 | */ 9 | import defaultLayout from '@/views/layout/LeftAccordionSidebar/index' 10 | 11 | /* 模块化路由 */ 12 | import systemManagementRouter from './modules/SystemManagement' 13 | import CodeGenerator from './modules/CodeGenerator' 14 | 15 | /** 16 | * 静态路由定义,无需权限的全局路由 17 | * @type {*[]} 18 | */ 19 | export const constantRouterMap = [ 20 | { 21 | path: '/redirect', // 通常用于刷新当前路由,可参见tagsView中的案例 22 | component: defaultLayout, 23 | hidden: true, 24 | children: [ 25 | { 26 | path: '/redirect/:path*', 27 | component: () => import('@/components/Redirect/index') 28 | } 29 | ] 30 | }, 31 | { 32 | path: '/login', 33 | component: () => import('@/views/login/index'), 34 | hidden: true 35 | }, 36 | { 37 | path: '/404', 38 | component: () => import('@/components/ErrorPage/404'), 39 | hidden: true 40 | }, 41 | { 42 | path: '/401', 43 | component: () => import('@/components/ErrorPage/401'), 44 | hidden: true 45 | }, 46 | { 47 | path: '/myself', 48 | component: defaultLayout, 49 | hidden: true, 50 | meta: { title: '个人设置', icon: 'user' }, 51 | children: [ 52 | { 53 | path: 'modify', 54 | component: () => import('@/views/system-management/user/myself/modify'), 55 | name: 'myself-modify', 56 | meta: { title: '个人信息编辑', icon: 'user' } 57 | } 58 | ] 59 | }, 60 | { 61 | path: '', 62 | component: defaultLayout, 63 | hidden: false, 64 | redirect: 'index', 65 | children: [ 66 | { 67 | path: '/index', 68 | component: () => import('@/views/dashboard/index'), 69 | name: 'index', 70 | meta: { title: '首页', icon: 'index' } 71 | } 72 | ] 73 | } 74 | ] 75 | 76 | export default new Router({ 77 | routes: constantRouterMap 78 | }) 79 | 80 | /** 81 | * 聚合子模块路由对象,登陆后异步匹配路由结构,动态添加路由 82 | * 建议,该动态路由表由前端控制 83 | * asyncRouterMap动态够钱过程中,请在最后末尾处加上路由 : { path: '*', redirect: '/404', hidden: true },将未知路由归置到404页面, 详见src/store/modules/permission.js 84 | */ 85 | export const asyncRouterMap = [ 86 | systemManagementRouter, 87 | CodeGenerator 88 | ] 89 | 90 | export const asyncMenuMap = JSON.parse(JSON.stringify(asyncRouterMap)) 91 | -------------------------------------------------------------------------------- /src/router/modules/CodeGenerator.js: -------------------------------------------------------------------------------- 1 | import defaultLayout from '@/views/layout/LeftAccordionSidebar/index' 2 | 3 | const asyncRouter = { 4 | path: '/java-code-generator', 5 | component: defaultLayout, 6 | hidden: false, 7 | redirect: '/java-code-generator/execute', 8 | name: '923c7i98uc6khj109b8930ba20d907j3', 9 | meta: { 10 | sortNum: 1, 11 | roles: [], 12 | title: '插件', 13 | icon: 'utils' 14 | }, 15 | children: [ 16 | { 17 | path: 'execute', 18 | component: () => import('@/views/code-generator/main'), 19 | hidden: false, 20 | alwaysShow: true, 21 | name: '723c7698uc6ghj109b8970baf0d008j5', 22 | meta: { 23 | sortNum: 2, 24 | roles: [], 25 | title: '代码生成器', 26 | icon: 'java' 27 | } 28 | } 29 | ] 30 | } 31 | 32 | export default asyncRouter 33 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: state => state.app.sidebar, 3 | 4 | visitedViews: state => state.tagsView.visitedViews, 5 | 6 | token: state => state.user.token, 7 | user: state => state.user.user, 8 | roles: state => state.user.roles, 9 | 10 | adminCode: state => state.permission.adminCode, 11 | permission_routers: state => state.permission.routers, 12 | addRouters: state => state.permission.addRouters, 13 | 14 | dictionaries: state => state.dictionaries 15 | } 16 | export default getters 17 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import app from './modules/app' 4 | import permission from './modules/permission' 5 | import tagsView from './modules/tagsView' 6 | import user from './modules/user' 7 | import dictionaries from './modules/dictionaries' 8 | import getters from './getters' 9 | 10 | Vue.use(Vuex) 11 | 12 | const store = new Vuex.Store({ 13 | modules: { 14 | app, 15 | permission, 16 | tagsView, 17 | user, 18 | dictionaries 19 | }, 20 | getters 21 | }) 22 | 23 | export default store 24 | -------------------------------------------------------------------------------- /src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const app = { 4 | state: { 5 | sidebar: { 6 | opened: !+Cookies.get('sidebarStatus'), 7 | withoutAnimation: false 8 | } 9 | }, 10 | mutations: { 11 | TOGGLE_SIDEBAR: state => { 12 | if (state.sidebar.opened) { 13 | Cookies.set('sidebarStatus', 1) 14 | } else { 15 | Cookies.set('sidebarStatus', 0) 16 | } 17 | state.sidebar.opened = !state.sidebar.opened 18 | state.sidebar.withoutAnimation = false 19 | }, 20 | CLOSE_SIDEBAR: (state, withoutAnimation) => { 21 | Cookies.set('sidebarStatus', 1) 22 | state.sidebar.opened = false 23 | state.sidebar.withoutAnimation = withoutAnimation 24 | }, 25 | OPEN_SIDEBAR: (state, withoutAnimation) => { 26 | Cookies.set('sidebarStatus', 0) 27 | state.sidebar.opened = true 28 | state.sidebar.withoutAnimation = withoutAnimation 29 | } 30 | }, 31 | actions: { 32 | toggleSideBar({ commit }) { 33 | commit('TOGGLE_SIDEBAR') 34 | }, 35 | closeSideBar({ commit }, { withoutAnimation }) { 36 | commit('CLOSE_SIDEBAR', withoutAnimation) 37 | }, 38 | openSideBar({ commit }, { withoutAnimation }) { 39 | commit('OPEN_SIDEBAR', withoutAnimation) 40 | } 41 | } 42 | } 43 | 44 | export default app 45 | -------------------------------------------------------------------------------- /src/store/modules/dictionaries.js: -------------------------------------------------------------------------------- 1 | const dictionaries = { 2 | state: { 3 | trueOrFalse: [{ 4 | key: '0', 5 | value: '否' 6 | }, { 7 | key: '1', 8 | value: '是' 9 | }], 10 | 11 | gender: [{ 12 | key: '0', 13 | value: '女' 14 | }, { 15 | key: '1', 16 | value: '男' 17 | }], 18 | 19 | dictionaryCategory: [{ 20 | key: '1', 21 | value: '字典分类' 22 | }, { 23 | key: '2', 24 | value: '单级字典' 25 | }, { 26 | key: '3', 27 | value: '多级字典' 28 | }] 29 | } 30 | } 31 | export default dictionaries 32 | -------------------------------------------------------------------------------- /src/store/modules/permission.js: -------------------------------------------------------------------------------- 1 | import { asyncRouterMap, constantRouterMap } from '@/router' 2 | import { filterAsyncRouter, initRouterRoles, initRouterRedirect } from '@/utils/auth' 3 | import { getRouterRoles } from '@/api/login' 4 | 5 | const permission = { 6 | state: { 7 | adminCode: 'admin', 8 | routers: constantRouterMap, 9 | addRouters: [] 10 | }, 11 | mutations: { 12 | SET_ROUTERS: (state, routers) => { 13 | state.routers = constantRouterMap.concat(routers) 14 | state.addRouters = routers 15 | } 16 | }, 17 | actions: { 18 | GenerateRoutes({ commit, state }, data) { 19 | return new Promise(resolve => { 20 | const { roles } = data 21 | let accessedRouters = null 22 | if (roles.includes(state.adminCode)) { 23 | // 将未知路由归置到404页面 24 | asyncRouterMap.push({ path: '*', redirect: '/404', hidden: true }) 25 | accessedRouters = asyncRouterMap 26 | initRouterRedirect(accessedRouters) 27 | commit('SET_ROUTERS', accessedRouters) 28 | resolve() 29 | } else { 30 | getRouterRoles().then(routerRoles => { 31 | const routerRolesMap = new Map(routerRoles) 32 | asyncRouterMap.forEach(module => { 33 | initRouterRoles(module, routerRolesMap) 34 | }) 35 | accessedRouters = filterAsyncRouter(asyncRouterMap, roles) 36 | // 将未知路由归置到404页面 37 | accessedRouters.push({ path: '*', redirect: '/404', hidden: true }) 38 | initRouterRedirect(accessedRouters) 39 | commit('SET_ROUTERS', accessedRouters) 40 | resolve() 41 | }) 42 | } 43 | }) 44 | } 45 | } 46 | } 47 | 48 | export default permission 49 | -------------------------------------------------------------------------------- /src/store/modules/tagsView.js: -------------------------------------------------------------------------------- 1 | const tagsView = { 2 | state: { 3 | visitedViews: [] 4 | }, 5 | mutations: { 6 | ADD_VISITED_VIEW: (state, view) => { 7 | if (state.visitedViews.some(v => v.path === view.path)) return 8 | state.visitedViews.push( 9 | Object.assign({}, view, { 10 | title: view.meta.title || 'no-name' 11 | }) 12 | ) 13 | }, 14 | DEL_VISITED_VIEW: (state, view) => { 15 | for (const [i, v] of state.visitedViews.entries()) { 16 | if (v.path === view.path) { 17 | state.visitedViews.splice(i, 1) 18 | break 19 | } 20 | } 21 | }, 22 | DEL_OTHERS_VISITED_VIEWS: (state, view) => { 23 | for (const [i, v] of state.visitedViews.entries()) { 24 | if (v.path === view.path) { 25 | state.visitedViews = state.visitedViews.slice(i, i + 1) 26 | break 27 | } 28 | } 29 | }, 30 | DEL_ALL_VISITED_VIEWS: state => { 31 | state.visitedViews = [] 32 | }, 33 | UPDATE_VISITED_VIEW: (state, view) => { 34 | for (let v of state.visitedViews) { 35 | if (v.path === view.path) { 36 | v = Object.assign(v, view) 37 | break 38 | } 39 | } 40 | } 41 | 42 | }, 43 | actions: { 44 | addView({ dispatch }, view) { 45 | dispatch('addVisitedView', view) 46 | }, 47 | addVisitedView({ commit }, view) { 48 | commit('ADD_VISITED_VIEW', view) 49 | }, 50 | delView({ dispatch, state }, view) { 51 | return new Promise(resolve => { 52 | dispatch('delVisitedView', view) 53 | resolve({ 54 | visitedViews: [...state.visitedViews] 55 | }) 56 | }) 57 | }, 58 | delVisitedView({ commit, state }, view) { 59 | return new Promise(resolve => { 60 | commit('DEL_VISITED_VIEW', view) 61 | resolve([...state.visitedViews]) 62 | }) 63 | }, 64 | delOthersViews({ dispatch, state }, view) { 65 | return new Promise(resolve => { 66 | dispatch('delOthersVisitedViews', view) 67 | resolve({ 68 | visitedViews: [...state.visitedViews] 69 | }) 70 | }) 71 | }, 72 | delOthersVisitedViews({ commit, state }, view) { 73 | return new Promise(resolve => { 74 | commit('DEL_OTHERS_VISITED_VIEWS', view) 75 | resolve([...state.visitedViews]) 76 | }) 77 | }, 78 | delAllViews({ dispatch, state }, view) { 79 | return new Promise(resolve => { 80 | dispatch('delAllVisitedViews', view) 81 | resolve({ 82 | visitedViews: [...state.visitedViews] 83 | }) 84 | }) 85 | }, 86 | delAllVisitedViews({ commit, state }) { 87 | return new Promise(resolve => { 88 | commit('DEL_ALL_VISITED_VIEWS') 89 | resolve([...state.visitedViews]) 90 | }) 91 | }, 92 | updateVisitedView({ commit }, view) { 93 | commit('UPDATE_VISITED_VIEW', view) 94 | } 95 | } 96 | } 97 | 98 | export default tagsView 99 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { logout, getUserInfo } from '@/api/login' 2 | import { getToken, setToken, removeToken } from '@/utils/auth' 3 | 4 | const user = { 5 | state: { 6 | token: getToken(), 7 | user: null, 8 | roles: [] 9 | }, 10 | 11 | mutations: { 12 | SET_TOKEN: (state, token) => { 13 | state.token = token 14 | if (token) { 15 | setToken(token) 16 | } else { 17 | removeToken() 18 | } 19 | }, 20 | SET_USER: (state, user) => { 21 | state.user = user 22 | }, 23 | SET_ROLES: (state, roles) => { 24 | state.roles = roles 25 | }, 26 | CLEAR_USER: (state) => { 27 | state.user = null 28 | state.roles = [] 29 | } 30 | }, 31 | 32 | actions: { 33 | // 用户名登录 34 | LoginByLoginName({ commit }, token) { 35 | commit('SET_TOKEN', token) 36 | commit('CLEAR_USER') 37 | }, 38 | 39 | // 获取用户信息 40 | GetUserInfo({ commit, state }) { 41 | return new Promise((resolve, reject) => { 42 | getUserInfo(state.token).then(data => { 43 | commit('SET_USER', data.user) 44 | commit('SET_ROLES', data.roles) 45 | resolve(data) 46 | }).catch(error => { 47 | commit('CLEAR_USER') 48 | reject(error) 49 | }) 50 | }) 51 | }, 52 | 53 | // 登出 54 | LogOut({ commit, state }) { 55 | return new Promise((resolve, reject) => { 56 | logout(state.token).then(() => { 57 | commit('SET_TOKEN', null) 58 | commit('CLEAR_USER') 59 | resolve() 60 | }).catch(error => { 61 | reject(error) 62 | }) 63 | }) 64 | }, 65 | 66 | // 前端 登出 67 | FedLogOut({ commit }) { 68 | return new Promise(resolve => { 69 | commit('SET_TOKEN', null) 70 | commit('CLEAR_USER') 71 | resolve() 72 | }) 73 | } 74 | } 75 | } 76 | 77 | export default user 78 | -------------------------------------------------------------------------------- /src/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | //覆盖一些element-ui样式 2 | 3 | .el-breadcrumb__inner, .el-breadcrumb__inner a { 4 | font-weight: 400!important; 5 | } 6 | 7 | .current-row { 8 | td { 9 | background-color: #409EFF !important; 10 | color: #f5f7fa; 11 | font-weight: 600; 12 | font-size: 16px; 13 | } 14 | } 15 | 16 | .el-upload { 17 | input[type="file"] { 18 | display: none !important; 19 | } 20 | } 21 | 22 | .el-upload__input { 23 | display: none; 24 | } 25 | 26 | //element ui upload 27 | .upload-container { 28 | .el-upload { 29 | width: 100%; 30 | .el-upload-dragger { 31 | width: 100%; 32 | height: 200px; 33 | } 34 | } 35 | } 36 | 37 | //dropdown 38 | .el-dropdown-menu{ 39 | a { 40 | display: block 41 | } 42 | } 43 | .el-menu--vertical > .el-menu .svg-icon { 44 | margin-right: 20px; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './mixin.scss'; 2 | @import './transition.scss'; 3 | @import './element-ui.scss'; 4 | 5 | body { 6 | height: 100%; 7 | -moz-osx-font-smoothing: grayscale; 8 | -webkit-font-smoothing: antialiased; 9 | text-rendering: optimizeLegibility; 10 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; 11 | } 12 | 13 | label { 14 | font-weight: 700; 15 | } 16 | 17 | html { 18 | height: 100%; 19 | box-sizing: border-box; 20 | } 21 | 22 | #app { 23 | height: 100%; 24 | } 25 | 26 | *, *:before, *:after { 27 | box-sizing: inherit; 28 | } 29 | 30 | a:focus, a:active { 31 | outline: none; 32 | } 33 | 34 | a, a:focus, a:hover { 35 | cursor: pointer; 36 | color: inherit; 37 | text-decoration: none; 38 | } 39 | 40 | div:focus{ 41 | outline: none; 42 | } 43 | 44 | .block { 45 | display: block; 46 | } 47 | 48 | .pointer { 49 | cursor: pointer; 50 | } 51 | -------------------------------------------------------------------------------- /src/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/styles/transition.scss: -------------------------------------------------------------------------------- 1 | //globl transition css 2 | 3 | /*fade*/ 4 | .fade-enter-active, .fade-leave-active { 5 | transition: opacity 0.28s; 6 | } 7 | 8 | .fade-enter, .fade-leave-active { 9 | opacity: 0; 10 | } 11 | 12 | /*fade-transform*/ 13 | .fade-transform-leave-active, .fade-transform-enter-active { 14 | transition: all .5s; 15 | } 16 | .fade-transform-enter { 17 | opacity: 0; 18 | transform: translateX(-30px); 19 | } 20 | .fade-transform-leave-to { 21 | opacity: 0; 22 | transform: translateX(30px); 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const TokenKey = 'USER_TOKEN' 4 | 5 | export function getToken() { 6 | return Cookies.get(TokenKey) 7 | } 8 | 9 | export function setToken(token) { 10 | return Cookies.set(TokenKey, token) 11 | } 12 | 13 | export function removeToken() { 14 | return Cookies.remove(TokenKey) 15 | } 16 | 17 | /** 18 | * 通过meta.role判断是否与当前用户权限匹配 19 | * @param roles 用户的角色列表 20 | * @param meta meta中规定了有权限操作的所有角色,只要用户具有其中一个即可 21 | */ 22 | export function hasPermission(roles, { meta }) { 23 | if (roles.indexOf('admin') >= 0) return true 24 | if (meta && meta.roles) { 25 | return roles.some(role => meta.roles.includes(role)) 26 | } else { 27 | return true 28 | } 29 | } 30 | 31 | /** 32 | * 递归过滤异步路由表,返回符合用户角色权限的路由表 33 | * @param routes asyncRouterMap 34 | * @param roles 35 | */ 36 | export function filterAsyncRouter(routes, roles) { 37 | const res = [] 38 | 39 | routes.forEach(router => { 40 | const temp = { ...router } // 继承一个router对象,非深度复制 41 | if (hasPermission(roles, temp)) { 42 | if (temp.children) { 43 | temp.children = filterAsyncRouter(temp.children, roles) 44 | } 45 | res.push(temp) 46 | } 47 | }) 48 | 49 | return res 50 | } 51 | 52 | export function initRouterRedirect(routes, redirect = '') { 53 | routes.forEach(router => { 54 | let routerRedirect = router.path 55 | // 约束,路由中请勿使用绝对路由路径path 56 | if (!router.path.startsWith('/')) { 57 | routerRedirect = redirect + '/' + router.path 58 | } 59 | if (router.children) { 60 | for (let i = 0; i < router.children.length; i++) { 61 | if (router.children[i].hidden === false) { 62 | router.redirect = routerRedirect + '/' + router.children[i].path 63 | break 64 | } 65 | } 66 | initRouterRedirect(router.children, routerRedirect) 67 | } 68 | }) 69 | } 70 | 71 | export function initRouterRoles(router, routerRolesMap) { 72 | if (!router.meta) { 73 | router.meta = { } 74 | } 75 | if (routerRolesMap.get(router.name)) { 76 | router.meta.roles = routerRolesMap.get(router.name) 77 | } else { 78 | router.meta.roles = [] 79 | } 80 | if (router.children) { 81 | router.children.forEach(children => { 82 | initRouterRoles(children, routerRolesMap) 83 | }) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/utils/clipboard.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Clipboard from 'clipboard' 3 | 4 | function clipboardSuccess() { 5 | Vue.prototype.$message({ 6 | message: 'Copy successfully', 7 | type: 'success', 8 | duration: 1500 9 | }) 10 | } 11 | 12 | function clipboardError() { 13 | Vue.prototype.$message({ 14 | message: 'Copy failed', 15 | type: 'error' 16 | }) 17 | } 18 | 19 | export default function handleClipboard(text, event) { 20 | const clipboard = new Clipboard(event.target, { 21 | text: () => text 22 | }) 23 | clipboard.on('success', () => { 24 | clipboardSuccess() 25 | clipboard.off('error') 26 | clipboard.off('success') 27 | clipboard.destroy() 28 | }) 29 | clipboard.on('error', () => { 30 | clipboardError() 31 | clipboard.off('error') 32 | clipboard.off('success') 33 | clipboard.destroy() 34 | }) 35 | clipboard.onClick(event) 36 | } 37 | -------------------------------------------------------------------------------- /src/utils/openWindow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 打开windows窗口 3 | * @param {Sting} url 4 | * @param {Sting} title 5 | * @param {Number} w 6 | * @param {Number} h 7 | */ 8 | 9 | export default function openWindow(url, title, w, h) { 10 | // Fixes dual-screen position Most browsers Firefox 11 | const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left 12 | const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top 13 | 14 | const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width 15 | const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height 16 | 17 | const left = ((width / 2) - (w / 2)) + dualScreenLeft 18 | const top = ((height / 2) - (h / 2)) + dualScreenTop 19 | const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left) 20 | 21 | // Puts focus on the newWindow 22 | if (window.focus) { 23 | newWindow.focus() 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/utils/permission.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | /** 4 | * @param {Array} value 5 | * @returns {Boolean} 6 | * @example see @/views/permission/directive.vue 7 | */ 8 | export default function checkPermission(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const roles = store.getters && store.getters.roles 11 | const permissionRoles = value 12 | 13 | const hasPermission = roles.some(role => { 14 | return permissionRoles.includes(role) 15 | }) 16 | 17 | if (!hasPermission) { 18 | return false 19 | } 20 | return true 21 | } else { 22 | console.error('权限不足') 23 | return false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import Qs from 'Qs' 3 | import { Message } from 'element-ui' 4 | import store from '@/store' 5 | 6 | // 本工程中axios使用,均通过其API构建请求,可参考https://www.kancloud.cn/yunye/axios/234845 7 | // create an axios instance 8 | const service = axios.create({ 9 | baseURL: process.env.BASE_API, // api 的 base_url 10 | timeout: 20000 // request timeout 11 | }) 12 | service.defaults.withCredentials = true 13 | 14 | // request interceptor 15 | service.interceptors.request.use( 16 | request => { 17 | // 后端服务jwt token信息 18 | if (store.getters.token) { 19 | request.headers.common['Authorization'] = `${store.getters.token}` 20 | } 21 | return request 22 | }, 23 | error => { 24 | // 请求发生错误 25 | console.log('request interceptor error') // for debug 26 | Promise.reject(error) 27 | } 28 | ) 29 | // { 30 | // code: 1, //1:正确结果,2:回话过期,3:非法回话,4:权限不足,5:未知错误 31 | // message: 后端错误信息 32 | // data: 后端正常处理结果封装 33 | // } 34 | // response interceptor 35 | service.interceptors.response.use( 36 | response => { 37 | const res = response.data 38 | if ('' + res.code !== '1') { 39 | if (('' + res.code).indexOf('3') === 0) { // 规则码3开头的均为回话问题,token过期等 40 | Message({ 41 | message: '你已从其他终端登出,或回话已超时,请重新登录', 42 | type: 'warning' 43 | }) 44 | store.dispatch('FedLogOut').then(() => { 45 | location.reload() // 为了重新实例化vue-router对象 避免bug 46 | }) 47 | } 48 | console.log('response interceptor: error') // for debug 49 | if (res.message) { 50 | Message({ 51 | message: res.message, 52 | type: 'error', 53 | duration: 3 * 1000 54 | }) 55 | } 56 | return Promise.reject('error') 57 | } else { 58 | console.log(res.data) 59 | return res.data 60 | } 61 | }, 62 | error => { 63 | console.log('response interceptor error') // for debug 64 | Message({ 65 | message: error.message, 66 | type: 'error', 67 | duration: 3 * 1000 68 | }) 69 | return Promise.reject(error) 70 | } 71 | ) 72 | 73 | export default function ({ url, method = 'get', data = null }) { 74 | // 解决axios post请求Request Payload问题 75 | if (data && method.toLowerCase() === 'post') { 76 | // 对 data 进行任意转换处理 77 | const isDeep = Object.keys(data).findIndex(prop => { 78 | const type = Object.prototype.toString.call(data[prop]) 79 | return type === '[object Object]' || type === '[object Array]' || type === '[object JSON]' 80 | }) !== -1 81 | 82 | if (isDeep) { 83 | // 嵌套data,对层JSON对象,提交时采用 Request Payload 方案 84 | // data 原样输出 85 | } else { 86 | // 非嵌套data,提交时采用Request FormData方案 87 | // data需要进行转换 88 | data = Qs.stringify(data) 89 | } 90 | } 91 | if (method.toLowerCase() === 'post') { 92 | return service({ 93 | url, 94 | method, 95 | data 96 | }) 97 | } else if(method.toLowerCase() === 'get') { 98 | return service({ 99 | url, 100 | method, 101 | params: data 102 | }) 103 | } else { 104 | throw "目前仅仅支持get/post方法" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/utils/scrollTo.js: -------------------------------------------------------------------------------- 1 | Math.easeInOutQuad = function(t, b, c, d) { 2 | t /= d / 2 3 | if (t < 1) { 4 | return c / 2 * t * t + b 5 | } 6 | t-- 7 | return -c / 2 * (t * (t - 2) - 1) + b 8 | } 9 | 10 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts 11 | var requestAnimFrame = (function() { 12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } 13 | })() 14 | 15 | // because it's so fucking difficult to detect the scrolling element, just move them all 16 | function move(amount) { 17 | document.documentElement.scrollTop = amount 18 | document.body.parentNode.scrollTop = amount 19 | document.body.scrollTop = amount 20 | } 21 | 22 | function position() { 23 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop 24 | } 25 | 26 | export function scrollTo(to, duration, callback) { 27 | const start = position() 28 | const change = to - start 29 | const increment = 20 30 | let currentTime = 0 31 | duration = (typeof (duration) === 'undefined') ? 500 : duration 32 | var animateScroll = function() { 33 | // increment the time 34 | currentTime += increment 35 | // find the value with the quadratic in-out easing function 36 | var val = Math.easeInOutQuad(currentTime, start, change, duration) 37 | // move the document.body 38 | move(val) 39 | // do the animation unless its over 40 | if (currentTime < duration) { 41 | requestAnimFrame(animateScroll) 42 | } else { 43 | if (callback && typeof (callback) === 'function') { 44 | // the animation is done so lets callback 45 | callback() 46 | } 47 | } 48 | } 49 | animateScroll() 50 | } 51 | -------------------------------------------------------------------------------- /src/utils/validate.js: -------------------------------------------------------------------------------- 1 | 2 | /* 合法uri*/ 3 | export function validateURL(textval) { 4 | 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.,?'\\+&%$#=~_-]+))*$/ 5 | return urlregex.test(textval) 6 | } 7 | 8 | /* 小写字母*/ 9 | export function validateLowerCase(str) { 10 | const reg = /^[a-z]+$/ 11 | return reg.test(str) 12 | } 13 | 14 | /* 大写字母*/ 15 | export function validateUpperCase(str) { 16 | const reg = /^[A-Z]+$/ 17 | return reg.test(str) 18 | } 19 | 20 | /* 大小写字母*/ 21 | export function validateAlphabets(str) { 22 | const reg = /^[A-Za-z]+$/ 23 | return reg.test(str) 24 | } 25 | 26 | /** 27 | * validate email 28 | * @param email 29 | * @returns {boolean} 30 | */ 31 | export function validateEmail(email) { 32 | 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,}))$/ 33 | return re.test(email) 34 | } 35 | -------------------------------------------------------------------------------- /src/views/code-generator/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /src/views/common/components/auditInfo/auditInfo.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 37 | 38 | 41 | -------------------------------------------------------------------------------- /src/views/common/components/buttons/ButtonRight.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | -------------------------------------------------------------------------------- /src/views/common/components/buttons/NewLineButtonRight.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /src/views/common/components/dictionaryTranslates/State.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /src/views/common/components/formItemViews/InputItemView.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 42 | 43 | 54 | -------------------------------------------------------------------------------- /src/views/common/components/formItemViews/TextItemView.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 42 | 43 | 54 | -------------------------------------------------------------------------------- /src/views/common/components/layouts/FlexCenter.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/views/common/components/layouts/FlexLeft.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/views/common/components/layouts/FlexRight.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/views/common/components/paginations/pagination.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 46 | 47 | 52 | -------------------------------------------------------------------------------- /src/views/common/components/selects/SelectRight.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 40 | -------------------------------------------------------------------------------- /src/views/common/index.js: -------------------------------------------------------------------------------- 1 | import upperFirst from 'lodash/upperFirst' 2 | import camelCase from 'lodash/camelCase' 3 | 4 | const requireComponent = require.context( 5 | // 其组件目录的相对路径 6 | './components', 7 | // 是否查询其子目录 8 | true, 9 | // 匹配基础组件文件名的正则表达式 10 | /[A-Za-z]\w+\.vue$/ 11 | ) 12 | 13 | const components = {} 14 | 15 | requireComponent.keys().forEach(fileName => { 16 | // 获取组件配置 17 | const componentConfig = requireComponent(fileName) 18 | 19 | fileName = (fileName.split('/'))[fileName.split('/').length - 1] 20 | 21 | // 获取组件的 PascalCase 命名 22 | const componentName = upperFirst( 23 | camelCase( 24 | // 排出子目录 25 | // 结尾的扩展名 26 | fileName.replace('.vue', '') 27 | ) 28 | ) 29 | 30 | // 如果这个组件选项是通过 `export default` 导出的, 31 | // 那么就会优先使用 `.default`, 32 | // 否则回退到使用模块的根。 33 | components[componentName] = componentConfig.default || componentConfig 34 | }) 35 | 36 | export default components 37 | -------------------------------------------------------------------------------- /src/views/common/mixins/BaseEditForm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * newest 记录最新的表单(通常为后端返回结果存储) 3 | */ 4 | export default { 5 | methods: { 6 | backHandler(data) { 7 | if (this.customBackHandler) { 8 | this.customBackHandler(data) 9 | } else { 10 | this.$emit('option-changed') 11 | } 12 | }, 13 | submitHandler(form, otherSubmitHandler = null) { 14 | this.newest = null 15 | this.$refs[form].validate((valid) => { 16 | if (!valid) return false 17 | this.$confirm('确定要保存吗?', '提示', { 18 | confirmButtonText: '确定', 19 | cancelButtonText: '取消', 20 | type: 'warning' 21 | }).then(() => { 22 | if (otherSubmitHandler) { 23 | otherSubmitHandler() 24 | } else { 25 | this.customSubmitHandler() 26 | } 27 | }).catch(() => { 28 | this.$message({ 29 | type: 'info', 30 | message: '已取消操作' 31 | }) 32 | }) 33 | }) 34 | }, 35 | submitSuccessHandler(data) { 36 | this.optionSuccessHandler() 37 | this.newest = data 38 | if (this.customSubmitSuccessHandler) { 39 | this.customSubmitSuccessHandler(data) 40 | } else { 41 | this.backHandler(data) 42 | } 43 | }, 44 | optionSuccessHandler() { 45 | this.$message({ 46 | type: 'success', 47 | message: '操作成功' 48 | }) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/views/common/mixins/BaseQueryPageForm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 适用于一个一个查询对象+一个分页结果集展示的简单组件 3 | * 约束: 4 | * 寄主对象中应具有: 5 | * --this.queryCriteria : 表单查询对象封装 6 | * --this.initQueryCriteria() : 表单查询对象初始化函数 7 | * --this.executeQueryPage : 分页表单查询接口 8 | */ 9 | 10 | import { deepMerge, deepClone } from '@/utils' 11 | 12 | export default { 13 | data() { 14 | const pagination = this.initPagination() 15 | return { 16 | autoRefresh: true, 17 | pagination: pagination 18 | } 19 | }, 20 | activated() { 21 | if (this.autoRefresh) { 22 | this.executeQueryPage() 23 | } 24 | }, 25 | methods: { 26 | initPagination(pagination = {}) { 27 | return deepMerge(pagination, { 28 | total: 0, 29 | pageSize: 10, 30 | page: 1, 31 | list: [], 32 | filters: [], 33 | sorts: [] 34 | }) 35 | }, 36 | resetHandler() { 37 | this.initQueryCriteria(this.queryCriteria) 38 | this.initPagination(this.pagination) 39 | this.executeQueryPage() 40 | }, 41 | queryHandler() { 42 | this.initPagination(this.pagination) 43 | this.executeQueryPage() 44 | }, 45 | createQueryParams() { 46 | this.pagination.filters = [] 47 | Object.keys(this.queryCriteria).forEach(key => { 48 | const value = this.queryCriteria[key] 49 | if (value) { 50 | if (typeof value === 'object') { 51 | this.pagination.filters.push({ field: key, value: deepClone(value) }) 52 | } else { 53 | this.pagination.filters.push({ field: key, value: value }) 54 | } 55 | } 56 | }) 57 | let filters = this.pagination.filters; 58 | if (this.pagination.sorts) { 59 | filters = filters.concat(this.pagination.sorts) 60 | } 61 | console.log(filters) 62 | return { 63 | page: this.pagination.page, 64 | pageSize: this.pagination.pageSize, 65 | filters: filters 66 | } 67 | }, 68 | queryResultHandler(result) { 69 | return deepMerge(this.pagination, result) 70 | }, 71 | pageSizeChangeHandler(pageSize) { 72 | this.pagination.pageSize = pageSize 73 | this.pagination.page = 1 74 | this.executeQueryPage() 75 | }, 76 | pageChangeHandler(page) { 77 | this.pagination.page = page 78 | this.executeQueryPage() 79 | }, 80 | sortChangeHandler({ column, prop, order }) { 81 | // ElementUI 目前并不支持远端多字段排序 82 | // sorts数组设计的目的是为了支持ElementUI后续拓展 83 | 84 | this.pagination.sorts = [] 85 | // sorts = [type: 'ORDER_BY_DESC', field: ['name']] 86 | if (column) { 87 | this.pagination.sorts.push({ 88 | field: [prop], 89 | type: order === 'descending' ? 'ORDER_BY_DESC' : 'ORDER_BY_ASC' 90 | }) 91 | } 92 | this.pagination.page = 1 93 | this.executeQueryPage() 94 | }, 95 | delHandler() { 96 | this.$confirm('此操作将永久删除, 是否继续?', '提示', { 97 | confirmButtonText: '确定', 98 | cancelButtonText: '取消', 99 | type: 'warning' 100 | }).then(() => { 101 | if (this.customDelHandler) { 102 | this.customDelHandler() 103 | } else { 104 | this.$message({ 105 | type: 'info', 106 | message: '您未定义删除逻辑处理方法customDelHandler' 107 | }) 108 | } 109 | }).catch(() => { 110 | this.$message({ 111 | type: 'info', 112 | message: '已取消删除' 113 | }) 114 | }) 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/views/dashboard/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 23 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | 22 | 31 | 32 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/components/Sidebar/Item.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 39 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/components/Sidebar/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 45 | 54 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as Navbar } from './Navbar' 2 | export { default as Sidebar } from './Sidebar/index.vue' 3 | export { default as TagsView } from './TagsView' 4 | export { default as AppMain } from './AppMain' 5 | -------------------------------------------------------------------------------- /src/views/layout/LeftAccordionSidebar/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | 40 | 133 | -------------------------------------------------------------------------------- /src/views/layout/MenuGroup/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /src/views/system-management/dept/add.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 70 | 71 | 74 | -------------------------------------------------------------------------------- /src/views/system-management/dept/check.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 65 | 66 | 71 | -------------------------------------------------------------------------------- /src/views/system-management/dept/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/dept/mixins.js: -------------------------------------------------------------------------------- 1 | import * as DeptAPI from '@/api/system-management/dept' 2 | 3 | export default { 4 | data() { 5 | return { 6 | parentDeptName: '', 7 | users: [], 8 | roles: [] 9 | } 10 | }, 11 | methods: { 12 | initForm() { 13 | return { 14 | id: null, 15 | token: null, 16 | parentId: null, 17 | type: '', 18 | name: '', 19 | sortNum: '', 20 | remark: '' 21 | } 22 | }, 23 | initRules() { 24 | return { 25 | type: [{ 26 | required: true, message: '请输入部门类型', trigger: 'blur' 27 | }], 28 | name: [{ 29 | required: true, message: '请输入部门名称', trigger: 'blur' 30 | }, { 31 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 32 | }], 33 | sortNum: [{ 34 | required: true, message: '请输入部门编号', trigger: 'blur' 35 | }] 36 | } 37 | }, 38 | queryAllUsers() { 39 | this.users = [] 40 | DeptAPI.queryAllDeptUsers(this.detail.id).then(users => { 41 | this.users = users 42 | }) 43 | }, 44 | queryAllRoles() { 45 | this.roles = [] 46 | DeptAPI.queryAllDeptRoles(this.detail.id).then(roles => { 47 | this.roles = roles 48 | }) 49 | }, 50 | getParentDeptName(id) { 51 | this.parentDeptName = '' 52 | if (!id) return 53 | DeptAPI.queryDeptById(id).then(dept => { 54 | this.parentDeptName = dept.name 55 | }) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary-type/add.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary-type/check.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 38 | 39 | 44 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary-type/edit.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 67 | 68 | 71 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary-type/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary-type/mixins.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | initForm() { 4 | return { 5 | id: null, 6 | token: null, 7 | parentId: null, 8 | category: 1, 9 | type: '', 10 | name: '', 11 | code: '', 12 | sortNum: '', 13 | remark: '' 14 | } 15 | }, 16 | initRules() { 17 | return { 18 | name: [{ 19 | required: true, message: '请输入字典分类名称', trigger: 'blur' 20 | }, { 21 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 22 | }], 23 | sortNum: [{ 24 | required: true, message: '请输入字典分类编号', trigger: 'blur' 25 | }] 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/add.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 77 | 78 | 83 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/check.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/edit.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 77 | 78 | 83 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/mixins.js: -------------------------------------------------------------------------------- 1 | import { mapGetters } from 'vuex' 2 | import * as DictionaryAPI from '@/api/system-management/dictionary' 3 | 4 | export default { 5 | props: { 6 | category: { 7 | required: true, 8 | type: String, 9 | default: () => {} 10 | }, 11 | detail: { 12 | required: false, 13 | type: Object, 14 | default: () => {} 15 | } 16 | }, 17 | data() { 18 | return { 19 | parentDictionaryName: '', 20 | dictionaryTypeList: [] 21 | } 22 | }, 23 | computed: { 24 | ...mapGetters([ 25 | 'dictionaries' 26 | ]) 27 | }, 28 | methods: { 29 | initForm() { 30 | return { 31 | id: null, 32 | token: null, 33 | parentId: null, 34 | category: 2, 35 | type: '', 36 | name: '', 37 | code: '', 38 | sortNum: '', 39 | remark: '' 40 | } 41 | }, 42 | initRules() { 43 | return { 44 | category: [{ 45 | required: true, message: '字典类别为必填项', trigger: 'change' 46 | }], 47 | type: [{ 48 | required: true, message: '请选择字典类型', trigger: 'change' 49 | }], 50 | name: [{ 51 | required: true, message: '请输入字典名称', trigger: 'blur' 52 | }, { 53 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 54 | }], 55 | sortNum: [{ 56 | required: true, message: '请输入字典编号', trigger: 'blur' 57 | }] 58 | } 59 | }, 60 | queryAllDictionaryType() { 61 | DictionaryAPI.queryAllDictionaries([{ field: 'category', value: 1 }]).then((list) => { 62 | this.dictionaryTypeList = list 63 | }, () => { 64 | this.dictionaryTypeList = [] 65 | }) 66 | }, 67 | getDictionaryTypeName(type) { 68 | const dictionary = this.dictionaryTypeList.find(item => item.id === type) 69 | if (dictionary) { 70 | return dictionary.name 71 | } 72 | return type 73 | }, 74 | getParentDictionaryName(id) { 75 | this.parentDictionaryName = '' 76 | if (!id || id === 'root') return 77 | DictionaryAPI.queryDictionaryById(id).then(dictionary => { 78 | this.parentDictionaryName = dictionary.name 79 | }) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/multiMain.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/dictionary/singleMain.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/group/add.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /src/views/system-management/group/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/group/mixins.js: -------------------------------------------------------------------------------- 1 | import * as GroupAPI from '@/api/system-management/group' 2 | 3 | export default { 4 | props: { 5 | detail: { 6 | required: false, 7 | type: Object, 8 | default: () => {} 9 | } 10 | }, 11 | data() { 12 | return { 13 | isUserGroup: this.$route.query.category === '' + 1, 14 | isRoleGroup: this.$route.query.category === '' + 2 15 | } 16 | }, 17 | methods: { 18 | initForm() { 19 | return { 20 | id: null, 21 | // 新增操作,根据路由决定该值的实际取值,分组可面向用户、角色等 22 | // 其他操作不允许修改该字段 23 | category: this.$route.query.category, 24 | name: '', 25 | sortNum: '', 26 | remark: '' 27 | } 28 | }, 29 | initRules() { 30 | return { 31 | category: [{ 32 | required: true, message: '请输入分组类型', trigger: 'blur' 33 | }], 34 | name: [{ 35 | required: true, message: '请输入分组名称', trigger: 'blur' 36 | }, { 37 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 38 | }], 39 | sortNum: [{ 40 | required: true, message: '请输入分组编号', trigger: 'blur' 41 | }] 42 | } 43 | }, 44 | queryAllUsers() { 45 | this.users = [] 46 | let queryAllUsers = null 47 | if (this.isUserGroup) { 48 | queryAllUsers = GroupAPI.queryAllUserGroupUsers // 用户分组下的所有用户 49 | } 50 | if (this.isRoleGroup) { 51 | queryAllUsers = GroupAPI.queryAllRoleGroupUsers // 角色分组下的所有用户 52 | } 53 | queryAllUsers(this.detail.id).then(users => { 54 | this.users = users 55 | }) 56 | }, 57 | queryAllGroups() { 58 | this.groups = [] 59 | let queryAllGroups = null 60 | if (this.isUserGroup) { 61 | queryAllGroups = GroupAPI.queryAllRoleGroups // 用户分组下的所有角色分组 62 | } 63 | if (this.isRoleGroup) { 64 | queryAllGroups = GroupAPI.queryAllUserGroups // 角色分组下的所有用户分组 65 | } 66 | queryAllGroups(this.detail.id).then(groups => { 67 | this.groups = groups 68 | }) 69 | }, 70 | queryAllRoles() { 71 | this.roles = [] 72 | GroupAPI.queryAllGroupRoles(this.detail.id).then(roles => { 73 | this.roles = roles 74 | }) 75 | }, 76 | getGroupName() { 77 | if (this.isUserGroup) return '关联的角色组信息' 78 | if (this.isRoleGroup) return '关联的用户组信息' 79 | return '未知分组信息' 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/views/system-management/menu/check.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 61 | 62 | 67 | -------------------------------------------------------------------------------- /src/views/system-management/menu/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 33 | -------------------------------------------------------------------------------- /src/views/system-management/menu/mixins.js: -------------------------------------------------------------------------------- 1 | import * as MenuAPI from '@/api/system-management/menu' 2 | 3 | export default { 4 | data() { 5 | return { 6 | parentMenuName: '', 7 | roles: [], 8 | securities: [] 9 | } 10 | }, 11 | methods: { 12 | queryMenuRoles() { 13 | this.roles = [] 14 | MenuAPI.queryAllMenuRole(this.detail.id).then(roles => { this.roles = roles }) 15 | }, 16 | queryMenuSecurities() { 17 | this.securities = [] 18 | MenuAPI.queryAllMenuSecurities(this.detail.id).then(securities => { 19 | this.securities = securities 20 | }) 21 | }, 22 | getParentMenuName(id) { 23 | this.parentMenuName = '' 24 | if (!id) return 25 | MenuAPI.queryMenuById(id).then(menu => { 26 | this.parentMenuName = menu.name 27 | }) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/views/system-management/role/add.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 61 | 62 | 65 | -------------------------------------------------------------------------------- /src/views/system-management/role/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/role/mixins.js: -------------------------------------------------------------------------------- 1 | import * as RoleAPI from '@/api/system-management/role' 2 | import * as MenuAPI from '@/api/system-management/menu' 3 | import { asyncMenuMap } from '@/router' 4 | 5 | export default { 6 | data() { 7 | return { 8 | menusTree: [], 9 | users: [], 10 | groups: [], 11 | depts: [] 12 | } 13 | }, 14 | methods: { 15 | initForm() { 16 | return { 17 | id: null, 18 | token: null, 19 | name: '', 20 | sortNum: '', 21 | remark: '' 22 | } 23 | }, 24 | initRules() { 25 | return { 26 | name: [{ 27 | required: true, message: '请输入角色名称', trigger: 'blur' 28 | }, { 29 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 30 | }], 31 | sortNum: [{ 32 | required: true, message: '请输入角色编号', trigger: 'blur' 33 | }] 34 | } 35 | }, 36 | queryAllUsers() { 37 | this.users = [] 38 | RoleAPI.queryAllRoleUsers(this.detail.id).then(users => { 39 | this.users = users 40 | }) 41 | }, 42 | queryAllGroups() { 43 | this.groups = [] 44 | RoleAPI.queryAllRoleGroups(this.detail.id).then(groups => { 45 | this.groups = groups 46 | }) 47 | }, 48 | queryAllDepts() { 49 | this.depts = [] 50 | RoleAPI.queryAllRoleDepts(this.detail.id).then(depts => { 51 | this.depts = depts 52 | }) 53 | }, 54 | filterNodeHandler(value, data) { 55 | if (!value) return true 56 | return data.name.indexOf(value) !== -1 57 | }, 58 | initMenus() { 59 | MenuAPI.queryAllMenus({}).then(allMenus => { 60 | const menusTree = [] 61 | asyncMenuMap.forEach(router => { 62 | menusTree.push(MenuAPI.createMenuTree(allMenus, router, null)) 63 | }) 64 | this.menusTree = menusTree 65 | const needSync = this.menusTree.some(menu => { 66 | return MenuAPI.syncMenuVoter(allMenus, menu) 67 | }) 68 | if (needSync) { 69 | this.$notify({ 70 | title: '提示', 71 | type: 'warning', 72 | message: '检测到您需要同步本地菜单信息树至服务端', 73 | duration: 0 74 | }) 75 | } 76 | 77 | RoleAPI.queryAllRoleMenus(this.detail.id).then(roleMenus => { 78 | const checkedMenus = [] 79 | roleMenus.forEach(item => { 80 | checkedMenus.push(item.id) 81 | }) 82 | this.$refs['menusTree'].setCheckedKeys(checkedMenus) 83 | }) 84 | }) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/views/system-management/role/query.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 88 | 89 | 98 | -------------------------------------------------------------------------------- /src/views/system-management/security/add.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 60 | 61 | 64 | -------------------------------------------------------------------------------- /src/views/system-management/security/check.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 42 | 43 | 48 | -------------------------------------------------------------------------------- /src/views/system-management/security/edit.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 75 | 76 | 81 | -------------------------------------------------------------------------------- /src/views/system-management/security/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /src/views/system-management/security/mixins.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | initForm() { 4 | return { 5 | id: null, 6 | securityDef: null, 7 | name: '', 8 | remark: '' 9 | } 10 | }, 11 | initRules() { 12 | return { 13 | securityDef: [{ 14 | required: true, message: '请输入资源定义', trigger: 'blur' 15 | }, { 16 | min: 1, max: 200, message: '长度在 1 到 200 个字符', trigger: 'blur' 17 | }], 18 | name: [{ 19 | required: true, message: '请输入资源名称', trigger: 'blur' 20 | }, { 21 | min: 4, max: 20, message: '长度在 4 到 20 个字符', trigger: 'blur' 22 | }], 23 | remark: [{ 24 | min: 0, max: 200, message: '长度在 0 到 200 个字符', trigger: 'blur' 25 | }] 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/views/system-management/user/main.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 35 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | 4 | function resolve(dir) { 5 | return path.join(__dirname, dir) 6 | } 7 | 8 | const port = 9527 // TODO: change to Settings 9 | const appName = 'element-admin' 10 | 11 | module.exports = { 12 | /** 13 | * You can set by yourself according to actual condition 14 | * You will need to set this if you plan to deploy your site under a sub path, 15 | * for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/, 16 | * then assetsPublicPath should be set to "/bar/". 17 | * In most cases please use '/' !!! 18 | * Detail https://cli.vuejs.org/config/#baseurl 19 | */ 20 | publicPath: '/', 21 | outputDir: 'dist', 22 | assetsDir: 'public', 23 | lintOnSave: process.env.NODE_ENV !== 'production', 24 | productionSourceMap: false, 25 | devServer: { 26 | port: port, 27 | open: true, 28 | overlay: { 29 | warnings: false, 30 | errors: true 31 | }, 32 | proxy: { 33 | '/admin': { 34 | // target: `http://localhost:${port}/mock`, 35 | target: 'http://localhost:8080', 36 | changeOrigin: true, 37 | pathRewrite: { 38 | '^/' : '/' 39 | } 40 | } 41 | } 42 | }, 43 | configureWebpack: { 44 | // We provide the app's title in Webpack's name field, so that 45 | // it can be accessed in index.html to inject the correct title. 46 | name: appName, 47 | resolve: { 48 | alias: { 49 | '@': resolve('src') 50 | } 51 | } 52 | }, 53 | chainWebpack(config) { 54 | config.module 55 | .rule('svg') 56 | .exclude.add(resolve('src/icons')) 57 | .end() 58 | config.module 59 | .rule('icons') 60 | .test(/\.svg$/) 61 | .include.add(resolve('src/icons')) 62 | .end() 63 | .use('svg-sprite-loader') 64 | .loader('svg-sprite-loader') 65 | .options({ 66 | symbolId: 'icon-[name]' 67 | }) 68 | .end() 69 | } 70 | } 71 | --------------------------------------------------------------------------------