Jelajahi Sumber

第一次提交202110180900

fanghuisheng 3 tahun lalu
melakukan
7453670cdf
100 mengubah file dengan 6102 tambahan dan 0 penghapusan
  1. 3 0
      .browserslistrc
  2. 15 0
      .eslintrc.js
  3. 10 0
      .gitattributes
  4. 26 0
      .gitignore
  5. 3 0
      .stylelintrc.js
  6. 0 0
      README.md
  7. 3 0
      babel.config.js
  8. 18 0
      deploy.sh
  9. 2294 0
      mock/controller/icon.js
  10. 37 0
      mock/controller/router.js
  11. 65 0
      mock/controller/table.js
  12. 103 0
      mock/controller/user.js
  13. 16 0
      mock/index.js
  14. 94 0
      mock/mockServer.js
  15. 43 0
      mock/utils/index.js
  16. 68 0
      package.json
  17. 16 0
      prettier.config.js
  18. TEMPAT SAMPAH
      public/favicon.ico
  19. TEMPAT SAMPAH
      public/favicon1.ico
  20. 51 0
      public/index.html
  21. 96 0
      public/static/css/loading.css
  22. 6 0
      src/App.vue
  23. 9 0
      src/api/icon.js
  24. 9 0
      src/api/router.js
  25. 25 0
      src/api/table.js
  26. 43 0
      src/api/user.js
  27. 107 0
      src/assets/css/global.scss
  28. 721 0
      src/assets/css/index.scss
  29. TEMPAT SAMPAH
      src/assets/error_images/403.png
  30. TEMPAT SAMPAH
      src/assets/error_images/404.png
  31. TEMPAT SAMPAH
      src/assets/error_images/cloud.png
  32. TEMPAT SAMPAH
      src/assets/images/bg-smooth.jpg
  33. TEMPAT SAMPAH
      src/assets/images/descIcon.png
  34. TEMPAT SAMPAH
      src/assets/images/logo.png
  35. TEMPAT SAMPAH
      src/assets/images/logo1.png
  36. TEMPAT SAMPAH
      src/assets/images/logo_admin.png
  37. TEMPAT SAMPAH
      src/assets/images/noDataImg.png
  38. TEMPAT SAMPAH
      src/assets/login_images/login_background.png
  39. TEMPAT SAMPAH
      src/assets/login_images/login_form.png
  40. TEMPAT SAMPAH
      src/assets/logo.png
  41. TEMPAT SAMPAH
      src/assets/logo1.png
  42. TEMPAT SAMPAH
      src/assets/logo_admin.png
  43. 43 0
      src/components/SvgIcon.vue
  44. 9 0
      src/config/config.js
  45. 8 0
      src/config/default/index.js
  46. 14 0
      src/config/default/net.config.js
  47. 79 0
      src/config/default/setting.config.js
  48. 28 0
      src/config/default/theme.config.js
  49. 9 0
      src/config/index.js
  50. 4 0
      src/icons/index.js
  51. 7 0
      src/icons/svgIcon/alarmManage.svg
  52. 1 0
      src/icons/svgIcon/arrow-down.svg
  53. 1 0
      src/icons/svgIcon/arrow-left.svg
  54. 1 0
      src/icons/svgIcon/arrow-left2.svg
  55. 1 0
      src/icons/svgIcon/arrow-right.svg
  56. 1 0
      src/icons/svgIcon/arrow-right2.svg
  57. 1 0
      src/icons/svgIcon/chart.svg
  58. 1 0
      src/icons/svgIcon/close.svg
  59. 1 0
      src/icons/svgIcon/close2.svg
  60. 0 0
      src/icons/svgIcon/components.svg
  61. 1 0
      src/icons/svgIcon/control.svg
  62. 7 0
      src/icons/svgIcon/dataManage.svg
  63. 1 0
      src/icons/svgIcon/detail.svg
  64. 7 0
      src/icons/svgIcon/deviceManage.svg
  65. 1 0
      src/icons/svgIcon/edit.svg
  66. 1 0
      src/icons/svgIcon/editor.svg
  67. 1 0
      src/icons/svgIcon/home.svg
  68. 1 0
      src/icons/svgIcon/icon.svg
  69. 1 0
      src/icons/svgIcon/language-outline.svg
  70. 1 0
      src/icons/svgIcon/list.svg
  71. 7 0
      src/icons/svgIcon/monthReport.svg
  72. 1 0
      src/icons/svgIcon/more.svg
  73. 5 0
      src/icons/svgIcon/operManage.svg
  74. 1 0
      src/icons/svgIcon/page.svg
  75. 7 0
      src/icons/svgIcon/patrolManage.svg
  76. 1 0
      src/icons/svgIcon/permissions.svg
  77. 7 0
      src/icons/svgIcon/planOutage.svg
  78. 7 0
      src/icons/svgIcon/powerQuality.svg
  79. 1 0
      src/icons/svgIcon/refresh.svg
  80. 1 0
      src/icons/svgIcon/set.svg
  81. 7 0
      src/icons/svgIcon/siteManage.svg
  82. 7 0
      src/icons/svgIcon/stationManage.svg
  83. 5 0
      src/icons/svgIcon/systemManage.svg
  84. 232 0
      src/layout/index.vue
  85. 54 0
      src/layout/vab-avatar/index.vue
  86. 66 0
      src/layout/vab-content/index.vue
  87. 24 0
      src/layout/vab-icon/index.vue
  88. 40 0
      src/layout/vab-logo/index.vue
  89. 43 0
      src/layout/vab-menu/components/MenuItem.vue
  90. 35 0
      src/layout/vab-menu/components/Submenu.vue
  91. 60 0
      src/layout/vab-menu/index.vue
  92. 240 0
      src/layout/vab-tabs/index.vue
  93. 39 0
      src/main.js
  94. 515 0
      src/router/index.js
  95. 17 0
      src/store/index.js
  96. 33 0
      src/store/modules/acl.js
  97. 62 0
      src/store/modules/routes.js
  98. 179 0
      src/store/modules/settings.js
  99. 146 0
      src/store/modules/tagsBar.js
  100. 148 0
      src/store/modules/user.js

+ 3 - 0
.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 15 - 0
.eslintrc.js

@@ -0,0 +1,15 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true,
+  },
+  extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/prettier'],
+  parserOptions: {
+    parser: 'babel-eslint',
+  },
+  rules: {
+    "prettier/prettier": "off",
+    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+  },
+}

+ 10 - 0
.gitattributes

@@ -0,0 +1,10 @@
+*.html text eol=lf
+*.css text eol=lf
+*.js text eol=lf linguist-language=vue
+*.scss text eol=lf
+*.vue text eol=lf
+*.hbs text eol=lf
+*.sh text eol=lf
+*.md text eol=lf
+*.json text eol=lf
+*.yml text eol=lf

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+.DS_Store
+node_modules
+dist
+package-lock.json
+*.zip
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+

+ 3 - 0
.stylelintrc.js

@@ -0,0 +1,3 @@
+module.exports = {
+  extends: ['stylelint-config-recess-order', 'stylelint-config-prettier'],
+}

+ 0 - 0
README.md


+ 3 - 0
babel.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  presets: ['@vue/cli-plugin-babel/preset'],
+}

+ 18 - 0
deploy.sh

@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+set -e
+npm run build
+cd dist
+touch .nojekyll
+git init
+git add -A
+git commit -m 'deploy'
+git push -f "https://${access_token}@gitee.com/chu1204505056/vue-admin-beautiful-mini.git" master:gh-pages
+git push -f "https://${access_token}@gitee.com/chu1204505056/vue-admin-beautiful-antdv.git" master:gh-pages
+start "https://gitee.com/chu1204505056/vue-admin-beautiful-mini/pages"
+start "https://gitee.com/chu1204505056/vue-admin-beautiful-antdv/pages"
+cd -
+exec /bin/bash
+
+
+
+

+ 2294 - 0
mock/controller/icon.js

