Browse Source

Merge branch 'refactor/theme' into main

xiaoxian521 3 years ago
parent
commit
2f457ac6b2
52 changed files with 881 additions and 572 deletions
  1. 1 1
      .env
  2. 1 1
      .env.development
  3. 1 0
      .gitignore
  4. 13 0
      CHANGELOG.en_US.md
  5. 13 0
      CHANGELOG.md
  6. 13 0
      CHANGELOG.zh_CN.md
  7. 2 2
      mock/asyncRoutes.ts
  8. 8 6
      package.json
  9. 107 76
      pnpm-lock.yaml
  10. 6 2
      public/serverConfig.json
  11. 1 7
      src/App.vue
  12. 7 1
      src/api/user.ts
  13. BIN
      src/assets/bg-logo.png
  14. BIN
      src/assets/iconfont/iconfont.ttf
  15. BIN
      src/assets/iconfont/iconfont.woff
  16. BIN
      src/assets/iconfont/iconfont.woff2
  17. 1 8
      src/components/ReMap/src/Amap.vue
  18. 15 0
      src/layout/components/appMain.vue
  19. 22 4
      src/layout/components/navbar.vue
  20. 3 1
      src/layout/components/panel/index.vue
  21. 220 202
      src/layout/components/setting/index.vue
  22. 20 2
      src/layout/components/sidebar/horizontal.vue
  23. 21 21
      src/layout/components/sidebar/sidebarItem.vue
  24. 12 6
      src/layout/components/tag/index.vue
  25. 46 22
      src/layout/index.vue
  26. 12 0
      src/layout/theme/auroraGreen-vars.scss
  27. 24 0
      src/layout/theme/default-vars.scss
  28. 12 0
      src/layout/theme/dusk-vars.scss
  29. 11 0
      src/layout/theme/light-vars.scss
  30. 12 0
      src/layout/theme/mingQing-vars.scss
  31. 12 0
      src/layout/theme/pink-vars.scss
  32. 12 0
      src/layout/theme/saucePurple-vars.scss
  33. 12 0
      src/layout/theme/volcano-vars.scss
  34. 12 0
      src/layout/theme/yellow-vars.scss
  35. 6 0
      src/layout/types.ts
  36. 40 2
      src/plugins/element-plus/index.ts
  37. 2 2
      src/plugins/i18n/config.ts
  38. 1 1
      src/router/modules/components.ts
  39. 1 1
      src/router/modules/editor.ts
  40. 1 1
      src/router/modules/error.ts
  41. 1 2
      src/router/modules/externalLink.ts
  42. 1 1
      src/router/modules/flowchart.ts
  43. 1 1
      src/router/modules/home.ts
  44. 1 1
      src/router/modules/nested.ts
  45. 1 1
      src/router/modules/remaining.ts
  46. 3 2
      src/store/modules/app.ts
  47. 0 4
      src/style/element-plus.scss
  48. 84 186
      src/style/sidebar.scss
  49. 11 2
      src/utils/storage/responsive.ts
  50. 3 2
      src/views/login.vue
  51. 4 0
      types/global.d.ts
  52. 68 1
      vite.config.ts

+ 1 - 1
.env

@@ -3,7 +3,7 @@ VITE_PORT = 8848
 # title
 VITE_TITLE = vue-pure-admin
 # version
-VITE_VERSION = 2.1.0
+VITE_VERSION = 2.6.0
 # open
 VITE_OPEN = false
 

+ 1 - 1
.env.development

@@ -3,7 +3,7 @@ VITE_PORT = 8848
 # title
 VITE_TITLE = vue-pure-admin
 # version
-VITE_VERSION = 2.1.0
+VITE_VERSION = 2.6.0
 # open
 VITE_OPEN = false
 

+ 1 - 0
.gitignore

@@ -5,6 +5,7 @@ dist-ssr
 *.local
 .eslintcache
 
+yarn.lock
 npm-debug.log*
 .pnpm-error.log*
 .pnpm-debug.log

+ 13 - 0
CHANGELOG.en_US.md

@@ -1,3 +1,16 @@
+# 2.6.0(2021-11-10)
+
+### 🎫 Feat
+
+- Refactored navigation theme color, supports multiple color schemes
+- Refactored login page, illustration style
+
+### 🍏 Perf
+
+- Optimize the navigation style
+- Eliminate strong navigation dependence on vxe-table
+- Synchronously update element-plus, replace Font Icon with SVG Icon
+
 # 2.1.0(2021-10-14)
 
 ### 🎫 Feat

+ 13 - 0
CHANGELOG.md

@@ -1,3 +1,16 @@
+# 2.6.0(2021-11-10)
+
+### 🎫 Feat
+
+- Refactored navigation theme color, supports multiple color schemes
+- Refactored login page, illustration style
+
+### 🍏 Perf
+
+- Optimize the navigation style
+- Eliminate strong navigation dependence on vxe-table
+- Synchronously update element-plus, replace Font Icon with SVG Icon
+
 # 2.1.0(2021-10-14)
 
 ### 🎫 Feat

+ 13 - 0
CHANGELOG.zh_CN.md

@@ -1,3 +1,16 @@
+# 2.6.0(2021-11-10)
+
+### 🎫 Feat
+
+- 重构导航主题色,支持多种配色
+- 重构登录页,插画风格
+
+### 🍏 Perf
+
+- 优化导航样式
+- 剔除导航强依赖 vxe-table
+- 同步更新 element-plus,使用 SVG Icon 替换 Font Icon
+
 # 2.1.0(2021-10-14)
 
 ### 🎫 Feat

+ 2 - 2
mock/asyncRoutes.ts

