Browse Source

Merge remote-tracking branch 'origin/master'

Administrator 4 years ago
parent
commit
7100d02075
100 changed files with 7276 additions and 7276 deletions
  1. 22 22
      ruoyi-ui/.editorconfig
  2. 8 8
      ruoyi-ui/.env.development
  3. 5 5
      ruoyi-ui/.env.production
  4. 7 7
      ruoyi-ui/.env.staging
  5. 9 9
      ruoyi-ui/.eslintignore
  6. 199 199
      ruoyi-ui/.eslintrc.js
  7. 23 23
      ruoyi-ui/.gitignore
  8. 29 29
      ruoyi-ui/README.md
  9. 13 13
      ruoyi-ui/babel.config.js
  10. 11 11
      ruoyi-ui/bin/build.bat
  11. 11 11
      ruoyi-ui/bin/package.bat
  12. 11 11
      ruoyi-ui/bin/run-web.bat
  13. 35 35
      ruoyi-ui/build/index.js
  14. 87 87
      ruoyi-ui/package.json
  15. 207 207
      ruoyi-ui/public/index.html
  16. 1 1
      ruoyi-ui/public/robots.txt
  17. 20 20
      ruoyi-ui/src/App.vue
  18. 41 41
      ruoyi-ui/src/api/login.js
  19. 8 8
      ruoyi-ui/src/api/menu.js
  20. 70 70
      ruoyi-ui/src/api/monitor/job.js
  21. 26 26
      ruoyi-ui/src/api/monitor/jobLog.js
  22. 18 18
      ruoyi-ui/src/api/monitor/online.js
  23. 110 110
      ruoyi-ui/src/api/system/config.js
  24. 68 68
      ruoyi-ui/src/api/system/dept.js
  25. 52 52
      ruoyi-ui/src/api/system/dict/data.js
  26. 60 60
      ruoyi-ui/src/api/system/dict/type.js
  27. 48 48
      ruoyi-ui/src/api/system/editing.js
  28. 26 26
      ruoyi-ui/src/api/system/logininfor.js
  29. 60 60
      ruoyi-ui/src/api/system/menu.js
  30. 44 44
      ruoyi-ui/src/api/system/notice.js
  31. 26 26
      ruoyi-ui/src/api/system/operlog.js
  32. 44 44
      ruoyi-ui/src/api/system/post.js
  33. 66 66
      ruoyi-ui/src/api/system/role.js
  34. 110 110
      ruoyi-ui/src/api/system/user.js
  35. 234 234
      ruoyi-ui/src/api/tool/gen.js
  36. 9 9
      ruoyi-ui/src/assets/icons/index.js
  37. 1 1
      ruoyi-ui/src/assets/icons/svg/monitor.svg
  38. 1 1
      ruoyi-ui/src/assets/icons/svg/system.svg
  39. 22 22
      ruoyi-ui/src/assets/icons/svgo.yml
  40. 38 38
      ruoyi-ui/src/assets/images/dark.svg
  41. 38 38
      ruoyi-ui/src/assets/images/light.svg
  42. 99 99
      ruoyi-ui/src/assets/styles/btn.scss
  43. 84 84
      ruoyi-ui/src/assets/styles/element-ui.scss
  44. 31 31
      ruoyi-ui/src/assets/styles/element-variables.scss
  45. 191 191
      ruoyi-ui/src/assets/styles/index.scss
  46. 66 66
      ruoyi-ui/src/assets/styles/mixin.scss
  47. 240 240
      ruoyi-ui/src/assets/styles/ruoyi.scss
  48. 245 245
      ruoyi-ui/src/assets/styles/sidebar.scss
  49. 48 48
      ruoyi-ui/src/assets/styles/transition.scss
  50. 44 44
      ruoyi-ui/src/assets/styles/variables.scss
  51. 74 74
      ruoyi-ui/src/components/Breadcrumb/index.vue
  52. 13 13
      ruoyi-ui/src/components/Directives/index.js
  53. 149 149
      ruoyi-ui/src/components/DynamicForms/index.vue
  54. 200 200
      ruoyi-ui/src/components/Editor/index.vue
  55. 178 178
      ruoyi-ui/src/components/FileUpload/index.vue
  56. 45 45
      ruoyi-ui/src/components/Hamburger/index.vue
  57. 189 189
      ruoyi-ui/src/components/HeaderSearch/index.vue
  58. 68 68
      ruoyi-ui/src/components/IconSelect/index.vue
  59. 11 11
      ruoyi-ui/src/components/IconSelect/requireIcons.js
  60. 99 99
      ruoyi-ui/src/components/ImageUpload/index.vue
  61. 35 35
      ruoyi-ui/src/components/MemoranDum/index.vue
  62. 101 101
      ruoyi-ui/src/components/Pagination/index.vue
  63. 142 142
      ruoyi-ui/src/components/PanThumb/index.vue
  64. 3 3
      ruoyi-ui/src/components/ParentView/index.vue
  65. 149 149
      ruoyi-ui/src/components/RightPanel/index.vue
  66. 80 80
      ruoyi-ui/src/components/RightToolbar/index.vue
  67. 20 20
      ruoyi-ui/src/components/RuoYi/Doc/index.vue
  68. 20 20
      ruoyi-ui/src/components/RuoYi/Git/index.vue
  69. 57 57
      ruoyi-ui/src/components/Screenfull/index.vue
  70. 136 136
      ruoyi-ui/src/components/SignNumArr/index.vue
  71. 57 57
      ruoyi-ui/src/components/SizeSelect/index.vue
  72. 61 61
      ruoyi-ui/src/components/SvgIcon/index.vue
  73. 71 71
      ruoyi-ui/src/components/TabForm/index.vue
  74. 175 175
      ruoyi-ui/src/components/ThemePicker/index.vue
  75. 28 28
      ruoyi-ui/src/directive/permission/hasPermi.js
  76. 28 28
      ruoyi-ui/src/directive/permission/hasRole.js
  77. 15 15
      ruoyi-ui/src/directive/permission/index.js
  78. 57 57
      ruoyi-ui/src/layout/components/AppMain.vue
  79. 201 201
      ruoyi-ui/src/layout/components/Navbar.vue
  80. 197 197
      ruoyi-ui/src/layout/components/Settings/index.vue
  81. 25 25
      ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
  82. 29 29
      ruoyi-ui/src/layout/components/Sidebar/Item.vue
  83. 43 43
      ruoyi-ui/src/layout/components/Sidebar/Link.vue
  84. 94 94
      ruoyi-ui/src/layout/components/Sidebar/Logo.vue
  85. 98 98
      ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
  86. 70 70
      ruoyi-ui/src/layout/components/Sidebar/index.vue
  87. 94 94
      ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
  88. 303 303
      ruoyi-ui/src/layout/components/TagsView/index.vue
  89. 5 5
      ruoyi-ui/src/layout/components/index.js
  90. 108 108
      ruoyi-ui/src/layout/index.vue
  91. 45 45
      ruoyi-ui/src/layout/mixin/ResizeHandler.js
  92. 83 83
      ruoyi-ui/src/main.js
  93. 52 52
      ruoyi-ui/src/permission.js
  94. 205 205
      ruoyi-ui/src/router/index.js
  95. 17 17
      ruoyi-ui/src/store/getters.js
  96. 23 23
      ruoyi-ui/src/store/index.js
  97. 56 56
      ruoyi-ui/src/store/modules/app.js
  98. 107 107
      ruoyi-ui/src/store/modules/permission.js
  99. 35 35
      ruoyi-ui/src/store/modules/settings.js
  100. 159 159
      ruoyi-ui/src/store/modules/tagsView.js

+ 22 - 22
ruoyi-ui/.editorconfig

@@ -1,22 +1,22 @@
-# 告诉EditorConfig插件,这是根文件,不用继续往上查找
-root = true
-
-# 匹配全部文件
-[*]
-# 设置字符集
-charset = utf-8
-# 缩进风格,可选space、tab
-indent_style = space
-# 缩进的空格数
-indent_size = 2
-# 结尾换行符,可选lf、cr、crlf
-end_of_line = lf
-# 在文件结尾插入新行
-insert_final_newline = true
-# 删除一行中的前后空格
-trim_trailing_whitespace = true
-
-# 匹配md结尾的文件
-[*.md]
-insert_final_newline = false
-trim_trailing_whitespace = false
+# 告诉EditorConfig插件,这是根文件,不用继续往上查找
+root = true
+
+# 匹配全部文件
+[*]
+# 设置字符集
+charset = utf-8
+# 缩进风格,可选space、tab
+indent_style = space
+# 缩进的空格数
+indent_size = 2
+# 结尾换行符,可选lf、cr、crlf
+end_of_line = lf
+# 在文件结尾插入新行
+insert_final_newline = true
+# 删除一行中的前后空格
+trim_trailing_whitespace = true
+
+# 匹配md结尾的文件
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 8 - 8
ruoyi-ui/.env.development

@@ -1,8 +1,8 @@
-# 开发环境配置
-ENV = 'development'
-
-# 潜山市云数据中心/开发环境
-VUE_APP_BASE_API = '/dev-api'
-
-# 路由懒加载
-VUE_CLI_BABEL_TRANSPILE_MODULES = true
+# 开发环境配置
+ENV = 'development'
+
+# 潜山市云数据中心/开发环境
+VUE_APP_BASE_API = '/dev-api'
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 5 - 5
ruoyi-ui/.env.production

@@ -1,5 +1,5 @@
-# 生产环境配置
-ENV = 'production'
-
-# 潜山市云数据中心/生产环境
-VUE_APP_BASE_API = '/prod-api'
+# 生产环境配置
+ENV = 'production'
+
+# 潜山市云数据中心/生产环境
+VUE_APP_BASE_API = '/prod-api'

+ 7 - 7
ruoyi-ui/.env.staging

@@ -1,7 +1,7 @@
-NODE_ENV = production
-
-# 测试环境配置
-ENV = 'staging'
-
-# 潜山市云数据中心/测试环境
-VUE_APP_BASE_API = '/stage-api'
+NODE_ENV = production
+
+# 测试环境配置
+ENV = 'staging'
+
+# 潜山市云数据中心/测试环境
+VUE_APP_BASE_API = '/stage-api'

+ 9 - 9
ruoyi-ui/.eslintignore

@@ -1,10 +1,10 @@
-# 忽略build目录下类型为js的文件的语法检查
-build/*.js
-# 忽略src/assets目录下文件的语法检查
-src/assets
-# 忽略public目录下文件的语法检查
-public
-# 忽略当前目录下为js的文件的语法检查
-*.js
-# 忽略当前目录下为vue的文件的语法检查
+# 忽略build目录下类型为js的文件的语法检查
+build/*.js
+# 忽略src/assets目录下文件的语法检查
+src/assets
+# 忽略public目录下文件的语法检查
+public
+# 忽略当前目录下为js的文件的语法检查
+*.js
+# 忽略当前目录下为vue的文件的语法检查
 *.vue

+ 199 - 199
ruoyi-ui/.eslintrc.js

@@ -1,199 +1,199 @@
-// ESlint 检查配置
-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']
-  }
-}
+// ESlint 检查配置
+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']
+  }
+}

+ 23 - 23
ruoyi-ui/.gitignore

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

+ 29 - 29
ruoyi-ui/README.md

@@ -1,30 +1,30 @@
-## 开发
-
-```bash
-# 克隆项目
-git clone https://gitee.com/y_project/RuoYi-Vue
-
-# 进入项目目录
-cd ruoyi-ui
-
-# 安装依赖
-npm install
-
-# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
-npm install --registry=https://registry.npm.taobao.org
-
-# 启动服务
-npm run dev
-```
-
-浏览器访问 http://localhost:80
-
-## 发布
-
-```bash
-# 构建测试环境
-npm run build:stage
-
-# 构建生产环境
-npm run build:prod
+## 开发
+
+```bash
+# 克隆项目
+git clone https://gitee.com/y_project/RuoYi-Vue
+
+# 进入项目目录
+cd ruoyi-ui
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 http://localhost:80
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
 ```

+ 13 - 13
ruoyi-ui/babel.config.js

@@ -1,13 +1,13 @@
-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.
-      'plugins': ['dynamic-import-node']
-    }
-  }
-}
+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.
+      'plugins': ['dynamic-import-node']
+    }
+  }
+}

+ 11 - 11
ruoyi-ui/bin/build.bat

@@ -1,12 +1,12 @@
-@echo off
-echo.
-echo [信息] 打包Web工程,生成dist文件。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm run build:prod
-
+@echo off
+echo.
+echo [信息] 打包Web工程,生成dist文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run build:prod
+
 pause

+ 11 - 11
ruoyi-ui/bin/package.bat

@@ -1,12 +1,12 @@
-@echo off
-echo.
-echo [信息] 安装Web工程,生成node_modules文件。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm install --registry=https://registry.npm.taobao.org
-
+@echo off
+echo.
+echo [信息] 安装Web工程,生成node_modules文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npm.taobao.org
+
 pause

+ 11 - 11
ruoyi-ui/bin/run-web.bat

@@ -1,12 +1,12 @@
-@echo off
-echo.
-echo [信息] 使用 Vue 运行 Web 工程。
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm run dev
-
+@echo off
+echo.
+echo [信息] 使用 Vue 运行 Web 工程。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
 pause

+ 35 - 35
ruoyi-ui/build/index.js

@@ -1,35 +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}`)
-}
+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}`)
+}

+ 87 - 87
ruoyi-ui/package.json

@@ -1,87 +1,87 @@
-{
-  "name": "ruoyi",
-  "version": "2.5.0",
-  "description": "潜山市云数据中心",
-  "author": "若依",
-  "license": "MIT",
-  "scripts": {
-    "dev": "vue-cli-service serve",
-    "build:prod": "vue-cli-service build",
-    "build:stage": "vue-cli-service build --mode staging",
-    "preview": "node build/index.js --preview",
-    "lint": "eslint --ext .js,.vue src"
-  },
-  "husky": {
-    "hooks": {
-      "pre-commit": "lint-staged"
-    }
-  },
-  "lint-staged": {
-    "src/**/*.{js,vue}": [
-      "eslint --fix",
-      "git add"
-    ]
-  },
-  "keywords": [
-    "vue",
-    "admin",
-    "dashboard",
-    "element-ui",
-    "boilerplate",
-    "admin-template",
-    "management-system"
-  ],
-  "repository": {
-    "type": "git",
-    "url": "https://gitee.com/y_project/RuoYi-Vue.git"
-  },
-  "dependencies": {
-    "@riophae/vue-treeselect": "0.4.0",
-    "axios": "0.21.0",
-    "clipboard": "2.0.6",
-    "core-js": "3.8.1",
-    "echarts": "4.9.0",
-    "element-ui": "2.15.0",
-    "file-saver": "2.0.4",
-    "fuse.js": "6.4.3",
-    "highlight.js": "9.18.5",
-    "js-beautify": "1.13.0",
-    "js-cookie": "2.2.1",
-    "jsencrypt": "3.0.0-rc.1",
-    "nprogress": "0.2.0",
-    "quill": "1.3.7",
-    "screenfull": "5.0.2",
-    "sortablejs": "1.10.2",
-    "vue": "2.6.12",
-    "vue-count-to": "1.0.13",
-    "vue-cropper": "0.5.5",
-    "vue-router": "3.4.9",
-    "vuedraggable": "2.24.3",
-    "vuex": "3.6.0"
-  },
-  "devDependencies": {
-    "@vue/cli-plugin-babel": "4.4.6",
-    "@vue/cli-plugin-eslint": "4.4.6",
-    "@vue/cli-service": "4.4.6",
-    "babel-eslint": "10.1.0",
-    "chalk": "4.1.0",
-    "connect": "3.6.6",
-    "eslint": "7.15.0",
-    "eslint-plugin-vue": "7.2.0",
-    "lint-staged": "10.5.3",
-    "runjs": "4.4.2",
-    "sass": "1.32.0",
-    "sass-loader": "10.1.0",
-    "script-ext-html-webpack-plugin": "2.1.5",
-    "svg-sprite-loader": "5.1.1",
-    "vue-template-compiler": "2.6.12"
-  },
-  "engines": {
-    "node": ">=8.9",
-    "npm": ">= 3.0.0"
-  },
-  "browserslist": [
-    "> 1%",
-    "last 2 versions"
-  ]
-}
+{
+  "name": "ruoyi",
+  "version": "2.5.0",
+  "description": "潜山市云数据中心",
+  "author": "若依",
+  "license": "MIT",
+  "scripts": {
+    "dev": "vue-cli-service serve",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "preview": "node build/index.js --preview",
+    "lint": "eslint --ext .js,.vue src"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "src/**/*.{js,vue}": [
+      "eslint --fix",
+      "git add"
+    ]
+  },
+  "keywords": [
+    "vue",
+    "admin",
+    "dashboard",
+    "element-ui",
+    "boilerplate",
+    "admin-template",
+    "management-system"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://gitee.com/y_project/RuoYi-Vue.git"
+  },
+  "dependencies": {
+    "@riophae/vue-treeselect": "0.4.0",
+    "axios": "0.21.0",
+    "clipboard": "2.0.6",
+    "core-js": "3.8.1",
+    "echarts": "4.9.0",
+    "element-ui": "2.15.0",
+    "file-saver": "2.0.4",
+    "fuse.js": "6.4.3",
+    "highlight.js": "9.18.5",
+    "js-beautify": "1.13.0",
+    "js-cookie": "2.2.1",
+    "jsencrypt": "3.0.0-rc.1",
+    "nprogress": "0.2.0",
+    "quill": "1.3.7",
+    "screenfull": "5.0.2",
+    "sortablejs": "1.10.2",
+    "vue": "2.6.12",
+    "vue-count-to": "1.0.13",
+    "vue-cropper": "0.5.5",
+    "vue-router": "3.4.9",
+    "vuedraggable": "2.24.3",
+    "vuex": "3.6.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "4.4.6",
+    "@vue/cli-plugin-eslint": "4.4.6",
+    "@vue/cli-service": "4.4.6",
+    "babel-eslint": "10.1.0",
+    "chalk": "4.1.0",
+    "connect": "3.6.6",
+    "eslint": "7.15.0",
+    "eslint-plugin-vue": "7.2.0",
+    "lint-staged": "10.5.3",
+    "runjs": "4.4.2",
+    "sass": "1.32.0",
+    "sass-loader": "10.1.0",
+    "script-ext-html-webpack-plugin": "2.1.5",
+    "svg-sprite-loader": "5.1.1",
+    "vue-template-compiler": "2.6.12"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
+}

+ 207 - 207
ruoyi-ui/public/index.html

@@ -1,207 +1,207 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="renderer" content="webkit">
-    <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>
-	  <style>
-    html,
-    body,
-    #app {
-      height: 100%;
-      margin: 0px;
-      padding: 0px;
-    }
-    .chromeframe {
-      margin: 0.2em 0;
-      background: #ccc;
-      color: #000;
-      padding: 0.2em 0;
-    }
-
-    #loader-wrapper {
-      position: fixed;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      z-index: 999999;
-    }
-
-    #loader {
-      display: block;
-      position: relative;
-      left: 50%;
-      top: 50%;
-      width: 150px;
-      height: 150px;
-      margin: -75px 0 0 -75px;
-      border-radius: 50%;
-      border: 3px solid transparent;
-      border-top-color: #FFF;
-      -webkit-animation: spin 2s linear infinite;
-      -ms-animation: spin 2s linear infinite;
-      -moz-animation: spin 2s linear infinite;
-      -o-animation: spin 2s linear infinite;
-      animation: spin 2s linear infinite;
-      z-index: 1001;
-    }
-
-    #loader:before {
-      content: "";
-      position: absolute;
-      top: 5px;
-      left: 5px;
-      right: 5px;
-      bottom: 5px;
-      border-radius: 50%;
-      border: 3px solid transparent;
-      border-top-color: #FFF;
-      -webkit-animation: spin 3s linear infinite;
-      -moz-animation: spin 3s linear infinite;
-      -o-animation: spin 3s linear infinite;
-      -ms-animation: spin 3s linear infinite;
-      animation: spin 3s linear infinite;
-    }
-
-    #loader:after {
-      content: "";
-      position: absolute;
-      top: 15px;
-      left: 15px;
-      right: 15px;
-      bottom: 15px;
-      border-radius: 50%;
-      border: 3px solid transparent;
-      border-top-color: #FFF;
-      -moz-animation: spin 1.5s linear infinite;
-      -o-animation: spin 1.5s linear infinite;
-      -ms-animation: spin 1.5s linear infinite;
-      -webkit-animation: spin 1.5s linear infinite;
-      animation: spin 1.5s linear infinite;
-    }
-
-
-    @-webkit-keyframes spin {
-      0% {
-        -webkit-transform: rotate(0deg);
-        -ms-transform: rotate(0deg);
-        transform: rotate(0deg);
-      }
-      100% {
-        -webkit-transform: rotate(360deg);
-        -ms-transform: rotate(360deg);
-        transform: rotate(360deg);
-      }
-    }
-
-    @keyframes spin {
-      0% {
-        -webkit-transform: rotate(0deg);
-        -ms-transform: rotate(0deg);
-        transform: rotate(0deg);
-      }
-      100% {
-        -webkit-transform: rotate(360deg);
-        -ms-transform: rotate(360deg);
-        transform: rotate(360deg);
-      }
-    }
-
-
-    #loader-wrapper .loader-section {
-      position: fixed;
-      top: 0;
-      width: 51%;
-      height: 100%;
-      background: #7171C6;
-      z-index: 1000;
-      -webkit-transform: translateX(0);
-      -ms-transform: translateX(0);
-      transform: translateX(0);
-    }
-
-    #loader-wrapper .loader-section.section-left {
-      left: 0;
-    }
-
-    #loader-wrapper .loader-section.section-right {
-      right: 0;
-    }
-
-
-    .loaded #loader-wrapper .loader-section.section-left {
-      -webkit-transform: translateX(-100%);
-      -ms-transform: translateX(-100%);
-      transform: translateX(-100%);
-      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
-      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
-    }
-
-    .loaded #loader-wrapper .loader-section.section-right {
-      -webkit-transform: translateX(100%);
-      -ms-transform: translateX(100%);
-      transform: translateX(100%);
-      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
-      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
-    }
-
-    .loaded #loader {
-      opacity: 0;
-      -webkit-transition: all 0.3s ease-out;
-      transition: all 0.3s ease-out;
-    }
-
-    .loaded #loader-wrapper {
-      visibility: hidden;
-      -webkit-transform: translateY(-100%);
-      -ms-transform: translateY(-100%);
-      transform: translateY(-100%);
-      -webkit-transition: all 0.3s 1s ease-out;
-      transition: all 0.3s 1s ease-out;
-    }
-
-    .no-js #loader-wrapper {
-      display: none;
-    }
-
-    .no-js h1 {
-      color: #222222;
-    }
-
-    #loader-wrapper .load_title {
-      font-family: 'Open Sans';
-      color: #FFF;
-      font-size: 19px;
-      width: 100%;
-      text-align: center;
-      z-index: 9999999999999;
-      position: absolute;
-      top: 60%;
-      opacity: 1;
-      line-height: 30px;
-    }
-
-    #loader-wrapper .load_title span {
-      font-weight: normal;
-      font-style: italic;
-      font-size: 13px;
-      color: #FFF;
-      opacity: 0.5;
-    }
-  </style>
-  </head>
-  <body>
-    <div id="app">
-	    <div id="loader-wrapper">
-		    <div id="loader"></div>
-		    <div class="loader-section section-left"></div>
-		    <div class="loader-section section-right"></div>
-		    <div class="load_title">正在加载系统资源,请耐心等待</div>
-        </div>
-	</div>
-  </body>
-</html>
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="renderer" content="webkit">
+    <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>
+	  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0px;
+      padding: 0px;
+    }
+    .chromeframe {
+      margin: 0.2em 0;
+      background: #ccc;
+      color: #000;
+      padding: 0.2em 0;
+    }
+
+    #loader-wrapper {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 999999;
+    }
+
+    #loader {
+      display: block;
+      position: relative;
+      left: 50%;
+      top: 50%;
+      width: 150px;
+      height: 150px;
+      margin: -75px 0 0 -75px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 2s linear infinite;
+      -ms-animation: spin 2s linear infinite;
+      -moz-animation: spin 2s linear infinite;
+      -o-animation: spin 2s linear infinite;
+      animation: spin 2s linear infinite;
+      z-index: 1001;
+    }
+
+    #loader:before {
+      content: "";
+      position: absolute;
+      top: 5px;
+      left: 5px;
+      right: 5px;
+      bottom: 5px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 3s linear infinite;
+      -moz-animation: spin 3s linear infinite;
+      -o-animation: spin 3s linear infinite;
+      -ms-animation: spin 3s linear infinite;
+      animation: spin 3s linear infinite;
+    }
+
+    #loader:after {
+      content: "";
+      position: absolute;
+      top: 15px;
+      left: 15px;
+      right: 15px;
+      bottom: 15px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -moz-animation: spin 1.5s linear infinite;
+      -o-animation: spin 1.5s linear infinite;
+      -ms-animation: spin 1.5s linear infinite;
+      -webkit-animation: spin 1.5s linear infinite;
+      animation: spin 1.5s linear infinite;
+    }
+
+
+    @-webkit-keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+    @keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+
+    #loader-wrapper .loader-section {
+      position: fixed;
+      top: 0;
+      width: 51%;
+      height: 100%;
+      background: #7171C6;
+      z-index: 1000;
+      -webkit-transform: translateX(0);
+      -ms-transform: translateX(0);
+      transform: translateX(0);
+    }
+
+    #loader-wrapper .loader-section.section-left {
+      left: 0;
+    }
+
+    #loader-wrapper .loader-section.section-right {
+      right: 0;
+    }
+
+
+    .loaded #loader-wrapper .loader-section.section-left {
+      -webkit-transform: translateX(-100%);
+      -ms-transform: translateX(-100%);
+      transform: translateX(-100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader-wrapper .loader-section.section-right {
+      -webkit-transform: translateX(100%);
+      -ms-transform: translateX(100%);
+      transform: translateX(100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader {
+      opacity: 0;
+      -webkit-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+    }
+
+    .loaded #loader-wrapper {
+      visibility: hidden;
+      -webkit-transform: translateY(-100%);
+      -ms-transform: translateY(-100%);
+      transform: translateY(-100%);
+      -webkit-transition: all 0.3s 1s ease-out;
+      transition: all 0.3s 1s ease-out;
+    }
+
+    .no-js #loader-wrapper {
+      display: none;
+    }
+
+    .no-js h1 {
+      color: #222222;
+    }
+
+    #loader-wrapper .load_title {
+      font-family: 'Open Sans';
+      color: #FFF;
+      font-size: 19px;
+      width: 100%;
+      text-align: center;
+      z-index: 9999999999999;
+      position: absolute;
+      top: 60%;
+      opacity: 1;
+      line-height: 30px;
+    }
+
+    #loader-wrapper .load_title span {
+      font-weight: normal;
+      font-style: italic;
+      font-size: 13px;
+      color: #FFF;
+      opacity: 0.5;
+    }
+  </style>
+  </head>
+  <body>
+    <div id="app">
+	    <div id="loader-wrapper">
+		    <div id="loader"></div>
+		    <div class="loader-section section-left"></div>
+		    <div class="loader-section section-right"></div>
+		    <div class="load_title">正在加载系统资源,请耐心等待</div>
+        </div>
+	</div>
+  </body>
+</html>

+ 1 - 1
ruoyi-ui/public/robots.txt

@@ -1,2 +1,2 @@
-User-agent: *
+User-agent: *
 Disallow: /

+ 20 - 20
ruoyi-ui/src/App.vue

@@ -1,20 +1,20 @@
-<template>
-  <div id="app">
-    <router-view />
-  </div>
-</template>
-
-<script>
-export default  {
-  name:  'App',
-}
-</script>
-<style>
-	.el-table--medium th{
-    height: 35px !important;
-		padding: 2px 0 !important;
-	}
-  .el-table--medium td{
-  	padding: 2px 0 !important;
-  }
-</style>
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default  {
+  name:  'App',
+}
+</script>
+<style>
+	.el-table--medium th{
+    height: 35px !important;
+		padding: 2px 0 !important;
+	}
+  .el-table--medium td{
+  	padding: 2px 0 !important;
+  }
+</style>

+ 41 - 41
ruoyi-ui/src/api/login.js