@@ -0,0 +1,2294 @@
+const data = [
+  '24-hours-fill',
+  '24-hours-line',
+  '4k-fill',
+  '4k-line',
+  'a-b',
+  'account-box-fill',
+  'account-box-line',
+  'account-circle-fill',
+  'account-circle-line',
+  'account-pin-box-fill',
+  'account-pin-box-line',
+  'account-pin-circle-fill',
+  'account-pin-circle-line',
+  'add-box-fill',
+  'add-box-line',
+  'add-circle-fill',
+  'add-circle-line',
+  'add-fill',
+  'add-line',
+  'admin-fill',
+  'admin-line',
+  'airplay-fill',
+  'airplay-line',
+  'alarm-fill',
+  'alarm-line',
+  'alarm-warning-fill',
+  'alarm-warning-line',
+  'album-fill',
+  'album-line',
+  'alert-fill',
+  'alert-line',
+  'aliens-fill',
+  'aliens-line',
+  'align-bottom',
+  'align-center',
+  'align-justify',
+  'align-left',
+  'align-right',
+  'align-top',
+  'align-vertically',
+  'alipay-fill',
+  'alipay-line',
+  'amazon-fill',
+  'amazon-line',
+  'anchor-fill',
+  'anchor-line',
+  'ancient-gate-fill',
+  'ancient-gate-line',
+  'ancient-pavilion-fill',
+  'ancient-pavilion-line',
+  'android-fill',
+  'android-line',
+  'angularjs-fill',
+  'angularjs-line',
+  'anticlockwise-2-fill',
+  'anticlockwise-2-line',
+  'anticlockwise-fill',
+  'anticlockwise-line',
+  'app-store-fill',
+  'app-store-line',
+  'apple-fill',
+  'apple-line',
+  'apps-2-fill',
+  'apps-2-line',
+  'apps-fill',
+  'apps-line',
+  'archive-drawer-fill',
+  'archive-drawer-line',
+  'archive-fill',
+  'archive-line',
+  'arrow-down-circle-fill',
+  'arrow-down-circle-line',
+  'arrow-down-fill',
+  'arrow-down-line',
+  'arrow-down-s-fill',
+  'arrow-down-s-line',
+  'arrow-drop-down-fill',
+  'arrow-drop-down-line',
+  'arrow-drop-left-fill',
+  'arrow-drop-left-line',
+  'arrow-drop-right-fill',
+  'arrow-drop-right-line',
+  'arrow-drop-up-fill',
+  'arrow-drop-up-line',
+  'arrow-go-back-fill',
+  'arrow-go-back-line',
+  'arrow-go-forward-fill',
+  'arrow-go-forward-line',
+  'arrow-left-circle-fill',
+  'arrow-left-circle-line',
+  'arrow-left-down-fill',
+  'arrow-left-down-line',
+  'arrow-left-fill',
+  'arrow-left-line',
+  'arrow-left-right-fill',
+  'arrow-left-right-line',
+  'arrow-left-s-fill',
+  'arrow-left-s-line',
+  'arrow-left-up-fill',
+  'arrow-left-up-line',
+  'arrow-right-circle-fill',
+  'arrow-right-circle-line',
+  'arrow-right-down-fill',
+  'arrow-right-down-line',
+  'arrow-right-fill',
+  'arrow-right-line',
+  'arrow-right-s-fill',
+  'arrow-right-s-line',
+  'arrow-right-up-fill',
+  'arrow-right-up-line',
+  'arrow-up-circle-fill',
+  'arrow-up-circle-line',
+  'arrow-up-down-fill',
+  'arrow-up-down-line',
+  'arrow-up-fill',
+  'arrow-up-line',
+  'arrow-up-s-fill',
+  'arrow-up-s-line',
+  'artboard-2-fill',
+  'artboard-2-line',
+  'artboard-fill',
+  'artboard-line',
+  'article-fill',
+  'article-line',
+  'aspect-ratio-fill',
+  'aspect-ratio-line',
+  'asterisk',
+  'at-fill',
+  'at-line',
+  'attachment-2',
+  'attachment-fill',
+  'attachment-line',
+  'auction-fill',
+  'auction-line',
+  'award-fill',
+  'award-line',
+  'baidu-fill',
+  'baidu-line',
+  'ball-pen-fill',
+  'ball-pen-line',
+  'bank-card-2-fill',
+  'bank-card-2-line',
+  'bank-card-fill',
+  'bank-card-line',
+  'bank-fill',
+  'bank-line',
+  'bar-chart-2-fill',
+  'bar-chart-2-line',
+  'bar-chart-box-fill',
+  'bar-chart-box-line',
+  'bar-chart-fill',
+  'bar-chart-grouped-fill',
+  'bar-chart-grouped-line',
+  'bar-chart-horizontal-fill',
+  'bar-chart-horizontal-line',
+  'bar-chart-line',
+  'barcode-box-fill',
+  'barcode-box-line',
+  'barcode-fill',
+  'barcode-line',
+  'barricade-fill',
+  'barricade-line',
+  'base-station-fill',
+  'base-station-line',
+  'basketball-fill',
+  'basketball-line',
+  'battery-2-charge-fill',
+  'battery-2-charge-line',
+  'battery-2-fill',
+  'battery-2-line',
+  'battery-charge-fill',
+  'battery-charge-line',
+  'battery-fill',
+  'battery-line',
+  'battery-low-fill',
+  'battery-low-line',
+  'battery-saver-fill',
+  'battery-saver-line',
+  'battery-share-fill',
+  'battery-share-line',
+  'bear-smile-fill',
+  'bear-smile-line',
+  'behance-fill',
+  'behance-line',
+  'bell-fill',
+  'bell-line',
+  'bike-fill',
+  'bike-line',
+  'bilibili-fill',
+  'bilibili-line',
+  'bill-fill',
+  'bill-line',
+  'billiards-fill',
+  'billiards-line',
+  'bit-coin-fill',
+  'bit-coin-line',
+  'blaze-fill',
+  'blaze-line',
+  'bluetooth-connect-fill',
+  'bluetooth-connect-line',
+  'bluetooth-fill',
+  'bluetooth-line',
+  'blur-off-fill',
+  'blur-off-line',
+  'body-scan-fill',
+  'body-scan-line',
+  'bold',
+  'book-2-fill',
+  'book-2-line',
+  'book-3-fill',
+  'book-3-line',
+  'book-fill',
+  'book-line',
+  'book-mark-fill',
+  'book-mark-line',
+  'book-open-fill',
+  'book-open-line',
+  'book-read-fill',
+  'book-read-line',
+  'booklet-fill',
+  'booklet-line',
+  'bookmark-2-fill',
+  'bookmark-2-line',
+  'bookmark-3-fill',
+  'bookmark-3-line',
+  'bookmark-fill',
+  'bookmark-line',
+  'boxing-fill',
+  'boxing-line',
+  'braces-fill',
+  'braces-line',
+  'brackets-fill',
+  'brackets-line',
+  'briefcase-2-fill',
+  'briefcase-2-line',
+  'briefcase-3-fill',
+  'briefcase-3-line',
+  'briefcase-4-fill',
+  'briefcase-4-line',
+  'briefcase-5-fill',
+  'briefcase-5-line',
+  'briefcase-fill',
+  'briefcase-line',
+  'bring-forward',
+  'bring-to-front',
+  'broadcast-fill',
+  'broadcast-line',
+  'brush-2-fill',
+  'brush-2-line',
+  'brush-3-fill',
+  'brush-3-line',
+  'brush-4-fill',
+  'brush-4-line',
+  'brush-fill',
+  'brush-line',
+  'bubble-chart-fill',
+  'bubble-chart-line',
+  'bug-2-fill',
+  'bug-2-line',
+  'bug-fill',
+  'bug-line',
+  'building-2-fill',
+  'building-2-line',
+  'building-3-fill',
+  'building-3-line',
+  'building-4-fill',
+  'building-4-line',
+  'building-fill',
+  'building-line',
+  'bus-2-fill',
+  'bus-2-line',
+  'bus-fill',
+  'bus-line',
+  'bus-wifi-fill',
+  'bus-wifi-line',
+  'cactus-fill',
+  'cactus-line',
+  'cake-2-fill',
+  'cake-2-line',
+  'cake-3-fill',
+  'cake-3-line',
+  'cake-fill',
+  'cake-line',
+  'calculator-fill',
+  'calculator-line',
+  'calendar-2-fill',
+  'calendar-2-line',
+  'calendar-check-fill',
+  'calendar-check-line',
+  'calendar-event-fill',
+  'calendar-event-line',
+  'calendar-fill',
+  'calendar-line',
+  'calendar-todo-fill',
+  'calendar-todo-line',
+  'camera-2-fill',
+  'camera-2-line',
+  'camera-3-fill',
+  'camera-3-line',
+  'camera-fill',
+  'camera-lens-fill',
+  'camera-lens-line',
+  'camera-line',
+  'camera-off-fill',
+  'camera-off-line',
+  'camera-switch-fill',
+  'camera-switch-line',
+  'capsule-fill',
+  'capsule-line',
+  'car-fill',
+  'car-line',
+  'car-washing-fill',
+  'car-washing-line',
+  'caravan-fill',
+  'caravan-line',
+  'cast-fill',
+  'cast-line',
+  'cellphone-fill',
+  'cellphone-line',
+  'celsius-fill',
+  'celsius-line',
+  'centos-fill',
+  'centos-line',
+  'character-recognition-fill',
+  'character-recognition-line',
+  'charging-pile-2-fill',
+  'charging-pile-2-line',
+  'charging-pile-fill',
+  'charging-pile-line',
+  'chat-1-fill',
+  'chat-1-line',
+  'chat-2-fill',
+  'chat-2-line',
+  'chat-3-fill',
+  'chat-3-line',
+  'chat-4-fill',
+  'chat-4-line',
+  'chat-check-fill',
+  'chat-check-line',
+  'chat-delete-fill',
+  'chat-delete-line',
+  'chat-download-fill',
+  'chat-download-line',
+  'chat-follow-up-fill',
+  'chat-follow-up-line',
+  'chat-forward-fill',
+  'chat-forward-line',
+  'chat-heart-fill',
+  'chat-heart-line',
+  'chat-history-fill',
+  'chat-history-line',
+  'chat-new-fill',
+  'chat-new-line',
+  'chat-off-fill',
+  'chat-off-line',
+  'chat-poll-fill',
+  'chat-poll-line',
+  'chat-private-fill',
+  'chat-private-line',
+  'chat-quote-fill',
+  'chat-quote-line',
+  'chat-settings-fill',
+  'chat-settings-line',
+  'chat-smile-2-fill',
+  'chat-smile-2-line',
+  'chat-smile-3-fill',
+  'chat-smile-3-line',
+  'chat-smile-fill',
+  'chat-smile-line',
+  'chat-upload-fill',
+  'chat-upload-line',
+  'chat-voice-fill',
+  'chat-voice-line',
+  'check-double-fill',
+  'check-double-line',
+  'check-fill',
+  'check-line',
+  'checkbox-blank-circle-fill',
+  'checkbox-blank-circle-line',
+  'checkbox-blank-fill',
+  'checkbox-blank-line',
+  'checkbox-circle-fill',
+  'checkbox-circle-line',
+  'checkbox-fill',
+  'checkbox-indeterminate-fill',
+  'checkbox-indeterminate-line',
+  'checkbox-line',
+  'checkbox-multiple-blank-fill',
+  'checkbox-multiple-blank-line',
+  'checkbox-multiple-fill',
+  'checkbox-multiple-line',
+  'china-railway-fill',
+  'china-railway-line',
+  'chrome-fill',
+  'chrome-line',
+  'clapperboard-fill',
+  'clapperboard-line',
+  'clipboard-fill',
+  'clipboard-line',
+  'clockwise-2-fill',
+  'clockwise-2-line',
+  'clockwise-fill',
+  'clockwise-line',
+  'close-circle-fill',
+  'close-circle-line',
+  'close-fill',
+  'close-line',
+  'closed-captioning-fill',
+  'closed-captioning-line',
+  'cloud-fill',
+  'cloud-line',
+  'cloud-off-fill',
+  'cloud-off-line',
+  'cloud-windy-fill',
+  'cloud-windy-line',
+  'cloudy-2-fill',
+  'cloudy-2-line',
+  'cloudy-fill',
+  'cloudy-line',
+  'code-box-fill',
+  'code-box-line',
+  'code-fill',
+  'code-line',
+  'code-s-fill',
+  'code-s-line',
+  'code-s-slash-fill',
+  'code-s-slash-line',
+  'code-view',
+  'codepen-fill',
+  'codepen-line',
+  'coin-fill',
+  'coin-line',
+  'coins-fill',
+  'coins-line',
+  'collage-fill',
+  'collage-line',
+  'command-fill',
+  'command-line',
+  'community-fill',
+  'community-line',
+  'compass-2-fill',
+  'compass-2-line',
+  'compass-3-fill',
+  'compass-3-line',
+  'compass-4-fill',
+  'compass-4-line',
+  'compass-discover-fill',
+  'compass-discover-line',
+  'compass-fill',
+  'compass-line',
+  'compasses-2-fill',
+  'compasses-2-line',
+  'compasses-fill',
+  'compasses-line',
+  'computer-fill',
+  'computer-line',
+  'contacts-book-2-fill',
+  'contacts-book-2-line',
+  'contacts-book-fill',
+  'contacts-book-line',
+  'contacts-book-upload-fill',
+  'contacts-book-upload-line',
+  'contacts-fill',
+  'contacts-line',
+  'contrast-2-fill',
+  'contrast-2-line',
+  'contrast-drop-2-fill',
+  'contrast-drop-2-line',
+  'contrast-drop-fill',
+  'contrast-drop-line',
+  'contrast-fill',
+  'contrast-line',
+  'copper-coin-fill',
+  'copper-coin-line',
+  'copper-diamond-fill',
+  'copper-diamond-line',
+  'copyleft-fill',
+  'copyleft-line',
+  'copyright-fill',
+  'copyright-line',
+  'coreos-fill',
+  'coreos-line',
+  'coupon-2-fill',
+  'coupon-2-line',
+  'coupon-3-fill',
+  'coupon-3-line',
+  'coupon-4-fill',
+  'coupon-4-line',
+  'coupon-5-fill',
+  'coupon-5-line',
+  'coupon-fill',
+  'coupon-line',
+  'cpu-fill',
+  'cpu-line',
+  'creative-commons-by-fill',
+  'creative-commons-by-line',
+  'creative-commons-fill',
+  'creative-commons-line',
+  'creative-commons-nc-fill',
+  'creative-commons-nc-line',
+  'creative-commons-nd-fill',
+  'creative-commons-nd-line',
+  'creative-commons-sa-fill',
+  'creative-commons-sa-line',
+  'creative-commons-zero-fill',
+  'creative-commons-zero-line',
+  'criminal-fill',
+  'criminal-line',
+  'crop-2-fill',
+  'crop-2-line',
+  'crop-fill',
+  'crop-line',
+  'css3-fill',
+  'css3-line',
+  'cup-fill',
+  'cup-line',
+  'currency-fill',
+  'currency-line',
+  'cursor-fill',
+  'cursor-line',
+  'customer-service-2-fill',
+  'customer-service-2-line',
+  'customer-service-fill',
+  'customer-service-line',
+  'dashboard-2-fill',
+  'dashboard-2-line',
+  'dashboard-3-fill',
+  'dashboard-3-line',
+  'dashboard-fill',
+  'dashboard-line',
+  'database-2-fill',
+  'database-2-line',
+  'database-fill',
+  'database-line',
+  'delete-back-2-fill',
+  'delete-back-2-line',
+  'delete-back-fill',
+  'delete-back-line',
+  'delete-bin-2-fill',
+  'delete-bin-2-line',
+  'delete-bin-3-fill',
+  'delete-bin-3-line',
+  'delete-bin-4-fill',
+  'delete-bin-4-line',
+  'delete-bin-5-fill',
+  'delete-bin-5-line',
+  'delete-bin-6-fill',
+  'delete-bin-6-line',
+  'delete-bin-7-fill',
+  'delete-bin-7-line',
+  'delete-bin-fill',
+  'delete-bin-line',
+  'delete-column',
+  'delete-row',
+  'device-fill',
+  'device-line',
+  'device-recover-fill',
+  'device-recover-line',
+  'dingding-fill',
+  'dingding-line',
+  'direction-fill',
+  'direction-line',
+  'disc-fill',
+  'disc-line',
+  'discord-fill',
+  'discord-line',
+  'discuss-fill',
+  'discuss-line',
+  'dislike-fill',
+  'dislike-line',
+  'disqus-fill',
+  'disqus-line',
+  'divide-fill',
+  'divide-line',
+  'donut-chart-fill',
+  'donut-chart-line',
+  'door-closed-fill',
+  'door-closed-line',
+  'door-fill',
+  'door-line',
+  'door-lock-box-fill',
+  'door-lock-box-line',
+  'door-lock-fill',
+  'door-lock-line',
+  'door-open-fill',
+  'door-open-line',
+  'dossier-fill',
+  'dossier-line',
+  'douban-fill',
+  'douban-line',
+  'double-quotes-l',
+  'double-quotes-r',
+  'download-2-fill',
+  'download-2-line',
+  'download-cloud-2-fill',
+  'download-cloud-2-line',
+  'download-cloud-fill',
+  'download-cloud-line',
+  'download-fill',
+  'download-line',
+  'draft-fill',
+  'draft-line',
+  'drag-drop-fill',
+  'drag-drop-line',
+  'drag-move-2-fill',
+  'drag-move-2-line',
+  'drag-move-fill',
+  'drag-move-line',
+  'dribbble-fill',
+  'dribbble-line',
+  'drive-fill',
+  'drive-line',
+  'drizzle-fill',
+  'drizzle-line',
+  'drop-fill',
+  'drop-line',
+  'dropbox-fill',
+  'dropbox-line',
+  'dual-sim-1-fill',
+  'dual-sim-1-line',
+  'dual-sim-2-fill',
+  'dual-sim-2-line',
+  'dv-fill',
+  'dv-line',
+  'dvd-fill',
+  'dvd-line',
+  'e-bike-2-fill',
+  'e-bike-2-line',
+  'e-bike-fill',
+  'e-bike-line',
+  'earth-fill',
+  'earth-line',
+  'earthquake-fill',
+  'earthquake-line',
+  'edge-fill',
+  'edge-line',
+  'edit-2-fill',
+  'edit-2-line',
+  'edit-box-fill',
+  'edit-box-line',
+  'edit-circle-fill',
+  'edit-circle-line',
+  'edit-fill',
+  'edit-line',
+  'eject-fill',
+  'eject-line',
+  'emotion-2-fill',
+  'emotion-2-line',
+  'emotion-fill',
+  'emotion-happy-fill',
+  'emotion-happy-line',
+  'emotion-laugh-fill',
+  'emotion-laugh-line',
+  'emotion-line',
+  'emotion-normal-fill',
+  'emotion-normal-line',
+  'emotion-sad-fill',
+  'emotion-sad-line',
+  'emotion-unhappy-fill',
+  'emotion-unhappy-line',
+  'empathize-fill',
+  'empathize-line',
+  'emphasis-cn',
+  'emphasis',
+  'english-input',
+  'equalizer-fill',
+  'equalizer-line',
+  'eraser-fill',
+  'eraser-line',
+  'error-warning-fill',
+  'error-warning-line',
+  'evernote-fill',
+  'evernote-line',
+  'exchange-box-fill',
+  'exchange-box-line',
+  'exchange-cny-fill',
+  'exchange-cny-line',
+  'exchange-dollar-fill',
+  'exchange-dollar-line',
+  'exchange-fill',
+  'exchange-funds-fill',
+  'exchange-funds-line',
+  'exchange-line',
+  'external-link-fill',
+  'external-link-line',
+  'eye-2-fill',
+  'eye-2-line',
+  'eye-close-fill',
+  'eye-close-line',
+  'eye-fill',
+  'eye-line',
+  'eye-off-fill',
+  'eye-off-line',
+  'facebook-box-fill',
+  'facebook-box-line',
+  'facebook-circle-fill',
+  'facebook-circle-line',
+  'facebook-fill',
+  'facebook-line',
+  'fahrenheit-fill',
+  'fahrenheit-line',
+  'feedback-fill',
+  'feedback-line',
+  'file-2-fill',
+  'file-2-line',
+  'file-3-fill',
+  'file-3-line',
+  'file-4-fill',
+  'file-4-line',
+  'file-add-fill',
+  'file-add-line',
+  'file-chart-2-fill',
+  'file-chart-2-line',
+  'file-chart-fill',
+  'file-chart-line',
+  'file-cloud-fill',
+  'file-cloud-line',
+  'file-code-fill',
+  'file-code-line',
+  'file-copy-2-fill',
+  'file-copy-2-line',
+  'file-copy-fill',
+  'file-copy-line',
+  'file-damage-fill',
+  'file-damage-line',
+  'file-download-fill',
+  'file-download-line',
+  'file-edit-fill',
+  'file-edit-line',
+  'file-excel-2-fill',
+  'file-excel-2-line',
+  'file-excel-fill',
+  'file-excel-line',
+  'file-fill',
+  'file-forbid-fill',
+  'file-forbid-line',
+  'file-gif-fill',
+  'file-gif-line',
+  'file-history-fill',
+  'file-history-line',
+  'file-hwp-fill',
+  'file-hwp-line',
+  'file-info-fill',
+  'file-info-line',
+  'file-line',
+  'file-list-2-fill',
+  'file-list-2-line',
+  'file-list-3-fill',
+  'file-list-3-line',
+  'file-list-fill',
+  'file-list-line',
+  'file-lock-fill',
+  'file-lock-line',
+  'file-mark-fill',
+  'file-mark-line',
+  'file-music-fill',
+  'file-music-line',
+  'file-paper-2-fill',
+  'file-paper-2-line',
+  'file-paper-fill',
+  'file-paper-line',
+  'file-pdf-fill',
+  'file-pdf-line',
+  'file-ppt-2-fill',
+  'file-ppt-2-line',
+  'file-ppt-fill',
+  'file-ppt-line',
+  'file-reduce-fill',
+  'file-reduce-line',
+  'file-search-fill',
+  'file-search-line',
+  'file-settings-fill',
+  'file-settings-line',
+  'file-shield-2-fill',
+  'file-shield-2-line',
+  'file-shield-fill',
+  'file-shield-line',
+  'file-shred-fill',
+  'file-shred-line',
+  'file-text-fill',
+  'file-text-line',
+  'file-transfer-fill',
+  'file-transfer-line',
+  'file-unknow-fill',
+  'file-unknow-line',
+  'file-upload-fill',
+  'file-upload-line',
+  'file-user-fill',
+  'file-user-line',
+  'file-warning-fill',
+  'file-warning-line',
+  'file-word-2-fill',
+  'file-word-2-line',
+  'file-word-fill',
+  'file-word-line',
+  'file-zip-fill',
+  'file-zip-line',
+  'film-fill',
+  'film-line',
+  'filter-2-fill',
+  'filter-2-line',
+  'filter-3-fill',
+  'filter-3-line',
+  'filter-fill',
+  'filter-line',
+  'filter-off-fill',
+  'filter-off-line',
+  'find-replace-fill',
+  'find-replace-line',
+  'finder-fill',
+  'finder-line',
+  'fingerprint-2-fill',
+  'fingerprint-2-line',
+  'fingerprint-fill',
+  'fingerprint-line',
+  'fire-fill',
+  'fire-line',
+  'firefox-fill',
+  'firefox-line',
+  'first-aid-kit-fill',
+  'first-aid-kit-line',
+  'flag-2-fill',
+  'flag-2-line',
+  'flag-fill',
+  'flag-line',
+  'flashlight-fill',
+  'flashlight-line',
+  'flask-fill',
+  'flask-line',
+  'flight-land-fill',
+  'flight-land-line',
+  'flight-takeoff-fill',
+  'flight-takeoff-line',
+  'flood-fill',
+  'flood-line',
+  'flow-chart',
+  'flutter-fill',
+  'flutter-line',
+  'focus-2-fill',
+  'focus-2-line',
+  'focus-3-fill',
+  'focus-3-line',
+  'focus-fill',
+  'focus-line',
+  'foggy-fill',
+  'foggy-line',
+  'folder-2-fill',
+  'folder-2-line',
+  'folder-3-fill',
+  'folder-3-line',
+  'folder-4-fill',
+  'folder-4-line',
+  'folder-5-fill',
+  'folder-5-line',
+  'folder-add-fill',
+  'folder-add-line',
+  'folder-chart-2-fill',
+  'folder-chart-2-line',
+  'folder-chart-fill',
+  'folder-chart-line',
+  'folder-download-fill',
+  'folder-download-line',
+  'folder-fill',
+  'folder-forbid-fill',
+  'folder-forbid-line',
+  'folder-history-fill',
+  'folder-history-line',
+  'folder-info-fill',
+  'folder-info-line',
+  'folder-keyhole-fill',
+  'folder-keyhole-line',
+  'folder-line',
+  'folder-lock-fill',
+  'folder-lock-line',
+  'folder-music-fill',
+  'folder-music-line',
+  'folder-open-fill',
+  'folder-open-line',
+  'folder-received-fill',
+  'folder-received-line',
+  'folder-reduce-fill',
+  'folder-reduce-line',
+  'folder-settings-fill',
+  'folder-settings-line',
+  'folder-shared-fill',
+  'folder-shared-line',
+  'folder-shield-2-fill',
+  'folder-shield-2-line',
+  'folder-shield-fill',
+  'folder-shield-line',
+  'folder-transfer-fill',
+  'folder-transfer-line',
+  'folder-unknow-fill',
+  'folder-unknow-line',
+  'folder-upload-fill',
+  'folder-upload-line',
+  'folder-user-fill',
+  'folder-user-line',
+  'folder-warning-fill',
+  'folder-warning-line',
+  'folder-zip-fill',
+  'folder-zip-line',
+  'folders-fill',
+  'folders-line',
+  'font-color',
+  'font-size-2',
+  'font-size',
+  'football-fill',
+  'football-line',
+  'footprint-fill',
+  'footprint-line',
+  'forbid-2-fill',
+  'forbid-2-line',
+  'forbid-fill',
+  'forbid-line',
+  'format-clear',
+  'fridge-fill',
+  'fridge-line',
+  'fullscreen-exit-fill',
+  'fullscreen-exit-line',
+  'fullscreen-fill',
+  'fullscreen-line',
+  'function-fill',
+  'function-line',
+  'functions',
+  'funds-box-fill',
+  'funds-box-line',
+  'funds-fill',
+  'funds-line',
+  'gallery-fill',
+  'gallery-line',
+  'gallery-upload-fill',
+  'gallery-upload-line',
+  'game-fill',
+  'game-line',
+  'gamepad-fill',
+  'gamepad-line',
+  'gas-station-fill',
+  'gas-station-line',
+  'gatsby-fill',
+  'gatsby-line',
+  'genderless-fill',
+  'genderless-line',
+  'ghost-2-fill',
+  'ghost-2-line',
+  'ghost-fill',
+  'ghost-line',
+  'ghost-smile-fill',
+  'ghost-smile-line',
+  'gift-2-fill',
+  'gift-2-line',
+  'gift-fill',
+  'gift-line',
+  'git-branch-fill',
+  'git-branch-line',
+  'git-commit-fill',
+  'git-commit-line',
+  'git-merge-fill',
+  'git-merge-line',
+  'git-pull-request-fill',
+  'git-pull-request-line',
+  'git-repository-commits-fill',
+  'git-repository-commits-line',
+  'git-repository-fill',
+  'git-repository-line',
+  'git-repository-private-fill',
+  'git-repository-private-line',
+  'github-fill',
+  'github-line',
+  'gitlab-fill',
+  'gitlab-line',
+  'global-fill',
+  'global-line',
+  'globe-fill',
+  'globe-line',
+  'goblet-fill',
+  'goblet-line',
+  'google-fill',
+  'google-line',
+  'google-play-fill',
+  'google-play-line',
+  'government-fill',
+  'government-line',
+  'gps-fill',
+  'gps-line',
+  'gradienter-fill',
+  'gradienter-line',
+  'grid-fill',
+  'grid-line',
+  'group-2-fill',
+  'group-2-line',
+  'group-fill',
+  'group-line',
+  'guide-fill',
+  'guide-line',
+  'h-1',
+  'h-2',
+  'h-3',
+  'h-4',
+  'h-5',
+  'h-6',
+  'hail-fill',
+  'hail-line',
+  'hammer-fill',
+  'hammer-line',
+  'hand-coin-fill',
+  'hand-coin-line',
+  'hand-heart-fill',
+  'hand-heart-line',
+  'hand-sanitizer-fill',
+  'hand-sanitizer-line',
+  'handbag-fill',
+  'handbag-line',
+  'hard-drive-2-fill',
+  'hard-drive-2-line',
+  'hard-drive-fill',
+  'hard-drive-line',
+  'hashtag',
+  'haze-2-fill',
+  'haze-2-line',
+  'haze-fill',
+  'haze-line',
+  'hd-fill',
+  'hd-line',
+  'heading',
+  'headphone-fill',
+  'headphone-line',
+  'health-book-fill',
+  'health-book-line',
+  'heart-2-fill',
+  'heart-2-line',
+  'heart-3-fill',
+  'heart-3-line',
+  'heart-add-fill',
+  'heart-add-line',
+  'heart-fill',
+  'heart-line',
+  'heart-pulse-fill',
+  'heart-pulse-line',
+  'hearts-fill',
+  'hearts-line',
+  'heavy-showers-fill',
+  'heavy-showers-line',
+  'history-fill',
+  'history-line',
+  'home-2-fill',
+  'home-2-line',
+  'home-3-fill',
+  'home-3-line',
+  'home-4-fill',
+  'home-4-line',
+  'home-5-fill',
+  'home-5-line',
+  'home-6-fill',
+  'home-6-line',
+  'home-7-fill',
+  'home-7-line',
+  'home-8-fill',
+  'home-8-line',
+  'home-fill',
+  'home-gear-fill',
+  'home-gear-line',
+  'home-heart-fill',
+  'home-heart-line',
+  'home-line',
+  'home-smile-2-fill',
+  'home-smile-2-line',
+  'home-smile-fill',
+  'home-smile-line',
+  'home-wifi-fill',
+  'home-wifi-line',
+  'honor-of-kings-fill',
+  'honor-of-kings-line',
+  'honour-fill',
+  'honour-line',
+  'hospital-fill',
+  'hospital-line',
+  'hotel-bed-fill',
+  'hotel-bed-line',
+  'hotel-fill',
+  'hotel-line',
+  'hotspot-fill',
+  'hotspot-line',
+  'hq-fill',
+  'hq-line',
+  'html5-fill',
+  'html5-line',
+  'ie-fill',
+  'ie-line',
+  'image-2-fill',
+  'image-2-line',
+  'image-add-fill',
+  'image-add-line',
+  'image-edit-fill',
+  'image-edit-line',
+  'image-fill',
+  'image-line',
+  'inbox-archive-fill',
+  'inbox-archive-line',
+  'inbox-fill',
+  'inbox-line',
+  'inbox-unarchive-fill',
+  'inbox-unarchive-line',
+  'increase-decrease-fill',
+  'increase-decrease-line',
+  'indent-decrease',
+  'indent-increase',
+  'indeterminate-circle-fill',
+  'indeterminate-circle-line',
+  'information-fill',
+  'information-line',
+  'infrared-thermometer-fill',
+  'infrared-thermometer-line',
+  'ink-bottle-fill',
+  'ink-bottle-line',
+  'input-cursor-move',
+  'input-method-fill',
+  'input-method-line',
+  'insert-column-left',
+  'insert-column-right',
+  'insert-row-bottom',
+  'insert-row-top',
+  'instagram-fill',
+  'instagram-line',
+  'install-fill',
+  'install-line',
+  'invision-fill',
+  'invision-line',
+  'italic',
+  'kakao-talk-fill',
+  'kakao-talk-line',
+  'key-2-fill',
+  'key-2-line',
+  'key-fill',
+  'key-line',
+  'keyboard-box-fill',
+  'keyboard-box-line',
+  'keyboard-fill',
+  'keyboard-line',
+  'keynote-fill',
+  'keynote-line',
+  'knife-blood-fill',
+  'knife-blood-line',
+  'knife-fill',
+  'knife-line',
+  'landscape-fill',
+  'landscape-line',
+  'layout-2-fill',
+  'layout-2-line',
+  'layout-3-fill',
+  'layout-3-line',
+  'layout-4-fill',
+  'layout-4-line',
+  'layout-5-fill',
+  'layout-5-line',
+  'layout-6-fill',
+  'layout-6-line',
+  'layout-bottom-2-fill',
+  'layout-bottom-2-line',
+  'layout-bottom-fill',
+  'layout-bottom-line',
+  'layout-column-fill',
+  'layout-column-line',
+  'layout-fill',
+  'layout-grid-fill',
+  'layout-grid-line',
+  'layout-left-2-fill',
+  'layout-left-2-line',
+  'layout-left-fill',
+  'layout-left-line',
+  'layout-line',
+  'layout-masonry-fill',
+  'layout-masonry-line',
+  'layout-right-2-fill',
+  'layout-right-2-line',
+  'layout-right-fill',
+  'layout-right-line',
+  'layout-row-fill',
+  'layout-row-line',
+  'layout-top-2-fill',
+  'layout-top-2-line',
+  'layout-top-fill',
+  'layout-top-line',
+  'leaf-fill',
+  'leaf-line',
+  'lifebuoy-fill',
+  'lifebuoy-line',
+  'lightbulb-fill',
+  'lightbulb-flash-fill',
+  'lightbulb-flash-line',
+  'lightbulb-line',
+  'line-chart-fill',
+  'line-chart-line',
+  'line-fill',
+  'line-height',
+  'line-line',
+  'link-m',
+  'link-unlink-m',
+  'link-unlink',
+  'link',
+  'linkedin-box-fill',
+  'linkedin-box-line',
+  'linkedin-fill',
+  'linkedin-line',
+  'links-fill',
+  'links-line',
+  'list-check-2',
+  'list-check',
+  'list-ordered',
+  'list-settings-fill',
+  'list-settings-line',
+  'list-unordered',
+  'live-fill',
+  'live-line',
+  'loader-2-fill',
+  'loader-2-line',
+  'loader-3-fill',
+  'loader-3-line',
+  'loader-4-fill',
+  'loader-4-line',
+  'loader-5-fill',
+  'loader-5-line',
+  'loader-fill',
+  'loader-line',
+  'lock-2-fill',
+  'lock-2-line',
+  'lock-fill',
+  'lock-line',
+  'lock-password-fill',
+  'lock-password-line',
+  'lock-unlock-fill',
+  'lock-unlock-line',
+  'login-box-fill',
+  'login-box-line',
+  'login-circle-fill',
+  'login-circle-line',
+  'logout-box-fill',
+  'logout-box-line',
+  'logout-box-r-fill',
+  'logout-box-r-line',
+  'logout-circle-fill',
+  'logout-circle-line',
+  'logout-circle-r-fill',
+  'logout-circle-r-line',
+  'luggage-cart-fill',
+  'luggage-cart-line',
+  'luggage-deposit-fill',
+  'luggage-deposit-line',
+  'lungs-fill',
+  'lungs-line',
+  'mac-fill',
+  'mac-line',
+  'macbook-fill',
+  'macbook-line',
+  'magic-fill',
+  'magic-line',
+  'mail-add-fill',
+  'mail-add-line',
+  'mail-check-fill',
+  'mail-check-line',
+  'mail-close-fill',
+  'mail-close-line',
+  'mail-download-fill',
+  'mail-download-line',
+  'mail-fill',
+  'mail-forbid-fill',
+  'mail-forbid-line',
+  'mail-line',
+  'mail-lock-fill',
+  'mail-lock-line',
+  'mail-open-fill',
+  'mail-open-line',
+  'mail-send-fill',
+  'mail-send-line',
+  'mail-settings-fill',
+  'mail-settings-line',
+  'mail-star-fill',
+  'mail-star-line',
+  'mail-unread-fill',
+  'mail-unread-line',
+  'mail-volume-fill',
+  'mail-volume-line',
+  'map-2-fill',
+  'map-2-line',
+  'map-fill',
+  'map-line',
+  'map-pin-2-fill',
+  'map-pin-2-line',
+  'map-pin-3-fill',
+  'map-pin-3-line',
+  'map-pin-4-fill',
+  'map-pin-4-line',
+  'map-pin-5-fill',
+  'map-pin-5-line',
+  'map-pin-add-fill',
+  'map-pin-add-line',
+  'map-pin-fill',
+  'map-pin-line',
+  'map-pin-range-fill',
+  'map-pin-range-line',
+  'map-pin-time-fill',
+  'map-pin-time-line',
+  'map-pin-user-fill',
+  'map-pin-user-line',
+  'mark-pen-fill',
+  'mark-pen-line',
+  'markdown-fill',
+  'markdown-line',
+  'markup-fill',
+  'markup-line',
+  'mastercard-fill',
+  'mastercard-line',
+  'mastodon-fill',
+  'mastodon-line',
+  'medal-2-fill',
+  'medal-2-line',
+  'medal-fill',
+  'medal-line',
+  'medicine-bottle-fill',
+  'medicine-bottle-line',
+  'medium-fill',
+  'medium-line',
+  'men-fill',
+  'men-line',
+  'mental-health-fill',
+  'mental-health-line',
+  'menu-2-fill',
+  'menu-2-line',
+  'menu-3-fill',
+  'menu-3-line',
+  'menu-4-fill',
+  'menu-4-line',
+  'menu-5-fill',
+  'menu-5-line',
+  'menu-add-fill',
+  'menu-add-line',
+  'menu-fill',
+  'menu-fold-fill',
+  'menu-fold-line',
+  'menu-line',
+  'menu-unfold-fill',
+  'menu-unfold-line',
+  'merge-cells-horizontal',
+  'merge-cells-vertical',
+  'message-2-fill',
+  'message-2-line',
+  'message-3-fill',
+  'message-3-line',
+  'message-fill',
+  'message-line',
+  'messenger-fill',
+  'messenger-line',
+  'meteor-fill',
+  'meteor-line',
+  'mic-2-fill',
+  'mic-2-line',
+  'mic-fill',
+  'mic-line',
+  'mic-off-fill',
+  'mic-off-line',
+  'mickey-fill',
+  'mickey-line',
+  'microscope-fill',
+  'microscope-line',
+  'microsoft-fill',
+  'microsoft-line',
+  'mind-map',
+  'mini-program-fill',
+  'mini-program-line',
+  'mist-fill',
+  'mist-line',
+  'money-cny-box-fill',
+  'money-cny-box-line',
+  'money-cny-circle-fill',
+  'money-cny-circle-line',
+  'money-dollar-box-fill',
+  'money-dollar-box-line',
+  'money-dollar-circle-fill',
+  'money-dollar-circle-line',
+  'money-euro-box-fill',
+  'money-euro-box-line',
+  'money-euro-circle-fill',
+  'money-euro-circle-line',
+  'money-pound-box-fill',
+  'money-pound-box-line',
+  'money-pound-circle-fill',
+  'money-pound-circle-line',
+  'moon-clear-fill',
+  'moon-clear-line',
+  'moon-cloudy-fill',
+  'moon-cloudy-line',
+  'moon-fill',
+  'moon-foggy-fill',
+  'moon-foggy-line',
+  'moon-line',
+  'more-2-fill',
+  'more-2-line',
+  'more-fill',
+  'more-line',
+  'motorbike-fill',
+  'motorbike-line',
+  'mouse-fill',
+  'mouse-line',
+  'movie-2-fill',
+  'movie-2-line',
+  'movie-fill',
+  'movie-line',
+  'music-2-fill',
+  'music-2-line',
+  'music-fill',
+  'music-line',
+  'mv-fill',
+  'mv-line',
+  'navigation-fill',
+  'navigation-line',
+  'netease-cloud-music-fill',
+  'netease-cloud-music-line',
+  'netflix-fill',
+  'netflix-line',
+  'newspaper-fill',
+  'newspaper-line',
+  'node-tree',
+  'notification-2-fill',
+  'notification-2-line',
+  'notification-3-fill',
+  'notification-3-line',
+  'notification-4-fill',
+  'notification-4-line',
+  'notification-badge-fill',
+  'notification-badge-line',
+  'notification-fill',
+  'notification-line',
+  'notification-off-fill',
+  'notification-off-line',
+  'npmjs-fill',
+  'npmjs-line',
+  'number-0',
+  'number-1',
+  'number-2',
+  'number-3',
+  'number-4',
+  'number-5',
+  'number-6',
+  'number-7',
+  'number-8',
+  'number-9',
+  'numbers-fill',
+  'numbers-line',
+  'nurse-fill',
+  'nurse-line',
+  'oil-fill',
+  'oil-line',
+  'omega',
+  'open-arm-fill',
+  'open-arm-line',
+  'open-source-fill',
+  'open-source-line',
+  'opera-fill',
+  'opera-line',
+  'order-play-fill',
+  'order-play-line',
+  'organization-chart',
+  'outlet-2-fill',
+  'outlet-2-line',
+  'outlet-fill',
+  'outlet-line',
+  'page-separator',
+  'pages-fill',
+  'pages-line',
+  'paint-brush-fill',
+  'paint-brush-line',
+  'paint-fill',
+  'paint-line',
+  'palette-fill',
+  'palette-line',
+  'pantone-fill',
+  'pantone-line',
+  'paragraph',
+  'parent-fill',
+  'parent-line',
+  'parentheses-fill',
+  'parentheses-line',
+  'parking-box-fill',
+  'parking-box-line',
+  'parking-fill',
+  'parking-line',
+  'passport-fill',
+  'passport-line',
+  'patreon-fill',
+  'patreon-line',
+  'pause-circle-fill',
+  'pause-circle-line',
+  'pause-fill',
+  'pause-line',
+  'pause-mini-fill',
+  'pause-mini-line',
+  'paypal-fill',
+  'paypal-line',
+  'pen-nib-fill',
+  'pen-nib-line',
+  'pencil-fill',
+  'pencil-line',
+  'pencil-ruler-2-fill',
+  'pencil-ruler-2-line',
+  'pencil-ruler-fill',
+  'pencil-ruler-line',
+  'percent-fill',
+  'percent-line',
+  'phone-camera-fill',
+  'phone-camera-line',
+  'phone-fill',
+  'phone-find-fill',
+  'phone-find-line',
+  'phone-line',
+  'phone-lock-fill',
+  'phone-lock-line',
+  'picture-in-picture-2-fill',
+  'picture-in-picture-2-line',
+  'picture-in-picture-exit-fill',
+  'picture-in-picture-exit-line',
+  'picture-in-picture-fill',
+  'picture-in-picture-line',
+  'pie-chart-2-fill',
+  'pie-chart-2-line',
+  'pie-chart-box-fill',
+  'pie-chart-box-line',
+  'pie-chart-fill',
+  'pie-chart-line',
+  'pin-distance-fill',
+  'pin-distance-line',
+  'ping-pong-fill',
+  'ping-pong-line',
+  'pinterest-fill',
+  'pinterest-line',
+  'pinyin-input',
+  'pixelfed-fill',
+  'pixelfed-line',
+  'plane-fill',
+  'plane-line',
+  'plant-fill',
+  'plant-line',
+  'play-circle-fill',
+  'play-circle-line',
+  'play-fill',
+  'play-line',
+  'play-list-2-fill',
+  'play-list-2-line',
+  'play-list-add-fill',
+  'play-list-add-line',
+  'play-list-fill',
+  'play-list-line',
+  'play-mini-fill',
+  'play-mini-line',
+  'playstation-fill',
+  'playstation-line',
+  'plug-2-fill',
+  'plug-2-line',
+  'plug-fill',
+  'plug-line',
+  'polaroid-2-fill',
+  'polaroid-2-line',
+  'polaroid-fill',
+  'polaroid-line',
+  'police-car-fill',
+  'police-car-line',
+  'price-tag-2-fill',
+  'price-tag-2-line',
+  'price-tag-3-fill',
+  'price-tag-3-line',
+  'price-tag-fill',
+  'price-tag-line',
+  'printer-cloud-fill',
+  'printer-cloud-line',
+  'printer-fill',
+  'printer-line',
+  'product-hunt-fill',
+  'product-hunt-line',
+  'profile-fill',
+  'profile-line',
+  'projector-2-fill',
+  'projector-2-line',
+  'projector-fill',
+  'projector-line',
+  'psychotherapy-fill',
+  'psychotherapy-line',
+  'pulse-fill',
+  'pulse-line',
+  'pushpin-2-fill',
+  'pushpin-2-line',
+  'pushpin-fill',
+  'pushpin-line',
+  'qq-fill',
+  'qq-line',
+  'qr-code-fill',
+  'qr-code-line',
+  'qr-scan-2-fill',
+  'qr-scan-2-line',
+  'qr-scan-fill',
+  'qr-scan-line',
+  'question-answer-fill',
+  'question-answer-line',
+  'question-fill',
+  'question-line',
+  'question-mark',
+  'questionnaire-fill',
+  'questionnaire-line',
+  'quill-pen-fill',
+  'quill-pen-line',
+  'radar-fill',
+  'radar-line',
+  'radio-2-fill',
+  'radio-2-line',
+  'radio-button-fill',
+  'radio-button-line',
+  'radio-fill',
+  'radio-line',
+  'rainbow-fill',
+  'rainbow-line',
+  'rainy-fill',
+  'rainy-line',
+  'reactjs-fill',
+  'reactjs-line',
+  'record-circle-fill',
+  'record-circle-line',
+  'record-mail-fill',
+  'record-mail-line',
+  'recycle-fill',
+  'recycle-line',
+  'red-packet-fill',
+  'red-packet-line',
+  'reddit-fill',
+  'reddit-line',
+  'refresh-fill',
+  'refresh-line',
+  'refund-2-fill',
+  'refund-2-line',
+  'refund-fill',
+  'refund-line',
+  'registered-fill',
+  'registered-line',
+  'remixicon-fill',
+  'remixicon-line',
+  'remote-control-2-fill',
+  'remote-control-2-line',
+  'remote-control-fill',
+  'remote-control-line',
+  'repeat-2-fill',
+  'repeat-2-line',
+  'repeat-fill',
+  'repeat-line',
+  'repeat-one-fill',
+  'repeat-one-line',
+  'reply-all-fill',
+  'reply-all-line',
+  'reply-fill',
+  'reply-line',
+  'reserved-fill',
+  'reserved-line',
+  'rest-time-fill',
+  'rest-time-line',
+  'restart-fill',
+  'restart-line',
+  'restaurant-2-fill',
+  'restaurant-2-line',
+  'restaurant-fill',
+  'restaurant-line',
+  'rewind-fill',
+  'rewind-line',
+  'rewind-mini-fill',
+  'rewind-mini-line',
+  'rhythm-fill',
+  'rhythm-line',
+  'riding-fill',
+  'riding-line',
+  'road-map-fill',
+  'road-map-line',
+  'roadster-fill',
+  'roadster-line',
+  'robot-fill',
+  'robot-line',
+  'rocket-2-fill',
+  'rocket-2-line',
+  'rocket-fill',
+  'rocket-line',
+  'rotate-lock-fill',
+  'rotate-lock-line',
+  'rounded-corner',
+  'route-fill',
+  'route-line',
+  'router-fill',
+  'router-line',
+  'rss-fill',
+  'rss-line',
+  'ruler-2-fill',
+  'ruler-2-line',
+  'ruler-fill',
+  'ruler-line',
+  'run-fill',
+  'run-line',
+  'safari-fill',
+  'safari-line',
+  'safe-2-fill',
+  'safe-2-line',
+  'safe-fill',
+  'safe-line',
+  'sailboat-fill',
+  'sailboat-line',
+  'save-2-fill',
+  'save-2-line',
+  'save-3-fill',
+  'save-3-line',
+  'save-fill',
+  'save-line',
+  'scales-2-fill',
+  'scales-2-line',
+  'scales-3-fill',
+  'scales-3-line',
+  'scales-fill',
+  'scales-line',
+  'scan-2-fill',
+  'scan-2-line',
+  'scan-fill',
+  'scan-line',
+  'scissors-2-fill',
+  'scissors-2-line',
+  'scissors-cut-fill',
+  'scissors-cut-line',
+  'scissors-fill',
+  'scissors-line',
+  'screenshot-2-fill',
+  'screenshot-2-line',
+  'screenshot-fill',
+  'screenshot-line',
+  'sd-card-fill',
+  'sd-card-line',
+  'sd-card-mini-fill',
+  'sd-card-mini-line',
+  'search-2-fill',
+  'search-2-line',
+  'search-eye-fill',
+  'search-eye-line',
+  'search-fill',
+  'search-line',
+  'secure-payment-fill',
+  'secure-payment-line',
+  'seedling-fill',
+  'seedling-line',
+  'send-backward',
+  'send-plane-2-fill',
+  'send-plane-2-line',
+  'send-plane-fill',
+  'send-plane-line',
+  'send-to-back',
+  'sensor-fill',
+  'sensor-line',
+  'separator',
+  'server-fill',
+  'server-line',
+  'service-fill',
+  'service-line',
+  'settings-2-fill',
+  'settings-2-line',
+  'settings-3-fill',
+  'settings-3-line',
+  'settings-4-fill',
+  'settings-4-line',
+  'settings-5-fill',
+  'settings-5-line',
+  'settings-6-fill',
+  'settings-6-line',
+  'settings-fill',
+  'settings-line',
+  'shape-2-fill',
+  'shape-2-line',
+  'shape-fill',
+  'shape-line',
+  'share-box-fill',
+  'share-box-line',
+  'share-circle-fill',
+  'share-circle-line',
+  'share-fill',
+  'share-forward-2-fill',
+  'share-forward-2-line',
+  'share-forward-box-fill',
+  'share-forward-box-line',
+  'share-forward-fill',
+  'share-forward-line',
+  'share-line',
+  'shield-check-fill',
+  'shield-check-line',
+  'shield-cross-fill',
+  'shield-cross-line',
+  'shield-fill',
+  'shield-flash-fill',
+  'shield-flash-line',
+  'shield-keyhole-fill',
+  'shield-keyhole-line',
+  'shield-line',
+  'shield-star-fill',
+  'shield-star-line',
+  'shield-user-fill',
+  'shield-user-line',
+  'ship-2-fill',
+  'ship-2-line',
+  'ship-fill',
+  'ship-line',
+  'shirt-fill',
+  'shirt-line',
+  'shopping-bag-2-fill',
+  'shopping-bag-2-line',
+  'shopping-bag-3-fill',
+  'shopping-bag-3-line',
+  'shopping-bag-fill',
+  'shopping-bag-line',
+  'shopping-basket-2-fill',
+  'shopping-basket-2-line',
+  'shopping-basket-fill',
+  'shopping-basket-line',
+  'shopping-cart-2-fill',
+  'shopping-cart-2-line',
+  'shopping-cart-fill',
+  'shopping-cart-line',
+  'showers-fill',
+  'showers-line',
+  'shuffle-fill',
+  'shuffle-line',
+  'shut-down-fill',
+  'shut-down-line',
+  'side-bar-fill',
+  'side-bar-line',
+  'signal-tower-fill',
+  'signal-tower-line',
+  'signal-wifi-1-fill',
+  'signal-wifi-1-line',
+  'signal-wifi-2-fill',
+  'signal-wifi-2-line',
+  'signal-wifi-3-fill',
+  'signal-wifi-3-line',
+  'signal-wifi-error-fill',
+  'signal-wifi-error-line',
+  'signal-wifi-fill',
+  'signal-wifi-line',
+  'signal-wifi-off-fill',
+  'signal-wifi-off-line',
+  'sim-card-2-fill',
+  'sim-card-2-line',
+  'sim-card-fill',
+  'sim-card-line',
+  'single-quotes-l',
+  'single-quotes-r',
+  'sip-fill',
+  'sip-line',
+  'skip-back-fill',
+  'skip-back-line',
+  'skip-back-mini-fill',
+  'skip-back-mini-line',
+  'skip-forward-fill',
+  'skip-forward-line',
+  'skip-forward-mini-fill',
+  'skip-forward-mini-line',
+  'skull-2-fill',
+  'skull-2-line',
+  'skull-fill',
+  'skull-line',
+  'skype-fill',
+  'skype-line',
+  'slack-fill',
+  'slack-line',
+  'slice-fill',
+  'slice-line',
+  'slideshow-2-fill',
+  'slideshow-2-line',
+  'slideshow-3-fill',
+  'slideshow-3-line',
+  'slideshow-4-fill',
+  'slideshow-4-line',
+  'slideshow-fill',
+  'slideshow-line',
+  'smartphone-fill',
+  'smartphone-line',
+  'snapchat-fill',
+  'snapchat-line',
+  'snowy-fill',
+  'snowy-line',
+  'sort-asc',
+  'sort-desc',
+  'sound-module-fill',
+  'sound-module-line',
+  'soundcloud-fill',
+  'soundcloud-line',
+  'space-ship-fill',
+  'space-ship-line',
+  'space',
+  'spam-2-fill',
+  'spam-2-line',
+  'spam-3-fill',
+  'spam-3-line',
+  'spam-fill',
+  'spam-line',
+  'speaker-2-fill',
+  'speaker-2-line',
+  'speaker-3-fill',
+  'speaker-3-line',
+  'speaker-fill',
+  'speaker-line',
+  'spectrum-fill',
+  'spectrum-line',
+  'speed-fill',
+  'speed-line',
+  'speed-mini-fill',
+  'speed-mini-line',
+  'split-cells-horizontal',
+  'split-cells-vertical',
+  'spotify-fill',
+  'spotify-line',
+  'spy-fill',
+  'spy-line',
+  'stack-fill',
+  'stack-line',
+  'stack-overflow-fill',
+  'stack-overflow-line',
+  'stackshare-fill',
+  'stackshare-line',
+  'star-fill',
+  'star-half-fill',
+  'star-half-line',
+  'star-half-s-fill',
+  'star-half-s-line',
+  'star-line',
+  'star-s-fill',
+  'star-s-line',
+  'star-smile-fill',
+  'star-smile-line',
+  'steam-fill',
+  'steam-line',
+  'steering-2-fill',
+  'steering-2-line',
+  'steering-fill',
+  'steering-line',
+  'stethoscope-fill',
+  'stethoscope-line',
+  'sticky-note-2-fill',
+  'sticky-note-2-line',
+  'sticky-note-fill',
+  'sticky-note-line',
+  'stock-fill',
+  'stock-line',
+  'stop-circle-fill',
+  'stop-circle-line',
+  'stop-fill',
+  'stop-line',
+  'stop-mini-fill',
+  'stop-mini-line',
+  'store-2-fill',
+  'store-2-line',
+  'store-3-fill',
+  'store-3-line',
+  'store-fill',
+  'store-line',
+  'strikethrough-2',
+  'strikethrough',
+  'subscript-2',
+  'subscript',
+  'subtract-fill',
+  'subtract-line',
+  'subway-fill',
+  'subway-line',
+  'subway-wifi-fill',
+  'subway-wifi-line',
+  'suitcase-2-fill',
+  'suitcase-2-line',
+  'suitcase-3-fill',
+  'suitcase-3-line',
+  'suitcase-fill',
+  'suitcase-line',
+  'sun-cloudy-fill',
+  'sun-cloudy-line',
+  'sun-fill',
+  'sun-foggy-fill',
+  'sun-foggy-line',
+  'sun-line',
+  'superscript-2',
+  'superscript',
+  'surgical-mask-fill',
+  'surgical-mask-line',
+  'surround-sound-fill',
+  'surround-sound-line',
+  'survey-fill',
+  'survey-line',
+  'swap-box-fill',
+  'swap-box-line',
+  'swap-fill',
+  'swap-line',
+  'switch-fill',
+  'switch-line',
+  'sword-fill',
+  'sword-line',
+  'syringe-fill',
+  'syringe-line',
+  't-box-fill',
+  't-box-line',
+  't-shirt-2-fill',
+  't-shirt-2-line',
+  't-shirt-air-fill',
+  't-shirt-air-line',
+  't-shirt-fill',
+  't-shirt-line',
+  'table-2',
+  'table-alt-fill',
+  'table-alt-line',
+  'table-fill',
+  'table-line',
+  'tablet-fill',
+  'tablet-line',
+  'takeaway-fill',
+  'takeaway-line',
+  'taobao-fill',
+  'taobao-line',
+  'tape-fill',
+  'tape-line',
+  'task-fill',
+  'task-line',
+  'taxi-fill',
+  'taxi-line',
+  'taxi-wifi-fill',
+  'taxi-wifi-line',
+  'team-fill',
+  'team-line',
+  'telegram-fill',
+  'telegram-line',
+  'temp-cold-fill',
+  'temp-cold-line',
+  'temp-hot-fill',
+  'temp-hot-line',
+  'terminal-box-fill',
+  'terminal-box-line',
+  'terminal-fill',
+  'terminal-line',
+  'terminal-window-fill',
+  'terminal-window-line',
+  'test-tube-fill',
+  'test-tube-line',
+  'text-direction-l',
+  'text-direction-r',
+  'text-spacing',
+  'text-wrap',
+  'text',
+  'thermometer-fill',
+  'thermometer-line',
+  'thumb-down-fill',
+  'thumb-down-line',
+  'thumb-up-fill',
+  'thumb-up-line',
+  'thunderstorms-fill',
+  'thunderstorms-line',
+  'ticket-2-fill',
+  'ticket-2-line',
+  'ticket-fill',
+  'ticket-line',
+  'time-fill',
+  'time-line',
+  'timer-2-fill',
+  'timer-2-line',
+  'timer-fill',
+  'timer-flash-fill',
+  'timer-flash-line',
+  'timer-line',
+  'todo-fill',
+  'todo-line',
+  'toggle-fill',
+  'toggle-line',
+  'tools-fill',
+  'tools-line',
+  'tornado-fill',
+  'tornado-line',
+  'trademark-fill',
+  'trademark-line',
+  'traffic-light-fill',
+  'traffic-light-line',
+  'train-fill',
+  'train-line',
+  'train-wifi-fill',
+  'train-wifi-line',
+  'translate-2',
+  'translate',
+  'travesti-fill',
+  'travesti-line',
+  'treasure-map-fill',
+  'treasure-map-line',
+  'trello-fill',
+  'trello-line',
+  'trophy-fill',
+  'trophy-line',
+  'truck-fill',
+  'truck-line',
+  'tumblr-fill',
+  'tumblr-line',
+  'tv-2-fill',
+  'tv-2-line',
+  'tv-fill',
+  'tv-line',
+  'twitch-fill',
+  'twitch-line',
+  'twitter-fill',
+  'twitter-line',
+  'typhoon-fill',
+  'typhoon-line',
+  'u-disk-fill',
+  'u-disk-line',
+  'ubuntu-fill',
+  'ubuntu-line',
+  'umbrella-fill',
+  'umbrella-line',
+  'underline',
+  'uninstall-fill',
+  'uninstall-line',
+  'unsplash-fill',
+  'unsplash-line',
+  'upload-2-fill',
+  'upload-2-line',
+  'upload-cloud-2-fill',
+  'upload-cloud-2-line',
+  'upload-cloud-fill',
+  'upload-cloud-line',
+  'upload-fill',
+  'upload-line',
+  'usb-fill',
+  'usb-line',
+  'user-2-fill',
+  'user-2-line',
+  'user-3-fill',
+  'user-3-line',
+  'user-4-fill',
+  'user-4-line',
+  'user-5-fill',
+  'user-5-line',
+  'user-6-fill',
+  'user-6-line',
+  'user-add-fill',
+  'user-add-line',
+  'user-fill',
+  'user-follow-fill',
+  'user-follow-line',
+  'user-heart-fill',
+  'user-heart-line',
+  'user-line',
+  'user-location-fill',
+  'user-location-line',
+  'user-received-2-fill',
+  'user-received-2-line',
+  'user-received-fill',
+  'user-received-line',
+  'user-search-fill',
+  'user-search-line',
+  'user-settings-fill',
+  'user-settings-line',
+  'user-shared-2-fill',
+  'user-shared-2-line',
+  'user-shared-fill',
+  'user-shared-line',
+  'user-smile-fill',
+  'user-smile-line',
+  'user-star-fill',
+  'user-star-line',
+  'user-unfollow-fill',
+  'user-unfollow-line',
+  'user-voice-fill',
+  'user-voice-line',
+  'video-add-fill',
+  'video-add-line',
+  'video-chat-fill',
+  'video-chat-line',
+  'video-download-fill',
+  'video-download-line',
+  'video-fill',
+  'video-line',
+  'video-upload-fill',
+  'video-upload-line',
+  'vidicon-2-fill',
+  'vidicon-2-line',
+  'vidicon-fill',
+  'vidicon-line',
+  'vimeo-fill',
+  'vimeo-line',
+  'vip-crown-2-fill',
+  'vip-crown-2-line',
+  'vip-crown-fill',
+  'vip-crown-line',
+  'vip-diamond-fill',
+  'vip-diamond-line',
+  'vip-fill',
+  'vip-line',
+  'virus-fill',
+  'virus-line',
+  'visa-fill',
+  'visa-line',
+  'voice-recognition-fill',
+  'voice-recognition-line',
+  'voiceprint-fill',
+  'voiceprint-line',
+  'volume-down-fill',
+  'volume-down-line',
+  'volume-mute-fill',
+  'volume-mute-line',
+  'volume-off-vibrate-fill',
+  'volume-off-vibrate-line',
+  'volume-up-fill',
+  'volume-up-line',
+  'volume-vibrate-fill',
+  'volume-vibrate-line',
+  'vuejs-fill',
+  'vuejs-line',
+  'walk-fill',
+  'walk-line',
+  'wallet-2-fill',
+  'wallet-2-line',
+  'wallet-3-fill',
+  'wallet-3-line',
+  'wallet-fill',
+  'wallet-line',
+  'water-flash-fill',
+  'water-flash-line',
+  'webcam-fill',
+  'webcam-line',
+  'wechat-2-fill',
+  'wechat-2-line',
+  'wechat-fill',
+  'wechat-line',
+  'wechat-pay-fill',
+  'wechat-pay-line',
+  'weibo-fill',
+  'weibo-line',
+  'whatsapp-fill',
+  'whatsapp-line',
+  'wheelchair-fill',
+  'wheelchair-line',
+  'wifi-fill',
+  'wifi-line',
+  'wifi-off-fill',
+  'wifi-off-line',
+  'window-2-fill',
+  'window-2-line',
+  'window-fill',
+  'window-line',
+  'windows-fill',
+  'windows-line',
+  'windy-fill',
+  'windy-line',
+  'wireless-charging-fill',
+  'wireless-charging-line',
+  'women-fill',
+  'women-line',
+  'wubi-input',
+  'xbox-fill',
+  'xbox-line',
+  'xing-fill',
+  'xing-line',
+  'youtube-fill',
+  'youtube-line',
+  'zcool-fill',
+  'zcool-line',
+  'zhihu-fill',
+  'zhihu-line',
+  'zoom-in-fill',
+  'zoom-in-line',
+  'zoom-out-fill',
+  'zoom-out-line',
+  'zzz-fill',
+  'zzz-line',
+]
+module.exports = [
+  {
+    url: '/icon/getList',
+    type: 'get',
+    response(config) {
+      const { title, current = 1, pageSize = 72 } = config.query
+      let mockList = data.filter((item) => {
+        if (title && item.indexOf(title) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * current && index >= pageSize * (current - 1)
+      )
+      return {
+        code: 200,
+        msg: 'success',
+        totalCount: mockList.length,
+        data: pageList,
+      }
+    },
+  },
+]

+ 37 - 0
mock/controller/router.js

@@ -0,0 +1,37 @@
+const data = [
+  {
+    path: '/',
+    component: 'Layout',
+    redirect: '/index',
+    meta: {
+      title: '首页',
+      icon: 'home-4-line',
+      affix: true,
+    },
+    children: [
+      {
+        path: 'index',
+        name: 'Index',
+        component: '@/views/index',
+        meta: {
+          title: '首页',
+          icon: 'home-4-line',
+          affix: true,
+        },
+      },
+    ],
+  },
+]
+module.exports = [
+  {
+    url: '/menu/navigate',
+    type: 'get',
+    response() {
+      return {
+        code: 200,
+        msg: 'success',
+        data,
+      }
+    },
+  },
+]

+ 65 - 0
mock/controller/table.js

@@ -0,0 +1,65 @@
+const { mock } = require('mockjs')
+const { handleRandomImage } = require('../utils')
+const List = []
+const count = 50
+for (let i = 0; i < count; i++) {
+  List.push(
+    mock({
+      uuid: '@uuid',
+      id: '@id',
+      title: '@title(1, 2)',
+      description: '@csentence',
+      'status|1': ['published', 'draft', 'deleted'],
+      author: '@cname',
+      datetime: '@datetime',
+      pageViews: '@integer(300, 5000)',
+      img: handleRandomImage(228, 228),
+      switch: '@boolean',
+      percent: '@integer(80,99)',
+      'rate|1': [1, 2, 3, 4, 5],
+    })
+  )
+}
+
+module.exports = [
+  {
+    url: '/table/getList',
+    type: 'get',
+    response(config) {
+      const { title, current = 1, pageSize = 10 } = config.query
+      let mockList = List.filter((item) => {
+        return !(title && item.title.indexOf(title) < 0)
+      })
+      const pageList = mockList.filter(
+        (item, index) =>
+          index < pageSize * current && index >= pageSize * (current - 1)
+      )
+      return {
+        code: 200,
+        msg: 'success',
+        total: mockList.length,
+        data: pageList,
+      }
+    },
+  },
+  {
+    url: '/table/doEdit',
+    type: 'post',
+    response() {
+      return {
+        code: 200,
+        msg: '模拟保存成功',
+      }
+    },
+  },
+  {
+    url: '/table/doDelete',
+    type: 'post',
+    response() {
+      return {
+        code: 200,
+        msg: '模拟删除成功',
+      }
+    },
+  },
+]

+ 103 - 0
mock/controller/user.js

@@ -0,0 +1,103 @@
+const accessTokens = {
+  admin: 'admin-accessToken',
+  editor: 'editor-accessToken',
+  test: 'test-accessToken',
+}
+
+module.exports = [
+  {
+    url: '/login',
+    type: 'post',
+    response(config) {
+      const { username } = config.body
+      const accessToken = accessTokens[username]
+      if (!accessToken) {
+        return {
+          code: 500,
+          msg: '帐户或密码不正确。',
+        }
+      }
+      return {
+        code: 200,
+        msg: 'success',
+        data: { accessToken },
+      }
+    },
+  },
+  {
+    url: '/socialLogin',
+    type: 'post',
+    response(config) {
+      const { code } = config.body
+      if (!code) {
+        return {
+          code: 500,
+          msg: '未成功获取Token。',
+        }
+      }
+      return {
+        code: 200,
+        msg: 'success',
+        data: { accessToken: accessTokens['admin'] },
+      }
+    },
+  },
+  {
+    url: '/register',
+    type: 'post',
+    response() {
+      return {
+        code: 200,
+        msg: '模拟注册成功',
+      }
+    },
+  },
+  {
+    url: '/userInfo',
+    type: 'post',
+    response(config) {
+      const { accessToken } = config.body
+      let roles = ['admin']
+      let ability = ['READ']
+      let username = 'admin'
+      if ('admin-accessToken' === accessToken) {
+        roles = ['admin']
+        ability = ['READ', 'WRITE', 'DELETE']
+        username = 'admin'
+      }
+      if ('editor-accessToken' === accessToken) {
+        roles = ['editor']
+        ability = ['READ', 'WRITE']
+        username = 'editor'
+      }
+      if ('test-accessToken' === accessToken) {
+        roles = ['admin', 'editor']
+        ability = ['READ']
+        username = 'test'
+      }
+      return {
+        code: 200,
+        msg: 'success',
+        data: {
+          roles,
+          ability,
+          username,
+          'avatar|1': [
+            'https://i.gtimg.cn/club/item/face/img/2/15922_100.gif',
+            'https://i.gtimg.cn/club/item/face/img/8/15918_100.gif',
+          ],
+        },
+      }
+    },
+  },
+  {
+    url: '/logout',
+    type: 'post',
+    response() {
+      return {
+        code: 200,
+        msg: 'success',
+      }
+    },
+  },
+]

+ 16 - 0
mock/index.js

@@ -0,0 +1,16 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 导入所有 controller 模块,npm run serve时在node环境中自动输出controller文件夹下Mock接口,请勿修改。
+ */
+
+const { handleMockArray } = require('./utils')
+
+const mocks = []
+const mockArray = handleMockArray()
+mockArray.forEach((item) => {
+  const obj = require(item)
+  mocks.push(...obj)
+})
+module.exports = {
+  mocks,
+}

+ 94 - 0
mock/mockServer.js

@@ -0,0 +1,94 @@
+const chokidar = require('chokidar')
+const bodyParser = require('body-parser')
+const chalk = require('chalk')
+const path = require('path')
+const Mock = require('mockjs')
+const { baseURL } = require('../src/config')
+const mockDir = path.join(process.cwd(), 'mock')
+
+/**
+ *
+ * @param app
+ * @returns {{mockStartIndex: number, mockRoutesLength: number}}
+ */
+const registerRoutes = (app) => {
+  let mockLastIndex
+  const { mocks } = require('./index.js')
+  const mocksForServer = mocks.map((route) => {
+    return responseFake(route.url, route.type, route.response)
+  })
+  for (const mock of mocksForServer) {
+    app[mock.type](mock.url, mock.response)
+    mockLastIndex = app._router.stack.length
+  }
+  const mockRoutesLength = Object.keys(mocksForServer).length
+  return {
+    mockRoutesLength: mockRoutesLength,
+    mockStartIndex: mockLastIndex - mockRoutesLength,
+  }
+}
+
+/**
+ *
+ * @param url
+ * @param type
+ * @param respond
+ * @returns {{response(*=, *=): void, type: (*|string), url: RegExp}}
+ */
+const responseFake = (url, type, respond) => {
+  return {
+    url: new RegExp(`${baseURL}${url}`),
+    type: type || 'get',
+    response(req, res) {
+      res.status(200)
+      if (JSON.stringify(req.body) !== '{}') {
+        console.log(chalk.green(`> 请求地址:${req.path}`))
+        console.log(chalk.green(`> 请求参数:${JSON.stringify(req.body)}\n`))
+      } else {
+        console.log(chalk.green(`> 请求地址:${req.path}\n`))
+      }
+      res.json(
+        Mock.mock(respond instanceof Function ? respond(req, res) : respond)
+      )
+    },
+  }
+}
+/**
+ *
+ * @param app
+ */
+module.exports = (app) => {
+  app.use(bodyParser.json())
+  app.use(
+    bodyParser.urlencoded({
+      extended: true,
+    })
+  )
+
+  const mockRoutes = registerRoutes(app)
+  let mockRoutesLength = mockRoutes.mockRoutesLength
+  let mockStartIndex = mockRoutes.mockStartIndex
+  chokidar
+    .watch(mockDir, {
+      ignored: /mock-server/,
+      ignoreInitial: true,
+    })
+    .on('all', (event) => {
+      if (event === 'change' || event === 'add') {
+        try {
+          app._router.stack.splice(mockStartIndex, mockRoutesLength)
+
+          Object.keys(require.cache).forEach((item) => {
+            if (item.includes(mockDir)) {
+              delete require.cache[require.resolve(item)]
+            }
+          })
+          const mockRoutes = registerRoutes(app)
+          mockRoutesLength = mockRoutes.mockRoutesLength
+          mockStartIndex = mockRoutes.mockStartIndex
+        } catch (error) {
+          console.log(chalk.red(error))
+        }
+      }
+    })
+}

+ 43 - 0
mock/utils/index.js

@@ -0,0 +1,43 @@
+const { Random } = require('mockjs')
+const { join } = require('path')
+const fs = require('fs')
+
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 随机生成图片url。
+ * @param width
+ * @param height
+ * @returns {string}
+ */
+function handleRandomImage(width = 50, height = 50) {
+  return `https://picsum.photos/${width}/${height}?random=${Random.guid()}`
+}
+
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 处理所有 controller 模块,npm run serve时在node环境中自动输出controller文件夹下Mock接口,请勿修改。
+ * @returns {[]}
+ */
+function handleMockArray() {
+  const mockArray = []
+  const getFiles = (jsonPath) => {
+    const jsonFiles = []
+    const findJsonFile = (path) => {
+      const files = fs.readdirSync(path)
+      files.forEach((item) => {
+        const fPath = join(path, item)
+        const stat = fs.statSync(fPath)
+        if (stat.isDirectory() === true) findJsonFile(item)
+        if (stat.isFile() === true) jsonFiles.push(item)
+      })
+    }
+    findJsonFile(jsonPath)
+    jsonFiles.forEach((item) => mockArray.push(`./controller/${item}`))
+  }
+  getFiles('mock/controller')
+  return mockArray
+}
+module.exports = {
+  handleRandomImage,
+  handleMockArray,
+}

+ 68 - 0
package.json

@@ -0,0 +1,68 @@
+{
+  "name": "vue-admin-beautiful-antdv",
+  "version": "1.0.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint",
+    "clear": "rimraf node_modules&&npm install --registry=https://registry.npm.taobao.org",
+    "use:npm": "nrm use npm",
+    "use:taobao": "nrm use taobao",
+    "update": "ncu -u --target greatest&&npm install --registry=https://registry.npm.taobao.org",
+    "deploy": "start ./deploy.sh"
+  },
+  "dependencies": {
+    "ant-design-vue": "2.0.0-rc.9",
+    "axios": "^0.21.1",
+    "clipboard": "^2.0.6",
+    "core-js": "^3.8.3",
+    "dayjs": "^1.10.4",
+    "echarts": "^5.2.1",
+    "element-plus": "^1.1.0-beta.20",
+    "js-cookie": "^3.0.0-rc.1",
+    "mockjs": "^1.1.0",
+    "remixicon": "^2.5.0",
+    "vue": "^3.2.18",
+    "vue-router": "^4.0.3",
+    "vuex": "^4.0.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "^4.5.9",
+    "@vue/cli-plugin-eslint": "^4.5.9",
+    "@vue/cli-service": "^4.5.9",
+    "@vue/compiler-sfc": "^3.0.5",
+    "@vue/eslint-config-prettier": "^6.0.0",
+    "babel-eslint": "^11.0.0-beta.2",
+    "body-parser": "^1.19.0",
+    "chalk": "^4.1.0",
+    "chokidar": "^3.5.1",
+    "eslint": "^7.19.0",
+    "eslint-plugin-prettier": "^3.3.1",
+    "eslint-plugin-vue": "^7.5.0",
+    "filemanager-webpack-plugin": "^3.1.0",
+    "image-webpack-loader": "^7.0.1",
+    "less": "^4.1.1",
+    "less-loader": "^7.3.0",
+    "lint-staged": "^10.5.3",
+    "node-sass": "^4.14.1",
+    "prettier": "^2.2.1",
+    "sass": "^1.42.1",
+    "sass-loader": "^8.0.2",
+    "stylelint": "^13.9.0",
+    "stylelint-config-prettier": "^8.0.2",
+    "stylelint-config-recess-order": "^2.3.0",
+    "svg-sprite-loader": "^5.2.1",
+    "vab-config": "0.0.8",
+    "webpackbar": "^5.0.0-3"
+  },
+  "gitHooks": {
+    "pre-commit": "lint-staged"
+  },
+  "lint-staged": {
+    "*.{js,jsx,vue}": [
+      "vue-cli-service lint",
+      "git add"
+    ]
+  }
+}

+ 16 - 0
prettier.config.js

@@ -0,0 +1,16 @@
+module.exports = {
+  printWidth: 80,
+  tabWidth: 2,
+  useTabs: false,
+  semi: false,
+  singleQuote: true,
+  quoteProps: 'as-needed',
+  jsxSingleQuote: false,
+  trailingComma: 'es5',
+  bracketSpacing: true,
+  jsxBracketSameLine: false,
+  arrowParens: 'always',
+  htmlWhitespaceSensitivity: 'ignore',
+  vueIndentScriptAndStyle: true,
+  endOfLine: 'lf',
+}

TEMPAT SAMPAH
public/favicon.ico


TEMPAT SAMPAH
public/favicon1.ico


+ 51 - 0
public/index.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
+    <title><%= htmlWebpackPlugin.options.title %></title>
+    <meta
+      content="vab,vab官网,后台管理框架,vue后台管理框架,vue-admin-beautiful,vue-admin-beautiful-pro,vue-admin-beautiful官网,vue-admin-beautiful文档,vue-element-admin,vue-element-admin官网,vue-element-admin文档,vue-admin,vue-admin官网,vue-admin文档"
+      name="keywords"
+    />
+    <meta
+      content="<%= VUE_APP_TITLE %>官网与文档基于vue-admin-beautiful-pro构建,简称vab(是一款超棒的vue+element中后台前端快速开发框架),QQ群972435319,作者:<%= VUE_APP_AUTHOR %>"
+      name="description"
+    />
+    <meta content="<%= VUE_APP_AUTHOR %>" name="author" />
+    <link href="<%= BASE_URL %>static/css/loading.css" rel="stylesheet" />
+    <script>
+      var _hmt = _hmt || [];
+      (function () {
+        var hm = document.createElement("script");
+        hm.src = "https://hm.baidu.com/hm.js?7174bade1219f9cc272e7978f9523fc8";
+        var s = document.getElementsByTagName("script")[0];
+        s.parentNode.insertBefore(hm, s);
+      })();
+    </script>
+  </head>
+  <body>
+    <noscript>
+      <strong>
+        We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
+        properly without JavaScript enabled. Please enable it to continue.
+      </strong>
+    </noscript>
+    <div id="app">
+      <div class="first-loading-wrp">
+        <div class="loading-wrp">
+          <span class="dot dot-spin">
+            <i></i>
+            <i></i>
+            <i></i>
+            <i></i>
+          </span>
+        </div>
+        <h1><%= VUE_APP_TITLE %></h1>
+      </div>
+    </div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 96 - 0
public/static/css/loading.css

@@ -0,0 +1,96 @@
+.first-loading-wrp {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 90vh;
+  min-height: 90vh;
+}
+
+.first-loading-wrp > h1 {
+  font-size: 24px;
+  font-weight: bolder;
+}
+
+.first-loading-wrp .loading-wrp {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 98px;
+}
+
+.dot {
+  position: relative;
+  box-sizing: border-box;
+  display: inline-block;
+  width: 64px;
+  height: 64px;
+  font-size: 64px;
+  transform: rotate(45deg);
+  animation: antRotate 1.2s infinite linear;
+}
+
+.dot i {
+  position: absolute;
+  display: block;
+  width: 28px;
+  height: 28px;
+  background-color: #1890ff;
+  border-radius: 100%;
+  opacity: 0.3;
+  transform: scale(0.75);
+  transform-origin: 50% 50%;
+  animation: antSpinMove 1s infinite linear alternate;
+}
+
+.dot i:nth-child(1) {
+  top: 0;
+  left: 0;
+}
+
+.dot i:nth-child(2) {
+  top: 0;
+  right: 0;
+  -webkit-animation-delay: 0.4s;
+  animation-delay: 0.4s;
+}
+
+.dot i:nth-child(3) {
+  right: 0;
+  bottom: 0;
+  -webkit-animation-delay: 0.8s;
+  animation-delay: 0.8s;
+}
+
+.dot i:nth-child(4) {
+  bottom: 0;
+  left: 0;
+  -webkit-animation-delay: 1.2s;
+  animation-delay: 1.2s;
+}
+
+@keyframes antRotate {
+  to {
+    -webkit-transform: rotate(405deg);
+    transform: rotate(405deg);
+  }
+}
+
+@-webkit-keyframes antRotate {
+  to {
+    -webkit-transform: rotate(405deg);
+    transform: rotate(405deg);
+  }
+}
+
+@keyframes antSpinMove {
+  to {
+    opacity: 1;
+  }
+}
+
+@-webkit-keyframes antSpinMove {
+  to {
+    opacity: 1;
+  }
+}

+ 6 - 0
src/App.vue

@@ -0,0 +1,6 @@
+<template>
+  <router-view />
+</template>
+<style lang="less">
+  @import '~@/vab/styles/vab.less';
+</style>

+ 9 - 0
src/api/icon.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getIconList(params) {
+  return request({
+    url: '/icon/getList',
+    method: 'get',
+    params,
+  })
+}

+ 9 - 0
src/api/router.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getRouterList(params) {
+  return request({
+    url: '/menu/navigate',
+    method: 'get',
+    params,
+  })
+}

+ 25 - 0
src/api/table.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+  return request({
+    url: '/table/getList',
+    method: 'get',
+    params,
+  })
+}
+
+export function doEdit(data) {
+  return request({
+    url: '/table/doEdit',
+    method: 'post',
+    data,
+  })
+}
+
+export function doDelete(data) {
+  return request({
+    url: '/table/doDelete',
+    method: 'post',
+    data,
+  })
+}