@@ -7,7 +7,7 @@ const systemRouter = {
   name: "system",
   redirect: "/system/user",
   meta: {
-    icon: "el-icon-setting",
+    icon: "Setting",
     title: "message.hssysManagement",
     showLink: true,
     rank: 6
@@ -38,7 +38,7 @@ const permissionRouter = {
   redirect: "/permission/page",
   meta: {
     title: "message.permission",
-    icon: "el-icon-lollipop",
+    icon: "Lollipop",
     showLink: true,
     rank: 3
   },

+ 8 - 6
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue-pure-admin",
-  "version": "2.1.0",
+  "version": "2.6.0",
   "private": true,
   "engines": {
     "node": ">= 16",
@@ -29,6 +29,7 @@
   ],
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
+    "@element-plus/icons": "^0.0.11",
     "@logicflow/core": "0.7.1",
     "@logicflow/extension": "0.7.1",
     "@vueuse/core": "^6.7.1",
@@ -39,7 +40,7 @@
     "cropperjs": "^1.5.11",
     "dayjs": "^1.10.7",
     "echarts": "^5.2.1",
-    "element-plus": "1.1.0-beta.24",
+    "element-plus": "1.2.0-beta.3",
     "element-resize-detector": "^1.2.3",
     "font-awesome": "^4.7.0",
     "lodash-es": "^4.17.21",
@@ -76,11 +77,12 @@
     "@types/nprogress": "0.2.0",
     "@typescript-eslint/eslint-plugin": "4.31.0",
     "@typescript-eslint/parser": "4.31.0",
-    "@vitejs/plugin-vue": "1.6.0",
-    "@vitejs/plugin-vue-jsx": "1.1.7",
+    "@vitejs/plugin-vue": "^1.9.4",
+    "@vitejs/plugin-vue-jsx": "^1.2.0",
     "@vue/compiler-sfc": "^3.2.21",
     "@vue/eslint-config-prettier": "6.0.0",
     "@vue/eslint-config-typescript": "7.0.0",
+    "@zougt/vite-plugin-theme-preprocessor": "^1.3.10",
     "autoprefixer": "10.2.4",
     "babel-plugin-transform-remove-console": "6.9.4",
     "chalk": "2.4.2",
@@ -95,8 +97,8 @@
     "prettier": "2.3.2",
     "pretty-quick": "3.1.1",
     "rimraf": "3.0.2",
-    "sass": "1.32.8",
-    "sass-loader": "12.1.0",
+    "sass": "^1.43.4",
+    "sass-loader": "^12.3.0",
     "stylelint": "13.13.1",
     "stylelint-config-prettier": "8.0.2",
     "stylelint-config-standard": "22.0.0",

+ 107 - 76
pnpm-lock.yaml

@@ -4,6 +4,7 @@ specifiers:
   "@amap/amap-jsapi-loader": ^1.0.1
   "@commitlint/cli": 13.1.0
   "@commitlint/config-conventional": 13.1.0
+  "@element-plus/icons": ^0.0.11
   "@logicflow/core": 0.7.1
   "@logicflow/extension": 0.7.1
   "@types/element-resize-detector": 1.1.3
@@ -12,13 +13,14 @@ specifiers:
   "@types/nprogress": 0.2.0
   "@typescript-eslint/eslint-plugin": 4.31.0
   "@typescript-eslint/parser": 4.31.0
-  "@vitejs/plugin-vue": 1.6.0
-  "@vitejs/plugin-vue-jsx": 1.1.7
+  "@vitejs/plugin-vue": ^1.9.4
+  "@vitejs/plugin-vue-jsx": ^1.2.0
   "@vue/compiler-sfc": ^3.2.21
   "@vue/eslint-config-prettier": 6.0.0
   "@vue/eslint-config-typescript": 7.0.0
   "@vueuse/core": ^6.7.1
   "@vueuse/motion": ^2.0.0-beta.4
+  "@zougt/vite-plugin-theme-preprocessor": ^1.3.10
   animate.css: ^4.1.1
   autoprefixer: 10.2.4
   await-to-js: ^3.0.0
@@ -29,7 +31,7 @@ specifiers:
   cross-env: 7.0.3
   dayjs: ^1.10.7
   echarts: ^5.2.1
-  element-plus: 1.1.0-beta.24
+  element-plus: 1.2.0-beta.3
   element-resize-detector: ^1.2.3
   eslint: 7.30.0
   eslint-plugin-prettier: 3.4.0
@@ -52,8 +54,8 @@ specifiers:
   resize-observer-polyfill: ^1.5.1
   responsive-storage: ^1.0.11
   rimraf: 3.0.2
-  sass: 1.32.8
-  sass-loader: 12.1.0
+  sass: ^1.43.4
+  sass-loader: ^12.3.0
   sortablejs: 1.13.0
   stylelint: 13.13.1
   stylelint-config-prettier: 8.0.2
@@ -82,6 +84,7 @@ specifiers:
 
 dependencies:
   "@amap/amap-jsapi-loader": 1.0.1
+  "@element-plus/icons": 0.0.11
   "@logicflow/core": 0.7.1
   "@logicflow/extension": 0.7.1
   "@vueuse/core": 6.7.5_vue@3.2.21
@@ -92,7 +95,7 @@ dependencies:
   cropperjs: 1.5.12
   dayjs: 1.10.7
   echarts: 5.2.2
-  element-plus: 1.1.0-beta.24_vue@3.2.21
+  element-plus: 1.2.0-beta.3_vue@3.2.21
   element-resize-detector: 1.2.3
   font-awesome: 4.7.0
   lodash-es: 4.17.21
@@ -129,11 +132,12 @@ devDependencies:
   "@types/nprogress": 0.2.0
   "@typescript-eslint/eslint-plugin": 4.31.0_f4e6dc0776b3600ef484e3c64a523136
   "@typescript-eslint/parser": 4.31.0_eslint@7.30.0+typescript@4.4.2
-  "@vitejs/plugin-vue": 1.6.0_@vue+compiler-sfc@3.2.21
-  "@vitejs/plugin-vue-jsx": 1.1.7
+  "@vitejs/plugin-vue": 1.9.4_vite@2.6.14
+  "@vitejs/plugin-vue-jsx": 1.2.0
   "@vue/compiler-sfc": 3.2.21
   "@vue/eslint-config-prettier": 6.0.0_82e4252401b0cc5be86f7c2133946f49
   "@vue/eslint-config-typescript": 7.0.0_e03d82996bd4a66fb128f33523d782ea
+  "@zougt/vite-plugin-theme-preprocessor": 1.3.10_sass@1.43.4
   autoprefixer: 10.2.4_postcss@8.2.6
   babel-plugin-transform-remove-console: 6.9.4
   chalk: 2.4.2
@@ -148,17 +152,17 @@ devDependencies:
   prettier: 2.3.2
   pretty-quick: 3.1.1_prettier@2.3.2
   rimraf: 3.0.2
-  sass: 1.32.8
-  sass-loader: 12.1.0_sass@1.32.8
+  sass: 1.43.4
+  sass-loader: 12.3.0_sass@1.43.4
   stylelint: 13.13.1
   stylelint-config-prettier: 8.0.2_stylelint@13.13.1
   stylelint-config-standard: 22.0.0_stylelint@13.13.1
   stylelint-order: 4.1.0_stylelint@13.13.1
   typescript: 4.4.2
-  unplugin-element-plus: 0.1.3_vite@2.6.13+vue@3.2.21
-  vite: 2.6.13_sass@1.32.8
-  vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.6.13
-  vite-plugin-style-import: 1.3.0_vite@2.6.13
+  unplugin-element-plus: 0.1.3_vite@2.6.14+vue@3.2.21
+  vite: 2.6.14_sass@1.43.4
+  vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.6.14
+  vite-plugin-style-import: 1.3.0_vite@2.6.14
   vite-svg-loader: 2.2.0
   vue-eslint-parser: 7.10.0_eslint@7.30.0
 
@@ -1259,10 +1263,10 @@ packages:
       eslint-visitor-keys: 2.1.0
     dev: true
 
-  /@vitejs/plugin-vue-jsx/1.1.7:
+  /@vitejs/plugin-vue-jsx/1.2.0:
     resolution:
       {
-        integrity: sha512-lomCrTZ/LXUk8L+1fBX4dpW+L/S7qY4+pzS5BRG2NuLpjo26Efh4yb8nDkYM7b8COS3ea7otis0SsqD8vGOSlg==
+        integrity: sha512-Y4Er2bn8bHNiUziJizcVT1yQKTq6oOJeBrKkxvjo2yKT/RTSK1ZlkP/qnzchxxuBkx0tYG4Aaxbb9xuVnNNDEA==
       }
     engines: { node: ">=12.0.0" }
     dependencies:
@@ -1276,16 +1280,16 @@ packages:
       - supports-color
     dev: true
 
-  /@vitejs/plugin-vue/1.6.0_@vue+compiler-sfc@3.2.21:
+  /@vitejs/plugin-vue/1.9.4_vite@2.6.14:
     resolution:
       {
-        integrity: sha512-n3i8htn8pTg9M+kM3cnEfsPZx/6ngInlTroth6fA1LQTJq5aTVQ8ggaE5pPoAy9vCgHPtcaXMzwpldhqRAkebQ==
+        integrity: sha512-0CZqaCoChriPTTtGkERy1LGPcYjGFpi2uYRhBPIkqJqUGV5JnJFhQAgh6oH9j5XZHfrRaisX8W0xSpO4T7S78A==
       }
     engines: { node: ">=12.0.0" }
     peerDependencies:
-      "@vue/compiler-sfc": ^3.2.6
+      vite: ^2.5.10
     dependencies:
-      "@vue/compiler-sfc": 3.2.21
+      vite: 2.6.14_sass@1.43.4
     dev: true
 
   /@vue/babel-helper-vue-transform-on/1.0.2:
@@ -1466,25 +1470,6 @@ packages:
         integrity: sha512-5EQmIPK6gw4UVYUbM959B0uPsJ58+xoMESCZs3N89XyvJ9e+fX4pqEPrOGV8OroIk3SbEvJcC+eYc8BH9JQrHA==
       }
 
-  /@vueuse/core/6.1.0_vue@3.2.21:
-    resolution:
-      {
-        integrity: sha512-6KienU5QOWKuDqvHytep14274IGKyLlACzXjifOrgDQMkqvWZIUnDhpckT/1+O8n8DN59d5wzzICZI/2sfGCyg==
-      }
-    peerDependencies:
-      "@vue/composition-api": ^1.1.0
-      vue: ^2.6.0 || ^3.2.0
-    peerDependenciesMeta:
-      "@vue/composition-api":
-        optional: true
-      vue:
-        optional: true
-    dependencies:
-      "@vueuse/shared": 6.1.0_vue@3.2.21
-      vue: 3.2.21
-      vue-demi: 0.12.1_vue@3.2.21
-    dev: false
-
   /@vueuse/core/6.7.5_vue@3.2.21:
     resolution:
       {
@@ -1522,10 +1507,10 @@ packages:
       vue-demi: 0.12.1_vue@3.2.21
     dev: false
 
-  /@vueuse/shared/6.1.0_vue@3.2.21:
+  /@vueuse/shared/6.7.5_vue@3.2.21:
     resolution:
       {
-        integrity: sha512-teW0TUQryGnEprHeOI6oH8NPVJBirknxksEiNCtdEjIi8W7JSTg8JPO+e1XlGI6ly24NDlDXUDYaHJayiaXjuw==
+        integrity: sha512-wUDMPTGUSTYsbiftKq7dYLKD2i3n0m8utbHBCyoxdyeKsmtQGIM2/XeeXjtALB7UXD6rqPsVgCMepNrPPt8zvw==
       }
     peerDependencies:
       "@vue/composition-api": ^1.1.0
@@ -1540,23 +1525,35 @@ packages:
       vue-demi: 0.12.1_vue@3.2.21
     dev: false
 
-  /@vueuse/shared/6.7.5_vue@3.2.21:
+  /@zougt/some-loader-utils/1.3.4_sass@1.43.4:
     resolution:
       {
-        integrity: sha512-wUDMPTGUSTYsbiftKq7dYLKD2i3n0m8utbHBCyoxdyeKsmtQGIM2/XeeXjtALB7UXD6rqPsVgCMepNrPPt8zvw==
+        integrity: sha512-HjlSsEVcpuDrOlUXRMZzLdoWvWAdhign3uNhuSBd4ydfoOnWBRcWNBWyt5ZvIT+CcqIRLli4LfQ3K6xSJxc6NA==
       }
+    engines: { node: ">= 10.13.0" }
     peerDependencies:
-      "@vue/composition-api": ^1.1.0
-      vue: ^2.6.0 || ^3.2.0
-    peerDependenciesMeta:
-      "@vue/composition-api":
-        optional: true
-      vue:
-        optional: true
+      less: ^3.13.1 || ^4.1.1
+      sass: ^1.32.8
     dependencies:
-      vue: 3.2.21
-      vue-demi: 0.12.1_vue@3.2.21
-    dev: false
+      parse-color: 1.0.0
+      postcss: 8.3.11
+      sass: 1.43.4
+    dev: true
+
+  /@zougt/vite-plugin-theme-preprocessor/1.3.10_sass@1.43.4:
+    resolution:
+      {
+        integrity: sha512-HHSTUYBv3quM8yRv57RJoDWqSm9cn9njCFk3ziSY+MALr7WT2uD5AmSnH9QBMVIU5jRcyPiuF3zDKbh8bifI+A==
+      }
+    engines: { node: ">= 12.0.0" }
+    dependencies:
+      "@zougt/some-loader-utils": 1.3.4_sass@1.43.4
+      fs-extra: 9.1.0
+      string-hash: 1.1.3
+    transitivePeerDependencies:
+      - less
+      - sass
+    dev: true
 
   /JSONStream/1.3.5:
     resolution:
@@ -1756,6 +1753,14 @@ packages:
       }
     dev: false
 
+  /at-least-node/1.0.0:
+    resolution:
+      {
+        integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+      }
+    engines: { node: ">= 4.0.0" }
+    dev: true
+
   /autoprefixer/10.2.4_postcss@8.2.6:
     resolution:
       {
@@ -2112,6 +2117,10 @@ packages:
     engines: { node: ">=0.8" }
     dev: true
 
+  /color-convert/0.5.3:
+    resolution: { integrity: sha1-vbbGnOZg+t/+CwAHzER+G59ygr0= }
+    dev: true
+
   /color-convert/1.9.3:
     resolution:
       {
@@ -2624,23 +2633,22 @@ packages:
       }
     dev: true
 
-  /element-plus/1.1.0-beta.24_vue@3.2.21:
+  /element-plus/1.2.0-beta.3_vue@3.2.21:
     resolution:
       {
-        integrity: sha512-dmo61e/D6mwJVacMhxOMSPb5sZPt/FPsuQQfsOs1kJWkhGDmTlny/sZvgIQr1z0zh3pjlJadGAlNS+0nySPMmw==
+        integrity: sha512-vvUxR3uL2k9K+WCWz/98hq4uPQ6jvfGf0hfzWvao7pySJkNQq9DtRPC6/4/zUceA/J6Y2Yo3xSbR19JRCwurRw==
       }
     peerDependencies:
       vue: ^3.2.0
     dependencies:
       "@element-plus/icons": 0.0.11
       "@popperjs/core": 2.10.2
-      "@vueuse/core": 6.1.0_vue@3.2.21
+      "@vueuse/core": 6.7.5_vue@3.2.21
       async-validator: 4.0.7
       dayjs: 1.10.7
       lodash: 4.17.21
-      memoize-one: 5.2.1
+      memoize-one: 6.0.0
       normalize-wheel-es: 1.1.1
-      resize-observer-polyfill: 1.5.1
       vue: 3.2.21
     transitivePeerDependencies:
       - "@vue/composition-api"
@@ -3511,6 +3519,19 @@ packages:
       universalify: 0.1.2
     dev: false
 
+  /fs-extra/9.1.0:
+    resolution:
+      {
+        integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
+      }
+    engines: { node: ">=10" }
+    dependencies:
+      at-least-node: 1.0.0
+      graceful-fs: 4.2.8
+      jsonfile: 6.1.0
+      universalify: 2.0.0
+    dev: true
+
   /fs.realpath/1.0.0:
     resolution: { integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8= }
     dev: true
@@ -4461,10 +4482,10 @@ packages:
       }
     dev: true
 
-  /memoize-one/5.2.1:
+  /memoize-one/6.0.0:
     resolution:
       {
-        integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+        integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
       }
     dev: false
 
@@ -4880,6 +4901,12 @@ packages:
       callsites: 3.1.0
     dev: true
 
+  /parse-color/1.0.0:
+    resolution: { integrity: sha1-e3SLlag/A/FqlPU15S1/PZRlhhk= }
+    dependencies:
+      color-convert: 0.5.3
+    dev: true
+
   /parse-entities/2.0.0:
     resolution:
       {
@@ -5563,10 +5590,10 @@ packages:
       }
     dev: true
 
-  /sass-loader/12.1.0_sass@1.32.8:
+  /sass-loader/12.3.0_sass@1.43.4:
     resolution:
       {
-        integrity: sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg==
+        integrity: sha512-6l9qwhdOb7qSrtOu96QQ81LVl8v6Dp9j1w3akOm0aWHyrTYtagDt5+kS32N4yq4hHk3M+rdqoRMH+lIdqvW6HA==
       }
     engines: { node: ">= 12.13.0" }
     peerDependencies:
@@ -5584,13 +5611,13 @@ packages:
     dependencies:
       klona: 2.0.5
       neo-async: 2.6.2
-      sass: 1.32.8
+      sass: 1.43.4
     dev: true
 
-  /sass/1.32.8:
+  /sass/1.43.4:
     resolution:
       {
-        integrity: sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==
+        integrity: sha512-/ptG7KE9lxpGSYiXn7Ar+lKOv37xfWsZRtFYal2QHNigyVQDx685VFT/h7ejVr+R8w7H4tmUgtulsKl5YpveOg==
       }
     engines: { node: ">=8.9.0" }
     hasBin: true
@@ -5846,6 +5873,10 @@ packages:
     engines: { node: ">=0.6.19" }
     dev: true
 
+  /string-hash/1.1.3:
+    resolution: { integrity: sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= }
+    dev: true
+
   /string-width/4.2.3:
     resolution:
       {
@@ -6394,7 +6425,7 @@ packages:
     engines: { node: ">= 0.8" }
     dev: true
 
-  /unplugin-element-plus/0.1.3_vite@2.6.13+vue@3.2.21:
+  /unplugin-element-plus/0.1.3_vite@2.6.14+vue@3.2.21:
     resolution:
       {
         integrity: sha512-6GO1tuDIXcoYFkbL26Mrd84oUOgAHShcwn/xma5bwmBN2O0N0s13RbBDsK53vm4hxRKIVuFSSr659BkpmXWm2w==
@@ -6405,7 +6436,7 @@ packages:
       "@rollup/pluginutils": 4.1.1
       es-module-lexer: 0.9.3
       magic-string: 0.25.7
-      unplugin: 0.2.19_vite@2.6.13
+      unplugin: 0.2.19_vite@2.6.14
       vue: 3.2.21
     transitivePeerDependencies:
       - rollup
@@ -6413,7 +6444,7 @@ packages:
       - webpack
     dev: true
 
-  /unplugin/0.2.19_vite@2.6.13:
+  /unplugin/0.2.19_vite@2.6.14:
     resolution:
       {
         integrity: sha512-r5PDeBBecir99rhLFp1ftqIkp5afD91anweIlWtF5Ca46FJsn2kQczD93FdFJw79R6HSF5waeYo79bFOQ9GVhQ==
@@ -6430,7 +6461,7 @@ packages:
       webpack:
         optional: true
     dependencies:
-      vite: 2.6.13_sass@1.32.8
+      vite: 2.6.14_sass@1.43.4
       webpack-virtual-modules: 0.4.3
     dev: true
 
@@ -6530,7 +6561,7 @@ packages:
       vfile-message: 2.0.4
     dev: true
 
-  /vite-plugin-mock/2.9.6_mockjs@1.1.0+vite@2.6.13:
+  /vite-plugin-mock/2.9.6_mockjs@1.1.0+vite@2.6.14:
     resolution:
       {
         integrity: sha512-/Rm59oPppe/ncbkSrUuAxIQihlI2YcBmnbR4ST1RA2VzM1C0tEQc1KlbQvnUGhXECAGTaQN2JyasiwXP6EtKgg==
@@ -6550,13 +6581,13 @@ packages:
       fast-glob: 3.2.7
       mockjs: 1.1.0
       path-to-regexp: 6.2.0
-      vite: 2.6.13_sass@1.32.8
+      vite: 2.6.14_sass@1.43.4
     transitivePeerDependencies:
       - rollup
       - supports-color
     dev: true
 
-  /vite-plugin-style-import/1.3.0_vite@2.6.13:
+  /vite-plugin-style-import/1.3.0_vite@2.6.14:
     resolution:
       {
         integrity: sha512-R3bEQcdhPqL+5CZiMXs9RGKwbBtIHBJmh7ngND3sJjCYbkBe6DGEL6DWGBS7xTaqfH+1mXRfX8lEK0W3PjQSzA==
@@ -6569,7 +6600,7 @@ packages:
       debug: 4.3.2
       es-module-lexer: 0.9.3
       magic-string: 0.25.7
-      vite: 2.6.13_sass@1.32.8
+      vite: 2.6.14_sass@1.43.4
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -6584,10 +6615,10 @@ packages:
       svgo: 2.8.0
     dev: true
 
-  /vite/2.6.13_sass@1.32.8:
+  /vite/2.6.14_sass@1.43.4:
     resolution:
       {
-        integrity: sha512-+tGZ1OxozRirTudl4M3N3UTNJOlxdVo/qBl2IlDEy/ZpTFcskp+k5ncNjayR3bRYTCbqSOFz2JWGN1UmuDMScA==
+        integrity: sha512-2HA9xGyi+EhY2MXo0+A2dRsqsAG3eFNEVIo12olkWhOmc8LfiM+eMdrXf+Ruje9gdXgvSqjLI9freec1RUM5EA==
       }
     engines: { node: ">=12.2.0" }
     hasBin: true
@@ -6607,7 +6638,7 @@ packages:
       postcss: 8.3.11
       resolve: 1.20.0
       rollup: 2.59.0
-      sass: 1.32.8
+      sass: 1.43.4
     optionalDependencies:
       fsevents: 2.3.2
     dev: true

+ 6 - 2
public/serverConfig.json

@@ -1,11 +1,15 @@
 {
-  "Version": "2.0.0",
+  "Version": "2.6.0",
   "Title": "PureAdmin",
   "FixedHeader": true,
   "HiddenSideBar": false,
   "KeepAlive": true,
   "Locale": "zh",
-  "Layout": "vertical-dark",
+  "Layout": "vertical",
+  "Theme": "default",
+  "Grey": false,
+  "Weak": false,
+  "HideTabs": false,
   "MapConfigure": {
     "amapKey": "97b3248d1553172e81f168cf94ea667e",
     "baiduKey": "wTHbkkEweiFqZLKunMIjcrb2RcqNXkhc",

+ 1 - 7
src/App.vue

@@ -14,14 +14,8 @@ export default {
     [ElConfigProvider.name]: ElConfigProvider
   },
   computed: {
-    // eslint-disable-next-line vue/return-in-computed-property
     currentLocale() {
-      switch (this.$storage.locale?.locale) {
-        case "zh":
-          return zhCn;
-        case "en":
-          return en;
-      }
+      return this.$storage.locale?.locale === "zh" ? zhCn : en;
     }
   }
 };

+ 7 - 1
src/api/user.ts

@@ -1,7 +1,13 @@
 import { http } from "../utils/http";
 
+interface userType extends Promise<any> {
+  svg?: string;
+  code?: number;
+  info?: object;
+}
+
 // 获取验证码
-export const getVerify = () => {
+export const getVerify = (): userType => {
   return http.request("get", "/captcha");
 };
 

BIN
src/assets/bg-logo.png


BIN
src/assets/iconfont/iconfont.ttf


BIN
src/assets/iconfont/iconfont.woff


BIN
src/assets/iconfont/iconfont.woff2


+ 1 - 8
src/components/ReMap/src/Amap.vue

@@ -126,14 +126,7 @@ onUnmounted(() => {
 </script>
 
 <template>
-  <div
-    id="mapview"
-    ref="mapview"
-    v-loading="mapSet.loading"
-    element-loading-text="地图加载中"
-    element-loading-spinner="el-icon-loading"
-    element-loading-background="rgba(0, 0, 0, 0.8)"
-  ></div>
+  <div id="mapview" ref="mapview" v-loading="mapSet.loading"></div>
 </template>
 
 <style lang="scss" scoped>

+ 15 - 0
src/layout/components/appMain.vue

@@ -17,6 +17,8 @@ const props = defineProps({
 const keepAlive: Boolean = ref(
   getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
 );
+const instance =
+  getCurrentInstance().appContext.app.config.globalProperties.$storage;
 
 const transitions = computed(() => {
   return route => {
@@ -24,6 +26,13 @@ const transitions = computed(() => {
   };
 });
 
+const hideTabs = computed(() => {
+  return instance?.sets.hideTabs;
+});
+const layout = computed(() => {
+  return instance?.layout.layout === "vertical";
+});
+
 const transitionMain = defineComponent({
   render() {
     return h(
@@ -62,6 +71,12 @@ const transitionMain = defineComponent({
 <template>
   <section
     :class="[props.fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
+    :style="[
+      hideTabs && layout ? 'padding-top: 48px;' : '',
+      !hideTabs && layout ? 'padding-top: 85px;' : '',
+      hideTabs && !layout ? 'padding-top: 62px' : '',
+      !hideTabs && !layout ? 'padding-top: 98px;' : ''
+    ]"
   >
     <router-view>
       <template #default="{ Component, route }">

+ 22 - 4
src/layout/components/navbar.vue

@@ -78,6 +78,8 @@ function translationEn() {
                 color: locale === 'zh' ? '#f4f4f5' : '#000'
               }"
               @click="translationCh"
+              ><el-icon class="check-zh" v-show="locale === 'zh'"
+                ><check /></el-icon
               >简体中文</el-dropdown-item
             >
             <el-dropdown-item
@@ -86,6 +88,8 @@ function translationEn() {
                 color: locale === 'en' ? '#f4f4f5' : '#000'
               }"
               @click="translationEn"
+              ><el-icon class="check-en" v-show="locale === 'en'"
+                ><check /></el-icon
               >English</el-dropdown-item
             >
           </el-dropdown-menu>
@@ -107,11 +111,13 @@ function translationEn() {
           </el-dropdown-menu>
         </template>
       </el-dropdown>
-      <i
+      <el-icon
         class="el-icon-setting"
         :title="$t('message.hssystemSet')"
         @click="onPanel"
-      ></i>
+      >
+        <Setting />
+      </el-icon>
     </div>
   </div>
 </template>
@@ -191,8 +197,8 @@ function translationEn() {
 
     .el-icon-setting {
       height: 48px;
-      width: 40px;
-      padding: 11px;
+      width: 38px;
+      padding: 12px;
       display: flex;
       cursor: pointer;
       align-items: center;
@@ -218,6 +224,18 @@ function translationEn() {
     color: #606266;
     background: #f0f0f0;
   }
+
+  .check-zh {
+    position: absolute;
+    left: 20px;
+    top: 13px;
+  }
+
+  .check-en {
+    position: absolute;
+    bottom: 13px;
+    left: 20px;
+  }
 }
 
 .logout {

+ 3 - 1
src/layout/components/panel/index.vue

@@ -22,7 +22,9 @@ emitter.on("openPanel", () => {
       <div class="right-panel-items">
         <div class="project-configuration">
           <h3>项目配置</h3>
-          <i class="el-icon-close" @click="show = !show"></i>
+          <el-icon title="关闭配置" class="el-icon-close" @click="show = !show">
+            <Close />
+          </el-icon>
         </div>
         <div style="border-bottom: 1px solid #dcdfe6"></div>
         <slot />

+ 220 - 202
src/layout/components/setting/index.vue

@@ -1,58 +1,84 @@
 <script setup lang="ts">
-import { split } from "lodash-es";
-import panel from "../panel/index.vue";
-import { useRouter } from "vue-router";
-import { emitter } from "/@/utils/mitt";
-import { templateRef } from "@vueuse/core";
-import { debounce } from "/@/utils/debounce";
-import { useAppStoreHook } from "/@/store/modules/app";
-import { storageLocal, storageSession } from "/@/utils/storage";
 import {
   reactive,
   ref,
   unref,
   watch,
+  computed,
+  nextTick,
   useCssModule,
   getCurrentInstance
 } from "vue";
+import panel from "../panel/index.vue";
+import { useRouter } from "vue-router";
+import { emitter } from "/@/utils/mitt";
+import { templateRef } from "@vueuse/core";
+import { debounce } from "/@/utils/debounce";
+import { themeColorsType } from "../../types";
+import { useAppStoreHook } from "/@/store/modules/app";
+import { storageLocal, storageSession } from "/@/utils/storage";
+import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils";
 
 const router = useRouter();
 const { isSelect } = useCssModule();
-
 const instance =
   getCurrentInstance().appContext.app.config.globalProperties.$storage;
 
+const instanceConfig =
+  getCurrentInstance().appContext.app.config.globalProperties.$config;
+
+let themeColors = ref<Array<themeColorsType>>([
+  // 暗雅(默认)
+  { rgb: "27, 42, 71", themeColor: "default" },
+  // 明亮
+  { rgb: "255, 255, 255", themeColor: "light" },
+  // 薄暮
+  { rgb: "245, 34, 45", themeColor: "dusk" },
+  // 火山
+  { rgb: "250, 84, 28", themeColor: "volcano" },
+  // 黄色
+  { rgb: "250, 219, 20", themeColor: "yellow" },
+  // 明青
+  { rgb: "19, 194, 194", themeColor: "mingQing" },
+  // 极光绿
+  { rgb: "82, 196, 26", themeColor: "auroraGreen" },
+  // 粉红
+  { rgb: "235, 47, 150", themeColor: "pink" },
+  // 酱紫
+  { rgb: "114, 46, 209", themeColor: "saucePurple" }
+]);
+
+const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
+const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
+
+let layoutTheme =
+  ref(storageLocal.getItem("responsive-layout")) ||
+  ref({
+    layout: instanceConfig?.Layout ?? "vertical",
+    theme: instanceConfig?.Theme ?? "default"
+  });
+
+// body添加layout属性,作用于src/style/sidebar.scss
+if (unref(layoutTheme)) {
+  let layout = unref(layoutTheme).layout;
+  let theme = unref(layoutTheme).theme;
+  toggleTheme({
+    scopeName: `layout-theme-${theme}`
+  });
+  setLayoutModel(layout);
+}
+
 // 默认灵动模式
 const markValue = ref(storageLocal.getItem("showModel") || "smart");
 
 const logoVal = ref(storageLocal.getItem("logoVal") || "1");
 
-const localOperate = (key: string, value?: any, model?: string): any => {
-  model && model === "set"
-    ? storageLocal.setItem(key, value)
-    : storageLocal.getItem(key);
-};
-
 const settings = reactive({
-  greyVal: storageLocal.getItem("greyVal"),
-  weekVal: storageLocal.getItem("weekVal"),
-  tagsVal: storageLocal.getItem("tagsVal")
+  greyVal: instance.sets.grey,
+  weakVal: instance.sets.weak,
+  tabsVal: instance.sets.hideTabs
 });
 
-settings.greyVal === null
-  ? localOperate("greyVal", false, "set")
-  : document.querySelector("html")?.setAttribute("class", "html-grey");
-
-settings.weekVal === null
-  ? localOperate("weekVal", false, "set")
-  : document.querySelector("html")?.setAttribute("class", "html-weakness");
-
-if (settings.tagsVal === null) {
-  localOperate("tagsVal", false, "set");
-  settings.tagsVal = false;
-}
-window.document.body.setAttribute("data-show-tag", settings.tagsVal);
-
 function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
   const targetEl = target || document.body;
   let { className } = targetEl;
@@ -61,76 +87,62 @@ function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
 }
 
 // 灰色模式设置
-const greyChange = ({ value }): void => {
+const greyChange = (value): void => {
   toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
-  value
-    ? localOperate("greyVal", true, "set")
-    : localOperate("greyVal", false, "set");
+  instance.sets = {
+    grey: value,
+    weak: instance.sets.weak,
+    hideTabs: instance.sets.hideTabs
+  };
 };
 
 // 色弱模式设置
-const weekChange = ({ value }): void => {
+const weekChange = (value): void => {
   toggleClass(
-    settings.weekVal,
+    settings.weakVal,
     "html-weakness",
     document.querySelector("html")
   );
-  value
-    ? localOperate("weekVal", true, "set")
-    : localOperate("weekVal", false, "set");
+  instance.sets = {
+    grey: instance.sets.grey,
+    weak: value,
+    hideTabs: instance.sets.hideTabs
+  };
 };
 
 const tagsChange = () => {
-  let showVal = settings.tagsVal;
-  showVal
-    ? storageLocal.setItem("tagsVal", true)
-    : storageLocal.setItem("tagsVal", false);
+  let showVal = settings.tabsVal;
+  instance.sets = {
+    grey: instance.sets.grey,
+    weak: instance.sets.weak,
+    hideTabs: showVal
+  };
   emitter.emit("tagViewsChange", showVal);
 };
 
+//初始化项目配置
+nextTick(() => {
+  settings.greyVal &&
+    document.querySelector("html")?.setAttribute("class", "html-grey");
+  settings.weakVal &&
+    document.querySelector("html")?.setAttribute("class", "html-weakness");
+  settings.tabsVal && tagsChange();
+});
+
+// 清空缓存并返回登录页
 function onReset() {
   storageLocal.clear();
   storageSession.clear();
+  toggleClass(false, "html-grey", document.querySelector("html"));
+  toggleClass(false, "html-weakness", document.querySelector("html"));
   router.push("/login");
 }
 
-function onChange({ label }) {
+function onChange(label) {
   storageLocal.setItem("showModel", label);
   emitter.emit("tagViewsShowModel", label);
 }
 
-const verticalDarkDom = templateRef<HTMLElement | null>(
-  "verticalDarkDom",
-  null
-);
-const verticalLightDom = templateRef<HTMLElement | null>(
-  "verticalLightDom",
-  null
-);
-const horizontalDarkDom = templateRef<HTMLElement | null>(
-  "horizontalDarkDom",
-  null
-);
-const horizontalLightDom = templateRef<HTMLElement | null>(
-  "horizontalLightDom",
-  null
-);
-
-let dataTheme =
-  ref(storageLocal.getItem("responsive-layout")) ||
-  ref({
-    layout: "horizontal-dark"
-  });
-
-if (unref(dataTheme)) {
-  // 设置主题
-  let theme = split(unref(dataTheme).layout, "-")[1];
-  window.document.body.setAttribute("data-theme", theme);
-  // 设置导航模式
-  let layout = split(unref(dataTheme).layout, "-")[0];
-  window.document.body.setAttribute("data-layout", layout);
-}
-
 // 侧边栏Logo
 function logoChange() {
   unref(logoVal) === "1"
@@ -147,155 +159,170 @@ function setFalse(Doms): any {
 
 watch(instance, ({ layout }) => {
   switch (layout["layout"]) {
-    case "vertical-dark":
-      toggleClass(true, isSelect, unref(verticalDarkDom));
-      debounce(
-        setFalse([verticalLightDom, horizontalDarkDom, horizontalLightDom]),
-        50
-      );
-      break;
-    case "vertical-light":
-      toggleClass(true, isSelect, unref(verticalLightDom));
-      debounce(
-        setFalse([verticalDarkDom, horizontalDarkDom, horizontalLightDom]),
-        50
-      );
-      break;
-    case "horizontal-dark":
-      toggleClass(true, isSelect, unref(horizontalDarkDom));
-      debounce(
-        setFalse([verticalDarkDom, verticalLightDom, horizontalLightDom]),
-        50
-      );
+    case "vertical":
+      toggleClass(true, isSelect, unref(verticalRef));
+      debounce(setFalse([horizontalRef]), 50);
       break;
-    case "horizontal-light":
-      toggleClass(true, isSelect, unref(horizontalLightDom));
-      debounce(
-        setFalse([verticalDarkDom, verticalLightDom, horizontalDarkDom]),
-        50
-      );
+    case "horizontal":
+      toggleClass(true, isSelect, unref(horizontalRef));
+      debounce(setFalse([verticalRef]), 50);
       break;
   }
 });
 
-function setTheme(layout: string, theme: string) {
-  dataTheme.value.layout = `${layout}-${theme}`;
-  window.document.body.setAttribute("data-layout", layout);
-  window.document.body.setAttribute("data-theme", theme);
-  instance.layout = { layout: `${layout}-${theme}` };
+// 主题色 激活选择项
+const getThemeColor = computed(() => {
+  return current => {
+    if (
+      current === layoutTheme.value.theme &&
+      layoutTheme.value.theme !== "light"
+    ) {
+      return "#fff";
+    } else if (
+      current === layoutTheme.value.theme &&
+      layoutTheme.value.theme === "light"
+    ) {
+      return "#1d2b45";
+    } else {
+      return "transparent";
+    }
+  };
+});
+
+// 设置导航模式
+function setLayoutModel(layout: string) {
+  layoutTheme.value.layout = layout;
+  window.document.body.setAttribute("layout", layout);
+  instance.layout = { layout, theme: layoutTheme.value.theme };
   useAppStoreHook().setLayout(layout);
 }
+
+// 设置导航主题色
+function setLayoutThemeColor(theme: string) {
+  layoutTheme.value.theme = theme;
+  toggleTheme({
+    scopeName: `layout-theme-${theme}`
+  });
+  instance.layout = { layout: useAppStoreHook().layout, theme };
+}
 </script>
 
 <template>
   <panel>
     <el-divider>主题风格</el-divider>
-    <ul class="theme-stley">
-      <el-tooltip class="item" content="左侧菜单暗色模式" placement="bottom">
+    <ul class="pure-theme">
+      <el-tooltip class="item" content="左侧菜单模式" placement="bottom">
         <li
-          :class="dataTheme.layout === 'vertical-dark' ? $style.isSelect : ''"
-          ref="verticalDarkDom"
-          @click="setTheme('vertical', 'dark')"
+          :class="layoutTheme.layout === 'vertical' ? $style.isSelect : ''"
+          ref="verticalRef"
+          @click="setLayoutModel('vertical')"
         >
           <div></div>
           <div></div>
         </li>
       </el-tooltip>
 
-      <el-tooltip class="item" content="左侧菜单亮色模式" placement="bottom">
+      <el-tooltip class="item" content="顶部菜单模式" placement="bottom">
         <li
-          :class="dataTheme.layout === 'vertical-light' ? $style.isSelect : ''"
-          ref="verticalLightDom"
-          @click="setTheme('vertical', 'light')"
-        >
-          <div></div>
-          <div></div>
-        </li>
-      </el-tooltip>
-
-      <el-tooltip class="item" content="顶部菜单暗色模式" placement="bottom">
-        <li
-          :class="dataTheme.layout === 'horizontal-dark' ? $style.isSelect : ''"
-          ref="horizontalDarkDom"
-          @click="setTheme('horizontal', 'dark')"
+          :class="layoutTheme.layout === 'horizontal' ? $style.isSelect : ''"
+          ref="horizontalRef"
+          @click="setLayoutModel('horizontal')"
         >
           <div></div>
           <div></div>
         </li>
       </el-tooltip>
+    </ul>
 
-      <el-tooltip class="item" content="顶部菜单亮色模式" placement="bottom">
-        <li
-          :class="
-            dataTheme.layout === 'horizontal-light' ? $style.isSelect : ''
-          "
-          ref="horizontalLightDom"
-          @click="setTheme('horizontal', 'light')"
+    <el-divider>主题色</el-divider>
+    <ul class="theme-color">
+      <li
+        v-for="(item, index) in themeColors"
+        :key="index"
+        :style="{ background: `rgb(${item.rgb})` }"
+        @click="setLayoutThemeColor(item.themeColor)"
+      >
+        <el-icon
+          style="margin: 0.1em 0.1em 0 0"
+          :size="17"
+          :color="getThemeColor(item.themeColor)"
         >
-          <div></div>
-          <div></div>
-        </li>
-      </el-tooltip>
+          <Check />
+        </el-icon>
+      </li>
     </ul>
 
     <el-divider>界面显示</el-divider>
     <ul class="setting">
       <li>
         <span>灰色模式</span>
-        <vxe-switch
+        <el-switch
           v-model="settings.greyVal"
-          open-label="开"
-          close-label="关"
+          inline-prompt
+          inactive-color="#a6a6a6"
+          active-text="开"
+          inactive-text="关"
           @change="greyChange"
-        ></vxe-switch>
+        >
+        </el-switch>
       </li>
       <li>
         <span>色弱模式</span>
-        <vxe-switch
-          v-model="settings.weekVal"
-          open-label="开"
-          close-label="关"
+        <el-switch
+          v-model="settings.weakVal"
+          inline-prompt
+          inactive-color="#a6a6a6"
+          active-text="开"
+          inactive-text="关"
           @change="weekChange"
-        ></vxe-switch>
+        >
+        </el-switch>
       </li>
       <li>
         <span>隐藏标签页</span>
-        <vxe-switch
-          v-model="settings.tagsVal"
-          open-label="开"
-          close-label="关"
+        <el-switch
+          v-model="settings.tabsVal"
+          inline-prompt
+          inactive-color="#a6a6a6"
+          active-text="开"
+          inactive-text="关"
           @change="tagsChange"
-        ></vxe-switch>
+        >
+        </el-switch>
       </li>
       <li>
         <span>侧边栏Logo</span>
-        <vxe-switch
+        <el-switch
           v-model="logoVal"
-          open-value="1"
-          close-value="-1"
-          open-label="开"
-          close-label="关"
+          inline-prompt
+          active-value="1"
+          inactive-value="-1"
+          inactive-color="#a6a6a6"
+          active-text="开"
+          inactive-text="关"
           @change="logoChange"
-        ></vxe-switch>
+        >
+        </el-switch>
       </li>
 
       <li>
         <span>标签风格</span>
-        <vxe-radio-group v-model="markValue" @change="onChange">
-          <vxe-radio label="card" content="卡片"></vxe-radio>
-          <vxe-radio label="smart" content="灵动"></vxe-radio>
-        </vxe-radio-group>
+        <el-radio-group v-model="markValue" size="small" @change="onChange">
+          <el-radio label="card">卡片</el-radio>
+          <el-radio label="smart">灵动</el-radio>
+        </el-radio-group>
       </li>
     </ul>
 
     <el-divider />
-    <vxe-button
-      status="danger"
+    <el-button
+      type="danger"
       style="width: 90%; margin: 24px 15px"
-      content="清空缓存并返回登录页"
-      icon="fa fa-sign-out"
       @click="onReset"
-    ></vxe-button>
+    >
+      <i class="fa fa-sign-out"></i>
+      清空缓存并返回登录页</el-button
+    >
   </panel>
 </template>
 
@@ -322,10 +349,10 @@ function setTheme(layout: string, theme: string) {
   font-weight: 700;
 }
 
-.theme-stley {
+.pure-theme {
   margin-top: 25px;
   width: 100%;
-  height: 180px;
+  height: 100px;
   display: flex;
   flex-wrap: wrap;
   justify-content: space-around;
@@ -362,28 +389,6 @@ function setTheme(layout: string, theme: string) {
     }
 
     &:nth-child(2) {
-      div {
-        &:nth-child(1) {
-          width: 30%;
-          height: 100%;
-          box-shadow: 0 0 1px #888;
-          background: #fff;
-          border-radius: 4px 0 0 4px;
-        }
-
-        &:nth-child(2) {
-          width: 70%;
-          height: 30%;
-          top: 0;
-          right: 0;
-          background: #fff;
-          box-shadow: 0 0 1px #888;
-          position: absolute;
-        }
-      }
-    }
-
-    &:nth-child(3) {
       div {
         &:nth-child(1) {
           width: 100%;
@@ -393,16 +398,29 @@ function setTheme(layout: string, theme: string) {
         }
       }
     }
+  }
+}
 
-    &:nth-child(4) {
-      div {
-        &:nth-child(1) {
-          width: 100%;
-          height: 30%;
-          background: #fff;
-          box-shadow: 0 0 1px #888;
-        }
-      }
+.theme-color {
+  width: 100%;
+  height: 40px;
+  margin-top: 20px;
+  display: flex;
+  justify-content: center;
+
+  li {
+    float: left;
+    width: 20px;
+    height: 20px;
+    margin-top: 8px;
+    margin-right: 8px;
+    font-weight: 700;
+    text-align: center;
+    border-radius: 2px;
+    cursor: pointer;
+
+    &:nth-child(2) {
+      border: 1px solid #ddd;
     }
   }
 }

+ 20 - 2
src/layout/components/sidebar/horizontal.vue

@@ -151,6 +151,8 @@ onMounted(() => {
                 color: locale === 'zh' ? '#f4f4f5' : '#000'
               }"
               @click="translationCh"
+              ><el-icon class="check-zh" v-show="locale === 'zh'"
+                ><check /></el-icon
               >简体中文</el-dropdown-item
             >
             <el-dropdown-item
@@ -159,6 +161,8 @@ onMounted(() => {
                 color: locale === 'en' ? '#f4f4f5' : '#000'
               }"
               @click="translationEn"
+              ><el-icon class="check-en" v-show="locale === 'en'"
+                ><check /></el-icon
               >English</el-dropdown-item
             >
           </el-dropdown-menu>
@@ -180,11 +184,13 @@ onMounted(() => {
           </el-dropdown-menu>
         </template>
       </el-dropdown>
-      <i
+      <el-icon
         class="el-icon-setting"
         :title="$t('message.hssystemSet')"
         @click="onPanel"
-      ></i>
+      >
+        <Setting />
+      </el-icon>
     </div>
   </div>
 </template>
@@ -200,6 +206,18 @@ onMounted(() => {
     color: #606266;
     background: #f0f0f0;
   }
+
+  .check-zh {
+    position: absolute;
+    left: 20px;
+    top: 13px;
+  }
+
+  .check-en {
+    position: absolute;
+    bottom: 13px;
+    left: 20px;
+  }
 }
 
 .logout {

+ 21 - 21
src/layout/components/sidebar/sidebarItem.vue

@@ -1,14 +1,12 @@
 <script setup lang="ts">
 import path from "path";
-import { storageLocal } from "/@/utils/storage";
-import { PropType, ref, nextTick } from "vue";
+import { PropType, ref, nextTick, getCurrentInstance } from "vue";
 import { childrenType } from "../../types";
 import { useAppStoreHook } from "/@/store/modules/app";
 import Icon from "/@/components/ReIcon/src/Icon.vue";
-const layout = ref(
-  storageLocal.getItem("responsive-layout") || "vertical-dark"
-);
-const menuMode = layout.value.layout.split("-")[0] === "vertical";
+
+const instance = getCurrentInstance().appContext.app.config.globalProperties;
+const menuMode = instance.$storage.layout?.layout === "vertical";
 const pureApp = useAppStoreHook();
 
 const props = defineProps({
@@ -86,21 +84,22 @@ function resolvePath(routePath) {
       :class="{ 'submenu-title-noDropdown': !isNest }"
       style="display: flex; align-items: center"
     >
-      <i
-        v-show="props.item.meta.icon"
-        :class="
-          onlyOneChild.meta.icon || (props.item.meta && props.item.meta.icon)
-        "
-      />
+      <el-icon v-show="props.item.meta.icon">
+        <component
+          :is="
+            onlyOneChild.meta.icon || (props.item.meta && props.item.meta.icon)
+          "
+        ></component>
+      </el-icon>
       <template #title>
         <div
-          style="
-            width: 100%;
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-            overflow: hidden;
-          "
+          :style="{
+            width: pureApp.sidebar.opened ? '' : '100%',
+            display: 'flex',
+            alignItems: 'center',
+            justifyContent: 'space-between',
+            overflow: 'hidden'
+          }"
         >
           <span v-if="!menuMode">{{ $t(onlyOneChild.meta.title) }}</span>
           <el-tooltip
@@ -139,9 +138,10 @@ function resolvePath(routePath) {
     popper-append-to-body
   >
     <template #title>
-      <i v-show="props.item.meta.icon" :class="props.item.meta.icon"></i>
+      <el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon">
+        <component :is="props.item.meta && props.item.meta.icon"></component>
+      </el-icon>
       <span v-if="!menuMode">{{ $t(props.item.meta.title) }}</span>
-
       <el-tooltip
         v-else
         placement="top"

+ 12 - 6
src/layout/components/tag/index.vue

@@ -447,7 +447,6 @@ onBeforeMount(() => {
   emitter.on("tagViewsChange", key => {
     if (unref(showTags) === key) return;
     showTags.value = key;
-    window.document.body.setAttribute("data-show-tag", key);
   });
 
   // 改变标签风格
@@ -484,14 +483,16 @@ onBeforeMount(() => {
         <router-link :to="item.path" @click="tagOnClick(item)">{{
           $t(item.meta.title)
         }}</router-link>
-        <span
+        <el-icon
           v-if="
             ($route.path === item.path && index !== 0) ||
             (index === activeIndex && index !== 0)
           "
           class="el-icon-close"
           @click="deleteMenu(item)"
-        ></span>
+        >
+          <CloseBold />
+        </el-icon>
         <div
           :ref="'schedule' + index"
           v-if="showModel !== 'card'"
@@ -522,15 +523,19 @@ onBeforeMount(() => {
     <!-- 右侧功能按钮 -->
     <ul class="right-button">
       <li>
-        <i
+        <el-icon
           :title="$t('message.hsrefreshRoute')"
           class="el-icon-refresh-right rotate"
           @click="onFresh"
-        ></i>
+        >
+          <RefreshRight />
+        </el-icon>
       </li>
       <li>
         <el-dropdown trigger="click" placement="bottom-end">
-          <i class="el-icon-arrow-down"></i>
+          <el-icon>
+            <ArrowDown />
+          </el-icon>
           <template #dropdown>
             <el-dropdown-menu>
               <el-dropdown-item
@@ -630,6 +635,7 @@ onBeforeMount(() => {
       font-size: 10px;
       color: #1890ff;
       cursor: pointer;
+      transform: fontsize3s;
 
       &:hover {
         border-radius: 50%;

+ 46 - 22
src/layout/index.vue

@@ -16,7 +16,6 @@ import { useI18n } from "vue-i18n";
 import { routerArrays } from "./types";
 import { emitter } from "/@/utils/mitt";
 import { useEventListener } from "@vueuse/core";
-import { storageLocal } from "/@/utils/storage";
 import backTop from "/@/assets/svg/back_top.svg";
 import { useAppStoreHook } from "/@/store/modules/app";
 import fullScreen from "/@/assets/svg/full_screen.svg";
@@ -30,30 +29,44 @@ import setting from "./components/setting/index.vue";
 import Vertical from "./components/sidebar/vertical.vue";
 import Horizontal from "./components/sidebar/horizontal.vue";
 
+const instance = getCurrentInstance().appContext.app.config.globalProperties;
+const hiddenSideBar = ref(instance.$config?.HiddenSideBar);
 const pureSetting = useSettingStoreHook();
 
-const instance =
-  getCurrentInstance().appContext.app.config.globalProperties.$storage;
-
-const hiddenSideBar = ref(
-  getCurrentInstance().appContext.config.globalProperties.$config?.HiddenSideBar
-);
-
+// 清空缓存后从serverConfig.json读取默认配置并赋值到storage中
 const layout = computed(() => {
-  if (!instance.layout) {
+  // 路由
+  if (
+    !instance.$storage.routesInStorage ||
+    instance.$storage.routesInStorage.length === 0
+  ) {
     // eslint-disable-next-line vue/no-side-effects-in-computed-properties
-    instance.layout = { layout: "vertical-dark" };
+    instance.$storage.routesInStorage = routerArrays;
   }
-  if (!instance.routesInStorage || instance.routesInStorage.length === 0) {
+  // 国际化
+  if (!instance.$storage.locale) {
+    // eslint-disable-next-line
+    instance.$storage.locale = { locale: instance.$config?.Locale ?? "zh" };
+    useI18n().locale.value = instance.$config?.Locale ?? "zh";
+  }
+  // 导航
+  if (!instance.$storage.layout) {
     // eslint-disable-next-line vue/no-side-effects-in-computed-properties
-    instance.routesInStorage = routerArrays;
+    instance.$storage.layout = {
+      layout: instance.$config?.Layout ?? "vertical",
+      theme: instance.$config?.Theme ?? "default"
+    };
   }
-  if (!instance.locale) {
+  // 灰色模式、色弱模式、隐藏标签页
+  if (!instance.$storage.sets) {
     // eslint-disable-next-line
-    instance.locale = { locale: "zh" };
-    useI18n().locale.value = "zh";
+    instance.$storage.sets = {
+      grey: instance.$config?.Grey ?? false,
+      weak: instance.$config?.Weak ?? false,
+      hideTabs: instance.$config?.HideTabs ?? false
+    };
   }
-  return instance?.layout.layout;
+  return instance.$storage?.layout.layout;
 });
 
 const set: setType = reactive({
@@ -76,6 +89,10 @@ const set: setType = reactive({
       withoutAnimation: set.sidebar.withoutAnimation,
       mobile: set.device === "mobile"
     };
+  }),
+
+  hideTabs: computed(() => {
+    return instance.$storage?.sets.hideTabs;
   })
 });
 
@@ -84,11 +101,11 @@ const handleClickOutside = (params: boolean) => {
 };
 
 function setTheme(layoutModel: string) {
-  let { layout } = storageLocal.getItem("responsive-layout");
-  let theme = layout.match(/-(.*)/)[1];
-  window.document.body.setAttribute("data-layout", layoutModel);
-  window.document.body.setAttribute("data-theme", theme);
-  instance.layout = { layout: `${layoutModel}-${theme}` };
+  window.document.body.setAttribute("layout", layoutModel);
+  instance.$storage.layout = {
+    layout: `${layoutModel}`,
+    theme: instance.$storage.layout?.theme
+  };
 }
 
 // 监听容器
@@ -140,7 +157,14 @@ const layoutHeader = defineComponent({
   render() {
     return h(
       "div",
-      { class: { "fixed-header": set.fixedHeader } },
+      {
+        class: { "fixed-header": set.fixedHeader },
+        style: [
+          set.hideTabs && layout.value.includes("horizontal")
+            ? "box-shadow: 0 1px 4px rgb(0 21 41 / 8%);"
+            : ""
+        ]
+      },
       {
         default: () => [
           !hiddenSideBar.value && layout.value.includes("vertical")

+ 12 - 0
src/layout/theme/auroraGreen-vars.scss

@@ -0,0 +1,12 @@
+// 极光绿
+
+$subMenuActiveText: #fff;
+$menuBg: #0b1e15;
+$menuHover: #60ac80;
+$subMenuBg: #000;
+$subMenuActiveBg: #60ac80;
+$navTextColor: #7a80b4;
+$menuText: #7a80b4;
+$sidebarLogo: #112f21;
+$menuTitleHover: #fff;
+$menuActiveBefore: #60ac80;

+ 24 - 0
src/layout/theme/default-vars.scss

@@ -0,0 +1,24 @@
+/**
+*此scss变量文件作为multipleScopeVars去编译时,会自动移除!default以达到变量提升
+*同时此scss变量文件作为默认主题变量文件,被其他.scss通过 @import 时,必需 !default
+*/
+
+// 暗雅(默认)
+
+// 菜单选中后字体样式
+$subMenuActiveText: #fff !default;
+//菜单背景
+$menuBg: #001529 !default;
+// 鼠标覆盖到菜单时的背景
+$menuHover: #4091f7 !default;
+// 子菜单背景
+$subMenuBg: #0f0303 !default;
+// 有无子集的激活菜单背景
+$subMenuActiveBg: #4091f7 !default;
+$navTextColor: #fff !default;
+$menuText: rgba(254, 254, 254, 0.65) !default;
+// logo背景颜色
+$sidebarLogo: #002140 !default;
+// 鼠标覆盖到菜单时的字体颜色
+$menuTitleHover: #fff !default;
+$menuActiveBefore: #4091f7 !default;

+ 12 - 0
src/layout/theme/dusk-vars.scss

@@ -0,0 +1,12 @@
+// 薄暮
+
+$subMenuActiveText: #fff;
+$menuBg: #2a0608;
+$menuHover: #e13c39;
+$subMenuBg: #000;
+$subMenuActiveBg: #e13c39;
+$navTextColor: red;
+$menuText: rgba(254, 254, 254, 0.651);
+$sidebarLogo: #42090c;
+$menuTitleHover: #fff;
+$menuActiveBefore: #e13c39;

+ 11 - 0
src/layout/theme/light-vars.scss

@@ -0,0 +1,11 @@
+// 明亮
+$subMenuActiveText: #409eff;
+$menuBg: #fff;
+$menuHover: #e0ebf6;
+$subMenuBg: #fff;
+$subMenuActiveBg: #e0ebf6;
+$navTextColor: #7a80b4;
+$menuText: #7a80b4;
+$sidebarLogo: #fff;
+$menuTitleHover: #000;
+$menuActiveBefore: #4091f7;

+ 12 - 0
src/layout/theme/mingQing-vars.scss

@@ -0,0 +1,12 @@
+// 明青
+
+$subMenuActiveText: #fff;
+$menuBg: #032121;
+$menuHover: #59bfc1;
+$subMenuBg: #000;
+$subMenuActiveBg: #59bfc1;
+$navTextColor: #7a80b4;
+$menuText: #7a80b4;
+$sidebarLogo: #053434;
+$menuTitleHover: #fff;
+$menuActiveBefore: #59bfc1;

+ 12 - 0
src/layout/theme/pink-vars.scss

@@ -0,0 +1,12 @@
+// 粉红
+
+$subMenuActiveText: #fff;
+$menuBg: #28081a;
+$menuHover: #d84493;
+$subMenuBg: #000;
+$subMenuActiveBg: #d84493;
+$navTextColor: #7a80b4;
+$menuText: #7a80b4;
+$sidebarLogo: #3f0d29;
+$menuTitleHover: #fff;
+$menuActiveBefore: #d84493;

+ 12 - 0
src/layout/theme/saucePurple-vars.scss

@@ -0,0 +1,12 @@
+// 酱紫
+
+$subMenuActiveText: #fff;
+$menuBg: #130824;
+$menuHover: #693ac9;
+$subMenuBg: #000;
+$subMenuActiveBg: #693ac9;
+$navTextColor: #7a80b4;
+$menuText: #7a80b4;
+$sidebarLogo: #1f0c38;
+$menuTitleHover: #fff;
+$menuActiveBefore: #693ac9;

+ 12 - 0
src/layout/theme/volcano-vars.scss

@@ -0,0 +1,12 @@
+// 火山
+
+$subMenuActiveText: #fff;
+$menuBg: #2b0e05;
+$menuHover: #e85f33;
+$subMenuBg: #0f0603;
+$subMenuActiveBg: #e85f33;
+$navTextColor: #fff;
+$menuText: rgba(254, 254, 254, 0.65);
+$sidebarLogo: #441708;
+$menuTitleHover: #fff;
+$menuActiveBefore: #e85f33;

+ 12 - 0
src/layout/theme/yellow-vars.scss

@@ -0,0 +1,12 @@
+// 黄色
+
+$subMenuActiveText: #d25f00;
+$menuBg: #2b2503;
+$menuHover: #f6da4d;
+$subMenuBg: #0f0603;
+$subMenuActiveBg: #f6da4d;
+$navTextColor: #fff;
+$menuText: rgba(254, 254, 254, 0.65);
+$sidebarLogo: #443b05;
+$menuTitleHover: #fff;
+$menuActiveBefore: #f6da4d;

+ 6 - 0
src/layout/types.ts

@@ -47,6 +47,7 @@ export interface setType {
     withoutAnimation: boolean;
     mobile: boolean;
   };
+  hideTabs: boolean;
 }
 
 export type childrenType = {
@@ -64,3 +65,8 @@ export type childrenType = {
   };
   showTooltip?: boolean;
 };
+
+export type themeColorsType = {
+  rgb: string;
+  themeColor: string;
+};

+ 40 - 2
src/plugins/element-plus/index.ts

@@ -30,13 +30,33 @@ import {
   ElDrawer,
   ElPagination,
   ElAlert,
+  ElRadio,
   ElRadioButton,
   ElRadioGroup,
   ElDescriptions,
   ElDescriptionsItem,
-  ElBacktop
+  ElBacktop,
+  ElSwitch
 } from "element-plus";
 
+// https://element-plus.org/zh-CN/component/icon.html
+import {
+  Check,
+  Menu,
+  HomeFilled,
+  SetUp,
+  Edit,
+  Setting,
+  Lollipop,
+  Link,
+  Position,
+  Histogram,
+  RefreshRight,
+  ArrowDown,
+  Close,
+  CloseBold
+} from "@element-plus/icons";
+
 const components = [
   ElTag,
   ElAffix,
@@ -67,11 +87,29 @@ const components = [
   ElDrawer,
   ElPagination,
   ElAlert,
+  ElRadio,
   ElRadioButton,
   ElRadioGroup,
   ElDescriptions,
   ElDescriptionsItem,
-  ElBacktop
+  ElBacktop,
+  ElSwitch,
+
+  // icon
+  Check,
+  Menu,
+  HomeFilled,
+  SetUp,
+  Edit,
+  Setting,
+  Lollipop,
+  Link,
+  Position,
+  Histogram,
+  RefreshRight,
+  ArrowDown,
+  Close,
+  CloseBold
 ];
 
 const plugins = [ElLoading];

+ 2 - 2
src/plugins/i18n/config.ts

@@ -98,7 +98,7 @@ export const buttonConfig = {
       hssearch: "搜索",
       hsexpendAll: "全部展开",
       hscollapseAll: "全部折叠",
-      hssystemSet: "系统设置",
+      hssystemSet: "打开项目配置",
       hsdelete: "删除",
       hsreload: "重新加载",
       hscloseCurrentTab: "关闭当前标签页",
@@ -121,7 +121,7 @@ export const buttonConfig = {
       hssearch: "Search",
       hsexpendAll: "Expand All",
       hscollapseAll: "Collapse All",
-      hssystemSet: "System Set",
+      hssystemSet: "Open ProjectConfig",
       hsdelete: "Delete",
       hsreload: "Reload",
       hscloseCurrentTab: "Close CurrentTab",

+ 1 - 1
src/router/modules/components.ts

@@ -6,7 +6,7 @@ const componentsRouter = {
   component: Layout,
   redirect: "/components/video",
   meta: {
-    icon: "el-icon-menu",
+    icon: "Menu",
     title: "message.hscomponents",
     showLink: true,
     rank: 4

+ 1 - 1
src/router/modules/editor.ts

@@ -6,7 +6,7 @@ const editorRouter = {
   component: Layout,
   redirect: "/editor/index",
   meta: {
-    icon: "el-icon-edit-outline",
+    icon: "Edit",
     title: "message.hseditor",
     showLink: true,
     rank: 2

+ 1 - 1
src/router/modules/error.ts

@@ -6,7 +6,7 @@ const errorRouter = {
   component: Layout,
   redirect: "/error/401",
   meta: {
-    icon: "el-icon-position",
+    icon: "Position",
     title: "message.hserror",
     showLink: true,
     rank: 7

+ 1 - 2
src/router/modules/externalLink.ts

@@ -5,7 +5,7 @@ const externalLink = {
   name: "external",
   component: Layout,
   meta: {
-    icon: "el-icon-link",
+    icon: "Link",
     title: "message.externalLink",
     showLink: true,
     rank: 190
@@ -14,7 +14,6 @@ const externalLink = {
     {
       path: "https://github.com/xiaoxian521/vue-pure-admin",
       meta: {
-        icon: "el-icon-link",
         title: "message.externalLink",
         showLink: true,
         rank: 191

+ 1 - 1
src/router/modules/flowchart.ts

@@ -6,7 +6,7 @@ const flowChartRouter = {
   component: Layout,
   redirect: "/flowChart/index",
   meta: {
-    icon: "el-icon-set-up",
+    icon: "SetUp",
     title: "message.hsflowChart",
     showLink: true,
     rank: 1

+ 1 - 1
src/router/modules/home.ts

@@ -6,7 +6,7 @@ const homeRouter = {
   component: Layout,
   redirect: "/welcome",
   meta: {
-    icon: "el-icon-s-home",
+    icon: "HomeFilled",
     showLink: true,
     rank: 0
   },

+ 1 - 1
src/router/modules/nested.ts

@@ -7,7 +7,7 @@ const nestedRouter = {
   name: "Nested",
   meta: {
     title: "message.hsmenus",
-    icon: "el-icon-s-data",
+    icon: "Histogram",
     showLink: true,
     rank: 5
   },

+ 1 - 1
src/router/modules/remaining.ts

@@ -16,7 +16,7 @@ const remainingRouter = [
     name: "redirect",
     component: Layout,
     meta: {
-      icon: "el-icon-s-home",
+      icon: "HomeFilled",
       title: "message.hshome",
       showLink: false,
       rank: 104

+ 3 - 2
src/store/modules/app.ts

@@ -2,6 +2,7 @@ import { storageLocal } from "/@/utils/storage";
 import { deviceDetection } from "/@/utils/deviceDetection";
 import { defineStore } from "pinia";
 import { store } from "/@/store";
+import { getConfig } from "/@/config";
 
 interface AppState {
   sidebar: {
@@ -21,9 +22,9 @@ export const useAppStore = defineStore({
         : true,
       withoutAnimation: false
     },
+    // 这里的layout用于监听容器拖拉后恢复对应的导航模式
     layout:
-      storageLocal.getItem("responsive-layout")?.layout.match(/(.*)-/)[1] ??
-      "vertical",
+      storageLocal.getItem("responsive-layout")?.layout ?? getConfig().Layout,
     device: deviceDetection() ? "mobile" : "desktop"
   }),
   getters: {

+ 0 - 4
src/style/element-plus.scss

@@ -37,10 +37,6 @@
   box-sizing: content-box;
 }
 
-.el-loading-mask {
-  z-index: -1;
-}
-
 // el-tooltip的权重
 .is-dark {
   z-index: 99999 !important;

+ 84 - 186
src/style/sidebar.scss

@@ -1,19 +1,9 @@
+@import "../layout/theme/default-vars.scss";
+
 @mixin merge-style(
-  // 菜单选中后字体样式
-  $subMenuActiveText,
-  //菜单背景
-  $menuBg,
-  // 鼠标覆盖菜单时的背景
-  $menuHover,
-  // 子菜单背景
-  $subMenuBg,
-  // 鼠标覆盖子菜单时的背景
-  $subMenuHover,
   // vertical模式下主体内容距离网页文档左侧的距离
-  $sideBarWidth,
-  $navTextColor
+  $sideBarWidth
 ) {
-  $menuText: #7a80b4;
   $menuActiveText: #7a80b4;
 
   @media screen and (min-width: 150px) and (max-width: 420px) {
@@ -62,7 +52,7 @@
       width: 100% !important;
 
       + .app-main {
-        padding-top: 37px;
+        padding-top: 37px !important;
       }
     }
   }
@@ -73,8 +63,8 @@
 
   .sidebar-container {
     transition: width 0.28s;
-    width: $sideBarWidth;
-    background-color: $menuBg;
+    width: $sideBarWidth !important;
+    background: $menuBg;
     height: 100%;
     position: fixed;
     font-size: 0;
@@ -129,14 +119,18 @@
     .el-menu-item,
     .el-sub-menu__title {
       color: $menuText;
-      padding: 0 16px 0 40px;
+      padding: 0 20px 0 40px;
+
+      &:hover {
+        color: $menuTitleHover !important;
+      }
     }
 
     // menu hover
     .submenu-title-noDropdown,
     .el-sub-menu__title {
       &:hover {
-        background-color: $menuHover !important;
+        background-color: transparent;
       }
     }
 
@@ -159,17 +153,23 @@
       font-size: 12px;
       min-width: $sideBarWidth !important;
       background-color: $subMenuBg !important;
+    }
 
-      &:hover {
-        background-color: $subMenuHover !important;
-      }
+    // 无子集的激活菜单背景
+    .is-active.submenu-title-noDropdown.outer-most {
+      background: $subMenuActiveBg;
+    }
+
+    // 有子集的激活菜单背景
+    .is-active.nest-menu {
+      background: $subMenuActiveBg !important;
     }
   }
 
   .horizontal-header {
     display: flex;
     justify-content: space-around;
-    background-color: $menuBg;
+    background: $menuBg;
     width: 100%;
     height: 62px;
     align-items: center;
@@ -184,10 +184,6 @@
       cursor: pointer;
       transition: all 0.2s ease;
 
-      &:hover {
-        background: $menuHover;
-      }
-
       i {
         font-size: 30px;
         color: #1890ff;
@@ -197,7 +193,7 @@
       h4 {
         font-size: 16px;
         font-weight: 700;
-        color: $navTextColor;
+        color: $subMenuActiveText;
         transition: all 0.5s;
       }
     }
@@ -213,7 +209,7 @@
       display: flex;
       min-width: 280px;
       align-items: center;
-      color: $navTextColor;
+      color: $subMenuActiveText;
       justify-content: flex-end;
 
       .screen-full {
@@ -229,7 +225,7 @@
         width: 40px;
         padding: 11px;
         cursor: pointer;
-        color: $navTextColor;
+        color: $subMenuActiveText;
 
         &:hover {
           background: $menuHover;
@@ -244,7 +240,7 @@
         align-items: center;
         justify-content: space-around;
         cursor: pointer;
-        color: $navTextColor;
+        color: $subMenuActiveText;
 
         &:hover {
           background: $menuHover;
@@ -264,7 +260,7 @@
       .el-icon-setting {
         height: 62px;
         width: 40px;
-        padding: 11px;
+        padding: 12px;
         display: flex;
         cursor: pointer;
         align-items: center;
@@ -285,16 +281,16 @@
     .el-menu-item,
     .el-sub-menu__title {
       color: $menuText;
+
+      &:hover {
+        color: $menuTitleHover !important;
+      }
     }
 
     .submenu-title-noDropdown,
     .el-sub-menu__title {
       height: 60px;
       background: $menuBg;
-
-      &:hover {
-        background-color: $menuHover !important;
-      }
     }
 
     .is-active > .el-sub-menu__title,
@@ -320,17 +316,10 @@
       background-color: $subMenuBg !important;
 
       .el-menu-item {
-        color: $menuText;
-        background-color: $subMenuBg;
-
         span {
           font-size: 12px;
           margin-left: 10px;
         }
-
-        &:hover {
-          background-color: $subMenuHover;
-        }
       }
 
       .el-sub-menu__title {
@@ -344,7 +333,7 @@
 
     & > .el-menu {
       i {
-        margin-right: 16px;
+        margin-right: 20px;
       }
     }
 
@@ -362,9 +351,15 @@
       font-size: 12px;
       min-width: $sideBarWidth !important;
       background-color: $subMenuBg !important;
+    }
+
+    .el-menu-item,
+    .el-sub-menu__title {
+      color: $menuText;
+      background-color: $subMenuBg;
 
       &:hover {
-        background-color: $menuHover !important;
+        color: $menuTitleHover !important;
       }
     }
 
@@ -373,11 +368,8 @@
       color: $subMenuActiveText !important;
     }
 
-    .nest-menu .el-sub-menu > .el-sub-menu__title,
-    .el-menu-item {
-      &:hover {
-        background-color: $menuHover !important;
-      }
+    .el-menu-item.is-active.nest-menu {
+      background: $subMenuActiveBg !important;
     }
 
     .el-menu-item,
@@ -395,8 +387,13 @@
     }
   }
 
-  // horizontal菜单折叠
+  // horizontal菜单
   .el-menu--horizontal {
+    & > .el-sub-menu .el-sub-menu__icon-arrow {
+      position: static !important;
+      margin-top: 0;
+    }
+
     .el-menu--popup {
       background-color: $subMenuBg !important;
 
@@ -408,10 +405,6 @@
           font-size: 12px;
           margin-left: 10px;
         }
-
-        &:hover {
-          background-color: $subMenuHover;
-        }
       }
 
       .el-sub-menu__title {
@@ -436,7 +429,7 @@
       background-color: $subMenuBg !important;
 
       &:hover {
-        background-color: $menuHover !important;
+        color: $menuTitleHover !important;
       }
     }
 
@@ -455,17 +448,22 @@
       }
     }
 
-    .is-active {
-      transition: color 0.3s;
-      color: $subMenuActiveText !important;
-    }
-
     .nest-menu .el-sub-menu > .el-sub-menu__title,
     .el-menu-item {
       &:hover {
-        background-color: $menuHover !important;
+        color: $menuTitleHover !important;
       }
     }
+
+    // 有子集的激活菜单背景
+    .is-active.nest-menu {
+      background: $subMenuActiveBg !important;
+    }
+
+    .el-menu-item.is-active {
+      transition: color 0.3s;
+      color: $subMenuActiveText !important;
+    }
   }
 
   .el-scrollbar__wrap {
@@ -486,7 +484,7 @@
     left: 5px;
     width: 3px;
     height: 100%;
-    background-color: #1890ff !important;
+    background-color: $menuActiveBefore;
     content: "";
     clear: both;
     -webkit-transition: all 0.2s ease-in-out;
@@ -502,7 +500,7 @@
     left: 5px;
     width: 3px;
     height: 100%;
-    background-color: #1890ff !important;
+    background-color: $menuActiveBefore;
     content: "";
     clear: both;
     -webkit-transition: all 0.2s ease-in-out;
@@ -536,7 +534,7 @@
 
     .sidebar-container {
       transition: transform 0.28s;
-      width: $sideBarWidth !important;
+      width: $sideBarWidth;
     }
 
     &.hideSidebar {
@@ -556,10 +554,17 @@
   }
 }
 
-body[data-layout="vertical"] {
+body[layout="vertical"] {
+  $sideBarWidth: 210px;
+  @include merge-style($sideBarWidth);
+
+  .sidebar-logo-container {
+    background: $sidebarLogo;
+  }
+
   .hideSidebar {
     .fixed-header {
-      width: calc(100% - 54px) !important;
+      width: calc(100% - 54px);
       transition: width 0.28s;
     }
 
@@ -568,7 +573,7 @@ body[data-layout="vertical"] {
     }
 
     .main-container {
-      margin-left: 54px !important;
+      margin-left: 54px;
     }
 
     .submenu-title-noDropdown {
@@ -590,8 +595,10 @@ body[data-layout="vertical"] {
       }
     }
 
+    // 菜单折叠
     .el-menu--collapse {
-      margin-left: -5px; //需优化的地方
+      margin-left: -5px;
+
       .el-sub-menu {
         & > .el-sub-menu__title {
           & > span {
@@ -603,129 +610,20 @@ body[data-layout="vertical"] {
           }
         }
       }
-    }
-  }
-}
-
-body[data-layout="horizontal"] {
-  .fixed-header {
-    width: 100% !important;
-    transition: none !important;
-  }
-}
-
-// vertical模式下不隐藏标签页
-body[data-layout="vertical"][data-show-tag="false"] {
-  .fixed-header + .app-main {
-    padding-top: 85px;
-  }
-}
 
-// vertical模式下隐藏标签页
-body[data-layout="vertical"][data-show-tag="true"] {
-  .fixed-header + .app-main {
-    padding-top: 48px;
+      .submenu-title-noDropdown {
+        background: transparent !important;
+      }
+    }
   }
 }
 
-// horizontal模式下不隐藏标签页
-body[data-layout="horizontal"][data-show-tag="false"] {
-  .fixed-header + .app-main {
-    padding-top: 98px;
-  }
-}
+body[layout="horizontal"] {
+  $sideBarWidth: 0;
+  @include merge-style($sideBarWidth);
 
-// horizontal模式下隐藏标签页
-body[data-layout="horizontal"][data-show-tag="true"] {
   .fixed-header {
-    box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
-  }
-
-  .fixed-header + .app-main {
-    padding-top: 62px;
+    width: 100%;
+    transition: none !important;
   }
 }
-
-// vertical模式下暗色主题
-body[data-layout="vertical"][data-theme="dark"] {
-  $subMenuActiveText: #f4f4f5;
-  $menuBg: #1b2a47;
-  $menuHover: #2a395b;
-  $subMenuBg: #1f2d3d;
-  $subMenuHover: #001528;
-  $sideBarWidth: 210px;
-  $navTextColor: #fff;
-
-  @include merge-style(
-    $subMenuActiveText,
-    $menuBg,
-    $menuHover,
-    $subMenuBg,
-    $subMenuHover,
-    $sideBarWidth,
-    $navTextColor
-  );
-}
-
-// vertical模式下亮色主题
-body[data-layout="vertical"][data-theme="light"] {
-  $subMenuActiveText: #409eff;
-  $menuBg: #fff;
-  $menuHover: #e0ebf6;
-  $subMenuBg: #fff;
-  $subMenuHover: #e0ebf6;
-  $sideBarWidth: 210px;
-  $navTextColor: #7a80b4;
-
-  @include merge-style(
-    $subMenuActiveText,
-    $menuBg,
-    $menuHover,
-    $subMenuBg,
-    $subMenuHover,
-    $sideBarWidth,
-    $navTextColor
-  );
-}
-
-// horizontal模式下暗色主题
-body[data-layout="horizontal"][data-theme="dark"] {
-  $subMenuActiveText: #f4f4f5;
-  $menuBg: #1b2a47;
-  $menuHover: #2a395b;
-  $subMenuBg: #1f2d3d;
-  $subMenuHover: #001528;
-  $sideBarWidth: 0;
-  $navTextColor: #fff;
-
-  @include merge-style(
-    $subMenuActiveText,
-    $menuBg,
-    $menuHover,
-    $subMenuBg,
-    $subMenuHover,
-    $sideBarWidth,
-    $navTextColor
-  );
-}
-
-// horizontal模式下亮色主题
-body[data-layout="horizontal"][data-theme="light"] {
-  $subMenuActiveText: #409eff;
-  $menuBg: #fff;
-  $menuHover: #e0ebf6;
-  $subMenuBg: #fff;
-  $subMenuHover: #e0ebf6;
-  $sideBarWidth: 0;
-  $navTextColor: #7a80b4;
-
-  @include merge-style(
-    $subMenuActiveText,
-    $menuBg,
-    $menuHover,
-    $subMenuBg,
-    $subMenuHover,
-    $sideBarWidth,
-    $navTextColor
-  );
-}

+ 11 - 2
src/utils/storage/responsive.ts

@@ -23,14 +23,23 @@ export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
     locale: {
       type: Object,
       default: Storage.getData(undefined, "locale") ?? {
-        locale: config.Locale
+        locale: config.Locale ?? "zh"
       }
     },
     // layout模式以及主题
     layout: {
       type: Object,
       default: Storage.getData(undefined, "layout") ?? {
-        layout: config.Layout
+        layout: config.Layout ?? "vertical",
+        theme: config.Theme ?? "default"
+      }
+    },
+    sets: {
+      type: Object,
+      default: Storage.getData(undefined, "sets") ?? {
+        grey: config.Grey ?? false,
+        weak: config.Weak ?? false,
+        hideTabs: config.HideTabs ?? false
       }
     }
   });

+ 3 - 2
src/views/login.vue

@@ -2,9 +2,10 @@
 import { ref, computed } from "vue";
 import { useRouter } from "vue-router";
 import { initRouter } from "/@/router";
-import avatar from "/@/assets/login/avatar.svg";
 import { storageSession } from "/@/utils/storage";
 import { addClass, removeClass } from "/@/utils/operate";
+import bg from "/@/assets/login/bg.png";
+import avatar from "/@/assets/login/avatar.svg";
 import illustration0 from "/@/assets/login/illustration0.svg";
 import illustration1 from "/@/assets/login/illustration1.svg";
 import illustration2 from "/@/assets/login/illustration2.svg";
@@ -69,7 +70,7 @@ function onPwdBlur() {
 </script>
 
 <template>
-  <img src="/@/assets/login/bg.png" class="wave" />
+  <img :src="bg" class="wave" />
   <div class="container">
     <div class="img">
       <component :is="currentWeek"></component>

+ 4 - 0
types/global.d.ts

@@ -90,6 +90,10 @@ declare global {
     KeepAlive?: boolean;
     Locale?: string;
     Layout?: string;
+    Theme?: string;
+    Grey?: boolean;
+    Weak?: boolean;
+    HideTabs?: boolean;
     MapConfigure?: {
       amapKey?: string;
       baiduKey?: string;

+ 68 - 1
vite.config.ts

@@ -8,6 +8,7 @@ import { viteMockServe } from "vite-plugin-mock";
 import svgLoader from "vite-svg-loader";
 import styleImport from "vite-plugin-style-import";
 import ElementPlus from "unplugin-element-plus/vite";
+import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
 
 const pathResolve = (dir: string): string => {
   return resolve(__dirname, ".", dir);
@@ -55,6 +56,71 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
     plugins: [
       vue(),
       vueJsx(),
+      themePreprocessorPlugin({
+        scss: {
+          multipleScopeVars: [
+            {
+              // 暗雅(默认)
+              scopeName: "layout-theme-default",
+              path: pathResolve("src/layout/theme/default-vars.scss")
+            },
+            {
+              // 明亮
+              scopeName: "layout-theme-light",
+              path: pathResolve("src/layout/theme/light-vars.scss")
+            },
+            {
+              // 薄暮
+              scopeName: "layout-theme-dusk",
+              path: pathResolve("src/layout/theme/dusk-vars.scss")
+            },
+            {
+              // 火山
+              scopeName: "layout-theme-volcano",
+              path: pathResolve("src/layout/theme/volcano-vars.scss")
+            },
+            {
+              // 黄色
+              scopeName: "layout-theme-yellow",
+              path: pathResolve("src/layout/theme/yellow-vars.scss")
+            },
+            {
+              // 明青
+              scopeName: "layout-theme-mingQing",
+              path: pathResolve("src/layout/theme/mingQing-vars.scss")
+            },
+            {
+              // 极光绿
+              scopeName: "layout-theme-auroraGreen",
+              path: pathResolve("src/layout/theme/auroraGreen-vars.scss")
+            },
+            {
+              // 粉红
+              scopeName: "layout-theme-pink",
+              path: pathResolve("src/layout/theme/pink-vars.scss")
+            },
+            {
+              // 酱紫
+              scopeName: "layout-theme-saucePurple",
+              path: pathResolve("src/layout/theme/saucePurple-vars.scss")
+            }
+          ],
+          // 默认取 multipleScopeVars[0].scopeName
+          defaultScopeName: "",
+          // 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
+          extract: true,
+          // 独立主题css文件的输出路径,默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
+          outputDir: "",
+          // 会选取defaultScopeName对应的主题css文件在html添加link
+          themeLinkTagId: "head",
+          // "head"||"head-prepend" || "body" ||"body-prepend"
+          themeLinkTagInjectTo: "head",
+          // 是否对抽取的css文件内对应scopeName的权重类名移除
+          removeCssScopeName: false,
+          // 可以自定义css文件名称的函数
+          customThemeCssFileName: scopeName => scopeName
+        }
+      }),
       svgLoader(),
       styleImport({
         libs: [
@@ -86,7 +152,8 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
         "element-plus/lib/locale/lang/en",
         "vxe-table/lib/locale/lang/zh-CN",
         "vxe-table/lib/locale/lang/en-US"
-      ]
+      ],
+      exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"]
     },
     build: {
       // @ts-ignore