chenjun 3 years ago
commit
596407b5dd
100 changed files with 5866 additions and 0 deletions
  1. 14 0
      .editorconfig
  2. 5 0
      .env.development
  3. 6 0
      .env.production
  4. 8 0
      .env.staging
  5. 4 0
      .eslintignore
  6. 198 0
      .eslintrc.js
  7. 16 0
      .gitignore
  8. 5 0
      .travis.yml
  9. 21 0
      LICENSE
  10. 111 0
      README-zh.md
  11. 99 0
      README.md
  12. 14 0
      babel.config.js
  13. 35 0
      build/index.js
  14. 24 0
      jest.config.js
  15. 9 0
      jsconfig.json
  16. 57 0
      mock/index.js
  17. 81 0
      mock/mock-server.js
  18. 29 0
      mock/table.js
  19. 84 0
      mock/user.js
  20. 25 0
      mock/utils.js
  21. 66 0
      package.json
  22. 8 0
      postcss.config.js
  23. 2 0
      public/config.js
  24. BIN
      public/favicon.ico
  25. 18 0
      public/index.html
  26. 238 0
      src/App.vue
  27. 63 0
      src/api/Account.js
  28. 81 0
      src/api/AccountGroup.js
  29. 210 0
      src/api/apiAuthority.js
  30. 72 0
      src/api/apiHome.js
  31. 31 0
      src/api/authGroupApi.js
  32. 71 0
      src/api/jobApi.js
  33. 46 0
      src/api/login.js
  34. 203 0
      src/api/postInterface.js
  35. 70 0
      src/api/systemConfiguration.js
  36. 10 0
      src/api/table.js
  37. 24 0
      src/api/user.js
  38. BIN
      src/assets/404_images/404.png
  39. BIN
      src/assets/404_images/404_cloud.png
  40. BIN
      src/assets/index/ic_close_card.png
  41. BIN
      src/assets/index/ic_data@2x.png
  42. BIN
      src/assets/index/ic_screen@2x.png
  43. BIN
      src/assets/index/ic_screen_edit@2x.png
  44. BIN
      src/assets/index/ic_time@2x.png
  45. BIN
      src/assets/loginpage/bg.jpg
  46. BIN
      src/assets/loginpage/d5b3da3756ddcd18e866ed91656935f.png
  47. BIN
      src/assets/loginpage/ic_ding_log@2x.png
  48. BIN
      src/assets/loginpage/ic_eye_close_password@2x.png
  49. BIN
      src/assets/loginpage/ic_eye_open_password@2x.png
  50. BIN
      src/assets/loginpage/ic_mail_log.png
  51. BIN
      src/assets/loginpage/ic_mail_log@2x.png
  52. BIN
      src/assets/loginpage/ic_password_log@2x.png
  53. BIN
      src/assets/loginpage/ic_phone_log@2x.png
  54. BIN
      src/assets/loginpage/ic_user_log@2x.png
  55. BIN
      src/assets/loginpage/ic_userid_log@2x.png
  56. BIN
      src/assets/loginpage/ic_wechat_log@2x.png
  57. BIN
      src/assets/nav/ic_home_nav_check.png
  58. BIN
      src/assets/status/ic_edit.png
  59. BIN
      src/assets/status/ic_edit_hovar.png
  60. BIN
      src/assets/status/ic_exit.png
  61. BIN
      src/assets/status/ic_exit_hovar.png
  62. BIN
      src/assets/status/ic_jobs.png
  63. BIN
      src/assets/status/ic_jobs_hovar.png
  64. BIN
      src/assets/status/ic_member.png
  65. BIN
      src/assets/status/ic_member_hovar.png
  66. BIN
      src/assets/status/ic_password.png
  67. BIN
      src/assets/status/ic_password_hovar.png
  68. BIN
      src/assets/status/ic_plus.png
  69. BIN
      src/assets/status/ic_plus_hovar.png
  70. BIN
      src/assets/status/ic_setting.png
  71. BIN
      src/assets/status/ic_setting_hovar.png
  72. BIN
      src/assets/status/ic_subordinate.png
  73. BIN
      src/assets/status/ic_subordinate_hovar.png
  74. BIN
      src/assets/status/ic_user.png
  75. 41 0
      src/checkPermission.js
  76. 118 0
      src/components/Breadcrumb/index.vue
  77. 157 0
      src/components/Hamburger/index.vue
  78. 62 0
      src/components/SvgIcon/index.vue
  79. 384 0
      src/components/bfbutton/index.vue
  80. 250 0
      src/components/competencypop/index.vue
  81. 149 0
      src/components/loginpolicy/index.vue
  82. 68 0
      src/components/loginpolicy/loginpolicy.scss
  83. 102 0
      src/components/loginpolicypop/index.vue
  84. 154 0
      src/components/loginpolicypop/loginpolicypop.scss
  85. 180 0
      src/components/organization/index.vue
  86. 103 0
      src/components/organization/organization.scss
  87. 175 0
      src/components/permissionlist/index.vue
  88. 249 0
      src/components/permissionlist/permissionlist.scss
  89. 238 0
      src/components/permissiontree/index copy.vue
  90. 372 0
      src/components/permissiontree/index.vue
  91. 189 0
      src/components/permissiontree/permissiontree.scss
  92. 129 0
      src/components/rolelist/index.vue
  93. 121 0
      src/components/rolelist/rolelist.scss
  94. 251 0
      src/components/rulesofcompetency/index copy.vue
  95. 231 0
      src/components/rulesofcompetency/index.vue
  96. 74 0
      src/components/rulesofcompetency/rulesofcompetency.scss
  97. 9 0
      src/icons/index.js
  98. 0 0
      src/icons/svg/dashboard.svg
  99. 1 0
      src/icons/svg/example.svg
  100. 1 0
      src/icons/svg/eye-open.svg

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+# http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 5 - 0
.env.development

@@ -0,0 +1,5 @@
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = '/dev-api'

+ 6 - 0
.env.production

@@ -0,0 +1,6 @@
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = '/prod-api'
+

+ 8 - 0
.env.staging

@@ -0,0 +1,8 @@
+NODE_ENV = production
+
+# just a flag
+ENV = 'staging'
+
+# base api
+VUE_APP_BASE_API = '/stage-api'
+

+ 4 - 0
.eslintignore

@@ -0,0 +1,4 @@
+build/*.js
+src/assets
+public
+dist

+ 198 - 0
.eslintrc.js

@@ -0,0 +1,198 @@
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/singleline-html-element-content-newline": "off",
+    "vue/multiline-html-element-content-newline":"off",
+    "vue/name-property-casing": ["error", "PascalCase"],
+    "vue/no-v-html": "off",
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': ["error", "always", {"null": "ignore"}],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+package-lock.json
+tests/**/coverage/
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 5 - 0
.travis.yml

@@ -0,0 +1,5 @@
+language: node_js
+node_js: 10
+script: npm run test
+notifications:
+  email: false

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-present PanJiaChen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 111 - 0
README-zh.md