+ 43 - 0
src/api/user.js

@@ -0,0 +1,43 @@
+import request from '@/utils/request'
+import { tokenName } from '@/config'
+
+export async function login(data) {
+  return request({
+    url: '/login',
+    method: 'post',
+    data,
+  })
+}
+
+export async function socialLogin(data) {
+  return request({
+    url: '/socialLogin',
+    method: 'post',
+    data,
+  })
+}
+
+export function getUserInfo(accessToken) {
+  //此处为了兼容mock.js使用data传递accessToken,如果使用mock可以走headers
+  return request({
+    url: '/userInfo',
+    method: 'post',
+    data: {
+      [tokenName]: accessToken,
+    },
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/logout',
+    method: 'post',
+  })
+}
+
+export function register() {
+  return request({
+    url: '/register',
+    method: 'post',
+  })
+}

+ 107 - 0
src/assets/css/global.scss

@@ -0,0 +1,107 @@
+// @import './element-variables.scss';
+// @import './variables.scss';
+// @import './mixin.scss';
+
+#nprogress .bar {
+    // background: $--color-primary !important;
+}
+
+.flex-wrap-wrap {
+    flex-wrap: wrap;
+}
+
+a {
+    color: #1890ff;
+    text-decoration: none;
+    background-color: transparent;
+    outline: none;
+    cursor: pointer;
+    transition: color 0.3s;
+}
+a:active,
+a:hover {
+    text-decoration: none;
+    outline: 0;
+}
+a:active {
+    color: #096dd9;
+}
+a:hover {
+    color: #40a9ff;
+}
+
+.border-solid-transparent {
+    border: solid 1px transparent;
+}
+
+.text-align-right {
+    text-align: right;
+}
+
+.float-right {
+    float: right;
+}
+
+.padding-t10 {
+    padding-top: 10px;
+}
+
+.cursor-pointer {
+    cursor: pointer;
+}
+
+//公共tabs样式
+// .el-tabs__header .el-tabs__item.is-active {
+//     border-bottom: 2px solid #409eff;
+//     color: #409eff;
+// }
+.el-tabs__header .el-tabs__item.is-active:hover {
+    color: #409eff !important;
+}
+.el-tabs__header:hover,
+.el-tabs__item:hover {
+    color: #409eff !important;
+}
+
+//公共input样式
+.el-input__icon {
+    color: #409eff;
+}
+.el-input__inner:hover {
+    border-color: #409eff;
+}
+.el-input__inner:focus {
+    border-color: #409eff;
+}
+
+//公共单选样式
+.el-radio__input.is-checked .el-radio__inner {
+    border-color: #409eff;
+    background: #409eff;
+}
+.el-radio__input.is-checked + .el-radio__label {
+    color: #409eff;
+}
+
+//公共复选样式
+.el-checkbox__input.is-checked .el-checkbox__inner {
+    background-color: #409eff;
+    border-color: #409eff;
+}
+.el-checkbox__input.is-checked + .el-checkbox__label {
+    color: #409eff;
+}
+
+.el-pagination .btn-prev .el-icon,
+.el-pagination .btn-next .el-icon {
+    padding-left: 10px;
+}
+
+.el-table--border th:first-child .cell,
+.el-table--border td:first-child .cell {
+    text-align: center;
+}
+
+.el-table .cell {
+    text-align: center;
+}