@@ -1,42 +1,42 @@
-import request from '@/utils/request'
-
-// 登录方法
-export function login(username, password, code, uuid) {
-  return request({
-    url: '/auth/login',
-    method: 'post',
-    data: { username, password, code, uuid }
-  })
-}
-
-// 刷新方法
-export function refreshToken() {
-  return request({
-    url: '/auth/refresh',
-    method: 'post'
-  })
-}
-
-// 获取用户详细信息
-export function getInfo() {
-  return request({
-    url: '/system/user/getInfo',
-    method: 'get'
-  })
-}
-
-// 退出方法
-export function logout() {
-  return request({
-    url: '/auth/logout',
-    method: 'delete'
-  })
-}
-
-// 获取验证码
-export function getCodeImg() {
-  return request({
-    url: '/code',
-    method: 'get'
-  })
+import request from '@/utils/request'
+
+// 登录方法
+export function login(username, password, code, uuid) {
+  return request({
+    url: '/auth/login',
+    method: 'post',
+    data: { username, password, code, uuid }
+  })
+}
+
+// 刷新方法
+export function refreshToken() {
+  return request({
+    url: '/auth/refresh',
+    method: 'post'
+  })
+}
+
+// 获取用户详细信息
+export function getInfo() {
+  return request({
+    url: '/system/user/getInfo',
+    method: 'get'
+  })
+}
+
+// 退出方法
+export function logout() {
+  return request({
+    url: '/auth/logout',
+    method: 'delete'
+  })
+}
+
+// 获取验证码
+export function getCodeImg() {
+  return request({
+    url: '/code',
+    method: 'get'
+  })
 }

+ 8 - 8
ruoyi-ui/src/api/menu.js

@@ -1,9 +1,9 @@
-import request from '@/utils/request'
-
-// 获取路由
-export const getRouters = () => {
-  return request({
-    url: '/system/menu/getRouters',
-    method: 'get'
-  })
+import request from '@/utils/request'
+
+// 获取路由
+export const getRouters = () => {
+  return request({
+    url: '/system/menu/getRouters',
+    method: 'get'
+  })
 }

+ 70 - 70
ruoyi-ui/src/api/monitor/job.js

@@ -1,71 +1,71 @@
-import request from '@/utils/request'
-
-// 查询定时任务调度列表
-export function listJob(query) {
-  return request({
-    url: '/schedule/job/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询定时任务调度详细
-export function getJob(jobId) {
-  return request({
-    url: '/schedule/job/' + jobId,
-    method: 'get'
-  })
-}
-
-// 新增定时任务调度
-export function addJob(data) {
-  return request({
-    url: '/schedule/job',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改定时任务调度
-export function updateJob(data) {
-  return request({
-    url: '/schedule/job',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除定时任务调度
-export function delJob(jobId) {
-  return request({
-    url: '/schedule/job/' + jobId,
-    method: 'delete'
-  })
-}
-
-// 任务状态修改
-export function changeJobStatus(jobId, status) {
-  const data = {
-    jobId,
-    status
-  }
-  return request({
-    url: '/schedule/job/changeStatus',
-    method: 'put',
-    data: data
-  })
-}
-
-
-// 定时任务立即执行一次
-export function runJob(jobId, jobGroup) {
-  const data = {
-    jobId,
-    jobGroup
-  }
-  return request({
-    url: '/schedule/job/run',
-    method: 'put',
-    data: data
-  })
+import request from '@/utils/request'
+
+// 查询定时任务调度列表
+export function listJob(query) {
+  return request({
+    url: '/schedule/job/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询定时任务调度详细
+export function getJob(jobId) {
+  return request({
+    url: '/schedule/job/' + jobId,
+    method: 'get'
+  })
+}
+
+// 新增定时任务调度
+export function addJob(data) {
+  return request({
+    url: '/schedule/job',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改定时任务调度
+export function updateJob(data) {
+  return request({
+    url: '/schedule/job',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除定时任务调度
+export function delJob(jobId) {
+  return request({
+    url: '/schedule/job/' + jobId,
+    method: 'delete'
+  })
+}
+
+// 任务状态修改
+export function changeJobStatus(jobId, status) {
+  const data = {
+    jobId,
+    status
+  }
+  return request({
+    url: '/schedule/job/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+
+// 定时任务立即执行一次
+export function runJob(jobId, jobGroup) {
+  const data = {
+    jobId,
+    jobGroup
+  }
+  return request({
+    url: '/schedule/job/run',
+    method: 'put',
+    data: data
+  })
 }

+ 26 - 26
ruoyi-ui/src/api/monitor/jobLog.js

@@ -1,26 +1,26 @@
-import request from '@/utils/request'
-
-// 查询调度日志列表
-export function listJobLog(query) {
-  return request({
-    url: '/schedule/job/log/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 删除调度日志
-export function delJobLog(jobLogId) {
-  return request({
-    url: '/schedule/job/log/' + jobLogId,
-    method: 'delete'
-  })
-}
-
-// 清空调度日志
-export function cleanJobLog() {
-  return request({
-    url: '/schedule/job/log/clean',
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询调度日志列表
+export function listJobLog(query) {
+  return request({
+    url: '/schedule/job/log/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 删除调度日志
+export function delJobLog(jobLogId) {
+  return request({
+    url: '/schedule/job/log/' + jobLogId,
+    method: 'delete'
+  })
+}
+
+// 清空调度日志
+export function cleanJobLog() {
+  return request({
+    url: '/schedule/job/log/clean',
+    method: 'delete'
+  })
+}

+ 18 - 18
ruoyi-ui/src/api/monitor/online.js

@@ -1,18 +1,18 @@
-import request from '@/utils/request'
-
-// 查询在线用户列表
-export function list(query) {
-  return request({
-    url: '/system/online/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 强退用户
-export function forceLogout(tokenId) {
-  return request({
-    url: '/system/online/' + tokenId,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询在线用户列表
+export function list(query) {
+  return request({
+    url: '/system/online/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 强退用户
+export function forceLogout(tokenId) {
+  return request({
+    url: '/system/online/' + tokenId,
+    method: 'delete'
+  })
+}

+ 110 - 110
ruoyi-ui/src/api/system/config.js

@@ -1,126 +1,126 @@
-import request from '@/utils/request'
-
-// 查询参数列表
-export function listConfig(query) {
-  return request({
-    url: '/system/config/list',
-    method: 'get',
-    params: query
-  })
-}
-
-export function listIndextwo(query) {
-  return request({
-    url: '/system/dict/data/type/' + query,
-    method: 'get'
-    // params: query
-  })
-}
-export function listIndextherr(query) {
-  return request({
-    url: '/system/dict/data/type/' + query,
-    method: 'get'
-    // params: query listIndextherr
-  })
+import request from '@/utils/request'
+
+// 查询参数列表
+export function listConfig(query) {
+  return request({
+    url: '/system/config/list',
+    method: 'get',
+    params: query
+  })
 }
 
-// 查询参数详细
-export function getConfig(id) {
-  return request({
-    url: '/system/config/' + id,
-    method: 'get'
-  })
+export function listIndextwo(query) {
+  return request({
+    url: '/system/dict/data/type/' + query,
+    method: 'get'
+    // params: query
+  })
 }
-
-// 根据参数键名查询参数值
-export function getConfigKey(configKey) {
-  return request({
-    url: '/system/config/configKey/' + configKey,
-    method: 'get'
-  })
+export function listIndextherr(query) {
+  return request({
+    url: '/system/dict/data/type/' + query,
+    method: 'get'
+    // params: query listIndextherr
+  })
+}
+
+// 查询参数详细
+export function getConfig(id) {
+  return request({
+    url: '/system/config/' + id,
+    method: 'get'
+  })
+}
+
+// 根据参数键名查询参数值
+export function getConfigKey(configKey) {
+  return request({
+    url: '/system/config/configKey/' + configKey,
+    method: 'get'
+  })
+}
+
+// 新增参数配置
+export function addConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'post',
+    data: data
+  })
 }
-
-// 新增参数配置
-export function addConfig(data) {
-  return request({
-    url: '/system/config',
-    method: 'post',
-    data: data
-  })
-}
-export function addConfigindex(data) {
-  return request({
-    url: '/boman-web-core/p/cs/objectSave',
-    method: 'post',
-    data: data
-  })
+export function addConfigindex(data) {
+  return request({
+    url: '/boman-web-core/p/cs/objectSave',
+    method: 'post',
+    data: data
+  })
 }
-
-export function listIndex(data) {
-  return request({
-    url: '/boman-web-core/p/cs/queryList',
-    method: 'post',
-    data: data
-  })
+
+export function listIndex(data) {
+  return request({
+    url: '/boman-web-core/p/cs/queryList',
+    method: 'post',
+    data: data
+  })
 }
-export function listIndexfou(data) {
-  return request({
-    url: '/boman-web-core/p/cs/queryList',
-    method: 'post',
-    data: data
-  })
+export function listIndexfou(data) {
+  return request({
+    url: '/boman-web-core/p/cs/queryList',
+    method: 'post',
+    data: data
+  })
 }
-// export function listIndextanl(data) {
-//   return request({
-//     url: '/boman-web-core/p/cs/table/getByTableName',
-//     method: 'post',
-//     data: data
-//   })
+// export function listIndextanl(data) {
+//   return request({
+//     url: '/boman-web-core/p/cs/table/getByTableName',
+//     method: 'post',
+//     data: data
+//   })
 // }
 
-export function listIndextanl(data) {
-  return request({
-    url: '/boman-web-core/p/cs/getObject',
-    method: 'post',
-    data: data
-  })
-}
-// 修改参数配置
-export function updateConfig(data) {
-  return request({
-    url: '/system/config',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除参数配置
-export function delConfig(id) {
-  return request({
-    url: '/system/config/' + id,
-    method: 'delete'
-  })
+export function listIndextanl(data) {
+  return request({
+    url: '/boman-web-core/p/cs/getObject',
+    method: 'post',
+    data: data
+  })
+}
+// 修改参数配置
+export function updateConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除参数配置
+export function delConfig(id) {
+  return request({
+    url: '/system/config/' + id,
+    method: 'delete'
+  })
 }
 
-export function delIndexnabd(data) {
+export function delIndexnabd(data) {
   return request({
     url: 'boman-web-core/p/cs/objectDelete',
     method: 'POST',
     data
-  })
-}
-
-// 清理参数缓存
-export function clearCache() {
-  return request({
-    url: '/system/config/clearCache',
-    method: 'delete'
-  })
-}
-// 查询用户个人信息
-export function getUserProfile() {
-  return request({
-    url: '/system/user/profile',
-    method: 'get'
-  })
+  })
+}
+
+// 清理参数缓存
+export function clearCache() {
+  return request({
+    url: '/system/config/clearCache',
+    method: 'delete'
+  })
 }
+// 查询用户个人信息
+export function getUserProfile() {
+  return request({
+    url: '/system/user/profile',
+    method: 'get'
+  })
+}

+ 68 - 68
ruoyi-ui/src/api/system/dept.js

@@ -1,68 +1,68 @@
-import request from '@/utils/request'
-
-// 查询部门列表
-export function listDept(query) {
-  return request({
-    url: '/system/dept/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询部门列表(排除节点)
-export function listDeptExcludeChild(id) {
-  return request({
-    url: '/system/dept/list/exclude/' + id,
-    method: 'get'
-  })
-}
-
-// 查询部门详细
-export function getDept(id) {
-  return request({
-    url: '/system/dept/' + id,
-    method: 'get'
-  })
-}
-
-// 查询部门下拉树结构
-export function treeselect() {
-  return request({
-    url: '/system/dept/treeselect',
-    method: 'get'
-  })
-}
-
-// 根据角色ID查询部门树结构
-export function roleDeptTreeselect(roleId) {
-  return request({
-    url: '/system/dept/roleDeptTreeselect/' + roleId,
-    method: 'get'
-  })
-}
-
-// 新增部门
-export function addDept(data) {
-  return request({
-    url: '/system/dept',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改部门
-export function updateDept(data) {
-  return request({
-    url: '/system/dept',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除部门
-export function delDept(id) {
-  return request({
-    url: '/system/dept/' + id,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询部门列表
+export function listDept(query) {
+  return request({
+    url: '/system/dept/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询部门列表(排除节点)
+export function listDeptExcludeChild(id) {
+  return request({
+    url: '/system/dept/list/exclude/' + id,
+    method: 'get'
+  })
+}
+
+// 查询部门详细
+export function getDept(id) {
+  return request({
+    url: '/system/dept/' + id,
+    method: 'get'
+  })
+}
+
+// 查询部门下拉树结构
+export function treeselect() {
+  return request({
+    url: '/system/dept/treeselect',
+    method: 'get'
+  })
+}
+
+// 根据角色ID查询部门树结构
+export function roleDeptTreeselect(roleId) {
+  return request({
+    url: '/system/dept/roleDeptTreeselect/' + roleId,
+    method: 'get'
+  })
+}
+
+// 新增部门
+export function addDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改部门
+export function updateDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除部门
+export function delDept(id) {
+  return request({
+    url: '/system/dept/' + id,
+    method: 'delete'
+  })
+}

+ 52 - 52
ruoyi-ui/src/api/system/dict/data.js

@@ -1,52 +1,52 @@
-import request from '@/utils/request'
-
-// 查询字典数据列表
-export function listData(query) {
-  return request({
-    url: '/system/dict/data/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询字典数据详细
-export function getData(dictCode) {
-  return request({
-    url: '/system/dict/data/' + dictCode,
-    method: 'get'
-  })
-}
-
-// 根据字典类型查询字典数据信息
-export function getDicts(dictType) {
-  return request({
-    url: '/system/dict/data/type/' + dictType,
-    method: 'get'
-  })
-}
-
-// 新增字典数据
-export function addData(data) {
-  return request({
-    url: '/system/dict/data',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改字典数据
-export function updateData(data) {
-  return request({
-    url: '/system/dict/data',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除字典数据
-export function delData(dictCode) {
-  return request({
-    url: '/system/dict/data/' + dictCode,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询字典数据列表
+export function listData(query) {
+  return request({
+    url: '/system/dict/data/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询字典数据详细
+export function getData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'get'
+  })
+}
+
+// 根据字典类型查询字典数据信息
+export function getDicts(dictType) {
+  return request({
+    url: '/system/dict/data/type/' + dictType,
+    method: 'get'
+  })
+}
+
+// 新增字典数据
+export function addData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改字典数据
+export function updateData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除字典数据
+export function delData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'delete'
+  })
+}

+ 60 - 60
ruoyi-ui/src/api/system/dict/type.js

@@ -1,60 +1,60 @@
-import request from '@/utils/request'
-
-// 查询字典类型列表
-export function listType(query) {
-  return request({
-    url: '/system/dict/type/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询字典类型详细
-export function getType(id) {
-  return request({
-    url: '/system/dict/type/' + id,
-    method: 'get'
-  })
-}
-
-// 新增字典类型
-export function addType(data) {
-  return request({
-    url: '/system/dict/type',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改字典类型
-export function updateType(data) {
-  return request({
-    url: '/system/dict/type',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除字典类型
-export function delType(id) {
-  return request({
-    url: '/system/dict/type/' + id,
-    method: 'delete'
-  })
-}
-
-// 清理参数缓存
-export function clearCache() {
-  return request({
-    url: '/system/dict/type/clearCache',
-    method: 'delete'
-  })
-}
-
-// 获取字典选择框列表
-export function optionselect() {
-  return request({
-    url: '/system/dict/type/optionselect',
-    method: 'get'
-  })
-}
+import request from '@/utils/request'
+
+// 查询字典类型列表
+export function listType(query) {
+  return request({
+    url: '/system/dict/type/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询字典类型详细
+export function getType(id) {
+  return request({
+    url: '/system/dict/type/' + id,
+    method: 'get'
+  })
+}
+
+// 新增字典类型
+export function addType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改字典类型
+export function updateType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除字典类型
+export function delType(id) {
+  return request({
+    url: '/system/dict/type/' + id,
+    method: 'delete'
+  })
+}
+
+// 清理参数缓存
+export function clearCache() {
+  return request({
+    url: '/system/dict/type/clearCache',
+    method: 'delete'
+  })
+}
+
+// 获取字典选择框列表
+export function optionselect() {
+  return request({
+    url: '/system/dict/type/optionselect',
+    method: 'get'
+  })
+}

+ 48 - 48
ruoyi-ui/src/api/system/editing.js

@@ -1,60 +1,60 @@
-import request from '@/utils/request'
-
-// 获取表单数据
-export function getQueryList(data) {
-  return request({
-    url: '/boman-web-core/p/cs/table/getByTableName',
-    method: 'POST',
-    data
-  })
+import request from '@/utils/request'
+
+// 获取表单数据
+export function getQueryList(data) {
+  return request({
+    url: '/boman-web-core/p/cs/table/getByTableName',
+    method: 'POST',
+    data
+  })
 }
-// 获取表单查询字段、按钮、表头
-export function getTableQuery(data) {
-  return request({
-    url: '/boman-web-core/p/cs/getTableQuery',
-    method: 'POST',
-    data
-  })
+// 获取表单查询字段、按钮、表头
+export function getTableQuery(data) {
+  return request({
+    url: '/boman-web-core/p/cs/getTableQuery',
+    method: 'POST',
+    data
+  })
 }
 
-// 保存
-export function addbjectSave(data) {
-  return request({
-    url: '/boman-web-core/p/cs/objectSave',
-    method: 'POST',
-    data
-  })
+// 保存
+export function addbjectSave(data) {
+  return request({
+    url: '/boman-web-core/p/cs/objectSave',
+    method: 'POST',
+    data
+  })
 }
-// 获取表单列表数据
-export function getObject(data) {
-  return request({
-    url: '/boman-web-core/p/cs/getObject',
-    method: 'POST',
-    data
-  })
+// 获取表单列表数据
+export function getObject(data) {
+  return request({
+    url: '/boman-web-core/p/cs/getObject',
+    method: 'POST',
+    data
+  })
 }
-// 根据表名获取表单信息
-export function getByTableName(data) {
-  return request({
-    url: '/boman-web-core/p/cs/table/getByTableName',
-    method: 'POST',
-    data
-  })
+// 根据表名获取表单信息
+export function getByTableName(data) {
+  return request({
+    url: '/boman-web-core/p/cs/table/getByTableName',
+    method: 'POST',
+    data
+  })
 }
-export function delMenu(id) {
-  return request({
-    url: 'boman-web-core/p/cs/objectDelete',
-    method: 'delete'
-  })
+export function delMenu(id) {
+  return request({
+    url: 'boman-web-core/p/cs/objectDelete',
+    method: 'delete'
+  })
 }
 
 // 提交
-export function tableSubimt(data) {
-  return request({
-    url: '/boman-web-core/p/cs/objectSubmit',
-    method: 'POST',
-    data
-  })
+export function tableSubimt(data) {
+  return request({
+    url: '/boman-web-core/p/cs/objectSubmit',
+    method: 'POST',
+    data
+  })
 }
  // 反提交
  export function tableSubimtanit(data) {

+ 26 - 26
ruoyi-ui/src/api/system/logininfor.js

@@ -1,26 +1,26 @@
-import request from '@/utils/request'
-
-// 查询登录日志列表
-export function list(query) {
-  return request({
-    url: '/system/logininfor/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 删除登录日志
-export function delLogininfor(id) {
-  return request({
-    url: '/system/logininfor/' + id,
-    method: 'delete'
-  })
-}
-
-// 清空登录日志
-export function cleanLogininfor() {
-  return request({
-    url: '/system/logininfor/clean',
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询登录日志列表
+export function list(query) {
+  return request({
+    url: '/system/logininfor/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 删除登录日志
+export function delLogininfor(id) {
+  return request({
+    url: '/system/logininfor/' + id,
+    method: 'delete'
+  })
+}
+
+// 清空登录日志
+export function cleanLogininfor() {
+  return request({
+    url: '/system/logininfor/clean',
+    method: 'delete'
+  })
+}

+ 60 - 60
ruoyi-ui/src/api/system/menu.js

@@ -1,60 +1,60 @@
-import request from '@/utils/request'
-
-// 查询菜单列表
-export function listMenu(query) {
-  return request({
-    url: '/system/menu/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询菜单详细
-export function getMenu(id) {
-  return request({
-    url: '/system/menu/' + id,
-    method: 'get'
-  })
-}
-
-// 查询菜单下拉树结构
-export function treeselect() {
-  return request({
-    url: '/system/menu/treeselect',
-    method: 'get'
-  })
-}
-
-// 根据角色ID查询菜单下拉树结构
-export function roleMenuTreeselect(roleId) {
-  return request({
-    url: '/system/menu/roleMenuTreeselect/' + roleId,
-    method: 'get'
-  })
-}
-
-// 新增菜单
-export function addMenu(data) {
-  return request({
-    url: '/system/menu',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改菜单
-export function updateMenu(data) {
-  return request({
-    url: '/system/menu',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除菜单
-export function delMenu(id) {
-  return request({
-    url: '/system/menu/' + id,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询菜单列表
+export function listMenu(query) {
+  return request({
+    url: '/system/menu/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询菜单详细
+export function getMenu(id) {
+  return request({
+    url: '/system/menu/' + id,
+    method: 'get'
+  })
+}
+
+// 查询菜单下拉树结构
+export function treeselect() {
+  return request({
+    url: '/system/menu/treeselect',
+    method: 'get'
+  })
+}
+
+// 根据角色ID查询菜单下拉树结构
+export function roleMenuTreeselect(roleId) {
+  return request({
+    url: '/system/menu/roleMenuTreeselect/' + roleId,
+    method: 'get'
+  })
+}
+
+// 新增菜单
+export function addMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改菜单
+export function updateMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除菜单
+export function delMenu(id) {
+  return request({
+    url: '/system/menu/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 44
ruoyi-ui/src/api/system/notice.js

@@ -1,44 +1,44 @@
-import request from '@/utils/request'
-
-// 查询公告列表
-export function listNotice(query) {
-  return request({
-    url: '/system/notice/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询公告详细
-export function getNotice(id) {
-  return request({
-    url: '/system/notice/' + id,
-    method: 'get'
-  })
-}
-
-// 新增公告
-export function addNotice(data) {
-  return request({
-    url: '/system/notice',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改公告
-export function updateNotice(data) {
-  return request({
-    url: '/system/notice',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除公告
-export function delNotice(id) {
-  return request({
-    url: '/system/notice/' + id,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询公告列表
+export function listNotice(query) {
+  return request({
+    url: '/system/notice/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询公告详细
+export function getNotice(id) {
+  return request({
+    url: '/system/notice/' + id,
+    method: 'get'
+  })
+}
+
+// 新增公告
+export function addNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改公告
+export function updateNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除公告
+export function delNotice(id) {
+  return request({
+    url: '/system/notice/' + id,
+    method: 'delete'
+  })
+}

+ 26 - 26
ruoyi-ui/src/api/system/operlog.js

@@ -1,26 +1,26 @@
-import request from '@/utils/request'
-
-// 查询操作日志列表
-export function list(query) {
-  return request({
-    url: '/system/operlog/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 删除操作日志
-export function delOperlog(id) {
-  return request({
-    url: '/system/operlog/' + id,
-    method: 'delete'
-  })
-}
-
-// 清空操作日志
-export function cleanOperlog() {
-  return request({
-    url: '/system/operlog/clean',
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询操作日志列表
+export function list(query) {
+  return request({
+    url: '/system/operlog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 删除操作日志
+export function delOperlog(id) {
+  return request({
+    url: '/system/operlog/' + id,
+    method: 'delete'
+  })
+}
+
+// 清空操作日志
+export function cleanOperlog() {
+  return request({
+    url: '/system/operlog/clean',
+    method: 'delete'
+  })
+}

+ 44 - 44
ruoyi-ui/src/api/system/post.js

@@ -1,44 +1,44 @@
-import request from '@/utils/request'
-
-// 查询岗位列表
-export function listPost(query) {
-  return request({
-    url: '/system/post/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询岗位详细
-export function getPost(id) {
-  return request({
-    url: '/system/post/' + id,
-    method: 'get'
-  })
-}
-
-// 新增岗位
-export function addPost(data) {
-  return request({
-    url: '/system/post',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改岗位
-export function updatePost(data) {
-  return request({
-    url: '/system/post',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除岗位
-export function delPost(id) {
-  return request({
-    url: '/system/post/' + id,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询岗位列表
+export function listPost(query) {
+  return request({
+    url: '/system/post/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询岗位详细
+export function getPost(id) {
+  return request({
+    url: '/system/post/' + id,
+    method: 'get'
+  })
+}
+
+// 新增岗位
+export function addPost(data) {
+  return request({
+    url: '/system/post',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改岗位
+export function updatePost(data) {
+  return request({
+    url: '/system/post',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除岗位
+export function delPost(id) {
+  return request({
+    url: '/system/post/' + id,
+    method: 'delete'
+  })
+}

+ 66 - 66
ruoyi-ui/src/api/system/role.js

@@ -1,66 +1,66 @@
-import request from '@/utils/request'
-
-// 查询角色列表
-export function listRole(query) {
-  return request({
-    url: '/system/role/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询角色详细
-export function getRole(id) {
-  return request({
-    url: '/system/role/' + id,
-    method: 'get'
-  })
-}
-
-// 新增角色
-export function addRole(data) {
-  return request({
-    url: '/system/role',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改角色
-export function updateRole(data) {
-  return request({
-    url: '/system/role',
-    method: 'put',
-    data: data
-  })
-}
-
-// 角色数据权限
-export function dataScope(data) {
-  return request({
-    url: '/system/role/dataScope',
-    method: 'put',
-    data: data
-  })
-}
-
-// 角色状态修改
-export function changeRoleStatus(id, status) {
-  const data = {
-    id,
-    status
-  }
-  return request({
-    url: '/system/role/changeStatus',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除角色
-export function delRole(id) {
-  return request({
-    url: '/system/role/' + id,
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询角色列表
+export function listRole(query) {
+  return request({
+    url: '/system/role/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询角色详细
+export function getRole(id) {
+  return request({
+    url: '/system/role/' + id,
+    method: 'get'
+  })
+}
+
+// 新增角色
+export function addRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改角色
+export function updateRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'put',
+    data: data
+  })
+}
+
+// 角色数据权限
+export function dataScope(data) {
+  return request({
+    url: '/system/role/dataScope',
+    method: 'put',
+    data: data
+  })
+}
+
+// 角色状态修改
+export function changeRoleStatus(id, status) {
+  const data = {
+    id,
+    status
+  }
+  return request({
+    url: '/system/role/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除角色
+export function delRole(id) {
+  return request({
+    url: '/system/role/' + id,
+    method: 'delete'
+  })
+}

+ 110 - 110
ruoyi-ui/src/api/system/user.js

@@ -1,110 +1,110 @@
-import request from '@/utils/request'
-import { praseStrEmpty } from "@/utils/ruoyi";
-
-// 查询用户列表
-export function listUser(query) {
-  return request({
-    url: '/system/user/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询用户详细
-export function getUser(id) {
-  return request({
-    url: '/system/user/' + praseStrEmpty(id),
-    method: 'get'
-  })
-}
-
-// 新增用户
-export function addUser(data) {
-  return request({
-    url: '/system/user',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改用户
-export function updateUser(data) {
-  return request({
-    url: '/system/user',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除用户
-export function delUser(id) {
-  return request({
-    url: '/system/user/' + id,
-    method: 'delete'
-  })
-}
-
-// 用户密码重置
-export function resetUserPwd(id, password) {
-  const data = {
-    id,
-    password
-  }
-  return request({
-    url: '/system/user/resetPwd',
-    method: 'put',
-    data: data
-  })
-}
-
-// 用户状态修改
-export function changeUserStatus(id, status) {
-  const data = {
-    id,
-    status
-  }
-  return request({
-    url: '/system/user/changeStatus',
-    method: 'put',
-    data: data
-  })
-}
-
-// 查询用户个人信息
-export function getUserProfile() {
-  return request({
-    url: '/system/user/profile',
-    method: 'get'
-  })
-}
-
-// 修改用户个人信息
-export function updateUserProfile(data) {
-  return request({
-    url: '/system/user/profile',
-    method: 'put',
-    data: data
-  })
-}
-
-// 用户密码重置
-export function updateUserPwd(oldPassword, newPassword) {
-  const data = {
-    oldPassword,
-    newPassword
-  }
-  return request({
-    url: '/system/user/profile/updatePwd',
-    method: 'put',
-    params: data
-  })
-}
-
-// 用户头像上传
-export function uploadAvatar(data) {
-  return request({
-    url: '/system/user/profile/avatar',
-    method: 'post',
-    data: data
-  })
-}
+import request from '@/utils/request'
+import { praseStrEmpty } from "@/utils/ruoyi";
+
+// 查询用户列表
+export function listUser(query) {
+  return request({
+    url: '/system/user/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户详细
+export function getUser(id) {
+  return request({
+    url: '/system/user/' + praseStrEmpty(id),
+    method: 'get'
+  })
+}
+
+// 新增用户
+export function addUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改用户
+export function updateUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除用户
+export function delUser(id) {
+  return request({
+    url: '/system/user/' + id,
+    method: 'delete'
+  })
+}
+
+// 用户密码重置
+export function resetUserPwd(id, password) {
+  const data = {
+    id,
+    password
+  }
+  return request({
+    url: '/system/user/resetPwd',
+    method: 'put',
+    data: data
+  })
+}
+
+// 用户状态修改
+export function changeUserStatus(id, status) {
+  const data = {
+    id,
+    status
+  }
+  return request({
+    url: '/system/user/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 查询用户个人信息
+export function getUserProfile() {
+  return request({
+    url: '/system/user/profile',
+    method: 'get'
+  })
+}
+
+// 修改用户个人信息
+export function updateUserProfile(data) {
+  return request({
+    url: '/system/user/profile',
+    method: 'put',
+    data: data
+  })
+}
+
+// 用户密码重置
+export function updateUserPwd(oldPassword, newPassword) {
+  const data = {
+    oldPassword,
+    newPassword
+  }
+  return request({
+    url: '/system/user/profile/updatePwd',
+    method: 'put',
+    params: data
+  })
+}
+
+// 用户头像上传
+export function uploadAvatar(data) {
+  return request({
+    url: '/system/user/profile/avatar',
+    method: 'post',
+    data: data
+  })
+}

+ 234 - 234
ruoyi-ui/src/api/tool/gen.js

@@ -1,234 +1,234 @@
-import request from '@/utils/request'
-
-// 新增关联表
-export function addGenTable(data) {
-  return request({
-    url: '/boman-gen/genTableRelation',
-    method: 'post',
-    data
-  })
-}
-// 修改关联表
-export function setGenTable(data) {
-  return request({
-    url: '/boman-gen/genTableRelation',
-    method: 'put',
-    data
-  })
-}
-// 删除关联表
-export function delGenTable(tableId) {
-  return request({
-    url: '/boman-gen/genTableRelation/' + tableId,
-    method: 'delete',
-  })
-}
-// 查看关联表
-export function qurGenTable(tableId) {
-  return request({
-    url: '/boman-gen/genTableRelation/' + tableId,
-    method: 'get',
-  })
-}
-
-// 关联表列表
-export function tabList(query) {
-  return request({
-    url: '/boman-gen/genTableRelation/list',
-    method: 'get',
-    params: query
-  })
-}
-// 查询生成表数据
-export function listTable(query) {
-  return request({
-    url: '/code/gen/list',
-    method: 'get',
-    params: query
-  })
-}
-// 查询db数据库列表
-export function listDbTable(query) {
-  return request({
-    url: '/code/gen/db/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 新增
-export function addMenu(data) {
-  return request({
-    url: '/boman-gen/gen/addTable',
-    method: 'post',
-    data: data
-  })
-}
-
-// 查询表详细信息
-export function getGenTable(tableId) {
-  return request({
-    url: '/code/gen/' + tableId,
-    method: 'get'
-  })
-}
-
-// 查询表详细信息
-export function listAllColumnsByTableId(data) {
-  return request({
-    url: '/boman-web-core/p/cs/table/listAllColumnsByTableId',
-    method: 'post',
-    data
-  })
-}
-// 查询表HR详细信息
-export function genTableColumnList(query) {
-  return request({
-    url: '/boman-gen/genTableColumn/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 修改代码生成信息
-export function updateGenTable(data) {
-  return request({
-    url: '/code/gen',
-    method: 'put',
-    data: data
-  })
-}
-
-// 导入表
-export function importTable(data) {
-  return request({
-    url: '/code/gen/importTable',
-    method: 'post',
-    params: data
-  })
-}
-
-// 预览生成代码
-export function previewTable(tableId) {
-  return request({
-    url: '/code/gen/preview/' + tableId,
-    method: 'get'
-  })
-}
-
-// 删除表数据
-export function delTable(tableId) {
-  return request({
-    url: '/code/gen/' + tableId,
-    method: 'delete'
-  })
-}
-// 删除
-export function delPost(id) {
-  return request({
-    url: '/genTableColumn/columnIds/' + id,
-    method: 'delete'
-  })
-}
-
-// 生成代码(自定义路径)
-export function genCode(tableName) {
-  return request({
-    url: '/code/gen/genCode/' + tableName,
-    method: 'get'
-  })
-}
-
-// 同步数据库
-export function synchDb(tableName) {
-  return request({
-    url: '/code/gen/synchDb/' + tableName,
-    method: 'get'
-  })
-}
-
-// 查询数据库sql
-export function tableSql(id) {
-  return request({
-    url: '/boman-gen/tableSql/'+id,
-    method: 'get',
-  })
-}
-// 执行创建语句
-export function zxImplement(data) {
-  return request({
-    url: '/boman-gen/tableSql/implement',
-    method: 'post',
-    data
-  })
-}
-// 刷新创建语句
-export function getReload(data) {
-  return request({
-    url: '/boman-gen/tableSql/reload',
-    method: 'POST',
-    data
-  })
-}
-// 新增字段信息
-export function addGenTableColumn(data) {
-  return request({
-    url: '/boman-gen/genTableColumn',
-    method: 'POST',
-    data
-  })
-}
-// 删除字段信息
-export function delGenTableColumn(id) {
-  return request({
-    url: '/boman-gen/genTableColumn/' + id,
-    method: 'delete',
-  })
-}
-// 修改字段信息
-export function setGenTableColumn(data) {
-  return request({
-    url: '/boman-gen/genTableColumn',
-    method: 'put',
-    data
-  })
-}
-// 获取字段信息
-export function getGenTableColumn(tableId) {
-  return request({
-    url: '/boman-gen/genTableColumn/getColumnInfo/' + tableId,
-    method: 'get',
-  })
-}
-// 获取字段信息
-export function getByIdWithForeignKey(tableId) {
-  return request({
-    url: '/boman-gen/genTableColumn/getByIdWithForeignKey/' + tableId,
-    method: 'get',
-  })
-}
-// 获取字段信息
-export function getLoadTable() {
-  return request({
-    url: 'boman-gen/init/loadTable',
-    method: 'get',
-  })
-}
-
-// 获取快速查询  查询框数据/ */
-export function tableQuery(data) {
-  return request({
-    url: '/boman-web-core/p/cs/getTableQuery',
-    method: 'POST',
-    data
-  })
-}
-
-// 快速查询列表
-export function listIndexfou(data) {
-  return request({
-    url: '/boman-web-core/p/cs/queryList',
-    method: 'post',
-    data: data
-  })
-}
+import request from '@/utils/request'
+
+// 新增关联表
+export function addGenTable(data) {
+  return request({
+    url: '/boman-gen/genTableRelation',
+    method: 'post',
+    data
+  })
+}
+// 修改关联表
+export function setGenTable(data) {
+  return request({
+    url: '/boman-gen/genTableRelation',
+    method: 'put',
+    data
+  })
+}
+// 删除关联表
+export function delGenTable(tableId) {
+  return request({
+    url: '/boman-gen/genTableRelation/' + tableId,
+    method: 'delete',
+  })
+}
+// 查看关联表
+export function qurGenTable(tableId) {
+  return request({
+    url: '/boman-gen/genTableRelation/' + tableId,
+    method: 'get',
+  })
+}
+
+// 关联表列表
+export function tabList(query) {
+  return request({
+    url: '/boman-gen/genTableRelation/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询生成表数据
+export function listTable(query) {
+  return request({
+    url: '/code/gen/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询db数据库列表
+export function listDbTable(query) {
+  return request({
+    url: '/code/gen/db/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 新增
+export function addMenu(data) {
+  return request({
+    url: '/boman-gen/gen/addTable',
+    method: 'post',
+    data: data
+  })
+}
+
+// 查询表详细信息
+export function getGenTable(tableId) {
+  return request({
+    url: '/code/gen/' + tableId,
+    method: 'get'
+  })
+}
+
+// 查询表详细信息
+export function listAllColumnsByTableId(data) {
+  return request({
+    url: '/boman-web-core/p/cs/table/listAllColumnsByTableId',
+    method: 'post',
+    data
+  })
+}
+// 查询表HR详细信息
+export function genTableColumnList(query) {
+  return request({
+    url: '/boman-gen/genTableColumn/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 修改代码生成信息
+export function updateGenTable(data) {
+  return request({
+    url: '/code/gen',
+    method: 'put',
+    data: data
+  })
+}
+
+// 导入表
+export function importTable(data) {
+  return request({
+    url: '/code/gen/importTable',
+    method: 'post',
+    params: data
+  })
+}
+
+// 预览生成代码
+export function previewTable(tableId) {
+  return request({
+    url: '/code/gen/preview/' + tableId,
+    method: 'get'
+  })
+}
+
+// 删除表数据
+export function delTable(tableId) {
+  return request({
+    url: '/code/gen/' + tableId,
+    method: 'delete'
+  })
+}
+// 删除
+export function delPost(id) {
+  return request({
+    url: '/genTableColumn/columnIds/' + id,
+    method: 'delete'
+  })
+}
+
+// 生成代码(自定义路径)
+export function genCode(tableName) {
+  return request({
+    url: '/code/gen/genCode/' + tableName,
+    method: 'get'
+  })
+}
+
+// 同步数据库
+export function synchDb(tableName) {
+  return request({
+    url: '/code/gen/synchDb/' + tableName,
+    method: 'get'
+  })
+}
+
+// 查询数据库sql
+export function tableSql(id) {
+  return request({
+    url: '/boman-gen/tableSql/'+id,
+    method: 'get',
+  })
+}
+// 执行创建语句
+export function zxImplement(data) {
+  return request({
+    url: '/boman-gen/tableSql/implement',
+    method: 'post',
+    data
+  })
+}
+// 刷新创建语句
+export function getReload(data) {
+  return request({
+    url: '/boman-gen/tableSql/reload',
+    method: 'POST',
+    data
+  })
+}
+// 新增字段信息
+export function addGenTableColumn(data) {
+  return request({
+    url: '/boman-gen/genTableColumn',
+    method: 'POST',
+    data
+  })
+}
+// 删除字段信息
+export function delGenTableColumn(id) {
+  return request({
+    url: '/boman-gen/genTableColumn/' + id,
+    method: 'delete',
+  })
+}
+// 修改字段信息
+export function setGenTableColumn(data) {
+  return request({
+    url: '/boman-gen/genTableColumn',
+    method: 'put',
+    data
+  })
+}
+// 获取字段信息
+export function getGenTableColumn(tableId) {
+  return request({
+    url: '/boman-gen/genTableColumn/getColumnInfo/' + tableId,
+    method: 'get',
+  })
+}
+// 获取字段信息
+export function getByIdWithForeignKey(tableId) {
+  return request({
+    url: '/boman-gen/genTableColumn/getByIdWithForeignKey/' + tableId,
+    method: 'get',
+  })
+}
+// 获取字段信息
+export function getLoadTable() {
+  return request({
+    url: 'boman-gen/init/loadTable',
+    method: 'get',
+  })
+}
+
+// 获取快速查询  查询框数据/ */
+export function tableQuery(data) {
+  return request({
+    url: '/boman-web-core/p/cs/getTableQuery',
+    method: 'POST',
+    data
+  })
+}
+
+// 快速查询列表
+export function listIndexfou(data) {
+  return request({
+    url: '/boman-web-core/p/cs/queryList',
+    method: 'post',
+    data: data
+  })
+}

+ 9 - 9
ruoyi-ui/src/assets/icons/index.js

@@ -1,9 +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)
+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)

+ 1 - 1
ruoyi-ui/src/assets/icons/svg/monitor.svg

@@ -1,2 +1,2 @@
-<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
 </style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>

File diff suppressed because it is too large
+ 1 - 1
ruoyi-ui/src/assets/icons/svg/system.svg


+ 22 - 22
ruoyi-ui/src/assets/icons/svgo.yml

@@ -1,22 +1,22 @@
-# replace default config
-
-# multipass: true
-# full: true
-
-plugins:
-
-  # - name
-  #
-  # or:
-  # - name: false
-  # - name: true
-  #
-  # or:
-  # - name:
-  #     param1: 1
-  #     param2: 2
-
-- removeAttrs:
-    attrs:
-      - 'fill'
-      - 'fill-rule'
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+  # - name
+  #
+  # or:
+  # - name: false
+  # - name: true
+  #
+  # or:
+  # - name:
+  #     param1: 1
+  #     param2: 2
+
+- removeAttrs:
+    attrs:
+      - 'fill'
+      - 'fill-rule'

+ 38 - 38
ruoyi-ui/src/assets/images/dark.svg

@@ -1,39 +1,39 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
-    xmlns="http://www.w3.org/2000/svg" 
-    xmlns:xlink="http://www.w3.org/1999/xlink">
-    <defs>
-        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
-            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
-            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
-            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
-            <feMerge>
-                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
-                <feMergeNode in="SourceGraphic"></feMergeNode>
-            </feMerge>
-        </filter>
-        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
-        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
-            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
-            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
-            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
-        </filter>
-    </defs>
-    <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
-            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
-                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
-                    <mask id="mask-3" fill="white">
-                        <use xlink:href="#path-2"></use>
-                    </mask>
-                    <g id="Rectangle-18">
-                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
-                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
-                    </g>
-                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
-                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
-                </g>
-            </g>
-        </g>
-    </g>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
 </svg>

+ 38 - 38
ruoyi-ui/src/assets/images/light.svg

@@ -1,39 +1,39 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
-    xmlns="http://www.w3.org/2000/svg" 
-    xmlns:xlink="http://www.w3.org/1999/xlink">
-    <defs>
-        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
-            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
-            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
-            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
-            <feMerge>
-                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
-                <feMergeNode in="SourceGraphic"></feMergeNode>
-            </feMerge>
-        </filter>
-        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
-        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
-            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
-            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
-            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
-        </filter>
-    </defs>
-    <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
-            <g id="Group-8" transform="translate(1167.000000, 0.000000)">
-                <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
-                    <mask id="mask-3" fill="white">
-                        <use xlink:href="#path-2"></use>
-                    </mask>
-                    <g id="Rectangle-18">
-                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
-                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
-                    </g>
-                    <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
-                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
-                </g>
-            </g>
-        </g>
-    </g>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
+            <g id="Group-8" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
 </svg>

+ 99 - 99
ruoyi-ui/src/assets/styles/btn.scss

@@ -1,99 +1,99 @@
-@import './variables.scss';
-
-@mixin colorBtn($color) {
-  background: $color;
-
-  &:hover {
-    color: $color;
-
-    &:before,
-    &:after {
-      background: $color;
-    }
-  }
-}
-
-.blue-btn {
-  @include colorBtn($blue)
-}
-
-.light-blue-btn {
-  @include colorBtn($light-blue)
-}
-
-.red-btn {
-  @include colorBtn($red)
-}
-
-.pink-btn {
-  @include colorBtn($pink)
-}
-
-.green-btn {
-  @include colorBtn($green)
-}
-
-.tiffany-btn {
-  @include colorBtn($tiffany)
-}
-
-.yellow-btn {
-  @include colorBtn($yellow)
-}
-
-.pan-btn {
-  font-size: 14px;
-  color: #fff;
-  padding: 14px 36px;
-  border-radius: 8px;
-  border: none;
-  outline: none;
-  transition: 600ms ease all;
-  position: relative;
-  display: inline-block;
-
-  &:hover {
-    background: #fff;
-
-    &:before,
-    &:after {
-      width: 100%;
-      transition: 600ms ease all;
-    }
-  }
-
-  &:before,
-  &:after {
-    content: '';
-    position: absolute;
-    top: 0;
-    right: 0;
-    height: 2px;
-    width: 0;
-    transition: 400ms ease all;
-  }
-
-  &::after {
-    right: inherit;
-    top: inherit;
-    left: 0;
-    bottom: 0;
-  }
-}
-
-.custom-button {
-  display: inline-block;
-  line-height: 1;
-  white-space: nowrap;
-  cursor: pointer;
-  background: #fff;
-  color: #fff;
-  -webkit-appearance: none;
-  text-align: center;
-  box-sizing: border-box;
-  outline: 0;
-  margin: 0;
-  padding: 10px 15px;
-  font-size: 14px;
-  border-radius: 4px;
-}
+@import './variables.scss';
+
+@mixin colorBtn($color) {
+  background: $color;
+
+  &:hover {
+    color: $color;
+
+    &:before,
+    &:after {
+      background: $color;
+    }
+  }
+}
+
+.blue-btn {
+  @include colorBtn($blue)
+}
+
+.light-blue-btn {
+  @include colorBtn($light-blue)
+}
+
+.red-btn {
+  @include colorBtn($red)
+}
+
+.pink-btn {
+  @include colorBtn($pink)
+}
+
+.green-btn {
+  @include colorBtn($green)
+}
+
+.tiffany-btn {
+  @include colorBtn($tiffany)
+}
+
+.yellow-btn {
+  @include colorBtn($yellow)
+}
+
+.pan-btn {
+  font-size: 14px;
+  color: #fff;
+  padding: 14px 36px;
+  border-radius: 8px;
+  border: none;
+  outline: none;
+  transition: 600ms ease all;
+  position: relative;
+  display: inline-block;
+
+  &:hover {
+    background: #fff;
+
+    &:before,
+    &:after {
+      width: 100%;
+      transition: 600ms ease all;
+    }
+  }
+
+  &:before,
+  &:after {
+    content: '';
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 2px;
+    width: 0;
+    transition: 400ms ease all;
+  }
+
+  &::after {
+    right: inherit;
+    top: inherit;
+    left: 0;
+    bottom: 0;
+  }
+}
+
+.custom-button {
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  background: #fff;
+  color: #fff;
+  -webkit-appearance: none;
+  text-align: center;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  padding: 10px 15px;
+  font-size: 14px;
+  border-radius: 4px;
+}

+ 84 - 84
ruoyi-ui/src/assets/styles/element-ui.scss

@@ -1,84 +1,84 @@
-// cover some element-ui styles
-
-.el-breadcrumb__inner,
-.el-breadcrumb__inner a {
-  font-weight: 400 !important;
-}
-
-.el-upload {
-  input[type="file"] {
-    display: none !important;
-  }
-}
-
-.el-upload__input {
-  display: none;
-}
-
-.cell {
-  .el-tag {
-    margin-right: 0px;
-  }
-}
-
-.small-padding {
-  .cell {
-    padding-left: 5px;
-    padding-right: 5px;
-  }
-}
-
-.fixed-width {
-  .el-button--mini {
-    padding: 7px 10px;
-    width: 60px;
-  }
-}
-
-.status-col {
-  .cell {
-    padding: 0 10px;
-    text-align: center;
-
-    .el-tag {
-      margin-right: 0px;
-    }
-  }
-}
-
-// to fixed https://github.com/ElemeFE/element/issues/2461
-.el-dialog {
-  transform: none;
-  left: 0;
-  position: relative;
-  margin: 0 auto;
-}
-
-// refine element ui upload
-.upload-container {
-  .el-upload {
-    width: 100%;
-
-    .el-upload-dragger {
-      width: 100%;
-      height: 200px;
-    }
-  }
-}
-
-// dropdown
-.el-dropdown-menu {
-  a {
-    display: block
-  }
-}
-
-// fix date-picker ui bug in filter-item
-.el-range-editor.el-input__inner {
-  display: inline-flex !important;
-}
-
-// to fix el-date-picker css style
-.el-range-separator {
-  box-sizing: content-box;
-}
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+  font-weight: 400 !important;
+}
+
+.el-upload {
+  input[type="file"] {
+    display: none !important;
+  }
+}
+
+.el-upload__input {
+  display: none;
+}
+
+.cell {
+  .el-tag {
+    margin-right: 0px;
+  }
+}
+
+.small-padding {
+  .cell {
+    padding-left: 5px;
+    padding-right: 5px;
+  }
+}
+
+.fixed-width {
+  .el-button--mini {
+    padding: 7px 10px;
+    width: 60px;
+  }
+}
+
+.status-col {
+  .cell {
+    padding: 0 10px;
+    text-align: center;
+
+    .el-tag {
+      margin-right: 0px;
+    }
+  }
+}
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+  transform: none;
+  left: 0;
+  position: relative;
+  margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+  .el-upload {
+    width: 100%;
+
+    .el-upload-dragger {
+      width: 100%;
+      height: 200px;
+    }
+  }
+}
+
+// dropdown
+.el-dropdown-menu {
+  a {
+    display: block
+  }
+}
+
+// fix date-picker ui bug in filter-item
+.el-range-editor.el-input__inner {
+  display: inline-flex !important;
+}
+
+// to fix el-date-picker css style
+.el-range-separator {
+  box-sizing: content-box;
+}

+ 31 - 31
ruoyi-ui/src/assets/styles/element-variables.scss

@@ -1,31 +1,31 @@
-/**
-* I think element-ui's default theme color is too light for long-term use.
-* So I modified the default color and you can modify it to your liking.
-**/
-
-/* theme color */
-$--color-primary: #1890ff;
-$--color-success: #13ce66;
-$--color-warning: #ffba00;
-$--color-danger: #ff4949;
-// $--color-info: #1E1E1E;
-
-$--button-font-weight: 400;
-
-// $--color-text-regular: #1f2d3d;
-
-$--border-color-light: #dfe4ed;
-$--border-color-lighter: #e6ebf5;
-
-$--table-border:1px solid#dfe6ec;
-
-/* icon font path, required */
-$--font-path: '~element-ui/lib/theme-chalk/fonts';
-
-@import "~element-ui/packages/theme-chalk/src/index";
-
-// the :export directive is the magic sauce for webpack
-// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
-:export {
-  theme: $--color-primary;
-}
+/**
+* I think element-ui's default theme color is too light for long-term use.
+* So I modified the default color and you can modify it to your liking.
+**/
+
+/* theme color */
+$--color-primary: #1890ff;
+$--color-success: #13ce66;
+$--color-warning: #ffba00;
+$--color-danger: #ff4949;
+// $--color-info: #1E1E1E;
+
+$--button-font-weight: 400;
+
+// $--color-text-regular: #1f2d3d;
+
+$--border-color-light: #dfe4ed;
+$--border-color-lighter: #e6ebf5;
+
+$--table-border:1px solid#dfe6ec;
+
+/* icon font path, required */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+
+@import "~element-ui/packages/theme-chalk/src/index";
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  theme: $--color-primary;
+}

+ 191 - 191
ruoyi-ui/src/assets/styles/index.scss

@@ -1,191 +1,191 @@
-@import './variables.scss';
-@import './mixin.scss';
-@import './transition.scss';
-@import './element-ui.scss';
-@import './sidebar.scss';
-@import './btn.scss';
-
-body {
-  height: 100%;
-  -moz-osx-font-smoothing: grayscale;
-  -webkit-font-smoothing: antialiased;
-  text-rendering: optimizeLegibility;
-  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
-}
-
-label {
-  font-weight: 700;
-}
-
-html {
-  height: 100%;
-  box-sizing: border-box;
-}
-
-#app {
-  height: 100%;
-}
-
-*,
-*:before,
-*:after {
-  box-sizing: inherit;
-}
-
-.no-padding {
-  padding: 0px !important;
-}
-
-.padding-content {
-  padding: 4px 0;
-}
-
-a:focus,
-a:active {
-  outline: none;
-}
-
-a,
-a:focus,
-a:hover {
-  cursor: pointer;
-  color: inherit;
-  text-decoration: none;
-}
-
-div:focus {
-  outline: none;
-}
-
-.fr {
-  float: right;
-}
-
-.fl {
-  float: left;
-}
-
-.pr-5 {
-  padding-right: 5px;
-}
-
-.pl-5 {
-  padding-left: 5px;
-}
-
-.block {
-  display: block;
-}
-
-.pointer {
-  cursor: pointer;
-}
-
-.inlineBlock {
-  display: block;
-}
-
-.clearfix {
-  &:after {
-    visibility: hidden;
-    display: block;
-    font-size: 0;
-    content: " ";
-    clear: both;
-    height: 0;
-  }
-}
-
-aside {
-  background: #eef1f6;
-  padding: 8px 24px;
-  margin-bottom: 20px;
-  border-radius: 2px;
-  display: block;
-  line-height: 32px;
-  font-size: 16px;
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-  color: #2c3e50;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-  a {
-    color: #337ab7;
-    cursor: pointer;
-
-    &:hover {
-      color: rgb(32, 160, 255);
-    }
-  }
-}
-
-//main-container全局样式
-.app-container {
-  padding: 20px;
-}
-
-.components-container {
-  margin: 30px 50px;
-  position: relative;
-}
-
-.pagination-container {
-  margin-top: 30px;
-}
-
-.text-center {
-  text-align: center
-}
-
-.sub-navbar {
-  height: 50px;
-  line-height: 50px;
-  position: relative;
-  width: 100%;
-  text-align: right;
-  padding-right: 20px;
-  transition: 600ms ease position;
-  background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
-
-  .subtitle {
-    font-size: 20px;
-    color: #fff;
-  }
-
-  &.draft {
-    background: #d0d0d0;
-  }
-
-  &.deleted {
-    background: #d0d0d0;
-  }
-}
-
-.link-type,
-.link-type:focus {
-  color: #337ab7;
-  cursor: pointer;
-
-  &:hover {
-    color: rgb(32, 160, 255);
-  }
-}
-
-.filter-container {
-  padding-bottom: 10px;
-
-  .filter-item {
-    display: inline-block;
-    vertical-align: middle;
-    margin-bottom: 10px;
-  }
-}
-
-//refine vue-multiselect plugin
-.multiselect {
-  line-height: 16px;
-}
-
-.multiselect--active {
-  z-index: 1000 !important;
-}
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+@import './btn.scss';
+
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+  font-weight: 700;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+*,
+*:before,
+*:after {
+  box-sizing: inherit;
+}
+
+.no-padding {
+  padding: 0px !important;
+}
+
+.padding-content {
+  padding: 4px 0;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+.fr {
+  float: right;
+}
+
+.fl {
+  float: left;
+}
+
+.pr-5 {
+  padding-right: 5px;
+}
+
+.pl-5 {
+  padding-left: 5px;
+}
+
+.block {
+  display: block;
+}
+
+.pointer {
+  cursor: pointer;
+}
+
+.inlineBlock {
+  display: block;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+aside {
+  background: #eef1f6;
+  padding: 8px 24px;
+  margin-bottom: 20px;
+  border-radius: 2px;
+  display: block;
+  line-height: 32px;
+  font-size: 16px;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+  color: #2c3e50;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+  a {
+    color: #337ab7;
+    cursor: pointer;
+
+    &:hover {
+      color: rgb(32, 160, 255);
+    }
+  }
+}
+
+//main-container全局样式
+.app-container {
+  padding: 20px;
+}
+
+.components-container {
+  margin: 30px 50px;
+  position: relative;
+}
+
+.pagination-container {
+  margin-top: 30px;
+}
+
+.text-center {
+  text-align: center
+}
+
+.sub-navbar {
+  height: 50px;
+  line-height: 50px;
+  position: relative;
+  width: 100%;
+  text-align: right;
+  padding-right: 20px;
+  transition: 600ms ease position;
+  background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
+
+  .subtitle {
+    font-size: 20px;
+    color: #fff;
+  }
+
+  &.draft {
+    background: #d0d0d0;
+  }
+
+  &.deleted {
+    background: #d0d0d0;
+  }
+}
+
+.link-type,
+.link-type:focus {
+  color: #337ab7;
+  cursor: pointer;
+
+  &:hover {
+    color: rgb(32, 160, 255);
+  }
+}
+
+.filter-container {
+  padding-bottom: 10px;
+
+  .filter-item {
+    display: inline-block;
+    vertical-align: middle;
+    margin-bottom: 10px;
+  }
+}
+
+//refine vue-multiselect plugin
+.multiselect {
+  line-height: 16px;
+}
+
+.multiselect--active {
+  z-index: 1000 !important;
+}

+ 66 - 66
ruoyi-ui/src/assets/styles/mixin.scss

@@ -1,66 +1,66 @@
-@mixin clearfix {
-  &:after {
-    content: "";
-    display: table;
-    clear: both;
-  }
-}
-
-@mixin scrollBar {
-  &::-webkit-scrollbar-track-piece {
-    background: #d3dce6;
-  }
-
-  &::-webkit-scrollbar {
-    width: 6px;
-  }
-
-  &::-webkit-scrollbar-thumb {
-    background: #99a9bf;
-    border-radius: 20px;
-  }
-}
-
-@mixin relative {
-  position: relative;
-  width: 100%;
-  height: 100%;
-}
-
-@mixin pct($pct) {
-  width: #{$pct};
-  position: relative;
-  margin: 0 auto;
-}
-
-@mixin triangle($width, $height, $color, $direction) {
-  $width: $width/2;
-  $color-border-style: $height solid $color;
-  $transparent-border-style: $width solid transparent;
-  height: 0;
-  width: 0;
-
-  @if $direction==up {
-    border-bottom: $color-border-style;
-    border-left: $transparent-border-style;
-    border-right: $transparent-border-style;
-  }
-
-  @else if $direction==right {
-    border-left: $color-border-style;
-    border-top: $transparent-border-style;
-    border-bottom: $transparent-border-style;
-  }
-
-  @else if $direction==down {
-    border-top: $color-border-style;
-    border-left: $transparent-border-style;
-    border-right: $transparent-border-style;
-  }
-
-  @else if $direction==left {
-    border-right: $color-border-style;
-    border-top: $transparent-border-style;
-    border-bottom: $transparent-border-style;
-  }
-}
+@mixin clearfix {
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
+  }
+}
+
+@mixin scrollBar {
+  &::-webkit-scrollbar-track-piece {
+    background: #d3dce6;
+  }
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #99a9bf;
+    border-radius: 20px;
+  }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+@mixin pct($pct) {
+  width: #{$pct};
+  position: relative;
+  margin: 0 auto;
+}
+
+@mixin triangle($width, $height, $color, $direction) {
+  $width: $width/2;
+  $color-border-style: $height solid $color;
+  $transparent-border-style: $width solid transparent;
+  height: 0;
+  width: 0;
+
+  @if $direction==up {
+    border-bottom: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==right {
+    border-left: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+
+  @else if $direction==down {
+    border-top: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==left {
+    border-right: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+}

+ 240 - 240
ruoyi-ui/src/assets/styles/ruoyi.scss

@@ -1,240 +1,240 @@
- /**
- * 通用css样式布局处理
- * Copyright (c) 2019 ruoyi
- */
-
- /** 基础通用 **/
-.pt5 {
-	padding-top: 5px;
-}
-.pr5 {
-	padding-right: 5px;
-}
-.pb5 {
-	padding-bottom: 5px;
-}
-.mt5 {
-	margin-top: 5px;
-}
-.mr5 {
-	margin-right: 5px;
-}
-.mb5 {
-	margin-bottom: 5px;
-}
-.mb8 {
-	margin-bottom: 8px;
-}
-.ml5 {
-	margin-left: 5px;
-}
-.mt10 {
-	margin-top: 10px;
-}
-.mr10 {
-	margin-right: 10px;
-}
-.mb10 {
-	margin-bottom: 10px;
-}
-.ml0 {
-	margin-left: 10px;
-}
-.mt20 {
-	margin-top: 20px;
-}
-.mr20 {
-	margin-right: 20px;
-}
-.mb20 {
-	margin-bottom: 20px;
-}
-.m20 {
-	margin-left: 20px;
-}
-
-.el-dialog:not(.is-fullscreen){
-	margin-top: 6vh !important;
-}
-
-.el-table {
-	.el-table__header-wrapper, .el-table__fixed-header-wrapper {
-		th {
-			word-break: break-word;
-			background-color: #f8f8f9;
-			color: #515a6e;
-			height: 40px;
-			font-size: 13px;
-		}
-	}
-	.el-table__body-wrapper {
-		.el-button [class*="el-icon-"] + span {
-			margin-left: 1px;
-		}
-	}
-}
-
-/** 表单布局 **/
-.form-header {
-    font-size:15px;
-	color:#6379bb;
-	border-bottom:1px solid #ddd;
-	margin:8px 10px 25px 10px;
-	padding-bottom:5px
-}
-
-/** 表格布局 **/
-.pagination-container {
-	position: relative;
-	height: 25px;
-	margin-bottom: 10px;
-	margin-top: 15px;
-	padding: 10px 20px !important;
-}
-
-/* tree border */
-.tree-border {
-    margin-top: 5px;
-    border: 1px solid #e5e6e7;
-    background: #FFFFFF none;
-    border-radius:4px;
-}
-
-.pagination-container .el-pagination {
-	right: 0;
-	position: absolute;
-}
-
-.el-table .fixed-width .el-button--mini {
-	color: #409EFF;
-	padding-left: 0;
-	padding-right: 0;
-	width: inherit;
-}
-
-.el-tree-node__content > .el-checkbox {
-	margin-right: 8px;
-}
-
-.list-group-striped > .list-group-item {
-	border-left: 0;
-	border-right: 0;
-	border-radius: 0;
-	padding-left: 0;
-	padding-right: 0;
-}
-
-.list-group {
-	padding-left: 0px;
-	list-style: none;
-}
-
-.list-group-item {
-	border-bottom: 1px solid #e7eaec;
-	border-top: 1px solid #e7eaec;
-	margin-bottom: -1px;
-	padding: 11px 0px;
-	font-size: 13px;
-}
-
-.pull-right {
-	float: right !important;
-}
-
-.el-card__header {
-	padding: 14px 15px 7px;
-	min-height: 40px;
-}
-
-.el-card__body {
-	padding: 15px 20px 20px 20px;
-}
-
-.card-box {
-	padding-right: 15px;
-	padding-left: 15px;
-	margin-bottom: 10px;
-}
-
-/* button color */
-.el-button--cyan.is-active,
-.el-button--cyan:active {
-  background: #20B2AA;
-  border-color: #20B2AA;
-  color: #FFFFFF;
-}
-
-.el-button--cyan:focus,
-.el-button--cyan:hover {
-  background: #48D1CC;
-  border-color: #48D1CC;
-  color: #FFFFFF;
-}
-
-.el-button--cyan {
-  background-color: #20B2AA;
-  border-color: #20B2AA;
-  color: #FFFFFF;
-}
-
-/* text color */
-.text-navy {
-	color: #1ab394;
-}
-
-.text-primary {
-	color: inherit;
-}
-
-.text-success {
-	color: #1c84c6;
-}
-
-.text-info {
-	color: #23c6c8;
-}
-
-.text-warning {
-	color: #f8ac59;
-}
-
-.text-danger {
-	color: #ed5565;
-}
-
-.text-muted {
-	color: #888888;
-}
-
-/* image */
-.img-circle {
-	border-radius: 50%;
-}
-
-.img-lg {
-	width: 120px;
-	height: 120px;
-}
-
-.avatar-upload-preview {
-	position: absolute;
-	top: 50%;
-	transform: translate(50%, -50%);
-	width: 200px;
-	height: 200px;
-	border-radius: 50%;
-	box-shadow: 0 0 4px #ccc;
-	overflow: hidden;
-}
-
-/* 拖拽列样式 */
-.sortable-ghost{
-	opacity: .8;
-	color: #fff!important;
-	background: #42b983!important;
-}
-
-.top-right-btn {
-	position: relative;
-	float: right;
-}
+ /**
+ * 通用css样式布局处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+ /** 基础通用 **/
+.pt5 {
+	padding-top: 5px;
+}
+.pr5 {
+	padding-right: 5px;
+}
+.pb5 {
+	padding-bottom: 5px;
+}
+.mt5 {
+	margin-top: 5px;
+}
+.mr5 {
+	margin-right: 5px;
+}
+.mb5 {
+	margin-bottom: 5px;
+}
+.mb8 {
+	margin-bottom: 8px;
+}
+.ml5 {
+	margin-left: 5px;
+}
+.mt10 {
+	margin-top: 10px;
+}
+.mr10 {
+	margin-right: 10px;
+}
+.mb10 {
+	margin-bottom: 10px;
+}
+.ml0 {
+	margin-left: 10px;
+}
+.mt20 {
+	margin-top: 20px;
+}
+.mr20 {
+	margin-right: 20px;
+}
+.mb20 {
+	margin-bottom: 20px;
+}
+.m20 {
+	margin-left: 20px;
+}
+
+.el-dialog:not(.is-fullscreen){
+	margin-top: 6vh !important;
+}
+
+.el-table {
+	.el-table__header-wrapper, .el-table__fixed-header-wrapper {
+		th {
+			word-break: break-word;
+			background-color: #f8f8f9;
+			color: #515a6e;
+			height: 40px;
+			font-size: 13px;
+		}
+	}
+	.el-table__body-wrapper {
+		.el-button [class*="el-icon-"] + span {
+			margin-left: 1px;
+		}
+	}
+}
+
+/** 表单布局 **/
+.form-header {
+    font-size:15px;
+	color:#6379bb;
+	border-bottom:1px solid #ddd;
+	margin:8px 10px 25px 10px;
+	padding-bottom:5px
+}
+
+/** 表格布局 **/
+.pagination-container {
+	position: relative;
+	height: 25px;
+	margin-bottom: 10px;
+	margin-top: 15px;
+	padding: 10px 20px !important;
+}
+
+/* tree border */
+.tree-border {
+    margin-top: 5px;
+    border: 1px solid #e5e6e7;
+    background: #FFFFFF none;
+    border-radius:4px;
+}
+
+.pagination-container .el-pagination {
+	right: 0;
+	position: absolute;
+}
+
+.el-table .fixed-width .el-button--mini {
+	color: #409EFF;
+	padding-left: 0;
+	padding-right: 0;
+	width: inherit;
+}
+
+.el-tree-node__content > .el-checkbox {
+	margin-right: 8px;
+}
+
+.list-group-striped > .list-group-item {
+	border-left: 0;
+	border-right: 0;
+	border-radius: 0;
+	padding-left: 0;
+	padding-right: 0;
+}
+
+.list-group {
+	padding-left: 0px;
+	list-style: none;
+}
+
+.list-group-item {
+	border-bottom: 1px solid #e7eaec;
+	border-top: 1px solid #e7eaec;
+	margin-bottom: -1px;
+	padding: 11px 0px;
+	font-size: 13px;
+}
+
+.pull-right {
+	float: right !important;
+}
+
+.el-card__header {
+	padding: 14px 15px 7px;
+	min-height: 40px;
+}
+
+.el-card__body {
+	padding: 15px 20px 20px 20px;
+}
+
+.card-box {
+	padding-right: 15px;
+	padding-left: 15px;
+	margin-bottom: 10px;
+}
+
+/* button color */
+.el-button--cyan.is-active,
+.el-button--cyan:active {
+  background: #20B2AA;
+  border-color: #20B2AA;
+  color: #FFFFFF;
+}
+
+.el-button--cyan:focus,
+.el-button--cyan:hover {
+  background: #48D1CC;
+  border-color: #48D1CC;
+  color: #FFFFFF;
+}
+
+.el-button--cyan {
+  background-color: #20B2AA;
+  border-color: #20B2AA;
+  color: #FFFFFF;
+}
+
+/* text color */
+.text-navy {
+	color: #1ab394;
+}
+
+.text-primary {
+	color: inherit;
+}
+
+.text-success {
+	color: #1c84c6;
+}
+
+.text-info {
+	color: #23c6c8;
+}
+
+.text-warning {
+	color: #f8ac59;
+}
+
+.text-danger {
+	color: #ed5565;
+}
+
+.text-muted {
+	color: #888888;
+}
+
+/* image */
+.img-circle {
+	border-radius: 50%;
+}
+
+.img-lg {
+	width: 120px;
+	height: 120px;
+}
+
+.avatar-upload-preview {
+	position: absolute;
+	top: 50%;
+	transform: translate(50%, -50%);
+	width: 200px;
+	height: 200px;
+	border-radius: 50%;
+	box-shadow: 0 0 4px #ccc;
+	overflow: hidden;
+}
+
+/* 拖拽列样式 */
+.sortable-ghost{
+	opacity: .8;
+	color: #fff!important;
+	background: #42b983!important;
+}
+
+.top-right-btn {
+	position: relative;
+	float: right;
+}

+ 245 - 245
ruoyi-ui/src/assets/styles/sidebar.scss

@@ -1,245 +1,245 @@
-#app {
-
-  .main-container {
-    min-height: 100%;
-    transition: margin-left .28s;
-    margin-left: $sideBarWidth;
-    position: relative;
-  }
-
-  .sidebar-container {
-    -webkit-transition: width .28s;
-    transition: width 0.28s;
-    width: $sideBarWidth !important;
-    background-color: $menuBg;
-    height: 100%;
-    position: fixed;
-    font-size: 0px;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    z-index: 1001;
-    overflow: hidden;
-    -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
-    box-shadow: 2px 0 6px rgba(0,21,41,.35);
-
-    // reset element-ui css
-    .horizontal-collapse-transition {
-      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
-    }
-
-    .scrollbar-wrapper {
-      overflow-x: hidden !important;
-    }
-
-    .el-scrollbar__bar.is-vertical {
-      right: 0px;
-    }
-
-    .el-scrollbar {
-      height: 100%;
-    }
-
-    &.has-logo {
-      .el-scrollbar {
-        height: calc(100% - 50px);
-      }
-    }
-
-    .is-horizontal {
-      display: none;
-    }
-
-    a {
-      display: inline-block;
-      width: 100%;
-      overflow: hidden;
-    }
-
-    .svg-icon {
-      margin-right: 16px;
-    }
-
-    .el-menu {
-      border: none;
-      height: 100%;
-      width: 100% !important;
-      .submenu-title-noDropdown.is-active{
-        span{
-          color: #3C8DBC!important;
-        }
-      }
-    }
-
-    .el-menu-item, .el-submenu__title {
-      overflow: hidden !important;
-      text-overflow: ellipsis !important;
-      white-space: nowrap !important;
-    }
-
-    // menu hover
-    .submenu-title-noDropdown,
-    .el-submenu__title {
-      &:hover {
-        background-color: rgba(0, 0, 0, 0.06) !important;
-      }
-    }
-
-
-    & .theme-dark .is-active > .el-submenu__title {
-      span{
-        color: $subMenuActiveText !important;
-      }
-    }
-
-    & .nest-menu .el-submenu>.el-submenu__title,
-    & .el-submenu .el-menu-item {
-      min-width: $sideBarWidth !important;
-
-
-      &:hover {
-        background-color: rgba(0, 0, 0, 0.06) !important;
-      }
-    }
-
-
-    & .theme-dark .nest-menu .el-submenu>.el-submenu__title,
-    & .theme-dark .el-submenu .el-menu-item {
-      background-color: $subMenuBg;
-      &:hover {
-        background-color: $subMenuHover !important;
-        span{
-          color: #fff!important;
-        }
-      }
-    }
-    .nest-menu .is-active{
-      &>span{
-        color: #fff!important;
-      }
-      background-color: #3C8DBC!important;
-    }
-  }
-
-
-  .hideSidebar {
-    .sidebar-container {
-      width: 54px !important;
-    }
-
-    .main-container {
-      margin-left: 54px;
-    }
-
-    .submenu-title-noDropdown {
-      padding: 0 !important;
-      position: relative;
-
-      .el-tooltip {
-        padding: 0 !important;
-
-        .svg-icon {
-          margin-left: 20px;
-        }
-      }
-    }
-
-    .el-submenu {
-      overflow: hidden;
-
-      &>.el-submenu__title {
-        padding: 0 !important;
-
-        .svg-icon {
-          margin-left: 20px;
-        }
-
-        .el-submenu__icon-arrow {
-          display: none;
-        }
-      }
-    }
-
-    .el-menu--collapse {
-      .el-submenu {
-        &>.el-submenu__title {
-          &>span {
-            height: 0;
-            width: 0;
-            overflow: hidden;
-            visibility: hidden;
-            display: inline-block;
-          }
-        }
-      }
-    }
-  }
-
-  .el-menu--collapse .el-menu .el-submenu {
-    min-width: $sideBarWidth !important;
-  }
-
-  // mobile responsive
-  .mobile {
-    .main-container {
-      margin-left: 0px;
-    }
-
-    .sidebar-container {
-      transition: transform .28s;
-      width: $sideBarWidth !important;
-    }
-
-    &.hideSidebar {
-      .sidebar-container {
-        pointer-events: none;
-        transition-duration: 0.3s;
-        transform: translate3d(-$sideBarWidth, 0, 0);
-      }
-    }
-  }
-
-  .withoutAnimation {
-
-    .main-container,
-    .sidebar-container {
-      transition: none;
-    }
-  }
-}
-
-// when menu collapsed
-.el-menu--vertical {
-  &>.el-menu {
-    .svg-icon {
-      margin-right: 16px;
-    }
-  }
-
-  .nest-menu .el-submenu>.el-submenu__title,
-  .el-menu-item {
-    &:hover {
-      // you can use $subMenuHover
-      background-color: rgba(0, 0, 0, 0.06) !important;
-    }
-  }
-
-  // the scroll bar appears when the subMenu is too long
-  >.el-menu--popup {
-    max-height: 100vh;
-    overflow-y: auto;
-
-    &::-webkit-scrollbar-track-piece {
-      background: #d3dce6;
-    }
-
-    &::-webkit-scrollbar {
-      width: 6px;
-    }
-
-    &::-webkit-scrollbar-thumb {
-      background: #99a9bf;
-      border-radius: 20px;
-    }
-  }
-}
+#app {
+
+  .main-container {
+    min-height: 100%;
+    transition: margin-left .28s;
+    margin-left: $sideBarWidth;
+    position: relative;
+  }
+
+  .sidebar-container {
+    -webkit-transition: width .28s;
+    transition: width 0.28s;
+    width: $sideBarWidth !important;
+    background-color: $menuBg;
+    height: 100%;
+    position: fixed;
+    font-size: 0px;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    overflow: hidden;
+    -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
+    box-shadow: 2px 0 6px rgba(0,21,41,.35);
+
+    // reset element-ui css
+    .horizontal-collapse-transition {
+      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+    }
+
+    .scrollbar-wrapper {
+      overflow-x: hidden !important;
+    }
+
+    .el-scrollbar__bar.is-vertical {
+      right: 0px;
+    }
+
+    .el-scrollbar {
+      height: 100%;
+    }
+
+    &.has-logo {
+      .el-scrollbar {
+        height: calc(100% - 50px);
+      }
+    }
+
+    .is-horizontal {
+      display: none;
+    }
+
+    a {
+      display: inline-block;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .svg-icon {
+      margin-right: 16px;
+    }
+
+    .el-menu {
+      border: none;
+      height: 100%;
+      width: 100% !important;
+      .submenu-title-noDropdown.is-active{
+        span{
+          color: #3C8DBC!important;
+        }
+      }
+    }
+
+    .el-menu-item, .el-submenu__title {
+      overflow: hidden !important;
+      text-overflow: ellipsis !important;
+      white-space: nowrap !important;
+    }
+
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: rgba(0, 0, 0, 0.06) !important;
+      }
+    }
+
+
+    & .theme-dark .is-active > .el-submenu__title {
+      span{
+        color: $subMenuActiveText !important;
+      }
+    }
+
+    & .nest-menu .el-submenu>.el-submenu__title,
+    & .el-submenu .el-menu-item {
+      min-width: $sideBarWidth !important;
+
+
+      &:hover {
+        background-color: rgba(0, 0, 0, 0.06) !important;
+      }
+    }
+
+
+    & .theme-dark .nest-menu .el-submenu>.el-submenu__title,
+    & .theme-dark .el-submenu .el-menu-item {
+      background-color: $subMenuBg;
+      &:hover {
+        background-color: $subMenuHover !important;
+        span{
+          color: #fff!important;
+        }
+      }
+    }
+    .nest-menu .is-active{
+      &>span{
+        color: #fff!important;
+      }
+      background-color: #3C8DBC!important;
+    }
+  }
+
+
+  .hideSidebar {
+    .sidebar-container {
+      width: 54px !important;
+    }
+
+    .main-container {
+      margin-left: 54px;
+    }
+
+    .submenu-title-noDropdown {
+      padding: 0 !important;
+      position: relative;
+
+      .el-tooltip {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+      }
+    }
+
+    .el-submenu {
+      overflow: hidden;
+
+      &>.el-submenu__title {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+
+        .el-submenu__icon-arrow {
+          display: none;
+        }
+      }
+    }
+
+    .el-menu--collapse {
+      .el-submenu {
+        &>.el-submenu__title {
+          &>span {
+            height: 0;
+            width: 0;
+            overflow: hidden;
+            visibility: hidden;
+            display: inline-block;
+          }
+        }
+      }
+    }
+  }
+
+  .el-menu--collapse .el-menu .el-submenu {
+    min-width: $sideBarWidth !important;
+  }
+
+  // mobile responsive
+  .mobile {
+    .main-container {
+      margin-left: 0px;
+    }
+
+    .sidebar-container {
+      transition: transform .28s;
+      width: $sideBarWidth !important;
+    }
+
+    &.hideSidebar {
+      .sidebar-container {
+        pointer-events: none;
+        transition-duration: 0.3s;
+        transform: translate3d(-$sideBarWidth, 0, 0);
+      }
+    }
+  }
+
+  .withoutAnimation {
+
+    .main-container,
+    .sidebar-container {
+      transition: none;
+    }
+  }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+  &>.el-menu {
+    .svg-icon {
+      margin-right: 16px;
+    }
+  }
+
+  .nest-menu .el-submenu>.el-submenu__title,
+  .el-menu-item {
+    &:hover {
+      // you can use $subMenuHover
+      background-color: rgba(0, 0, 0, 0.06) !important;
+    }
+  }
+
+  // the scroll bar appears when the subMenu is too long
+  >.el-menu--popup {
+    max-height: 100vh;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar-track-piece {
+      background: #d3dce6;
+    }
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background: #99a9bf;
+      border-radius: 20px;
+    }
+  }
+}

+ 48 - 48
ruoyi-ui/src/assets/styles/transition.scss

@@ -1,48 +1,48 @@
-// global transition css
-
-/* fade */
-.fade-enter-active,
-.fade-leave-active {
-  transition: opacity 0.28s;
-}
-
-.fade-enter,
-.fade-leave-active {
-  opacity: 0;
-}
-
-/* fade-transform */
-.fade-transform-leave-active,
-.fade-transform-enter-active {
-  transition: all .5s;
-}
-
-.fade-transform-enter {
-  opacity: 0;
-  transform: translateX(-30px);
-}
-
-.fade-transform-leave-to {
-  opacity: 0;
-  transform: translateX(30px);
-}
-
-/* breadcrumb transition */
-.breadcrumb-enter-active,
-.breadcrumb-leave-active {
-  transition: all .5s;
-}
-
-.breadcrumb-enter,
-.breadcrumb-leave-active {
-  opacity: 0;
-  transform: translateX(20px);
-}
-
-.breadcrumb-move {
-  transition: all .5s;
-}
-
-.breadcrumb-leave-active {
-  position: absolute;
-}
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+  opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all .5s;
+}
+
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+  transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+  opacity: 0;
+  transform: translateX(20px);
+}
+
+.breadcrumb-move {
+  transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+  position: absolute;
+}

+ 44 - 44
ruoyi-ui/src/assets/styles/variables.scss

@@ -1,44 +1,44 @@
-// base color
-$blue:#324157;
-$light-blue:#3A71A8;
-$red:#C03639;
-$pink: #E65D6E;
-$green: #30B08F;
-$tiffany: #4AB7BD;
-$yellow:#FEC171;
-$panGreen: #30B08F;
-
-// sidebar
-$menuText:#bfcbd9;
-$menuActiveText:#409EFF;
-$subMenuActiveText:#3C8DBC; // https://github.com/ElemeFE/element/issues/12951
-
-$menuBg: #FAFAFA;
-$menuHover:#263445;
-$sidebarTitle: #ffffff;
-
-$menuLightBg:#ffffff;
-$menuLightHover:#f0f1f5;
-$sidebarLightTitle: #001529;
-
-$subMenuBg:#FAFAFA;
-$subMenuHover:#3C8DBC;
-
-$sideBarWidth: 200px;
-
-// the :export directive is the magic sauce for webpack
-// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
-:export {
-  menuText: $menuText;
-  menuActiveText: $menuActiveText;
-  subMenuActiveText: $subMenuActiveText;
-  menuBg: $menuBg;
-  menuHover: $menuHover;
-  menuLightBg: $menuLightBg;
-  menuLightHover: $menuLightHover;
-  subMenuBg: $subMenuBg;
-  subMenuHover: $subMenuHover;
-  sideBarWidth: $sideBarWidth;
-  sidebarTitle: $sidebarTitle;
-  sidebarLightTitle: $sidebarLightTitle
-}
+// base color
+$blue:#324157;
+$light-blue:#3A71A8;
+$red:#C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow:#FEC171;
+$panGreen: #30B08F;
+
+// sidebar
+$menuText:#bfcbd9;
+$menuActiveText:#409EFF;
+$subMenuActiveText:#3C8DBC; // https://github.com/ElemeFE/element/issues/12951
+
+$menuBg: #FAFAFA;
+$menuHover:#263445;
+$sidebarTitle: #ffffff;
+
+$menuLightBg:#ffffff;
+$menuLightHover:#f0f1f5;
+$sidebarLightTitle: #001529;
+
+$subMenuBg:#FAFAFA;
+$subMenuHover:#3C8DBC;
+
+$sideBarWidth: 200px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  menuText: $menuText;
+  menuActiveText: $menuActiveText;
+  subMenuActiveText: $subMenuActiveText;
+  menuBg: $menuBg;
+  menuHover: $menuHover;
+  menuLightBg: $menuLightBg;
+  menuLightHover: $menuLightHover;
+  subMenuBg: $subMenuBg;
+  subMenuHover: $subMenuHover;
+  sideBarWidth: $sideBarWidth;
+  sidebarTitle: $sidebarTitle;
+  sidebarLightTitle: $sidebarLightTitle
+}

+ 74 - 74
ruoyi-ui/src/components/Breadcrumb/index.vue

@@ -1,74 +1,74 @@
-<template>
-  <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>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      levelList: null
-    }
-  },
-  watch: {
-    $route(route) {
-      // if you go to the redirect page, do not update the breadcrumbs
-      if (route.path.startsWith('/redirect/')) {
-        return
-      }
-      this.getBreadcrumb()
-    }
-  },
-  created() {
-    this.getBreadcrumb()
-  },
-  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: '/index', meta: { title: '首页' }}].concat(matched)
-      }
-      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
-      console.log(this.levelList,999)
-    },
-    isDashboard(route) {
-      const name = route && route.name
-      if (!name) {
-        return false
-      }
-      return name.trim() === '首页'
-    },
-    handleLink(item) {
-      const { redirect, path } = item
-      if (redirect) {
-        this.$router.push(redirect)
-        return
-      }
-      this.$router.push(path)
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.app-breadcrumb.el-breadcrumb {
-  display: inline-block;
-  font-size: 14px;
-  line-height: 50px;
-  margin-left: 8px;
-
-  .no-redirect {
-    color: #97a8be;
-    cursor: text;
-  }
-}
-</style>
+<template>
+  <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>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route(route) {
+      // if you go to the redirect page, do not update the breadcrumbs
+      if (route.path.startsWith('/redirect/')) {
+        return
+      }
+      this.getBreadcrumb()
+    }
+  },
+  created() {
+    this.getBreadcrumb()
+  },
+  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: '/index', meta: { title: '首页' }}].concat(matched)
+      }
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+      console.log(this.levelList,999)
+    },
+    isDashboard(route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim() === '首页'
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      this.$router.push(path)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+
+  .no-redirect {
+    color: #97a8be;
+    cursor: text;
+  }
+}
+</style>

+ 13 - 13
ruoyi-ui/src/components/Directives/index.js

@@ -1,14 +1,14 @@
-// import Vue from 'vue'
-// Vue.directive('loadmore', {
-//  bind (el, binding) {
-//   // 获取element-ui定义好的scroll盒子
-//   const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
-//   SELECTWRAP_DOM.addEventListener('scroll', function () {
-    
-//    const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
-//    if (CONDITION) {
-//     binding.value()
-//    }
-//   })
-//  }
+// import Vue from 'vue'
+// Vue.directive('loadmore', {
+//  bind (el, binding) {
+//   // 获取element-ui定义好的scroll盒子
+//   const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
+//   SELECTWRAP_DOM.addEventListener('scroll', function () {
+    
+//    const CONDITION = this.scrollHeight - this.scrollTop <= this.clientHeight
+//    if (CONDITION) {
+//     binding.value()
+//    }
+//   })
+//  }
 // })

+ 149 - 149
ruoyi-ui/src/components/DynamicForms/index.vue

@@ -1,149 +1,149 @@
-<template>
-    <el-form-item :label="formConfig.columnComment" style="display: inline-block;" :prop="formConfig.columnName">
-      <!-- 输入框 -->
-      <el-input v-if="formConfig.htmlType == 'input'" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
-        clearable @keyup.enter.native="handleQuery" />
-      <!-- 多行输入框 -->
-      <el-input v-if="formConfig.htmlType == 'textarea'" type="textarea" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
-        clearable @keyup.enter.native="handleQuery" />
-      <!-- 下拉框 -->
-      <el-select v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'select'" filterable :placeholder="'请输入'+formConfig.columnComment">
-        <el-option v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue">
-        </el-option>
-      </el-select>
-      <!-- 复选框 -->
-      <el-checkbox-group v-model="config" v-if="formConfig.htmlType == 'checkbox'">
-        <el-checkbox @change="handleCheckedCitiesChange" v-for="itemChild in formConfig.sysDictData" :label="itemChild.dictValue" :key="itemChild.dictLabel" >
-          {{itemChild.dictLabel}}
-        </el-checkbox>
-      </el-checkbox-group>
-      <!-- 单选框 -->
-      <el-radio-group v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'radio'">
-        <el-radio v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictValue">{{itemChild.dictLabel}}</el-radio>
-      </el-radio-group>
-      <!-- 时间控件 -->
-      <el-date-picker  v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'datetime'" type="date" :placeholder="'请输入'+formConfig.columnComment">
-      </el-date-picker>
-      <!-- 上传图片 -->
-      <el-upload v-if="formConfig.htmlType == 'imageUpload'" :headers="{Authorization: 'Bearer ' + getToken()}" :action="process + '/boman-file/upload'" :file-list="config" list-type="picture-card"
-        :on-preview="handlePictureCardPreview" :on-success="upImageFn" :on-remove="reseImage" >
-        <i class="el-icon-plus"></i>
-      </el-upload>
-      <el-dialog :visible.sync="dialogVisible" v-if="formConfig.htmlType == 'imageUpload'">
-        <img width="100%" :src="dialogImageUrl" alt="">
-      </el-dialog>
-      <!-- 上传文件 -->
-      <el-upload
-        class="upload-demo"
-        :headers="{Authorization: 'Bearer ' + getToken()}"
-        v-if="formConfig.htmlType == 'fileUpload'"
-        :action="process + '/boman-file/upload'"
-        :on-change="handleChange"
-        :on-success="upImageFn"
-         :on-remove="reseImage"
-        :file-list="config">
-        <el-button size="small" type="primary">点击上传</el-button>
-        <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
-      </el-upload>
-      <!-- 富文本 -->
-      <editor v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'editor'" :min-height="192"/>
-    </el-form-item>
-</template>
-
-<script>
-  const defaultSettings = require('@/settings.js')
-  import Editor from '@/components/Editor';
-  import { getToken } from "@/utils/auth";
-  export default {
-    data() {
-      return {
-        fileList: [],
-        defaultSettings,
-        dialogImageUrl: '',
-        process: process.env.VUE_APP_BASE_API,
-        dialogVisible: false,
-        disabled: false,
-        config: {},
-      }
-    },
-    components: {
-      Editor
-    },
-    props: {
-      formConfig: {
-        type: Object,
-        required: true,
-        'default': {
-          sysDictData: []
-        }
-      },
-    },
-    created() {
-      this.config = {}
-      this.init()
-    },
-    mounted() {
-    },
-    methods: {
-      upImageFn(res, file){
-        this.config.push(res.data);
-        console.log(this.config,12153)
-      },
-      init() {
-        if(this.formConfig.htmlType == 'checkbox' || this.formConfig.htmlType == 'imageUpload' || this.formConfig.htmlType == 'fileUpload'){
-          this.config =  []
-        }else{
-          this.$set(this.config, this.formConfig.columnName,(this.formConfig.columnValue || ''))
-        }
-      },
-      handleChange(file, fileList) {
-        this.fileList = fileList.slice(-3);
-      },
-      getToken() {
-        return getToken()
-      },
-      reseImage(file, fileList) {
-        let urls = ""
-        if(file.response){
-          urls = file.response.url
-        }else{
-          urls = file.url
-        }
-        for (let i = this.config.length - 1; i >= 0; i--) {
-          if (this.config[i].url == urls) {
-            this.config.splice(i, 1);
-          }
-        }
-      },
-      reseImage1(file, fileList) {
-        let urls = ""
-        if(file.response){
-          urls = file.response.url
-        }else{
-          urls = file.url
-        }
-        for (let i = this.config.length - 1; i >= 0; i--) {
-          if (this.config[i].url == urls) {
-            this.config.splice(i, 1);
-          }
-        }
-      },
-      handlePictureCardPreview(file) {
-        this.dialogImageUrl = file.url;
-        this.dialogVisible = true;
-      },
-      handleDownload(file) {
-        console.log(file);
-      },
-      handleQuery() {
-        this.$emit('btns')
-      },
-      handleCheckedCitiesChange(value){
-        console.log(this.config)
-      }
-    }
-  }
-</script>
-
-<style>
-</style>
+<template>
+    <el-form-item :label="formConfig.columnComment" style="display: inline-block;" :prop="formConfig.columnName">
+      <!-- 输入框 -->
+      <el-input v-if="formConfig.htmlType == 'input'" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
+        clearable @keyup.enter.native="handleQuery" />
+      <!-- 多行输入框 -->
+      <el-input v-if="formConfig.htmlType == 'textarea'" type="textarea" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
+        clearable @keyup.enter.native="handleQuery" />
+      <!-- 下拉框 -->
+      <el-select v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'select'" filterable :placeholder="'请输入'+formConfig.columnComment">
+        <el-option v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue">
+        </el-option>
+      </el-select>
+      <!-- 复选框 -->
+      <el-checkbox-group v-model="config" v-if="formConfig.htmlType == 'checkbox'">
+        <el-checkbox @change="handleCheckedCitiesChange" v-for="itemChild in formConfig.sysDictData" :label="itemChild.dictValue" :key="itemChild.dictLabel" >
+          {{itemChild.dictLabel}}
+        </el-checkbox>
+      </el-checkbox-group>
+      <!-- 单选框 -->
+      <el-radio-group v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'radio'">
+        <el-radio v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictValue">{{itemChild.dictLabel}}</el-radio>
+      </el-radio-group>
+      <!-- 时间控件 -->
+      <el-date-picker  v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'datetime'" type="date" :placeholder="'请输入'+formConfig.columnComment">
+      </el-date-picker>
+      <!-- 上传图片 -->
+      <el-upload v-if="formConfig.htmlType == 'imageUpload'" :headers="{Authorization: 'Bearer ' + getToken()}" :action="process + '/boman-file/upload'" :file-list="config" list-type="picture-card"
+        :on-preview="handlePictureCardPreview" :on-success="upImageFn" :on-remove="reseImage" >
+        <i class="el-icon-plus"></i>
+      </el-upload>
+      <el-dialog :visible.sync="dialogVisible" v-if="formConfig.htmlType == 'imageUpload'">
+        <img width="100%" :src="dialogImageUrl" alt="">
+      </el-dialog>
+      <!-- 上传文件 -->
+      <el-upload
+        class="upload-demo"
+        :headers="{Authorization: 'Bearer ' + getToken()}"
+        v-if="formConfig.htmlType == 'fileUpload'"
+        :action="process + '/boman-file/upload'"
+        :on-change="handleChange"
+        :on-success="upImageFn"
+         :on-remove="reseImage"
+        :file-list="config">
+        <el-button size="small" type="primary">点击上传</el-button>
+        <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
+      </el-upload>
+      <!-- 富文本 -->
+      <editor v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'editor'" :min-height="192"/>
+    </el-form-item>
+</template>
+
+<script>
+  const defaultSettings = require('@/settings.js')
+  import Editor from '@/components/Editor';
+  import { getToken } from "@/utils/auth";
+  export default {
+    data() {
+      return {
+        fileList: [],
+        defaultSettings,
+        dialogImageUrl: '',
+        process: process.env.VUE_APP_BASE_API,
+        dialogVisible: false,
+        disabled: false,
+        config: {},
+      }
+    },
+    components: {
+      Editor
+    },
+    props: {
+      formConfig: {
+        type: Object,
+        required: true,
+        'default': {
+          sysDictData: []
+        }
+      },
+    },
+    created() {
+      this.config = {}
+      this.init()
+    },
+    mounted() {
+    },
+    methods: {
+      upImageFn(res, file){
+        this.config.push(res.data);
+        console.log(this.config,12153)
+      },
+      init() {
+        if(this.formConfig.htmlType == 'checkbox' || this.formConfig.htmlType == 'imageUpload' || this.formConfig.htmlType == 'fileUpload'){
+          this.config =  []
+        }else{
+          this.$set(this.config, this.formConfig.columnName,(this.formConfig.columnValue || ''))
+        }
+      },
+      handleChange(file, fileList) {
+        this.fileList = fileList.slice(-3);
+      },
+      getToken() {
+        return getToken()
+      },
+      reseImage(file, fileList) {
+        let urls = ""
+        if(file.response){
+          urls = file.response.url
+        }else{
+          urls = file.url
+        }
+        for (let i = this.config.length - 1; i >= 0; i--) {
+          if (this.config[i].url == urls) {
+            this.config.splice(i, 1);
+          }
+        }
+      },
+      reseImage1(file, fileList) {
+        let urls = ""
+        if(file.response){
+          urls = file.response.url
+        }else{
+          urls = file.url
+        }
+        for (let i = this.config.length - 1; i >= 0; i--) {
+          if (this.config[i].url == urls) {
+            this.config.splice(i, 1);
+          }
+        }
+      },
+      handlePictureCardPreview(file) {
+        this.dialogImageUrl = file.url;
+        this.dialogVisible = true;
+      },
+      handleDownload(file) {
+        console.log(file);
+      },
+      handleQuery() {
+        this.$emit('btns')
+      },
+      handleCheckedCitiesChange(value){
+        console.log(this.config)
+      }
+    }
+  }
+</script>
+
+<style>
+</style>

+ 200 - 200
ruoyi-ui/src/components/Editor/index.vue

@@ -1,200 +1,200 @@
-<template>
-    <div class="editor" ref="editor" :style="styles"></div>
-</template>
-
-<script>
-import Quill from "quill";
-import "quill/dist/quill.core.css";
-import "quill/dist/quill.snow.css";
-import "quill/dist/quill.bubble.css";
-
-export default {
-  name: "Editor",
-  props: {
-    /* 编辑器的内容 */
-    value: {
-      type: String,
-      default: "",
-    },
-    /* 高度 */
-    height: {
-      type: Number,
-      default: null,
-    },
-    /* 最小高度 */
-    minHeight: {
-      type: Number,
-      default: null,
-    },
-    /* 只读 */
-    readOnly: {
-      type: Boolean,
-      default: false,
-    }
-  },
-  data() {
-    return {
-      Quill: null,
-      currentValue: "",
-      options: {
-        theme: "snow",
-        bounds: document.body,
-        debug: "warn",
-        modules: {
-          // 工具栏配置
-          toolbar: [
-            ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
-            ["blockquote", "code-block"],                    // 引用  代码块
-            [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
-            [{ indent: "-1" }, { indent: "+1" }],            // 缩进
-            [{ size: ["small", false, "large", "huge"] }],   // 字体大小
-            [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
-            [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
-            [{ align: [] }],                                 // 对齐方式
-            ["clean"],                                       // 清除文本格式
-            ["link", "image", "video"]                       // 链接、图片、视频
-          ],
-        },
-        placeholder: "请输入内容",
-        readOnly: this.readOnly,
-      },
-    };
-  },
-  computed: {
-    styles() {
-      let style = {};
-      if (this.minHeight) {
-        style.minHeight = `${this.minHeight}px`;
-      }
-      if (this.height) {
-        style.height = `${this.height}px`;
-      }
-      return style;
-    },
-  },
-  watch: {
-    value: {
-      handler(val) {
-        if (val !== this.currentValue) {
-          this.currentValue = val === null ? "" : val;
-          if (this.Quill) {
-            this.Quill.pasteHTML(this.currentValue);
-          }
-        }
-      },
-      immediate: true,
-    },
-  },
-  mounted() {
-    this.init();
-  },
-  beforeDestroy() {
-    this.Quill = null;
-  },
-  methods: {
-    init() {
-      const editor = this.$refs.editor;
-      this.Quill = new Quill(editor, this.options);
-      this.Quill.pasteHTML(this.currentValue);
-      this.Quill.on("text-change", (delta, oldDelta, source) => {
-        const html = this.$refs.editor.children[0].innerHTML;
-        const text = this.Quill.getText();
-        const quill = this.Quill;
-        this.currentValue = html;
-        this.$emit("input", html);
-        this.$emit("on-change", { html, text, quill });
-      });
-      this.Quill.on("text-change", (delta, oldDelta, source) => {
-        this.$emit("on-text-change", delta, oldDelta, source);
-      });
-      this.Quill.on("selection-change", (range, oldRange, source) => {
-        this.$emit("on-selection-change", range, oldRange, source);
-      });
-      this.Quill.on("editor-change", (eventName, ...args) => {
-        this.$emit("on-editor-change", eventName, ...args);
-      });
-    },
-  },
-};
-</script>
-
-<style>
-.editor, .ql-toolbar {
-  white-space: pre-wrap!important;
-  line-height: normal !important;
-}
-.quill-img {
-  display: none;
-}
-.ql-snow .ql-tooltip[data-mode="link"]::before {
-  content: "请输入链接地址:";
-}
-.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
-  border-right: 0px;
-  content: "保存";
-  padding-right: 0px;
-}
-
-.ql-snow .ql-tooltip[data-mode="video"]::before {
-  content: "请输入视频地址:";
-}
-
-.ql-snow .ql-picker.ql-size .ql-picker-label::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item::before {
-  content: "14px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
-  content: "10px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
-  content: "18px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
-  content: "32px";
-}
-
-.ql-snow .ql-picker.ql-header .ql-picker-label::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item::before {
-  content: "文本";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
-  content: "标题1";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
-  content: "标题2";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
-  content: "标题3";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
-  content: "标题4";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
-  content: "标题5";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
-  content: "标题6";
-}
-
-.ql-snow .ql-picker.ql-font .ql-picker-label::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item::before {
-  content: "标准字体";
-}
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
-  content: "衬线字体";
-}
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
-  content: "等宽字体";
-}
-</style>
+<template>
+    <div class="editor" ref="editor" :style="styles"></div>
+</template>
+
+<script>
+import Quill from "quill";
+import "quill/dist/quill.core.css";
+import "quill/dist/quill.snow.css";
+import "quill/dist/quill.bubble.css";
+
+export default {
+  name: "Editor",
+  props: {
+    /* 编辑器的内容 */
+    value: {
+      type: String,
+      default: "",
+    },
+    /* 高度 */
+    height: {
+      type: Number,
+      default: null,
+    },
+    /* 最小高度 */
+    minHeight: {
+      type: Number,
+      default: null,
+    },
+    /* 只读 */
+    readOnly: {
+      type: Boolean,
+      default: false,
+    }
+  },
+  data() {
+    return {
+      Quill: null,
+      currentValue: "",
+      options: {
+        theme: "snow",
+        bounds: document.body,
+        debug: "warn",
+        modules: {
+          // 工具栏配置
+          toolbar: [
+            ["bold", "italic", "underline", "strike"],       // 加粗 斜体 下划线 删除线
+            ["blockquote", "code-block"],                    // 引用  代码块
+            [{ list: "ordered" }, { list: "bullet" }],       // 有序、无序列表
+            [{ indent: "-1" }, { indent: "+1" }],            // 缩进
+            [{ size: ["small", false, "large", "huge"] }],   // 字体大小
+            [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 标题
+            [{ color: [] }, { background: [] }],             // 字体颜色、字体背景颜色
+            [{ align: [] }],                                 // 对齐方式
+            ["clean"],                                       // 清除文本格式
+            ["link", "image", "video"]                       // 链接、图片、视频
+          ],
+        },
+        placeholder: "请输入内容",
+        readOnly: this.readOnly,
+      },
+    };
+  },
+  computed: {
+    styles() {
+      let style = {};
+      if (this.minHeight) {
+        style.minHeight = `${this.minHeight}px`;
+      }
+      if (this.height) {
+        style.height = `${this.height}px`;
+      }
+      return style;
+    },
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val !== this.currentValue) {
+          this.currentValue = val === null ? "" : val;
+          if (this.Quill) {
+            this.Quill.pasteHTML(this.currentValue);
+          }
+        }
+      },
+      immediate: true,
+    },
+  },
+  mounted() {
+    this.init();
+  },
+  beforeDestroy() {
+    this.Quill = null;
+  },
+  methods: {
+    init() {
+      const editor = this.$refs.editor;
+      this.Quill = new Quill(editor, this.options);
+      this.Quill.pasteHTML(this.currentValue);
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        const html = this.$refs.editor.children[0].innerHTML;
+        const text = this.Quill.getText();
+        const quill = this.Quill;
+        this.currentValue = html;
+        this.$emit("input", html);
+        this.$emit("on-change", { html, text, quill });
+      });
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        this.$emit("on-text-change", delta, oldDelta, source);
+      });
+      this.Quill.on("selection-change", (range, oldRange, source) => {
+        this.$emit("on-selection-change", range, oldRange, source);
+      });
+      this.Quill.on("editor-change", (eventName, ...args) => {
+        this.$emit("on-editor-change", eventName, ...args);
+      });
+    },
+  },
+};
+</script>
+
+<style>
+.editor, .ql-toolbar {
+  white-space: pre-wrap!important;
+  line-height: normal !important;
+}
+.quill-img {
+  display: none;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+  content: "请输入链接地址:";
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+  border-right: 0px;
+  content: "保存";
+  padding-right: 0px;
+}
+
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+  content: "请输入视频地址:";
+}
+
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+  content: "14px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+  content: "10px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+  content: "18px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+  content: "32px";
+}
+
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+  content: "文本";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+  content: "标题1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+  content: "标题2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+  content: "标题3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+  content: "标题4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+  content: "标题5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+  content: "标题6";
+}
+
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+  content: "标准字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+  content: "衬线字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+  content: "等宽字体";
+}
+</style>

+ 178 - 178
ruoyi-ui/src/components/FileUpload/index.vue

@@ -1,179 +1,179 @@
-<template>
-  <div class="upload-file">
-    <el-upload
-      :action="uploadFileUrl"
-      :before-upload="handleBeforeUpload"
-      :file-list="fileList"
-      :limit="1"
-      :on-error="handleUploadError"
-      :on-exceed="handleExceed"
-      :on-success="handleUploadSuccess"
-      :show-file-list="false"
-      :headers="headers"
-      class="upload-file-uploader"
-      ref="upload"
-    >
-      <!-- 上传按钮 -->
-      <el-button size="mini" type="primary">选取文件</el-button>
-      <!-- 上传提示 -->
-      <div class="el-upload__tip" slot="tip" v-if="showTip">
-        请上传
-        <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
-        <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
-        的文件
-      </div>
-    </el-upload>
-
-    <!-- 文件列表 -->
-    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
-      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in list">
-        <el-link :href="file.url" :underline="false" target="_blank">
-          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
-        </el-link>
-        <div class="ele-upload-list__item-content-action">
-          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
-        </div>
-      </li>
-    </transition-group>
-  </div>
-</template>
-
-<script>
-import { getToken } from "@/utils/auth";
-
-export default {
-  props: {
-    // 值
-    value: [String, Object, Array],
-    // 大小限制(MB)
-    fileSize: {
-      type: Number,
-      default: 5,
-    },
-    // 文件类型, 例如['png', 'jpg', 'jpeg']
-    fileType: {
-      type: Array,
-      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
-    },
-    // 是否显示提示
-    isShowTip: {
-      type: Boolean,
-      default: true
-    }
-  },
-  data() {
-    return {
-      uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
-      headers: {
-        Authorization: "Bearer " + getToken(),
-      },
-      fileList: [],
-    };
-  },
-  computed: {
-    // 是否显示提示
-    showTip() {
-      return this.isShowTip && (this.fileType || this.fileSize);
-    },
-    // 列表
-    list() {
-      let temp = 1;
-      if (this.value) {
-        // 首先将值转为数组
-        const list = Array.isArray(this.value) ? this.value : [this.value];
-        // 然后将数组转为对象数组
-        return list.map((item) => {
-          if (typeof item === "string") {
-            item = { name: item, url: item };
-          }
-          item.uid = item.uid || new Date().getTime() + temp++;
-          return item;
-        });
-      } else {
-        this.fileList = [];
-        return [];
-      }
-    },
-  },
-  methods: {
-    // 上传前校检格式和大小
-    handleBeforeUpload(file) {
-      // 校检文件类型
-      if (this.fileType) {
-        let fileExtension = "";
-        if (file.name.lastIndexOf(".") > -1) {
-          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
-        }
-        const isTypeOk = this.fileType.some((type) => {
-          if (file.type.indexOf(type) > -1) return true;
-          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
-          return false;
-        });
-        if (!isTypeOk) {
-          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
-          return false;
-        }
-      }
-      // 校检文件大小
-      if (this.fileSize) {
-        const isLt = file.size / 1024 / 1024 < this.fileSize;
-        if (!isLt) {
-          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
-          return false;
-        }
-      }
-      return true;
-    },
-    // 文件个数超出
-    handleExceed() {
-      this.$message.error(`只允许上传单个文件`);
-    },
-    // 上传失败
-    handleUploadError(err) {
-      this.$message.error("上传失败, 请重试");
-    },
-    // 上传成功回调
-    handleUploadSuccess(res, file) {
-      this.$message.success("上传成功");
-      this.$emit("input", res.data.url);
-    },
-    // 删除文件
-    handleDelete(index) {
-      this.fileList.splice(index, 1);
-      this.$emit("input", '');
-    },
-    // 获取文件名称
-    getFileName(name) {
-      if (name.lastIndexOf("/") > -1) {
-        return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
-      } else {
-        return "";
-      }
-    }
-  },
-  created() {
-    this.fileList = this.list;
-  },
-};
-</script>
-
-<style scoped lang="scss">
-.upload-file-uploader {
-  margin-bottom: 5px;
-}
-.upload-file-list .el-upload-list__item {
-  border: 1px solid #e4e7ed;
-  line-height: 2;
-  margin-bottom: 10px;
-  position: relative;
-}
-.upload-file-list .ele-upload-list__item-content {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  color: inherit;
-}
-.ele-upload-list__item-content-action .el-link {
-  margin-right: 10px;
-}
+<template>
+  <div class="upload-file">
+    <el-upload
+      :action="uploadFileUrl"
+      :before-upload="handleBeforeUpload"
+      :file-list="fileList"
+      :limit="1"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      :on-success="handleUploadSuccess"
+      :show-file-list="false"
+      :headers="headers"
+      class="upload-file-uploader"
+      ref="upload"
+    >
+      <!-- 上传按钮 -->
+      <el-button size="mini" type="primary">选取文件</el-button>
+      <!-- 上传提示 -->
+      <div class="el-upload__tip" slot="tip" v-if="showTip">
+        请上传
+        <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+        <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+        的文件
+      </div>
+    </el-upload>
+
+    <!-- 文件列表 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in list">
+        <el-link :href="file.url" :underline="false" target="_blank">
+          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  props: {
+    // 值
+    value: [String, Object, Array],
+    // 大小限制(MB)
+    fileSize: {
+      type: Number,
+      default: 5,
+    },
+    // 文件类型, 例如['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
+    },
+    // 是否显示提示
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: [],
+    };
+  },
+  computed: {
+    // 是否显示提示
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+    // 列表
+    list() {
+      let temp = 1;
+      if (this.value) {
+        // 首先将值转为数组
+        const list = Array.isArray(this.value) ? this.value : [this.value];
+        // 然后将数组转为对象数组
+        return list.map((item) => {
+          if (typeof item === "string") {
+            item = { name: item, url: item };
+          }
+          item.uid = item.uid || new Date().getTime() + temp++;
+          return item;
+        });
+      } else {
+        this.fileList = [];
+        return [];
+      }
+    },
+  },
+  methods: {
+    // 上传前校检格式和大小
+    handleBeforeUpload(file) {
+      // 校检文件类型
+      if (this.fileType) {
+        let fileExtension = "";
+        if (file.name.lastIndexOf(".") > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
+        }
+        const isTypeOk = this.fileType.some((type) => {
+          if (file.type.indexOf(type) > -1) return true;
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+          return false;
+        });
+        if (!isTypeOk) {
+          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
+          return false;
+        }
+      }
+      // 校检文件大小
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      return true;
+    },
+    // 文件个数超出
+    handleExceed() {
+      this.$message.error(`只允许上传单个文件`);
+    },
+    // 上传失败
+    handleUploadError(err) {
+      this.$message.error("上传失败, 请重试");
+    },
+    // 上传成功回调
+    handleUploadSuccess(res, file) {
+      this.$message.success("上传成功");
+      this.$emit("input", res.data.url);
+    },
+    // 删除文件
+    handleDelete(index) {
+      this.fileList.splice(index, 1);
+      this.$emit("input", '');
+    },
+    // 获取文件名称
+    getFileName(name) {
+      if (name.lastIndexOf("/") > -1) {
+        return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
+      } else {
+        return "";
+      }
+    }
+  },
+  created() {
+    this.fileList = this.list;
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  border: 1px solid #e4e7ed;
+  line-height: 2;
+  margin-bottom: 10px;
+  position: relative;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
 </style>

+ 45 - 45
ruoyi-ui/src/components/Hamburger/index.vue

@@ -1,45 +1,45 @@
-<template>
-  <div style="padding: 0 15px;" @click="toggleClick">
-    <svg
-      :class="{'is-active':isActive}"
-      class="hamburger"
-      viewBox="0 0 1024 1024"
-      xmlns="http://www.w3.org/2000/svg"
-      width="64"
-      height="64"
-       fill="#fff"
-    >
-      <path fill="#fff" d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
-    </svg>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'Hamburger',
-  props: {
-    isActive: {
-      type: Boolean,
-      default: false
-    }
-  },
-  methods: {
-    toggleClick() {
-      this.$emit('toggleClick')
-    }
-  }
-}
-</script>
-
-<style scoped>
-.hamburger {
-  display: inline-block;
-  vertical-align: middle;
-  width: 20px;
-  height: 20px;
-}
-
-.hamburger.is-active {
-  transform: rotate(180deg);
-}
-</style>
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+       fill="#fff"
+    >
+      <path fill="#fff" d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    toggleClick() {
+      this.$emit('toggleClick')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>

+ 189 - 189
ruoyi-ui/src/components/HeaderSearch/index.vue

@@ -1,189 +1,189 @@
-<template>
-  <div :class="{'show':show}" class="header-search">
-    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
-    <el-select
-      ref="headerSearchSelect"
-      v-model="search"
-      :remote-method="querySearch"
-      filterable
-      default-first-option
-      remote
-      placeholder="Search"
-      class="header-search-select"
-      @change="change"
-    >
-      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
-    </el-select>
-  </div>
-</template>
-
-<script>
-// fuse is a lightweight fuzzy-search module
-// make search results more in line with expectations
-import Fuse from 'fuse.js/dist/fuse.min.js'
-import path from 'path'
-
-export default {
-  name: 'HeaderSearch',
-  data() {
-    return {
-      search: '',
-      options: [],
-      searchPool: [],
-      show: false,
-      fuse: undefined
-    }
-  },
-  computed: {
-    routes() {
-      return this.$store.getters.permission_routes
-    }
-  },
-  watch: {
-    routes() {
-      this.searchPool = this.generateRoutes(this.routes)
-    },
-    searchPool(list) {
-      this.initFuse(list)
-    },
-    show(value) {
-      if (value) {
-        document.body.addEventListener('click', this.close)
-      } else {
-        document.body.removeEventListener('click', this.close)
-      }
-    }
-  },
-  mounted() {
-    this.searchPool = this.generateRoutes(this.routes)
-    console.log(this.searchPool,999)
-  },
-  methods: {
-    click() {
-      this.show = !this.show
-      if (this.show) {
-        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
-      }
-    },
-    close() {
-      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
-      this.options = []
-      this.show = false
-    },
-    change(val) {
-      if(this.ishttp(val.path)) {
-        // http(s):// 路径新窗口打开
-        window.open(val.path, "_blank");
-      } else {
-        this.$router.push(val.path)
-      }
-      this.search = ''
-      this.options = []
-      this.$nextTick(() => {
-        this.show = false
-      })
-    },
-    initFuse(list) {
-      this.fuse = new Fuse(list, {
-        shouldSort: true,
-        threshold: 0.4,
-        location: 0,
-        distance: 100,
-        maxPatternLength: 32,
-        minMatchCharLength: 1,
-        keys: [{
-          name: 'title',
-          weight: 0.7
-        }, {
-          name: 'path',
-          weight: 0.3
-        }]
-      })
-    },
-    // Filter out the routes that can be displayed in the sidebar
-    // And generate the internationalized title
-    generateRoutes(routes, basePath = '/', prefixTitle = []) {
-      let res = []
-
-      for (const router of routes) {
-        // skip hidden router
-        if (router.hidden) { continue }
-
-        const data = {
-          path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
-          title: [...prefixTitle]
-        }
-
-        if (router.meta && router.meta.title) {
-          data.title = [...data.title, router.meta.title]
-
-          if (router.redirect !== 'noRedirect') {
-            // only push the routes with title
-            // special case: need to exclude parent router without redirect
-            res.push(data)
-          }
-        }
-
-        // recursive child routes
-        if (router.children) {
-          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
-          if (tempRoutes.length >= 1) {
-            res = [...res, ...tempRoutes]
-          }
-        }
-      }
-      return res
-    },
-    querySearch(query) {
-      if (query !== '') {
-        this.options = this.fuse.search(query)
-      } else {
-        this.options = []
-      }
-    },
-    ishttp(url) {
-      return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.header-search {
-  font-size: 0 !important;
-
-  .search-icon {
-    cursor: pointer;
-    font-size: 18px;
-    vertical-align: middle;
-  }
-
-  .header-search-select {
-    font-size: 18px;
-    transition: width 0.2s;
-    width: 0;
-    overflow: hidden;
-    background: transparent;
-    border-radius: 0;
-    display: inline-block;
-    vertical-align: middle;
-
-    ::v-deep .el-input__inner {
-      border-radius: 0;
-      border: 0;
-      padding-left: 0;
-      padding-right: 0;
-      box-shadow: none !important;
-      border-bottom: 1px solid #d9d9d9;
-      vertical-align: middle;
-    }
-  }
-
-  &.show {
-    .header-search-select {
-      width: 210px;
-      margin-left: 10px;
-    }
-  }
-}
-</style>
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelect"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js/dist/fuse.min.js'
+import path from 'path'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routes() {
+      return this.$store.getters.permission_routes
+    }
+  },
+  watch: {
+    routes() {
+      this.searchPool = this.generateRoutes(this.routes)
+    },
+    searchPool(list) {
+      this.initFuse(list)
+    },
+    show(value) {
+      if (value) {
+        document.body.addEventListener('click', this.close)
+      } else {
+        document.body.removeEventListener('click', this.close)
+      }
+    }
+  },
+  mounted() {
+    this.searchPool = this.generateRoutes(this.routes)
+    console.log(this.searchPool,999)
+  },
+  methods: {
+    click() {
+      this.show = !this.show
+      if (this.show) {
+        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+      }
+    },
+    close() {
+      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+      this.options = []
+      this.show = false
+    },
+    change(val) {
+      if(this.ishttp(val.path)) {
+        // http(s):// 路径新窗口打开
+        window.open(val.path, "_blank");
+      } else {
+        this.$router.push(val.path)
+      }
+      this.search = ''
+      this.options = []
+      this.$nextTick(() => {
+        this.show = false
+      })
+    },
+    initFuse(list) {
+      this.fuse = new Fuse(list, {
+        shouldSort: true,
+        threshold: 0.4,
+        location: 0,
+        distance: 100,
+        maxPatternLength: 32,
+        minMatchCharLength: 1,
+        keys: [{
+          name: 'title',
+          weight: 0.7
+        }, {
+          name: 'path',
+          weight: 0.3
+        }]
+      })
+    },
+    // Filter out the routes that can be displayed in the sidebar
+    // And generate the internationalized title
+    generateRoutes(routes, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: !this.ishttp(router.path) ? path.resolve(basePath, router.path) : router.path,
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          data.title = [...data.title, router.meta.title]
+
+          if (router.redirect !== 'noRedirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        // recursive child routes
+        if (router.children) {
+          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+          if (tempRoutes.length >= 1) {
+            res = [...res, ...tempRoutes]
+          }
+        }
+      }
+      return res
+    },
+    querySearch(query) {
+      if (query !== '') {
+        this.options = this.fuse.search(query)
+      } else {
+        this.options = []
+      }
+    },
+    ishttp(url) {
+      return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+  font-size: 0 !important;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+  }
+
+  .header-search-select {
+    font-size: 18px;
+    transition: width 0.2s;
+    width: 0;
+    overflow: hidden;
+    background: transparent;
+    border-radius: 0;
+    display: inline-block;
+    vertical-align: middle;
+
+    ::v-deep .el-input__inner {
+      border-radius: 0;
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+      border-bottom: 1px solid #d9d9d9;
+      vertical-align: middle;
+    }
+  }
+
+  &.show {
+    .header-search-select {
+      width: 210px;
+      margin-left: 10px;
+    }
+  }
+}
+</style>

+ 68 - 68
ruoyi-ui/src/components/IconSelect/index.vue

@@ -1,68 +1,68 @@
-<!-- @author zhengjie -->
-<template>
-  <div class="icon-body">
-    <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons">
-      <i slot="suffix" class="el-icon-search el-input__icon" />
-    </el-input>
-    <div class="icon-list">
-      <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
-        <svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
-        <span>{{ item }}</span>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import icons from './requireIcons'
-export default {
-  name: 'IconSelect',
-  data() {
-    return {
-      name: '',
-      iconList: icons
-    }
-  },
-  methods: {
-    filterIcons() {
-      this.iconList = icons
-      if (this.name) {
-        this.iconList = this.iconList.filter(item => item.includes(this.name))
-      }
-    },
-    selectedIcon(name) {
-      this.$emit('selected', name)
-      document.body.click()
-    },
-    reset() {
-      this.name = ''
-      this.iconList = icons
-    }
-  }
-}
-</script>
-
-<style rel="stylesheet/scss" lang="scss" scoped>
-  .icon-body {
-    width: 100%;
-    padding: 10px;
-    .icon-list {
-      height: 200px;
-      overflow-y: scroll;
-      div {
-        height: 30px;
-        line-height: 30px;
-        margin-bottom: -5px;
-        cursor: pointer;
-        width: 33%;
-        float: left;
-      }
-      span {
-        display: inline-block;
-        vertical-align: -0.15em;
-        fill: currentColor;
-        overflow: hidden;
-      }
-    }
-  }
-</style>
+<!-- @author zhengjie -->
+<template>
+  <div class="icon-body">
+    <el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons">
+      <i slot="suffix" class="el-icon-search el-input__icon" />
+    </el-input>
+    <div class="icon-list">
+      <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
+        <svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
+        <span>{{ item }}</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+  name: 'IconSelect',
+  data() {
+    return {
+      name: '',
+      iconList: icons
+    }
+  },
+  methods: {
+    filterIcons() {
+      this.iconList = icons
+      if (this.name) {
+        this.iconList = this.iconList.filter(item => item.includes(this.name))
+      }
+    },
+    selectedIcon(name) {
+      this.$emit('selected', name)
+      document.body.click()
+    },
+    reset() {
+      this.name = ''
+      this.iconList = icons
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .icon-body {
+    width: 100%;
+    padding: 10px;
+    .icon-list {
+      height: 200px;
+      overflow-y: scroll;
+      div {
+        height: 30px;
+        line-height: 30px;
+        margin-bottom: -5px;
+        cursor: pointer;
+        width: 33%;
+        float: left;
+      }
+      span {
+        display: inline-block;
+        vertical-align: -0.15em;
+        fill: currentColor;
+        overflow: hidden;
+      }
+    }
+  }
+</style>

+ 11 - 11
ruoyi-ui/src/components/IconSelect/requireIcons.js

@@ -1,11 +1,11 @@
-
-const req = require.context('../../assets/icons/svg', false, /\.svg$/)
-const requireAll = requireContext => requireContext.keys()
-
-const re = /\.\/(.*)\.svg/
-
-const icons = requireAll(req).map(i => {
-  return i.match(re)[1]
-})
-
-export default icons
+
+const req = require.context('../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+  return i.match(re)[1]
+})
+
+export default icons

+ 99 - 99
ruoyi-ui/src/components/ImageUpload/index.vue

@@ -1,100 +1,100 @@
-<template>
-  <div class="component-upload-image">
-    <el-upload
-      :action="uploadImgUrl"
-      list-type="picture-card"
-      :on-success="handleUploadSuccess"
-      :before-upload="handleBeforeUpload"
-      :on-error="handleUploadError"
-      name="file"
-      :show-file-list="false"
-      :headers="headers"
-      style="display: inline-block; vertical-align: top"
-    >
-      <el-image v-if="!value" :src="value">
-        <div slot="error" class="image-slot">
-          <i class="el-icon-plus" />
-        </div>
-      </el-image>
-      <div v-else class="image">
-        <el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/>
-        <div class="mask">
-          <div class="actions">
-            <span title="预览" @click.stop="dialogVisible = true">
-              <i class="el-icon-zoom-in" />
-            </span>
-            <span title="移除" @click.stop="removeImage">
-              <i class="el-icon-delete" />
-            </span>
-          </div>
-        </div>
-      </div>
-    </el-upload>
-    <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
-      <img :src="value" style="display: block; max-width: 100%; margin: 0 auto;">
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { getToken } from "@/utils/auth";
-
-export default {
-  data() {
-    return {
-      dialogVisible: false,
-      uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
-      headers: {
-        Authorization: "Bearer " + getToken(),
-      },
-    };
-  },
-  props: {
-    value: {
-      type: String,
-      default: "",
-    },
-  },
-  methods: {
-    removeImage() {
-      this.$emit("input", "");
-    },
-    handleUploadSuccess(res) {
-      this.$emit("input", res.data.url);
-      this.loading.close();
-    },
-    handleBeforeUpload() {
-      this.loading = this.$loading({
-        lock: true,
-        text: "上传中",
-        background: "rgba(0, 0, 0, 0.7)",
-      });
-    },
-    handleUploadError() {
-      this.$message({
-        type: "error",
-        message: "上传失败",
-      });
-      this.loading.close();
-    },
-  },
-  watch: {},
-};
-</script>
-
-<style scoped lang="scss">
-.image {
-  position: relative;
-  .mask {
-    opacity: 0;
-    position: absolute;
-    top: 0;
-    width: 100%;
-    background-color: rgba(0, 0, 0, 0.5);
-    transition: all 0.3s;
-  }
-  &:hover .mask {
-    opacity: 1;
-  }
-}
+<template>
+  <div class="component-upload-image">
+    <el-upload
+      :action="uploadImgUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :on-error="handleUploadError"
+      name="file"
+      :show-file-list="false"
+      :headers="headers"
+      style="display: inline-block; vertical-align: top"
+    >
+      <el-image v-if="!value" :src="value">
+        <div slot="error" class="image-slot">
+          <i class="el-icon-plus" />
+        </div>
+      </el-image>
+      <div v-else class="image">
+        <el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/>
+        <div class="mask">
+          <div class="actions">
+            <span title="预览" @click.stop="dialogVisible = true">
+              <i class="el-icon-zoom-in" />
+            </span>
+            <span title="移除" @click.stop="removeImage">
+              <i class="el-icon-delete" />
+            </span>
+          </div>
+        </div>
+      </div>
+    </el-upload>
+    <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
+      <img :src="value" style="display: block; max-width: 100%; margin: 0 auto;">
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  data() {
+    return {
+      dialogVisible: false,
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+    };
+  },
+  props: {
+    value: {
+      type: String,
+      default: "",
+    },
+  },
+  methods: {
+    removeImage() {
+      this.$emit("input", "");
+    },
+    handleUploadSuccess(res) {
+      this.$emit("input", res.data.url);
+      this.loading.close();
+    },
+    handleBeforeUpload() {
+      this.loading = this.$loading({
+        lock: true,
+        text: "上传中",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    handleUploadError() {
+      this.$message({
+        type: "error",
+        message: "上传失败",
+      });
+      this.loading.close();
+    },
+  },
+  watch: {},
+};
+</script>
+
+<style scoped lang="scss">
+.image {
+  position: relative;
+  .mask {
+    opacity: 0;
+    position: absolute;
+    top: 0;
+    width: 100%;
+    background-color: rgba(0, 0, 0, 0.5);
+    transition: all 0.3s;
+  }
+  &:hover .mask {
+    opacity: 1;
+  }
+}
 </style>

+ 35 - 35
ruoyi-ui/src/components/MemoranDum/index.vue

@@ -60,21 +60,21 @@
 
     </div>
 
-</template>
-
-<script>
+</template>
+
+<script>
   const defaultSettings = require('@/settings.js')
   import { addConfigindex } from "@/api/system/config";
   import Editor from '@/components/Editor';
   import { getToken } from "@/utils/auth";
-  export default {
-    data() {
+  export default {
+    data() {
       return {
-        fileList: [],
-        defaultSettings,
+        fileList: [],
+        defaultSettings,
         dialogImageUrl: '',
-        process: process.env.VUE_APP_BASE_API,
-        dialogVisible: false,
+        process: process.env.VUE_APP_BASE_API,
+        dialogVisible: false,
         disabled: false,
         config: {},
         form:{},
@@ -82,20 +82,20 @@
         rules: {
         },
         open:false
-      }
+      }
     },
     components: {
       Editor
-    },
-    props: {
+    },
+    props: {
       formConfig: {},
-      nummer:0
+      nummer:0
     },
     created() {
       this.init()
-    },
-    mounted() {
-    },
+    },
+    mounted() {
+    },
     methods: {
       init() {
         // if(this.formConfig.htmlType == 'checkbox'){
@@ -109,19 +109,19 @@
       },
       getToken() {
         return getToken()
-      },
-      handleRemove(file, fileList) {
-        console.log(file, fileList);
-      },
-      handlePictureCardPreview(file) {
-        this.dialogImageUrl = file.url;
-        this.dialogVisible = true;
-      },
-      handleDownload(file) {
-        console.log(file);
-      },
-      handleQuery() {
-        this.$emit('btns')
+      },
+      handleRemove(file, fileList) {
+        console.log(file, fileList);
+      },
+      handlePictureCardPreview(file) {
+        this.dialogImageUrl = file.url;
+        this.dialogVisible = true;
+      },
+      handleDownload(file) {
+        console.log(file);
+      },
+      handleQuery() {
+        this.$emit('btns')
       },
       submitForm(value){
         console.log(1243)
@@ -153,11 +153,11 @@
       },
       handleCheckedCitiesChange(value){
         console.log(this.config)
-      }
-    }
-  }
-</script>
-
+      }
+    }
+  }
+</script>
+
 <style lang="scss">
   .from_index{
     .el-form-item{
@@ -169,7 +169,7 @@
     .el-select{
       width: 100%;
     }
-  }
+  }
 </style>
 <style scoped lang="scss">
   .dialog-footer{

+ 101 - 101
ruoyi-ui/src/components/Pagination/index.vue

@@ -1,101 +1,101 @@
-<template>
-  <div :class="{'hidden':hidden}" class="pagination-container">
-    <el-pagination
-      :background="background"
-      :current-page.sync="currentPage"
-      :page-size.sync="pageSize"
-      :layout="layout"
-      :page-sizes="pageSizes"
-      :total="total"
-      v-bind="$attrs"
-      @size-change="handleSizeChange"
-      @current-change="handleCurrentChange"
-    />
-  </div>
-</template>
-
-<script>
-import { scrollTo } from '@/utils/scroll-to'
-
-export default {
-  name: 'Pagination',
-  props: {
-    total: {
-      required: true,
-      type: Number
-    },
-    page: {
-      type: Number,
-      default: 1
-    },
-    limit: {
-      type: Number,
-      default: 20
-    },
-    pageSizes: {
-      type: Array,
-      default() {
-        return [10, 20, 30, 50]
-      }
-    },
-    layout: {
-      type: String,
-      default: 'total, sizes, prev, pager, next, jumper'
-    },
-    background: {
-      type: Boolean,
-      default: true
-    },
-    autoScroll: {
-      type: Boolean,
-      default: true
-    },
-    hidden: {
-      type: Boolean,
-      default: false
-    }
-  },
-  computed: {
-    currentPage: {
-      get() {
-        return this.page
-      },
-      set(val) {
-        this.$emit('update:page', val)
-      }
-    },
-    pageSize: {
-      get() {
-        return this.limit
-      },
-      set(val) {
-        this.$emit('update:limit', val)
-      }
-    }
-  },
-  methods: {
-    handleSizeChange(val) {
-      this.$emit('pagination', { page: this.currentPage, limit: val })
-      if (this.autoScroll) {
-        scrollTo(0, 800)
-      }
-    },
-    handleCurrentChange(val) {
-      this.$emit('pagination', { page: val, limit: this.pageSize })
-      if (this.autoScroll) {
-        scrollTo(0, 800)
-      }
-    }
-  }
-}
-</script>
-
-<style scoped>
-.pagination-container {
-  background: #fff;
-  padding: 32px 16px;
-}
-.pagination-container.hidden {
-  display: none;
-}
-</style>
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 20, 30, 50]
+      }
+    },
+    layout: {
+      type: String,
+      default: 'total, sizes, prev, pager, next, jumper'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(val) {
+      this.$emit('pagination', { page: this.currentPage, limit: val })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(val) {
+      this.$emit('pagination', { page: val, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>

+ 142 - 142
ruoyi-ui/src/components/PanThumb/index.vue

@@ -1,142 +1,142 @@
-<template>
-  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
-    <div class="pan-info">
-      <div class="pan-info-roles-container">
-        <slot />
-      </div>
-    </div>
-    <!-- eslint-disable-next-line -->
-    <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'PanThumb',
-  props: {
-    image: {
-      type: String,
-      required: true
-    },
-    zIndex: {
-      type: Number,
-      default: 1
-    },
-    width: {
-      type: String,
-      default: '150px'
-    },
-    height: {
-      type: String,
-      default: '150px'
-    }
-  }
-}
-</script>
-
-<style scoped>
-.pan-item {
-  width: 200px;
-  height: 200px;
-  border-radius: 50%;
-  display: inline-block;
-  position: relative;
-  cursor: default;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-}
-
-.pan-info-roles-container {
-  padding: 20px;
-  text-align: center;
-}
-
-.pan-thumb {
-  width: 100%;
-  height: 100%;
-  background-position: center center;
-  background-size: cover;
-  border-radius: 50%;
-  overflow: hidden;
-  position: absolute;
-  transform-origin: 95% 40%;
-  transition: all 0.3s ease-in-out;
-}
-
-/* .pan-thumb:after {
-  content: '';
-  width: 8px;
-  height: 8px;
-  position: absolute;
-  border-radius: 50%;
-  top: 40%;
-  left: 95%;
-  margin: -4px 0 0 -4px;
-  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
-  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
-} */
-
-.pan-info {
-  position: absolute;
-  width: inherit;
-  height: inherit;
-  border-radius: 50%;
-  overflow: hidden;
-  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
-}
-
-.pan-info h3 {
-  color: #fff;
-  text-transform: uppercase;
-  position: relative;
-  letter-spacing: 2px;
-  font-size: 18px;
-  margin: 0 60px;
-  padding: 22px 0 0 0;
-  height: 85px;
-  font-family: 'Open Sans', Arial, sans-serif;
-  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
-}
-
-.pan-info p {
-  color: #fff;
-  padding: 10px 5px;
-  font-style: italic;
-  margin: 0 30px;
-  font-size: 12px;
-  border-top: 1px solid rgba(255, 255, 255, 0.5);
-}
-
-.pan-info p a {
-  display: block;
-  color: #333;
-  width: 80px;
-  height: 80px;
-  background: rgba(255, 255, 255, 0.3);
-  border-radius: 50%;
-  color: #fff;
-  font-style: normal;
-  font-weight: 700;
-  text-transform: uppercase;
-  font-size: 9px;
-  letter-spacing: 1px;
-  padding-top: 24px;
-  margin: 7px auto 0;
-  font-family: 'Open Sans', Arial, sans-serif;
-  opacity: 0;
-  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
-  transform: translateX(60px) rotate(90deg);
-}
-
-.pan-info p a:hover {
-  background: rgba(255, 255, 255, 0.5);
-}
-
-.pan-item:hover .pan-thumb {
-  transform: rotate(-110deg);
-}
-
-.pan-item:hover .pan-info p a {
-  opacity: 1;
-  transform: translateX(0px) rotate(0deg);
-}
-</style>
+<template>
+  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+    <div class="pan-info">
+      <div class="pan-info-roles-container">
+        <slot />
+      </div>
+    </div>
+    <!-- eslint-disable-next-line -->
+    <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'PanThumb',
+  props: {
+    image: {
+      type: String,
+      required: true
+    },
+    zIndex: {
+      type: Number,
+      default: 1
+    },
+    width: {
+      type: String,
+      default: '150px'
+    },
+    height: {
+      type: String,
+      default: '150px'
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pan-item {
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  display: inline-block;
+  position: relative;
+  cursor: default;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+  padding: 20px;
+  text-align: center;
+}
+
+.pan-thumb {
+  width: 100%;
+  height: 100%;
+  background-position: center center;
+  background-size: cover;
+  border-radius: 50%;
+  overflow: hidden;
+  position: absolute;
+  transform-origin: 95% 40%;
+  transition: all 0.3s ease-in-out;
+}
+
+/* .pan-thumb:after {
+  content: '';
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  border-radius: 50%;
+  top: 40%;
+  left: 95%;
+  margin: -4px 0 0 -4px;
+  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+} */
+
+.pan-info {
+  position: absolute;
+  width: inherit;
+  height: inherit;
+  border-radius: 50%;
+  overflow: hidden;
+  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+  color: #fff;
+  text-transform: uppercase;
+  position: relative;
+  letter-spacing: 2px;
+  font-size: 18px;
+  margin: 0 60px;
+  padding: 22px 0 0 0;
+  height: 85px;
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+  color: #fff;
+  padding: 10px 5px;
+  font-style: italic;
+  margin: 0 30px;
+  font-size: 12px;
+  border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+  display: block;
+  color: #333;
+  width: 80px;
+  height: 80px;
+  background: rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  color: #fff;
+  font-style: normal;
+  font-weight: 700;
+  text-transform: uppercase;
+  font-size: 9px;
+  letter-spacing: 1px;
+  padding-top: 24px;
+  margin: 7px auto 0;
+  font-family: 'Open Sans', Arial, sans-serif;
+  opacity: 0;
+  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+  transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+  background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+  transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+  opacity: 1;
+  transform: translateX(0px) rotate(0deg);
+}
+</style>

+ 3 - 3
ruoyi-ui/src/components/ParentView/index.vue

@@ -1,3 +1,3 @@
-<template >
-  <router-view />
-</template>
+<template >
+  <router-view />
+</template>

+ 149 - 149
ruoyi-ui/src/components/RightPanel/index.vue

@@ -1,149 +1,149 @@
-<template>
-  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
-    <div class="rightPanel-background" />
-    <div class="rightPanel">
-      <div class="rightPanel-items">
-        <slot />
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import { addClass, removeClass } from '@/utils'
-
-export default {
-  name: 'RightPanel',
-  props: {
-    clickNotClose: {
-      default: false,
-      type: Boolean
-    },
-    buttonTop: {
-      default: 250,
-      type: Number
-    }
-  },
-  computed: {
-    show: {
-      get() {
-        return this.$store.state.settings.showSettings
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
-      }
-    },
-    theme() {
-      return this.$store.state.settings.theme
-    },
-  },
-  watch: {
-    show(value) {
-      if (value && !this.clickNotClose) {
-        this.addEventClick()
-      }
-      if (value) {
-        addClass(document.body, 'showRightPanel')
-      } else {
-        removeClass(document.body, 'showRightPanel')
-      }
-    }
-  },
-  mounted() {
-    this.insertToBody()
-    this.addEventClick()
-  },
-  beforeDestroy() {
-    const elx = this.$refs.rightPanel
-    elx.remove()
-  },
-  methods: {
-    addEventClick() {
-      window.addEventListener('click', this.closeSidebar)
-    },
-    closeSidebar(evt) {
-      const parent = evt.target.closest('.rightPanel')
-      if (!parent) {
-        this.show = false
-        window.removeEventListener('click', this.closeSidebar)
-      }
-    },
-    insertToBody() {
-      const elx = this.$refs.rightPanel
-      const body = document.querySelector('body')
-      body.insertBefore(elx, body.firstChild)
-    }
-  }
-}
-</script>
-
-<style>
-.showRightPanel {
-  overflow: hidden;
-  position: relative;
-  width: calc(100% - 15px);
-}
-</style>
-
-<style lang="scss" scoped>
-.rightPanel-background {
-  position: fixed;
-  top: 0;
-  left: 0;
-  opacity: 0;
-  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
-  background: rgba(0, 0, 0, .2);
-  z-index: -1;
-}
-
-.rightPanel {
-  width: 100%;
-  max-width: 260px;
-  height: 100vh;
-  position: fixed;
-  top: 0;
-  right: 0;
-  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
-  transition: all .25s cubic-bezier(.7, .3, .1, 1);
-  transform: translate(100%);
-  background: #fff;
-  z-index: 40000;
-}
-
-.show {
-  transition: all .3s cubic-bezier(.7, .3, .1, 1);
-
-  .rightPanel-background {
-    z-index: 20000;
-    opacity: 1;
-    width: 100%;
-    height: 100%;
-  }
-
-  .rightPanel {
-    transform: translate(0);
-  }
-}
-
-.handle-button {
-  width: 48px;
-  height: 48px;
-  position: absolute;
-  left: -48px;
-  text-align: center;
-  font-size: 24px;
-  border-radius: 6px 0 0 6px !important;
-  z-index: 0;
-  pointer-events: auto;
-  cursor: pointer;
-  color: #fff;
-  line-height: 48px;
-  i {
-    font-size: 24px;
-    line-height: 48px;
-  }
-}
-</style>
+<template>
+  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/utils'
+
+export default {
+  name: 'RightPanel',
+  props: {
+    clickNotClose: {
+      default: false,
+      type: Boolean
+    },
+    buttonTop: {
+      default: 250,
+      type: Number
+    }
+  },
+  computed: {
+    show: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    },
+    theme() {
+      return this.$store.state.settings.theme
+    },
+  },
+  watch: {
+    show(value) {
+      if (value && !this.clickNotClose) {
+        this.addEventClick()
+      }
+      if (value) {
+        addClass(document.body, 'showRightPanel')
+      } else {
+        removeClass(document.body, 'showRightPanel')
+      }
+    }
+  },
+  mounted() {
+    this.insertToBody()
+    this.addEventClick()
+  },
+  beforeDestroy() {
+    const elx = this.$refs.rightPanel
+    elx.remove()
+  },
+  methods: {
+    addEventClick() {
+      window.addEventListener('click', this.closeSidebar)
+    },
+    closeSidebar(evt) {
+      const parent = evt.target.closest('.rightPanel')
+      if (!parent) {
+        this.show = false
+        window.removeEventListener('click', this.closeSidebar)
+      }
+    },
+    insertToBody() {
+      const elx = this.$refs.rightPanel
+      const body = document.querySelector('body')
+      body.insertBefore(elx, body.firstChild)
+    }
+  }
+}
+</script>
+
+<style>
+.showRightPanel {
+  overflow: hidden;
+  position: relative;
+  width: calc(100% - 15px);
+}
+</style>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.show {
+  transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+  .rightPanel-background {
+    z-index: 20000;
+    opacity: 1;
+    width: 100%;
+    height: 100%;
+  }
+
+  .rightPanel {
+    transform: translate(0);
+  }
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>

+ 80 - 80
ruoyi-ui/src/components/RightToolbar/index.vue

@@ -1,80 +1,80 @@
-<template>
-  <div class="top-right-btn">
-    <el-row>
-      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
-        <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
-      </el-tooltip>
-      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
-        <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
-      </el-tooltip>
-      <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
-        <el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" />
-      </el-tooltip>
-    </el-row>
-    <el-dialog :title="title" :visible.sync="open" append-to-body>
-      <el-transfer
-        :titles="['显示', '隐藏']"
-        v-model="value"
-        :data="columns"
-        @change="dataChange"
-      ></el-transfer>
-    </el-dialog>
-  </div>
-</template>
-<script>
-export default {
-  name: "RightToolbar",
-  data() {
-    return {
-      // 显隐数据
-      value: [],
-      // 弹出层标题
-      title: "显示/隐藏",
-      // 是否显示弹出层
-      open: false,
-    };
-  },
-  props: {
-    showSearch: {
-      type: Boolean,
-      default: true,
-    },
-    columns: {
-      type: Array,
-    },
-  },
-
-  methods: {
-    // 搜索
-    toggleSearch() {
-      this.$emit("update:showSearch", !this.showSearch);
-    },
-    // 刷新
-    refresh() {
-      this.$emit("queryTable");
-    },
-    // 右侧列表元素变化
-    dataChange(data) {
-      for (var item in this.columns) {
-        const key = this.columns[item].key;
-        this.columns[item].visible = !data.includes(key);
-      }
-    },
-    // 打开显隐列dialog
-    showColumn() {
-      this.open = true;
-    },
-  },
-};
-</script>
-<style lang="scss" scoped>
-::v-deep .el-transfer__button {
-  border-radius: 50%;
-  padding: 12px;
-  display: block;
-  margin-left: 0px;
-}
-::v-deep .el-transfer__button:first-child {
-  margin-bottom: 10px;
-}
-</style>
+<template>
+  <div class="top-right-btn">
+    <el-row>
+      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
+        <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
+        <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
+        <el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" />
+      </el-tooltip>
+    </el-row>
+    <el-dialog :title="title" :visible.sync="open" append-to-body>
+      <el-transfer
+        :titles="['显示', '隐藏']"
+        v-model="value"
+        :data="columns"
+        @change="dataChange"
+      ></el-transfer>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  name: "RightToolbar",
+  data() {
+    return {
+      // 显隐数据
+      value: [],
+      // 弹出层标题
+      title: "显示/隐藏",
+      // 是否显示弹出层
+      open: false,
+    };
+  },
+  props: {
+    showSearch: {
+      type: Boolean,
+      default: true,
+    },
+    columns: {
+      type: Array,
+    },
+  },
+
+  methods: {
+    // 搜索
+    toggleSearch() {
+      this.$emit("update:showSearch", !this.showSearch);
+    },
+    // 刷新
+    refresh() {
+      this.$emit("queryTable");
+    },
+    // 右侧列表元素变化
+    dataChange(data) {
+      for (var item in this.columns) {
+        const key = this.columns[item].key;
+        this.columns[item].visible = !data.includes(key);
+      }
+    },
+    // 打开显隐列dialog
+    showColumn() {
+      this.open = true;
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-transfer__button {
+  border-radius: 50%;
+  padding: 12px;
+  display: block;
+  margin-left: 0px;
+}
+::v-deep .el-transfer__button:first-child {
+  margin-bottom: 10px;
+}
+</style>

+ 20 - 20
ruoyi-ui/src/components/RuoYi/Doc/index.vue

@@ -1,21 +1,21 @@
-<template>
-  <div>
-    <svg-icon icon-class="question" @click="goto"/>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RuoYiDoc',
-  data() {
-    return {
-      url: 'http://doc.ruoyi.vip/ruoyi-vue'
-    }
-  },
-  methods: {
-    goto() {
-      window.open(this.url)
-    }
-  }
-}
+<template>
+  <div>
+    <svg-icon icon-class="question" @click="goto"/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RuoYiDoc',
+  data() {
+    return {
+      url: 'http://doc.ruoyi.vip/ruoyi-vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
 </script>

+ 20 - 20
ruoyi-ui/src/components/RuoYi/Git/index.vue

@@ -1,21 +1,21 @@
-<template>
-  <div>
-    <svg-icon icon-class="github" @click="goto"/>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RuoYiGit',
-  data() {
-    return {
-      url: 'https://gitee.com/y_project/RuoYi-Vue'
-    }
-  },
-  methods: {
-    goto() {
-      window.open(this.url)
-    }
-  }
-}
+<template>
+  <div>
+    <svg-icon icon-class="github" @click="goto"/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RuoYiGit',
+  data() {
+    return {
+      url: 'https://gitee.com/y_project/RuoYi-Vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
 </script>

+ 57 - 57
ruoyi-ui/src/components/Screenfull/index.vue

@@ -1,57 +1,57 @@
-<template>
-  <div>
-    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
-  </div>
-</template>
-
-<script>
-import screenfull from 'screenfull'
-
-export default {
-  name: 'Screenfull',
-  data() {
-    return {
-      isFullscreen: false
-    }
-  },
-  mounted() {
-    this.init()
-  },
-  beforeDestroy() {
-    this.destroy()
-  },
-  methods: {
-    click() {
-      if (!screenfull.isEnabled) {
-        this.$message({ message: '你的浏览器不支持全屏', type: 'warning' })
-        return false
-      }
-      screenfull.toggle()
-    },
-    change() {
-      this.isFullscreen = screenfull.isFullscreen
-    },
-    init() {
-      if (screenfull.isEnabled) {
-        screenfull.on('change', this.change)
-      }
-    },
-    destroy() {
-      if (screenfull.isEnabled) {
-        screenfull.off('change', this.change)
-      }
-    }
-  }
-}
-</script>
-
-<style scoped>
-.screenfull-svg {
-  display: inline-block;
-  cursor: pointer;
-  fill: #5a5e66;;
-  width: 20px;
-  height: 20px;
-  vertical-align: 10px;
-}
-</style>
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'Screenfull',
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  mounted() {
+    this.init()
+  },
+  beforeDestroy() {
+    this.destroy()
+  },
+  methods: {
+    click() {
+      if (!screenfull.isEnabled) {
+        this.$message({ message: '你的浏览器不支持全屏', type: 'warning' })
+        return false
+      }
+      screenfull.toggle()
+    },
+    change() {
+      this.isFullscreen = screenfull.isFullscreen
+    },
+    init() {
+      if (screenfull.isEnabled) {
+        screenfull.on('change', this.change)
+      }
+    },
+    destroy() {
+      if (screenfull.isEnabled) {
+        screenfull.off('change', this.change)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 136 - 136
ruoyi-ui/src/components/SignNumArr/index.vue

@@ -1,136 +1,136 @@
-<template>
-  <div class="sign_box">
-    <div class="sign_item" :class="{active: activeMenu.includes((item.path||item.redirect))}" v-for="item in this.sidebarRouters.filter(res => {
-          return res.hidden == false || res.redirect == 'index'
-        })"
-      @click="tabBtn(item)">
-     <!-- <img src="@/assets/images/pic_tabbg@2x.png" draggable="false" v-show="activeMenu.includes((item.path||item.redirect))"
-        alt="" class="img"> -->
-      <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
-      <item v-if="!item.meta" :icon="item.meta && item.meta.icon" :title="'首页'" />
-    </div>
-  </div>
-</template>
-
-<script>
-  import {
-    mapGetters,
-    mapState
-  } from "vuex";
-  import Item from '@/layout/components/Sidebar/Item'
-
-  export default {
-    data() {
-      return {
-        indexs: 1,
-        newArr: [],
-      }
-    },
-    components: {
-      Item
-    },
-    computed: {
-      ...mapGetters(["sidebarRouters", "sidebar", "tabIndex"]),
-      activeMenu() {
-        // const route = this.$route;
-        // const { meta, path } = route;
-        // // if set path, the sidebar will highlight the path you set
-        // if (meta.activeMenu) {
-        //     return meta.activeMenu;
-        // }
-        return this.tabIndex;
-      },
-    },
-    mounted() {
-      this.init()
-    },
-    watch: {
-
-    },
-    methods: {
-      tabBtn(item) {
-        if(this.activeMenu.includes((item.path||item.redirect))){
-          return
-        }
-        if (item.redirect == 'index') {
-          if(this.$route.path!=='/index'){
-            this.$router.push({
-              path: '/index'
-            })
-          }
-          this.$store.dispatch('TabFn', item.redirect)
-          return
-        }
-        this.$store.dispatch('TabFn', item.path)
-      },
-      init() {
-        const route = this.$route;
-        const {
-          meta,
-          path
-        } = route;
-        // if set path, the sidebar will highlight the path you set
-        console.log(route)
-        if (meta.activeMenu) {
-          this.$store.dispatch('TabFn', meta.activeMenu)
-        }
-        this.$store.dispatch('TabFn', path)
-      }
-    }
-  }
-</script>
-
-<style lang="scss" scoped>
-  .sign_box {
-    // padding-left: 12px;
-    width: calc(100% - 160px);
-    overflow-x: scroll;
-     white-space: nowrap;
-
-    .sign_item {
-      cursor: pointer;
-      float: left;
-      display: inline-table;
-      height: 50px;
-      text-align: center;
-      line-height: 50px;
-      position: relative;
-      width: 143px;
-      box-sizing: border-box;
-      color: #fff;
-
-      .img {
-        width: 153px;
-        height: 48px;
-        position: absolute;
-        left: 0;
-        bottom: 0;
-      }
-
-      .icon {
-        position: relative;
-        z-index: 1;
-        width: 16px;
-        height: 16px;
-        margin-right: 8px;
-      }
-
-      span {
-        position: relative;
-        z-index: 1;
-        color: #fff !important;
-        font-size: 16px !important;
-      }
-
-      svg {
-        color: #fff !important;
-        z-index: 2;
-        line-height: 1;
-        margin-right: 5px;
-      }
-    }
-  }
-  .active{
-    background-color: #367FA8!important;
-  }
-</style>
+<template>
+  <div class="sign_box">
+    <div class="sign_item" :class="{active: activeMenu.includes((item.path||item.redirect))}" v-for="item in this.sidebarRouters.filter(res => {
+          return res.hidden == false || res.redirect == 'index'
+        })"
+      @click="tabBtn(item)">
+     <!-- <img src="@/assets/images/pic_tabbg@2x.png" draggable="false" v-show="activeMenu.includes((item.path||item.redirect))"
+        alt="" class="img"> -->
+      <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+      <item v-if="!item.meta" :icon="item.meta && item.meta.icon" :title="'首页'" />
+    </div>
+  </div>
+</template>
+
+<script>
+  import {
+    mapGetters,
+    mapState
+  } from "vuex";
+  import Item from '@/layout/components/Sidebar/Item'
+
+  export default {
+    data() {
+      return {
+        indexs: 1,
+        newArr: [],
+      }
+    },
+    components: {
+      Item
+    },
+    computed: {
+      ...mapGetters(["sidebarRouters", "sidebar", "tabIndex"]),
+      activeMenu() {
+        // const route = this.$route;
+        // const { meta, path } = route;
+        // // if set path, the sidebar will highlight the path you set
+        // if (meta.activeMenu) {
+        //     return meta.activeMenu;
+        // }
+        return this.tabIndex;
+      },
+    },
+    mounted() {
+      this.init()
+    },
+    watch: {
+
+    },
+    methods: {
+      tabBtn(item) {
+        if(this.activeMenu.includes((item.path||item.redirect))){
+          return
+        }
+        if (item.redirect == 'index') {
+          if(this.$route.path!=='/index'){
+            this.$router.push({
+              path: '/index'
+            })
+          }
+          this.$store.dispatch('TabFn', item.redirect)
+          return
+        }
+        this.$store.dispatch('TabFn', item.path)
+      },
+      init() {
+        const route = this.$route;
+        const {
+          meta,
+          path
+        } = route;
+        // if set path, the sidebar will highlight the path you set
+        console.log(route)
+        if (meta.activeMenu) {
+          this.$store.dispatch('TabFn', meta.activeMenu)
+        }
+        this.$store.dispatch('TabFn', path)
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .sign_box {
+    // padding-left: 12px;
+    width: calc(100% - 160px);
+    overflow-x: scroll;
+     white-space: nowrap;
+
+    .sign_item {
+      cursor: pointer;
+      float: left;
+      display: inline-table;
+      height: 50px;
+      text-align: center;
+      line-height: 50px;
+      position: relative;
+      width: 143px;
+      box-sizing: border-box;
+      color: #fff;
+
+      .img {
+        width: 153px;
+        height: 48px;
+        position: absolute;
+        left: 0;
+        bottom: 0;
+      }
+
+      .icon {
+        position: relative;
+        z-index: 1;
+        width: 16px;
+        height: 16px;
+        margin-right: 8px;
+      }
+
+      span {
+        position: relative;
+        z-index: 1;
+        color: #fff !important;
+        font-size: 16px !important;
+      }
+
+      svg {
+        color: #fff !important;
+        z-index: 2;
+        line-height: 1;
+        margin-right: 5px;
+      }
+    }
+  }
+  .active{
+    background-color: #367FA8!important;
+  }
+</style>

+ 57 - 57
ruoyi-ui/src/components/SizeSelect/index.vue

@@ -1,57 +1,57 @@
-<template>
-  <el-dropdown trigger="click" @command="handleSetSize">
-    <div>
-      <svg-icon class-name="size-icon" icon-class="size" />
-    </div>
-    <el-dropdown-menu slot="dropdown">
-      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
-        {{
-          item.label }}
-      </el-dropdown-item>
-    </el-dropdown-menu>
-  </el-dropdown>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      sizeOptions: [
-        { label: 'Default', value: 'default' },
-        { label: 'Medium', value: 'medium' },
-        { label: 'Small', value: 'small' },
-        { label: 'Mini', value: 'mini' }
-      ]
-    }
-  },
-  computed: {
-    size() {
-      return this.$store.getters.size
-    }
-  },
-  methods: {
-    handleSetSize(size) {
-      this.$ELEMENT.size = size
-      this.$store.dispatch('app/setSize', size)
-      this.refreshView()
-      this.$message({
-        message: 'Switch Size Success',
-        type: 'success'
-      })
-    },
-    refreshView() {
-      // In order to make the cached page re-rendered
-      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
-
-      const { fullPath } = this.$route
-
-      this.$nextTick(() => {
-        this.$router.replace({
-          path: '/redirect' + fullPath
-        })
-      })
-    }
-  }
-
-}
-</script>
+<template>
+  <el-dropdown trigger="click" @command="handleSetSize">
+    <div>
+      <svg-icon class-name="size-icon" icon-class="size" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+        {{
+          item.label }}
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      sizeOptions: [
+        { label: 'Default', value: 'default' },
+        { label: 'Medium', value: 'medium' },
+        { label: 'Small', value: 'small' },
+        { label: 'Mini', value: 'mini' }
+      ]
+    }
+  },
+  computed: {
+    size() {
+      return this.$store.getters.size
+    }
+  },
+  methods: {
+    handleSetSize(size) {
+      this.$ELEMENT.size = size
+      this.$store.dispatch('app/setSize', size)
+      this.refreshView()
+      this.$message({
+        message: 'Switch Size Success',
+        type: 'success'
+      })
+    },
+    refreshView() {
+      // In order to make the cached page re-rendered
+      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+      const { fullPath } = this.$route
+
+      this.$nextTick(() => {
+        this.$router.replace({
+          path: '/redirect' + fullPath
+        })
+      })
+    }
+  }
+
+}
+</script>

+ 61 - 61
ruoyi-ui/src/components/SvgIcon/index.vue

@@ -1,61 +1,61 @@
-<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>
-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>
+<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>
+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>

+ 71 - 71
ruoyi-ui/src/components/TabForm/index.vue

@@ -1,37 +1,37 @@
 <template>
-    <el-form-item :label="formConfig.columnComment" style="display: inline-block;" :prop="formConfig.columnName">
-      <!-- 输入框 -->
-      <el-input v-if="formConfig.htmlType == 'input'" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
-        clearable @keyup.enter.native="handleQuery" />
-      <!-- 多行输入框 -->
-      <el-input v-if="formConfig.htmlType == 'textarea'" type="textarea" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
-        clearable @keyup.enter.native="handleQuery" />
-      <!-- 下拉框 -->
-      <el-select v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'select'" filterable :placeholder="'请输入'+formConfig.columnComment">
-        <el-option v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue">
-        </el-option>
-      </el-select>
+    <el-form-item :label="formConfig.columnComment" style="display: inline-block;" :prop="formConfig.columnName">
+      <!-- 输入框 -->
+      <el-input v-if="formConfig.htmlType == 'input'" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
+        clearable @keyup.enter.native="handleQuery" />
+      <!-- 多行输入框 -->
+      <el-input v-if="formConfig.htmlType == 'textarea'" type="textarea" v-model="config[formConfig.columnName]" :placeholder="'请输入'+formConfig.columnComment"
+        clearable @keyup.enter.native="handleQuery" />
+      <!-- 下拉框 -->
+      <el-select v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'select'" filterable :placeholder="'请输入'+formConfig.columnComment">
+        <el-option v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue">
+        </el-option>
+      </el-select>
       <!-- 复选框 -->
-      <el-checkbox-group v-model="formConfig.sysDictDatatwo" v-if="formConfig.htmlType == 'checkbox'">
-        <el-checkbox @change="handleCheckedCitiesChange" v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel"
-        :value="itemChild.dictValue" ></el-checkbox>
-      </el-checkbox-group>
-      <!-- 单选框 -->
-      <el-radio-group v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'radio'">
-        <el-radio v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue"></el-radio>
-      </el-radio-group>
-      <!-- 时间控件 -->
-      <el-date-picker v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'datetime'" type="date" :placeholder="'请输入'+formConfig.columnComment">
-      </el-date-picker>
-      <!-- 上传图片 -->
-      <el-upload v-if="formConfig.htmlType == 'imageUpload'" :headers="{Authorization: 'Bearer ' + getToken()}" :action="process + '/boman-file/upload'" list-type="picture-card"
-        :on-preview="handlePictureCardPreview" :on-remove="handleRemove">
-        <i class="el-icon-plus"></i>
-      </el-upload>
-      <el-dialog :visible.sync="dialogVisible" v-if="formConfig.htmlType == 'imageUpload'">
-        <img width="100%" :src="dialogImageUrl" alt="">
-      </el-dialog>
-      <!-- 上传文件 -->
+      <el-checkbox-group v-model="formConfig.sysDictDatatwo" v-if="formConfig.htmlType == 'checkbox'">
+        <el-checkbox @change="handleCheckedCitiesChange" v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel"
+        :value="itemChild.dictValue" ></el-checkbox>
+      </el-checkbox-group>
+      <!-- 单选框 -->
+      <el-radio-group v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'radio'">
+        <el-radio v-for="itemChild in formConfig.sysDictData" :key="itemChild.dictValue" :label="itemChild.dictLabel" :value="itemChild.dictValue"></el-radio>
+      </el-radio-group>
+      <!-- 时间控件 -->
+      <el-date-picker v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'datetime'" type="date" :placeholder="'请输入'+formConfig.columnComment">
+      </el-date-picker>
+      <!-- 上传图片 -->
+      <el-upload v-if="formConfig.htmlType == 'imageUpload'" :headers="{Authorization: 'Bearer ' + getToken()}" :action="process + '/boman-file/upload'" list-type="picture-card"
+        :on-preview="handlePictureCardPreview" :on-remove="handleRemove">
+        <i class="el-icon-plus"></i>
+      </el-upload>
+      <el-dialog :visible.sync="dialogVisible" v-if="formConfig.htmlType == 'imageUpload'">
+        <img width="100%" :src="dialogImageUrl" alt="">
+      </el-dialog>
+      <!-- 上传文件 -->
       <el-upload
         class="upload-demo"
         :headers="{Authorization: 'Bearer ' + getToken()}"
@@ -44,70 +44,70 @@
       </el-upload>
       <!-- 富文本 -->
       <editor v-model="config[formConfig.columnName]" v-if="formConfig.htmlType == 'editor'" :min-height="192"/>
-      123
+      123
     </el-form-item>
    
-</template>
-
-<script>
+</template>
+
+<script>
   const defaultSettings = require('@/settings.js')
   import Editor from '@/components/Editor';
   import { getToken } from "@/utils/auth";
-  export default {
-    data() {
+  export default {
+    data() {
       return {
-        fileList: [],
-        defaultSettings,
+        fileList: [],
+        defaultSettings,
         dialogImageUrl: '',
-        process: process.env.VUE_APP_BASE_API,
-        dialogVisible: false,
+        process: process.env.VUE_APP_BASE_API,
+        dialogVisible: false,
         disabled: false,
         config: {},
-      }
+      }
     },
     components: {
       Editor
-    },
-    props: {
-      formConfig: {
-        type: Object,
+    },
+    props: {
+      formConfig: {
+        type: Object,
         required: true,
         'default': {
           sysDictData: []
-        }
-      },
+        }
+      },
     },
     created() {
     console.log(this.formConfig)
-    },
-    mounted() {
-    },
+    },
+    mounted() {
+    },
     methods: {
       handleChange(file, fileList) {
         this.fileList = fileList.slice(-3);
       },
       getToken() {
         return getToken()
-      },
-      handleRemove(file, fileList) {
-        console.log(file, fileList);
-      },
-      handlePictureCardPreview(file) {
-        this.dialogImageUrl = file.url;
-        this.dialogVisible = true;
-      },
-      handleDownload(file) {
-        console.log(file);
-      },
-      handleQuery() {
-        this.$emit('btns')
+      },
+      handleRemove(file, fileList) {
+        console.log(file, fileList);
+      },
+      handlePictureCardPreview(file) {
+        this.dialogImageUrl = file.url;
+        this.dialogVisible = true;
+      },
+      handleDownload(file) {
+        console.log(file);
+      },
+      handleQuery() {
+        this.$emit('btns')
       },
       handleCheckedCitiesChange(value){
         console.log(value)
-      }
-    }
-  }
-</script>
-
-<style>
+      }
+    }
+  }
+</script>
+
+<style>
 </style>

+ 175 - 175
ruoyi-ui/src/components/ThemePicker/index.vue

@@ -1,175 +1,175 @@
-<template>
-  <el-color-picker
-    v-model="theme"
-    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
-    class="theme-picker"
-    popper-class="theme-picker-dropdown"
-  />
-</template>
-
-<script>
-const version = require('element-ui/package.json').version // element-ui version from node_modules
-const ORIGINAL_THEME = '#409EFF' // default color
-
-export default {
-  data() {
-    return {
-      chalk: '', // content of theme-chalk css
-      theme: ''
-    }
-  },
-  computed: {
-    defaultTheme() {
-      return this.$store.state.settings.theme
-    }
-  },
-  watch: {
-    defaultTheme: {
-      handler: function(val, oldVal) {
-        this.theme = val
-      },
-      immediate: true
-    },
-    async theme(val) {
-      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
-      if (typeof val !== 'string') return
-      const themeCluster = this.getThemeCluster(val.replace('#', ''))
-      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
-      console.log(themeCluster, originalCluster)
-
-      const $message = this.$message({
-        message: '  Compiling the theme',
-        customClass: 'theme-message',
-        type: 'success',
-        duration: 0,
-        iconClass: 'el-icon-loading'
-      })
-
-      const getHandler = (variable, id) => {
-        return () => {
-          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
-          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
-
-          let styleTag = document.getElementById(id)
-          if (!styleTag) {
-            styleTag = document.createElement('style')
-            styleTag.setAttribute('id', id)
-            document.head.appendChild(styleTag)
-          }
-          styleTag.innerText = newStyle
-        }
-      }
-
-      if (!this.chalk) {
-        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
-        await this.getCSSString(url, 'chalk')
-      }
-
-      const chalkHandler = getHandler('chalk', 'chalk-style')
-
-      chalkHandler()
-
-      const styles = [].slice.call(document.querySelectorAll('style'))
-        .filter(style => {
-          const text = style.innerText
-          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
-        })
-      styles.forEach(style => {
-        const { innerText } = style
-        if (typeof innerText !== 'string') return
-        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
-      })
-
-      this.$emit('change', val)
-
-      $message.close()
-    }
-  },
-
-  methods: {
-    updateStyle(style, oldCluster, newCluster) {
-      let newStyle = style
-      oldCluster.forEach((color, index) => {
-        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
-      })
-      return newStyle
-    },
-
-    getCSSString(url, variable) {
-      return new Promise(resolve => {
-        const xhr = new XMLHttpRequest()
-        xhr.onreadystatechange = () => {
-          if (xhr.readyState === 4 && xhr.status === 200) {
-            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
-            resolve()
-          }
-        }
-        xhr.open('GET', url)
-        xhr.send()
-      })
-    },
-
-    getThemeCluster(theme) {
-      const tintColor = (color, tint) => {
-        let red = parseInt(color.slice(0, 2), 16)
-        let green = parseInt(color.slice(2, 4), 16)
-        let blue = parseInt(color.slice(4, 6), 16)
-
-        if (tint === 0) { // when primary color is in its rgb space
-          return [red, green, blue].join(',')
-        } else {
-          red += Math.round(tint * (255 - red))
-          green += Math.round(tint * (255 - green))
-          blue += Math.round(tint * (255 - blue))
-
-          red = red.toString(16)
-          green = green.toString(16)
-          blue = blue.toString(16)
-
-          return `#${red}${green}${blue}`
-        }
-      }
-
-      const shadeColor = (color, shade) => {
-        let red = parseInt(color.slice(0, 2), 16)
-        let green = parseInt(color.slice(2, 4), 16)
-        let blue = parseInt(color.slice(4, 6), 16)
-
-        red = Math.round((1 - shade) * red)
-        green = Math.round((1 - shade) * green)
-        blue = Math.round((1 - shade) * blue)
-
-        red = red.toString(16)
-        green = green.toString(16)
-        blue = blue.toString(16)
-
-        return `#${red}${green}${blue}`
-      }
-
-      const clusters = [theme]
-      for (let i = 0; i <= 9; i++) {
-        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
-      }
-      clusters.push(shadeColor(theme, 0.1))
-      return clusters
-    }
-  }
-}
-</script>
-
-<style>
-.theme-message,
-.theme-picker-dropdown {
-  z-index: 99999 !important;
-}
-
-.theme-picker .el-color-picker__trigger {
-  height: 26px !important;
-  width: 26px !important;
-  padding: 2px;
-}
-
-.theme-picker-dropdown .el-color-dropdown__link-btn {
-  display: none;
-}
-</style>
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+  data() {
+    return {
+      chalk: '', // content of theme-chalk css
+      theme: ''
+    }
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    defaultTheme: {
+      handler: function(val, oldVal) {
+        this.theme = val
+      },
+      immediate: true
+    },
+    async theme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+      if (typeof val !== 'string') return
+      const themeCluster = this.getThemeCluster(val.replace('#', ''))
+      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+      console.log(themeCluster, originalCluster)
+
+      const $message = this.$message({
+        message: '  Compiling the theme',
+        customClass: 'theme-message',
+        type: 'success',
+        duration: 0,
+        iconClass: 'el-icon-loading'
+      })
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+          let styleTag = document.getElementById(id)
+          if (!styleTag) {
+            styleTag = document.createElement('style')
+            styleTag.setAttribute('id', id)
+            document.head.appendChild(styleTag)
+          }
+          styleTag.innerText = newStyle
+        }
+      }
+
+      if (!this.chalk) {
+        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+        await this.getCSSString(url, 'chalk')
+      }
+
+      const chalkHandler = getHandler('chalk', 'chalk-style')
+
+      chalkHandler()
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+        })
+      styles.forEach(style => {
+        const { innerText } = style
+        if (typeof innerText !== 'string') return
+        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+      })
+
+      this.$emit('change', val)
+
+      $message.close()
+    }
+  },
+
+  methods: {
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+      })
+      return newStyle
+    },
+
+    getCSSString(url, variable) {
+      return new Promise(resolve => {
+        const xhr = new XMLHttpRequest()
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+            resolve()
+          }
+        }
+        xhr.open('GET', url)
+        xhr.send()
+      })
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        if (tint === 0) { // when primary color is in its rgb space
+          return [red, green, blue].join(',')
+        } else {
+          red += Math.round(tint * (255 - red))
+          green += Math.round(tint * (255 - green))
+          blue += Math.round(tint * (255 - blue))
+
+          red = red.toString(16)
+          green = green.toString(16)
+          blue = blue.toString(16)
+
+          return `#${red}${green}${blue}`
+        }
+      }
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        red = Math.round((1 - shade) * red)
+        green = Math.round((1 - shade) * green)
+        blue = Math.round((1 - shade) * blue)
+
+        red = red.toString(16)
+        green = green.toString(16)
+        blue = blue.toString(16)
+
+        return `#${red}${green}${blue}`
+      }
+
+      const clusters = [theme]
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+      }
+      clusters.push(shadeColor(theme, 0.1))
+      return clusters
+    }
+  }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>

+ 28 - 28
ruoyi-ui/src/directive/permission/hasPermi.js

@@ -1,28 +1,28 @@
- /**
- * 操作权限处理
- * Copyright (c) 2019 ruoyi
- */
- 
-import store from '@/store'
-
-export default {
-  inserted(el, binding, vnode) {
-    const { value } = binding
-    const all_permission = "*:*:*";
-    const permissions = store.getters && store.getters.permissions
-
-    if (value && value instanceof Array && value.length > 0) {
-      const permissionFlag = value
-
-      const hasPermissions = permissions.some(permission => {
-        return all_permission === permission || permissionFlag.includes(permission)
-      })
-
-      if (!hasPermissions) {
-        el.parentNode && el.parentNode.removeChild(el)
-      }
-    } else {
-      throw new Error(`请设置操作权限标签值`)
-    }
-  }
-}
+ /**
+ * 操作权限处理
+ * Copyright (c) 2019 ruoyi
+ */
+ 
+import store from '@/store'
+
+export default {
+  inserted(el, binding, vnode) {
+    const { value } = binding
+    const all_permission = "*:*:*";
+    const permissions = store.getters && store.getters.permissions
+
+    if (value && value instanceof Array && value.length > 0) {
+      const permissionFlag = value
+
+      const hasPermissions = permissions.some(permission => {
+        return all_permission === permission || permissionFlag.includes(permission)
+      })
+
+      if (!hasPermissions) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    } else {
+      throw new Error(`请设置操作权限标签值`)
+    }
+  }
+}

+ 28 - 28
ruoyi-ui/src/directive/permission/hasRole.js

@@ -1,28 +1,28 @@
- /**
- * 角色权限处理
- * Copyright (c) 2019 ruoyi
- */
- 
-import store from '@/store'
-
-export default {
-  inserted(el, binding, vnode) {
-    const { value } = binding
-    const super_admin = "admin";
-    const roles = store.getters && store.getters.roles
-
-    if (value && value instanceof Array && value.length > 0) {
-      const roleFlag = value
-
-      const hasRole = roles.some(role => {
-        return super_admin === role || roleFlag.includes(role)
-      })
-
-      if (!hasRole) {
-        el.parentNode && el.parentNode.removeChild(el)
-      }
-    } else {
-      throw new Error(`请设置角色权限标签值"`)
-    }
-  }
-}
+ /**
+ * 角色权限处理
+ * Copyright (c) 2019 ruoyi
+ */
+ 
+import store from '@/store'
+
+export default {
+  inserted(el, binding, vnode) {
+    const { value } = binding
+    const super_admin = "admin";
+    const roles = store.getters && store.getters.roles
+
+    if (value && value instanceof Array && value.length > 0) {
+      const roleFlag = value
+
+      const hasRole = roles.some(role => {
+        return super_admin === role || roleFlag.includes(role)
+      })
+
+      if (!hasRole) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    } else {
+      throw new Error(`请设置角色权限标签值"`)
+    }
+  }
+}

+ 15 - 15
ruoyi-ui/src/directive/permission/index.js

@@ -1,15 +1,15 @@
-import hasRole from './hasRole'
-import hasPermi from './hasPermi'
-
-const install = function(Vue) {
-  Vue.directive('hasRole', hasRole)
-  Vue.directive('hasPermi', hasPermi)
-}
-
-if (window.Vue) {
-  window['hasRole'] = hasRole
-  window['hasPermi'] = hasPermi
-  Vue.use(install); // eslint-disable-line
-}
-
-export default install
+import hasRole from './hasRole'
+import hasPermi from './hasPermi'
+
+const install = function(Vue) {
+  Vue.directive('hasRole', hasRole)
+  Vue.directive('hasPermi', hasPermi)
+}
+
+if (window.Vue) {
+  window['hasRole'] = hasRole
+  window['hasPermi'] = hasPermi
+  Vue.use(install); // eslint-disable-line
+}
+
+export default install

+ 57 - 57
ruoyi-ui/src/layout/components/AppMain.vue

@@ -1,57 +1,57 @@
-<template>
-  <section class="app-main">
-    <transition name="fade-transform" mode="out-in">
-      <keep-alive :include="cachedViews">
-        <router-view :key="key" />
-      </keep-alive>
-    </transition>
-  </section>
-</template>
-
-<script>
-export default {
-  name: 'AppMain',
-  computed: {
-    cachedViews() {
-      return this.$store.state.tagsView.cachedViews
-    },
-    key() {
-      return this.$route.path
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.app-main {
-  /* 50= navbar  50  */
-  min-height: calc(100vh - 50px);
-  width: 100%;
-  position: relative;
-  overflow: hidden;
-}
-
-.fixed-header+.app-main {
-  padding-top: 50px;
-}
-
-.hasTagsView {
-  .app-main {
-    /* 84 = navbar + tags-view = 50 + 34 */
-    min-height: calc(100vh - 94px);
-  }
-
-  .fixed-header+.app-main {
-    padding-top: 84px;
-  }
-}
-</style>
-
-<style lang="scss">
-// fix css style bug in open el-dialog
-.el-popup-parent--hidden {
-  .fixed-header {
-    padding-right: 15px;
-  }
-}
-</style>
+<template>
+  <section class="app-main">
+    <transition name="fade-transform" mode="out-in">
+      <keep-alive :include="cachedViews">
+        <router-view :key="key" />
+      </keep-alive>
+    </transition>
+  </section>
+</template>
+
+<script>
+export default {
+  name: 'AppMain',
+  computed: {
+    cachedViews() {
+      return this.$store.state.tagsView.cachedViews
+    },
+    key() {
+      return this.$route.path
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-main {
+  /* 50= navbar  50  */
+  min-height: calc(100vh - 50px);
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+}
+
+.fixed-header+.app-main {
+  padding-top: 50px;
+}
+
+.hasTagsView {
+  .app-main {
+    /* 84 = navbar + tags-view = 50 + 34 */
+    min-height: calc(100vh - 94px);
+  }
+
+  .fixed-header+.app-main {
+    padding-top: 84px;
+  }
+}
+</style>
+
+<style lang="scss">
+// fix css style bug in open el-dialog
+.el-popup-parent--hidden {
+  .fixed-header {
+    padding-right: 15px;
+  }
+}
+</style>

+ 201 - 201
ruoyi-ui/src/layout/components/Navbar.vue

@@ -1,201 +1,201 @@
-<template>
-  <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
-
-    <!-- <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> -->
-
-      <SignNumArr class="SignNumArr"/>
-    <div class="right-menu">
-      <!-- <template v-if="device!=='mobile'">
-        <search id="header-search" class="right-menu-item" />
-
-        <el-tooltip content="源码地址" effect="dark" placement="bottom">
-          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <screenfull id="screenfull" class="right-menu-item hover-effect" />
-
-        <el-tooltip content="布局大小" effect="dark" placement="bottom">
-          <size-select id="size-select" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-      </template> -->
-
-      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
-        <div class="avatar-wrapper">
-          <img :src="avatar" class="user-avatar">
-		  <span></span>
-          <i class="el-icon-caret-bottom" />
-        </div>
-        <el-dropdown-menu slot="dropdown">
-          <router-link to="/user/profile">
-            <el-dropdown-item>个人中心</el-dropdown-item>
-          </router-link>
-          <el-dropdown-item @click.native="setting = true">
-            <span>布局设置</span>
-          </el-dropdown-item>
-          <el-dropdown-item divided @click.native="logout">
-            <span>退出登录</span>
-          </el-dropdown-item>
-        </el-dropdown-menu>
-      </el-dropdown>
-    </div>
-  </div>
-</template>
-
-<script>
-import { mapGetters } from 'vuex'
-import Breadcrumb from '@/components/Breadcrumb'
-import SignNumArr from '@/components/SignNumArr'
-import Hamburger from '@/components/Hamburger'
-import Screenfull from '@/components/Screenfull'
-import SizeSelect from '@/components/SizeSelect'
-import Search from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
-
-export default {
-  components: {
-    SignNumArr,
-    Hamburger,
-    Screenfull,
-    SizeSelect,
-    Search,
-    RuoYiGit,
-    RuoYiDoc
-  },
-  mounted() {
-  },
-  computed: {
-    ...mapGetters([
-      'sidebar',
-      'avatar',
-      'device'
-    ]),
-    setting: {
-      get() {
-        return this.$store.state.settings.showSettings
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
-      }
-    }
-  },
-  methods: {
-    toggleSideBar() {
-      this.$store.dispatch('app/toggleSideBar')
-    },
-    async logout() {
-      this.$confirm('确定注销并退出系统吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        this.$store.dispatch('LogOut').then(() => {
-          location.href = '/index';
-        })
-      })
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.navbar {
-  height: 50px;
-  overflow: hidden;
-  position: relative;
-  background-color: #3C8DBC;
-  box-shadow: 0 1px 4px rgba(0,21,41,.08);
-
-  .SignNumArr{
-    float: left;
-  }
-
-  .hamburger-container {
-    line-height: 46px;
-    height: 100%;
-    float: left;
-    cursor: pointer;
-    transition: background .3s;
-    color: #fff;
-    -webkit-tap-highlight-color:transparent;
-    svg{
-      color: #fff!important;
-    }
-
-    &:hover {
-      background: rgba(0, 0, 0, .025)
-    }
-  }
-
-  .breadcrumb-container {
-    float: left;
-  }
-
-  .errLog-container {
-    display: inline-block;
-    vertical-align: top;
-  }
-
-  .right-menu {
-    float: right;
-    height: 100%;
-    line-height: 50px;
-
-    &:focus {
-      outline: none;
-    }
-
-    .right-menu-item {
-      display: inline-block;
-      padding: 0 8px;
-      height: 100%;
-      font-size: 18px;
-      color: #5a5e66;
-      vertical-align: text-bottom;
-
-      &.hover-effect {
-        cursor: pointer;
-        transition: background .3s;
-
-        &:hover {
-          background: rgba(0, 0, 0, .025)
-        }
-      }
-    }
-
-    .avatar-container {
-      margin-right: 30px;
-
-      .avatar-wrapper {
-        margin-top: 5px;
-        position: relative;
-
-        .user-avatar {
-          cursor: pointer;
-          width: 40px;
-          height: 40px;
-          border-radius: 50%;
-        }
-
-        .el-icon-caret-bottom {
-          cursor: pointer;
-          position: absolute;
-          right: -20px;
-          top: 25px;
-          color: #fff;
-          font-size: 12px;
-        }
-      }
-    }
-  }
-}
-</style>
+<template>
+  <div class="navbar">
+    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+
+    <!-- <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> -->
+
+      <SignNumArr class="SignNumArr"/>
+    <div class="right-menu">
+      <!-- <template v-if="device!=='mobile'">
+        <search id="header-search" class="right-menu-item" />
+
+        <el-tooltip content="源码地址" effect="dark" placement="bottom">
+          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+        <el-tooltip content="文档地址" effect="dark" placement="bottom">
+          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+        <screenfull id="screenfull" class="right-menu-item hover-effect" />
+
+        <el-tooltip content="布局大小" effect="dark" placement="bottom">
+          <size-select id="size-select" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+      </template> -->
+
+      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
+        <div class="avatar-wrapper">
+          <img :src="avatar" class="user-avatar">
+		  <span></span>
+          <i class="el-icon-caret-bottom" />
+        </div>
+        <el-dropdown-menu slot="dropdown">
+          <router-link to="/user/profile">
+            <el-dropdown-item>个人中心</el-dropdown-item>
+          </router-link>
+          <el-dropdown-item @click.native="setting = true">
+            <span>布局设置</span>
+          </el-dropdown-item>
+          <el-dropdown-item divided @click.native="logout">
+            <span>退出登录</span>
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Breadcrumb from '@/components/Breadcrumb'
+import SignNumArr from '@/components/SignNumArr'
+import Hamburger from '@/components/Hamburger'
+import Screenfull from '@/components/Screenfull'
+import SizeSelect from '@/components/SizeSelect'
+import Search from '@/components/HeaderSearch'
+import RuoYiGit from '@/components/RuoYi/Git'
+import RuoYiDoc from '@/components/RuoYi/Doc'
+
+export default {
+  components: {
+    SignNumArr,
+    Hamburger,
+    Screenfull,
+    SizeSelect,
+    Search,
+    RuoYiGit,
+    RuoYiDoc
+  },
+  mounted() {
+  },
+  computed: {
+    ...mapGetters([
+      'sidebar',
+      'avatar',
+      'device'
+    ]),
+    setting: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    }
+  },
+  methods: {
+    toggleSideBar() {
+      this.$store.dispatch('app/toggleSideBar')
+    },
+    async logout() {
+      this.$confirm('确定注销并退出系统吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$store.dispatch('LogOut').then(() => {
+          location.href = '/index';
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.navbar {
+  height: 50px;
+  overflow: hidden;
+  position: relative;
+  background-color: #3C8DBC;
+  box-shadow: 0 1px 4px rgba(0,21,41,.08);
+
+  .SignNumArr{
+    float: left;
+  }
+
+  .hamburger-container {
+    line-height: 46px;
+    height: 100%;
+    float: left;
+    cursor: pointer;
+    transition: background .3s;
+    color: #fff;
+    -webkit-tap-highlight-color:transparent;
+    svg{
+      color: #fff!important;
+    }
+
+    &:hover {
+      background: rgba(0, 0, 0, .025)
+    }
+  }
+
+  .breadcrumb-container {
+    float: left;
+  }
+
+  .errLog-container {
+    display: inline-block;
+    vertical-align: top;
+  }
+
+  .right-menu {
+    float: right;
+    height: 100%;
+    line-height: 50px;
+
+    &:focus {
+      outline: none;
+    }
+
+    .right-menu-item {
+      display: inline-block;
+      padding: 0 8px;
+      height: 100%;
+      font-size: 18px;
+      color: #5a5e66;
+      vertical-align: text-bottom;
+
+      &.hover-effect {
+        cursor: pointer;
+        transition: background .3s;
+
+        &:hover {
+          background: rgba(0, 0, 0, .025)
+        }
+      }
+    }
+
+    .avatar-container {
+      margin-right: 30px;
+
+      .avatar-wrapper {
+        margin-top: 5px;
+        position: relative;
+
+        .user-avatar {
+          cursor: pointer;
+          width: 40px;
+          height: 40px;
+          border-radius: 50%;
+        }
+
+        .el-icon-caret-bottom {
+          cursor: pointer;
+          position: absolute;
+          right: -20px;
+          top: 25px;
+          color: #fff;
+          font-size: 12px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 197 - 197
ruoyi-ui/src/layout/components/Settings/index.vue

@@ -1,197 +1,197 @@
-<template>
-  <div class="drawer-container">
-    <div>
-      <div class="setting-drawer-content">
-        <div class="setting-drawer-title">
-          <h3 class="drawer-title">主题风格设置</h3>
-        </div>
-        <div class="setting-drawer-block-checbox">
-          <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
-            <img src="@/assets/images/dark.svg" alt="dark">
-            <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
-              <i aria-label="图标: check" class="anticon anticon-check">
-                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
-                     focusable="false" class="">
-                  <path
-                    d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
-                </svg>
-              </i>
-            </div>
-          </div>
-          <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
-            <img src="@/assets/images/light.svg" alt="light">
-            <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
-              <i aria-label="图标: check" class="anticon anticon-check">
-                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
-                     focusable="false" class="">
-                  <path
-                    d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
-                </svg>
-              </i>
-            </div>
-          </div>
-        </div>
-
-        <div class="drawer-item">
-          <span>主题颜色</span>
-          <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
-        </div>
-      </div>
-
-      <el-divider/>
-
-      <h3 class="drawer-title">系统布局配置</h3>
-
-      <div class="drawer-item">
-        <span>开启 Tags-Views</span>
-        <el-switch v-model="tagsView" class="drawer-switch" />
-      </div>
-
-      <div class="drawer-item">
-        <span>固定 Header</span>
-        <el-switch v-model="fixedHeader" class="drawer-switch" />
-      </div>
-
-      <div class="drawer-item">
-        <span>显示 Logo</span>
-        <el-switch v-model="sidebarLogo" class="drawer-switch" />
-      </div>
-
-    </div>
-  </div>
-</template>
-
-<script>
-import ThemePicker from '@/components/ThemePicker'
-
-export default {
-  components: { ThemePicker },
-  data() {
-    return {}
-  },
-  computed: {
-    theme() {
-      return this.$store.state.settings.theme
-    },
-    sideTheme() {
-      return this.$store.state.settings.sideTheme
-    },
-    fixedHeader: {
-      get() {
-        return this.$store.state.settings.fixedHeader
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'fixedHeader',
-          value: val
-        })
-      }
-    },
-    tagsView: {
-      get() {
-        return this.$store.state.settings.tagsView
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'tagsView',
-          value: val
-        })
-      }
-    },
-    sidebarLogo: {
-      get() {
-        return this.$store.state.settings.sidebarLogo
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'sidebarLogo',
-          value: val
-        })
-      }
-    },
-  },
-  methods: {
-    themeChange(val) {
-      this.$store.dispatch('settings/changeSetting', {
-        key: 'theme',
-        value: val
-      })
-    },
-    handleTheme(val) {
-      this.$store.dispatch('settings/changeSetting', {
-        key: 'sideTheme',
-        value: val
-      })
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-  .setting-drawer-content {
-    .setting-drawer-title {
-      margin-bottom: 12px;
-      color: rgba(0, 0, 0, .85);
-      font-size: 14px;
-      line-height: 22px;
-      font-weight: bold;
-    }
-
-    .setting-drawer-block-checbox {
-      display: flex;
-      justify-content: flex-start;
-      align-items: center;
-      margin-top: 10px;
-      margin-bottom: 20px;
-
-      .setting-drawer-block-checbox-item {
-        position: relative;
-        margin-right: 16px;
-        border-radius: 2px;
-        cursor: pointer;
-
-        img {
-          width: 48px;
-          height: 48px;
-        }
-
-        .setting-drawer-block-checbox-selectIcon {
-          position: absolute;
-          top: 0;
-          right: 0;
-          width: 100%;
-          height: 100%;
-          padding-top: 15px;
-          padding-left: 24px;
-          color: #1890ff;
-          font-weight: 700;
-          font-size: 14px;
-        }
-      }
-    }
-  }
-
-  .drawer-container {
-    padding: 24px;
-    font-size: 14px;
-    line-height: 1.5;
-    word-wrap: break-word;
-
-    .drawer-title {
-      margin-bottom: 12px;
-      color: rgba(0, 0, 0, .85);
-      font-size: 14px;
-      line-height: 22px;
-    }
-
-    .drawer-item {
-      color: rgba(0, 0, 0, .65);
-      font-size: 14px;
-      padding: 12px 0;
-    }
-
-    .drawer-switch {
-      float: right
-    }
-  }
-</style>
+<template>
+  <div class="drawer-container">
+    <div>
+      <div class="setting-drawer-content">
+        <div class="setting-drawer-title">
+          <h3 class="drawer-title">主题风格设置</h3>
+        </div>
+        <div class="setting-drawer-block-checbox">
+          <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
+            <img src="@/assets/images/dark.svg" alt="dark">
+            <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+              <i aria-label="图标: check" class="anticon anticon-check">
+                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
+                     focusable="false" class="">
+                  <path
+                    d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+                </svg>
+              </i>
+            </div>
+          </div>
+          <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
+            <img src="@/assets/images/light.svg" alt="light">
+            <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+              <i aria-label="图标: check" class="anticon anticon-check">
+                <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
+                     focusable="false" class="">
+                  <path
+                    d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+                </svg>
+              </i>
+            </div>
+          </div>
+        </div>
+
+        <div class="drawer-item">
+          <span>主题颜色</span>
+          <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+        </div>
+      </div>
+
+      <el-divider/>
+
+      <h3 class="drawer-title">系统布局配置</h3>
+
+      <div class="drawer-item">
+        <span>开启 Tags-Views</span>
+        <el-switch v-model="tagsView" class="drawer-switch" />
+      </div>
+
+      <div class="drawer-item">
+        <span>固定 Header</span>
+        <el-switch v-model="fixedHeader" class="drawer-switch" />
+      </div>
+
+      <div class="drawer-item">
+        <span>显示 Logo</span>
+        <el-switch v-model="sidebarLogo" class="drawer-switch" />
+      </div>
+
+    </div>
+  </div>
+</template>
+
+<script>
+import ThemePicker from '@/components/ThemePicker'
+
+export default {
+  components: { ThemePicker },
+  data() {
+    return {}
+  },
+  computed: {
+    theme() {
+      return this.$store.state.settings.theme
+    },
+    sideTheme() {
+      return this.$store.state.settings.sideTheme
+    },
+    fixedHeader: {
+      get() {
+        return this.$store.state.settings.fixedHeader
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'fixedHeader',
+          value: val
+        })
+      }
+    },
+    tagsView: {
+      get() {
+        return this.$store.state.settings.tagsView
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'tagsView',
+          value: val
+        })
+      }
+    },
+    sidebarLogo: {
+      get() {
+        return this.$store.state.settings.sidebarLogo
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'sidebarLogo',
+          value: val
+        })
+      }
+    },
+  },
+  methods: {
+    themeChange(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'theme',
+        value: val
+      })
+    },
+    handleTheme(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'sideTheme',
+        value: val
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .setting-drawer-content {
+    .setting-drawer-title {
+      margin-bottom: 12px;
+      color: rgba(0, 0, 0, .85);
+      font-size: 14px;
+      line-height: 22px;
+      font-weight: bold;
+    }
+
+    .setting-drawer-block-checbox {
+      display: flex;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 10px;
+      margin-bottom: 20px;
+
+      .setting-drawer-block-checbox-item {
+        position: relative;
+        margin-right: 16px;
+        border-radius: 2px;
+        cursor: pointer;
+
+        img {
+          width: 48px;
+          height: 48px;
+        }
+
+        .setting-drawer-block-checbox-selectIcon {
+          position: absolute;
+          top: 0;
+          right: 0;
+          width: 100%;
+          height: 100%;
+          padding-top: 15px;
+          padding-left: 24px;
+          color: #1890ff;
+          font-weight: 700;
+          font-size: 14px;
+        }
+      }
+    }
+  }
+
+  .drawer-container {
+    padding: 24px;
+    font-size: 14px;
+    line-height: 1.5;
+    word-wrap: break-word;
+
+    .drawer-title {
+      margin-bottom: 12px;
+      color: rgba(0, 0, 0, .85);
+      font-size: 14px;
+      line-height: 22px;
+    }
+
+    .drawer-item {
+      color: rgba(0, 0, 0, .65);
+      font-size: 14px;
+      padding: 12px 0;
+    }
+
+    .drawer-switch {
+      float: right
+    }
+  }
+</style>

+ 25 - 25
ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js

@@ -1,25 +1,25 @@
-export default {
-  computed: {
-    device() {
-      return this.$store.state.app.device
-    }
-  },
-  mounted() {
-    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
-    this.fixBugIniOS()
-  },
-  methods: {
-    fixBugIniOS() {
-      const $subMenu = this.$refs.subMenu
-      if ($subMenu) {
-        const handleMouseleave = $subMenu.handleMouseleave
-        $subMenu.handleMouseleave = (e) => {
-          if (this.device === 'mobile') {
-            return
-          }
-          handleMouseleave(e)
-        }
-      }
-    }
-  }
-}
+export default {
+  computed: {
+    device() {
+      return this.$store.state.app.device
+    }
+  },
+  mounted() {
+    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
+    this.fixBugIniOS()
+  },
+  methods: {
+    fixBugIniOS() {
+      const $subMenu = this.$refs.subMenu
+      if ($subMenu) {
+        const handleMouseleave = $subMenu.handleMouseleave
+        $subMenu.handleMouseleave = (e) => {
+          if (this.device === 'mobile') {
+            return
+          }
+          handleMouseleave(e)
+        }
+      }
+    }
+  }
+}

+ 29 - 29
ruoyi-ui/src/layout/components/Sidebar/Item.vue

@@ -1,29 +1,29 @@
-<script>
-export default {
-  name: 'MenuItem',
-  functional: true,
-  props: {
-    icon: {
-      type: String,
-      default: ''
-    },
-    title: {
-      type: String,
-      default: ''
-    }
-  },
-  render(h, context) {
-    const { icon, title } = context.props
-    const vnodes = []
-
-    if (icon) {
-      vnodes.push(<svg-icon icon-class={icon}/>)
-    }
-
-    if (title) {
-      vnodes.push(<span slot='title' style="color: #343434">{(title)}</span>)
-    }
-    return vnodes
-  }
-}
-</script>
+<script>
+export default {
+  name: 'MenuItem',
+  functional: true,
+  props: {
+    icon: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+  render(h, context) {
+    const { icon, title } = context.props
+    const vnodes = []
+
+    if (icon) {
+      vnodes.push(<svg-icon icon-class={icon}/>)
+    }
+
+    if (title) {
+      vnodes.push(<span slot='title' style="color: #343434">{(title)}</span>)
+    }
+    return vnodes
+  }
+}
+</script>

+ 43 - 43
ruoyi-ui/src/layout/components/Sidebar/Link.vue

@@ -1,43 +1,43 @@
-<template>
-  <component :is="type" v-bind="linkProps(to)">
-    <slot />
-  </component>
-</template>
-
-<script>
-import { isExternal } from '@/utils/validate'
-
-export default {
-  props: {
-    to: {
-      type: String,
-      required: true
-    }
-  },
-  computed: {
-    isExternal() {
-      return isExternal(this.to)
-    },
-    type() {
-      if (this.isExternal) {
-        return 'a'
-      }
-      return 'router-link'
-    }
-  },
-  methods: {
-    linkProps(to) {
-      if (this.isExternal) {
-        return {
-          href: to,
-          target: '_blank',
-          rel: 'noopener'
-        }
-      }
-      return {
-        to: to
-      }
-    }
-  }
-}
-</script>
+<template>
+  <component :is="type" v-bind="linkProps(to)">
+    <slot />
+  </component>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  props: {
+    to: {
+      type: String,
+      required: true
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.to)
+    },
+    type() {
+      if (this.isExternal) {
+        return 'a'
+      }
+      return 'router-link'
+    }
+  },
+  methods: {
+    linkProps(to) {
+      if (this.isExternal) {
+        return {
+          href: to,
+          target: '_blank',
+          rel: 'noopener'
+        }
+      }
+      return {
+        to: to
+      }
+    }
+  }
+}
+</script>

+ 94 - 94
ruoyi-ui/src/layout/components/Sidebar/Logo.vue

@@ -1,94 +1,94 @@
-<template>
-  <!-- <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }"> -->
-     <div class="sidebar-logo-container" :class="{'collapse':collapse}">
-    <transition name="sidebarLogoFade">
-      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
-        <!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
-        <h1  class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
-      </router-link>
-      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
-        <!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
-        <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
-      </router-link>
-    </transition>
-  </div>
-</template>
-
-<script>
-import logoImg from '@/assets/logo/logo.png'
-import variables from '@/assets/styles/variables.scss'
-
-export default {
-  name: 'SidebarLogo',
-  props: {
-    collapse: {
-      type: Boolean,
-      required: true
-    }
-  },
-  computed: {
-    variables() {
-      return variables;
-    },
-	sideTheme() {
-      return this.$store.state.settings.sideTheme
-    }
-  },
-  data() {
-    return {
-      title: '潜山市云数据中心',
-      logo: logoImg
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.sidebarLogoFade-enter-active {
-  transition: opacity 1.5s;
-}
-
-.sidebarLogoFade-enter,
-.sidebarLogoFade-leave-to {
-  opacity: 0;
-}
-
-.sidebar-logo-container {
-  position: relative;
-  width: 100%;
-  height: 50px;
-  line-height: 50px;
-  background-color: #3C8DBC;
-  text-align: center;
-  overflow: hidden;
-
-  & .sidebar-logo-link {
-    height: 100%;
-    width: 100%;
-
-    & .sidebar-logo {
-      width: 32px;
-      height: 32px;
-      vertical-align: middle;
-      margin-right: 12px;
-    }
-
-    & .sidebar-title {
-      display: inline-block;
-      margin: 0;
-      color: #fff;
-      font-weight: 600;
-      line-height: 50px;
-      font-size: 14px;
-      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
-      vertical-align: middle;
-    }
-  }
-
-  &.collapse {
-    .sidebar-logo {
-      margin-right: 0px;
-    }
-  }
-}
-</style>
+<template>
+  <!-- <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }"> -->
+     <div class="sidebar-logo-container" :class="{'collapse':collapse}">
+    <transition name="sidebarLogoFade">
+      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+        <!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
+        <h1  class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
+      </router-link>
+      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
+        <!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
+        <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
+      </router-link>
+    </transition>
+  </div>
+</template>
+
+<script>
+import logoImg from '@/assets/logo/logo.png'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+  name: 'SidebarLogo',
+  props: {
+    collapse: {
+      type: Boolean,
+      required: true
+    }
+  },
+  computed: {
+    variables() {
+      return variables;
+    },
+	sideTheme() {
+      return this.$store.state.settings.sideTheme
+    }
+  },
+  data() {
+    return {
+      title: '潜山市云数据中心',
+      logo: logoImg
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.sidebarLogoFade-enter-active {
+  transition: opacity 1.5s;
+}
+
+.sidebarLogoFade-enter,
+.sidebarLogoFade-leave-to {
+  opacity: 0;
+}
+
+.sidebar-logo-container {
+  position: relative;
+  width: 100%;
+  height: 50px;
+  line-height: 50px;
+  background-color: #3C8DBC;
+  text-align: center;
+  overflow: hidden;
+
+  & .sidebar-logo-link {
+    height: 100%;
+    width: 100%;
+
+    & .sidebar-logo {
+      width: 32px;
+      height: 32px;
+      vertical-align: middle;
+      margin-right: 12px;
+    }
+
+    & .sidebar-title {
+      display: inline-block;
+      margin: 0;
+      color: #fff;
+      font-weight: 600;
+      line-height: 50px;
+      font-size: 14px;
+      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+      vertical-align: middle;
+    }
+  }
+
+  &.collapse {
+    .sidebar-logo {
+      margin-right: 0px;
+    }
+  }
+}
+</style>

+ 98 - 98
ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue

@@ -1,98 +1,98 @@
-<template>
-  <div v-if="!item.hidden">
-    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
-      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
-        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
-          <!-- <item :title="onlyOneChild.meta.title" /> -->
-          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
-        </el-menu-item>
-      </app-link>
-    </template>
-
-    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
-      <template slot="title">
-        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
-        <!-- <item v-if="item.meta" :title="item.meta.title" /> -->
-      </template>
-      <sidebar-item
-        v-for="child in item.children"
-        :key="child.path"
-        :is-nest="true"
-        :item="child"
-        :base-path="resolvePath(child.path)"
-        class="nest-menu"
-      />
-    </el-submenu>
-  </div>
-</template>
-
-<script>
-import path from 'path'
-import { isExternal } from '@/utils/validate'
-import Item from './Item'
-import AppLink from './Link'
-import FixiOSBug from './FixiOSBug'
-
-export default {
-  name: 'SidebarItem',
-  components: { Item, AppLink },
-  mixins: [FixiOSBug],
-  props: {
-    // route object
-    item: {
-      type: Object,
-      required: true
-    },
-    isNest: {
-      type: Boolean,
-      default: false
-    },
-    basePath: {
-      type: String,
-      default: ''
-    }
-  },
-  data() {
-    this.onlyOneChild = null
-    return {
-    }
-  },
-  mounted() {
-  },
-  methods: {
-    hasOneShowingChild(children = [], parent) {
-      const showingChildren = children.filter(item => {
-        if (item.hidden) {
-          return false
-        } else {
-          // Temp set(will be used if only has one showing child)
-          this.onlyOneChild = item
-          return true
-        }
-      })
-
-      // When there is only one child router, the child router is displayed by default
-      if (showingChildren.length === 1) {
-        return true
-      }
-
-      // Show parent if there are no child router to display
-      if (showingChildren.length === 0) {
-        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
-        return true
-      }
-
-      return false
-    },
-    resolvePath(routePath) {
-      if (isExternal(routePath)) {
-        return routePath
-      }
-      if (isExternal(this.basePath)) {
-        return this.basePath
-      }
-      return path.resolve(this.basePath, routePath)
-    }
-  }
-}
-</script>
+<template>
+  <div v-if="!item.hidden">
+    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
+      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
+        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+          <!-- <item :title="onlyOneChild.meta.title" /> -->
+          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
+        </el-menu-item>
+      </app-link>
+    </template>
+
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+      <template slot="title">
+        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+        <!-- <item v-if="item.meta" :title="item.meta.title" /> -->
+      </template>
+      <sidebar-item
+        v-for="child in item.children"
+        :key="child.path"
+        :is-nest="true"
+        :item="child"
+        :base-path="resolvePath(child.path)"
+        class="nest-menu"
+      />
+    </el-submenu>
+  </div>
+</template>
+
+<script>
+import path from 'path'
+import { isExternal } from '@/utils/validate'
+import Item from './Item'
+import AppLink from './Link'
+import FixiOSBug from './FixiOSBug'
+
+export default {
+  name: 'SidebarItem',
+  components: { Item, AppLink },
+  mixins: [FixiOSBug],
+  props: {
+    // route object
+    item: {
+      type: Object,
+      required: true
+    },
+    isNest: {
+      type: Boolean,
+      default: false
+    },
+    basePath: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    this.onlyOneChild = null
+    return {
+    }
+  },
+  mounted() {
+  },
+  methods: {
+    hasOneShowingChild(children = [], parent) {
+      const showingChildren = children.filter(item => {
+        if (item.hidden) {
+          return false
+        } else {
+          // Temp set(will be used if only has one showing child)
+          this.onlyOneChild = item
+          return true
+        }
+      })
+
+      // When there is only one child router, the child router is displayed by default
+      if (showingChildren.length === 1) {
+        return true
+      }
+
+      // Show parent if there are no child router to display
+      if (showingChildren.length === 0) {
+        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
+        return true
+      }
+
+      return false
+    },
+    resolvePath(routePath) {
+      if (isExternal(routePath)) {
+        return routePath
+      }
+      if (isExternal(this.basePath)) {
+        return this.basePath
+      }
+      return path.resolve(this.basePath, routePath)
+    }
+  }
+}
+</script>

+ 70 - 70
ruoyi-ui/src/layout/components/Sidebar/index.vue

@@ -1,70 +1,70 @@
-<template>
-    <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
-        <logo v-if="showLogo" :collapse="isCollapse" />
-        <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
-            <el-menu
-                :default-active="activeMenu"
-                :collapse="isCollapse"
-                :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg"
-                :text-color="settings.sideTheme === 'theme-dark' ? variables.menuText : 'rgba(0,0,0,.65)'"
-                :unique-opened="true"
-                :active-text-color="settings.theme"
-                :collapse-transition="false"
-                mode="vertical"
-            >
-                <sidebar-item
-                    v-for="(route, index) in handleSide"
-                    :key="route.path  + index"
-                    :item="route"
-                    :base-path="route.path"
-                />
-            </el-menu>
-        </el-scrollbar>
-    </div>
-</template>
-
-<script>
-import { mapGetters, mapState } from "vuex";
-import Logo from "./Logo";
-import SidebarItem from "./SidebarItem";
-import variables from "@/assets/styles/variables.scss";
-
-export default {
-    components: { SidebarItem, Logo },
-    mounted() {
-      console.log(this.sidebarRouters,this.sidebar,this.settings)
-    },
-    computed: {
-        ...mapState(["settings"]),
-        ...mapGetters(["sidebarRouters", "sidebar","tabIndex"]),
-        activeMenu() {
-            // const route = this.$route;
-            // const { meta, path } = route;
-            // // if set path, the sidebar will highlight the path you set
-            // if (meta.activeMenu) {
-            //     return meta.activeMenu;
-            // }
-
-            return this.tabIndex;
-        },
-        handleSide() {
-          let add = []
-          for(let item of this.sidebarRouters){
-            if(this.activeMenu.includes(item.path||item.redirect)){
-              add.push(item)
-            }
-          }
-          return add
-        },
-        showLogo() {
-            return this.$store.state.settings.sidebarLogo;
-        },
-        variables() {
-            return variables;
-        },
-        isCollapse() {
-            return !this.sidebar.opened;
-        }
-    }
-};
-</script>
+<template>
+    <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
+        <logo v-if="showLogo" :collapse="isCollapse" />
+        <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
+            <el-menu
+                :default-active="activeMenu"
+                :collapse="isCollapse"
+                :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg"
+                :text-color="settings.sideTheme === 'theme-dark' ? variables.menuText : 'rgba(0,0,0,.65)'"
+                :unique-opened="true"
+                :active-text-color="settings.theme"
+                :collapse-transition="false"
+                mode="vertical"
+            >
+                <sidebar-item
+                    v-for="(route, index) in handleSide"
+                    :key="route.path  + index"
+                    :item="route"
+                    :base-path="route.path"
+                />
+            </el-menu>
+        </el-scrollbar>
+    </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex";
+import Logo from "./Logo";
+import SidebarItem from "./SidebarItem";
+import variables from "@/assets/styles/variables.scss";
+
+export default {
+    components: { SidebarItem, Logo },
+    mounted() {
+      console.log(this.sidebarRouters,this.sidebar,this.settings)
+    },
+    computed: {
+        ...mapState(["settings"]),
+        ...mapGetters(["sidebarRouters", "sidebar","tabIndex"]),
+        activeMenu() {
+            // const route = this.$route;
+            // const { meta, path } = route;
+            // // if set path, the sidebar will highlight the path you set
+            // if (meta.activeMenu) {
+            //     return meta.activeMenu;
+            // }
+
+            return this.tabIndex;
+        },
+        handleSide() {
+          let add = []
+          for(let item of this.sidebarRouters){
+            if(this.activeMenu.includes(item.path||item.redirect)){
+              add.push(item)
+            }
+          }
+          return add
+        },
+        showLogo() {
+            return this.$store.state.settings.sidebarLogo;
+        },
+        variables() {
+            return variables;
+        },
+        isCollapse() {
+            return !this.sidebar.opened;
+        }
+    }
+};
+</script>

+ 94 - 94
ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue

@@ -1,94 +1,94 @@
-<template>
-  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
-    <slot />
-  </el-scrollbar>
-</template>
-
-<script>
-const tagAndTagSpacing = 4 // tagAndTagSpacing
-
-export default {
-  name: 'ScrollPane',
-  data() {
-    return {
-      left: 0
-    }
-  },
-  computed: {
-    scrollWrapper() {
-      return this.$refs.scrollContainer.$refs.wrap
-    }
-  },
-  mounted() {
-    this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
-  },
-  beforeDestroy() {
-    this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
-  },
-  methods: {
-    handleScroll(e) {
-      const eventDelta = e.wheelDelta || -e.deltaY * 40
-      const $scrollWrapper = this.scrollWrapper
-      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
-    },
-    emitScroll() {
-      this.$emit('scroll')
-    },
-    moveToTarget(currentTag) {
-      const $container = this.$refs.scrollContainer.$el
-      const $containerWidth = $container.offsetWidth
-      const $scrollWrapper = this.scrollWrapper
-      const tagList = this.$parent.$refs.tag
-
-      let firstTag = null
-      let lastTag = null
-
-      // find first tag and last tag
-      if (tagList.length > 0) {
-        firstTag = tagList[0]
-        lastTag = tagList[tagList.length - 1]
-      }
-
-      if (firstTag === currentTag) {
-        $scrollWrapper.scrollLeft = 0
-      } else if (lastTag === currentTag) {
-        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
-      } else {
-        // find preTag and nextTag
-        const currentIndex = tagList.findIndex(item => item === currentTag)
-        const prevTag = tagList[currentIndex - 1]
-        const nextTag = tagList[currentIndex + 1]
-
-        // the tag's offsetLeft after of nextTag
-        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
-
-        // the tag's offsetLeft before of prevTag
-        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
-
-        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
-          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
-        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
-          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
-        }
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.scroll-container {
-  white-space: nowrap;
-  position: relative;
-  overflow: hidden;
-  width: 100%;
-  ::v-deep {
-    .el-scrollbar__bar {
-      bottom: 0px;
-    }
-    .el-scrollbar__wrap {
-      height: 49px;
-    }
-  }
-}
-</style>
+<template>
+  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
+    <slot />
+  </el-scrollbar>
+</template>
+
+<script>
+const tagAndTagSpacing = 4 // tagAndTagSpacing
+
+export default {
+  name: 'ScrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  computed: {
+    scrollWrapper() {
+      return this.$refs.scrollContainer.$refs.wrap
+    }
+  },
+  mounted() {
+    this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
+  },
+  beforeDestroy() {
+    this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 40
+      const $scrollWrapper = this.scrollWrapper
+      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+    },
+    emitScroll() {
+      this.$emit('scroll')
+    },
+    moveToTarget(currentTag) {
+      const $container = this.$refs.scrollContainer.$el
+      const $containerWidth = $container.offsetWidth
+      const $scrollWrapper = this.scrollWrapper
+      const tagList = this.$parent.$refs.tag
+
+      let firstTag = null
+      let lastTag = null
+
+      // find first tag and last tag
+      if (tagList.length > 0) {
+        firstTag = tagList[0]
+        lastTag = tagList[tagList.length - 1]
+      }
+
+      if (firstTag === currentTag) {
+        $scrollWrapper.scrollLeft = 0
+      } else if (lastTag === currentTag) {
+        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
+      } else {
+        // find preTag and nextTag
+        const currentIndex = tagList.findIndex(item => item === currentTag)
+        const prevTag = tagList[currentIndex - 1]
+        const nextTag = tagList[currentIndex + 1]
+
+        // the tag's offsetLeft after of nextTag
+        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+
+        // the tag's offsetLeft before of prevTag
+        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+
+        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
+        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  ::v-deep {
+    .el-scrollbar__bar {
+      bottom: 0px;
+    }
+    .el-scrollbar__wrap {
+      height: 49px;
+    }
+  }
+}
+</style>

+ 303 - 303
ruoyi-ui/src/layout/components/TagsView/index.vue

@@ -1,303 +1,303 @@
-<template>
-  <div id="tags-view-container" class="tags-view-container">
-    <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
-      <router-link
-        v-for="tag in visitedViews"
-        ref="tag"
-        :key="tag.path"
-        :class="isActive(tag)?'active':''"
-        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
-        tag="span"
-        class="tags-view-item"
-        :style="activeStyle(tag)"
-        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
-        @contextmenu.prevent.native="openMenu(tag,$event)"
-      >
-        {{ tag.title }}
-        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
-      </router-link>
-    </scroll-pane>
-    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)">刷新页面</li>
-      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前</li>
-      <li @click="closeOthersTags">关闭其他</li>
-      <li @click="closeAllTags(selectedTag)">关闭所有</li>
-    </ul>
-  </div>
-</template>
-
-<script>
-import ScrollPane from './ScrollPane'
-import path from 'path'
-
-export default {
-  components: { ScrollPane },
-  data() {
-    return {
-      visible: false,
-      top: 0,
-      left: 0,
-      selectedTag: {},
-      affixTags: []
-    }
-  },
-  computed: {
-    visitedViews() {
-      return this.$store.state.tagsView.visitedViews
-    },
-    routes() {
-      return this.$store.state.permission.routes
-    },
-    theme() {
-      return this.$store.state.settings.theme;
-    }
-  },
-  watch: {
-    $route() {
-      this.addTags()
-      this.moveToCurrentTag()
-    },
-    visible(value) {
-      if (value) {
-        document.body.addEventListener('click', this.closeMenu)
-      } else {
-        document.body.removeEventListener('click', this.closeMenu)
-      }
-    }
-  },
-  mounted() {
-    this.initTags()
-    this.addTags()
-  },
-  methods: {
-    isActive(route) {
-      return route.path === this.$route.path
-    },
-    activeStyle(tag) {
-      if (!this.isActive(tag)) return {};
-      return {
-        "background-color": this.theme,
-        "border-color": this.theme
-      };
-    },
-    isAffix(tag) {
-      return tag.meta && tag.meta.affix
-    },
-    filterAffixTags(routes, basePath = '/') {
-      let tags = []
-      routes.forEach(route => {
-        if (route.meta && route.meta.affix) {
-          const tagPath = path.resolve(basePath, route.path)
-          tags.push({
-            fullPath: tagPath,
-            path: tagPath,
-            name: route.name,
-            meta: { ...route.meta }
-          })
-        }
-        if (route.children) {
-          const tempTags = this.filterAffixTags(route.children, route.path)
-          if (tempTags.length >= 1) {
-            tags = [...tags, ...tempTags]
-          }
-        }
-      })
-      return tags
-    },
-    initTags() {
-      const affixTags = this.affixTags = this.filterAffixTags(this.routes)
-      for (const tag of affixTags) {
-        // Must have tag name
-        if (tag.name) {
-          this.$store.dispatch('tagsView/addVisitedView', tag)
-        }
-      }
-    },
-    addTags() {
-      const { name } = this.$route
-      if (name) {
-        this.$store.dispatch('tagsView/addView', this.$route)
-      }
-      return false
-    },
-    moveToCurrentTag() {
-      const tags = this.$refs.tag
-      this.$nextTick(() => {
-        for (const tag of tags) {
-          if (tag.to.path === this.$route.path) {
-            this.$refs.scrollPane.moveToTarget(tag)
-            // when query is different then update
-            if (tag.to.fullPath !== this.$route.fullPath) {
-              this.$store.dispatch('tagsView/updateVisitedView', this.$route)
-            }
-            break
-          }
-        }
-      })
-    },
-    refreshSelectedTag(view) {
-      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
-        const { fullPath } = view
-        this.$nextTick(() => {
-          this.$router.replace({
-            path: '/redirect' + fullPath
-          })
-        })
-      })
-    },
-    closeSelectedTag(view) {
-      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
-        if (this.isActive(view)) {
-          this.toLastView(visitedViews, view)
-        }
-      })
-    },
-    closeOthersTags() {
-      this.$router.push(this.selectedTag).catch(()=>{});
-      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
-        this.moveToCurrentTag()
-      })
-    },
-    closeAllTags(view) {
-      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
-        if (this.affixTags.some(tag => tag.path === this.$route.path)) {
-          return
-        }
-        this.toLastView(visitedViews, view)
-      })
-    },
-    toLastView(visitedViews, view) {
-      const latestView = visitedViews.slice(-1)[0]
-      if (latestView) {
-        this.$router.push(latestView.fullPath)
-      } else {
-        // now the default is to redirect to the home page if there is no tags-view,
-        // you can adjust it according to your needs.
-        if (view.name === 'Dashboard') {
-          // to reload home page
-          this.$router.replace({ path: '/redirect' + view.fullPath })
-        } else {
-          this.$router.push('/')
-        }
-      }
-    },
-    openMenu(tag, e) {
-      const menuMinWidth = 105
-      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
-      const offsetWidth = this.$el.offsetWidth // container width
-      const maxLeft = offsetWidth - menuMinWidth // left boundary
-      const left = e.clientX - offsetLeft + 15 // 15: margin right
-
-      if (left > maxLeft) {
-        this.left = maxLeft
-      } else {
-        this.left = left
-      }
-
-      this.top = e.clientY
-      this.visible = true
-      this.selectedTag = tag
-    },
-    closeMenu() {
-      this.visible = false
-    },
-    handleScroll() {
-      this.closeMenu()
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.tags-view-container {
-  height: 34px;
-  width: 100%;
-  background: #fff;
-  border-bottom: 1px solid #d8dce5;
-  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
-  .tags-view-wrapper {
-    .tags-view-item {
-      display: inline-block;
-      position: relative;
-      cursor: pointer;
-      height: 26px;
-      line-height: 26px;
-      border: 1px solid #d8dce5;
-      color: #495060;
-      background: #fff;
-      padding: 0 8px;
-      font-size: 12px;
-      margin-left: 5px;
-      margin-top: 4px;
-      &:first-of-type {
-        margin-left: 15px;
-      }
-      &:last-of-type {
-        margin-right: 15px;
-      }
-      &.active {
-        background-color: #42b983;
-        color: #fff;
-        border-color: #42b983;
-        &::before {
-          content: '';
-          background: #fff;
-          display: inline-block;
-          width: 8px;
-          height: 8px;
-          border-radius: 50%;
-          position: relative;
-          margin-right: 2px;
-        }
-      }
-    }
-  }
-  .contextmenu {
-    margin: 0;
-    background: #fff;
-    z-index: 3000;
-    position: absolute;
-    list-style-type: none;
-    padding: 5px 0;
-    border-radius: 4px;
-    font-size: 12px;
-    font-weight: 400;
-    color: #333;
-    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
-    li {
-      margin: 0;
-      padding: 7px 16px;
-      cursor: pointer;
-      &:hover {
-        background: #eee;
-      }
-    }
-  }
-}
-</style>
-
-<style lang="scss">
-//reset element css of el-icon-close
-.tags-view-wrapper {
-  .tags-view-item {
-    .el-icon-close {
-      width: 16px;
-      height: 16px;
-      vertical-align: 2px;
-      border-radius: 50%;
-      text-align: center;
-      transition: all .3s cubic-bezier(.645, .045, .355, 1);
-      transform-origin: 100% 50%;
-      &:before {
-        transform: scale(.6);
-        display: inline-block;
-        vertical-align: -3px;
-      }
-      &:hover {
-        background-color: #b4bccc;
-        color: #fff;
-      }
-    }
-  }
-}
-</style>
+<template>
+  <div id="tags-view-container" class="tags-view-container">
+    <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
+      <router-link
+        v-for="tag in visitedViews"
+        ref="tag"
+        :key="tag.path"
+        :class="isActive(tag)?'active':''"
+        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+        tag="span"
+        class="tags-view-item"
+        :style="activeStyle(tag)"
+        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
+        @contextmenu.prevent.native="openMenu(tag,$event)"
+      >
+        {{ tag.title }}
+        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+      </router-link>
+    </scroll-pane>
+    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
+      <li @click="refreshSelectedTag(selectedTag)">刷新页面</li>
+      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前</li>
+      <li @click="closeOthersTags">关闭其他</li>
+      <li @click="closeAllTags(selectedTag)">关闭所有</li>
+    </ul>
+  </div>
+</template>
+
+<script>
+import ScrollPane from './ScrollPane'
+import path from 'path'
+
+export default {
+  components: { ScrollPane },
+  data() {
+    return {
+      visible: false,
+      top: 0,
+      left: 0,
+      selectedTag: {},
+      affixTags: []
+    }
+  },
+  computed: {
+    visitedViews() {
+      return this.$store.state.tagsView.visitedViews
+    },
+    routes() {
+      return this.$store.state.permission.routes
+    },
+    theme() {
+      return this.$store.state.settings.theme;
+    }
+  },
+  watch: {
+    $route() {
+      this.addTags()
+      this.moveToCurrentTag()
+    },
+    visible(value) {
+      if (value) {
+        document.body.addEventListener('click', this.closeMenu)
+      } else {
+        document.body.removeEventListener('click', this.closeMenu)
+      }
+    }
+  },
+  mounted() {
+    this.initTags()
+    this.addTags()
+  },
+  methods: {
+    isActive(route) {
+      return route.path === this.$route.path
+    },
+    activeStyle(tag) {
+      if (!this.isActive(tag)) return {};
+      return {
+        "background-color": this.theme,
+        "border-color": this.theme
+      };
+    },
+    isAffix(tag) {
+      return tag.meta && tag.meta.affix
+    },
+    filterAffixTags(routes, basePath = '/') {
+      let tags = []
+      routes.forEach(route => {
+        if (route.meta && route.meta.affix) {
+          const tagPath = path.resolve(basePath, route.path)
+          tags.push({
+            fullPath: tagPath,
+            path: tagPath,
+            name: route.name,
+            meta: { ...route.meta }
+          })
+        }
+        if (route.children) {
+          const tempTags = this.filterAffixTags(route.children, route.path)
+          if (tempTags.length >= 1) {
+            tags = [...tags, ...tempTags]
+          }
+        }
+      })
+      return tags
+    },
+    initTags() {
+      const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+      for (const tag of affixTags) {
+        // Must have tag name
+        if (tag.name) {
+          this.$store.dispatch('tagsView/addVisitedView', tag)
+        }
+      }
+    },
+    addTags() {
+      const { name } = this.$route
+      if (name) {
+        this.$store.dispatch('tagsView/addView', this.$route)
+      }
+      return false
+    },
+    moveToCurrentTag() {
+      const tags = this.$refs.tag
+      this.$nextTick(() => {
+        for (const tag of tags) {
+          if (tag.to.path === this.$route.path) {
+            this.$refs.scrollPane.moveToTarget(tag)
+            // when query is different then update
+            if (tag.to.fullPath !== this.$route.fullPath) {
+              this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+            }
+            break
+          }
+        }
+      })
+    },
+    refreshSelectedTag(view) {
+      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
+        const { fullPath } = view
+        this.$nextTick(() => {
+          this.$router.replace({
+            path: '/redirect' + fullPath
+          })
+        })
+      })
+    },
+    closeSelectedTag(view) {
+      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
+        if (this.isActive(view)) {
+          this.toLastView(visitedViews, view)
+        }
+      })
+    },
+    closeOthersTags() {
+      this.$router.push(this.selectedTag).catch(()=>{});
+      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
+        this.moveToCurrentTag()
+      })
+    },
+    closeAllTags(view) {
+      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
+        if (this.affixTags.some(tag => tag.path === this.$route.path)) {
+          return
+        }
+        this.toLastView(visitedViews, view)
+      })
+    },
+    toLastView(visitedViews, view) {
+      const latestView = visitedViews.slice(-1)[0]
+      if (latestView) {
+        this.$router.push(latestView.fullPath)
+      } else {
+        // now the default is to redirect to the home page if there is no tags-view,
+        // you can adjust it according to your needs.
+        if (view.name === 'Dashboard') {
+          // to reload home page
+          this.$router.replace({ path: '/redirect' + view.fullPath })
+        } else {
+          this.$router.push('/')
+        }
+      }
+    },
+    openMenu(tag, e) {
+      const menuMinWidth = 105
+      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
+      const offsetWidth = this.$el.offsetWidth // container width
+      const maxLeft = offsetWidth - menuMinWidth // left boundary
+      const left = e.clientX - offsetLeft + 15 // 15: margin right
+
+      if (left > maxLeft) {
+        this.left = maxLeft
+      } else {
+        this.left = left
+      }
+
+      this.top = e.clientY
+      this.visible = true
+      this.selectedTag = tag
+    },
+    closeMenu() {
+      this.visible = false
+    },
+    handleScroll() {
+      this.closeMenu()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.tags-view-container {
+  height: 34px;
+  width: 100%;
+  background: #fff;
+  border-bottom: 1px solid #d8dce5;
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+  .tags-view-wrapper {
+    .tags-view-item {
+      display: inline-block;
+      position: relative;
+      cursor: pointer;
+      height: 26px;
+      line-height: 26px;
+      border: 1px solid #d8dce5;
+      color: #495060;
+      background: #fff;
+      padding: 0 8px;
+      font-size: 12px;
+      margin-left: 5px;
+      margin-top: 4px;
+      &:first-of-type {
+        margin-left: 15px;
+      }
+      &:last-of-type {
+        margin-right: 15px;
+      }
+      &.active {
+        background-color: #42b983;
+        color: #fff;
+        border-color: #42b983;
+        &::before {
+          content: '';
+          background: #fff;
+          display: inline-block;
+          width: 8px;
+          height: 8px;
+          border-radius: 50%;
+          position: relative;
+          margin-right: 2px;
+        }
+      }
+    }
+  }
+  .contextmenu {
+    margin: 0;
+    background: #fff;
+    z-index: 3000;
+    position: absolute;
+    list-style-type: none;
+    padding: 5px 0;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 400;
+    color: #333;
+    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+    li {
+      margin: 0;
+      padding: 7px 16px;
+      cursor: pointer;
+      &:hover {
+        background: #eee;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+//reset element css of el-icon-close
+.tags-view-wrapper {
+  .tags-view-item {
+    .el-icon-close {
+      width: 16px;
+      height: 16px;
+      vertical-align: 2px;
+      border-radius: 50%;
+      text-align: center;
+      transition: all .3s cubic-bezier(.645, .045, .355, 1);
+      transform-origin: 100% 50%;
+      &:before {
+        transform: scale(.6);
+        display: inline-block;
+        vertical-align: -3px;
+      }
+      &:hover {
+        background-color: #b4bccc;
+        color: #fff;
+      }
+    }
+  }
+}
+</style>

+ 5 - 5
ruoyi-ui/src/layout/components/index.js

@@ -1,5 +1,5 @@
-export { default as AppMain } from './AppMain'
-export { default as Navbar } from './Navbar'
-export { default as Settings } from './Settings'
-export { default as Sidebar } from './Sidebar/index.vue'
-export { default as TagsView } from './TagsView/index.vue'
+export { default as AppMain } from './AppMain'
+export { default as Navbar } from './Navbar'
+export { default as Settings } from './Settings'
+export { default as Sidebar } from './Sidebar/index.vue'
+export { default as TagsView } from './TagsView/index.vue'

+ 108 - 108
ruoyi-ui/src/layout/index.vue

@@ -1,108 +1,108 @@
-<template>
-  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
-    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
-    <sidebar class="sidebar-container" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }" />
-    <div :class="{hasTagsView:needTagsView}" class="main-container">
-      <div :class="{'fixed-header':fixedHeader}">
-        <navbar />
-        <tags-view v-if="needTagsView"/>
-      </div>
-      <app-main />
-      <right-panel v-if="showSettings">
-        <settings />
-      </right-panel>
-    </div>
-  </div>
-</template>
-
-<script>
-import RightPanel from '@/components/RightPanel'
-import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
-import ResizeMixin from './mixin/ResizeHandler'
-import { mapState } from 'vuex'
-import variables from '@/assets/styles/variables.scss'
-
-export default {
-  name: 'Layout',
-  components: {
-    AppMain,
-    Navbar,
-    RightPanel,
-    Settings,
-    Sidebar,
-    TagsView
-  },
-  mixins: [ResizeMixin],
-  computed: {
-    ...mapState({
-      theme: state => state.settings.theme,
-      sideTheme: state => state.settings.sideTheme,
-      sidebar: state => state.app.sidebar,
-      device: state => state.app.device,
-      showSettings: state => state.settings.showSettings,
-      needTagsView: state => state.settings.tagsView,
-      fixedHeader: state => state.settings.fixedHeader
-    }),
-    classObj() {
-      return {
-        hideSidebar: !this.sidebar.opened,
-        openSidebar: this.sidebar.opened,
-        withoutAnimation: this.sidebar.withoutAnimation,
-        mobile: this.device === 'mobile'
-      }
-    },
-    variables() {
-      return variables;
-    }
-  },
-  methods: {
-    handleClickOutside() {
-      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-  @import "~@/assets/styles/mixin.scss";
-  @import "~@/assets/styles/variables.scss";
-
-  .app-wrapper {
-    @include clearfix;
-    position: relative;
-    height: 100%;
-    width: 100%;
-
-    &.mobile.openSidebar {
-      position: fixed;
-      top: 0;
-    }
-  }
-
-  .drawer-bg {
-    background: #000;
-    opacity: 0.3;
-    width: 100%;
-    top: 0;
-    height: 100%;
-    position: absolute;
-    z-index: 999;
-  }
-
-  .fixed-header {
-    position: fixed;
-    top: 0;
-    right: 0;
-    z-index: 9;
-    width: calc(100% - #{$sideBarWidth});
-    transition: width 0.28s;
-  }
-
-  .hideSidebar .fixed-header {
-    width: calc(100% - 54px)
-  }
-
-  .mobile .fixed-header {
-    width: 100%;
-  }
-</style>
+<template>
+  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
+    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
+    <sidebar class="sidebar-container" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }" />
+    <div :class="{hasTagsView:needTagsView}" class="main-container">
+      <div :class="{'fixed-header':fixedHeader}">
+        <navbar />
+        <tags-view v-if="needTagsView"/>
+      </div>
+      <app-main />
+      <right-panel v-if="showSettings">
+        <settings />
+      </right-panel>
+    </div>
+  </div>
+</template>
+
+<script>
+import RightPanel from '@/components/RightPanel'
+import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+import { mapState } from 'vuex'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+  name: 'Layout',
+  components: {
+    AppMain,
+    Navbar,
+    RightPanel,
+    Settings,
+    Sidebar,
+    TagsView
+  },
+  mixins: [ResizeMixin],
+  computed: {
+    ...mapState({
+      theme: state => state.settings.theme,
+      sideTheme: state => state.settings.sideTheme,
+      sidebar: state => state.app.sidebar,
+      device: state => state.app.device,
+      showSettings: state => state.settings.showSettings,
+      needTagsView: state => state.settings.tagsView,
+      fixedHeader: state => state.settings.fixedHeader
+    }),
+    classObj() {
+      return {
+        hideSidebar: !this.sidebar.opened,
+        openSidebar: this.sidebar.opened,
+        withoutAnimation: this.sidebar.withoutAnimation,
+        mobile: this.device === 'mobile'
+      }
+    },
+    variables() {
+      return variables;
+    }
+  },
+  methods: {
+    handleClickOutside() {
+      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "~@/assets/styles/mixin.scss";
+  @import "~@/assets/styles/variables.scss";
+
+  .app-wrapper {
+    @include clearfix;
+    position: relative;
+    height: 100%;
+    width: 100%;
+
+    &.mobile.openSidebar {
+      position: fixed;
+      top: 0;
+    }
+  }
+
+  .drawer-bg {
+    background: #000;
+    opacity: 0.3;
+    width: 100%;
+    top: 0;
+    height: 100%;
+    position: absolute;
+    z-index: 999;
+  }
+
+  .fixed-header {
+    position: fixed;
+    top: 0;
+    right: 0;
+    z-index: 9;
+    width: calc(100% - #{$sideBarWidth});
+    transition: width 0.28s;
+  }
+
+  .hideSidebar .fixed-header {
+    width: calc(100% - 54px)
+  }
+
+  .mobile .fixed-header {
+    width: 100%;
+  }
+</style>

+ 45 - 45
ruoyi-ui/src/layout/mixin/ResizeHandler.js

@@ -1,45 +1,45 @@
-import store from '@/store'
-
-const { body } = document
-const WIDTH = 992 // refer to Bootstrap's responsive design
-
-export default {
-  watch: {
-    $route(route) {
-      if (this.device === 'mobile' && this.sidebar.opened) {
-        store.dispatch('app/closeSideBar', { withoutAnimation: false })
-      }
-    }
-  },
-  beforeMount() {
-    window.addEventListener('resize', this.$_resizeHandler)
-  },
-  beforeDestroy() {
-    window.removeEventListener('resize', this.$_resizeHandler)
-  },
-  mounted() {
-    const isMobile = this.$_isMobile()
-    if (isMobile) {
-      store.dispatch('app/toggleDevice', 'mobile')
-      store.dispatch('app/closeSideBar', { withoutAnimation: true })
-    }
-  },
-  methods: {
-    // use $_ for mixins properties
-    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
-    $_isMobile() {
-      const rect = body.getBoundingClientRect()
-      return rect.width - 1 < WIDTH
-    },
-    $_resizeHandler() {
-      if (!document.hidden) {
-        const isMobile = this.$_isMobile()
-        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
-
-        if (isMobile) {
-          store.dispatch('app/closeSideBar', { withoutAnimation: true })
-        }
-      }
-    }
-  }
-}
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+export default {
+  watch: {
+    $route(route) {
+      if (this.device === 'mobile' && this.sidebar.opened) {
+        store.dispatch('app/closeSideBar', { withoutAnimation: false })
+      }
+    }
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.$_resizeHandler)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.$_resizeHandler)
+  },
+  mounted() {
+    const isMobile = this.$_isMobile()
+    if (isMobile) {
+      store.dispatch('app/toggleDevice', 'mobile')
+      store.dispatch('app/closeSideBar', { withoutAnimation: true })
+    }
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_isMobile() {
+      const rect = body.getBoundingClientRect()
+      return rect.width - 1 < WIDTH
+    },
+    $_resizeHandler() {
+      if (!document.hidden) {
+        const isMobile = this.$_isMobile()
+        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
+
+        if (isMobile) {
+          store.dispatch('app/closeSideBar', { withoutAnimation: true })
+        }
+      }
+    }
+  }
+}

+ 83 - 83
ruoyi-ui/src/main.js

@@ -1,83 +1,83 @@
-import Vue from 'vue'
-
-import Cookies from 'js-cookie'
-
-import Element from 'element-ui'
-import './assets/styles/element-variables.scss'
-
-import '@/assets/styles/index.scss' // global css
-import '@/assets/styles/ruoyi.scss' // ruoyi css
-import App from './App'
-import store from './store'
-import router from './router'
-import permission from './directive/permission'
-import { download } from '@/utils/request'
-
-import './assets/icons' // icon
-import './permission' // permission control
-import { getDicts } from "@/api/system/dict/data";
-import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
-import Pagination from "@/components/Pagination";
-// 自定义表格工具扩展
-import RightToolbar from "@/components/RightToolbar"
-import DynamicForm from "@/components/DynamicForm"
-import DynamicForms from "@/components/DynamicForms"
-import MemoranDum from "@/components/MemoranDum"
-
-// 全局方法挂载
-Vue.prototype.getDicts = getDicts
-Vue.prototype.getConfigKey = getConfigKey
-Vue.prototype.parseTime = parseTime
-Vue.prototype.resetForm = resetForm
-Vue.prototype.addDateRange = addDateRange
-Vue.prototype.selectDictLabel = selectDictLabel
-Vue.prototype.selectDictLabels = selectDictLabels
-Vue.prototype.download = download
-Vue.prototype.handleTree = handleTree
-
-Vue.prototype.msgSuccess = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "success" });
-}
-
-Vue.prototype.msgError = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "error" });
-}
-
-Vue.prototype.msgInfo = function (msg) {
-  this.$message.info(msg);
-}
-
-import directive from "@/components/Directives";
-Vue.use(directive)
-
-// 全局组件挂载
-Vue.component('Pagination', Pagination)
-Vue.component('RightToolbar', RightToolbar)
-Vue.component('DynamicForm', DynamicForm)
-Vue.component('DynamicForms', DynamicForms)
-Vue.component('MemoranDum', MemoranDum)
-
-Vue.use(permission)
-
-/**
- * If you don't want to use mock-server
- * you want to use MockJs for mock api
- * you can execute: mockXHR()
- *
- * Currently MockJs will be used in the production environment,
- * please remove it before going online! ! !
- */
-
-Vue.use(Element, {
-  size: Cookies.get('size') || 'medium' // set element-ui default size
-})
-
-Vue.config.productionTip = false
-
-new Vue({
-  el: '#app',
-  router,
-  store,
-  render: h => h(App)
-})
+import Vue from 'vue'
+
+import Cookies from 'js-cookie'
+
+import Element from 'element-ui'
+import './assets/styles/element-variables.scss'
+
+import '@/assets/styles/index.scss' // global css
+import '@/assets/styles/ruoyi.scss' // ruoyi css
+import App from './App'
+import store from './store'
+import router from './router'
+import permission from './directive/permission'
+import { download } from '@/utils/request'
+
+import './assets/icons' // icon
+import './permission' // permission control
+import { getDicts } from "@/api/system/dict/data";
+import { getConfigKey } from "@/api/system/config";
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
+import Pagination from "@/components/Pagination";
+// 自定义表格工具扩展
+import RightToolbar from "@/components/RightToolbar"
+import DynamicForm from "@/components/DynamicForm"
+import DynamicForms from "@/components/DynamicForms"
+import MemoranDum from "@/components/MemoranDum"
+
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
+Vue.prototype.handleTree = handleTree
+
+Vue.prototype.msgSuccess = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "success" });
+}
+
+Vue.prototype.msgError = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "error" });
+}
+
+Vue.prototype.msgInfo = function (msg) {
+  this.$message.info(msg);
+}
+
+import directive from "@/components/Directives";
+Vue.use(directive)
+
+// 全局组件挂载
+Vue.component('Pagination', Pagination)
+Vue.component('RightToolbar', RightToolbar)
+Vue.component('DynamicForm', DynamicForm)
+Vue.component('DynamicForms', DynamicForms)
+Vue.component('MemoranDum', MemoranDum)
+
+Vue.use(permission)
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online! ! !
+ */
+
+Vue.use(Element, {
+  size: Cookies.get('size') || 'medium' // set element-ui default size
+})
+
+Vue.config.productionTip = false
+
+new Vue({
+  el: '#app',
+  router,
+  store,
+  render: h => h(App)
+})

+ 52 - 52
ruoyi-ui/src/permission.js

@@ -1,52 +1,52 @@
-import router from './router'
-import store from './store'
-import { Message } from 'element-ui'
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-import { getToken } from '@/utils/auth'
-
-NProgress.configure({ showSpinner: false })
-
-const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
-
-router.beforeEach((to, from, next) => {
-  NProgress.start()
-  if (getToken()) {
-    /* has token*/
-    if (to.path === '/login') {
-      next({ path: '/' })
-      NProgress.done()
-    } else {
-      if (store.getters.roles.length === 0) {
-        // 判断当前用户是否已拉取完user_info信息
-        store.dispatch('GetInfo').then(() => {
-          store.dispatch('GenerateRoutes').then(accessRoutes => {
-            // 根据roles权限生成可访问的路由表
-            router.addRoutes(accessRoutes) // 动态添加可访问路由表
-            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
-          })
-        }).catch(err => {
-            store.dispatch('LogOut').then(() => {
-              Message.error(err)
-              next({ path: '/' })
-            })
-          })
-      } else {
-        next()
-      }
-    }
-  } else {
-    // 没有token
-    if (whiteList.indexOf(to.path) !== -1) {
-      // 在免登录白名单,直接进入
-      next()
-    } else {
-      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
-      NProgress.done()
-    }
-  }
-})
-
-router.afterEach(() => {
-  NProgress.done()
-})
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { getToken } from '@/utils/auth'
+
+NProgress.configure({ showSpinner: false })
+
+const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
+
+router.beforeEach((to, from, next) => {
+  NProgress.start()
+  if (getToken()) {
+    /* has token*/
+    if (to.path === '/login') {
+      next({ path: '/' })
+      NProgress.done()
+    } else {
+      if (store.getters.roles.length === 0) {
+        // 判断当前用户是否已拉取完user_info信息
+        store.dispatch('GetInfo').then(() => {
+          store.dispatch('GenerateRoutes').then(accessRoutes => {
+            // 根据roles权限生成可访问的路由表
+            router.addRoutes(accessRoutes) // 动态添加可访问路由表
+            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+          })
+        }).catch(err => {
+            store.dispatch('LogOut').then(() => {
+              Message.error(err)
+              next({ path: '/' })
+            })
+          })
+      } else {
+        next()
+      }
+    }
+  } else {
+    // 没有token
+    if (whiteList.indexOf(to.path) !== -1) {
+      // 在免登录白名单,直接进入
+      next()
+    } else {
+      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
+      NProgress.done()
+    }
+  }
+})
+
+router.afterEach(() => {
+  NProgress.done()
+})

+ 205 - 205
ruoyi-ui/src/router/index.js

@@ -1,205 +1,205 @@
-import Vue from 'vue'
-import Router from 'vue-router'
-
-Vue.use(Router)
-
-/* Layout */
-import Layout from '@/layout'
-import ParentView from '@/components/ParentView';
-
-/**
- * Note: 路由配置项
- *
- * hidden: true                   // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
- * alwaysShow: true               // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
- *                                // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
- *                                // 若你想不管路由下面的 children 声明的个数都显示你的根路由
- *                                // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
- * redirect: noRedirect           // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
- * name:'router-name'             // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
- * meta : {
-    noCache: true                // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
-    title: 'title'               // 设置该路由在侧边栏和面包屑中展示的名字
-    icon: 'svg-name'             // 设置该路由的图标,对应路径src/assets/icons/svg
-    breadcrumb: false            // 如果设置为false,则不会在breadcrumb面包屑中显示
-  }
- */
-
-// 公共路由
-export const constantRoutes = [
-  {
-    path: '/redirect',
-    component: Layout,
-    hidden: true,
-    children: [
-      {
-        path: '/redirect/:path(.*)',
-        component: (resolve) => require(['@/views/redirect'], resolve)
-      }
-    ]
-  },
-  {
-    path: '/login',
-    component: (resolve) => require(['@/views/login'], resolve),
-    hidden: true
-  },
-  {
-    path: '/404',
-    component: (resolve) => require(['@/views/error/404'], resolve),
-    hidden: true
-  },
-  {
-    path: '/401',
-    component: (resolve) => require(['@/views/error/401'], resolve),
-    hidden: true
-  },
-  {
-    path: '',
-    component: Layout,
-    redirect: 'index',
-    meta: { title: '首页', icon: '', noCache: true, affix: true },
-    children: [
-      {
-        path: 'index',
-        component: (resolve) => require(['@/views/index'], resolve),
-        name: '首页',
-        meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true }
-      },
-      {
-        path: 'index1',
-        name: '流程工作台',
-        hidden: false,
-        alwaysShow: true,
-        meta: { title: '流程工作台', icon: 'spot', noCache: true },
-        children: [{
-          path: 'index1',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '待我审批',
-          meta: { title: '待我审批', icon: '', noCache: false},
-        },{
-          path: 'index2',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '已办理',
-          meta: { title: '已办理', icon: '', noCache: false},
-        },{
-          path: 'index3',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '已延时',
-          meta: { title: '已延时', icon: '', noCache: false},
-        },{
-          path: 'index4',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '我的流程',
-          meta: { title: '我的流程', icon: '', noCache: false},
-        }]
-      },{
-        path: 'index2',
-        name: '工作协助',
-        hidden: false,
-        alwaysShow: true,
-        meta: { title: '工作协助', icon: 'spot', noCache: true },
-        children: [{
-          path: 'index1',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '批注',
-          meta: { title: '批注', icon: '', noCache: false},
-        },{
-          path: 'index2',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '微邮',
-          meta: { title: '微邮', icon: '', noCache: false},
-        }]
-      },{
-        path: 'index3',
-        name: '交办事项',
-        hidden: false,
-        alwaysShow: true,
-        meta: { title: '交办事项', icon: 'spot', noCache: true },
-        children: [{
-          path: 'index1',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '待我处理',
-          meta: { title: '待我处理', icon: '', noCache: false},
-        },{
-          path: 'index2',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '我的安排',
-          meta: { title: '我的安排', icon: '', noCache: false },
-        },{
-          path: 'index3',
-          hidden: false,
-          component: (resolve) => require(['@/views/index'], resolve),
-          name: '历史事务',
-          meta: { title: '历史事务', icon: '', noCache: false},
-        }]
-      }
-    ]
-  },
-  {
-    path: '/user',
-    component: Layout,
-    hidden: true,
-    redirect: 'noredirect',
-    children: [
-      {
-        path: 'profile',
-        component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
-        name: 'Profile',
-        meta: { title: '个人中心', icon: 'user' }
-      }
-    ]
-  },
-  {
-    path: '/dict',
-    component: Layout,
-    hidden: true,
-    children: [
-      {
-        path: 'type/data/:dictId(\\d+)',
-        component: (resolve) => require(['@/views/system/dict/data'], resolve),
-        name: 'Data',
-        meta: { title: '字典数据', icon: '' }
-      }
-    ]
-  },
-  {
-    path: '/job',
-    component: Layout,
-    hidden: true,
-    children: [
-      {
-        path: 'log',
-        component: (resolve) => require(['@/views/monitor/job/log'], resolve),
-        name: 'JobLog',
-        meta: { title: '调度日志' }
-      }
-    ]
-  },
-  {
-    path: '/gen',
-    component: Layout,
-    hidden: true,
-    children: [
-      {
-        path: 'edit/:tableId(\\d+)',
-        component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
-        name: 'GenEdit',
-        meta: { title: '修改生成配置' }
-      }
-    ]
-  }
-]
-
-export default new Router({
-  mode: 'history', // 去掉url中的#
-  scrollBehavior: () => ({ y: 0 }),
-  routes: constantRoutes
-})
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+import ParentView from '@/components/ParentView';
+
+/**
+ * Note: 路由配置项
+ *
+ * hidden: true                   // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
+ * alwaysShow: true               // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+ *                                // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
+ *                                // 若你想不管路由下面的 children 声明的个数都显示你的根路由
+ *                                // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
+ * redirect: noRedirect           // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+ * name:'router-name'             // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
+ * meta : {
+    noCache: true                // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
+    title: 'title'               // 设置该路由在侧边栏和面包屑中展示的名字
+    icon: 'svg-name'             // 设置该路由的图标,对应路径src/assets/icons/svg
+    breadcrumb: false            // 如果设置为false,则不会在breadcrumb面包屑中显示
+  }
+ */
+
+// 公共路由
+export const constantRoutes = [
+  {
+    path: '/redirect',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: '/redirect/:path(.*)',
+        component: (resolve) => require(['@/views/redirect'], resolve)
+      }
+    ]
+  },
+  {
+    path: '/login',
+    component: (resolve) => require(['@/views/login'], resolve),
+    hidden: true
+  },
+  {
+    path: '/404',
+    component: (resolve) => require(['@/views/error/404'], resolve),
+    hidden: true
+  },
+  {
+    path: '/401',
+    component: (resolve) => require(['@/views/error/401'], resolve),
+    hidden: true
+  },
+  {
+    path: '',
+    component: Layout,
+    redirect: 'index',
+    meta: { title: '首页', icon: '', noCache: true, affix: true },
+    children: [
+      {
+        path: 'index',
+        component: (resolve) => require(['@/views/index'], resolve),
+        name: '首页',
+        meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true }
+      },
+      {
+        path: 'index1',
+        name: '流程工作台',
+        hidden: false,
+        alwaysShow: true,
+        meta: { title: '流程工作台', icon: 'spot', noCache: true },
+        children: [{
+          path: 'index1',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '待我审批',
+          meta: { title: '待我审批', icon: '', noCache: false},
+        },{
+          path: 'index2',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '已办理',
+          meta: { title: '已办理', icon: '', noCache: false},
+        },{
+          path: 'index3',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '已延时',
+          meta: { title: '已延时', icon: '', noCache: false},
+        },{
+          path: 'index4',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '我的流程',
+          meta: { title: '我的流程', icon: '', noCache: false},
+        }]
+      },{
+        path: 'index2',
+        name: '工作协助',
+        hidden: false,
+        alwaysShow: true,
+        meta: { title: '工作协助', icon: 'spot', noCache: true },
+        children: [{
+          path: 'index1',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '批注',
+          meta: { title: '批注', icon: '', noCache: false},
+        },{
+          path: 'index2',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '微邮',
+          meta: { title: '微邮', icon: '', noCache: false},
+        }]
+      },{
+        path: 'index3',
+        name: '交办事项',
+        hidden: false,
+        alwaysShow: true,
+        meta: { title: '交办事项', icon: 'spot', noCache: true },
+        children: [{
+          path: 'index1',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '待我处理',
+          meta: { title: '待我处理', icon: '', noCache: false},
+        },{
+          path: 'index2',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '我的安排',
+          meta: { title: '我的安排', icon: '', noCache: false },
+        },{
+          path: 'index3',
+          hidden: false,
+          component: (resolve) => require(['@/views/index'], resolve),
+          name: '历史事务',
+          meta: { title: '历史事务', icon: '', noCache: false},
+        }]
+      }
+    ]
+  },
+  {
+    path: '/user',
+    component: Layout,
+    hidden: true,
+    redirect: 'noredirect',
+    children: [
+      {
+        path: 'profile',
+        component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
+        name: 'Profile',
+        meta: { title: '个人中心', icon: 'user' }
+      }
+    ]
+  },
+  {
+    path: '/dict',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'type/data/:dictId(\\d+)',
+        component: (resolve) => require(['@/views/system/dict/data'], resolve),
+        name: 'Data',
+        meta: { title: '字典数据', icon: '' }
+      }
+    ]
+  },
+  {
+    path: '/job',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'log',
+        component: (resolve) => require(['@/views/monitor/job/log'], resolve),
+        name: 'JobLog',
+        meta: { title: '调度日志' }
+      }
+    ]
+  },
+  {
+    path: '/gen',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'edit/:tableId(\\d+)',
+        component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
+        name: 'GenEdit',
+        meta: { title: '修改生成配置' }
+      }
+    ]
+  }
+]
+
+export default new Router({
+  mode: 'history', // 去掉url中的#
+  scrollBehavior: () => ({ y: 0 }),
+  routes: constantRoutes
+})

+ 17 - 17
ruoyi-ui/src/store/getters.js

@@ -1,17 +1,17 @@
-const getters = {
-  sidebar: state => state.app.sidebar,
-  size: state => state.app.size,
-  device: state => state.app.device,
-  visitedViews: state => state.tagsView.visitedViews,
-  cachedViews: state => state.tagsView.cachedViews,
-  token: state => state.user.token,
-  avatar: state => state.user.avatar,
-  name: state => state.user.name,
-  introduction: state => state.user.introduction,
-  roles: state => state.user.roles,
-  permissions: state => state.user.permissions,
-  permission_routes: state => state.permission.routes,
-  sidebarRouters:state => state.permission.sidebarRouters,
-  tabIndex:state => state.permission.tabIndex,
-}
-export default getters
+const getters = {
+  sidebar: state => state.app.sidebar,
+  size: state => state.app.size,
+  device: state => state.app.device,
+  visitedViews: state => state.tagsView.visitedViews,
+  cachedViews: state => state.tagsView.cachedViews,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name,
+  introduction: state => state.user.introduction,
+  roles: state => state.user.roles,
+  permissions: state => state.user.permissions,
+  permission_routes: state => state.permission.routes,
+  sidebarRouters:state => state.permission.sidebarRouters,
+  tabIndex:state => state.permission.tabIndex,
+}
+export default getters

+ 23 - 23
ruoyi-ui/src/store/index.js

@@ -1,23 +1,23 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-import app from './modules/app'
-import user from './modules/user'
-import tagsView from './modules/tagsView'
-import permission from './modules/permission'
-import settings from './modules/settings'
-import getters from './getters'
-
-Vue.use(Vuex)
-
-const store = new Vuex.Store({
-  modules: {
-    app,
-    user,
-    tagsView,
-    permission,
-    settings
-  },
-  getters
-})
-
-export default store
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import user from './modules/user'
+import tagsView from './modules/tagsView'
+import permission from './modules/permission'
+import settings from './modules/settings'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    app,
+    user,
+    tagsView,
+    permission,
+    settings
+  },
+  getters
+})
+
+export default store

+ 56 - 56
ruoyi-ui/src/store/modules/app.js

@@ -1,56 +1,56 @@
-import Cookies from 'js-cookie'
-
-const state = {
-  sidebar: {
-    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
-    withoutAnimation: false
-  },
-  device: 'desktop',
-  size: Cookies.get('size') || 'medium'
-}
-
-const mutations = {
-  TOGGLE_SIDEBAR: state => {
-    state.sidebar.opened = !state.sidebar.opened
-    state.sidebar.withoutAnimation = false
-    if (state.sidebar.opened) {
-      Cookies.set('sidebarStatus', 1)
-    } else {
-      Cookies.set('sidebarStatus', 0)
-    }
-  },
-  CLOSE_SIDEBAR: (state, withoutAnimation) => {
-    Cookies.set('sidebarStatus', 0)
-    state.sidebar.opened = false
-    state.sidebar.withoutAnimation = withoutAnimation
-  },
-  TOGGLE_DEVICE: (state, device) => {
-    state.device = device
-  },
-  SET_SIZE: (state, size) => {
-    state.size = size
-    Cookies.set('size', size)
-  }
-}
-
-const actions = {
-  toggleSideBar({ commit }) {
-    commit('TOGGLE_SIDEBAR')
-  },
-  closeSideBar({ commit }, { withoutAnimation }) {
-    commit('CLOSE_SIDEBAR', withoutAnimation)
-  },
-  toggleDevice({ commit }, device) {
-    commit('TOGGLE_DEVICE', device)
-  },
-  setSize({ commit }, size) {
-    commit('SET_SIZE', size)
-  }
-}
-
-export default {
-  namespaced: true,
-  state,
-  mutations,
-  actions
-}
+import Cookies from 'js-cookie'
+
+const state = {
+  sidebar: {
+    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+    withoutAnimation: false
+  },
+  device: 'desktop',
+  size: Cookies.get('size') || 'medium'
+}
+
+const mutations = {
+  TOGGLE_SIDEBAR: state => {
+    state.sidebar.opened = !state.sidebar.opened
+    state.sidebar.withoutAnimation = false
+    if (state.sidebar.opened) {
+      Cookies.set('sidebarStatus', 1)
+    } else {
+      Cookies.set('sidebarStatus', 0)
+    }
+  },
+  CLOSE_SIDEBAR: (state, withoutAnimation) => {
+    Cookies.set('sidebarStatus', 0)
+    state.sidebar.opened = false
+    state.sidebar.withoutAnimation = withoutAnimation
+  },
+  TOGGLE_DEVICE: (state, device) => {
+    state.device = device
+  },
+  SET_SIZE: (state, size) => {
+    state.size = size
+    Cookies.set('size', size)
+  }
+}
+
+const actions = {
+  toggleSideBar({ commit }) {
+    commit('TOGGLE_SIDEBAR')
+  },
+  closeSideBar({ commit }, { withoutAnimation }) {
+    commit('CLOSE_SIDEBAR', withoutAnimation)
+  },
+  toggleDevice({ commit }, device) {
+    commit('TOGGLE_DEVICE', device)
+  },
+  setSize({ commit }, size) {
+    commit('SET_SIZE', size)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}

+ 107 - 107
ruoyi-ui/src/store/modules/permission.js

@@ -1,107 +1,107 @@
-import { constantRoutes } from '@/router'
-import { getRouters } from '@/api/menu'
-import Layout from '@/layout/index'
-import ParentView from '@/components/ParentView';
-
-const permission = {
-  state: {
-    routes: [],
-    addRoutes: [],
-    sidebarRouters: [],
-    tabIndex: '',
-  },
-  mutations: {
-    SET_TABINDEX: (state, tabIndex) => {
-      state.tabIndex = tabIndex
-    },
-    SET_ROUTES: (state, routes) => {
-      state.addRoutes = routes
-      state.routes = constantRoutes.concat(routes)
-    },
-    SET_SIDEBAR_ROUTERS: (state, routers) => {
-      state.sidebarRouters = constantRoutes.concat(routers)
-    },
-  },
-  actions: {
-    // 根据属性修改tab值
-    TabFn({ commit, state },userInfo){
-      return new Promise(resolve => {
-        commit('SET_TABINDEX', userInfo)
-        resolve()
-      })
-    },
-    // 生成路由
-    GenerateRoutes({ commit }) {
-      return new Promise(resolve => {
-        // 向后端请求路由数据
-        getRouters().then(res => {
-          const sdata = JSON.parse(JSON.stringify(res.data))
-          const rdata = JSON.parse(JSON.stringify(res.data))
-          const sidebarRoutes = filterAsyncRouter(sdata)
-          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
-          console.log(sdata,sidebarRoutes,9998888)
-          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
-          commit('SET_ROUTES', rewriteRoutes)
-          commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
-          resolve(rewriteRoutes)
-        })
-      })
-    }
-  }
-}
-
-// 遍历后台传来的路由字符串,转换为组件对象
-function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
-  return asyncRouterMap.filter(route => {
-    if (type && route.children) {
-      route.children = filterChildren(route.children)
-    }
-    if (route.component) {
-      // Layout ParentView 组件特殊处理
-      if (route.component === 'Layout') {
-        route.component = Layout
-      } else if (route.component === 'ParentView') {
-        route.component = ParentView
-      } else {
-        route.component = loadView(route.component)
-      }
-    }
-    if (route.children != null && route.children && route.children.length) {
-      route.children = filterAsyncRouter(route.children, route, type)
-    } else {
-      delete route['children']
-      delete route['redirect']
-    }
-    return true
-  })
-}
-
-function filterChildren(childrenMap, lastRouter = false) {
-  var children = []
-  childrenMap.forEach((el, index) => {
-    if (el.children && el.children.length) {
-      if (el.component === 'ParentView') {
-        el.children.forEach(c => {
-          c.path = el.path + '/' + c.path
-          if (c.children && c.children.length) {
-            children = children.concat(filterChildren(c.children, c))
-            return
-          }
-          children.push(c)
-        })
-        return
-      }
-    }
-    if (lastRouter) {
-      el.path = lastRouter.path + '/' + el.path
-    }
-    children = children.concat(el)
-  })
-  return children
-}
-
-export const loadView = (view) => { // 路由懒加载
-  return (resolve) => require([`@/views/${view}`], resolve)
-}
-
-export default permission
+import { constantRoutes } from '@/router'
+import { getRouters } from '@/api/menu'
+import Layout from '@/layout/index'
+import ParentView from '@/components/ParentView';
+
+const permission = {
+  state: {
+    routes: [],
+    addRoutes: [],
+    sidebarRouters: [],
+    tabIndex: '',
+  },
+  mutations: {
+    SET_TABINDEX: (state, tabIndex) => {
+      state.tabIndex = tabIndex
+    },
+    SET_ROUTES: (state, routes) => {
+      state.addRoutes = routes
+      state.routes = constantRoutes.concat(routes)
+    },
+    SET_SIDEBAR_ROUTERS: (state, routers) => {
+      state.sidebarRouters = constantRoutes.concat(routers)
+    },
+  },
+  actions: {
+    // 根据属性修改tab值
+    TabFn({ commit, state },userInfo){
+      return new Promise(resolve => {
+        commit('SET_TABINDEX', userInfo)
+        resolve()
+      })
+    },
+    // 生成路由
+    GenerateRoutes({ commit }) {
+      return new Promise(resolve => {
+        // 向后端请求路由数据
+        getRouters().then(res => {
+          const sdata = JSON.parse(JSON.stringify(res.data))
+          const rdata = JSON.parse(JSON.stringify(res.data))
+          const sidebarRoutes = filterAsyncRouter(sdata)
+          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
+          console.log(sdata,sidebarRoutes,9998888)
+          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
+          commit('SET_ROUTES', rewriteRoutes)
+          commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
+          resolve(rewriteRoutes)
+        })
+      })
+    }
+  }
+}
+
+// 遍历后台传来的路由字符串,转换为组件对象
+function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
+  return asyncRouterMap.filter(route => {
+    if (type && route.children) {
+      route.children = filterChildren(route.children)
+    }
+    if (route.component) {
+      // Layout ParentView 组件特殊处理
+      if (route.component === 'Layout') {
+        route.component = Layout
+      } else if (route.component === 'ParentView') {
+        route.component = ParentView
+      } else {
+        route.component = loadView(route.component)
+      }
+    }
+    if (route.children != null && route.children && route.children.length) {
+      route.children = filterAsyncRouter(route.children, route, type)
+    } else {
+      delete route['children']
+      delete route['redirect']
+    }
+    return true
+  })
+}
+
+function filterChildren(childrenMap, lastRouter = false) {
+  var children = []
+  childrenMap.forEach((el, index) => {
+    if (el.children && el.children.length) {
+      if (el.component === 'ParentView') {
+        el.children.forEach(c => {
+          c.path = el.path + '/' + c.path
+          if (c.children && c.children.length) {
+            children = children.concat(filterChildren(c.children, c))
+            return
+          }
+          children.push(c)
+        })
+        return
+      }
+    }
+    if (lastRouter) {
+      el.path = lastRouter.path + '/' + el.path
+    }
+    children = children.concat(el)
+  })
+  return children
+}
+
+export const loadView = (view) => { // 路由懒加载
+  return (resolve) => require([`@/views/${view}`], resolve)
+}
+
+export default permission

+ 35 - 35
ruoyi-ui/src/store/modules/settings.js

@@ -1,35 +1,35 @@
-import variables from '@/assets/styles/element-variables.scss'
-import defaultSettings from '@/settings'
-
-const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
-
-const state = {
-  theme: variables.theme,
-  sideTheme: sideTheme,
-  showSettings: showSettings,
-  tagsView: tagsView,
-  fixedHeader: fixedHeader,
-  sidebarLogo: sidebarLogo
-}
-
-const mutations = {
-  CHANGE_SETTING: (state, { key, value }) => {
-    if (state.hasOwnProperty(key)) {
-      state[key] = value
-    }
-  }
-}
-
-const actions = {
-  changeSetting({ commit }, data) {
-    commit('CHANGE_SETTING', data)
-  }
-}
-
-export default {
-  namespaced: true,
-  state,
-  mutations,
-  actions
-}
-
+import variables from '@/assets/styles/element-variables.scss'
+import defaultSettings from '@/settings'
+
+const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
+
+const state = {
+  theme: variables.theme,
+  sideTheme: sideTheme,
+  showSettings: showSettings,
+  tagsView: tagsView,
+  fixedHeader: fixedHeader,
+  sidebarLogo: sidebarLogo
+}
+
+const mutations = {
+  CHANGE_SETTING: (state, { key, value }) => {
+    if (state.hasOwnProperty(key)) {
+      state[key] = value
+    }
+  }
+}
+
+const actions = {
+  changeSetting({ commit }, data) {
+    commit('CHANGE_SETTING', data)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+

+ 159 - 159
ruoyi-ui/src/store/modules/tagsView.js

@@ -1,159 +1,159 @@
-const state = {
-  visitedViews: [],
-  cachedViews: []
-}
-
-const mutations = {
-  ADD_VISITED_VIEW: (state, view) => {
-    if (state.visitedViews.some(v => v.path === view.path)) return
-    state.visitedViews.push(
-      Object.assign({}, view, {
-        title: view.meta.title || 'no-name'
-      })
-    )
-  },
-  ADD_CACHED_VIEW: (state, view) => {
-    if (state.cachedViews.includes(view.name)) return
-    if (!view.meta.noCache) {
-      state.cachedViews.push(view.name)
-    }
-  },
-
-  DEL_VISITED_VIEW: (state, view) => {
-    for (const [i, v] of state.visitedViews.entries()) {
-      if (v.path === view.path) {
-        state.visitedViews.splice(i, 1)
-        break
-      }
-    }
-  },
-  DEL_CACHED_VIEW: (state, view) => {
-    const index = state.cachedViews.indexOf(view.name)
-    index > -1 && state.cachedViews.splice(index, 1)
-  },
-
-  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
-    state.visitedViews = state.visitedViews.filter(v => {
-      return v.meta.affix || v.path === view.path
-    })
-  },
-  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
-    const index = state.cachedViews.indexOf(view.name)
-    if (index > -1) {
-      state.cachedViews = state.cachedViews.slice(index, index + 1)
-    } else {
-      state.cachedViews = []
-    }
-  },
-
-  DEL_ALL_VISITED_VIEWS: state => {
-    // keep affix tags
-    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
-    state.visitedViews = affixTags
-  },
-  DEL_ALL_CACHED_VIEWS: state => {
-    state.cachedViews = []
-  },
-
-  UPDATE_VISITED_VIEW: (state, view) => {
-    for (let v of state.visitedViews) {
-      if (v.path === view.path) {
-        v = Object.assign(v, view)
-        break
-      }
-    }
-  }
-}
-
-const actions = {
-  addView({ dispatch }, view) {
-    dispatch('addVisitedView', view)
-    dispatch('addCachedView', view)
-  },
-  addVisitedView({ commit }, view) {
-    commit('ADD_VISITED_VIEW', view)
-  },
-  addCachedView({ commit }, view) {
-    commit('ADD_CACHED_VIEW', view)
-  },
-
-  delView({ dispatch, state }, view) {
-    return new Promise(resolve => {
-      dispatch('delVisitedView', view)
-      dispatch('delCachedView', view)
-      resolve({
-        visitedViews: [...state.visitedViews],
-        cachedViews: [...state.cachedViews]
-      })
-    })
-  },
-  delVisitedView({ commit, state }, view) {
-    return new Promise(resolve => {
-      commit('DEL_VISITED_VIEW', view)
-      resolve([...state.visitedViews])
-    })
-  },
-  delCachedView({ commit, state }, view) {
-    return new Promise(resolve => {
-      commit('DEL_CACHED_VIEW', view)
-      resolve([...state.cachedViews])
-    })
-  },
-
-  delOthersViews({ dispatch, state }, view) {
-    return new Promise(resolve => {
-      dispatch('delOthersVisitedViews', view)
-      dispatch('delOthersCachedViews', view)
-      resolve({
-        visitedViews: [...state.visitedViews],
-        cachedViews: [...state.cachedViews]
-      })
-    })
-  },
-  delOthersVisitedViews({ commit, state }, view) {
-    return new Promise(resolve => {
-      commit('DEL_OTHERS_VISITED_VIEWS', view)
-      resolve([...state.visitedViews])
-    })
-  },
-  delOthersCachedViews({ commit, state }, view) {
-    return new Promise(resolve => {
-      commit('DEL_OTHERS_CACHED_VIEWS', view)
-      resolve([...state.cachedViews])
-    })
-  },
-
-  delAllViews({ dispatch, state }, view) {
-    return new Promise(resolve => {
-      dispatch('delAllVisitedViews', view)
-      dispatch('delAllCachedViews', view)
-      resolve({
-        visitedViews: [...state.visitedViews],
-        cachedViews: [...state.cachedViews]
-      })
-    })
-  },
-  delAllVisitedViews({ commit, state }) {
-    return new Promise(resolve => {
-      commit('DEL_ALL_VISITED_VIEWS')
-      resolve([...state.visitedViews])
-    })
-  },
-  delAllCachedViews({ commit, state }) {
-    return new Promise(resolve => {
-      commit('DEL_ALL_CACHED_VIEWS')
-      resolve([...state.cachedViews])
-    })
-  },
-
-  updateVisitedView({ commit }, view) {
-    commit('UPDATE_VISITED_VIEW', view)
-  }
-}
-
-export default {
-  namespaced: true,
-  state,
-  mutations,
-  actions
-}
+const state = {
+  visitedViews: [],
+  cachedViews: []
+}
+
+const mutations = {
+  ADD_VISITED_VIEW: (state, view) => {
+    if (state.visitedViews.some(v => v.path === view.path)) return
+    state.visitedViews.push(
+      Object.assign({}, view, {
+        title: view.meta.title || 'no-name'
+      })
+    )
+  },
+  ADD_CACHED_VIEW: (state, view) => {
+    if (state.cachedViews.includes(view.name)) return
+    if (!view.meta.noCache) {
+      state.cachedViews.push(view.name)
+    }
+  },
+
+  DEL_VISITED_VIEW: (state, view) => {
+    for (const [i, v] of state.visitedViews.entries()) {
+      if (v.path === view.path) {
+        state.visitedViews.splice(i, 1)
+        break
+      }
+    }
+  },
+  DEL_CACHED_VIEW: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    index > -1 && state.cachedViews.splice(index, 1)
+  },
+
+  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+    state.visitedViews = state.visitedViews.filter(v => {
+      return v.meta.affix || v.path === view.path
+    })
+  },
+  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    if (index > -1) {
+      state.cachedViews = state.cachedViews.slice(index, index + 1)
+    } else {
+      state.cachedViews = []
+    }
+  },
+
+  DEL_ALL_VISITED_VIEWS: state => {
+    // keep affix tags
+    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+    state.visitedViews = affixTags
+  },
+  DEL_ALL_CACHED_VIEWS: state => {
+    state.cachedViews = []
+  },
+
+  UPDATE_VISITED_VIEW: (state, view) => {
+    for (let v of state.visitedViews) {
+      if (v.path === view.path) {
+        v = Object.assign(v, view)
+        break
+      }
+    }
+  }
+}
+
+const actions = {
+  addView({ dispatch }, view) {
+    dispatch('addVisitedView', view)
+    dispatch('addCachedView', view)
+  },
+  addVisitedView({ commit }, view) {
+    commit('ADD_VISITED_VIEW', view)
+  },
+  addCachedView({ commit }, view) {
+    commit('ADD_CACHED_VIEW', view)
+  },
+
+  delView({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delVisitedView', view)
+      dispatch('delCachedView', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delVisitedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_VISITED_VIEW', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delCachedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_CACHED_VIEW', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delOthersViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delOthersVisitedViews', view)
+      dispatch('delOthersCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delOthersVisitedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_VISITED_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delOthersCachedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_CACHED_VIEWS', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delAllViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delAllVisitedViews', view)
+      dispatch('delAllCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delAllVisitedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_VISITED_VIEWS')
+      resolve([...state.visitedViews])
+    })
+  },
+  delAllCachedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_CACHED_VIEWS')
+      resolve([...state.cachedViews])
+    })
+  },
+
+  updateVisitedView({ commit }, view) {
+    commit('UPDATE_VISITED_VIEW', view)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}

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