@@ -0,0 +1,111 @@
+# vue-admin-template
+
+> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
+
+[线上地址](http://panjiachen.github.io/vue-admin-template)
+
+[国内访问](https://panjiachen.gitee.io/vue-admin-template)
+
+目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。
+
+<p align="center">
+  <b>SPONSORED BY</b>
+</p>
+<p align="center">
+   <a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
+      <img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
+   </a>
+</p>
+
+## Extra
+
+如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+## 相关项目
+
+- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
+- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
+
+- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
+
+- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
+
+写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
+
+- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
+- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
+- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
+- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
+- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
+
+## Build Setup
+
+```bash
+# 克隆项目
+git clone https://github.com/PanJiaChen/vue-admin-template.git
+
+# 进入项目目录
+cd vue-admin-template
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 [http://localhost:9528](http://localhost:9528)
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+```
+
+## 其它
+
+```bash
+# 预览发布环境效果
+npm run preview
+
+# 预览发布环境效果 + 静态资源分析
+npm run preview -- --report
+
+# 代码格式检查
+npm run lint
+
+# 代码格式检查并自动修复
+npm run lint -- --fix
+```
+
+更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## 购买贴纸
+
+你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。
+
+## Demo
+
+![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
+
+## License
+
+[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2017-present PanJiaChen

+ 99 - 0
README.md

@@ -0,0 +1,99 @@
+# vue-admin-template
+
+English | [简体中文](./README-zh.md)
+
+> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint
+
+**Live demo:** http://panjiachen.github.io/vue-admin-template
+
+
+**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
+
+<p align="center">
+  <b>SPONSORED BY</b>
+</p>
+<p align="center">
+   <a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
+      <img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
+   </a>
+</p>
+
+## Build Setup
+
+```bash
+# clone the project
+git clone https://github.com/PanJiaChen/vue-admin-template.git
+
+# enter the project directory
+cd vue-admin-template
+
+# install dependency
+npm install
+
+# develop
+npm run dev
+```
+
+This will automatically open http://localhost:9528
+
+## Build
+
+```bash
+# build for test environment
+npm run build:stage
+
+# build for production environment
+npm run build:prod
+```
+
+## Advanced
+
+```bash
+# preview the release environment effect
+npm run preview
+
+# preview the release environment effect + static resource analysis
+npm run preview -- --report
+
+# code format check
+npm run lint
+
+# code format check and auto fix
+npm run lint -- --fix
+```
+
+Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
+
+## Demo
+
+![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
+
+## Extra
+
+If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
+
+## Related Project
+
+- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
+- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
+
+- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
+
+- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
+
+## License
+
+[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2017-present PanJiaChen

+ 14 - 0
babel.config.js

@@ -0,0 +1,14 @@
+module.exports = {
+  presets: [
+    // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+    '@vue/cli-plugin-babel/preset'
+  ],
+  'env': {
+    'development': {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
+      'plugins': ['dynamic-import-node']
+    }
+  }
+}

+ 35 - 0
build/index.js

@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}

+ 24 - 0
jest.config.js

@@ -0,0 +1,24 @@
+module.exports = {
+  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
+  transform: {
+    '^.+\\.vue$': 'vue-jest',
+    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
+      'jest-transform-stub',
+    '^.+\\.jsx?$': 'babel-jest'
+  },
+  moduleNameMapper: {
+    '^@/(.*)$': '<rootDir>/src/$1'
+  },
+  snapshotSerializers: ['jest-serializer-vue'],
+  testMatch: [
+    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
+  ],
+  collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
+  coverageDirectory: '<rootDir>/tests/unit/coverage',
+  // 'collectCoverage': true,
+  'coverageReporters': [
+    'lcov',
+    'text-summary'
+  ],
+  testURL: 'http://localhost/'
+}

+ 9 - 0
jsconfig.json

@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "baseUrl": "./",
+    "paths": {
+        "@/*": ["src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}

+ 57 - 0
mock/index.js

@@ -0,0 +1,57 @@
+const Mock = require('mockjs')
+const { param2Obj } = require('./utils')
+
+const user = require('./user')
+const table = require('./table')
+
+const mocks = [
+  ...user,
+  ...table
+]
+
+// for front mock
+// please use it cautiously, it will redefine XMLHttpRequest,
+// which will cause many of your third-party libraries to be invalidated(like progress event).
+function mockXHR() {
+  // mock patch
+  // https://github.com/nuysoft/Mock/issues/300
+  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
+  Mock.XHR.prototype.send = function() {
+    if (this.custom.xhr) {
+      this.custom.xhr.withCredentials = this.withCredentials || false
+
+      if (this.responseType) {
+        this.custom.xhr.responseType = this.responseType
+      }
+    }
+    this.proxy_send(...arguments)
+  }
+
+  function XHR2ExpressReqWrap(respond) {
+    return function(options) {
+      let result = null
+      if (respond instanceof Function) {
+        const { body, type, url } = options
+        // https://expressjs.com/en/4x/api.html#req
+        result = respond({
+          method: type,
+          body: JSON.parse(body),
+          query: param2Obj(url)
+        })
+      } else {
+        result = respond
+      }
+      return Mock.mock(result)
+    }
+  }
+
+  for (const i of mocks) {
+    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
+  }
+}
+
+module.exports = {
+  mocks,
+  mockXHR
+}
+

+ 81 - 0
mock/mock-server.js

@@ -0,0 +1,81 @@
+const chokidar = require('chokidar')
+const bodyParser = require('body-parser')
+const chalk = require('chalk')
+const path = require('path')
+const Mock = require('mockjs')
+
+const mockDir = path.join(process.cwd(), 'mock')
+
+function registerRoutes(app) {
+  let mockLastIndex
+  const { mocks } = require('./index.js')
+  const mocksForServer = mocks.map(route => {
+    return responseFake(route.url, route.type, route.response)
+  })
+  for (const mock of mocksForServer) {
+    app[mock.type](mock.url, mock.response)
+    mockLastIndex = app._router.stack.length
+  }
+  const mockRoutesLength = Object.keys(mocksForServer).length
+  return {
+    mockRoutesLength: mockRoutesLength,
+    mockStartIndex: mockLastIndex - mockRoutesLength
+  }
+}
+
+function unregisterRoutes() {
+  Object.keys(require.cache).forEach(i => {
+    if (i.includes(mockDir)) {
+      delete require.cache[require.resolve(i)]
+    }
+  })
+}
+
+// for mock server
+const responseFake = (url, type, respond) => {
+  return {
+    url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
+    type: type || 'get',
+    response(req, res) {
+      console.log('request invoke:' + req.path)
+      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
+    }
+  }
+}
+
+module.exports = app => {
+  // parse app.body
+  // https://expressjs.com/en/4x/api.html#req.body
+  app.use(bodyParser.json())
+  app.use(bodyParser.urlencoded({
+    extended: true
+  }))
+
+  const mockRoutes = registerRoutes(app)
+  var mockRoutesLength = mockRoutes.mockRoutesLength
+  var mockStartIndex = mockRoutes.mockStartIndex
+
+  // watch files, hot reload mock server
+  chokidar.watch(mockDir, {
+    ignored: /mock-server/,
+    ignoreInitial: true
+  }).on('all', (event, path) => {
+    if (event === 'change' || event === 'add') {
+      try {
+        // remove mock routes stack
+        app._router.stack.splice(mockStartIndex, mockRoutesLength)
+
+        // clear routes cache
+        unregisterRoutes()
+
+        const mockRoutes = registerRoutes(app)
+        mockRoutesLength = mockRoutes.mockRoutesLength
+        mockStartIndex = mockRoutes.mockStartIndex
+
+        console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed  ${path}`))
+      } catch (error) {
+        console.log(chalk.redBright(error))
+      }
+    }
+  })
+}

+ 29 - 0
mock/table.js

@@ -0,0 +1,29 @@
+const Mock = require('mockjs')
+
+const data = Mock.mock({
+  'items|30': [{
+    id: '@id',
+    title: '@sentence(10, 20)',
+    'status|1': ['published', 'draft', 'deleted'],
+    author: 'name',
+    display_time: '@datetime',
+    pageviews: '@integer(300, 5000)'
+  }]
+})
+
+module.exports = [
+  {
+    url: '/vue-admin-template/table/list',
+    type: 'get',
+    response: config => {
+      const items = data.items
+      return {
+        code: 20000,
+        data: {
+          total: items.length,
+          items: items
+        }
+      }
+    }
+  }
+]

+ 84 - 0
mock/user.js

@@ -0,0 +1,84 @@
+
+const tokens = {
+  admin: {
+    token: 'admin-token'
+  },
+  editor: {
+    token: 'editor-token'
+  }
+}
+
+const users = {
+  'admin-token': {
+    roles: ['admin'],
+    introduction: 'I am a super administrator',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Super Admin'
+  },
+  'editor-token': {
+    roles: ['editor'],
+    introduction: 'I am an editor',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Normal Editor'
+  }
+}
+
+module.exports = [
+  // user login
+  {
+    url: '/vue-admin-template/user/login',
+    type: 'post',
+    response: config => {
+      const { username } = config.body
+      const token = tokens[username]
+
+      // mock error
+      if (!token) {
+        return {
+          code: 60204,
+          message: 'Account and password are incorrect.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: token
+      }
+    }
+  },
+
+  // get user info
+  {
+    url: '/vue-admin-template/user/info\.*',
+    type: 'get',
+    response: config => {
+      const { token } = config.query
+      const info = users[token]
+
+      // mock error
+      if (!info) {
+        return {
+          code: 50008,
+          message: 'Login failed, unable to get user details.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: info
+      }
+    }
+  },
+
+  // user logout
+  {
+    url: '/vue-admin-template/user/logout',
+    type: 'post',
+    response: _ => {
+      return {
+        code: 20000,
+        data: 'success'
+      }
+    }
+  }
+]

+ 25 - 0
mock/utils.js

@@ -0,0 +1,25 @@
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+function param2Obj(url) {
+  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+  if (!search) {
+    return {}
+  }
+  const obj = {}
+  const searchArr = search.split('&')
+  searchArr.forEach(v => {
+    const index = v.indexOf('=')
+    if (index !== -1) {
+      const name = v.substring(0, index)
+      const val = v.substring(index + 1, v.length)
+      obj[name] = val
+    }
+  })
+  return obj
+}
+
+module.exports = {
+  param2Obj
+}

+ 66 - 0
package.json

@@ -0,0 +1,66 @@
+{
+  "name": "vue-admin-template",
+  "version": "4.4.0",
+  "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
+  "author": "Pan <panfree23@gmail.com>",
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "preview": "node build/index.js --preview",
+    "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+    "lint": "eslint --ext .js,.vue src",
+    "test:unit": "jest --clearCache && vue-cli-service test:unit",
+    "test:ci": "npm run lint && npm run test:unit"
+  },
+  "dependencies": {
+    "axios": "0.18.1",
+    "core-js": "3.6.5",
+    "echarts": "^5.2.2",
+    "element-ui": "^2.15.7",
+    "js-cookie": "2.2.0",
+    "jsencrypt": "^3.2.1",
+    "lodash": "^4.17.21",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "path-to-regexp": "2.4.0",
+    "vue": "2.6.10",
+    "vue-router": "3.0.6",
+    "vue2-org-tree": "^1.3.5",
+    "vuex": "3.1.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "4.4.4",
+    "@vue/cli-plugin-eslint": "4.4.4",
+    "@vue/cli-plugin-unit-jest": "4.4.4",
+    "@vue/cli-service": "4.4.4",
+    "@vue/test-utils": "1.0.0-beta.29",
+    "autoprefixer": "9.5.1",
+    "babel-eslint": "10.1.0",
+    "babel-jest": "23.6.0",
+    "babel-plugin-dynamic-import-node": "2.3.3",
+    "chalk": "2.4.2",
+    "connect": "3.6.6",
+    "eslint": "6.7.2",
+    "eslint-plugin-vue": "6.2.2",
+    "html-webpack-plugin": "3.2.0",
+    "mockjs": "1.0.1-beta3",
+    "runjs": "4.3.2",
+    "sass": "1.26.8",
+    "sass-loader": "8.0.2",
+    "script-ext-html-webpack-plugin": "2.1.3",
+    "serve-static": "1.13.2",
+    "svg-sprite-loader": "4.1.3",
+    "svgo": "1.2.2",
+    "vue-template-compiler": "2.6.10"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ],
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "license": "MIT"
+}

+ 8 - 0
postcss.config.js

@@ -0,0 +1,8 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  'plugins': {
+    // to edit target browsers: use "browserslist" field in package.json
+    'autoprefixer': {}
+  }
+}

+ 2 - 0
public/config.js

@@ -0,0 +1,2 @@
+var PLATFROM_CONFIG = {};
+PLATFROM_CONFIG.baseUrl ="http://106.14.243.117:9002" // http请求地址

BIN
public/favicon.ico


+ 18 - 0
public/index.html

@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= webpackConfig.name %></title>
+    <script src="<%= BASE_URL %>config.js"></script>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 238 - 0
src/App.vue

@@ -0,0 +1,238 @@
+<!--
+ * @Author: your name
+ * @Date: 2021-10-14 17:17:53
+ * @LastEditTime: 2022-01-06 12:03:00
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \Foshan4A\src\App.vue
+-->
+<template>
+  <div id="app">
+    <!--全局休眠弹框-->
+    <Dialog :flag="false" customClass="dormancyDialog" width="496px">
+      <div class="dormancy">
+        <div class="title">系统休眠,请输入密码解锁</div>
+        <div class="content">
+          <el-form ref="form" :rules="rules" :model="form">
+            <el-form-item prop="pwd">
+              <el-input show-password placeholder="请输入密码" v-model="form.pwd"></el-input>
+            </el-form-item>
+            <el-form-item>
+              <button class="button-public-shadow onSubmit" @click="onSubmit('form')">
+                确定
+              </button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </div>
+    </Dialog>
+    <!--路由出口-->
+    <router-view />
+  </div>
+</template>
+
+<script>
+import Dialog from "@/layout/components/Dialog/index.vue";
+import { mapGetters } from "vuex";
+import { SsoLogin } from "@/api/apiHome";
+export default {
+  name: "App",
+  components: {
+    Dialog,
+  },
+  data () {
+    return {
+      arr: [], //鼠标移动screenX值数组
+      arrLen: [], //一段时间后上报的screenX值数组
+      timer: null, //定时器
+      time: null, //定时器时间 1=1S
+      desc: null, //固定的定时器时间/和time保持一致
+      form: {
+        //表单数据
+        pwd: "",
+      },
+      rules: {
+        //表单验证
+        pwd: [{ required: true, message: "请输入密码", trigger: "blur" }],
+      },
+    };
+  },
+  computed: {
+    ...mapGetters(["dialog", "token", "name", "systemSet"]),
+  },
+  watch: {
+    "$store.state.user.token": {
+      handler (val) {
+        if (val) {
+          this.handleInit();
+        } else {
+          this.clearAll();
+        }
+      },
+      deep: true,
+    },
+    $route: {
+      handler () {
+        this.$store.dispatch("auth/changeAuthMsg", []);
+        this.$store.dispatch("auth/changeAuthArrs", []);
+        this.$store.dispatch("auth/changeAuthList", []);
+        this.$store.dispatch("auth/changeAuthId", null);
+      },
+      deep: true,
+    },
+  },
+  mounted () {
+    this.beforeUnload();
+  },
+  beforeDestroy () {
+    //结束定时器和释放timer
+    this.clearAll();
+  },
+  methods: {
+    // 初始化
+    handleInit () {
+      this.handleMove();
+      if (!this.dialog) {
+        this.handleTimer();
+      }
+    },
+    /**
+     * @description: 清除页面定时器和监听
+     * @param {*}
+     * @return {*}
+     */
+    clearAll () {
+      clearInterval(this.timer);
+      this.timer = null;
+      this.time = null;
+      this.desc = null;
+      this.arr = [];
+      this.arrLen = [];
+      this.handleRmove();
+      sessionStorage.setItem("token", "");
+    },
+    // 页面刷新 重新启用方法
+    beforeUnload () {
+      window.addEventListener("beforeunload", () => {
+        if (this.token) {
+          sessionStorage.setItem("token", this.token);
+        }
+      });
+      let oldViews = sessionStorage.getItem("token") || "";
+      if (oldViews) {
+        this.handleInit();
+      }
+    },
+    /**
+     * @description: 定时器方法
+     * @param {*}
+     * @return {*}
+     */
+    handleTimer () {
+      const obj =
+        typeof this.systemSet === "string"
+          ? JSON.parse(this.systemSet)
+          : this.systemSet;
+      const { LockMins } = obj;
+      this.time = LockMins * 60;
+      this.desc = LockMins * 60;
+      this.timer = setInterval(() => {
+        this.time--;
+        if (this.time === 0) {
+          const result = this.arrLen;
+          const rut = this.arr;
+          result.push(rut.length);
+          if (result.length >= 2) {
+            if (result[result.length - 2] === result[result.length - 1]) {
+              // 相同时 结束倒计时
+              this.$store.dispatch("app/toggleDialog", true);
+              this.clearAll();
+            } else {
+              this.time = this.desc;
+            }
+          } else {
+            this.time = this.desc;
+          }
+        }
+      }, 1000);
+    },
+    /**
+     * @description: 监听鼠标移动方法/防抖
+     * @param {*}
+     * @return {*}
+     */
+    handleMove () {
+      window.addEventListener(
+        "mousemove",
+        _.debounce(this.handleDebounce, 100)
+      );
+    },
+    /**
+     * @description: 移除鼠标移动监听
+     * @param {*}
+     * @return {*}
+     */
+    handleRmove () {
+      window.removeEventListener("mousemove", () => {
+        this.arr = [];
+      });
+    },
+    /**
+     * @description: 防抖方法
+     * @param {*} e
+     * @return {*}
+     */
+    handleDebounce (e) {
+      const screenX = e.screenX;
+      this.arr.push(screenX);
+    },
+    /**
+     * @description: 提交
+     * @param {*}
+     * @return {*}
+     */
+    onSubmit (formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.ssoLogin();
+        } else {
+          return false;
+        }
+      });
+    },
+    //锁屏验证
+    async ssoLogin () {
+      const res = await SsoLogin({
+        LoginName: this.name,
+        LoginPwd: this.form.pwd,
+      });
+      if (res.code === 0) {
+        this.$store.dispatch("app/toggleDialog", false);
+        this.arr = [];
+        this.arrLen = [];
+        this.time = this.desc;
+        this.form.pwd = "";
+        this.handleTimer();
+      } else {
+        this.$message.error(res.message);
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+::v-deep .dormancyDialog {
+  .el-input__inner {
+    height: 48px;
+    line-height: 48px;
+    background: #f5f7fa;
+    border: 1px solid #ebeef5;
+    border-radius: 6px;
+  }
+  .onSubmit {
+    margin-top: 10px;
+  }
+}
+</style>
+

+ 63 - 0
src/api/Account.js

@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+
+// 账号列表查询
+export function GetAccountList(params) {
+  return request({
+    url: '/api/4A/GetUserList/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号状态变更
+
+export function ChangeUserStatus(params) {
+  return request({
+    url: '/api/4A/ChangeUserStatus/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号删除
+export function delAccount(params) {
+  return request({
+    url: '/api/4A/DeleteUser/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号新增保存
+export function addAccount(params) {
+
+  return request({
+    url: '/api/4A/SaveUser/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号详情查询
+export function accDeaitls(params) {
+  return request({
+    url: '/api/4A/GetUserDetails/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号编辑保存
+export function deitAcc(params) {
+  return request({
+    url: '/api/4A/EditUser/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}

+ 81 - 0
src/api/AccountGroup.js

@@ -0,0 +1,81 @@
+import request from '@/utils/request'
+
+// 账号组树查询
+export function GetGroupTree (params) {
+    return request({
+      url: '/api/4A/GetGroupTree/v1',
+      method: 'post',
+      data: params,
+      proxy: true
+    })
+  }
+
+  //账号组新增
+  export function SaveGroup(params){
+    return request({
+        url: '/api/4A/SaveGroup/v1',
+        method: 'post',
+        data: params,
+        proxy: true
+      })
+  }
+
+    //账号组删除
+    export function DeleteGroup(params){
+        return request({
+            url: '/api/4A/DeleteGroup/v1',
+            method: 'post',
+            data: params,
+            proxy: true
+          })
+      }
+
+  //账号组详情
+  export function GetGroupDetails(params){
+      return request({
+        url: '/api/4A/GetGroupDetails/v1',
+        method: 'post',
+        data: params,
+        proxy: true
+      })
+  }
+
+    //账号组修改状态
+    export function ChangeGroupStatus(params){
+        return request({
+          url: '/api/4A/ChangeGroupStatus/v1',
+          method: 'post',
+          data: params,
+          proxy: true
+        })
+    }
+
+    // 根据账号组获取权限树
+    export function GetAuthTreeByGroup(params){
+      return request({
+        url: '/api/4A/GetAuthTreeByGroup/v1',
+        method: 'post',
+        data: params,
+        proxy: true
+      })
+  }
+
+      // 修改保存账号组
+      export function EditGroup(params){
+        return request({
+          url: '/api/4A/EditGroup/v1',
+          method: 'post',
+          data: params,
+          proxy: true
+        })
+    }
+
+    //根据账号组获取角色
+    export function GetRoleByGroup(params){
+      return request({
+        url: '/api/4A/GetRoleByGroup/v1',
+        method: 'post',
+        data: params,
+        proxy: true
+      })
+  }

+ 210 - 0
src/api/apiAuthority.js

@@ -0,0 +1,210 @@
+/*
+ * @Author: your name
+ * @Date: 2021-12-21 09:22:04
+ * @LastEditTime: 2021-12-27 11:56:24
+ * @LastEditors: Please set LastEditors
+ * @Description: 权限项管理
+ * @FilePath: \Foshan4A2.0\src\api\apiAuthority.js
+ */
+import request from '@/utils/request'
+
+//权限树查询
+export function GetAuthTree (params) {
+  return request({
+    url: '/api/4A/GetAuthTree/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//应用新增保存
+export function SaveApp (params) {
+  return request({
+    url: '/api/4A/SaveApp/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//应用详情查询
+export function GetAppDetails (params) {
+  return request({
+    url: '/api/4A/GetAppDetails/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//应用修改保存
+export function EditApp (params) {
+  return request({
+    url: '/api/4A/EditApp/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//应用状态变更
+export function UpdateAppStatus (params) {
+  return request({
+    url: '/api/4A/UpdateAppStatus/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//应用删除
+export function DeleteApp (params) {
+  return request({
+    url: '/api/4A/DeleteApp/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+
+//权限项修改保存
+export function EditAuth (params) {
+  return request({
+    url: '/api/4A/EditAuth/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//权限详情查询
+export function GetAuthDetails (params) {
+  return request({
+    url: '/api/4A/GetAuthDetails/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//根据权限获取授权规则
+export function GetAuthTo (params) {
+  return request({
+    url: '/api/4A/GetAuthTo/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//权限项新增保存
+export function SaveAuth (params) {
+  return request({
+    url: '/api/4A/SaveAuth/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//权限项删除
+export function DeleteAuth (params) {
+  return request({
+    url: '/api/4A/DeleteAuth/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//权限状态变更
+export function UpdateAuthStatus (params) {
+  return request({
+    url: '/api/4A/UpdateAuthStatus/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色新增保存
+export function SaveRole (params) {
+  return request({
+    url: '/api/4A/SaveRole/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色列表查询
+export function QueryRole (params) {
+  return request({
+    url: '/api/4A/QueryRole/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//账号列表查询
+export function GetUserList (params) {
+  return request({
+    url: '/api/4A/GetUserList/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色明细查询
+export function RoleDetails (params) {
+  return request({
+    url: '/api/4A/RoleDetails/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色权限列表
+export function RoleAuths (params) {
+  return request({
+    url: '/api/4A/RoleAuths/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色删除
+export function DeleteRole (params) {
+  return request({
+    url: '/api/4A/DeleteRole/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色编辑保存
+export function EditRole (params) {
+  return request({
+    url: '/api/4A/EditRole/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//角色状态变更
+export function UpdateStatus (params) {
+  return request({
+    url: '/api/4A/UpdateStatus/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}

+ 72 - 0
src/api/apiHome.js

@@ -0,0 +1,72 @@
+/*
+ * @Author: your name
+ * @Date: 2021-12-20 10:26:41
+ * @LastEditTime: 2022-01-05 15:41:53
+ * @LastEditors: Please set LastEditors
+ * @Description: 首页接口
+ * @FilePath: \Foshan4A2.0\src\api\apiHome.js
+ */
+import request from '@/utils/request'
+
+//接入系统信息
+export function GetOthSystem (params) {
+  return request({
+    url: '/api/4A/GetOthSystem/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//账号信息分析
+export function GetUserAna (params) {
+  return request({
+    url: '/api/4A/GetUserAna/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//职员信息分析
+export function GetOfficerAna (params) {
+  return request({
+    url: '/api/4A/GetOfficerAna/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//角色信息分析
+export function GetRoleAna (params) {
+  return request({
+    url: '/api/4A/GetRoleAna/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//权限信息分析
+export function GetAuthAna (params) {
+  return request({
+    url: '/api/4A/GetAuthAna/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//修改密码
+export function EditPwd (params) {
+  return request({
+    url: '/api/4A/EditPwd/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//锁屏验证
+export function SsoLogin (params) {
+  return request({
+    url: '/api/4A/SsoLogin/v1',
+    method: 'post',
+    data: params
+  })
+}

+ 31 - 0
src/api/authGroupApi.js

@@ -0,0 +1,31 @@
+import request from '@/utils/request'
+
+// 根据组织获取权限组
+export function GetGroupByOrgan (params) {
+    return request({
+      url: '/api/4A/GetGroupByOrgan/v1',
+      method: 'post',
+      data: params,
+      proxy: true
+    })
+  }
+
+  //根据岗位获取权限组
+  export function GetGroupByJob(params){
+    return request({
+        url: '/api/4A/GetGroupByJob/v1',
+        method: 'post',
+        data: params,
+        proxy: true
+      })
+  }
+
+  //根据权限组获取权限列表
+  export function GroupAuths(params){
+    return request({
+      url: '/api/4A/GroupAuths/v1',
+      method: 'post',
+      data: params,
+      proxy: true
+    })
+  }

+ 71 - 0
src/api/jobApi.js

@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+//岗位列表查询
+export function GetJobList(params) {
+  return request({
+    url: '/api/4A/GetJobList/v1',
+    method: 'post',
+    data: params
+  })
+}
+
+//新增岗位
+export function SaveJob(params) {
+  return request({
+    url: '/api/4A/SaveJob/v1',
+    method: 'post',
+    data: params,
+  })
+}
+//修改岗位状态
+export function ChangeJobStatus(params) {
+  return request({
+    url: '/api/4A/ChangeJobStatus/v1',
+    method: 'post',
+    data: params,
+  })
+}
+
+//编辑岗位
+export function EditJob(params) {
+  return request({
+    url: '/api/4A/EditJob/v1',
+    method: 'post',
+    data: params,
+  })
+}
+//删除岗位
+export function DeleteJob(params) {
+  return request({
+    url: '/api/4A/DeleteJob/v1',
+    method: 'post',
+    data: params,
+  })
+}
+
+//根据岗位获取权限
+export function GetAuthTreeByJob(params) {
+  return request({
+    url: '/api/4A/GetAuthTreeByJob/v1',
+    method: 'post',
+    data: params,
+  })
+}
+
+//岗位详情
+export function GetJobDetails(params) {
+  return request({
+    url: '/api/4A/GetJobDetails/v1',
+    method: 'post',
+    data: params,
+  })
+}
+
+//根据岗位获取角色
+export function GetRoleByJob(params) {
+  return request({
+    url: '/api/4A/GetRoleByJob/v1',
+    method: 'post',
+    data: params,
+  })
+}

+ 46 - 0
src/api/login.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+
+//获取动态验证码
+export function GetCheckCode (params) {
+    return request({
+        url: '/api/4A/GetCheckCode/v1',
+        method: 'post',
+        data: params
+    })
+}
+
+//登录
+export function login (params) {
+    return request({
+        url: '/api/4A/Login/v1',
+        method: 'post',
+        data: params
+    })
+}
+
+//登出
+export function loginUp (params) {
+    return request({
+        url: '/api/4A/Logout/v1',
+        method: 'post',
+        data: params
+    })
+}
+
+//忘记密码
+export function changePassword (params) {
+    return request({
+        url: '/api/4A/ForgetPwd/v1',
+        method: 'post',
+        data: params
+    })
+}
+
+//权限获取
+export function permission (params) {
+    return request({
+        url: '/api/4A/GetAuth/v1',
+        method: 'post',
+        data: params
+    })
+}

+ 203 - 0
src/api/postInterface.js

@@ -0,0 +1,203 @@
+import request from '@/utils/request'
+
+//岗位列表查询
+export function postList (params) {
+    return request({
+        url: '/api/4A/GetJobList/v1',
+        method: 'post',
+        data: params
+    })
+}
+
+//组织树查询
+export function tissueTreeList (params) {
+    return request({
+        url: '/api/4A/GetOrganTree/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//组织树状态
+export function tissueTreeStart (params) {
+    return request({
+        url: '/api/4A/ChangeOrganStatus/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//职员查询
+export function staffList (params) {
+    return request({
+        url: '/api/4A/GetOfficerList/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//职员状态
+export function staffStart (params) {
+    return request({
+        url: '/api/4A/ChangeOfficerStatus/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//删除职员
+export function staffListele (params) {
+    return request({
+        url: '/api/4A/DeleteOfficer/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//新增岗位
+export function newPostUp (params) {
+    return request({
+        url: '/api/4A/SaveJob/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//岗位状态
+export function PostSatrt (params) {
+    return request({
+        url: '/api/4A/ChangeJobStatus/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//编辑岗位
+export function PostSatrtmod (params) {
+    return request({
+        url: '/api/4A/EditJob/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//删除岗位
+export function PostUpele (params) {
+    return request({
+        url: '/api/4A/DeleteJob/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+
+//新增组织
+export function newOrgan (params) {
+    return request({
+        url: '/api/4A/SaveOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//编辑组织
+export function newOrganmod (params) {
+    return request({
+        url: '/api/4A/EditOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+
+//组织详情
+export function newOrganall (params) {
+    return request({
+        url: '/api/4A/GetOrganDetails/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+
+//新增职员
+export function newstaff (params) {
+    return request({
+        url: '/api/4A/SaveOfficer/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//职员详情
+export function Staffdetails (params) {
+    return request({
+        url: '/api/4A/GetOfficerDetails/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//编辑职员
+export function newstaffmod (params) {
+    return request({
+        url: '/api/4A/EditOfficer/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//根据组织获取权限
+export function organizationUptree (params) {
+    return request({
+        url: '/api/4A/GetAuthTreeByOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}
+//根据岗位获取权限
+export function postUptree (params) {
+    return request({
+        url: '/api/4A/GetAuthTreeByJob/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//岗位详情
+export function jbdetails (params) {
+    return request({
+        url: '/api/4A/GetJobDetails/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//根据岗位获取角色
+export function jbdetpop (params) {
+    return request({
+        url: '/api/4A/GetRoleByJob/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//组织获取角色
+export function organpop (params) {
+    return request({
+        url: '/api/4A/GetRoleByOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//组织删除
+export function organele (params) {
+    return request({
+        url: '/api/4A/DeleteOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}
+
+//根据组织查询岗位列表
+export function organgitpost (params) {
+    return request({
+        url: '/api/4A/GetJobListByOrgan/v1',
+        method: 'post',
+        data: params,
+    })
+}

+ 70 - 0
src/api/systemConfiguration.js

@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+//登录策略详情查询
+export function GetTacDetails (params) {
+    return request({
+      url: '/api/4A/GetTacDetails/v1',
+      method: 'post',
+      data: params,
+      proxy: true
+    })
+  }
+//登录策略列表查询
+export function GetTacList (params) {
+  return request({
+    url: '/api/4A/GetTacList/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//登录策略新增
+export function SaveTac (params) {
+  return request({
+    url: '/api/4A/SaveTac/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//登录策略编辑
+export function EditTac (params) {
+  return request({
+    url: '/api/4A/EditTac/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//登录策略删除
+export function DeleteTac (params) {
+  return request({
+    url: '/api/4A/DeleteTac/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//获取系统基础设置
+export function GetSystemSet (params) {
+  return request({
+    url: '/api/4A/GetSystemSet/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}
+
+//保存系统基础设置
+export function SaveSystemSet (params) {
+  return request({
+    url: '/api/4A/SaveSystemSet/v1',
+    method: 'post',
+    data: params,
+    proxy: true
+  })
+}

+ 10 - 0
src/api/table.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+
+export function GetCheckCode(params) {
+  return request({
+    url: '/vue-admin-template/table/list',
+    method: 'get',
+    params
+  })
+}

+ 24 - 0
src/api/user.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+
+export function login(data) {
+  return request({
+    url: '/vue-admin-template/user/login',
+    method: 'post',
+    data: data
+  })
+}
+
+export function getInfo(token) {
+  return request({
+    url: '/vue-admin-template/user/info',
+    method: 'get',
+    params: { token }
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/vue-admin-template/user/logout',
+    method: 'post'
+  })
+}

BIN
src/assets/404_images/404.png


BIN
src/assets/404_images/404_cloud.png


BIN
src/assets/index/ic_close_card.png


BIN
src/assets/index/ic_data@2x.png


BIN
src/assets/index/ic_screen@2x.png


BIN
src/assets/index/ic_screen_edit@2x.png


BIN
src/assets/index/ic_time@2x.png


BIN
src/assets/loginpage/bg.jpg


BIN
src/assets/loginpage/d5b3da3756ddcd18e866ed91656935f.png


BIN
src/assets/loginpage/ic_ding_log@2x.png


BIN
src/assets/loginpage/ic_eye_close_password@2x.png


BIN
src/assets/loginpage/ic_eye_open_password@2x.png


BIN
src/assets/loginpage/ic_mail_log.png


BIN
src/assets/loginpage/ic_mail_log@2x.png


BIN
src/assets/loginpage/ic_password_log@2x.png


BIN
src/assets/loginpage/ic_phone_log@2x.png


BIN
src/assets/loginpage/ic_user_log@2x.png


BIN
src/assets/loginpage/ic_userid_log@2x.png


BIN
src/assets/loginpage/ic_wechat_log@2x.png


BIN
src/assets/nav/ic_home_nav_check.png


BIN
src/assets/status/ic_edit.png


BIN
src/assets/status/ic_edit_hovar.png


BIN
src/assets/status/ic_exit.png


BIN
src/assets/status/ic_exit_hovar.png


BIN
src/assets/status/ic_jobs.png


BIN
src/assets/status/ic_jobs_hovar.png


BIN
src/assets/status/ic_member.png


BIN
src/assets/status/ic_member_hovar.png


BIN
src/assets/status/ic_password.png


BIN
src/assets/status/ic_password_hovar.png


BIN
src/assets/status/ic_plus.png


BIN
src/assets/status/ic_plus_hovar.png


BIN
src/assets/status/ic_setting.png


BIN
src/assets/status/ic_setting_hovar.png


BIN
src/assets/status/ic_subordinate.png


BIN
src/assets/status/ic_subordinate_hovar.png


BIN
src/assets/status/ic_user.png


+ 41 - 0
src/checkPermission.js

@@ -0,0 +1,41 @@
+/*
+ * @Author: your name
+ * @Date: 2021-11-01 10:33:45
+ * @LastEditTime: 2021-12-28 11:34:01
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \Foshan4A\src\config\checkPermission.js
+ */
+import Vue from 'vue'
+import store from '@/store'
+
+function checkPermission (el, binding) {
+  const { value } = binding
+  const roles = store.getters && store.getters.roles
+  if (value && value instanceof Array) {
+    if (value.length > 0) {
+      const permissionRoles = value
+
+      const hasPermission = roles.some(role => {
+        return permissionRoles.includes(role)
+      })
+
+      if (!hasPermission) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    }
+  } else {
+    throw new Error(`need roles! Like v-is="['admin','editor']"`)
+  }
+}
+
+Vue.directive(
+  'is', {
+  inserted (el, binding) {
+    checkPermission(el, binding)
+  },
+  update (el, binding) {
+    checkPermission(el, binding)
+  }
+}
+)

+ 118 - 0
src/components/Breadcrumb/index.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="flex app-contair">
+    <div class="app-breadcrumb">
+      <!-- <el-breadcrumb class="app-breadcrumb" separator="/">
+        <transition-group name="breadcrumb">
+          <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+            <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+            <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+          </el-breadcrumb-item>
+        </transition-group>
+      </el-breadcrumb> -->
+    </div>
+    <div class="app-time">{{ time }}</div>
+  </div>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+import { parseTime } from '@/utils/index'
+export default {
+  data () {
+    return {
+      levelList: null,
+      time: ''
+    }
+  },
+  watch: {
+    $route () {
+      this.getBreadcrumb()
+    }
+  },
+  created () {
+    this.getBreadcrumb()
+  },
+  mounted () {
+    setInterval(() => {
+      this.time = parseTime(new Date())
+    })
+  },
+  methods: {
+    getBreadcrumb () {
+      // only show routes with meta.title
+      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
+      const first = matched[0]
+
+      if (!this.isDashboard(first)) {
+        matched = [{ path: '/dashboard', meta: { title: '首页' } }].concat(matched)
+      }
+
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+    },
+    isDashboard (route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
+    },
+    pathCompile (path) {
+      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
+      const { params } = this.$route
+      var toPath = pathToRegexp.compile(path)
+      return toPath(params)
+    },
+    handleLink (item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      this.$router.push(this.pathCompile(path))
+    },
+    historyRoute (i) {
+      const path = this.levelList[i - 1].path
+      this.levelList.splice(i, 1)
+      this.$router.push(path)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-contair {
+  position: absolute;
+  right: 57px;
+  top: 65px;
+  line-height: 48px;
+  .app-time {
+    font-size: 18px;
+    font-family: DIN;
+    font-weight: bold;
+    color: #303133;
+  }
+  .route-breadcrumb {
+    height: 32px;
+    background: #f0f2fe;
+    border: 1px solid #767eba;
+    border-radius: 4px;
+    display: inline-block;
+    line-height: 32px;
+    margin-right: 16px;
+    padding: 0 13px;
+    font-size: 16px;
+    font-family: Microsoft YaHei;
+    font-weight: 400;
+    color: #767eba;
+    cursor: pointer;
+    transition: all 0.3s;
+    i {
+      color: #303133;
+      margin-left: 5px;
+    }
+    &:last-child {
+      margin-right: 0;
+    }
+  }
+}
+</style>

+ 157 - 0
src/components/Hamburger/index.vue

@@ -0,0 +1,157 @@
+<template>
+  <div class="head-box">
+    <div class="flex head-box-content">
+      <div class="head-box-title">
+        <span class="avt"></span>
+        <span class="title">佛山交科4A统一身份安全管理平台</span>
+      </div>
+      <div class="head-box-menu flex-wrap">
+        <div class="user">
+          <img class="head-icon-img" src="../../assets/status/ic_user.png" alt="">
+          <span class="name">{{ name }}</span>
+        </div>
+        <!-- <div class="seting">
+          <span @click="toSystem" class="img-icon"></span>
+        </div> -->
+        <div class="lock">
+          <span @click="dialogPwd" class="img-icon"></span>
+        </div>
+        <div class="exit">
+          <span @click="exitDialog" class="img-icon"></span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { loginUp } from '@/api/login'
+export default {
+  name: 'Hamburger',
+  computed: {
+    name () {
+      return this.$store.state.user.name
+    }
+  },
+  watch: {
+    '$store.state.app.outcheck': {
+      handler (val) {
+        if (val) {
+          this.logout()
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    //退出系统-弹框
+    exitDialog () {
+      this.$store.dispatch('app/toggleOutflag', true)
+    },
+    // 退出系统
+    async logout () {
+      let params = {
+        UserId: this.$store.state.user.UserId,
+        UserType: this.$store.state.user.UserType
+      }
+      // let loginUper = await loginUp(params)
+      // if (loginUper) {}
+      // await this.$store.dispatch('user/logout')
+      // this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+      // if (loginUper.code == 0) {
+      await this.$store.dispatch('user/logout')
+      this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+      // }
+    },
+    //修改密码
+    dialogPwd () {
+      this.$store.dispatch('app/togglePwdflag', true)
+    },
+    //跳转
+    toSystem () {
+      this.$router.push(`/systemManagement`)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.head-box {
+  .head-box-title {
+    font-size: 20px;
+    font-family: Microsoft YaHei;
+    font-weight: bold;
+    color: #303133;
+    .avt {
+      display: inline-block;
+      width: 32px;
+      height: 32px;
+      background: #303133;
+      border-radius: 50%;
+      vertical-align: middle;
+      margin-right: 16px;
+      position: relative;
+      top: -3px;
+      img {
+        max-width: 100%;
+      }
+    }
+  }
+  .head-box-menu {
+    > div {
+      margin-right: 20px;
+      &:last-child {
+        margin-right: 0;
+      }
+    }
+    .head-icon-img {
+      position: relative;
+      top: 6px;
+    }
+    .img-icon {
+      display: inline-block;
+      width: 24px;
+      height: 24px;
+      vertical-align: middle;
+      background-repeat: no-repeat;
+      background-size: cover;
+      cursor: pointer;
+      transition: all 0.3s;
+    }
+    .user {
+      font-size: 16px;
+      font-family: Microsoft YaHei;
+      font-weight: bold;
+      color: #303133;
+      .name {
+        margin-left: 10px;
+      }
+    }
+    .seting {
+      .img-icon {
+        background-image: url("../../assets/status/ic_setting.png");
+        &:hover {
+          background-image: url("../../assets/status/ic_setting_hovar.png");
+        }
+      }
+    }
+    .lock {
+      .img-icon {
+        background-image: url("../../assets/status/ic_password.png");
+        &:hover {
+          background-image: url("../../assets/status/ic_password_hovar.png");
+        }
+      }
+    }
+    .exit {
+      .img-icon {
+        background-image: url("../../assets/status/ic_exit.png");
+        &:hover {
+          background-image: url("../../assets/status/ic_exit_hovar.png");
+        }
+      }
+    }
+  }
+}
+</style>
+

+ 62 - 0
src/components/SvgIcon/index.vue

@@ -0,0 +1,62 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
+import { isExternal } from '@/utils/validate'
+
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.iconClass)
+    },
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    },
+    styleExternalIcon() {
+      return {
+        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>

+ 384 - 0
src/components/bfbutton/index.vue

@@ -0,0 +1,384 @@
+<template>
+    <div class="bf-button">
+        <!-- 1 2是公用头部按钮 3是左边长按钮 4 10导入新增 8 9调用规则管理-->
+        <el-row>
+            <el-button  :class="{'but':type == 1 , 'buter': type == 2 , 'butewid': type == 3 , 'butdao': type == 4 , 'butdaoadd': type == 10 ,'butedit': type == 5 , 'butels': type == 6 , 'buteles': type == 7 , 'butcan': type == 8 , 'butsub': type == 9, 'butout': type == 11 , 'butmod': type == 12,  'butb': type == 13,  'butc': type == 14,'butd': type == 15, 'bute': type == 16, 'butmods': type == 17, 'butsuber': type == 18}">{{butName}}</el-button>
+        </el-row>
+    </div>
+</template>
+<script>
+export default {
+    props: ['butName', 'type'],
+    data () {
+        return {}
+    },
+    mounted () {
+        console.log(this.type)
+    }
+}
+</script>
+<style lang="scss">
+.bf-button{
+    // height: 48px;
+    border-radius: 16px;
+    >.el-row{
+        width: 100%;
+        height: 100%;
+        >.but{
+            width: 100%;
+            height: 100%;
+            padding: 0 32px 0 32px;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+            border: none;
+            background: linear-gradient(0deg, #777DBA, #6983BE);
+            // box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.18);
+        }
+        .but:hover{
+            background: #87A6D3
+        }
+        .but:focus{         
+            background: #2D4F80;
+        }
+        >.buter{
+            width: 100%;
+            height: 100%;
+            padding: 1px 32px 1px 32px;
+            background:  #F5F7FA;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #5077AE;
+            border: 1px solid #90A8C9;
+            box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+        }
+        .buter:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .buter:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        >.butewid{
+            width: 100%;
+            height: 100%;
+            padding: 0 92px 0 92px;
+            background: linear-gradient(0deg, #777DBA, #6983BE);
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+            box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+        }
+        .butewid:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butewid:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butdao{
+            width: 100%;
+            height: 100%;
+            padding: 0 47px 0 47px;
+            background: #FFFFFF;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #5077AE;
+            border: 1px solid #E4E8F0;
+            border-radius: 6px;
+        }
+        .butdao:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butdao:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butdaoadd{
+            width: 100%;
+            height: 100%;
+            padding: 0 47px 0 47px;
+            background: linear-gradient(0deg, #777DBA, #6983BE);
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+            border-radius: 6px;
+        }
+        .butdaoadd:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butdaoadd:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butedit{
+            width: 100%;
+            height: 100%;
+            padding: 0 16px 0 16px;
+            background: #5077AE;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butedit:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butedit:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butels{
+            width: 100%;
+            height: 100%;
+            padding: 0 15px 0 15px;
+            background: #F56C6C;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butels:hover{
+            background: #F88585;
+            color: #FFFFFF;
+        }
+        .butels:focus{         
+            background: #DD4343;
+            color: #FFFFFF;
+        }
+        .buteles{
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 0 24px 0 24px;
+            background: #F56C6C;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+            border: none;
+        }
+        .buteles:hover{
+            background: #F88585;
+            color: #FFFFFF;
+        }
+        .buteles:focus{         
+            background: #DD4343;
+            color: #FFFFFF;
+            border: none;
+        }
+        .butcan{
+            width: 100%;
+            height: 100%;
+            padding: 0 24px 0 24px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: #FFFFFF;
+            border: 1px solid #E4E8F0;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #5077AE;
+        }
+        .butcan:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butcan:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butsub{
+            width: 100%;
+            height: 100%;
+            padding: 0 24px 0 24px;
+            background: linear-gradient(0deg, #777DBA, #6983BE);
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butsub:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butsub:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butsuber{
+            width: 100%;
+            height: 100%;
+            padding: 0 15px 0 15px;
+            background: linear-gradient(0deg, #777DBA, #6983BE);
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butsuber:hover{
+            background: #87A6D3;
+            color: #FFFFFF;
+        }
+        .butsuber:focus{         
+            background: #2D4F80;
+            color: #FFFFFF;
+        }
+        .butout{
+            width: 100%;
+            height: 100%;
+            padding: 0 20px 0 20px;
+            // background: #F56C6C;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #F56C6C;
+            border: 1px solid #F56C6C
+        }
+        .butout:hover{
+            background: #F88585;
+            color: #FFFFFF;
+        }
+        .butout:focus{         
+            background: #DD4343;
+            color: #FFFFFF;
+        }
+        .butmod{
+            width: 100%;
+            height: 100%;
+            padding: 0 20px 0 20px;
+            // background: #F56C6C;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #303133;
+            border: 1px solid #E3E5E8;
+        }
+        .butmod:hover{
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butmod:focus{         
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butb{
+            width: 100%;
+            height: 100%;
+            padding: 0 24px 0 24px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: #FFFFFF;
+            border: 1px solid #E4E8F0;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #5077AE;
+        }
+        .butb:hover{
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butb:focus{         
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butc{
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 0 24px 0 24px;
+            background: #F56C6C;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butc:hover{
+            background: #F88585;
+            color: #FFFFFF;
+        }
+        .butc:focus{         
+            background: #DD4343;
+            color: #FFFFFF;
+        }
+        .butd{
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 0 8px 0 8px;
+            background: #6E81BC;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .butd:hover{
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butd:focus{         
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .bute{
+            width: 100%;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            padding: 0 74px 0 74px;
+            background: #6E81BC;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #FFFFFF;
+        }
+        .bute:hover{
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .bute:focus{         
+            background: #6f80bc;
+            color: #FFFFFF;
+            // border: none;
+        }
+        .butmods{
+            width: 100%;
+            height: 100%;
+            padding: 0 20px 0 20px;
+            // background: #F56C6C;
+            font-size: 16px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #303133;
+            border: 1px solid #E3E5E8;
+        }
+    }
+}
+</style>

+ 250 - 0
src/components/competencypop/index.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="bf-competencypop">
+    <el-dialog title="" :visible.sync="dialogVisiblestart" :modal-append-to-body="false" :lock-scroll="false" :before-close="handleClose" :width="isWidth">
+      <div class="competencypop_header">
+        <div class="left">
+          <p>权限规则</p>
+        </div>
+        <div class="right">
+          <el-radio v-model="form.Action" disabled :label="item.id" v-for='(item,index) in option' :key="index">{{item.label}}</el-radio>
+        </div>
+      </div>
+      <div class="juris_list">
+        <p>时效范围起</p>
+        <el-date-picker v-model="form.ValidBegin" disabled type="datetime" :picker-options="pickerOptionsStart" placeholder="选择时间">
+        </el-date-picker>
+      </div>
+      <div class="juris_list">
+        <p>至</p>
+        <el-date-picker v-model="form.ValidEnd" disabled @change="setTime" :picker-options="pickerOptionsEnd" type="datetime" placeholder="选择时间">
+        </el-date-picker>
+      </div>
+      <div class="juris_list">
+        <p>许可查询行</p>
+        <el-input v-model="form.QueryRow" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="juris_list">
+        <p>许可查询列</p>
+        <el-input v-model="form.QueryCol" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="juris_list">
+        <p>许可删除行</p>
+        <el-input v-model="form.DeleteRow" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="juris_list">
+        <p>许可新增列</p>
+        <el-input v-model="form.NewCol" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="juris_list">
+        <p>许可编辑行</p>
+        <el-input v-model="form.EditRow" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="juris_list" style="margin-bottom:0">
+        <p>许可编辑列</p>
+        <el-input v-model="form.EditCol" placeholder="请输入内容" disabled></el-input>
+      </div>
+      <div class="footer">
+        <Bfbutton :butName='butName1' class="but" @click.native="handleClose" :type='16' />
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import Bfbutton from '../../components/bfbutton/index.vue'
+export default {
+  props: {
+    dialogVisiblestart: {
+      type: Boolean,
+      default: false
+    },
+    form: {
+      type: Object,
+      default: () => { }
+    }
+  },
+  data () {
+    return {
+      pickerOptionsStart: {
+        disabledDate: time => {
+          if (this.form.endWeeks) {
+            return time.getTime() >= new Date(this.form.endWeeks).getTime()
+          }
+        }
+      },
+      pickerOptionsEnd: {
+        disabledDate: time => {
+          if (this.form.firstWeeks) {
+            return time.getTime() <= new Date(this.form.firstWeeks).getTime() - 86400000
+          }
+        }
+      },
+      //   form: {
+      //     endWeeks: '',
+      //     firstWeeks: '',
+      //     value1: '',
+      //     value2: '',
+      //     input1: '',
+      //     input2: '',
+      //     input3: '',
+      //     input4: '',
+      //     input5: '',
+      //     input6: '',
+      //   },
+      butName1: '确定',
+      isWidth: '29.1%',
+      radio: 1,
+      option: [{
+        label: '显示权限',
+        id: 1
+      },
+      {
+        label: '显示及编辑权限',
+        id: 2
+      }],
+      value1: '',
+      value2: ''
+    }
+  },
+  components: {
+    Bfbutton
+  },
+  methods: {
+    handleClose () {
+      this.$emit('handleClose', this.form)
+    },
+    setTime (val) {
+      if (this.form.endWeeks < this.form.firstWeeks) {
+        this.endWeeks = ''
+      }
+    }
+  }
+}
+</script>
+<style lang="scss">
+.bf-competencypop {
+  .el-dialog {
+    border-radius: 20px;
+    display: flex;
+    display: -ms-flex; /* 兼容IE */
+    flex-direction: column;
+    -ms-flex-direction: column; /* 兼容IE */
+    margin: 0 !important;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    max-height: calc(100% - 30px);
+    max-width: calc(100% - 30px);
+  }
+  .el-picker-panel {
+    > .el-picker-panel__footer {
+      > .el-button--text {
+        display: none;
+      }
+    }
+  }
+  .el-dialog__header {
+    display: none;
+  }
+  .el-dialog__body {
+    padding: 0;
+    background: #ffffff;
+    box-shadow: 0px 6px 10px 0px rgba(0, 0, 0, 0.3);
+    border-radius: 20px;
+    padding: 0 48px 0 48px;
+    > .competencypop_header {
+      width: 100%;
+      height: 120px;
+      display: flex;
+      > .left {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        > p {
+          font-size: 24px;
+          font-family: Microsoft YaHei;
+          font-weight: bold;
+          color: #303133;
+        }
+      }
+      > .right {
+        width: 50%;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        > .but {
+          width: 180px;
+          height: 32px;
+        }
+      }
+    }
+    > .juris_list {
+      width: 100%;
+      display: flex;
+      align-items: center;
+      margin-bottom: 24px;
+      > p {
+        width: 75px;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        margin-bottom: 0;
+        margin-top: 0;
+        margin-right: 16px;
+        font-size: 14px;
+        font-family: Microsoft YaHei;
+        font-weight: 400;
+        color: #303133;
+      }
+      .el-input__inner {
+        width: 375px;
+        height: 32px;
+        background: #f9fbff;
+        border-radius: 6px;
+      }
+      .el-input__icon {
+        display: flex;
+        align-items: center;
+      }
+      .el-input {
+        width: 375px;
+        height: 32px;
+        background: #f9fbff;
+        border-radius: 6px;
+        > .el-input__inner {
+          width: 100%;
+          height: 100%;
+          background: #f9fbff;
+          border-radius: 6px;
+        }
+      }
+      > .el-textarea {
+        width: 524px;
+        height: 64px;
+        border-radius: 4px;
+        .el-textarea__inner {
+          width: 100%;
+          height: 100%;
+          background: #f9fbff;
+          border: 1px solid #d7dae3;
+          border-radius: 4px;
+          resize: none;
+        }
+      }
+    }
+    > .footer {
+      width: 100%;
+      height: 112px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      > .but {
+        height: 36px;
+        margin-right: 24px;
+      }
+    }
+  }
+}
+</style>

+ 149 - 0
src/components/loginpolicy/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="bf-loginpolicys">
+    <!-- 登录策略 -->
+    <div class="cont">
+      <div class="paren_header">
+        <p>登录策略</p>
+      </div>
+      <div class="paren_cont">
+        <template v-if="dataList.length">
+          <el-scrollbar style="height: 100%">
+            <el-row :gutter="24">
+              <el-col :span="8" v-for="(item, index) in dataList" :key="index">
+                <div class="cide">
+                  <div class="cide_header">
+                    <el-tooltip effect="dark" :content="item.TacName" placement="bottom">
+                      <span v-if="item.TacName.length>11">{{ item.TacName }}</span>
+                    </el-tooltip>
+                    <span v-if="item.TacName.length<12">{{ item.TacName }}</span>
+                  </div>
+                  <div class="cide_foot">
+                    <span @click="upStart(item.TacId)">查看</span>
+                    <el-checkbox v-model="item.checked" @change="checkedChange(item)" :disabled="isEdit"></el-checkbox>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+          </el-scrollbar>
+        </template>
+        <template v-else>
+          <el-empty :image-size="imageSize" description="暂无数据"></el-empty>
+        </template>
+      </div>
+    </div>
+    <Loginpolicypop :dialogVisiblestart="dialogVisiblestart" :itemData="itemData" @handleClose="handleClose" />
+  </div>
+</template>
+<script>
+import { GetTacList, GetTacDetails } from "@/api/systemConfiguration";
+import Loginpolicypop from "@/components/loginpolicypop/index.vue";
+// props: checkedList  已选中列表数组  isEdit 是否可以编辑  true 为是  false 为否
+//emit: getCheckedList  获取已选中的列表
+export default {
+  data () {
+    return {
+      dialogVisiblestart: false,
+      dataList: [],
+      listArray: [],
+      itemData: [],
+    };
+  },
+  props: {
+    //选中列表
+    checkedList: {
+      type: Array,
+      default: () => [],
+    },
+    isEdit: {
+      type: Boolean,
+      required: false,
+    },
+    imageSize: {
+      type: Number,
+      default: 160
+    }
+  },
+  watch: {
+    checkedList: {
+      handler (nv, ov) {
+        // 特别注意,不能用箭头函数,箭头函数,this指向全局
+        let arr = []
+        nv.forEach((item1) => {
+          this.dataList.forEach((item2) => {
+            if (item1.TacId == item2.TacId && item1.IsSelected == 1) {
+              item2.checked = true;
+              arr.push(item1)
+            }
+          });
+        });
+        this.listArray = JSON.parse(JSON.stringify(arr));
+      },
+      deep: true, // 可以深度检测到 obj 对象的属性值的变化
+    },
+  },
+  created: function () {
+    this.getTacList();
+  },
+  components: {
+    Loginpolicypop,
+  },
+  methods: {
+    //打开弹窗
+    upStart (id) {
+      return new Promise((resolve, reject) => {
+        GetTacDetails({ TacId: id })
+          .then((response) => {
+            if (response.code === 0) {
+              const { returnData } = response;
+              this.itemData = returnData;
+              this.dialogVisiblestart = true;
+            }
+            resolve();
+          })
+          .catch((error) => {
+            reject(error);
+          });
+      });
+    },
+    //关闭弹窗
+    handleClose () {
+      this.dialogVisiblestart = false;
+    },
+    getTacList () {
+      return new Promise((resolve, reject) => {
+        GetTacList({ QueryName: "" })
+          .then((response) => {
+            if (response.code === 0) {
+              const { returnData } = response;
+              returnData.forEach((element) => {
+                element["checked"] = false;
+              });
+              this.dataList = returnData;
+            }
+            resolve();
+          })
+          .catch((error) => {
+            reject(error);
+          });
+      });
+    },
+    checkedChange (data) {
+      if (data.checked == true) {
+        // this.listArray = [];
+        this.listArray.push(data);
+        this.$emit("getCheckedList", this.listArray);
+      } else {
+        this.listArray.splice(
+          this.listArray.findIndex((item) => item.TacId === data.TacId),
+          1
+        );
+        this.$emit("getCheckedList", this.listArray);
+      }
+    },
+  },
+  mounted: function () { },
+};
+</script>
+<style lang="scss">
+@import "./loginpolicy.scss";
+</style>

+ 68 - 0
src/components/loginpolicy/loginpolicy.scss

@@ -0,0 +1,68 @@
+.bf-loginpolicys {
+  width: 100%;
+  height: 100%;
+  > .cont {
+    width: 100%;
+    background: #ffffff;
+    padding: 0 32px 0 32px;
+    height: 100%;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      padding: 32px 0;
+      display: flex;
+      align-items: center;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+    }
+    > .paren_cont {
+      width: 100%;
+      height: calc(100% - 110px);
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          overflow-x: hidden;
+          > .el-scrollbar__view {
+            .el-row {
+              width: 100%;
+            }
+            .cide {
+              height: 80px;
+              background: #f5f7fa;
+              box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
+              border-radius: 8px;
+              padding: 10px;
+              margin-bottom: 16px;
+              > .cide_header {
+                width: 100%;
+                height: 38px;
+                display: flex;
+                display: -webkit-box;
+                overflow: hidden;
+                -webkit-box-orient: vertical;
+                -webkit-line-clamp: 2;
+              }
+              > .cide_foot {
+                width: 100%;
+                display: flex;
+                flex-direction: row;
+                justify-content: space-between;
+                > span {
+                  cursor: pointer;
+                  color: #6e81bc;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 102 - 0
src/components/loginpolicypop/index.vue

@@ -0,0 +1,102 @@
+<template>
+    <div class="bf-loginpolicypop">
+        <el-dialog
+        title=""
+        :visible.sync="dialogVisiblestart"
+        :modal-append-to-body="false"
+        :before-close="handleClose"
+        :width="isWidth">
+            <div class="loginpolicypop_header">
+                <div class="left">
+                    <p>登录策略信息</p>
+                </div>
+            </div>
+            <div class="loginpolicypop_cont">
+                <div class="juris_list">
+                    <p>时效范围起</p>
+                    <el-date-picker
+                    v-model="itemData.DateBegin"
+                    type="date"
+                    disabled
+                    placeholder="">
+                    </el-date-picker>
+                </div>
+                <div class="juris_list">
+                    <p>至</p>
+                    <el-date-picker
+                    v-model="itemData.DateEnd"
+                    type="date"
+                    disabled
+                    placeholder="">
+                    </el-date-picker>
+                </div>
+                <div class="juris_list">
+                    <p>登录时间起</p>
+                    <el-input
+                        disabled
+                        placeholder=""
+                        v-model="itemData.TimeBegin">
+                    </el-input>
+                </div>
+                <div class="juris_list">
+                    <p>至</p>
+                    <el-input
+                        disabled
+                        placeholder=""
+                        v-model="itemData.TimeEnd">
+                    </el-input>
+                </div>
+                <div class="juris_lists">
+                    <p>IP段</p>
+                    <el-input
+                        type="textarea"
+                        disabled
+                        placeholder=""
+                        v-model="itemData.IpList">
+                    </el-input>
+                </div>
+                <div class="juris_lists">
+                    <p>描述</p>
+                    <el-input
+                        type="textarea"
+                        disabled
+                        placeholder=""
+                        v-model="itemData.TacDesc">
+                    </el-input>
+                </div>
+            </div>
+            <div class="footer">
+                <Bfbutton :butName='butName1' class="but" @click.native="handleClose" :type = '16'/>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+<script>
+import Bfbutton from '../../components/bfbutton/index.vue'
+import './loginpolicypop.scss'
+export default {
+    props: ['dialogVisiblestart',"itemData"],
+    data () {
+        return {
+            isWidth: '27.4%',
+            butName1: '确定',
+            value1: '',
+            value2: '',
+            value3: '',
+            value4: '',
+            textarea2: '',
+            textarea3: ''
+        }
+    },
+    components: {
+        Bfbutton
+    },
+    methods: {
+        handleClose () {
+            this.$emit('handleClose')
+        }
+    }
+}
+</script>
+<style lang="scss">
+</style>

+ 154 - 0
src/components/loginpolicypop/loginpolicypop.scss

@@ -0,0 +1,154 @@
+.bf-loginpolicypop{
+    .el-dialog{
+        border-radius: 20px;
+        display: flex;
+        display: -ms-flex; /* 兼容IE */
+        flex-direction: column;
+        -ms-flex-direction: column; /* 兼容IE */
+        margin:0 !important;
+        position:absolute;
+        top:50%;
+        left:50%;
+        transform:translate(-50%,-50%);
+        max-height:calc(100% - 30px);
+        max-width:calc(100% - 30px);
+    }
+    .el-dialog__header{
+        display: none;
+    }
+    .el-dialog__body{
+        padding: 0;
+        background: #ffffff;
+        box-shadow: 0px 6px 10px 0px rgba(0, 0, 0, 0.3);
+        border-radius: 20px;
+        padding: 0 48px 0 48px;
+        >.loginpolicypop_header{
+            width: 100%;
+            height: 120px;
+            display: flex;
+            >.left{
+                width: 100%;
+                height: 100%;
+                display: flex;
+                align-items: center;
+                >p{
+                    font-size: 24px;
+                    font-family: Microsoft YaHei;
+                    font-weight: bold;
+                    color: #303133;
+                }
+            }
+            >.right{
+                width: 50%;
+                height: 100%;
+                display: flex;
+                align-items: center;
+                justify-content: flex-end;
+                >.but{
+                    width: 180px;
+                    height: 32px;
+                }
+            }
+        }
+        >.loginpolicypop_cont{
+            >.juris_list{
+                width: 100%;
+                display: flex;
+                align-items: center;
+                margin-bottom: 24px;
+                >p{
+                    width: 70px;
+                    display: flex;
+                    align-items: center;
+                    justify-content: flex-end;
+                    margin-bottom: 0;
+                    margin-top: 0;
+                    margin-right: 16px;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    color: #303133;
+                }
+                .el-input__inner{
+                    width: 343px;
+                    height: 32px;
+                    background: #F9FBFF;
+                    border-radius: 6px;
+                }
+                .el-input__icon{
+                    display: flex;
+                    align-items: center;
+                }
+                .el-input{
+                    width: 343px;
+                    height: 32px;
+                    background: #F9FBFF;
+                    border-radius: 6px;
+                    >.el-input__inner{
+                        width: 100%;
+                        height: 100%;
+                        background: #F9FBFF;
+                        border-radius: 6px;
+                    }
+                }
+                >.el-textarea{
+                    width: 524px;
+                    height: 64px;
+                    border-radius: 4px;
+                    .el-textarea__inner{
+                        width: 100%;
+                        height: 100%;
+                        background: #F9FBFF;
+                        border: 1px solid #D7DAE3;
+                        border-radius: 4px;
+                        resize: none;
+                    }
+                }
+            }
+            >.juris_lists{
+                width: 100%;
+                display: flex;
+                align-items: flex-start;
+                margin-bottom: 24px;
+                >p{
+                    width: 70px;
+                    display: flex;
+                    align-items: center;
+                    justify-content: flex-end;
+                    margin-bottom: 0;
+                    margin-top: 0;
+                    margin-right: 16px;
+                    font-size: 14px;
+                    font-family: Microsoft YaHei;
+                    font-weight: 400;
+                    color: #303133;
+                    margin-top: 10px;
+                }
+                >.el-textarea{
+                    width: 348px;
+                    height: 64px;
+                    border-radius: 4px;
+                    .el-textarea__inner{
+                        width: 100%;
+                        height: 100%;
+                        background: #F9FBFF;
+                        border: 1px solid #D7DAE3;
+                        border-radius: 4px;
+                        resize: none;
+                    }
+                }
+            }
+        }
+        >.footer{
+            width: 100%;
+            height: 96px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            >.but{
+                height: 36px;
+                margin-right: 24px;
+            }
+        }
+    }
+}

+ 180 - 0
src/components/organization/index.vue

@@ -0,0 +1,180 @@
+<template>
+  <div class="bf-organization">
+    <!-- 上级组织 -->
+    <div class="left">
+      <div class="paren_header">
+        <p>{{ title }}</p>
+        <div class="column" v-show="vice">
+          <div :class="active == index ? 'column_childs' : 'column_child'" v-for="(item, index) in colType" :key="index" @click="upStart(index)">
+            {{ item.name }}
+          </div>
+        </div>
+      </div>
+      <div class="paren_content">
+        <div class="dptBox" v-show="active == 0">
+          <el-scrollbar style="height: 100%">
+            <el-tree :data="data" :check-strictly="true" show-checkbox @node-click="nodeClick" @check-change="currentChange" :props="defaultProps" default-expand-all :default-checked-keys="checkedKeys" :expand-on-click-node="false" :node-key="nodekey" ref="tree" highlight-current>
+            </el-tree>
+          </el-scrollbar>
+        </div>
+        <div class="dptBox" v-show="active == 1">
+          <Rolelist :type="true" @radioChange="radioChange" :radioCheck="radioCheck" :number="8" :active="true" class="lessData" :dataList="mainData" />
+        </div>
+        <div class="dptBox" v-show="active == 2">
+          <Rolelist :number="8" @checkClick="checkClick" @checkChange="checkChange" :checkBoxList="checkBoxList" :active="true" class="lessData" :dataList="lessData" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import Rolelist from '@/components/rolelist'
+export default {
+  props: {
+    title: {
+      type: String,
+      default: "",
+    },
+    vice: {
+      type: Boolean,
+      default: false,
+    },
+    data: {
+      type: Array,
+      default: () => [],
+    },
+    nodekey: {
+      type: String,
+      default: "",
+    },
+    defaultProps: {
+      type: Object,
+      default: () => { },
+    },
+    checkedKeys: {
+      //已选中
+      type: Array,
+      default: () => [],
+    },
+    lessData: {
+      //副岗
+      type: Array,
+      default: () => [],
+    },
+    mainData: {
+      //主岗
+      type: Array,
+      default: () => [],
+    },
+    radioCheck: {
+      type: Number,
+      default: 0,
+    },
+    checkBoxList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  components: { Rolelist },
+  data () {
+    return {
+      active: 0,
+      colType: [
+        {
+          name: "组织",
+        },
+        {
+          name: "主岗",
+        },
+        {
+          name: "副岗",
+        },
+      ],
+      checkedDatas: [],
+      checkedId: null,
+      checkedList: [], //选中的列表,
+      nodekeys: "nodekey",
+    };
+  },
+  watch: {
+    checkedKeys: {
+      handler (val) {
+        this.checkedList = val;
+        this.$refs.tree.setCheckedKeys(val)
+      },
+      deep: true,
+    },
+  },
+  mounted () {
+    this.data = this.formatData(this.data)
+  },
+  methods: {
+    //点击选择
+    upStart (index) {
+      this.active = index;
+      this.$emit("getTreeindex", index)
+    },
+    formatData (params) {
+      let data = params;
+      data.map((item) => {
+        if (item.hasOwnProperty('children')) {
+          item.disabled = true;
+          this.formatData(item.children)
+        }
+      });
+      return data;
+    },
+    currentChange (data, isChecked) {
+      const { OrganId } = data
+      this.$emit("getTreeData", this.$refs.tree.getCheckedNodes())
+      if (isChecked) {
+        const checked = [OrganId]
+        this.$refs.tree.setCheckedKeys(checked)
+      }
+    },
+    // 选中后设置初始数据
+    setDataObj (arr) {
+      arr.forEach((item) => {
+        if (!item.children) {
+          item.children = {
+            OrganId: item.OrganId,
+            ValidBegin: "",
+            ValidEnd: "",
+            Action: "",
+            QueryRow: "",
+            QueryCol: "",
+            NewCol: "",
+            EditRow: "",
+            EditCol: "",
+            DeleteRow: "",
+          };
+        }
+      });
+      this.$emit("getTreeData", arr)
+    },
+    nodeClick (data) {
+      this.$emit("getTreeDatas", data)
+      this.checkedId = data.nodekey
+    },
+    radioChange (val) {
+      this.$emit('radioChange', val)
+    },
+    //多选框
+    checkChange (arr) {
+      this.$emit("checkChange", arr)
+    },
+    checkClick (item) {
+      this.$emit("checkClick", item)
+    }
+  },
+};
+</script>
+<style lang="scss">
+@import "./organization.scss";
+.DBox {
+  cursor: not-allowed;
+}
+.dptBox {
+  height: 100%;
+}
+</style>

+ 103 - 0
src/components/organization/organization.scss

@@ -0,0 +1,103 @@
+.bf-organization {
+  width: 100%;
+  height: 100%;
+  .left {
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      height: 90px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+      > .column {
+        height: 36px;
+        background: #f5f7fa;
+        border-radius: 4px;
+        display: flex;
+        align-items: center;
+        padding: 0 4px 0 4px;
+        > .column_child {
+          height: 30px;
+          padding: 0 16px 0 16px;
+          font-size: 16px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          color: #606266;
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+        }
+        > .column_childs {
+          height: 30px;
+          padding: 0 16px 0 16px;
+          font-size: 16px;
+          font-family: Microsoft YaHei;
+          font-weight: 400;
+          color: #606266;
+          display: flex;
+          align-items: center;
+          background: #ffffff;
+          box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.06);
+          border-radius: 4px;
+          cursor: pointer;
+        }
+      }
+    }
+    > .paren_content {
+      width: 100%;
+      height: 83%;
+      .dptBox{
+        > .el-scrollbar {
+          > .el-scrollbar__wrap {
+            overflow-x: hidden;
+            > .el-scrollbar__view {
+              padding-top: 10px;
+            }
+          }
+        }
+      }
+      .el-tree {
+        .el-checkbox__inner {
+          border-radius: 50%;
+        }
+      }
+      .el-checkbox__inner::after {
+        width: 5px;
+        height: 5px;
+        background: #ffffff;
+        border-radius: 50%;
+        top: 3px;
+        left: 3px;
+      }
+      .el-tree-node__children {
+        display: flex;
+        flex-direction: column;
+      }
+      .lessData {
+        .el-checkbox__inner::after {
+          left: 4px;
+          top: 1px;
+          width: 3px;
+          height: 7px;
+          background: inherit;
+          border-radius: 0;
+        }
+      }
+
+      }
+
+  }
+}

+ 175 - 0
src/components/permissionlist/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="bf-permissionlist">
+    <!-- 权限列表 -->
+    <div class="right">
+      <div class="paren_header">
+        <p>{{title}}</p>
+      </div>
+      <div class="paren_type">
+        <ul>
+          <li>
+            <div class="log"></div>
+            <p>时效规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>数据规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示及编辑权限</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示权限</p>
+          </li>
+        </ul>
+      </div>
+      <div class="paren_list">
+        <ul>
+          <li v-for="(item,index) in dataLists" :key="index">
+            <div class="up_type" :class="active === index ? 'up_types' : 'up_type'" @click="upActive(item,index)">{{item.AppName}}</div>
+          </li>
+        </ul>
+      </div>
+      <template v-if="RoleData.length">
+        <div :class="active ? 'bgActive':''" class="paren_content">
+          <el-scrollbar style="height:100%">
+            <el-row :gutter="16">
+              <el-col :span="8" v-for="(item,index) in RoleData" :key="index">
+                <div :title="item.AuthName" class="cide">
+                  <div class="cide_header">
+                    <p>{{item.AuthName}}</p>
+                    <span @click.stop="upStart(item)">查看</span>
+                  </div>
+                  <div class="cide_cont">
+                    <ul>
+                      <li v-if="item.ValidBegin" class="statusDate"></li>
+                      <li v-if="item.DeleteRow || item.EditCol || item.EditRow || item.NewCol || item.QueryCol || item.QueryRow" class="statusShow"></li>
+                      <li v-if="item.Action" :class="'statusRule'+ item.Action"></li>
+                    </ul>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+          </el-scrollbar>
+        </div>
+      </template>
+      <template v-else>
+        <el-empty :image-size="imageSize" description="暂无数据"></el-empty>
+      </template>
+      <Competencypop :dialogVisiblestart='dialogVisiblestart' :form="form" @handleClose='handleClose' />
+    </div>
+  </div>
+</template>
+<script>
+import './permissionlist.scss'
+import Competencypop from '../competencypop/index.vue'
+export default {
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    check: {
+      type: Boolean,
+      default: false
+    },
+    RoleList: {
+      type: Array,
+      default: () => []
+    },
+    imageSize: {
+      type: Number,
+      default: 160
+    }
+  },
+  data () {
+    return {
+      dialogVisiblestart: false,
+      active: 0,
+      msg: 0,
+      RoleData: [],
+      dataLists: [],
+      jurisdiction: [{
+        name: '权限名称'
+      },
+      {
+        name: '权限名称'
+      },
+      {
+        name: '权限名称'
+      },
+      {
+        name: '权限名称'
+      }],
+      DataList: [],
+      form: {}
+    }
+  },
+  components: {
+    Competencypop
+  },
+  mounted () {
+    this.Roleup()
+  },
+  watch: {
+    RoleList: {
+      handler (arr) {
+        this.RoleData = []
+        this.dataLists = []
+        if (arr && arr.length) {
+          this.Roleup(arr)
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    Roleup (arr) {
+      const datas = _.cloneDeep(arr)
+      const arrs = _.unionBy(datas, 'AppName')
+      const newDatas = arrs.filter(item => item.AppName)
+      if (newDatas && newDatas.length) {
+        this.dataLists = newDatas
+        const goodDatas = this.getData(newDatas[0].AppName)
+        this.RoleData = goodDatas
+      } else {
+        this.RoleData = []
+        this.dataLists = []
+      }
+    },
+    upActive (item, index) {
+      this.active = index
+      this.RoleData = this.getData(item.AppName)
+    },
+    getData (name) {
+      const datas = []
+      this.RoleList.forEach(item => {
+        if (item.AppName === name) {
+          datas.push(item)
+        }
+      })
+      return datas
+    },
+    //打开编辑
+    upStart (item) {
+      this.form = item
+      // if (item.Action == 2) {
+      //   this.dialogVisiblestart = true
+      // }
+      this.dialogVisiblestart = true
+    },
+    //关闭编辑
+    handleClose (data) {
+      let arr = {
+        AuthId: ''
+      }
+      this.dialogVisiblestart = false
+      this.$emit('Competen', data)
+    },
+  }
+}
+</script>
+<style lang="scss">
+</style>

+ 249 - 0
src/components/permissionlist/permissionlist.scss

@@ -0,0 +1,249 @@
+.bf-permissionlist {
+  width: 100%;
+  height: 100%;
+  > .right {
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      height: 57px;
+      display: flex;
+      align-items: flex-end;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+    }
+    > .paren_type {
+      width: 100%;
+      height: 60px;
+      > ul {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-top: 0;
+        margin-bottom: 0;
+        padding-left: 0;
+        > li {
+          display: flex;
+          align-items: center;
+          background-size: 100% 100%;
+          > .log {
+            width: 22px;
+            height: 22px;
+            margin-right: 9px;
+          }
+          > p {
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #303133;
+            margin-bottom: 0;
+            margin-top: 0;
+          }
+        }
+        > li:nth-child(1) {
+          > .log {
+            background: url('../../assets/index/ic_time@2x.png') no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(2) {
+          > .log {
+            background: url('../../assets/index/ic_data@2x.png') no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(3) {
+          > .log {
+            background: url('../../assets/index/ic_screen_edit@2x.png')
+              no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(4) {
+          > .log {
+            background: url('../../assets/index/ic_screen@2x.png') no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+      }
+    }
+    > .paren_list {
+      width: 100%;
+      margin-bottom: 10px;
+      > ul {
+        width: 100%;
+        height: 100%;
+        padding-left: 0;
+        margin-bottom: 0;
+        margin-top: 0;
+        display: flex;
+        align-items: center;
+        flex-wrap: wrap;
+        > li {
+          margin-right: 16px;
+          margin-bottom: 16px;
+          > .up_type {
+            padding: 0 5px;
+            height: 32px;
+            background: #f3f5fc;
+            border: 1px solid #6e81bc;
+            border-radius: 4px;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #6e81bc;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+          }
+          > .up_types {
+            padding: 0 5px;
+            height: 32px;
+            background: #6e81bc;
+            border-radius: 4px;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #ffffff;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+    .paren_content {
+      width: 100%;
+      height: 65%;
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          overflow-x: hidden;
+          > .el-scrollbar__view {
+            padding-top: 10px;
+            .el-row {
+              width: 100%;
+            }
+            .cide {
+              height: 80px;
+              cursor: pointer;
+              background: #f5f7fa;
+              box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
+              border-radius: 8px;
+              padding: 4px 16px 0 16px;
+              margin-bottom: 16px;
+              > .cide_header {
+                width: 100%;
+                height: 40px;
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                > p {
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #303133;
+                  white-space: nowrap;
+                  overflow: hidden;
+                  text-overflow: ellipsis;
+                }
+                > span {
+                  font-size: 14px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #6e81bc;
+                  cursor: pointer;
+                  min-width: 30px;
+                }
+              }
+              > .cide_cont {
+                > ul {
+                  width: 100%;
+                  height: 22px;
+                  display: flex;
+                  align-items: center;
+                  margin-bottom: 0;
+                  margin-top: 0;
+                  padding-left: 0;
+                  > li {
+                    width: 22px;
+                    height: 22px;
+                    margin-right: 8px;
+                  }
+                  .statusDate {
+                    background: url('../../assets/index/ic_time@2x.png')
+                      no-repeat;
+                    background-size: 100% 100%;
+                  }
+                  .statusShow {
+                    background: url('../../assets/index/ic_data@2x.png')
+                      no-repeat;
+                    background-size: 100% 100%;
+                  }
+                  .statusRule1 {
+                    background: url('../../assets/index/ic_screen@2x.png');
+                    background-size: 100% 100%;
+                  }
+                  .statusRule2 {
+                    background: url('../../assets/index/ic_screen_edit@2x.png');
+                    background-size: 100% 100%;
+                  }
+                }
+              }
+            }
+            > .paren_list {
+              width: 100%;
+              height: 32px;
+              margin-bottom: 10px;
+            }
+          }
+        }
+      }
+    }
+    .bgActive {
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          > .el-scrollbar__view {
+            .cide {
+              cursor: pointer;
+            }
+            .bgColor {
+              background: #6e81bc;
+              > .cide_header {
+                > p {
+                  color: #f5f7fa;
+                }
+                > span {
+                  color: #f5f7fa;
+                }
+              }
+              .el-radio__input.is-checked .el-radio__inner {
+                border-color: #f5f7fa;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+.hucPower {
+  .right {
+    .paren_content {
+      height: 25%;
+    }
+  }
+}

+ 238 - 0
src/components/permissiontree/index copy.vue

@@ -0,0 +1,238 @@
+<template>
+  <div class="bf-permissiontree">
+    <!-- 权限树 -->
+    <div class="cont">
+      <div class="paren_header">
+        <p>{{ title }}</p>
+      </div>
+      <div class="paren_type">
+        <ul>
+          <li>
+            <div class="log"></div>
+            <p>时效规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>数据规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示及编辑权限</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示权限</p>
+          </li>
+        </ul>
+      </div>
+      <div class="paren_list">
+        <ul>
+          <li v-for="(item, index) in treeTitles" :key="index">
+            <div
+              class="up_type"
+              :class="active === index ? 'up_types' : 'up_type'"
+              @click="upActive(item, index)"
+            >
+              {{ item.AuthName }}
+            </div>
+          </li>
+        </ul>
+      </div>
+      <div class="paren_cont">
+        <el-scrollbar style="height: 100%">
+          <el-tree
+            :data="data"
+            show-checkbox
+            @check-change="currentChange"
+            @node-click="handleNodeClick"
+            :defaultProps="defaultProps"
+            :expand-on-click-node="false"
+            node-key="AuthId"
+            default-expand-all
+            ref="tree"
+            highlight-current
+          >
+            <span class="custom-tree-node" slot-scope="{ data }">
+              {{ data.AuthName }}
+              <div class="logup">
+                <div
+                  class="one"
+                  v-if="
+                    data.AuthList != null && data.AuthList.ValidBegin != null
+                  "
+                ></div>
+                <div
+                  class="two"
+                  v-if="data.AuthList != null && data.AuthList.Action == '1'"
+                ></div>
+                <div
+                  class="four"
+                  v-if="data.AuthList != null && data.AuthList.Action == '2'"
+                ></div>
+                <div
+                  class="three"
+                  v-if="
+                    data.AuthList &&
+                    (data.AuthList.EditCol ||
+                      data.AuthList.DeleteRow ||
+                      data.AuthList.EditRow ||
+                      data.AuthList.NewCol ||
+                      data.AuthList.QueryCol ||
+                      data.AuthList.QueryRow)
+                  "
+                ></div>
+              </div>
+            </span>
+          </el-tree>
+        </el-scrollbar>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+// import treeData from "@/views/authorityManagement/minixs/treeData";
+import { translateDataToTreeAll } from "@/utils/validate";
+import { GetAuthTree } from "@/api/apiAuthority";
+export default {
+  props: {
+    title: {
+      type: String,
+      default: "",
+    },
+    checkedKeys: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      active: 0,
+      data: [],
+      treeTitles: [],
+      defaultProps: {
+        children: "children",
+        label: "AuthName",
+      },
+      dataObj: {}, //上级权限指定树数据
+      AuthArrList: [],//权限列表源数据
+      AuthList:[],//权限规则列表
+      checkedList:[]//选中的列表
+    };
+  },
+  watch: {
+    checkedKeys: {
+      handler(val) {
+        this.checkedList = val;
+        this.$refs.tree.setCheckedKeys(val);
+      },
+      deep: true,
+    },
+    "$store.state.auth.authList": {
+      handler(val) {
+        this.AuthList = val;
+        this.resetData();
+      },
+      immediate: true,
+      deep: true
+    },
+  },
+  created: function () {
+    this.getDataList();
+  },
+  methods: {
+    //获取权限列表
+    getDataList() {
+      GetAuthTree({ QueryName: "" }).then((result) => {
+        if (result.code === 0 && result.returnData.length) {
+          result.returnData.forEach((item) => {
+            item.flag = item.Status === 1 ? true : false;
+            item["AuthList"] = null;
+          });
+          this.AuthArrList = _.cloneDeep(result.returnData);
+          this.toTree();
+        } else {
+          this.$message.error(result.message);
+        }
+      });
+    },
+    //数据转树形
+    toTree() {
+      this.data = [];
+      this.dataObj = {};
+      this.treeTitles =[];
+      let arr = null
+      arr = translateDataToTreeAll(
+          this.AuthArrList,
+          "UpAuthId",
+          "AuthId"
+        )
+      let items = null
+      items = {
+        AuthId: 0,
+        AuthName: "所有权限",
+        QueryTarget: 0,
+        Status: 0,
+        UpAuthId: 0,
+        Type: 0,
+        children: arr,
+      };
+      this.dataObj = _.cloneDeep(items)
+      this.data = [items];
+      let obj = null
+      obj = _.cloneDeep(items);
+      let datas = null
+      datas = obj.children.filter((item) => item.Type === 1);
+      datas.forEach((item) => {
+        delete item.children;
+      });
+      delete obj.children;
+      datas.unshift(obj);
+      this.treeTitles = datas;
+    },
+    //数据切换
+    upActive(item, index) {
+      this.active = index;
+      this.decompose([this.dataObj], item.AuthId);
+      this.$refs.tree.setCheckedKeys(this.checkedList);
+    },
+    // 树节点选中
+    currentChange() {
+      this.checkedList = [],
+       this.$refs.tree.getCheckedNodes().forEach(item =>{
+         this.checkedList.push(item.AuthId);
+       })
+      this.$emit("getTreeData", this.$refs.tree.getCheckedNodes());
+    },
+    //获取指定数据
+    decompose(data, id) {
+      for (let i = 0; i < data.length; i++) {
+        if (data[i].AuthId == id) {
+          this.data = [data[i]];
+        } else if (data[i].children && data[i].children.length > 0) {
+          this.decompose(data[i].children, id);
+        }
+      }
+    },
+    //获取权限规则 从新组合数据
+    resetData() {
+      this.AuthArrList.forEach((item1) => {
+        item1["AuthList"] = null;
+        this.AuthList.forEach((item2) => {
+          if (item1.AuthId == item2.AuthId) {
+            item1.AuthList = item2;
+          }
+        });
+      });
+      this.toTree();
+    },
+    //获取点击目标
+    handleNodeClick(data){
+      // this.toTree();
+      this.$store.state.auth.authId = data;
+    }
+  },
+};
+</script>
+<style lang="scss">
+@import "./permissiontree.scss";
+</style>

+ 372 - 0
src/components/permissiontree/index.vue

@@ -0,0 +1,372 @@
+<template>
+  <div class="bf-permissiontree">
+    <!-- 权限树 -->
+    <div class="cont">
+      <div class="paren_header">
+        <p>{{ title }}</p>
+      </div>
+      <div class="paren_type">
+        <ul>
+          <li>
+            <div class="log"></div>
+            <p>时效规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>数据规则有</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示及编辑权限</p>
+          </li>
+          <li>
+            <div class="log"></div>
+            <p>显示权限</p>
+          </li>
+        </ul>
+      </div>
+      <!-- <div class="paren_list">
+        <ul>
+          <li v-for="(item, index) in treeTitles" :key="index">
+            <div
+              class="up_type"
+              :class="active === index ? 'up_types' : 'up_type'"
+              @click="upActive(item, index)"
+            >
+              {{ item.AuthName }}
+            </div>
+          </li>
+        </ul>
+      </div> -->
+      <div class="paren_cont">
+        <el-scrollbar style="height: 100%">
+          <el-tree
+            :data="data"
+            show-checkbox
+            :check-strictly="true"
+            @check-change="currentChange"
+            @node-click="handleNodeClick"
+            :defaultProps="defaultProps"
+            :expand-on-click-node="false"
+            node-key="AuthId"
+            default-expand-all
+            ref="tree"
+            highlight-current
+          >
+            <span class="custom-tree-node" slot-scope="{ data }">
+              {{ data.AuthName }}
+              <div class="logup">
+                <div
+                  class="one"
+                  v-if="data.AuthList && data.AuthList.ValidBegin"
+                ></div>
+                <div
+                  class="two"
+                  v-if="data.AuthList && data.AuthList.Action == '1'"
+                ></div>
+                <div
+                  class="four"
+                  v-if="data.AuthList && data.AuthList.Action == '2'"
+                ></div>
+                <div
+                  class="three"
+                  v-if="
+                    data.AuthList &&
+                    (data.AuthList.EditCol ||
+                      data.AuthList.DeleteRow ||
+                      data.AuthList.EditRow ||
+                      data.AuthList.NewCol ||
+                      data.AuthList.QueryCol ||
+                      data.AuthList.QueryRow)
+                  "
+                ></div>
+              </div>
+            </span>
+          </el-tree>
+        </el-scrollbar>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+// import treeData from "@/views/authorityManagement/minixs/treeData";
+import { translateDataToTreeAll, deteleObject } from "@/utils/validate";
+import { GetAuthTree } from "@/api/apiAuthority";
+import { GetAuthTreeByGroup } from "@/api/AccountGroup";
+import { organizationUptree, postUptree } from "@/api/postInterface";
+export default {
+  props: {
+    title: {
+      type: String,
+      default: "",
+    },
+    checkedKeys: {
+      //已选中
+      type: Array,
+      default: () => [],
+    },
+    //查询类型:queryType: all/获取全部权限树;job/根据岗位获取权限树;origin/根据组织获取权限树;group/根据帐号组获取权限树;
+    queryType: {
+      type: String,
+      default: "all",
+    },
+    //要查询的查询ID
+    queryId: {
+      type: String,
+      default: "",
+    },
+    //要查询的查询ID
+    isMainJob: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  data() {
+    return {
+      active: 0,
+      data: [],
+      treeTitles: [],
+      defaultProps: {
+        children: "children",
+        label: "AuthName",
+      },
+      searchId: "",
+      dataObj: {}, //上级权限指定树数据
+      AuthArrList: [], //权限列表源数据
+      AuthList: [], //权限规则列表
+      checkedList: [], //选中的列表
+      oldType: "",
+      queryIdArr: [], //历史查询ID
+      MainJobId:"",//主岗ID
+    };
+  },
+  watch: {
+    checkedKeys: {
+      handler(val) {
+        this.checkedList = val;
+        this.$refs.tree.setCheckedKeys(val);
+      },
+      deep: true,
+    },
+    "$store.state.auth.authList": {
+      handler(val) {
+        this.AuthList = val;
+        this.resetData();
+      },
+      immediate: true,
+      deep: true,
+    },
+    queryId: {
+      handler(val) {
+        if (this.queryType == "job") {
+          this.setDisabledAll();
+          let ids = val.split(",");
+          this.queryIdArr = [];
+          this.$refs.tree.setCheckedKeys([]);
+          if(this.isMainJob == true){
+            this.MainJobId = val;
+          }
+          if(this.MainJobId!=""){
+            this.queryIdArr.push(this.MainJobId);
+          }
+          for (let i = 0; i < ids.length; i++) {
+            if (_.indexOf(this.queryIdArr, ids[i]) == -1) {
+              this.queryIdArr.push(ids[i]);
+            }
+          }
+          for (let j = 0; j < this.queryIdArr.length; j++) {
+            this.searchId = this.queryIdArr[j];
+            this.getDefaultDataList();
+          }
+        } else {
+          this.searchId = val;
+          this.getDefaultDataList();
+        }
+      },
+      deep: true,
+    },
+  },
+  created: function () {
+    this.getDataList();
+    this.searchId = this.queryId;
+  },
+  methods: {
+    //获取权限列表
+    getDataList() {
+      GetAuthTree({ QueryName: "" }).then((result) => {
+        this.getDefaultDataList();
+        this.setData(result);
+      });
+    },
+    async getDefaultDataList() {
+      if (this.queryType == "all" && this.searchId != "") {
+        //获取全部权限树
+        GetAuthTree({ QueryName: "" }).then((result) => {
+          this.setUnDisabledData(result.returnData);
+        });
+      } else if (this.queryType == "job") {
+        //根据岗位获取权限树
+        postUptree({ JobId: this.searchId }).then((result) => {
+          this.setUnDisabledData(result.returnData);
+        });
+      } else if (this.queryType == "origin") {
+        //根据组织获取权限树
+        this.AuthList = [];
+        this.$refs.tree.setCheckedKeys([])
+        organizationUptree({ OrganId: this.searchId }).then((result) => {
+          this.setUnDisabledData(result.returnData);
+        });
+      } else if (this.queryType == "group") {
+        //根据帐号组获取权限树
+        GetAuthTreeByGroup({ GroupId: this.searchId }).then((result) => {
+          this.setUnDisabledData(result.returnData);
+        });
+      }
+    },
+    setData(result) {
+      if (result.code === 0 && result.returnData.length) {
+        this.AuthArrList = [];
+        result.returnData.forEach((item) => {
+          item.flag = item.Status === 1 ? true : false;
+          item["AuthList"] = null;
+          if(this.queryType!="all"){
+            item["disabled"] = true;
+          }
+        });
+        this.AuthArrList = _.cloneDeep(result.returnData);
+        this.toTree();
+      } else {
+        this.$message.error(result.message);
+      }
+    },
+    //数据转树形
+    toTree() {
+      this.data = [];
+      this.dataObj = {};
+      this.treeTitles = [];
+      let arr = null;
+      arr = translateDataToTreeAll(this.AuthArrList, "UpAuthId", "AuthId");
+      let items = null;
+      items = {
+        AuthId: 0,
+        AuthName: "所有权限",
+        QueryTarget: 0,
+        Status: 0,
+        UpAuthId: 0,
+        Type: 0,
+        disabled:true,
+        children: arr,
+      };
+      this.dataObj = _.cloneDeep(items);
+      this.data = [items];
+      let obj = null;
+      obj = _.cloneDeep(items);
+      let datas = null;
+      datas = obj.children.filter((item) => item.Type === 1);
+      datas.forEach((item) => {
+        delete item.children;
+      });
+      delete obj.children;
+      datas.unshift(obj);
+      this.treeTitles = datas;
+      if (this.$refs.tree) {
+        this.$refs.tree.setCheckedKeys(this.checkedList);
+      }
+    },
+    //数据切换
+    upActive(item, index) {
+      this.active = index;
+      this.decompose([this.dataObj], item.AuthId);
+      this.$refs.tree.setCheckedKeys(this.checkedList);
+    },
+    // 树节点选中
+    currentChange() {
+      this.checkedList = [];
+      const arr = this.$refs.tree.getCheckedNodes();
+      arr.forEach((item) => {
+        // if(item.disabled==false){
+          this.checkedList.push(item.AuthId);
+        // }
+      });
+      this.setDataObj(arr);
+    },
+    // 选中后设置初始数据
+    setDataObj(arr) {
+      arr.forEach((item) => {
+        if (!item.AuthList) {
+          item.AuthList = {
+            AuthId: item.AuthId,
+            ValidBegin: "",
+            ValidEnd: "",
+            Action: "1",
+            QueryRow: "",
+            QueryCol: "",
+            NewCol: "",
+            EditRow: "",
+            EditCol: "",
+            DeleteRow: "",
+          };
+        }
+      });
+      this.$emit("getTreeData", arr);
+    },
+    //获取指定数据
+    decompose(data, id) {
+      for (let i = 0; i < data.length; i++) {
+        if (data[i].AuthId == id) {
+          this.data = [data[i]];
+        } else if (data[i].children && data[i].children.length > 0) {
+          this.decompose(data[i].children, id);
+        }
+      }
+    },
+    //获取权限规则 从新组合数据
+    resetData() {
+      if (this.AuthList) {
+        this.AuthArrList.forEach((item1) => {
+          item1["AuthList"] = null;
+          this.AuthList.forEach((item2) => {
+            if (item1.AuthId == item2.AuthId) {
+              item1.AuthList = item2;
+            }
+          });
+        });
+      }
+      this.toTree();
+    },
+    setUnDisabledData(data) {
+      const ArrData = _.cloneDeep(data);
+      this.AuthArrList.forEach((item1) => {
+        if (this.queryType != "job") {
+          item1.disabled = true;
+        }
+        ArrData.forEach((item2) => {
+          if (item1.AuthId == item2.AuthId&&item1.Type!=1) {
+            item1.disabled = false;
+          }
+        });
+      });
+      this.toTree();
+    },
+    //获取点击目标
+    handleNodeClick(data) {
+      // this.toTree();
+      const arr = this.$store.getters.authArrs;
+      arr.push(data);
+      const datas = _.unionBy(arr, "AuthId");
+      const newDatas = _.cloneDeep(datas);
+      this.$store.dispatch("auth/changeAuthMsg", newDatas);
+      this.$store.dispatch("auth/changeAuthArrs", datas);
+      this.$store.dispatch("auth/changeAuthId", data.AuthId);
+    },
+    async setDisabledAll(){
+      this.AuthArrList.forEach(item=>{
+        item.disabled = true;
+      })
+    }
+  },
+};
+</script>
+<style lang="scss">
+@import "./permissiontree.scss";
+</style>

+ 189 - 0
src/components/permissiontree/permissiontree.scss

@@ -0,0 +1,189 @@
+.bf-permissiontree {
+  .el-checkbox__input.is-disabled .el-checkbox__inner{
+    background-color: #ebeef5!important;
+    border-color: #e4e7ed!important;
+  }
+  width: 100%;
+  height: 100%;
+  > .cont {
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      height: 57px;
+      display: flex;
+      align-items: flex-end;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+    }
+    > .paren_type {
+      width: 100%;
+      height: 60px;
+      > ul {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-top: 0;
+        margin-bottom: 0;
+        padding-left: 0;
+        > li {
+          display: flex;
+          align-items: center;
+          > .log {
+            width: 22px;
+            height: 22px;
+            margin-right: 9px;
+          }
+          > p {
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #303133;
+            margin-bottom: 0;
+            margin-top: 0;
+          }
+        }
+        > li:nth-child(1) {
+          > .log {
+            background: url("../../assets/index/ic_time@2x.png") no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(2) {
+          > .log {
+            background: url("../../assets/index/ic_data@2x.png") no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(3) {
+          > .log {
+            background: url("../../assets/index/ic_screen_edit@2x.png")
+              no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+        > li:nth-child(4) {
+          > .log {
+            background: url("../../assets/index/ic_screen@2x.png") no-repeat;
+            background-size: 100% 100%;
+          }
+        }
+      }
+    }
+    > .paren_list {
+      width: 100%;
+      > ul {
+        width: 100%;
+        height: 100%;
+        padding-left: 0;
+        margin-bottom: 0;
+        margin-top: 0;
+        display: flex;
+        align-items: center;
+        flex-wrap: wrap;
+        > li {
+          margin-right: 16px;
+          margin-bottom: 16px;
+          > .up_type {
+            padding: 0 5px;
+            height: 32px;
+            background: #f3f5fc;
+            border: 1px solid #6e81bc;
+            border-radius: 4px;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: 400;
+            color: #6e81bc;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+          }
+          > .up_types {
+            padding: 0 5px;
+            height: 32px;
+            background: #6e81bc;
+            border-radius: 4px;
+            font-size: 14px;
+            font-family: Microsoft YaHei;
+            font-weight: bold;
+            color: #ffffff;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+    > .paren_cont {
+      width: 100%;
+      height:calc(100% - 161px);
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          overflow-x: hidden;
+          > .el-scrollbar__view {
+            padding-top: 10px;
+          }
+        }
+      }
+    }
+    .el-tree-node__children {
+      display: flex;
+      flex-direction: column;
+    }
+    .custom-tree-node {
+      width: 90%;
+      font-size: 14px;
+      font-family: Microsoft YaHei;
+      font-weight: 400;
+      color: #303133;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+    .logup {
+      display: flex;
+      align-items: center;
+      .one {
+        width: 22px;
+        height: 22px;
+        background: url("../../assets/index/ic_time@2x.png") no-repeat;
+        background-size: 100% 100%;
+      }
+      .two {
+        width: 22px;
+        height: 22px;
+        background: url("../../assets/index/ic_screen@2x.png") no-repeat;
+        background-size: 100% 100%;
+        margin-left: 10px;
+      }
+      .three {
+        width: 22px;
+        height: 22px;
+        background: url("../../assets/index/ic_data@2x.png") no-repeat;
+        background-size: 100% 100%;
+        margin-left: 10px;
+      }
+      .four {
+        width: 22px;
+        height: 22px;
+        background: url("../../assets/index/ic_screen_edit@2x.png") no-repeat;
+        background-size: 100% 100%;
+        margin-left: 10px;
+      }
+    }
+  }
+}

+ 129 - 0
src/components/rolelist/index.vue

@@ -0,0 +1,129 @@
+<template>
+  <div class="bf-rolelist">
+    <!-- 角色列表 -->
+    <div class="cont">
+      <div v-if="title" class="paren_header">
+        <p>{{ title }}</p>
+      </div>
+      <template v-if="dataList.length">
+        <div :class="active ? 'bgActive' : 'bgActivecheckbox'" class="paren_content">
+          <el-scrollbar style="height: 100%">
+            <template v-if="!type">
+              <el-row :gutter="16">
+                <el-checkbox-group @change="checkChange" v-model="checkList">
+                  <el-col :span="number" v-for="(item, index) in dataList" :key="index">
+                    <div @click="handleBg(item, index)" :class="active && msg === index ? 'bgColor' : ''" class="cide">
+                      <div class="cide_header">
+                        <p :title="item.name">{{ item.name }}</p>
+                        <el-checkbox :label="index"></el-checkbox>
+                      </div>
+                    </div>
+                  </el-col>
+                </el-checkbox-group>
+              </el-row>
+            </template>
+            <template v-else>
+              <el-row :gutter="16">
+                <el-radio-group style="display: block;" @change="radioChange" v-model="radio">
+                  <el-col :span="number" v-for="(item, index) in dataList" :key="index">
+                    <div @click.stop="handleBg(index)" :class="active && msg === index ? 'bgColor' : ''" class="cide">
+                      <div class="cide_header">
+                        <p>{{ item.name }}</p>
+                        <el-radio :label="index"></el-radio>
+                      </div>
+                    </div>
+                  </el-col>
+                </el-radio-group>
+              </el-row>
+            </template>
+          </el-scrollbar>
+        </div>
+      </template>
+      <template v-else>
+        <el-empty description="暂无数据"></el-empty>
+      </template>
+    </div>
+  </div>
+</template>
+<script>
+import "./rolelist.scss";
+export default {
+  props: {
+    title: {
+      type: String,
+      default: "",
+    },
+    type: {
+      type: Boolean,
+      default: false,
+    },
+    number: {
+      type: Number,
+      default: 3,
+    },
+    active: {
+      type: Boolean,
+      default: false,
+    },
+    dataList: {
+      type: Array,
+      default: () => [],
+    },
+    checkBoxList: {
+      type: Array,
+      default: () => [],
+    },
+    radioCheck: {
+      type: Number,
+      default: 0,
+    }
+  },
+  data () {
+    return {
+      radio: null,
+      checkList: [],
+      msg: null,
+    };
+  },
+  watch: {
+    checkBoxList: {
+      handler (arr) {
+        this.checkList = arr;
+      },
+      deep: true,
+    },
+    radioCheck: {
+      handler (num) {
+        this.radio = num;
+      },
+      deep: true,
+    },
+  },
+  methods: {
+    // 选中
+    handleBg (item, i) {
+      this.msg = i;
+      this.$emit("checkClick", item);
+    },
+    //多选框
+    checkChange (arr) {
+      this.$emit("checkChange", arr);
+    },
+    //单选框
+    radioChange (val) {
+      this.$emit("radioChange", val);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.paren_content {
+  ::v-deep .el-radio__label {
+    display: none;
+  }
+  ::v-deep .el-checkbox__label {
+    display: none;
+  }
+}
+</style>

+ 121 - 0
src/components/rolelist/rolelist.scss

@@ -0,0 +1,121 @@
+.bf-rolelist {
+  width: 100%;
+  height: 100%;
+  > .cont {
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      height: 90px;
+      display: flex;
+      align-items: center;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+    }
+    .paren_content {
+      width: 100%;
+      height: 83%;
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          overflow-x: hidden;
+          > .el-scrollbar__view {
+            padding-top: 10px;
+            .el-row {
+              width: 100%;
+            }
+            .cide {
+              height: 80px;
+              background: #f5f7fa;
+              box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
+              border-radius: 8px;
+              margin-bottom: 16px;
+              padding: 16px 16px 0 16px;
+              cursor: pointer;
+              > .cide_header {
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+                > p {
+                  font-size: 16px;
+                  font-family: Microsoft YaHei;
+                  font-weight: 400;
+                  color: #303133;
+                  margin-top: 0;
+                  margin-bottom: 0;
+                  text-overflow: -o-ellipsis-lastline;
+                  overflow: hidden;
+                  text-overflow: ellipsis;
+                  display: -webkit-box;
+                  -webkit-line-clamp: 2;
+                  line-clamp: 2;
+                  -webkit-box-orient: vertical;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    .bgActive {
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          > .el-scrollbar__view {
+            .cide {
+              height: 64px;
+            }
+            .bgColor {
+              background: #6e81bc;
+              > .cide_header {
+                > p {
+                  color: #f5f7fa;
+                }
+              }
+              .el-radio__input.is-checked .el-radio__inner {
+                border-color: #f5f7fa;
+              }
+            }
+          }
+        }
+      }
+    }
+    .bgActivecheckbox {
+      > .el-scrollbar {
+        > .el-scrollbar__wrap {
+          > .el-scrollbar__view {
+            .cide {
+              // height: 64px;
+            }
+            .bgColor {
+              background: #6e81bc;
+              > .cide_header {
+                > p {
+                  color: #f5f7fa;
+                }
+              }
+              .el-radio__input.is-checked .el-radio__inner {
+                border-color: #f5f7fa;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+.lessData {
+  .cont {
+    padding: 0;
+    box-shadow: none;
+    background: inherit;
+  }
+}

+ 251 - 0
src/components/rulesofcompetency/index copy.vue

@@ -0,0 +1,251 @@
+<template>
+  <el-form class="bf-rulesofcompetency">
+    <!-- 权限规则 -->
+    <div class="right">
+      <div class="paren_header">
+        <p>{{ title }}</p>
+        <div class="header_right">
+          <el-radio
+            v-model="form.Action"
+            :label="item.id"
+            v-for="(item, index) in option"
+            :key="index"
+            >{{ item.label }}</el-radio
+          >
+        </div>
+      </div>
+      <div>
+        <span>{{name}}</span>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>时效范围起</p>
+        <el-date-picker
+          v-model="form.ValidBegin"
+          type="datetime"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          placeholder="选择时间"
+          size="mini"
+          :picker-options="pickerOptionsStart"
+        >
+        </el-date-picker>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>至</p>
+        <el-date-picker
+          @change="setTime"
+          v-model="form.ValidEnd"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetime"
+          placeholder="选择时间"
+          size="mini"
+          :picker-options="pickerOptionsEnd"
+        >
+        </el-date-picker>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可查询行</p>
+        <el-input
+          v-model="form.QueryRow"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可查询列</p>
+        <el-input
+          v-model="form.QueryCol"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可删除行</p>
+        <el-input
+          v-model="form.DeleteRow"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可新增列</p>
+        <el-input
+          v-model="form.NewCol"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可编辑行</p>
+        <el-input
+          v-model="form.EditRow"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可编辑列</p>
+        <el-input
+          v-model="form.EditCol"
+          placeholder="请输入内容"
+          size="mini"
+        ></el-input>
+      </div>
+    </div>
+  </el-form>
+</template>
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      default: " ",
+    },
+    marginB: {
+      type: String,
+      default: "24px",
+    },
+    authTo: {
+      type: Object,
+      default: () => {},
+    },
+    authList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      name:"",
+      pickerOptionsStart: {
+        disabledDate: (time) => {
+          if (this.endWeeks) {
+            return time.getTime() >= new Date(this.endWeeks).getTime();
+          }
+        },
+      },
+      pickerOptionsEnd: {
+        disabledDate: (time) => {
+          if (this.firstWeeks) {
+            return (
+              time.getTime() <= new Date(this.firstWeeks).getTime() - 86400000
+            );
+          }
+        },
+      },
+      form: {
+        AuthId:null,
+        DeleteRow: null,
+        EditCol: null,
+        Action: null,
+        EditRow: null,
+        NewCol: null,
+        QueryCol: null,
+        QueryRow: null,
+        ValidBegin: null,
+        ValidEnd: null,
+      },
+      option: [
+        {
+          label: "显示权限",
+          id: 1,
+        },
+        {
+          label: "显示及编辑权限",
+          id: 2,
+        },
+      ],
+      oldVal: null,
+    };
+  },
+  watch: {
+    "$store.state.auth.authId": {
+      handler(val) {
+        if (val && val.AuthId && this.oldVal == null) {
+          this.oldVal = val;
+          this.getFormData(val.AuthId);
+          this.name = val.AuthName;
+        }
+        if (val && val.AuthId && this.oldVal != null) {
+          if (val.AuthId != this.oldVal.AuthId) {
+          this.name = val.AuthName;
+            this.setAuthListData(val);
+          }
+        }
+      },
+      deep: true,
+    },
+  },
+  methods: {
+    getFormData(id) {
+      this.form = {
+        AuthId:null,
+        DeleteRow: null,
+        EditCol: null,
+        Action: null,
+        EditRow: null,
+        NewCol: null,
+        QueryCol: null,
+        QueryRow: null,
+        ValidBegin: null,
+        ValidEnd: null,
+      }
+      let list = this.$store.state.auth.authList;
+      console.log(list)
+      let idArr = [];
+      list.forEach((item) => {
+        console.log(item)
+        if(item!=null){
+        idArr.push(item.AuthId);
+        }
+        else{
+          idArr.push(null);
+        }
+      });
+      let index = idArr.indexOf(id);
+      if(index>-1){
+        this.form = this.$store.state.auth.authList[index];
+      }
+      else{
+        this.form.AuthId = id;
+      }
+      console.log( this.form)
+    },
+    setAuthListData(data) {
+      let list = this.$store.state.auth.authList;
+      let idArr = [];
+      list.forEach((item) => {
+        if(item.AuthId){
+        idArr.push(item.AuthId);
+        }
+        else{
+          idArr.push(null);
+        }
+      });
+      let index = idArr.indexOf(this.oldVal.AuthId);
+      if(index>-1){
+        this.$store.state.auth.authList[index] = this.form;
+      }
+      else{
+        this.$store.state.auth.authList.push(this.form)
+      }
+      this.oldVal = data;
+      this.getFormData(data.AuthId);
+    },
+    setTime(val) {
+      if (this.endWeeks < this.firstWeeks) {
+        this.endWeeks = "";
+      }
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+@import "./rulesofcompetency.scss";
+.el-picker-panel {
+  > .el-picker-panel__footer {
+    > .el-button--text {
+      display: none;
+    }
+  }
+}
+</style>

+ 231 - 0
src/components/rulesofcompetency/index.vue

@@ -0,0 +1,231 @@
+<template>
+  <el-form class="bf-rulesofcompetency">
+    <!-- 权限规则 -->
+    <div class="right">
+      <div class="paren_header">
+        <p>{{ title }}</p>
+        <div class="header_right">
+          <el-radio v-model="form.radio" :label="item.id" v-for="(item, index) in option" :key="index">{{ item.label }}</el-radio>
+        </div>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>时效范围起</p>
+        <el-date-picker v-model="form.firstWeeks" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择时间" size="mini" :picker-options="pickerOptionsStart">
+        </el-date-picker>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>至</p>
+        <el-date-picker @change="setTime" v-model="form.endWeeks" value-format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="选择时间" size="mini" :picker-options="pickerOptionsEnd">
+        </el-date-picker>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可查询行</p>
+        <el-input v-model="form.input1" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可查询列</p>
+        <el-input v-model="form.input2" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可删除行</p>
+        <el-input v-model="form.input3" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可新增列</p>
+        <el-input v-model="form.input4" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可编辑行</p>
+        <el-input v-model="form.input5" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+      <div class="juris_list" :style="{ marginBottom: marginB }">
+        <p>许可编辑列</p>
+        <el-input v-model="form.input6" placeholder="请输入内容" size="mini"></el-input>
+      </div>
+    </div>
+  </el-form>
+</template>
+<script>
+export default {
+  props: {
+    title: {
+      type: String,
+      default: " ",
+    },
+    marginB: {
+      type: String,
+      default: "24px",
+    },
+    authTo: {
+      type: Object,
+      default: () => { }
+    },
+    authList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data () {
+    return {
+      pickerOptionsStart: {
+        disabledDate: time => {
+          if (this.form.endWeeks) {
+            return time.getTime() >= new Date(this.endWeeks).getTime()
+          }
+        }
+      },
+      pickerOptionsEnd: {
+        disabledDate: time => {
+          if (this.form.firstWeeks) {
+            return time.getTime() <= new Date(this.firstWeeks).getTime() - 86400000
+          }
+        }
+      },
+      form: {
+        endWeeks: '',
+        firstWeeks: '',
+        radio: 1,
+        value1: "",
+        value2: "",
+        input1: "",
+        input2: "",
+        input3: "",
+        input4: "",
+        input5: "",
+        input6: "",
+      },
+      option: [
+        {
+          label: "显示权限",
+          id: 1,
+        },
+        {
+          label: "显示及编辑权限",
+          id: 2,
+        },
+      ],
+    };
+  },
+  watch: {
+    authTo: {
+      handler (obj) {
+        const { Action, ValidBegin, ValidEnd, QueryRow, QueryCol, NewCol, EditCol, EditRow, DeleteRow } = obj
+        this.form.radio = Number(Action)
+        this.form.firstWeeks = ValidBegin
+        this.form.endWeeks = ValidEnd
+        this.form.input1 = QueryRow
+        this.form.input2 = QueryCol
+        this.form.input3 = DeleteRow
+        this.form.input4 = NewCol
+        this.form.input5 = EditRow
+        this.form.input6 = EditCol
+      },
+      deep: true
+    },
+    form: {
+      handler () {
+        this.getData()
+      },
+      deep: true
+    },
+    authList: {
+      handler (arr) {
+        this.$store.dispatch('auth/changeAuthList', arr)
+      },
+      deep: true
+    },
+    "$store.state.auth.authMsg": {
+      handler (arr) {
+        const id = this.$store.getters.authId
+        const obj = arr.filter(item => item.AuthId === id)[0]
+        this.clearFormData()
+        this.setFormData(obj)
+      },
+      deep: true
+    },
+  },
+  methods: {
+    setTime () {
+      if (this.form.endWeeks <= this.form.firstWeeks) {
+        this.form.endWeeks = ''
+        this.$message.error('结束时间不能小于开始时间,请重新选择')
+      }
+    },
+    getData () {
+      const obj = {
+        Action: this.form.radio,
+        ValidBegin: this.form.firstWeeks,
+        ValidEnd: this.form.endWeeks,
+        QueryRow: this.form.input1,
+        QueryCol: this.form.input2,
+        NewCol: this.form.input4,
+        EditCol: this.form.input6,
+        EditRow: this.form.input5,
+        DeleteRow: this.form.input3
+      }
+      this.$emit('getData', obj)
+      const arr = this.$store.getters.authArrs
+      const datas = _.unionBy(arr, 'AuthId')
+      const id = this.$store.getters.authId
+      // console.log(datas)
+      if (datas.length) {
+        // const dat = datas[datas.length - 1]
+        let dat = datas[datas.length - 1]
+        datas.map(item=>{
+          if(item.AuthId == id){
+            dat = item;
+          }
+        })
+        const { AuthId } = dat
+        obj["AuthId"] = AuthId
+        datas.forEach(item => {
+          if (item.AuthId == id) {
+            item.AuthList = obj
+          }
+        })
+        this.$store.dispatch('auth/changeAuthArrs', datas)
+        //this.$emit('getData', obj)
+      }
+    },
+    clearFormData () {
+      this.form.radio = ''
+      this.form.firstWeeks = ''
+      this.form.endWeeks = ''
+      this.form.input1 = ''
+      this.form.input2 = ''
+      this.form.input3 = ''
+      this.form.input4 = ''
+      this.form.input5 = ''
+      this.form.input6 = ''
+    },
+    setFormData (obj) {
+      let data = {}
+      if (obj.AuthList) {
+        data = obj.AuthList
+      } else {
+        data = obj
+      }
+      const { Action = '', ValidBegin = '', ValidEnd = '', QueryRow = '', QueryCol = '', NewCol = '', EditCol = '', EditRow = '', DeleteRow = '' } = data
+      this.form.radio = Number(Action)
+      this.form.firstWeeks = ValidBegin
+      this.form.endWeeks = ValidEnd
+      this.form.input1 = QueryRow
+      this.form.input2 = QueryCol
+      this.form.input3 = DeleteRow
+      this.form.input4 = NewCol
+      this.form.input5 = EditRow
+      this.form.input6 = EditCol
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+@import "./rulesofcompetency.scss";
+.el-picker-panel {
+  > .el-picker-panel__footer {
+    > .el-button--text {
+      display: none;
+    }
+  }
+}
+</style>

+ 74 - 0
src/components/rulesofcompetency/rulesofcompetency.scss

@@ -0,0 +1,74 @@
+.bf-rulesofcompetency {
+  width: 100%;
+  height: 100%;
+  > .right {
+    width: 100%;
+    height: 100%;
+    background: #ffffff;
+    box-shadow: 0px 6px 7px 0px rgba(0, 0, 0, 0.06);
+    border-radius: 16px;
+    padding: 0 32px 0 32px;
+    > .paren_header {
+      width: 100%;
+      height: 70px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      // margin-bottom: 24px;
+      > p {
+        font-size: 24px;
+        font-family: Microsoft YaHei;
+        font-weight: bold;
+        color: #303133;
+        margin-top: 0;
+        margin-bottom: 0;
+      }
+      > .header_right {
+        height: 100%;
+        display: flex;
+        align-items: center;
+      }
+    }
+    > .juris_list {
+      width: 100%;
+      display: flex;
+      align-items: center;
+      // margin-bottom: 19px;
+      > p {
+        width: 71px;
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+        margin-bottom: 0;
+        margin-top: 0;
+        margin-right: 16px;
+        font-size: 14px;
+        font-family: Microsoft YaHei;
+        font-weight: 400;
+        color: #303133;
+      }
+      .el-input__inner {
+        width: 376px;
+        height: 32px;
+        background: #f9fbff;
+        border-radius: 6px;
+      }
+      .el-input__icon {
+        display: flex;
+        align-items: center;
+      }
+      > .el-input {
+        width: 376px;
+        height: 32px;
+        background: #f9fbff;
+        border-radius: 6px;
+        > .el-input__inner {
+          width: 100%;
+          height: 100%;
+          background: #f9fbff;
+          border-radius: 6px;
+        }
+      }
+    }
+  }
+}

+ 9 - 0
src/icons/index.js

@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)

File diff suppressed because it is too large
+ 0 - 0
src/icons/svg/dashboard.svg


+ 1 - 0
src/icons/svg/example.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>

+ 1 - 0
src/icons/svg/eye-open.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>

Some files were not shown because too many files changed in this diff