+ 721 - 0
src/assets/css/index.scss

@@ -0,0 +1,721 @@
+// @import './variables.scss';
+// @import './mixin.scss';
+// @import './transition.scss';
+// @import './element-variables.scss';
+// @import './sidebar.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;
+}
+
+a:focus,
+a:active {
+    outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+    cursor: pointer;
+    color: inherit;
+    text-decoration: none;
+}
+
+div:focus {
+    outline: none;
+}
+
+.clearfix {
+    &:after {
+        visibility: hidden;
+        display: block;
+        font-size: 0;
+        content: " ";
+        clear: both;
+        height: 0;
+    }
+}
+
+ul li {
+    padding: 0;
+    margin: 0;
+    list-style: none
+}
+
+.inOneLine {
+    display: inline-block;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+// main-container global css
+.mb-5 {
+    margin-bottom: 5px
+}
+
+.mb-10 {
+    margin-bottom: 10px
+}
+
+.mb-20 {
+    margin-bottom: 20px
+}
+
+.mr-30 {
+    margin-right: 30px
+}
+
+.ml-30 {
+    margin-left: 30px
+}
+
+.mt-20 {
+    margin-top: 20px
+}
+
+.mt-40 {
+    margin-top: 40px
+}
+
+.mt-60 {
+    margin-top: 60px
+}
+
+.font-16 {
+    font-size: 16px
+}
+
+.padding-20 {
+    padding: 20px
+}
+
+.text-center {
+    text-align: center
+}
+
+.delete-text {
+    color: #F80000!important
+}
+
+.remarksTxt {
+    opacity: .45;
+    line-height: 1.5;
+}
+
+.app-container {
+    padding: 20px;
+    // width: 100%;
+    width: calc(100%);
+    height: 100%;
+    // margin: 20px;
+    // margin-top: 70px;
+    background: #fff;
+    min-height: calc(100vh - 130px)
+}
+
+.filter-container {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    -webkit-box-pack: justify;
+    -webkit-justify-content: space-between;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+    vertical-align: middle;
+    .el-button+.el-button {
+        margin-left: 30px!important;
+    }
+    .filter-item {
+        margin-right: 30px;
+        display: inline-block;
+    }
+}
+
+.el-input__inner {
+    height: 36px;
+    line-height: 36px
+}
+
+.el-button {
+    padding: 10px 12px;
+}
+
+.el-table--small {
+    font-size: 14px!important
+}
+
+.el-table td,
+.el-table th {
+    padding: 10px 0
+}
+
+// 弹框样式start
+.el-dialog__header {
+    background: #f8f8f8;
+    padding: 16px 20px 16px;
+}
+
+.el-form-item:not(.user-layout .el-form-item) {
+    width: 90%;
+    max-width: 400px;
+    margin: 0 auto 20px;
+}
+
+// 弹框样式end
+// 台区列表
+.siteTitle {
+    font-size: 16px;
+    padding: 10px 20px 30px 20px;
+    text-align: center;
+    position: relative;
+    .goBack {
+        position: absolute;
+        left: 0;
+        top: 0
+    }
+}
+
+.status.el-avatar {
+    width: 14px;
+    height: 14px;
+    background: #04F21C
+}
+
+// 基本信息
+.basicInfo {
+    width: 100%;
+    height: calc(100vh - 180px);
+    // border: 1px solid pink;
+    display: block;
+    overflow-y: auto;
+}
+
+.siteManage-main {
+    padding: 20px;
+}
+
+.groupInfo,
+.basic-info-page,
+.powerScore {
+    .el-form-item {
+        margin-left: 0px!important
+    }
+}
+
+.goArchive {
+    color: #056FFF;
+    text-decoration: underline;
+}
+
+.blockTitle {
+    font-weight: bold
+}
+
+// input长度
+.el-form-item__content {
+    width: 250px;
+}
+
+.el-date-editor.el-input,
+.el-date-editor.el-input__inner {
+    width: 390px;
+}
+
+.el-select {
+    width: 100%
+}
+
+// 单选框样式
+.el-radio {
+    margin-right: 24px
+}
+
+//提交:
+.sublitArea {
+    text-align: right;
+    margin-top: 40px
+}
+
+// 图片上传样式 start
+.el-upload.el-upload--picture-card {
+    width: 90px;
+    height: 90px;
+    line-height: 100px;
+}
+
+.el-upload-list--picture-card .el-upload-list__item {
+    width: 92px!important;
+    height: 92px!important;
+    line-height: 92px!important;
+    text-align: center
+}
+
+.el-upload-list--picture-card .el-upload-list__item-thumbnail {
+    width: 90px!important;
+    height: 90px!important;
+    line-height: 90px!important;
+}
+
+.avatar {
+    width: 90px;
+    height: 90px;
+}
+
+// 电力监测
+.watchDog,
+.variableList {
+    .el-form-item__content {
+        width: 270px
+    }
+    .el-form-item__label {
+        width: 150px!important
+    }
+    .el-form-item__content {
+        // margin-left: 150px!important
+    }
+}
+
+.paginationBlock {
+    margin-top: 20px;
+    text-align: right
+}
+
+.filter-container {
+    .el-button+.el-button {
+        margin-left: 20px !important;
+    }
+    .el-input {
+        margin: 0 20px 0 0;
+    }
+}
+
+// 树形控件icon
+.el-tree-node__content {
+    position: relative
+}
+
+.siteTree .el-icon-delete {
+    color: #409EFF;
+    position: absolute;
+    right: 6px;
+    top: 5px;
+}
+
+//告警详情弹框组件
+.alarmStatusDialog {
+    .el-form-item:not(.user-layout .el-form-item) {
+        margin-bottom: 0
+    }
+    .deviceTit {
+        font-size: 16px;
+        color: #409EFF;
+        padding: 20px 0
+    }
+    .basicTit {
+        color: #4074e7;
+        line-height: 49px;
+        height: 49px;
+    }
+    .basicTit:before {
+        content: "";
+        width: 3px;
+        margin-right: 9px;
+        height: 16px;
+        position: relative;
+        top: 3px;
+        display: inline-block;
+        background: #4074e7;
+    }
+    .topInfo {
+        position: relative;
+        .lubo {
+            position: absolute;
+            right: 0px;
+            bottom: 20px;
+        }
+        .handleStatus {
+            position: absolute;
+            right: 0px;
+            top: 0px;
+            color: #F80000
+        }
+    }
+}
+
+.underline {
+    position: relative;
+}
+
+.underline:after {
+    position: absolute;
+    bottom: 0;
+    left: -20px;
+    right: -20px;
+    height: 1px;
+    content: '';
+    -webkit-transform: scaleY(.5);
+    transform: scaleY(.5);
+    background-color: #000; //这个是唯佳的线颜色
+    opacity: .2
+}
+
+.underline:last-child:after {
+    //可以这样用
+    height: 0;
+}
+
+// 谐波分析
+.harmonicReport {
+    .filter-container .filter-item {
+        // margin-right: 10px
+    }
+}
+
+.timeTab.el-button {
+    margin-bottom: 20px;
+    border-radius: 0
+}
+
+// 三项不平衡
+.blanceChartTit {
+    padding: 10px 14px;
+    margin-bottom: 10px;
+    border-bottom: 1px solid #f0f0f0;
+    background: #FAFAFA;
+    font-weight: bold
+}
+
+//评估报告
+.assePage .blanceChartTit {
+    margin-bottom: 0;
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    vertical-align: middle;
+    span {
+        display: inline-block
+    }
+}
+
+.assePage {
+    .subTits {
+        margin: 25px auto;
+        text-align: center;
+        font-weight: bold
+    }
+    .assNum {
+        font-size: 18px;
+        color: #2EAEFF;
+        margin-bottom: 10px;
+    }
+    .greenRate {
+        color: #04A522
+    }
+    .assTxt {
+        font-size: 14px
+    }
+    .assSmallbox {
+        padding: 10px 0;
+        text-align: center;
+        font-weight: bold;
+    }
+}
+
+// tab重置样式
+.asseTabs {
+    margin-bottom: 20px;
+    border-bottom: 1px solid #E5E5E5;
+    width: calc(100% + 40px);
+    margin-left: -20px;
+}
+
+.asseTabs span {
+    line-height: 50px;
+    height: 50px;
+    font-size: 16px;
+    display: inline-block;
+    padding: 0 20px;
+}
+
+.asseTabs span.active {
+    border-bottom: 2px solid #2EAEFF
+}
+
+.banlanceBtn {
+    max-width: 80%;
+    margin: 0 auto 20px;
+    height: 40px;
+    line-height: 40px;
+    width: 236px;
+    font-size: 16px!important;
+    // background: #6dc6ff;
+    // color: #fff
+}
+
+.assCard {
+    min-height: 336px!important;
+    .noDataImg {
+        width: 40%;
+        margin-top: 40px;
+    }
+}
+
+.assCard ul {
+    text-align: left;
+    margin: 0;
+    padding: 15px 20px 0;
+    li:not(:last-child) {
+        border-bottom: 1px solid #F0F0F0;
+    }
+    li {
+        line-height: 40px;
+        display: flex;
+        justify-content: space-between;
+        vertical-align: middle;
+        font-size: 14px;
+        div {
+            display: inline-block;
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+        span {
+            color: #04A522;
+            background: #F4F4F4;
+            display: inline-block;
+            border-radius: 20px;
+            line-height: 20px;
+            height: 20px;
+            text-align: center;
+            width: 58px;
+            margin-top: 10px;
+        }
+        span.overLimit {
+            color: #F80000
+        }
+    }
+}
+
+.totalScore {
+    font-weight: bold;
+    text-align: center;
+    margin: 30px;
+    .el-button {
+        font-size: 16px;
+        margin-left: 10px;
+    }
+}
+
+// 实时评分 
+.descIcon img {
+    position: relative;
+    top: 2px;
+}
+
+.smallSquare {
+    display: inline-block;
+    width: 7px;
+    position: relative;
+    top: -1px;
+    height: 7px;
+    background: #F80000;
+}
+
+.smallSquare.green {
+    background: #24BE00
+}
+
+.loopUnbanlancePanel,
+.loopHarmonicPanel {
+    height: 591px;
+    overflow: hidden;
+    .el-row {
+        margin-bottom: 0!important;
+    }
+}
+
+.loopUnbanlanceCard {
+    // height: calc(100% - 100px);
+    ul {
+        padding: 0;
+        margin-bottom: 0;
+        font-size: 14px;
+    }
+    li {
+        display: flex;
+        >div {
+            margin: 7px 20px;
+        }
+        >div:first-child {
+            // min-width: 64px;
+        }
+    }
+}
+
+.voltagePanel {
+    .el-table--small th,
+    .el-table--small td {
+        padding: 15px 0
+    }
+    .uList p {
+        margin-right: 10px;
+        padding: 8px 0
+    }
+    .shangXian {
+        padding: 20px 0 0;
+        display: flex;
+        width: 300px;
+        margin-left: 40px;
+        text-align: center;
+        div {
+            width: 50%;
+            text-align: center;
+            position: relative
+        }
+        div:first-child:after {
+            position: absolute;
+            top: 0;
+            z-index: 4;
+            /* left: -20px; */
+            right: 20px;
+            height: 211px;
+            width: 1px;
+            border: 1px dashed #000;
+            content: "";
+            /* transform: scaleY(0.5); */
+            background-color: rgba(0, 0, 0, 0);
+            opacity: .2;
+        }
+        div:last-child:before {
+            position: absolute;
+            top: 0;
+            z-index: 4;
+            left: 20px;
+            height: 211px;
+            width: 1px;
+            border: 1px dashed #000;
+            content: "";
+            /* transform: scaleY(.2); */
+            background-color: rgba(0, 0, 0, 0);
+            opacity: .2;
+        }
+    }
+}
+
+.frequencyPanel {
+    text-align: center;
+    .frequencyTit {
+        color: #F80000;
+        font-weight: bold
+    }
+    .frequencyTit2 {
+        font-weight: bold;
+        margin: 10px auto;
+        span {
+            color: #fff;
+            background: #21c393;
+            display: inline-block;
+            border-radius: 20px;
+            line-height: 24px;
+            height: 24px;
+            text-align: center;
+            font-size: 14px;
+            width: 58px;
+        }
+    }
+    .frequencyBox .grid-content {
+        min-height: 50px!important;
+        border-radius: 0;
+        background: #f0f0f0;
+        border: none;
+    }
+    .rightSplitRed {
+        position: relative;
+        i {
+            position: absolute;
+            position: absolute;
+            right: -14.5px;
+            bottom: -11px;
+            color: #f1673d
+        }
+        i:after {
+            display: none
+        }
+    }
+    .greenShadow {
+        position: absolute;
+        width: 118px;
+        height: 100%;
+        bottom: 0;
+        background: rgba(37, 215, 162, .3);
+        left: 41px;
+        background-image: -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.25, hsla(0, 0%, 100%, .2)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, hsla(0, 0%, 100%, .2)), color-stop(.75, hsla(0, 0%, 100%, .2)), color-stop(.75, transparent), to(transparent));
+        background-image: -moz-gradient(linear, 0 0, 100% 100%, color-stop(.25, hsla(0, 0%, 100%, .2)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, hsla(0, 0%, 100%, .2)), color-stop(.75, hsla(0, 0%, 100%, .2)), color-stop(.75, transparent), to(transparent));
+        background-image: -ms-gradient(linear, 0 0, 100% 100%, color-stop(.25, hsla(0, 0%, 100%, .2)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, hsla(0, 0%, 100%, .2)), color-stop(.75, hsla(0, 0%, 100%, .2)), color-stop(.75, transparent), to(transparent));
+        background-image: -o-gradient(linear, 0 0, 100% 100%, color-stop(.25, hsla(0, 0%, 100%, .2)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, hsla(0, 0%, 100%, .2)), color-stop(.75, hsla(0, 0%, 100%, .2)), color-stop(.75, transparent), to(transparent));
+        background-image: gradient(linear, 0 0, 100% 100%, color-stop(.25, hsla(0, 0%, 100%, .2)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, hsla(0, 0%, 100%, .2)), color-stop(.75, hsla(0, 0%, 100%, .2)), color-stop(.75, transparent), to(transparent));
+        background-size: 8px 8px
+    }
+    .rightSplitRed .grid-content:after {
+        position: absolute;
+        bottom: -3px;
+        z-index: 4;
+        right: -8px;
+        height: 125%;
+        width: 2px;
+        border: 1px solid #f1673d;
+        content: "";
+        background-color: rgba(0, 0, 0, 0);
+    }
+    .frequencyBox .grid-content {
+        border-right: 1px dashed #aaa
+    }
+    .frequencyBox .el-col:last-child .grid-content {
+        border-right: none
+    }
+}
+
+.voltagePanel,
+.frequencyPanel,
+.powerPanel {
+    height: 285px
+}
+
+.powerPanel {
+    .el-table--small th,
+    .el-table--small td {
+        padding: 15px 0
+    }
+    .uList p {
+        margin-right: 10px;
+        padding: 8px 0
+    }
+}
+
+.harmonicCard {
+    height: calc(50% - 56px);
+    // border: 1px solid red;
+}

TEMPAT SAMPAH
src/assets/error_images/403.png


TEMPAT SAMPAH
src/assets/error_images/404.png


TEMPAT SAMPAH
src/assets/error_images/cloud.png


TEMPAT SAMPAH
src/assets/images/bg-smooth.jpg


TEMPAT SAMPAH
src/assets/images/descIcon.png


TEMPAT SAMPAH
src/assets/images/logo.png


TEMPAT SAMPAH
src/assets/images/logo1.png


TEMPAT SAMPAH
src/assets/images/logo_admin.png


TEMPAT SAMPAH
src/assets/images/noDataImg.png


TEMPAT SAMPAH
src/assets/login_images/login_background.png


TEMPAT SAMPAH
src/assets/login_images/login_form.png


TEMPAT SAMPAH
src/assets/logo.png


TEMPAT SAMPAH
src/assets/logo1.png


TEMPAT SAMPAH
src/assets/logo_admin.png


+ 43 - 0
src/components/SvgIcon.vue

@@ -0,0 +1,43 @@
+<template>
+  <svg :class="svgClass" aria-hidden="true">
+    <use :xlink:href="iconName"></use>
+  </svg>
+</template>
+
+<script>
+export default {
+  name: 'svg-icon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String
+    }
+  },
+  computed: {
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  /* vertical-align: -0.15em; */
+  fill: currentColor;
+  overflow: hidden;
+  margin-right: 8px;
+}
+</style>

+ 9 - 0
src/config/config.js

@@ -0,0 +1,9 @@
+/**
+ * @description 导出自定义配置
+ **/
+const config = {
+  layout: 'vertical',
+  donation: false,
+  templateFolder: 'project',
+}
+module.exports = config

+ 8 - 0
src/config/default/index.js

@@ -0,0 +1,8 @@
+/**
+ * @description 导出默认配置(通用配置|主题配置|网络配置)
+ **/
+const setting = require('./setting.config')
+const theme = require('./theme.config')
+const network = require('./net.config')
+
+module.exports = { setting, theme, network }

+ 14 - 0
src/config/default/net.config.js

@@ -0,0 +1,14 @@
+/**
+ * @description 导出默认网路配置
+ **/
+const network = {
+  //配后端数据的接收方式application/json;charset=UTF-8 或 application/x-www-form-urlencoded;charset=UTF-8
+  contentType: 'application/json;charset=UTF-8',
+  //消息框消失时间
+  messageDuration: 3000,
+  //最长请求时间
+  requestTimeout: 10000,
+  //操作正常code,支持String、Array、int多种类型
+  successCode: [200, 0],
+}
+module.exports = network

+ 79 - 0
src/config/default/setting.config.js

@@ -0,0 +1,79 @@
+/**
+ * @description 导出默认通用配置
+ */
+const setting = {
+  //开发以及部署时的URL,hash模式时在不确定二级目录名称的情况下建议使用""代表相对路径或者"/二级目录/",history模式默认使用"/"或者"/二级目录/"
+  publicPath: '',
+  //生产环境构建文件的目录名
+  outputDir: 'dist',
+  //放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
+  assetsDir: 'static',
+  //开发环境每次保存时是否输出为eslint编译警告
+  lintOnSave: true,
+  //进行编译的依赖
+  transpileDependencies: ['vue-echarts', 'resize-detector'],
+  //默认的接口地址 如果是开发环境和生产环境走vab-mock-server,当然你也可以选择自己配置成需要的接口地址
+  baseURL:
+    process.env.NODE_ENV === 'development' ? 'mock-server' : 'mock-server',
+  //标题 (包括初次加载雪花屏的标题 页面的标题 浏览器的标题)
+  // title: 'vue-admin-beautiful-antdv',
+  //标题分隔符
+  titleSeparator: ' - ',
+  //标题是否反转 如果为false:"page - title",如果为ture:"title - page"
+  titleReverse: false,
+  //简写
+  abbreviation: 'vab-pro',
+  //开发环境端口号
+  devPort: '9999',
+  //版本号
+  version: process.env.VUE_APP_VERSION,
+  //pro版本copyright可随意修改
+  copyright: '1813914505@qq.com',
+  //缓存路由的最大数量
+  keepAliveMaxNum: 99,
+  //路由模式,可选值为 history 或 hash
+  routerMode: 'hash',
+  //不经过token校验的路由
+  routesWhiteList: ['/login', '/register', '/callback', '/404', '/403'],
+  //加载时显示文字
+  loadingText: '正在加载中...',
+  //token名称
+  tokenName: 'accessToken',
+  //token在localStorage、sessionStorage、cookie存储的key的名称
+  tokenTableName: 'accessToken',
+  //token存储位置localStorage sessionStorage cookie
+  storage: 'localStorage',
+  //token失效回退到登录页时是否记录本次的路由
+  recordRoute: true,
+  //是否显示logo,不显示时设置false,显示时请填写remixIcon图标名称,暂时只支持设置remixIcon
+  // logo: 'vuejs-fill',
+  //语言类型zh、en
+  i18n: 'zh',
+  //在哪些环境下显示高亮错误
+  errorLog: ['development', 'production'],
+  //是否开启登录拦截
+  loginInterception: true,
+  //是否开启登录RSA加密
+  loginRSA: false,
+  //intelligence(前端导出路由)和all(后端导出路由)两种方式
+  authentication: 'intelligence',
+  //是否开启roles字段进行角色权限控制(如果是all模式后端完全处理角色并进行json组装,可设置false不处理路由中的roles字段)
+  rolesControl: true,
+  //vertical gallery comprehensive common布局时是否只保持一个子菜单的展开
+  uniqueOpened: false,
+  //vertical布局时默认展开的菜单path,使用逗号隔开建议只展开一个
+  defaultOpeneds: ['/vab'],
+  //需要加loading层的请求,防止重复提交
+  debounce: ['doEdit'],
+  //需要自动注入并加载的模块
+  providePlugin: {},
+  //npm run build时是否自动生成7z压缩包
+  build7z: false,
+  //代码生成机生成在view下的文件夹名称
+  templateFolder: 'project',
+  //是否显示终端donation打印
+  donation: false,
+  //画廊布局和综合布局时,是否点击一级菜单默认开启第一个二级菜单
+  openFirstMenu: true,
+}
+module.exports = setting

+ 28 - 0
src/config/default/theme.config.js

@@ -0,0 +1,28 @@
+/**
+ * @description 导出默认主题配置
+ */
+const theme = {
+  //布局种类 horizontal vertical gallery comprehensive common
+  layout: 'horizontal',
+  //主题名称 default ocean green glory white
+  themeName: 'default',
+  //是否固定头部
+  fixedHeader: true,
+  //是否显示顶部进度条
+  showProgressBar: true,
+  //是否显示多标签页
+  showTabsBar: true,
+  //是否显示语言选择组件
+  showLanguage: true,
+  //是否显示刷新组件
+  showRefresh: true,
+  //是否显示搜索组件
+  showSearch: true,
+  //是否显示主题组件
+  showTheme: true,
+  //是否显示通知组件
+  showNotice: true,
+  //是否显示全屏组件
+  showFullScreen: true,
+}
+module.exports = theme

+ 9 - 0
src/config/index.js

@@ -0,0 +1,9 @@
+/**
+ * @description 3个子配置,通用配置|主题配置|网络配置,建议在当前目录下修改config.js修改配置,会覆盖默认配置,也可以直接修改默认配置
+ */
+//默认配置
+const { setting, theme, network } = require('./default')
+//自定义配置
+const config = require('./config')
+//导出配置(以自定义配置为主)
+module.exports = Object.assign({}, setting, theme, network, config)

+ 4 - 0
src/icons/index.js

@@ -0,0 +1,4 @@
+//自动引入 @/src/icons
+const requireAll = requireContext => requireContext.keys().map(requireContext);
+const req = require.context('./svgIcon', false, /\.svg$/);
+requireAll(req);

+ 7 - 0
src/icons/svgIcon/alarmManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="16px">
+<path fill-rule="evenodd" 
+ d="M15.467,7.724 L13.867,7.724 C13.572,7.724 13.333,7.477 13.333,7.172 C13.333,6.868 13.572,6.621 13.867,6.621 L15.467,6.621 C15.761,6.621 16.000,6.868 16.000,7.172 C16.000,7.477 15.761,7.724 15.467,7.724 ZM13.067,3.862 C12.625,3.862 12.267,3.491 12.267,3.034 C12.267,2.577 12.625,2.207 13.067,2.207 C13.508,2.207 13.867,2.577 13.867,3.034 C13.867,3.491 13.508,3.862 13.067,3.862 ZM13.074,12.690 L13.333,12.690 C14.217,12.690 14.933,13.431 14.933,14.345 C14.933,15.259 14.217,16.000 13.333,16.000 L2.667,16.000 C1.783,16.000 1.067,15.259 1.067,14.345 C1.067,13.431 1.783,12.690 2.667,12.690 L2.941,12.690 L2.941,8.276 C2.941,5.381 5.209,3.034 8.007,3.034 C10.806,3.034 13.074,5.381 13.074,8.276 L13.074,12.690 ZM2.133,14.345 C2.133,14.650 2.372,14.896 2.667,14.896 L13.333,14.896 C13.628,14.896 13.867,14.650 13.867,14.345 C13.867,14.040 13.628,13.793 13.333,13.793 L2.667,13.793 C2.372,13.793 2.133,14.040 2.133,14.345 ZM8.007,4.138 C5.798,4.138 4.007,5.991 4.007,8.276 L4.007,12.690 L7.467,12.690 L7.467,10.393 C6.697,10.154 6.133,9.425 6.133,8.552 C6.133,7.485 6.969,6.621 8.000,6.621 C9.031,6.621 9.867,7.485 9.867,8.552 C9.867,9.425 9.303,10.154 8.533,10.393 L8.533,12.690 L12.007,12.690 L12.007,8.276 C12.007,5.991 10.217,4.138 8.007,4.138 ZM8.000,9.379 C8.442,9.379 8.800,9.009 8.800,8.552 C8.800,8.095 8.442,7.724 8.000,7.724 C7.558,7.724 7.200,8.095 7.200,8.552 C7.200,9.009 7.558,9.379 8.000,9.379 ZM8.000,2.759 C7.705,2.759 7.467,2.512 7.467,2.207 L7.467,0.552 C7.467,0.247 7.705,-0.000 8.000,-0.000 C8.294,-0.000 8.533,0.247 8.533,0.552 L8.533,2.207 C8.533,2.512 8.294,2.759 8.000,2.759 ZM2.933,3.862 C2.491,3.862 2.133,3.491 2.133,3.034 C2.133,2.577 2.491,2.207 2.933,2.207 C3.375,2.207 3.733,2.577 3.733,3.034 C3.733,3.491 3.375,3.862 2.933,3.862 ZM2.667,7.172 C2.667,7.477 2.428,7.724 2.133,7.724 L0.533,7.724 C0.239,7.724 -0.000,7.477 -0.000,7.172 C-0.000,6.868 0.239,6.621 0.533,6.621 L2.133,6.621 C2.428,6.621 2.667,6.868 2.667,7.172 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/arrow-down.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M894.771 261.769L512 644.539 129.229 261.77H11.537L512 762.23l500.463-500.462z"/></svg>

+ 1 - 0
src/icons/svgIcon/arrow-left.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M762.231 894.771L379.461 512l382.77-382.771V11.537L261.77 512l500.462 500.463z"/></svg>

+ 1 - 0
src/icons/svgIcon/arrow-left2.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M603.144 49.243L48.15 483.723c-12.743 8.252-19.54 23.908-15.656 39.442 2.306 9.345 8.01 16.991 15.534 21.724L603.144 979.49c6.31 4.976 15.655.486 15.655-7.646v-63.108c0-5.947-2.79-11.651-7.403-15.292L181.53 557.026c-3.641-2.792-1.578-8.617 3.034-8.617h798.325c5.34 0 9.71-4.37 9.71-9.71v-48.544c0-5.34-4.37-9.71-9.71-9.71H184.563c-4.612 0-6.675-5.825-3.034-8.616l429.867-336.54c4.733-3.64 7.403-9.345 7.403-15.291v-63.11c0-8.01-9.345-12.62-15.655-7.645z"/></svg>

+ 1 - 0
src/icons/svgIcon/arrow-right.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M261.769 129.229L644.539 512 261.77 894.771v117.692L762.23 512 261.77 11.537z"/></svg>

+ 1 - 0
src/icons/svgIcon/arrow-right2.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M420.856 49.243l554.993 434.48c12.743 8.252 19.54 23.908 15.656 39.442-2.306 9.345-8.01 16.991-15.534 21.724L420.856 979.611c-6.31 4.976-15.655.486-15.655-7.645v-63.11c0-5.946 2.79-11.65 7.403-15.29l429.867-336.54c3.641-2.792 1.578-8.617-3.034-8.617H41.112c-5.34 0-9.71-4.37-9.71-9.71v-48.544c0-5.34 4.37-9.71 9.71-9.71h798.325c4.612 0 6.675-5.825 3.034-8.616l-429.746-336.54c-4.733-3.64-7.403-9.345-7.403-15.291v-63.11c-.121-8.01 9.224-12.62 15.534-7.645z"/></svg>

+ 1 - 0
src/icons/svgIcon/chart.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M978.034 1016.87H45.966A38.836 38.836 0 017.13 978.034V45.966a38.836 38.836 0 0177.672 0v893.232h893.232a38.836 38.836 0 010 77.672z"/><path d="M317.82 978.034a38.836 38.836 0 01-38.837-38.836V550.836a38.836 38.836 0 0177.672 0v388.362a38.836 38.836 0 01-38.836 38.836zm271.852 0a38.836 38.836 0 01-38.836-38.836v-504.87a38.836 38.836 0 0177.672 0v504.87a38.836 38.836 0 01-38.836 38.836zm271.853 0a38.836 38.836 0 01-38.836-38.836V356.655a38.836 38.836 0 0177.672 0v582.543a38.836 38.836 0 01-38.836 38.836zM201.311 395.492a39.613 39.613 0 01-31.07-15.535 38.836 38.836 0 017.768-54.37L488.7 92.57a38.06 38.06 0 0150.486 0l132.043 131.266L954.732 14.897a38.836 38.836 0 1146.603 62.138L690.646 310.052a38.06 38.06 0 01-50.487-3.884L512 174.902 224.613 387.724a38.06 38.06 0 01-23.302 7.768z"/></svg>

+ 1 - 0
src/icons/svgIcon/close.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M577.691 513.767l399.45-399.45c18.411-18.41 18.411-48.31 0-66.721s-48.311-18.412-66.722 0l-399.45 399.597-399.45-399.597c-18.41-18.412-48.31-18.412-66.722 0s-18.411 48.31 0 66.722l399.597 399.597-399.597 399.45c-18.411 18.41-18.411 48.31 0 66.722s48.311 18.41 66.722 0L511.116 580.49l399.597 399.597c18.411 18.41 48.311 18.41 66.722 0s18.412-48.311 0-66.723L577.691 513.767z"/></svg>

+ 1 - 0
src/icons/svgIcon/close2.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1025 1024" xmlns="http://www.w3.org/2000/svg" width="200.195" height="200"><defs><style/></defs><path d="M874.02 874.02c-199.931 199.974-524.106 199.974-724.037 0-199.975-199.933-199.975-524.107 0-724.04 199.931-199.974 524.106-199.974 724.038 0 199.974 199.933 199.974 524.107 0 724.04zm-60.329-663.71c-166.61-166.61-436.77-166.61-603.379 0-166.61 166.61-166.61 436.77 0 603.38s436.77 166.61 603.38 0 166.61-436.77 0-603.38zm-86.74 509.088l-7.55 7.552a37.29 37.29 0 01-52.778 0L512.002 572.33 361.136 723.195a42.666 42.666 0 01-60.33-60.372L451.672 512l-154.62-154.62a37.29 37.29 0 010-52.778l7.551-7.552a37.29 37.29 0 0152.778 0l154.62 154.62 150.867-150.866a42.666 42.666 0 0160.33 60.33L572.33 512l154.62 154.62a37.29 37.29 0 010 52.778z"/></svg>

File diff ditekan karena terlalu besar
+ 0 - 0
src/icons/svgIcon/components.svg


+ 1 - 0
src/icons/svgIcon/control.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1055 1024" xmlns="http://www.w3.org/2000/svg" width="206.055" height="200"><defs><style/></defs><path d="M93.09 0h868.85a93.09 93.09 0 0193.09 93.09v620.607a93.09 93.09 0 01-93.09 93.09H93.09A93.09 93.09 0 010 713.698V93.091A93.09 93.09 0 0193.09 0zm0 62.06a31.03 31.03 0 00-31.03 31.03v620.607a31.03 31.03 0 0031.03 31.03h868.85a31.03 31.03 0 0031.03-31.03V93.091a31.03 31.03 0 00-31.03-31.03H93.09z"/><path d="M217.212 279.273h620.606q31.03 0 31.03 31.03t-31.03 31.03H217.212q-31.03 0-31.03-31.03t31.03-31.03zm0 217.212h620.606q31.03 0 31.03 31.03t-31.03 31.03H217.212q-31.03 0-31.03-31.03t31.03-31.03zm124.121 341.333h372.364q31.03 0 31.03 31.03t-31.03 31.03H341.333q-31.03 0-31.03-31.03t31.03-31.03zM155.151 961.94H899.88q31.03 0 31.03 31.03T899.88 1024H155.152q-31.03 0-31.03-31.03t31.03-31.03z"/><path d="M310.303 372.364V248.242q0-31.03 31.03-31.03t31.03 31.03v124.122q0 31.03-31.03 31.03t-31.03-31.03zm372.364 217.212V465.455q0-31.03 31.03-31.03t31.03 31.03v124.12q0 31.031-31.03 31.031t-31.03-31.03z"/></svg>

+ 7 - 0
src/icons/svgIcon/dataManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="16px">
+<path fill-rule="evenodd"
+ d="M7.687,0.978 L7.687,8.312 L15.022,8.312 L15.022,8.489 C15.022,12.596 11.618,16.000 7.511,16.000 C3.404,16.000 -0.000,12.596 -0.000,8.489 C-0.000,4.442 3.306,1.077 7.333,0.980 L7.511,0.978 L7.687,0.978 L7.687,0.978 ZM6.356,2.442 L6.239,2.465 C3.421,3.074 1.330,5.589 1.330,8.489 C1.330,11.912 4.087,14.668 7.511,14.668 C10.413,14.668 12.927,12.578 13.535,9.761 L13.559,9.644 L7.511,9.644 C6.858,9.644 6.400,9.215 6.360,8.581 L6.357,8.489 L6.356,2.442 ZM8.978,0.000 C12.829,0.000 15.905,3.016 15.999,6.842 L16.000,7.022 L16.000,7.199 L8.802,7.199 L8.802,0.001 L8.978,0.001 L8.978,0.000 ZM10.132,1.464 L10.132,5.867 L14.536,5.867 L14.513,5.752 C14.045,3.639 12.362,1.956 10.248,1.488 L10.132,1.464 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/detail.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M348.16 202.24V23.04l-256 217.6H307.2c20.48 0 40.96-17.92 40.96-38.4zm-58.88 2.56H166.4L312.32 94.72v89.6c-2.56 10.24-12.8 20.48-23.04 20.48zM729.6 604.16H291.84c-10.24 0-17.92 10.24-17.92 25.6v25.6c0 12.8 7.68 25.6 17.92 25.6H729.6c10.24 0 17.92-10.24 17.92-25.6v-25.6c0-15.36-7.68-25.6-17.92-25.6zM860.16 23.04h-499.2v202.24c0 17.92-17.92 38.4-35.84 38.4H94.72v704c0 17.92 17.92 38.4 35.84 38.4H857.6c17.92 0 35.84-23.04 35.84-40.96V56.32c0-17.92-15.36-33.28-33.28-33.28zm-5.12 906.24c0 17.92-15.36 38.4-33.28 38.4H161.28c-17.92 2.56-33.28-17.92-33.28-35.84v-614.4h209.92c15.36 0 69.12-56.32 69.12-71.68V61.44h417.28c15.36 0 28.16 12.8 28.16 30.72v837.12zM729.6 424.96H291.84c-10.24 0-17.92 10.24-17.92 23.04v23.04c0 12.8 7.68 23.04 17.92 23.04H729.6c10.24 0 17.92-10.24 17.92-23.04V448c0-12.8-7.68-23.04-17.92-23.04zm0 360.96H291.84c-10.24 0-17.92 10.24-17.92 23.04v25.6c0 12.8 7.68 25.6 17.92 25.6H729.6c10.24 0 17.92-10.24 17.92-25.6v-25.6c0-10.24-7.68-23.04-17.92-23.04z"/></svg>

+ 7 - 0
src/icons/svgIcon/deviceManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="13px">
+<path fill-rule="evenodd"
+ d="M14.698,13.000 L1.302,13.000 C0.583,13.000 -0.001,12.434 -0.001,11.736 L-0.001,8.486 C-0.001,7.788 0.583,7.222 1.302,7.222 L14.698,7.222 C15.417,7.222 16.000,7.788 16.000,8.486 L16.000,11.736 C16.000,12.434 15.417,13.000 14.698,13.000 ZM14.884,8.486 C14.884,8.386 14.801,8.306 14.698,8.306 L1.302,8.306 C1.199,8.306 1.116,8.386 1.116,8.486 L1.116,11.736 C1.116,11.836 1.199,11.917 1.302,11.917 L14.698,11.917 C14.801,11.917 14.884,11.836 14.884,11.736 L14.884,8.486 ZM13.209,10.653 C12.798,10.653 12.465,10.329 12.465,9.930 C12.465,9.532 12.798,9.208 13.209,9.208 C13.620,9.208 13.954,9.532 13.954,9.930 C13.954,10.329 13.620,10.653 13.209,10.653 ZM14.698,5.778 L1.302,5.778 C0.583,5.778 -0.001,5.212 -0.001,4.514 L-0.001,1.264 C-0.001,0.566 0.583,-0.000 1.302,-0.000 L14.698,-0.000 C15.417,-0.000 16.000,0.566 16.000,1.264 L16.000,4.514 C16.000,5.212 15.417,5.778 14.698,5.778 ZM14.884,1.264 C14.884,1.164 14.801,1.083 14.698,1.083 L1.302,1.083 C1.199,1.083 1.116,1.164 1.116,1.264 L1.116,4.514 C1.116,4.614 1.199,4.694 1.302,4.694 L14.698,4.694 C14.801,4.694 14.884,4.614 14.884,4.514 L14.884,1.264 ZM2.790,3.431 C2.379,3.431 2.046,3.107 2.046,2.708 C2.046,2.708 2.046,2.708 2.046,2.708 C2.046,2.309 2.379,1.986 2.791,1.986 C3.202,1.986 3.535,2.309 3.534,2.708 C3.534,2.708 3.534,2.709 3.534,2.709 C3.534,3.108 3.201,3.431 2.790,3.431 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/edit.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M983.67 457.627L850.219 324.174c-4.866-4.867-11.324-7.487-18.156-7.487s-13.289 2.62-18.155 7.487L465.114 672.967a25.904 25.904 0 00-6.551 11.137l-52.034 183.614c-2.527 8.891-.093 18.437 6.458 24.988 4.772 4.866 11.417 7.58 18.249 7.58 2.246 0 4.492-.28 6.644-.842l185.487-50.162c4.305-1.216 8.235-3.463 11.417-6.644l348.887-348.794c4.866-4.866 7.487-11.323 7.487-18.155 0-6.832-2.714-13.196-7.487-18.062zM506.573 734.453l66.446 66.445-92.37 24.988 25.924-91.433zm118.292 33.503l-84.976-84.975 292.174-292.268 84.976 84.976-292.174 292.267z"/><path d="M841.42 838.239c-16.564 0-29.946 13.383-29.946 29.947 0 35.282-28.638 63.92-63.92 63.92H92.738V91.987h459.037l179.871 180.995c11.698 11.698 30.603 11.791 42.394.093 11.699-11.698 11.792-30.602.094-42.394L576.668 32H32.842v960h714.713c68.224 0 123.813-55.496 123.813-123.814 0-16.564-13.382-29.947-29.947-29.947z"/><path d="M422.158 213.65H182.579c-16.565 0-29.947 13.382-29.947 29.947s13.382 29.947 29.947 29.947h239.579c16.565 0 29.947-13.383 29.947-29.947s-13.382-29.948-29.947-29.948zm0 179.684H182.579c-16.565 0-29.947 13.382-29.947 29.947s13.382 29.947 29.947 29.947h239.579c16.565 0 29.947-13.382 29.947-29.947s-13.382-29.947-29.947-29.947zm0 179.684H182.579c-16.565 0-29.947 13.382-29.947 29.947s13.382 29.947 29.947 29.947h239.579c16.565 0 29.947-13.382 29.947-29.947s-13.382-29.947-29.947-29.947z"/></svg>

+ 1 - 0
src/icons/svgIcon/editor.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M289.28 758.4a32.64 32.64 0 01-21.12-8.32L15.36 522.24a30.72 30.72 0 01-10.88-23.68 35.84 35.84 0 0110.88-23.68l256-222.72a32 32 0 1142.24 48L85.12 498.56 311.04 704a32 32 0 010 45.44 32 32 0 01-21.76 8.96zm442.24 0a32.64 32.64 0 01-23.68-10.88 32.64 32.64 0 010-45.44l225.92-203.52-223.36-198.4a32 32 0 010-45.44 31.36 31.36 0 0144.8 0l256 222.72a31.36 31.36 0 010 47.36L759.04 752.64a35.2 35.2 0 01-27.52 5.76zM441.6 866.56h-5.12A32.64 32.64 0 01410.24 832l112.64-686.72A32.64 32.64 0 01560 119.04a31.36 31.36 0 0126.24 36.48L473.6 840.32a32 32 0 01-32 26.24z"/></svg>

+ 1 - 0
src/icons/svgIcon/home.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M896 192v73.6l64 54.4V160c0-19.2-12.8-32-32-32H736l73.6 64H896zM544 64h-64L0 480v32c0 19.2 12.8 32 32 32h96v384c0 19.2 12.8 32 32 32h256c19.2 0 32-12.8 32-32V640h128v288c0 19.2 12.8 32 32 32h256c19.2 0 32-12.8 32-32V544h96c19.2 0 32-12.8 32-32v-32L544 64zm320 416c-19.2 0-32 12.8-32 32v384H640V608c0-19.2-12.8-32-32-32H416c-19.2 0-32 12.8-32 32v288H192V512c0-19.2-12.8-32-32-32h-57.6L512 128l409.6 352H864z"/></svg>

+ 1 - 0
src/icons/svgIcon/icon.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M512 258.276c-33.337 0-60.302 26.965-60.302 60.302S478.663 378.88 512 378.88s60.302-26.965 60.302-60.302-26.965-60.302-60.302-60.302zM402.546 427.349v72.59h73.045v280.235h72.932V427.35z"/><path d="M512 1.138C229.831 1.138 1.138 229.83 1.138 512S229.83 1022.862 512 1022.862 1022.862 794.17 1022.862 512 794.17 1.138 512 1.138zm0 948.906C270.108 950.044 73.956 753.892 73.956 512S270.108 73.956 512 73.956 950.044 270.108 950.044 512 753.892 950.044 512 950.044z"/></svg>

+ 1 - 0
src/icons/svgIcon/language-outline.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M985.316 985.316c-14.109 0-27.535-8.192-33.451-22.073l-53.02-123.563H634.88l-53.02 123.563c-7.965 18.432-29.355 27.079-47.787 19.114s-27.08-29.354-19.115-47.786l218.454-509.725c5.688-13.426 18.887-22.073 33.45-22.073s27.762 8.647 33.45 22.073l218.454 509.725c7.965 18.432-.682 39.822-19.114 47.786-4.78 2.048-9.558 2.959-14.336 2.959zm-319.26-218.454h201.613L766.862 531.57 666.055 766.862zM111.501 839.68c-12.515 0-24.576-6.372-31.402-17.977-10.24-17.294-4.552-39.595 12.743-49.835 1.365-.682 135.168-81.01 261.006-235.064 89.43-109.455 142.905-246.216 166.343-316.075H38.684c-20.024 0-36.408-16.384-36.408-36.409s16.384-36.409 36.408-36.409h291.272V75.093c0-20.025 16.384-36.409 36.408-36.409s36.41 16.384 36.41 36.41v72.817h291.27c20.025 0 36.41 16.384 36.41 36.409s-16.385 36.409-36.41 36.409h-97.166c-19.797 64.398-77.596 228.92-186.368 362.04C276.025 747.52 135.85 831.034 129.934 834.675c-5.689 3.413-12.06 5.006-18.432 5.006z"/><path d="M512 730.453c-7.737 0-15.474-2.503-22.3-7.509-3.414-2.73-84.424-65.536-170.44-177.266-85.333-110.592-129.251-195.47-131.072-199.11-9.102-17.978-2.048-39.823 15.702-48.925 17.977-9.103 39.822-2.048 48.924 15.701.455.91 43.008 82.83 123.79 187.733 79.872 103.766 156.559 163.385 157.241 164.068 15.93 12.288 18.887 35.271 6.6 50.972-6.827 9.558-17.522 14.336-28.445 14.336z"/></svg>

+ 1 - 0
src/icons/svgIcon/list.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M5.468 109.545v820.849h1005.925V109.545H5.468zm377.221 527.69v-175.9h251.48v175.9H382.69zm251.48 58.633v175.894H382.69V695.868h251.48zm0-469.061v175.896H382.69V226.807h251.48zm-314.354 0v175.896H68.335V226.807h251.48zM68.335 461.335h251.481v175.9H68.336v-175.9zm628.703 0h251.478v175.9H697.038v-175.9zm0-58.632V226.807h251.478v175.896H697.038zM68.336 695.868h251.48v175.894H68.336V695.868zm628.702 175.894V695.868h251.478v175.894H697.038zm0 0"/></svg>

+ 7 - 0
src/icons/svgIcon/monthReport.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="14px" height="16px">
+<path fill-rule="evenodd"
+ d="M12.727,15.998 L1.272,15.998 C0.570,15.998 -0.001,15.446 -0.001,14.767 L-0.001,2.460 C-0.001,1.782 0.570,1.230 1.272,1.230 L2.980,1.230 C3.243,0.515 3.943,-0.001 4.772,-0.001 L9.227,-0.001 C10.056,-0.001 10.755,0.515 11.019,1.230 L12.727,1.230 C13.429,1.230 14.000,1.782 14.000,2.460 L14.000,14.767 C14.000,15.446 13.429,15.998 12.727,15.998 ZM9.227,1.230 L4.772,1.230 C4.421,1.230 4.136,1.506 4.136,1.845 C4.136,2.184 4.421,2.460 4.772,2.460 L9.227,2.460 C9.578,2.460 9.863,2.184 9.863,1.845 C9.863,1.506 9.578,1.230 9.227,1.230 ZM12.727,2.460 L11.019,2.460 C10.755,3.175 10.056,3.691 9.227,3.691 L4.772,3.691 C3.943,3.691 3.243,3.175 2.980,2.460 L1.272,2.460 L1.272,14.767 L12.727,14.767 L12.727,2.460 ZM10.130,7.855 L3.869,7.855 L3.869,6.530 L10.130,6.530 L10.130,7.855 ZM10.130,11.311 L3.869,11.311 L3.869,9.986 L10.130,9.986 L10.130,11.311 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/more.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M128.784 381.394c-52.822 0-95.651 42.769-95.651 95.659 0 52.867 42.829 95.634 95.651 95.634 52.826 0 95.653-42.768 95.653-95.634 0-52.89-42.827-95.659-95.653-95.659zm382.612 0c-52.826 0-95.653 42.769-95.653 95.659 0 52.867 42.827 95.634 95.653 95.634 52.822 0 95.651-42.768 95.651-95.634 0-52.89-42.829-95.659-95.651-95.659zm382.608 0c-52.822 0-95.651 42.769-95.651 95.659 0 52.867 42.83 95.634 95.651 95.634 52.826 0 95.653-42.768 95.653-95.634-.001-52.89-42.827-95.659-95.653-95.659zm0 0"/></svg>

File diff ditekan karena terlalu besar
+ 5 - 0
src/icons/svgIcon/operManage.svg


+ 1 - 0
src/icons/svgIcon/page.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M216.178 284.444c-13.654 0-22.756 9.103-22.756 22.756s9.102 22.756 22.756 22.756c13.653 0 22.755-9.103 22.755-22.756s-9.102-22.756-22.755-22.756zm-91.022 0c-13.654 0-22.756 9.103-22.756 22.756s9.102 22.756 22.756 22.756c13.653 0 22.755-9.103 22.755-22.756s-9.102-22.756-22.755-22.756zm591.644 0H398.222c-13.653 0-22.755 9.103-22.755 22.756s9.102 22.756 22.755 22.756H716.8c13.653 0 22.756-9.103 22.756-22.756s-9.103-22.756-22.756-22.756zM921.6 11.378H284.444c-50.062 0-91.022 40.96-91.022 91.022v22.756c0 13.653 9.102 22.755 22.756 22.755 13.653 0 22.755-9.102 22.755-22.755V102.4c0-25.031 20.48-45.511 45.511-45.511H921.6c25.031 0 45.511 20.48 45.511 45.511v637.156c0 25.03-20.48 45.51-45.511 45.51h-22.756c-13.653 0-22.755 9.103-22.755 22.756s9.102 22.756 22.755 22.756H921.6c50.062 0 91.022-40.96 91.022-91.022V102.4c0-50.062-40.96-91.022-91.022-91.022zM307.2 284.444c-13.653 0-22.756 9.103-22.756 22.756s9.103 22.756 22.756 22.756 22.756-9.103 22.756-22.756-9.103-22.756-22.756-22.756zm432.356-91.022H102.4c-50.062 0-91.022 40.96-91.022 91.022V921.6c0 50.062 40.96 91.022 91.022 91.022h637.156c50.062 0 91.022-40.96 91.022-91.022V284.444c0-50.062-40.96-91.022-91.022-91.022zm45.51 728.178c0 25.031-20.48 45.511-45.51 45.511H102.4c-25.031 0-45.511-20.48-45.511-45.511V420.978h728.178V921.6zm0-546.133H56.89v-91.023c0-25.03 20.48-45.51 45.511-45.51h637.156c25.03 0 45.51 20.48 45.51 45.51v91.023z"/></svg>

+ 7 - 0
src/icons/svgIcon/patrolManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="14px" height="16px">
+<path fill-rule="evenodd" 
+ d="M13.869,8.244 L10.196,12.610 C10.086,12.742 9.927,12.810 9.767,12.810 C9.640,12.810 9.512,12.767 9.408,12.680 C9.170,12.482 9.139,12.130 9.338,11.894 L13.010,7.527 C13.209,7.291 13.562,7.260 13.799,7.458 C14.036,7.656 14.067,8.008 13.869,8.244 ZM3.928,10.255 L7.272,10.255 C7.582,10.255 7.832,10.505 7.832,10.813 C7.832,11.121 7.582,11.371 7.272,11.371 L3.928,11.371 C3.619,11.371 3.368,11.121 3.368,10.813 C3.368,10.505 3.619,10.255 3.928,10.255 ZM3.928,6.262 L8.766,6.262 C9.075,6.262 9.326,6.512 9.326,6.820 C9.326,7.128 9.075,7.378 8.766,7.378 L3.928,7.378 C3.619,7.378 3.368,7.128 3.368,6.820 C3.368,6.512 3.619,6.262 3.928,6.262 ZM12.134,5.890 C11.824,5.890 11.574,5.640 11.574,5.332 L11.574,2.238 L9.982,2.238 C9.749,2.884 9.128,3.347 8.400,3.347 L4.293,3.347 C3.565,3.347 2.944,2.884 2.711,2.238 L1.120,2.238 L1.120,14.884 L11.574,14.884 L11.574,13.968 C11.574,13.660 11.824,13.410 12.134,13.410 C12.443,13.410 12.694,13.660 12.694,13.968 L12.694,15.442 C12.694,15.750 12.443,16.000 12.134,16.000 L0.560,16.000 C0.250,16.000 -0.000,15.750 -0.000,15.442 L-0.000,1.680 C-0.000,1.372 0.250,1.122 0.560,1.122 L2.707,1.122 C2.936,0.469 3.561,-0.000 4.293,-0.000 L8.400,-0.000 C9.133,-0.000 9.757,0.469 9.986,1.122 L12.134,1.122 C12.443,1.122 12.694,1.372 12.694,1.680 L12.694,5.332 C12.694,5.640 12.443,5.890 12.134,5.890 ZM8.400,1.116 L4.293,1.116 C3.985,1.116 3.733,1.366 3.733,1.674 C3.733,1.981 3.985,2.232 4.293,2.232 L8.400,2.232 C8.709,2.232 8.960,1.981 8.960,1.674 C8.960,1.366 8.709,1.116 8.400,1.116 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/permissions.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M511.963 0l-397.57 126.309a35.842 35.842 0 00-24.987 34.31l2.035 496.503.465 5.666c.766 3.442 17.035 86.51 98.356 166.536 62.526 61.659 215.895 142.238 281.324 176.623 10.289 5.428 17.965 9.41 22.35 11.872l7.474 4.046a17.513 17.513 0 0016.332.226l10.892-5.528c38.242-18.77 232.793-115.944 305.081-187.19 81.421-80.088 97.69-163.13 98.381-166.585l2.513-502.144a35.842 35.842 0 00-24.988-34.348L511.963 0zm355.534 653.516c-3.065 12.2-20.578 72.376-79.888 130.782-57.288 56.533-212.592 137.276-269.05 165.706a17.412 17.412 0 01-16.093-.188h-.088c-57.539-30.227-210.293-110.455-266.035-165.468-59.474-58.481-76.86-118.57-79.926-130.781l-1.822-461.24a15.905 15.905 0 0111.043-15.188L501.222 70.504a35.478 35.478 0 0121.483 0l335.583 106.635a15.905 15.905 0 0111.144 15.188l-1.91 461.202zm-349.503-414.04a146.585 146.585 0 01103.695 42.539 143.13 143.13 0 01-.616 204.514 146.158 146.158 0 01-67.287 37.149l-.34 60.817 60.667.138a36.307 36.307 0 0136.609 36.194 35.905 35.905 0 01-10.842 25.566 36.797 36.797 0 01-25.968 10.566l-60.667-.138-.276 101.019a35.905 35.905 0 01-10.842 25.566 36.797 36.797 0 01-25.968 10.578 36.307 36.307 0 01-36.608-36.194l.892-234.175a145.932 145.932 0 01-67.05-37.363 143.219 143.219 0 01.541-204.652 146.988 146.988 0 01104.034-42.136zm88.242 143.32a83.506 83.506 0 00-25.126-60.202 87.388 87.388 0 00-122.163-.24 83.255 83.255 0 00-25.452 59.964 84.26 84.26 0 0025.126 60.303 85.981 85.981 0 0060.918 24.925c46.408.163 86.572-39.36 86.685-84.813z"/></svg>

+ 7 - 0
src/icons/svgIcon/planOutage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="16px">
+<path fill-rule="evenodd" 
+ d="M14.545,-0.000 C15.349,-0.000 16.000,0.651 16.000,1.455 L16.000,14.545 C16.000,15.349 15.349,16.000 14.545,16.000 L1.454,16.000 C0.651,16.000 -0.000,15.349 -0.000,14.545 L-0.000,1.455 C-0.000,0.651 0.651,-0.000 1.454,-0.000 L14.545,-0.000 ZM14.545,1.455 L1.454,1.455 L1.454,14.545 L14.545,14.545 L14.545,1.455 ZM5.091,8.727 C6.296,8.727 7.273,9.704 7.273,10.909 C7.273,12.114 6.296,13.091 5.091,13.091 C3.886,13.091 2.909,12.114 2.909,10.909 C2.909,9.704 3.886,8.727 5.091,8.727 ZM13.091,10.182 L13.091,11.636 L8.727,11.636 L8.727,10.182 L13.091,10.182 ZM5.091,10.182 C4.689,10.182 4.364,10.507 4.364,10.909 C4.364,11.311 4.689,11.636 5.091,11.636 C5.493,11.636 5.818,11.311 5.818,10.909 C5.818,10.507 5.493,10.182 5.091,10.182 ZM6.633,3.548 L7.663,4.577 L4.577,7.662 L2.519,5.605 L3.548,4.577 L4.577,5.605 L6.633,3.549 L6.633,3.548 ZM13.091,5.091 L13.091,6.545 L8.727,6.545 L8.727,5.091 L13.091,5.091 Z"/>
+</svg>

+ 7 - 0
src/icons/svgIcon/powerQuality.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="13px" height="16px">
+<path fill-rule="evenodd"
+ d="M6.882,3.293 L5.633,5.759 C5.424,6.170 5.407,6.653 5.587,7.078 C5.767,7.504 6.123,7.823 6.563,7.954 L10.058,8.995 L5.035,12.758 L6.053,11.146 C6.311,10.736 6.367,10.240 6.204,9.784 C6.041,9.329 5.685,8.981 5.228,8.834 L1.801,7.727 L6.882,3.293 M9.103,-0.000 C9.011,-0.000 8.916,0.032 8.830,0.106 L0.145,7.690 C-0.106,7.908 -0.021,8.320 0.292,8.421 L4.891,9.905 C5.156,9.990 5.268,10.306 5.119,10.541 L2.088,15.338 C1.890,15.650 2.144,15.999 2.444,15.999 C2.526,15.999 2.614,15.973 2.694,15.912 L11.830,9.066 C12.110,8.857 12.031,8.414 11.698,8.312 L6.877,6.876 C6.622,6.800 6.500,6.509 6.621,6.272 L9.480,0.626 C9.641,0.310 9.387,-0.000 9.103,-0.000 Z"/>
+</svg>

+ 1 - 0
src/icons/svgIcon/refresh.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><defs><style/></defs><path d="M128 800v160a32 32 0 11-64 0V704a32 32 0 0135.968-31.744l256 32a32 32 0 11-7.936 63.488l-180.608-22.592A416 416 0 00928 512h64a480 480 0 01-864 288zm771.968-570.688V64.192a32 32 0 1164 0v256A32 32 0 01928 352l-256-32a32 32 0 017.936-63.488l176.448 22.016A416 416 0 0096 512H31.936a480 480 0 01867.968-282.688z"/></svg>

+ 1 - 0
src/icons/svgIcon/set.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1031 1024" xmlns="http://www.w3.org/2000/svg" width="201.367" height="200"><defs><style/></defs><path d="M512 723.2c-115.2 0-211.2-96-211.2-211.2s96-211.2 211.2-211.2 211.2 96 211.2 211.2-96 211.2-211.2 211.2zm0-358.4c-83.2 0-147.2 64-147.2 147.2s64 147.2 147.2 147.2 147.2-64 147.2-147.2-64-147.2-147.2-147.2z"/><path d="M569.6 1024H454.4c-25.6 0-51.2-19.2-51.2-51.2l-6.4-89.6c-25.6-6.4-51.2-19.2-70.4-32l-64 57.6c-19.2 19.2-51.2 19.2-70.4 0L108.8 832c-19.2-19.2-19.2-51.2 0-70.4l57.6-64c-12.8-25.6-19.2-44.8-32-70.4l-83.2-6.4c-32 0-51.2-19.2-51.2-51.2V454.4c0-25.6 19.2-51.2 51.2-51.2l89.6-6.4c6.4-25.6 19.2-51.2 32-70.4l-57.6-64C96 256 96 243.2 96 230.4s6.4-25.6 12.8-38.4l83.2-83.2c19.2-19.2 51.2-19.2 70.4 0l64 57.6c25.6-12.8 44.8-19.2 70.4-32l6.4-89.6c0-25.6 19.2-44.8 51.2-44.8H576c25.6 0 51.2 19.2 51.2 51.2l6.4 89.6c25.6 6.4 51.2 19.2 70.4 32l64-57.6c19.2-19.2 51.2-19.2 70.4 0l76.8 76.8c19.2 19.2 19.2 51.2 0 70.4l-57.6 64c12.8 25.6 19.2 44.8 32 70.4l89.6 6.4c25.6 0 51.2 25.6 51.2 51.2V576c0 25.6-19.2 51.2-51.2 51.2l-89.6 6.4c-6.4 25.6-19.2 51.2-32 70.4l57.6 64c6.4 6.4 12.8 19.2 12.8 32s-6.4 25.6-12.8 38.4L832 915.2c-19.2 19.2-51.2 19.2-70.4 0l-64-57.6c-25.6 12.8-44.8 19.2-70.4 32l-6.4 89.6c0 25.6-19.2 44.8-51.2 44.8zm-102.4-64h96l6.4-121.6 19.2-6.4c32-6.4 64-19.2 96-38.4l19.2-12.8 89.6 83.2 64-64-76.8-96 12.8-19.2c19.2-32 32-64 38.4-96l6.4-25.6 121.6-6.4v-89.6l-121.6-6.4-6.4-25.6c-6.4-32-19.2-64-38.4-96L780.8 320l83.2-89.6-64-64-96 76.8-19.2-12.8c-32-19.2-64-32-96-38.4l-25.6-6.4L556.8 64h-89.6l-6.4 121.6-25.6 6.4c-32 6.4-64 19.2-96 38.4L320 243.2 230.4 160l-64 64 76.8 96-12.8 19.2c-12.8 32-32 64-38.4 96l-6.4 25.6L64 467.2v96l121.6 6.4 6.4 19.2c6.4 32 19.2 64 38.4 96l12.8 19.2-83.2 89.6 64 64 96-76.8 19.2 12.8c32 19.2 64 32 96 38.4l25.6 6.4 6.4 121.6z"/></svg>

+ 7 - 0
src/icons/svgIcon/siteManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="16px">
+<path fill-rule="evenodd"
+ d="M15.379,9.548 L13.380,9.548 C13.384,9.501 13.384,9.454 13.380,9.407 C13.189,8.432 12.494,7.630 11.552,7.299 C11.497,7.283 11.439,7.275 11.381,7.275 L8.624,7.275 L8.624,6.446 L10.623,6.446 C10.968,6.446 11.248,6.168 11.248,5.825 L11.248,5.825 L11.248,0.612 C11.248,0.269 10.968,-0.009 10.623,-0.009 L10.623,-0.009 L5.376,-0.009 C5.031,-0.009 4.751,0.269 4.751,0.612 L4.751,5.830 C4.751,6.172 5.031,6.451 5.376,6.451 L7.375,6.451 L7.375,7.279 L4.514,7.279 C3.064,7.366 2.669,9.217 2.627,9.428 C2.623,9.468 2.623,9.508 2.627,9.548 L0.620,9.548 C0.275,9.548 -0.005,9.826 -0.005,10.169 L-0.005,10.169 L-0.005,15.386 C-0.005,15.729 0.275,16.007 0.620,16.007 L5.867,16.007 C6.212,16.007 6.492,15.729 6.492,15.386 L6.492,10.169 C6.492,9.826 6.212,9.548 5.867,9.548 L5.867,9.548 L3.885,9.548 C3.989,9.134 4.255,8.538 4.551,8.517 L11.256,8.517 C11.670,8.726 11.973,9.101 12.089,9.548 L10.132,9.548 C9.787,9.548 9.507,9.826 9.507,10.169 L9.507,10.169 L9.507,15.386 C9.507,15.729 9.787,16.007 10.132,16.007 L15.379,16.007 C15.724,16.007 16.004,15.729 16.004,15.386 L16.004,10.169 C16.004,9.826 15.724,9.548 15.379,9.548 L15.379,9.548 ZM6.000,1.233 L9.999,1.233 L9.999,5.208 L6.000,5.208 L6.000,1.233 ZM5.242,14.765 L1.244,14.765 L1.244,10.790 L5.242,10.790 L5.242,14.765 ZM14.755,14.765 L10.756,14.765 L10.756,10.790 L14.755,10.790 L14.755,14.765 Z"/>
+</svg>

+ 7 - 0
src/icons/svgIcon/stationManage.svg

@@ -0,0 +1,7 @@
+<svg 
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="16px" height="16px">
+<path fill-rule="evenodd"
+ d="M13.333,10.667 L10.667,10.667 L10.667,13.333 C10.667,14.806 9.473,16.000 8.000,16.000 L2.667,16.000 C1.194,16.000 -0.000,14.806 -0.000,13.333 L-0.000,8.000 C-0.000,6.527 1.194,5.333 2.667,5.333 L5.333,5.333 L5.333,2.667 C5.333,1.194 6.527,-0.000 8.000,-0.000 L13.333,-0.000 C14.806,-0.000 16.000,1.194 16.000,2.667 L16.000,8.000 C16.000,9.473 14.806,10.667 13.333,10.667 ZM2.667,6.667 C1.930,6.667 1.333,7.264 1.333,8.000 L1.333,13.333 C1.333,14.070 1.930,14.667 2.667,14.667 L8.000,14.667 C8.736,14.667 9.333,14.070 9.333,13.333 L9.333,10.667 L8.000,10.667 C6.527,10.667 5.333,9.473 5.333,8.000 L5.333,6.667 L2.667,6.667 ZM9.333,9.333 L9.333,8.000 C9.333,7.264 8.736,6.667 8.000,6.667 L6.667,6.667 L6.667,8.000 C6.667,8.736 7.264,9.333 8.000,9.333 L9.333,9.333 ZM14.667,2.667 C14.667,1.930 14.070,1.333 13.333,1.333 L8.000,1.333 C7.264,1.333 6.667,1.930 6.667,2.667 L6.667,5.333 L8.000,5.333 C9.473,5.333 10.667,6.527 10.667,8.000 L10.667,9.333 L13.333,9.333 C14.070,9.333 14.667,8.736 14.667,8.000 L14.667,2.667 Z"/>
+</svg>

File diff ditekan karena terlalu besar
+ 5 - 0
src/icons/svgIcon/systemManage.svg


+ 232 - 0
src/layout/index.vue

@@ -0,0 +1,232 @@
+<template>
+  <a-layout class="vab-layout-wrap">
+    <div
+      v-if="device === 'mobile' && !collapse"
+      class="vab-mask"
+      @click="handleFoldSideBar"
+    ></div>
+    <a-layout-sider
+      collapsible
+      class="vab-sider"
+      width="220"
+      v-model:collapsed="collapse"
+      :class="classObj"
+      :trigger="null"
+    >
+      <vab-logo />
+      <a-menu
+        class="vab-menu"
+        theme="dark"
+        mode="inline"
+        v-model:selectedKeys="selectedKeys"
+        v-model:openKeys="openKeys"
+      >
+        <vab-menu v-for="route in routes" :key="route.path" :item="route" />
+      </a-menu>
+    </a-layout-sider>
+    <a-layout
+      class="vab-layout"
+      :class="'mobile' === device ? 'vab-mobile-layout' : ''"
+    >
+      <a-layout-header class="vab-header">
+        <a-row>
+          <a-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
+            <menu-unfold-outlined
+              v-if="collapse"
+              class="trigger"
+              @click="toggleCollapse"
+            />
+            <menu-fold-outlined
+              v-else
+              class="trigger"
+              @click="toggleCollapse"
+            />
+          </a-col>
+          <a-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
+            <vab-avatar />
+          </a-col>
+        </a-row>
+      </a-layout-header>
+      <vab-tabs />
+      <vab-content />
+    </a-layout>
+  </a-layout>
+</template>
+<script>
+import VabLogo from './vab-logo'
+import VabAvatar from './vab-avatar'
+import VabMenu from './vab-menu'
+import VabTabs from './vab-tabs'
+import VabContent from './vab-content'
+import { mapActions, mapGetters } from 'vuex'
+import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue'
+
+export default {
+  components: {
+    VabLogo,
+    VabAvatar,
+    VabMenu,
+    VabTabs,
+    VabContent,
+    MenuUnfoldOutlined,
+    MenuFoldOutlined,
+  },
+  data() {
+    return {
+      selectedKeys: [],
+      openKeys: [],
+    }
+  },
+  computed: {
+    ...mapGetters({
+      collapse: 'settings/collapse',
+      routes: 'routes/routes',
+      device: 'settings/device',
+    }),
+    classObj() {
+      return {
+        'vab-mobile': this.device === 'mobile',
+        'vab-collapse': this.collapse,
+      }
+    },
+  },
+  watch: {
+    $route: {
+      handler({ path, matched }) {
+        matched[0].children.length > 1
+          ? (this.selectedKeys = [path])
+          : (this.selectedKeys = [matched[0].path])
+        this.openKeys = [matched[0].path]
+      },
+      immediate: true,
+    },
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.handleLayouts)
+  },
+  beforeUnmount() {
+    window.removeEventListener('resize', this.handleLayouts)
+  },
+  mounted() {
+    this.handleLayouts()
+  },
+  methods: {
+    ...mapActions({
+      toggleDevice: 'settings/toggleDevice',
+      handleFoldSideBar: 'settings/foldSideBar',
+      toggleCollapse: 'settings/toggleCollapse',
+    }),
+    handleLayouts() {
+      const width = document.body.getBoundingClientRect().width
+      if (this.width !== width) {
+        const isMobile = width - 1 < 992
+        this.toggleDevice(isMobile ? 'mobile' : 'desktop')
+        this.width = width
+      }
+    },
+  },
+}
+</script>
+<style lang="less">
+.vab-layout-wrap {
+  height: 100%;
+  .vab-sider {
+    background-color: #fff;
+    position: fixed;
+    left: 0;
+    height: 100vh;
+    overflow: auto;
+    .vab-menu {
+      overflow-y: auto;
+      height: calc(100vh - @vab-header-height);
+      li {
+        margin-top: 0px;
+      }
+    }
+    .vab-menu::-webkit-scrollbar {
+      display: none;
+    }
+  }
+  .vab-layout {
+    height: 100%;
+    padding-left: 220px;
+    transition: all 0.2s;
+    background-color: #f0f3f4;
+  }
+  .vab-mobile-layout {
+    padding-left: 0;
+    transition: all 0.2s;
+  }
+  .vab-collapse {
+    .vab-logo .anticon + span {
+      display: inline-block;
+      max-width: 0;
+      opacity: 0;
+      transition: all 0.2s;
+    }
+    & + .vab-layout {
+      padding-left: 81px;
+      transition: all 0.2s;
+    }
+  }
+  .vab-mask {
+    position: fixed;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 998;
+    width: 100%;
+    height: 100vh;
+    overflow: hidden;
+    background: #000;
+    opacity: 0.5;
+  }
+  .vab-mobile {
+    position: fixed !important;
+    z-index: 999;
+    &.vab-collapse {
+      width: 0 !important;
+      min-width: 0 !important;
+      max-width: 0 !important;
+      * {
+        display: none !important;
+        width: 0 !important;
+        min-width: 0 !important;
+        max-width: 0 !important;
+      }
+      .ant-menu-item,
+      .ant-menu-submenu {
+        display: none !important;
+        width: 0 !important;
+        min-width: 0 !important;
+        max-width: 0 !important;
+      }
+      & + .vab-layout {
+        padding-left: 0px !important;
+        transition: all 0.2s;
+      }
+    }
+  }
+  .vab-header {
+    padding: 0;
+    background: #fff;
+    .ant-col + .ant-col {
+      display: flex;
+      justify-content: flex-end;
+      padding: 0 @vab-padding;
+    }
+    .trigger {
+      height: @vab-header-height;
+      padding: 0 @vab-padding;
+      font-size: 18px;
+      line-height: @vab-header-height;
+      cursor: pointer;
+      transition: color 0.3s;
+      &:hover {
+        color: #1890ff;
+      }
+    }
+  }
+}
+</style>

+ 54 - 0
src/layout/vab-avatar/index.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="vab-avatar">
+    <a-dropdown>
+      <span class="ant-dropdown-link">
+        <a-avatar :src="avatar" />
+        {{ username }}
+        <DownOutlined />
+      </span>
+      <template v-slot:overlay>
+        <a-menu>
+          <a-menu-item @click="logout">退出登录</a-menu-item>
+        </a-menu>
+      </template>
+    </a-dropdown>
+  </div>
+</template>
+
+<script>
+  import { recordRoute } from '@/config'
+  import { DownOutlined } from '@ant-design/icons-vue'
+
+  import { mapGetters } from 'vuex'
+  export default {
+    name: 'VabAvatar',
+    components: { DownOutlined },
+    computed: {
+      ...mapGetters({
+        avatar: 'user/avatar',
+        username: 'user/username',
+      }),
+    },
+    methods: {
+      async logout() {
+        await this.$store.dispatch('user/logout')
+        if (recordRoute) {
+          const fullPath = this.$route.fullPath
+          this.$router.push(`/login?redirect=${fullPath}`)
+        } else {
+          this.$router.push('/login')
+        }
+      },
+    },
+  }
+</script>
+<style lang="less">
+  .vab-avatar {
+    .ant-dropdown-link {
+      display: block;
+      min-height: @vab-header-height;
+      cursor: pointer;
+      line-height: @vab-header-height;
+    }
+  }
+</style>

+ 66 - 0
src/layout/vab-content/index.vue

@@ -0,0 +1,66 @@
+<template>
+  <a-layout-content class="vab-content">
+    <router-view v-slot="{ Component }">
+      <transition mode="out-in" name="fade-transform">
+        <component :is="Component" />
+      </transition>
+    </router-view>
+  </a-layout-content>
+</template>
+
+<script>
+export default {
+  name: 'VabContent',
+  watch: {
+    $route: {
+      handler() {
+        if ('mobile' === this.device) {
+          this.$store.dispatch('settings/foldSideBar')
+        }
+      },
+      immediate: true,
+    },
+  },
+}
+</script>
+
+<style lang="less">
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all 0.2s;
+}
+
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+.vab-content {
+  overflow-y: auto;
+  min-height: calc(
+    100vh - @vab-header-height - @vab-padding - @vab-padding - @vab-padding -
+      @vab-padding
+  ) !important;
+  max-height: calc(
+    100vh - @vab-header-height - @vab-padding - @vab-padding - @vab-padding -
+      @vab-padding
+  ) !important;
+  // padding: @vab-padding;
+  margin: @vab-margin;
+  // background: #fff;
+  .error-container {
+    height: calc(
+      100vh - @vab-header-height - @vab-padding - @vab-padding - @vab-padding -
+        @vab-padding - @vab-padding - @vab-margin
+    ) !important;
+  }
+}
+.vab-content::-webkit-scrollbar {
+  display: none;
+}
+</style>

+ 24 - 0
src/layout/vab-icon/index.vue

@@ -0,0 +1,24 @@
+<template>
+  <i :class="'ri-' + icon" aria-hidden="true"></i>
+</template>
+
+<script>
+  import 'remixicon/fonts/remixicon.css'
+
+  export default {
+    name: 'VabIcon',
+    props: {
+      icon: {
+        type: String,
+        required: true,
+      },
+    },
+  }
+</script>
+
+<style lang="less" scoped>
+  [class*='ri'] {
+    font-size: 16px;
+    vertical-align: -1px;
+  }
+</style>

+ 40 - 0
src/layout/vab-logo/index.vue

@@ -0,0 +1,40 @@
+<template>
+  <div class="vab-logo">
+    <router-link to="/" class="logo-url">
+      <img v-if="collapse" src="../../assets/logo.png" width="30" />
+      <img v-else src="../../assets/logo_admin.png" />
+    </router-link>
+    <span class="anticon"></span>
+    <span>{{ title }}</span>
+  </div>
+</template>
+
+<script>
+import { computed } from 'vue'
+import { useStore, mapGetters } from 'vuex'
+
+export default {
+  name: 'VabLogo',
+  computed: {
+    ...mapGetters({
+      collapse: 'settings/collapse',
+      routes: 'routes/routes',
+      device: 'settings/device',
+    }),
+  },
+  setup() {
+    const store = useStore()
+    return {
+      collapsed: false,
+      logo: computed(() => store.getters['settings/logo']),
+      title: computed(() => store.getters['settings/title']),
+    }
+  },
+}
+</script>
+<style lang="less" scoped>
+.vab-logo {
+  text-align: center;
+  margin: 10px 5px;
+}
+</style>

+ 43 - 0
src/layout/vab-menu/components/MenuItem.vue

@@ -0,0 +1,43 @@
+<template>
+  <a-menu-item :key="routeChildren.path" @click.capture="handleLink">
+    <span class="anticon">
+      <!-- <vab-icon :icon="routeChildren.meta.icon"></vab-icon> -->
+      <svg-icon :iconClass="routeChildren.meta.icon"></svg-icon>
+    </span>
+    <span>{{ routeChildren.meta.title }}</span>
+  </a-menu-item>
+</template>
+
+<script>
+  import { isExternal } from '@/utils/validate'
+  // import VabIcon from '@/layout/vab-icon'
+  export default {
+    name: 'MenuItem',
+    components: {  },
+    props: {
+      item: {
+        type: Object,
+        default() {
+          return null
+        },
+      },
+      routeChildren: {
+        type: Object,
+        default: () => null,
+      },
+    },
+    methods: {
+      handleLink() {
+        const routePath = this.routeChildren.fullPath
+        const target = this.routeChildren.meta.target
+        if (target === '_blank') {
+          if (isExternal(routePath)) window.open(routePath)
+          else if (this.$route.path !== routePath) window.open(routePath.href)
+        } else {
+          if (isExternal(routePath)) window.location.href = routePath
+          else if (this.$route.path !== routePath) this.$router.push(routePath)
+        }
+      },
+    },
+  }
+</script>

+ 35 - 0
src/layout/vab-menu/components/Submenu.vue

@@ -0,0 +1,35 @@
+<template>
+  <a-sub-menu :key="item.fullPath">
+    <template v-slot:title>
+      <span class="anticon">
+        <svg-icon :iconClass="item.meta.icon"></svg-icon>
+        <!-- <vab-icon :icon="item.meta.icon"></vab-icon> -->
+      </span>
+      <span>{{ item.meta.title }}</span>
+    </template>
+    <slot></slot>
+  </a-sub-menu>
+</template>
+
+<script>
+  // import VabIcon from '@/layout/vab-icon'
+  export default {
+    name: 'Submenu',
+    components: {  },
+    props: {
+      item: {
+        type: Object,
+        default() {
+          return null
+        },
+      },
+      routeChildren: {
+        type: Object,
+        default() {
+          return null
+        },
+      },
+    },
+    methods: {},
+  }
+</script>

+ 60 - 0
src/layout/vab-menu/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <component
+    :is="menuComponent"
+    v-if="!item.hidden"
+    :item="item"
+    :route-children="routeChildren"
+  >
+    <template v-if="item.children && item.children.length">
+      <vab-menu
+        v-for="route in item.children"
+        :key="route.path"
+        :item="route"
+      ></vab-menu>
+    </template>
+  </component>
+</template>
+
+<script>
+  import MenuItem from './components/MenuItem'
+  import Submenu from './components/Submenu'
+  export default {
+    name: 'VabMenu',
+    components: { MenuItem, Submenu },
+    props: {
+      item: {
+        type: Object,
+        required: true,
+      },
+    },
+    data() {
+      return {
+        routeChildren: {},
+        menuComponent: '',
+      }
+    },
+    created() {
+      const showChildren = this.handleChildren(this.item.children)
+      if (showChildren.length === 0) {
+        this.menuComponent = 'MenuItem'
+        this.routeChildren = this.item
+      } else if (showChildren.length === 1 && this.item.alwaysShow !== true) {
+        this.menuComponent = 'MenuItem'
+        this.routeChildren = showChildren[0]
+      } else {
+        this.menuComponent = 'Submenu'
+      }
+    },
+    methods: {
+      handleChildren(children = []) {
+        if (children === null) return []
+        return children.filter((item) => item.hidden !== true)
+      },
+    },
+  }
+</script>
+<style lang="less">
+  .anticon {
+    margin-right: 3px !important;
+  }
+</style>

+ 240 - 0
src/layout/vab-tabs/index.vue

@@ -0,0 +1,240 @@
+<template>
+  <div class="vab-tabs">
+    <div class="vab-tabs-left-panel">
+      <!-- <a-tabs
+        @tab-click="handleTabClick"
+        @edit="handleTabRemove"
+        v-model:activeKey="tabActive"
+        hide-add
+        type="editable-card"
+      >
+        <a-tab-pane
+          v-for="item in visitedRoutes"
+          :key="item.fullPath"
+          :closable="!isAffix(item)"
+          :tab="item.meta.title"
+        ></a-tab-pane>
+      </a-tabs> -->
+
+      <el-breadcrumb separator="/">
+        <el-breadcrumb-item
+          v-for="(item, ind) in breadListLast"
+          :key="ind"
+          :to="item.path"
+        >
+          {{ item.title }}
+        </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+    <!-- <div class="vab-tabs-right-panel">
+      <a-dropdown>
+        <template v-slot:overlay>
+          <a-menu @click="handleClick">
+            <a-menu-item key="closeOthersTabs">
+              <a>关闭其他</a>
+            </a-menu-item>
+            <a-menu-item key="closeLeftTabs">
+              <a>关闭左侧</a>
+            </a-menu-item>
+            <a-menu-item key="closeRightTabs">
+              <a>关闭右侧</a>
+            </a-menu-item>
+            <a-menu-item key="closeAllTabs">
+              <a>关闭全部</a>
+            </a-menu-item>
+          </a-menu>
+        </template>
+        <a-button style="margin-left: 8px">
+          更多
+          <DownOutlined />
+        </a-button>
+      </a-dropdown>
+    </div> -->
+  </div>
+</template>
+
+<script>
+// import { DownOutlined } from '@ant-design/icons-vue'
+import { mapActions, mapGetters } from 'vuex'
+export default {
+  name: 'VabTabs',
+  components: {
+    // DownOutlined,
+  },
+  data() {
+    return {
+      breadListLast: [],
+      affixTabs: [],
+      tabActive: null,
+      created: false,
+    }
+  },
+  computed: {
+    ...mapGetters({
+      visitedRoutes: 'tagsBar/visitedRoutes',
+      routes: 'routes/routes',
+    }),
+  },
+  watch: {
+    $route() {
+      this.loadChange()
+    },
+  },
+  created() {
+    this.initAffixTabs(this.routes)
+    this.addTabs(this.$route)
+    this.loadChange()
+  },
+  methods: {
+    loadChange() {
+      this.breadListLast = []
+
+      this.$route.matched.map((val) => {
+        this.breadListLast.push({
+          path:val.path,
+          title:val.meta.title
+        })
+      })
+    },
+
+    ...mapActions({
+      addVisitedRoute: 'tagsBar/addVisitedRoute',
+      delVisitedRoute: 'tagsBar/delVisitedRoute',
+      delOthersVisitedRoutes: 'tagsBar/delOthersVisitedRoutes',
+      delLeftVisitedRoutes: 'tagsBar/delLeftVisitedRoutes',
+      delRightVisitedRoutes: 'tagsBar/delRightVisitedRoutes',
+      delAllVisitedRoutes: 'tagsBar/delAllVisitedRoutes',
+    }),
+    initAffixTabs(routes) {
+      routes.forEach((route) => {
+        if (route.meta && route.meta.affix) this.addTabs(route)
+        if (route.children) this.initAffixTabs(route.children)
+      })
+    },
+    async addTabs(tag) {
+      if (tag.name && tag.meta && tag.meta.tagHidden !== true) {
+        let matched = [tag.name]
+        if (tag.matched) matched = tag.matched.map((item) => item.name)
+        await this.addVisitedRoute({
+          path: tag.path,
+          fullPath: tag.fullPath,
+          query: tag.query,
+          params: tag.params,
+          name: tag.name,
+          matched: matched,
+          meta: { ...tag.meta },
+        })
+        this.tabActive = tag.fullPath
+      }
+    },
+    isActive(route) {
+      return route.path === this.$route.path
+    },
+    isAffix(tag) {
+      return tag.meta && tag.meta.affix
+    },
+    handleTabClick(tab) {
+      const route = this.visitedRoutes.filter((item) => item.path === tab)[0]
+      if (this.$route.fullPath !== route.fullPath) this.$router.push(route)
+    },
+    async handleTabRemove(fullPath) {
+      const view = this.visitedRoutes.find((item) => {
+        return fullPath === item.fullPath
+      })
+      await this.delVisitedRoute(view)
+      if (this.isActive(view)) this.toLastTag()
+    },
+    handleClick({ key }) {
+      switch (key) {
+        case 'closeOthersTabs':
+          this.closeOthersTabs()
+          break
+        case 'closeLeftTabs':
+          this.closeLeftTabs()
+          break
+        case 'closeRightTabs':
+          this.closeRightTabs()
+          break
+        case 'closeAllTabs':
+          this.closeAllTabs()
+          break
+      }
+    },
+    async closeSelectedTag(view) {
+      await this.delVisitedRoute(view)
+      if (this.isActive(view)) {
+        this.toLastTag()
+      }
+    },
+    async closeOthersTabs() {
+      await this.delOthersVisitedRoutes(this.toThisTag())
+    },
+    async closeLeftTabs() {
+      await this.delLeftVisitedRoutes(this.toThisTag())
+    },
+    async closeRightTabs() {
+      await this.delRightVisitedRoutes(this.toThisTag())
+    },
+    async closeAllTabs() {
+      await this.delAllVisitedRoutes()
+      if (this.affixTabs.some((tag) => tag.path === this.toThisTag().path))
+        return
+      this.toLastTag()
+    },
+    toLastTag() {
+      const latestView = this.visitedRoutes.slice(-1)[0]
+      if (latestView) this.$router.push(latestView)
+      else this.$router.push('/')
+    },
+    toThisTag() {
+      const view = this.visitedRoutes.find(
+        (item) => item.fullPath === this.$route.fullPath
+      )
+      if (this.$route.path !== view.path) this.$router.push(view)
+      return view
+    },
+  },
+}
+</script>
+<style lang="less">
+.vab-tabs {
+  padding: 0 @vab-margin;
+  background: #ffffff;
+  overflow: hidden;
+  &-left-panel {
+    float: left;
+    width: calc(100% - 52px - @vab-margin - @vab-margin);
+  }
+  &-right-panel {
+    float: left;
+    width: 52px;
+  }
+  .ant-tabs {
+    &-bar {
+      margin: 0 !important;
+    }
+    &-tab {
+      height: 32px !important;
+      margin-right: 5px !important;
+      line-height: 32px !important;
+      background: #ffffff !important;
+      border: 1px solid #dedede !important;
+    }
+    &-tab-prev,
+    &-tab-next {
+      height: 32px !important;
+      line-height: 32px !important;
+    }
+    &-tab-active {
+      border: 1px solid #1890ff !important;
+      .ant-tabs-close-x {
+        color: #1890ff !important;
+      }
+    }
+  }
+  .el-breadcrumb {
+    height: @vab-breadcrumb-height;
+    line-height: @vab-breadcrumb-height;
+  }
+}
+</style>

+ 39 - 0
src/main.js

@@ -0,0 +1,39 @@
+import { createApp } from 'vue'
+import Antd from 'ant-design-vue'
+import App from './App'
+import router from './router'
+import store from './store'
+import 'ant-design-vue/dist/antd.css'
+import '@/vab'
+
+// 引入 ElementUI
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import zhCn from 'element-plus/lib/locale/lang/zh-cn'// 中文
+import '@/assets/css/index.scss'
+import '@/assets/css/global.scss'
+import * as echarts from 'echarts';
+
+import '@/icons'
+import SvgIcon from "@/components/SvgIcon"
+
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 正式环境默认使用mock,正式项目记得注释后再打包
+ */
+if (process.env.NODE_ENV === 'production') {
+  const { mockXHR } = require('@/utils/static')
+  mockXHR()
+}
+
+var app = createApp(App)
+
+app.config.globalProperties.$echarts = echarts
+
+app
+  .component("svg-icon", SvgIcon)
+  .use(store)
+  .use(router)
+  .use(ElementPlus, { locale: zhCn, size: 'small' })
+  .use(Antd)
+  .mount('#app')

+ 515 - 0
src/router/index.js

@@ -0,0 +1,515 @@
+import { createRouter, createWebHashHistory } from 'vue-router'
+import Layout from '@/layout'
+
+export const constantRoutes = [
+  {
+    path: '/login',
+    component: () => import('@/views/login'),
+    hidden: true,
+  },
+  {
+    path: '/403',
+    name: '403',
+    component: () => import('@/views/403'),
+    hidden: true,
+  },
+  {
+    path: '/404',
+    name: '404',
+    component: () => import('@/views/404'),
+    hidden: true,
+  },
+]
+export const asyncRoutes = [
+  {
+    path: '/',
+    component: Layout,
+    redirect: '/index',
+    meta: {
+      title: '首页',
+      icon: 'home',
+      affix: true,
+    },
+    children: [
+      {
+        path: 'index',
+        name: 'Index',
+        component: () => import('@/views/index'),
+        meta: {
+          title: '首页',
+          icon: 'home',
+          affix: true,
+        },
+      },
+    ],
+  },
+
+  {
+    path: '/alarmManage',
+    redirect: '/alarmManage/index',
+    meta: {
+      title: '告警管理',
+      icon: 'alarmManage',
+    },
+    component: Layout,
+    children: [
+      {
+        path: 'alarmTotal',
+        component: () => import('@/views/alarmManage/alarmTotal'),
+        selectLeftMenu: '/alarmManage',
+        meta: {
+          title: '告警总数',
+          icon: 'alarmManage',
+        },
+        hidden: true
+      },
+      {
+        meta: {
+          title: '告警管理',
+          icon: 'alarmManage',
+        },
+        path: 'index',
+        component: () => import('@/views/alarmManage/index'),
+        selectLeftMenu: '/alarmManage',
+        hidden: true
+      },
+
+    ]
+  },
+
+  {
+    path: '/siteManage',
+    redirect: '/siteManage/index',
+    meta: {
+      title: '站点管理',
+      icon: 'siteManage',
+    },
+    component: Layout,
+    children: [
+      {
+        meta: {
+          title: '站点管理',
+          icon: 'siteManage',
+        },
+        path: '/siteManage',
+        component: () => import('@/views/siteManage/index'),
+        selectLeftMenu: '/alarmManage',
+        hidden: true
+      }
+    ]
+  },
+
+
+  {
+    meta: {
+      icon: 'stationManage',
+      title: '台区管理',
+    },
+    path: '/stationManage',
+    redirect: '/stationManage/index',
+    component: Layout,
+    children: [
+      {
+        meta: {
+          icon: 'stationManage',
+          title: '站点列表',
+        },
+        path: 'siteList',
+        component: () => import('@/views/stationManage/siteList.vue'),
+        selectLeftMenu: '/stationManage',
+        hidden: true
+      },
+      {
+        meta: {
+          icon: 'stationManage',
+          title: '所有台区',
+        },
+        path: 'index',
+        component: () => import('@/views/stationManage/index.vue'),
+        selectLeftMenu: '/stationManage',
+        hidden: true
+      }
+    ]
+  },
+
+  /**
+   * deviceManage 设备管理
+   * powerEquip 电力监测设备
+   * videoEquip 视频监测设备
+   * communicateEquip 通信设备
+   * channelList 通道列表
+   * attribTemplate 属性模板
+   */
+  {
+    meta: { icon: 'deviceManage', title: '设备管理', },
+    path: '/deviceManage',
+    component: Layout,
+    redirect: '/deviceManage/powerEquip',
+    children: [
+      {
+        meta: { icon: 'deviceManage', title: '设备管理', },
+        path: 'powerEquip',
+        component: () => import('@/views/deviceManage/powerEquip/index.vue'),
+      },
+      // {
+      //   title: 'index-layout.menu.deviceManage.videoEquip',
+      //   path: 'videoEquip',
+      //   component: () => import('@/views/deviceManage/videoEquip/index.vue'),
+      // },
+      // {
+      //   title: 'index-layout.menu.deviceManage.communicateEquip',
+      //   path: 'communicateEquip',
+      //   component: () => import('@/views/deviceManage/communicateEquip/index.vue'),
+      // },
+      // {
+      //   title: 'index-layout.menu.deviceManage.channelList',
+      //   path: 'channelList',
+      //   component: () => import('@/views/deviceManage/channelList/index.vue'),
+      // },
+      {
+        meta: { icon: 'deviceManage', title: '属性模板', },
+        path: 'attribTemplate',
+        component: () => import('@/views/deviceManage/attribTemplate/index.vue'),
+      }
+    ]
+  },
+
+  /**
+   * dataManage 数据管理
+   * sameAnalysis 同比分析报表
+   * chainAnalysis 环比分析报表
+   * handOpera 手动抄表
+   * energyReport 用能月报
+   * demandAnalysis 需量分析
+   * consumConfig 能耗分析配置
+   */
+  {
+    meta: { icon: 'dataManage', title: '数据管理', },
+    path: '/dataManage',
+    component: Layout,
+    redirect: '/dataManage/sameAnalysis',
+    children: [
+      {
+        meta: { icon: 'sameAnalysis', title: '同比分析报表', },
+        path: 'sameAnalysis',
+        component: () => import('@/views/dataManage/sameAnalysis/index.vue'),
+      },
+      {
+        meta: { icon: 'chainAnalysis', title: '环比分析报表', },
+        path: 'chainAnalysis',
+        component: () => import('@/views/dataManage/chainAnalysis/index.vue'),
+      },
+      {
+        meta: { icon: 'handOpera', title: '手动抄表', },
+        title: 'index-layout.menu.dataManage.handOpera',
+        path: 'handOpera',
+        component: () => import('@/views/dataManage/handOpera/index.vue'),
+      },
+      {
+        meta: { icon: 'energyReport', title: '用能月报', },
+        title: 'index-layout.menu.dataManage.energyReport',
+        path: 'energyReport',
+        component: () => import('@/views/dataManage/energyReport/index.vue'),
+      },
+      {
+        meta: { icon: 'demandAnalysis', title: '需量分析', },
+        title: 'index-layout.menu.dataManage.demandAnalysis',
+        path: 'demandAnalysis',
+        component: () => import('@/views/dataManage/demandAnalysis/index.vue'),
+      },
+      {
+        meta: { icon: 'consumConfig', title: '能耗分析配置', },
+        title: 'index-layout.menu.dataManage.consumConfig',
+        path: 'consumConfig',
+        component: () =>
+          import('@/views/dataManage/consumConfig/index.vue'),
+      }
+    ]
+  },
+
+  /**
+     * powerQuality 电能质量
+     * harmonicReport 谐波报表
+     * realTimeMonitoring 实时监测
+     * asseReport 评估报告
+     * unbalanceAnalysis 三相不平衡分析
+     */
+  {
+    meta: { icon: 'powerQuality', title: '电能质量', },
+    path: '/powerQuality',
+    component: Layout,
+    redirect: '/powerQuality/harmonicReport',
+    children: [
+      {
+        meta: { icon: 'harmonicReport', title: '谐波报表', },
+        path: 'harmonicReport',
+        component: () => import('@/views/powerQuality/harmonicReport/index.vue'),
+      },
+      {
+        meta: { icon: 'realTimeMonitoring', title: '实时监测', },
+        path: 'realTimeMonitoring',
+        component: () => import('@/views/powerQuality/realTimeMonitoring/index.vue'),
+      },
+      {
+        meta: { icon: 'asseReport', title: '评估报告', },
+        path: 'asseReport',
+        component: () => import('@/views/powerQuality/asseReport/index.vue'),
+      },
+      {
+        meta: { icon: 'unbalanceAnalysis', title: '三相不平衡分析', },
+        path: 'unbalanceAnalysis',
+        component: () => import('@/views/powerQuality/unbalanceAnalysis/index.vue'),
+      },
+
+    ]
+  },
+
+
+  /**
+   * monthReport 月度报告
+   */
+  {
+    path: '/monthReport',
+    redirect: '/monthReport',
+    meta: {
+      title: '月度报告',
+      icon: 'monthReport',
+    },
+    component: Layout,
+    children: [
+      {
+        path: '/monthReport',
+        component: () => import('@/views/monthReport/index'),
+        hidden: true
+      }
+    ]
+  },
+
+
+  {
+    path: '/planOutage',
+    redirect: '/planOutage',
+    meta: {
+      title: '计划停电',
+      icon: 'planOutage',
+    },
+    component: Layout,
+    children: [
+      {
+        path: '/planOutage',
+        component: () => import('@/views/planOutage/index'),
+        hidden: true
+      }
+    ]
+  },
+
+
+  /**
+   * patrolManage 巡检管理
+   * patrolPlan 巡检计划
+   * patrolRecord 巡检记录
+   * patrolContent 巡检内容
+   * checkEntries 检查条目
+   */
+  {
+    meta: { title: '巡检管理', icon: 'patrolManage', },
+    path: '/patrolManage',
+    component: Layout,
+    redirect: '/patrolManage/patrolPlan',
+    name: 'patrolManage',
+    children: [
+      {
+        meta: { title: '巡检计划' },
+        path: 'patrolPlan',
+        name: 'patrolPlan',
+        component: () => import('@/views/patrolManage/patrolPlan/index.vue'),
+      },
+      {
+        meta: { title: '巡检记录' },
+        path: 'patrolRecord',
+        name: 'patrolRecord',
+        component: () => import('@/views/patrolManage/patrolRecord/index.vue'),
+      },
+      {
+        meta: { title: '巡检内容' },
+        path: 'patrolContent',
+        name: 'patrolContent',
+        component: () => import('@/views/patrolManage/patrolContent/index.vue'),
+      },
+      {
+        meta: { title: '检查条目' },
+        path: 'checkEntries',
+        name: 'checkEntries',
+        component: () => import('@/views/patrolManage/checkEntries/index.vue'),
+      },
+    ]
+  },
+
+
+  /**
+   * operManage 运维管理
+   * siteAchives 现场档案
+   * defectManage 缺陷管理
+   * workManage 工单管理
+   * operStatistics 运维统计
+   * workStatistics 工作量统计
+   */
+  {
+    meta: { title: '运维管理', icon: 'operManage', },
+    path: '/operManage',
+    component: Layout,
+    redirect: '/operManage/siteAchives',
+    name: 'operManage',
+    children: [
+      {
+        meta: { title: '现场档案' },
+        path: 'siteAchives',
+        component: () => import('@/views/operManage/siteAchives/index.vue'),
+      },
+      {
+        meta: { title: '缺陷管理' },
+        path: 'defectManage',
+        component: () =>
+          import('@/views/operManage/defectManage/index.vue'),
+      },
+      {
+        meta: { title: '工单管理' },
+        path: 'workManage',
+        component: () =>
+          import('@/views/operManage/workManage/index.vue'),
+      },
+      {
+        meta: { title: '运维统计' },
+        path: 'operStatistics',
+        component: () => import('@/views/operManage/operStatistics/index.vue'),
+      },
+      {
+        meta: { title: '工作量统计' },
+        path: 'workStatistics',
+        component: () => import('@/views/operManage/workStatistics/index.vue'),
+      },
+
+    ]
+  },
+
+  /** 
+     * systemManage 系统管理
+     * userManage 用户管理
+     * rolePermission 权限管理
+     */
+  {
+    meta: { title: '系统管理', icon: 'systemManage', },
+    path: '/systemManage',
+    component: Layout,
+    redirect: '/systemManage/userManage',
+    children: [
+      {
+        meta: { title: '用户管理' },
+        path: 'userManage',
+        component: () => import('@/views/systemManage/userManage/index.vue'),
+      },
+      {
+        meta: { title: '权限管理' },
+        path: 'rolePermission',
+        component: () => import('@/views/systemManage/rolePermission/index.vue'),
+      },
+    ]
+  },
+
+
+
+
+  {
+    path: '/vab',
+    component: Layout,
+    redirect: '/vab/table',
+    alwaysShow: true,
+    meta: {
+      title: '组件',
+      icon: 'apps-line',
+    },
+    children: [
+      {
+        path: 'table',
+        name: 'Table',
+        component: () => import('@/views/vab/table'),
+        meta: {
+          title: '表格',
+          icon: 'table-2',
+        },
+      },
+      {
+        path: 'icon',
+        name: 'Icon',
+        component: () => import('@/views/vab/icon'),
+        meta: {
+          title: '图标',
+          icon: 'remixicon-line',
+        },
+      },
+    ],
+  },
+
+  // {
+  //   path: '/test',
+  //   component: Layout,
+  //   redirect: '/test/test',
+  //   meta: {
+  //     title: '动态路由测试',
+  //     icon: 'test-tube-line',
+  //   },
+  //   children: [
+  //     {
+  //       path: 'test',
+  //       name: 'Test',
+  //       component: () => import('@/views/test'),
+  //       meta: {
+  //         title: '动态路由测试',
+  //         icon: 'test-tube-line',
+  //       },
+  //     },
+  //   ],
+  // },
+
+  // {
+  //   path: '/error',
+  //   name: 'Error',
+  //   component: Layout,
+  //   redirect: '/error/403',
+  //   meta: {
+  //     title: '错误页',
+  //     icon: 'error-warning-line',
+  //   },
+  //   children: [
+  //     {
+  //       path: '403',
+  //       name: 'Error403',
+  //       component: () => import('@/views/403'),
+  //       meta: {
+  //         title: '403',
+  //         icon: 'error-warning-line',
+  //       },
+  //     },
+  //     {
+  //       path: '404',
+  //       name: 'Error404',
+  //       component: () => import('@/views/404'),
+  //       meta: {
+  //         title: '404',
+  //         icon: 'error-warning-line',
+  //       },
+  //     },
+  //   ],
+  // },
+  {
+    path: '/*',
+    redirect: '/404',
+    hidden: true,
+  },
+]
+const router = createRouter({
+  history: createWebHashHistory(),
+  routes: constantRoutes,
+})
+
+export default router

+ 17 - 0
src/store/index.js

@@ -0,0 +1,17 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 导入所有 vuex 模块,自动加入namespaced:true,用于解决vuex命名冲突,请勿修改。
+ */
+import { createStore } from 'vuex'
+
+const files = require.context('./modules', false, /\.js$/)
+const modules = {}
+files.keys().forEach((key) => {
+  modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
+})
+Object.keys(modules).forEach((key) => {
+  modules[key]['namespaced'] = true
+})
+export default createStore({
+  modules,
+})

+ 33 - 0
src/store/modules/acl.js

@@ -0,0 +1,33 @@
+const state = () => ({
+  admin: false,
+  role: [],
+  ability: [],
+})
+const getters = {
+  admin: (state) => state.admin,
+  role: (state) => state.role,
+  ability: (state) => state.ability,
+}
+const mutations = {
+  setFull(state, admin) {
+    state.admin = admin
+  },
+  setRole(state, role) {
+    state.role = role
+  },
+  setAbility(state, ability) {
+    state.ability = ability
+  },
+}
+const actions = {
+  setFull({ commit }, admin) {
+    commit('setFull', admin)
+  },
+  setRole({ commit }, role) {
+    commit('setRole', role)
+  },
+  setAbility({ commit }, ability) {
+    commit('setAbility', ability)
+  },
+}
+export default { state, getters, mutations, actions }

+ 62 - 0
src/store/modules/routes.js

@@ -0,0 +1,62 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 路由拦截状态管理,目前两种模式:all模式与intelligence模式,其中partialRoutes是菜单暂未使用
+ */
+import { asyncRoutes, constantRoutes } from '@/router'
+import { getRouterList } from '@/api/router'
+import { convertRouter, filterRoutes } from '@/utils/routes'
+
+const state = () => ({
+  routes: [],
+  partialRoutes: [],
+})
+const getters = {
+  routes: (state) => state.routes,
+  partialRoutes: (state) => state.partialRoutes,
+}
+const mutations = {
+  setRoutes(state, routes) {
+    state.routes = routes
+  },
+  setPartialRoutes(state, routes) {
+    state.partialRoutes = routes
+  },
+}
+const actions = {
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description intelligence模式设置路由
+   * @param {*} { commit }
+   * @returns
+   */
+  async setRoutes({ commit }) {
+    const finallyRoutes = filterRoutes([...constantRoutes, ...asyncRoutes])
+    commit('setRoutes', finallyRoutes)
+    return [...asyncRoutes]
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description all模式设置路由
+   * @param {*} { commit }
+   * @returns
+   */
+  async setAllRoutes({ commit }) {
+    let { data } = await getRouterList()
+    if (data[data.length - 1].path !== '*')
+      data.push({ path: '*', redirect: '/404', hidden: true })
+    const asyncRoutes = convertRouter(data)
+    const finallyRoutes = filterRoutes([...constantRoutes, ...asyncRoutes])
+    commit('setRoutes', finallyRoutes)
+    return [...asyncRoutes]
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 画廊布局、综合布局设置路由
+   * @param {*} { commit }
+   * @param accessedRoutes 画廊布局、综合布局设置路由
+   */
+  setPartialRoutes({ commit }, accessedRoutes) {
+    commit('setPartialRoutes', accessedRoutes)
+  },
+}
+export default { state, getters, mutations, actions }

+ 179 - 0
src/store/modules/settings.js

@@ -0,0 +1,179 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 所有全局配置的状态管理,如无必要请勿修改
+ */
+import defaultSettings from '@/config'
+import { isJson } from '@/utils/validate'
+
+const {
+  logo,
+  title,
+  layout,
+  header,
+  themeName,
+  i18n,
+  showLanguage,
+  showProgressBar,
+  showRefresh,
+  showSearch,
+  showTheme,
+  showTagsBar,
+  showNotice,
+  showFullScreen,
+} = defaultSettings
+
+const getLocalStorage = (key) => {
+  const value = localStorage.getItem(key)
+  if (isJson(value)) {
+    return JSON.parse(value)
+  } else {
+    return false
+  }
+}
+
+const theme = getLocalStorage('vue-admin-beautiful-pro-theme')
+const { collapse } = getLocalStorage('vue-admin-beautiful-pro-collapse')
+const { language } = getLocalStorage('vue-admin-beautiful-pro-language')
+const toggleBoolean = (key) => {
+  return typeof theme[key] !== 'undefined' ? theme[key] : key
+}
+
+const state = () => ({
+  logo,
+  title,
+  collapse,
+  themeName: theme.themeName || themeName,
+  layout: theme.layout || layout,
+  header: theme.header || header,
+  device: 'desktop',
+  language: language || i18n,
+  showLanguage: toggleBoolean(showLanguage),
+  showProgressBar: toggleBoolean(showProgressBar),
+  showRefresh: toggleBoolean(showRefresh),
+  showSearch: toggleBoolean(showSearch),
+  showTheme: toggleBoolean(showTheme),
+  showTagsBar: toggleBoolean(showTagsBar),
+  showNotice: toggleBoolean(showNotice),
+  showFullScreen: toggleBoolean(showFullScreen),
+})
+const getters = {
+  collapse: (state) => state.collapse,
+  device: (state) => state.device,
+  header: (state) => state.header,
+  language: (state) => state.language,
+  layout: (state) => state.layout,
+  logo: (state) => state.logo,
+  title: (state) => state.title,
+  showLanguage: (state) => state.showLanguage,
+  showProgressBar: (state) => state.showProgressBar,
+  showRefresh: (state) => state.showRefresh,
+  showSearch: (state) => state.showSearch,
+  showTheme: (state) => state.showTheme,
+  showTagsBar: (state) => state.showTagsBar,
+  showNotice: (state) => state.showNotice,
+  showFullScreen: (state) => state.showFullScreen,
+  themeName: (state) => state.themeName,
+}
+const mutations = {
+  toggleCollapse(state) {
+    state.collapse = !state.collapse
+    localStorage.setItem(
+      'vue-admin-beautiful-pro-collapse',
+      `{"collapse":${state.collapse}}`
+    )
+  },
+  toggleDevice(state, device) {
+    state.device = device
+  },
+  changeHeader(state, header) {
+    state.header = header
+  },
+  changeLayout(state, layout) {
+    state.layout = layout
+  },
+  handleShowLanguage(state, showLanguage) {
+    state.showLanguage = showLanguage
+  },
+  handleShowProgressBar(state, showProgressBar) {
+    state.showProgressBar = showProgressBar
+  },
+  handleShowRefresh(state, showRefresh) {
+    state.showRefresh = showRefresh
+  },
+  handleShowSearch(state, showSearch) {
+    state.showSearch = showSearch
+  },
+  handleShowTheme(state, showTheme) {
+    state.showTheme = showTheme
+  },
+  handleShowTagsBar(state, showTagsBar) {
+    state.showTagsBar = showTagsBar
+  },
+  handleShowNotice(state, showNotice) {
+    state.showNotice = showNotice
+  },
+  handleShowFullScreen(state, showFullScreen) {
+    state.showFullScreen = showFullScreen
+  },
+  openSideBar(state) {
+    state.collapse = false
+  },
+  foldSideBar(state) {
+    state.collapse = true
+  },
+  changeLanguage(state, language) {
+    localStorage.setItem(
+      'vue-admin-beautiful-pro-language',
+      `{"language":"${language}"}`
+    )
+    state.language = language
+  },
+}
+const actions = {
+  toggleCollapse({ commit }) {
+    commit('toggleCollapse')
+  },
+  toggleDevice({ commit }, device) {
+    commit('toggleDevice', device)
+  },
+  changeHeader({ commit }, header) {
+    commit('changeHeader', header)
+  },
+  changeLayout({ commit }, layout) {
+    commit('changeLayout', layout)
+  },
+  handleShowLanguage: ({ commit }, showLanguage) => {
+    commit('handleShowLanguage', showLanguage)
+  },
+  handleShowProgressBar: ({ commit }, showProgressBar) => {
+    commit('handleShowProgressBar', showProgressBar)
+  },
+  handleShowRefresh: ({ commit }, showRefresh) => {
+    commit('handleShowRefresh', showRefresh)
+  },
+  handleShowSearch: ({ commit }, showSearch) => {
+    commit('handleShowSearch', showSearch)
+  },
+  handleShowTheme: ({ commit }, showTheme) => {
+    commit('handleShowTheme', showTheme)
+  },
+  handleShowTagsBar({ commit }, showTagsBar) {
+    commit('handleShowTagsBar', showTagsBar)
+  },
+  handleShowNotice: ({ commit }, showNotice) => {
+    commit('handleShowNotice', showNotice)
+  },
+  handleShowFullScreen: ({ commit }, showFullScreen) => {
+    commit('handleShowFullScreen', showFullScreen)
+  },
+  openSideBar({ commit }) {
+    commit('openSideBar')
+  },
+  foldSideBar({ commit }) {
+    commit('foldSideBar')
+  },
+  changeLanguage: ({ commit }, language) => {
+    commit('changeLanguage', language)
+  },
+}
+export default { state, getters, mutations, actions }

+ 146 - 0
src/store/modules/tagsBar.js

@@ -0,0 +1,146 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description tagsBar多标签页逻辑,前期借鉴了很多开源项目发现都有个共同的特点很繁琐并不符合框架设计的初衷,后来在github用户cyea的启发下完成了重构,请勿修改
+ */
+
+const state = () => ({
+  visitedRoutes: [],
+})
+const getters = {
+  visitedRoutes: (state) => state.visitedRoutes,
+}
+const mutations = {
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 添加标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  addVisitedRoute(state, route) {
+    let target = state.visitedRoutes.find((item) => item.path === route.path)
+    if (target) {
+      if (route.fullPath !== target.fullPath) Object.assign(target, route)
+      return
+    }
+    state.visitedRoutes.push(Object.assign({}, route))
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  delVisitedRoute(state, route) {
+    state.visitedRoutes.forEach((item, index) => {
+      if (item.path === route.path) state.visitedRoutes.splice(index, 1)
+    })
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页以外其它全部多标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  delOthersVisitedRoutes(state, route) {
+    state.visitedRoutes = state.visitedRoutes.filter(
+      (item) => item.meta.affix || item.path === route.path
+    )
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页左边全部多标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  delLeftVisitedRoutes(state, route) {
+    let index = state.visitedRoutes.length
+    state.visitedRoutes = state.visitedRoutes.filter((item) => {
+      if (item.name === route.name) index = state.visitedRoutes.indexOf(item)
+      return item.meta.affix || index <= state.visitedRoutes.indexOf(item)
+    })
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页右边全部多标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  delRightVisitedRoutes(state, route) {
+    let index = state.visitedRoutes.length
+    state.visitedRoutes = state.visitedRoutes.filter((item) => {
+      if (item.name === route.name) index = state.visitedRoutes.indexOf(item)
+      return item.meta.affix || index >= state.visitedRoutes.indexOf(item)
+    })
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除全部多标签页
+   * @param {*} state
+   * @param {*} route
+   * @returns
+   */
+  delAllVisitedRoutes(state) {
+    state.visitedRoutes = state.visitedRoutes.filter((item) => item.meta.affix)
+  },
+}
+const actions = {
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 添加标签页
+   * @param {*} { commit }
+   * @param {*} route
+   */
+  addVisitedRoute({ commit }, route) {
+    commit('addVisitedRoute', route)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页
+   * @param {*} { commit }
+   * @param {*} route
+   */
+  delVisitedRoute({ commit }, route) {
+    commit('delVisitedRoute', route)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页以外其它全部多标签页
+   * @param {*} { commit }
+   * @param {*} route
+   */
+  delOthersVisitedRoutes({ commit }, route) {
+    commit('delOthersVisitedRoutes', route)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页左边全部多标签页
+   * @param {*} { commit }
+   * @param {*} route
+   */
+  delLeftVisitedRoutes({ commit }, route) {
+    commit('delLeftVisitedRoutes', route)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除当前标签页右边全部多标签页
+   * @param {*} { commit }
+   * @param {*} route
+   */
+  delRightVisitedRoutes({ commit }, route) {
+    commit('delRightVisitedRoutes', route)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 删除全部多标签页
+   * @param {*} { commit }
+   */
+  delAllVisitedRoutes({ commit }) {
+    commit('delAllVisitedRoutes')
+  },
+}
+export default { state, getters, mutations, actions }

+ 148 - 0
src/store/modules/user.js

@@ -0,0 +1,148 @@
+/**
+ * @author chuzhixin 1204505056@qq.com
+ * @description 登录、获取用户信息、退出登录、清除accessToken逻辑,不建议修改
+ */
+import { getUserInfo, login, logout } from '@/api/user'
+import {
+  getAccessToken,
+  removeAccessToken,
+  setAccessToken,
+} from '@/utils/accessToken'
+import { title, tokenName } from '@/config'
+import { message, notification } from 'ant-design-vue'
+
+const state = () => ({
+  accessToken: getAccessToken(),
+  username: '',
+  avatar: '',
+})
+const getters = {
+  accessToken: (state) => state.accessToken,
+  username: (state) => state.username,
+  avatar: (state) => state.avatar,
+}
+const mutations = {
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 设置accessToken
+   * @param {*} state
+   * @param {*} accessToken
+   */
+  setAccessToken(state, accessToken) {
+    state.accessToken = accessToken
+    setAccessToken(accessToken)
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 设置用户名
+   * @param {*} state
+   * @param {*} username
+   */
+  setUsername(state, username) {
+    state.username = username
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 设置头像
+   * @param {*} state
+   * @param {*} avatar
+   */
+  setAvatar(state, avatar) {
+    state.avatar = avatar
+  },
+}
+const actions = {
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 登录拦截放行时,设置虚拟角色
+   * @param {*} { commit, dispatch }
+   */
+  setVirtualRoles({ commit, dispatch }) {
+    dispatch('acl/setFull', true, { root: true })
+    commit('setAvatar', 'https://i.gtimg.cn/club/item/face/img/2/15922_100.gif')
+    commit('setUsername', 'admin(未开启登录拦截)')
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 登录
+   * @param {*} { commit }
+   * @param {*} userInfo
+   */
+  async login({ commit }, userInfo) {
+    const { data } = await login(userInfo)
+    const accessToken = data[tokenName]
+    if (accessToken) {
+      commit('setAccessToken', accessToken)
+      const hour = new Date().getHours()
+      const thisTime =
+        hour < 8
+          ? '早上好'
+          : hour <= 11
+          ? '上午好'
+          : hour <= 13
+          ? '中午好'
+          : hour < 18
+          ? '下午好'
+          : '晚上好'
+      notification.open({
+        message: `欢迎登录${title}`,
+        description: `${thisTime}!`,
+      })
+    } else {
+      message.error(`登录接口异常,未正确返回${tokenName}...`)
+    }
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 获取用户信息接口 这个接口非常非常重要,如果没有明确底层前逻辑禁止修改此方法,错误的修改可能造成整个框架无法正常使用
+   * @param {*} { commit, dispatch, state }
+   * @returns
+   */
+  async getUserInfo({ commit, dispatch, state }) {
+    const { data } = await getUserInfo(state.accessToken)
+    if (!data) {
+      message.error(`验证失败,请重新登录...`)
+      return false
+    }
+    let { username, avatar, roles, ability } = data
+    if (username && roles && Array.isArray(roles)) {
+      dispatch('acl/setRole', roles, { root: true })
+      if (ability && ability.length > 0)
+        dispatch('acl/setAbility', ability, { root: true })
+      commit('setUsername', username)
+      commit('setAvatar', avatar)
+    } else {
+      message.error('用户信息接口异常')
+    }
+  },
+
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 退出登录
+   * @param {*} { dispatch }
+   */
+  async logout({ dispatch }) {
+    await logout(state.accessToken)
+    await dispatch('resetAll')
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 重置accessToken、roles、ability、router等
+   * @param {*} { commit, dispatch }
+   */
+  async resetAll({ dispatch }) {
+    await dispatch('setAccessToken', '')
+    await dispatch('acl/setFull', false, { root: true })
+    await dispatch('acl/setRole', [], { root: true })
+    await dispatch('acl/setAbility', [], { root: true })
+    removeAccessToken()
+  },
+  /**
+   * @author chuzhixin 1204505056@qq.com
+   * @description 设置token
+   */
+  setAccessToken({ commit }, accessToken) {
+    commit('setAccessToken', accessToken)
+  },
+}
+export default { state, getters, mutations, actions }

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini