Browse Source

项目初始化

王飞 1 year ago
commit
177cf25628
100 changed files with 6129 additions and 0 deletions
  1. 11 0
      .env.base
  2. 23 0
      .env.dev
  3. 23 0
      .env.gitee
  4. 23 0
      .env.pro
  5. 23 0
      .env.test
  6. 8 0
      .eslintignore
  7. 70 0
      .eslintrc.js
  8. 8 0
      .gitignore
  9. 10 0
      .prettierignore
  10. 6 0
      .stylelintignore
  11. 1015 0
      CHANGELOG.md
  12. 21 0
      LICENSE
  13. 144 0
      README.md
  14. 144 0
      README.zh-CN.md
  15. 28 0
      commitlint.config.js
  16. 142 0
      index.html
  17. 18 0
      mock/_createProductionServer.ts
  18. 89 0
      mock/analysis/index.ts
  19. 219 0
      mock/department/index.ts
  20. 63 0
      mock/dict/index.ts
  21. 248 0
      mock/menu/index.ts
  22. 1129 0
      mock/role/index.ts
  23. 256 0
      mock/table/index.ts
  24. 93 0
      mock/user/index.ts
  25. 172 0
      mock/workplace/index.ts
  26. 129 0
      package.json
  27. 11 0
      plop/component/component.hbs
  28. 3 0
      plop/component/index.hbs
  29. 38 0
      plop/component/prompt.js
  30. 37 0
      plop/view/prompt.js
  31. 7 0
      plop/view/view.hbs
  32. 7 0
      plopfile.js
  33. 5 0
      postcss.config.js
  34. 19 0
      prettier.config.js
  35. BIN
      public/favicon.ico
  36. BIN
      public/logo.png
  37. 71 0
      scripts/icon.ts
  38. 73 0
      src/App.vue
  39. 15 0
      src/api/common/index.ts
  40. 23 0
      src/api/dashboard/analysis/index.ts
  41. 22 0
      src/api/dashboard/analysis/types.ts
  42. 22 0
      src/api/dashboard/workplace/index.ts
  43. 30 0
      src/api/dashboard/workplace/types.ts
  44. 57 0
      src/api/department/index.ts
  45. 62 0
      src/api/department/types.ts
  46. 34 0
      src/api/login/index.ts
  47. 12 0
      src/api/login/types.ts
  48. 18 0
      src/api/manage/company.ts
  49. 26 0
      src/api/manage/dict.ts
  50. 18 0
      src/api/manage/file.ts
  51. 18 0
      src/api/manage/img.ts
  52. 22 0
      src/api/manage/news.ts
  53. 22 0
      src/api/manage/product.ts
  54. 76 0
      src/api/manage/types.ts
  55. 5 0
      src/api/menu/index.ts
  56. 5 0
      src/api/role/index.ts
  57. 22 0
      src/api/table/index.ts
  58. 22 0
      src/api/table/types.ts
  59. BIN
      src/assets/imgs/avatar.jpg
  60. BIN
      src/assets/imgs/favicon.ico
  61. BIN
      src/assets/imgs/logo.png
  62. 0 0
      src/assets/svgs/403.svg
  63. 0 0
      src/assets/svgs/404.svg
  64. 0 0
      src/assets/svgs/500.svg
  65. 1 0
      src/assets/svgs/icon.svg
  66. 0 0
      src/assets/svgs/login-bg.svg
  67. 0 0
      src/assets/svgs/login-box-bg.svg
  68. 1 0
      src/assets/svgs/message.svg
  69. 1 0
      src/assets/svgs/money.svg
  70. 1 0
      src/assets/svgs/peoples.svg
  71. 0 0
      src/assets/svgs/shopping.svg
  72. 3 0
      src/components/Backtop/index.ts
  73. 16 0
      src/components/Backtop/src/Backtop.vue
  74. 3 0
      src/components/Breadcrumb/index.ts
  75. 126 0
      src/components/Breadcrumb/src/Breadcrumb.vue
  76. 30 0
      src/components/Breadcrumb/src/helper.ts
  77. 3 0
      src/components/Collapse/index.ts
  78. 34 0
      src/components/Collapse/src/Collapse.vue
  79. 5 0
      src/components/ConfigGlobal/index.ts
  80. 62 0
      src/components/ConfigGlobal/src/ConfigGlobal.vue
  81. 5 0
      src/components/ConfigGlobal/src/types/index.ts
  82. 3 0
      src/components/ContentDetailWrap/index.ts
  83. 25 0
      src/components/ContentDetailWrap/src/ContentDetailWrap.vue
  84. 3 0
      src/components/ContentWrap/index.ts
  85. 36 0
      src/components/ContentWrap/src/ContentWrap.vue
  86. 12 0
      src/components/ContextMenu/index.ts
  87. 72 0
      src/components/ContextMenu/src/ContextMenu.vue
  88. 7 0
      src/components/ContextMenu/src/types/index.ts
  89. 3 0
      src/components/CountTo/index.ts
  90. 180 0
      src/components/CountTo/src/CountTo.vue
  91. 5 0
      src/components/Descriptions/index.ts
  92. 161 0
      src/components/Descriptions/src/Descriptions.vue
  93. 15 0
      src/components/Descriptions/src/types/index.ts
  94. 3 0
      src/components/Dialog/index.ts
  95. 132 0
      src/components/Dialog/src/Dialog.vue
  96. 3 0
      src/components/Echart/index.ts
  97. 113 0
      src/components/Echart/src/Echart.vue
  98. 8 0
      src/components/Editor/index.ts
  99. 137 0
      src/components/Editor/src/Editor.vue
  100. 3 0
      src/components/Error/index.ts

+ 11 - 0
.env.base

@@ -0,0 +1,11 @@
+# 环境
+NODE_ENV=development
+
+# 接口前缀
+VITE_API_BASE_PATH=base
+
+# 打包路径
+VITE_BASE_PATH=/
+
+# 标题
+VITE_APP_TITLE=网站后台管理

+ 23 - 0
.env.dev

@@ -0,0 +1,23 @@
+# 环境
+NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=dev
+
+# 打包路径
+VITE_BASE_PATH=/dist-dev/
+
+# 是否删除debugger
+VITE_DROP_DEBUGGER=false
+
+# 是否删除console.log
+VITE_DROP_CONSOLE=false
+
+# 是否sourcemap
+VITE_SOURCEMAP=true
+
+# 输出路径
+VITE_OUT_DIR=dist-dev
+
+# 标题
+VITE_APP_TITLE=网站后台管理

+ 23 - 0
.env.gitee

@@ -0,0 +1,23 @@
+# 环境
+NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=pro
+
+# 打包路径
+VITE_BASE_PATH=/vue-element-plus-admin/
+
+# 是否删除debugger
+VITE_DROP_DEBUGGER=true
+
+# 是否删除console.log
+VITE_DROP_CONSOLE=true
+
+# 是否sourcemap
+VITE_SOURCEMAP=false
+
+# 输出路径
+VITE_OUT_DIR=dist-pro
+
+# 标题
+VITE_APP_TITLE=网站后台管理

+ 23 - 0
.env.pro

@@ -0,0 +1,23 @@
+# 环境
+NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=pro
+
+# 打包路径
+VITE_BASE_PATH=/
+
+# 是否删除debugger
+VITE_DROP_DEBUGGER=true
+
+# 是否删除console.log
+VITE_DROP_CONSOLE=true
+
+# 是否sourcemap
+VITE_SOURCEMAP=false
+
+# 输出路径
+VITE_OUT_DIR=dist-pro
+
+# 标题
+VITE_APP_TITLE=网站后台管理

+ 23 - 0
.env.test

@@ -0,0 +1,23 @@
+# 环境
+NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=test
+
+# 打包路径
+VITE_BASE_PATH=/dist-test/
+
+# 是否删除debugger
+VITE_DROP_DEBUGGER=false
+
+# 是否删除console.log
+VITE_DROP_CONSOLE=false
+
+# 是否sourcemap
+VITE_SOURCEMAP=true
+
+# 输出路径
+VITE_OUT_DIR=dist-test
+
+# 标题
+VITE_APP_TITLE=网站后台管理

+ 8 - 0
.eslintignore

@@ -0,0 +1,8 @@
+/build/
+/config/
+/dist/
+/*.js
+/test/unit/coverage/
+/node_modules/*
+/dist*
+/src/main.ts

+ 70 - 0
.eslintrc.js

@@ -0,0 +1,70 @@
+// @ts-check
+const { defineConfig } = require('eslint-define-config')
+module.exports = defineConfig({
+  root: true,
+  env: {
+    browser: true,
+    node: true,
+    es6: true
+  },
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    parser: '@typescript-eslint/parser',
+    ecmaVersion: 2020,
+    sourceType: 'module',
+    jsxPragma: 'React',
+    ecmaFeatures: {
+      jsx: true
+    }
+  },
+  extends: [
+    'plugin:vue/vue3-recommended',
+    'plugin:@typescript-eslint/recommended',
+    'prettier',
+    'plugin:prettier/recommended'
+  ],
+  rules: {
+    'vue/no-setup-props-destructure': 'off',
+    'vue/script-setup-uses-vars': 'error',
+    'vue/no-reserved-component-names': 'off',
+    '@typescript-eslint/ban-ts-ignore': 'off',
+    '@typescript-eslint/explicit-function-return-type': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/no-var-requires': 'off',
+    '@typescript-eslint/no-empty-function': 'off',
+    'vue/custom-event-name-casing': 'off',
+    'no-use-before-define': 'off',
+    '@typescript-eslint/no-use-before-define': 'off',
+    '@typescript-eslint/ban-ts-comment': 'off',
+    '@typescript-eslint/ban-types': 'off',
+    '@typescript-eslint/no-non-null-assertion': 'off',
+    '@typescript-eslint/explicit-module-boundary-types': 'off',
+    '@typescript-eslint/no-unused-vars': 'off',
+    'no-unused-vars': 'off',
+    'space-before-function-paren': 'off',
+
+    'vue/attributes-order': 'off',
+    'vue/one-component-per-file': 'off',
+    'vue/html-closing-bracket-newline': 'off',
+    'vue/max-attributes-per-line': 'off',
+    'vue/multiline-html-element-content-newline': 'off',
+    'vue/singleline-html-element-content-newline': 'off',
+    'vue/attribute-hyphenation': 'off',
+    'vue/require-default-prop': 'off',
+    'vue/require-explicit-emits': 'off',
+    'vue/html-self-closing': [
+      'error',
+      {
+        html: {
+          void: 'always',
+          normal: 'never',
+          component: 'always'
+        },
+        svg: 'always',
+        math: 'always'
+      }
+    ],
+    'vue/multi-word-component-names': 'off',
+    'vue/no-v-html': 'off'
+  }
+})

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
+/dist*
+*-lock.*
+pnpm-debug

+ 10 - 0
.prettierignore

@@ -0,0 +1,10 @@
+/node_modules/**
+/dist/
+/dist*
+/public/*
+/docs/*
+/vite.config.ts
+/src/types/env.d.ts
+/docs/**/*
+/plop/**/*
+CHANGELOG

+ 6 - 0
.stylelintignore

@@ -0,0 +1,6 @@
+/dist/*
+/public/*
+public/*
+/dist*
+/src/types/env.d.ts
+/docs/**/*

+ 1015 - 0
CHANGELOG.md

@@ -0,0 +1,1015 @@
+# Changelog
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+## [2.2.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v2.1.0...v2.2.0) (2023-08-27)
+
+
+### Features
+
+* JsonEditor ([c0f4517](https://github.com/kailong321200875/vue-element-plus-admin/commit/c0f4517b87de5a0172a057fb9da141f758cca1fa))
+* 新增 useCrudSchemas demo ([ae0628e](https://github.com/kailong321200875/vue-element-plus-admin/commit/ae0628e3af3466c7c9d7b593b825f776843de5ec))
+* 新增useTagsView ([a869a45](https://github.com/kailong321200875/vue-element-plus-admin/commit/a869a457e6a8052531ce3040ae0d332d7afbb478))
+
+
+### Bug Fixes
+
+* [#316](https://github.com/kailong321200875/vue-element-plus-admin/issues/316) ([7582e4d](https://github.com/kailong321200875/vue-element-plus-admin/commit/7582e4d12f18ae86f5ef4ff36211c364afca5763))
+* [#317](https://github.com/kailong321200875/vue-element-plus-admin/issues/317) ([2095caa](https://github.com/kailong321200875/vue-element-plus-admin/commit/2095caaa854b686b57f47ee183419f42563a5a95))
+* [#318](https://github.com/kailong321200875/vue-element-plus-admin/issues/318) ([4169e52](https://github.com/kailong321200875/vue-element-plus-admin/commit/4169e52baaaa43765848c29c5ce222d019e81c35))
+* [#319](https://github.com/kailong321200875/vue-element-plus-admin/issues/319) ([b6ee4e5](https://github.com/kailong321200875/vue-element-plus-admin/commit/b6ee4e5d48deb3a07f289366ed3700baa3674cd6))
+* 修复useValidator报错 ([4912f6c](https://github.com/kailong321200875/vue-element-plus-admin/commit/4912f6c0586249b3de7ac7d365c8ea98af7923c7))
+* 修复动态路由无效 ([1452a1a](https://github.com/kailong321200875/vue-element-plus-admin/commit/1452a1afc77eb3f64cd3de91a05ddc15e40f4a06))
+
+
+### Docs
+
+* 更新README ([5b4defa](https://github.com/kailong321200875/vue-element-plus-admin/commit/5b4defa8c4be2de894b2cb50ae9ea739a10cf7d9))
+* 更新群二维码 ([13aa71c](https://github.com/kailong321200875/vue-element-plus-admin/commit/13aa71c5bd5b5076599501961a24a171a9133c57))
+* 更新群二维码 ([ae29e97](https://github.com/kailong321200875/vue-element-plus-admin/commit/ae29e974bfed2214d1beda703b976cdfa63070ab))
+
+
+### Styling
+
+* 修改Descriptions样式 ([cd0e05a](https://github.com/kailong321200875/vue-element-plus-admin/commit/cd0e05a6b9146af7ae64be62613724cd58e6c2a3))
+
+
+### Code Refactoring
+
+* 重构useValidator ([b8849da](https://github.com/kailong321200875/vue-element-plus-admin/commit/b8849dabe2b306831f69e84db167a367570d992a))
+
+
+### Performance Improvements
+
+* 优化动态路由 ([8793588](https://github.com/kailong321200875/vue-element-plus-admin/commit/879358821d02d5e4575dfee0d189b9fee7f2e217))
+* 完善useTagsView ([e0c55f4](https://github.com/kailong321200875/vue-element-plus-admin/commit/e0c55f40d4c1c47e29de6c4c7e9433efa978bf7f))
+* 完善useTagsView ([175abd0](https://github.com/kailong321200875/vue-element-plus-admin/commit/175abd0aa3388e8473f6ecbf63e28133fce55bd3))
+* 更新demo ([2c99cd2](https://github.com/kailong321200875/vue-element-plus-admin/commit/2c99cd20f0c25a740ac7a3a8319f7a112e69c0d3))
+
+## [2.1.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v2.0.0...v2.1.0) (2023-08-12)
+
+
+### Features
+
+* 新增多开标签页Demo ([5c253ce](https://github.com/kailong321200875/vue-element-plus-admin/commit/5c253ce803a9ef7ce03534ddd5f0865db4602378))
+
+
+### Bug Fixes
+
+* [#307](https://github.com/kailong321200875/vue-element-plus-admin/issues/307) ([4ce07e1](https://github.com/kailong321200875/vue-element-plus-admin/commit/4ce07e150c0bd3903cc5f43fcd88c2cb292d7690))
+* [#311](https://github.com/kailong321200875/vue-element-plus-admin/issues/311) ([bdde4cc](https://github.com/kailong321200875/vue-element-plus-admin/commit/bdde4ccd39d5d698d68b299c6e80546d4a8be89f))
+* 修复eslint错误 ([b5e47e0](https://github.com/kailong321200875/vue-element-plus-admin/commit/b5e47e04d8f5f889e0c46a2dced108d058ded94e))
+* 修复Table插槽传参错误 ([97344e6](https://github.com/kailong321200875/vue-element-plus-admin/commit/97344e68f5abb144d9e5d4ad273108858dbcfba2))
+* 修复Table组件插槽传参错误 ([c83a026](https://github.com/kailong321200875/vue-element-plus-admin/commit/c83a026d559e2854fead17d2e28fbebcf25490de))
+
+
+### Docs
+
+* 修改Readme ([ee059b7](https://github.com/kailong321200875/vue-element-plus-admin/commit/ee059b7619ad01ded9d3be20287086ddbcce3253))
+* 修改Readme ([e05f5a7](https://github.com/kailong321200875/vue-element-plus-admin/commit/e05f5a77edc175daa267e4fc6abbcfc8fec2e291))
+* 修改Readme ([b0e561d](https://github.com/kailong321200875/vue-element-plus-admin/commit/b0e561d8acd36e8780087e317cc34257956981fd))
+* 修改Readme ([fced2e0](https://github.com/kailong321200875/vue-element-plus-admin/commit/fced2e0087694445a89cf360e5e3e3013d8ca604))
+* 修改README ([dce76f0](https://github.com/kailong321200875/vue-element-plus-admin/commit/dce76f042d5243039540828a3fd982af25f37531))
+* 更新群二维码 ([607ef58](https://github.com/kailong321200875/vue-element-plus-admin/commit/607ef585d010c9ade6f54d96c2a12b36099ece74))
+
+
+### Styling
+
+* 修改TabMenu样式 ([e8cd6f9](https://github.com/kailong321200875/vue-element-plus-admin/commit/e8cd6f9e1c4387c582e461cde4d59796bf17c1bd))
+
+## [2.0.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.10.0...v2.0.0) (2023-08-06)
+
+
+### ⚠ BREAKING CHANGES
+
+* 重构完成
+
+### Features
+
+* 重构完成 ([76e971e](https://github.com/kailong321200875/vue-element-plus-admin/commit/76e971ef96ad4f5cc7df58abd0559898ce70207d))
+
+
+### Code Refactoring
+
+* 重构完成 ([85f8cda](https://github.com/kailong321200875/vue-element-plus-admin/commit/85f8cda19d8cafb951f211b845aad970a661dd1e))
+* 重构完成 ([5d55597](https://github.com/kailong321200875/vue-element-plus-admin/commit/5d55597cca6c9d2bc6cb6211a01c161fa5f086ba))
+
+## [1.10.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.9...v1.10.0) (2023-08-06)
+
+
+### Types
+
+* Form类型调整 ([a0f4aeb](https://github.com/kailong321200875/vue-element-plus-admin/commit/a0f4aebc5a685366cd56b1a7bb39fa614976e3bb))
+* Form类型调整 ([674d760](https://github.com/kailong321200875/vue-element-plus-admin/commit/674d760029b451c0c6fc23a2aeac5c83992a0b27))
+* 修改类型 ([c3ac191](https://github.com/kailong321200875/vue-element-plus-admin/commit/c3ac1915045d4d59bca09ec6d19151bc5da342f1))
+* 修改类型 ([7d0476f](https://github.com/kailong321200875/vue-element-plus-admin/commit/7d0476f47c5858019db871cff2bdd19f0210f0d4))
+* 类型优化 ([283bc58](https://github.com/kailong321200875/vue-element-plus-admin/commit/283bc58d46151a8954bb81ee6bf8f499177b15fc))
+* 调整类型 ([24c8af9](https://github.com/kailong321200875/vue-element-plus-admin/commit/24c8af91835fb2c8c00e7c2673fff01f098c9944))
+* 迁移types ([ccbec86](https://github.com/kailong321200875/vue-element-plus-admin/commit/ccbec865568b1c9b3c3321d7071c164fdc350a0f))
+* 迁移types ([46b35e4](https://github.com/kailong321200875/vue-element-plus-admin/commit/46b35e48b3e7876c74159625b5149ef663396f5c))
+
+
+### Features
+
+* axios 改造 ([3238140](https://github.com/kailong321200875/vue-element-plus-admin/commit/32381408bbe418eeaca2a975305bac80ddaa03f5))
+* axios 改造 ([5807db1](https://github.com/kailong321200875/vue-element-plus-admin/commit/5807db1dc12a7ff2dbf66801a742a78974ad8f9c))
+* Descriptions组件重构 ([49e415d](https://github.com/kailong321200875/vue-element-plus-admin/commit/49e415d27788cb468c96f2a828f1df7ae65b7a3c))
+* Dialog组件重构 ([3701a04](https://github.com/kailong321200875/vue-element-plus-admin/commit/3701a04231af02ec7f7ef73533f3a22e707380fb))
+* Form useForm 完成 ([3e4e27c](https://github.com/kailong321200875/vue-element-plus-admin/commit/3e4e27c21fd59c944229856bee929f005d2ee140))
+* Form改造 ([9c724dc](https://github.com/kailong321200875/vue-element-plus-admin/commit/9c724dc9aad18397d5ecd00e53c3c24e142a34b5))
+* Icon改版 ([882f162](https://github.com/kailong321200875/vue-element-plus-admin/commit/882f162ff21c74239b638f284f52161e5791722d))
+* Radio改造 ([deeee73](https://github.com/kailong321200875/vue-element-plus-admin/commit/deeee73bcb3ad912844fddee62b1155d95d4b42b))
+* Radio改造 ([83513d5](https://github.com/kailong321200875/vue-element-plus-admin/commit/83513d519d4b6b8fbfd48db266b9bd7b3a998d63))
+* Search组件重构 ([a7f3702](https://github.com/kailong321200875/vue-element-plus-admin/commit/a7f370214481577ab82bf2871191dda717c7978a))
+* SelectV2改造完成 ([4d04734](https://github.com/kailong321200875/vue-element-plus-admin/commit/4d04734e13f6926c16aeee421feecb0d339534f0))
+* Table重构 ([94800b0](https://github.com/kailong321200875/vue-element-plus-admin/commit/94800b0120ee05ca7d534dda3e59653f38d7fda0))
+* 完善search组件demo ([cdf44a4](https://github.com/kailong321200875/vue-element-plus-admin/commit/cdf44a43a05010dbcba3a3ec0cb7c8251f16fce3))
+* 拖拽表格 ([b69b8ed](https://github.com/kailong321200875/vue-element-plus-admin/commit/b69b8ed1bde36100fc86e51fcc63805d4ea21210))
+* 新增TreeSelect表单项 ([de0cb43](https://github.com/kailong321200875/vue-element-plus-admin/commit/de0cb43566b9065250abbc71548ffeca4c8e8bf1))
+* 新增Uload ([c181887](https://github.com/kailong321200875/vue-element-plus-admin/commit/c181887f7f0c5eecc9584edfe99e9065440bdc56))
+* 新增useStorage ([dfea91c](https://github.com/kailong321200875/vue-element-plus-admin/commit/dfea91c7e1d18fa299067c62557cac61723ea861))
+* 新增权限测试页 ([3fe40ba](https://github.com/kailong321200875/vue-element-plus-admin/commit/3fe40ba62df29c2ffea9adfd65fc559489481e24))
+* 新增锁屏功能 ([e2fd349](https://github.com/kailong321200875/vue-element-plus-admin/commit/e2fd349070147c57f9400fa9a413260b7707bda2))
+* 用户列表重构 ([755cea0](https://github.com/kailong321200875/vue-element-plus-admin/commit/755cea0990d9e3b64c936f29c02e4053393a1a19))
+* 登录页改造 ([5312951](https://github.com/kailong321200875/vue-element-plus-admin/commit/5312951359b5d919b6c1a03783aa6bbaf8ec0044))
+* 综合示例重构 ([9a0259d](https://github.com/kailong321200875/vue-element-plus-admin/commit/9a0259de5c47970502db95f4dda24998ad5d9efe))
+* 菜单管理 ([c72b3a3](https://github.com/kailong321200875/vue-element-plus-admin/commit/c72b3a33aab7d3605770a64d23b8a84ef4ad68d2))
+* 角色管理 ([47016a5](https://github.com/kailong321200875/vue-element-plus-admin/commit/47016a535f2b7a22ab498bee197bc30a983f507d))
+* 部门管理 ([28d0785](https://github.com/kailong321200875/vue-element-plus-admin/commit/28d0785be842022cae7808c23e1f19eaab5fb996))
+* 重构Dialog组件示例 ([9a78ac9](https://github.com/kailong321200875/vue-element-plus-admin/commit/9a78ac977eb0cfb3bd6c2a9b96e69d9f010017f4))
+
+
+### Bug Fixes
+
+* mock数据 ([8bdac71](https://github.com/kailong321200875/vue-element-plus-admin/commit/8bdac7152f463cd98c50c9893a46bb6c111fd428))
+* 修复Form已知问题 ([097b32e](https://github.com/kailong321200875/vue-element-plus-admin/commit/097b32e1a9d92a609a66179d68b3dabe12f96b66))
+* 修复Table组件已知问题 ([b1a83f6](https://github.com/kailong321200875/vue-element-plus-admin/commit/b1a83f601838cb82fb29c036654a4cdc729997cd))
+* 修复类型错误 ([26dc886](https://github.com/kailong321200875/vue-element-plus-admin/commit/26dc886f8ccb5cf1ffc10e1d9601c827a1f960c2))
+* 样式问题修复 ([cdc7c76](https://github.com/kailong321200875/vue-element-plus-admin/commit/cdc7c76eb5ac3ccb79f5f55ff5b7ce6b8c4955e1))
+* 解决类型检测报错 ([9d93496](https://github.com/kailong321200875/vue-element-plus-admin/commit/9d9349600b3d2008e4216d49c9fa1c1b9995fa79))
+* 解决类型检测报错 ([513108c](https://github.com/kailong321200875/vue-element-plus-admin/commit/513108c00e622812e2e70dfe833435f6b5462d6e))
+* 解决类型检测报错 ([28bf8be](https://github.com/kailong321200875/vue-element-plus-admin/commit/28bf8bee45e3cc8575a356623abdbe56e30991f8))
+
+
+### Styling
+
+* Table样式修改 ([5fc57bd](https://github.com/kailong321200875/vue-element-plus-admin/commit/5fc57bdb08488f6898eafd6f28289b0567d6d9e2))
+* Table样式修改 ([411c0f7](https://github.com/kailong321200875/vue-element-plus-admin/commit/411c0f792ae8359c49e81974d8193f049120985b))
+* Table样式修改 ([d487c6a](https://github.com/kailong321200875/vue-element-plus-admin/commit/d487c6a93ec0281d76a3938e6e23ea2a4a7940c1))
+* Table样式修改 ([c7d21e3](https://github.com/kailong321200875/vue-element-plus-admin/commit/c7d21e36d012377ba863ac848d77abb5db4f475a))
+* Table样式修改 ([7f5078a](https://github.com/kailong321200875/vue-element-plus-admin/commit/7f5078a436c4d5abcaf7a420df35d2be9b3680c5))
+* 修改Dialog样式 ([e451bfc](https://github.com/kailong321200875/vue-element-plus-admin/commit/e451bfcde6e5a47d4b3022e240ffcc0576ebb9a8))
+* 修改样式 ([207c5b3](https://github.com/kailong321200875/vue-element-plus-admin/commit/207c5b3fc4e52bb06baa36cd4b659e14893785ba))
+* 完善角色管理 ([c4576bd](https://github.com/kailong321200875/vue-element-plus-admin/commit/c4576bd57bcf504733f20188202ea7d33ab1c184))
+* 布局样式优化 ([962689a](https://github.com/kailong321200875/vue-element-plus-admin/commit/962689a8bd0ed5eb17d946b8a21dec4a197f13a7))
+* 样式布局调整完成 ([7193176](https://github.com/kailong321200875/vue-element-plus-admin/commit/719317694f71e22692256bb557070343f034ffe5))
+* 用户管理样式修改 ([57a5fa7](https://github.com/kailong321200875/vue-element-plus-admin/commit/57a5fa7b82ae9f3d7a1f8ec5391f14b1d1cd32e8))
+* 移除不必要样式 ([7ef1d1e](https://github.com/kailong321200875/vue-element-plus-admin/commit/7ef1d1e3013cc5bf7fc574e67c2004f50792e66d))
+* 移除不必要样式 ([366db45](https://github.com/kailong321200875/vue-element-plus-admin/commit/366db4528254d18659e6a922817702b5b92a57b0))
+* 调整Icon悬停样式 ([64c7e48](https://github.com/kailong321200875/vue-element-plus-admin/commit/64c7e48bd18ba83e605daccbc4c2f4cc6b58695d))
+* 调整工作台样式错乱 ([cc18f29](https://github.com/kailong321200875/vue-element-plus-admin/commit/cc18f297ef50655d5773d01fcfddabc365dc53e7))
+
+
+### Performance Improvements
+
+* Dialog默认高度修改 ([0e04fce](https://github.com/kailong321200875/vue-element-plus-admin/commit/0e04fce4367d6829e8de97a249318b0309e06fd5))
+* Form Table Search Descriptions 支持嵌套赋值 ([46ddf62](https://github.com/kailong321200875/vue-element-plus-admin/commit/46ddf62d2d4ce1a653f47695cb0bb3475aa16bd8))
+* ImageViewer组件优化 ([3b9c3d8](https://github.com/kailong321200875/vue-element-plus-admin/commit/3b9c3d8b757646eaf74625403112a969bfd15e55))
+* 优化Form事件传递 ([69cafb3](https://github.com/kailong321200875/vue-element-plus-admin/commit/69cafb3b7b2ce7ecbd9f2e8ef09e250817e9a55c))
+* 优化Search组件 ([e548668](https://github.com/kailong321200875/vue-element-plus-admin/commit/e548668ccef8c41d9ac7d9fe39ffe66471d160d2))
+* 优化表单组件 ([77a3866](https://github.com/kailong321200875/vue-element-plus-admin/commit/77a38662488ab9ff4cbe5ff3cf9b65eea34abca1))
+* 优化锁屏组件 ([4f8330a](https://github.com/kailong321200875/vue-element-plus-admin/commit/4f8330a4faf6cc98a9bac17bd3e1719ae1b30c81))
+
+## [1.9.9](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.8...v1.9.9) (2023-04-13)
+
+
+### Bug Fixes
+
+* 使用动态路由时,多级路由只有一个子路且父路由未使用alwaysShow时,子路由未添加至路由中 ([9b330a1](https://github.com/kailong321200875/vue-element-plus-admin/commit/9b330a1f513d3af9233b9a9dde6bdfeeefbc3393))
+
+## [1.9.8](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.7...v1.9.8) (2023-04-12)
+
+
+### Bug Fixes
+
+* 修复已知问题 ([0a6f306](https://github.com/kailong321200875/vue-element-plus-admin/commit/0a6f306686ea024e30bcdccac34e485b8526e38f))
+
+## [1.9.7](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.6...v1.9.7) (2023-03-28)
+
+
+### Bug Fixes
+
+* 修复表格与搜索框字段不能不一致的问题 ([5c1cd29](https://github.com/kailong321200875/vue-element-plus-admin/commit/5c1cd298defefb36b858adc766b776a0a7b9bd66))
+
+## [1.9.6](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.5...v1.9.6) (2023-03-22)
+
+
+### Bug Fixes
+
+* 修改 Editor 的 z-index 使其不会遮挡『综合示例 - 新增』界面的下拉菜单 ([c046e45](https://github.com/kailong321200875/vue-element-plus-admin/commit/c046e4554ba8fd99614484d8fb636650072b833e))
+
+## [1.9.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.4...v1.9.5) (2023-03-13)
+
+
+### Bug Fixes
+
+* 面包屑:1.修复使用动态路由的时候,无法显示的bug ([8790c8c](https://github.com/kailong321200875/vue-element-plus-admin/commit/8790c8cbd8d63ea0f8f276fd5af006f39b06e7d3))
+
+## [1.9.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.3...v1.9.4) (2023-03-03)
+
+
+### Bug Fixes
+
+* 修复已知BUG ([782b8e2](https://github.com/kailong321200875/vue-element-plus-admin/commit/782b8e2f94c867c3ee282287c37c888fff93fc55))
+
+## [1.9.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.2...v1.9.3) (2023-03-01)
+
+
+### Types
+
+* 修复类型错误 ([297b2c6](https://github.com/kailong321200875/vue-element-plus-admin/commit/297b2c69a239b487126c3b9316645a1b5f06bb7c))
+
+
+### Styling
+
+* 抽屉弹出样式问题 ([16a3eef](https://github.com/kailong321200875/vue-element-plus-admin/commit/16a3eef85a1ffb296bd44f67d89a911ecaf1c25e))
+* 调整主题切换样式 ([6e6beef](https://github.com/kailong321200875/vue-element-plus-admin/commit/6e6beefc3c380f7297985adcabcf966fbd2c5197))
+
+## [1.9.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.1...v1.9.2) (2023-01-16)
+
+
+### Bug Fixes
+
+* 修复TS类型错误 ([1c06a27](https://github.com/kailong321200875/vue-element-plus-admin/commit/1c06a27b900a891cd0b47098062cebc984ff6505))
+
+## [1.9.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.9.0...v1.9.1) (2023-01-11)
+
+
+### Bug Fixes
+
+* dark mode toggle ([bbc7646](https://github.com/kailong321200875/vue-element-plus-admin/commit/bbc764601ec864c2fdbe3ad78c083c5ae80615e0))
+
+## [1.9.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.7...v1.9.0) (2022-12-28)
+
+
+### Features
+
+* 添加打包进度条 ([354e87f](https://github.com/kailong321200875/vue-element-plus-admin/commit/354e87f7c533ad8e93ef484b47d0fe16f17048c9))
+
+
+### Bug Fixes
+
+* husky ([6fe5b2e](https://github.com/kailong321200875/vue-element-plus-admin/commit/6fe5b2e6c781b251bff5f0ac936c04dcfe5ef95f))
+
+## [1.8.7](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.6...v1.8.7) (2022-12-05)
+
+
+### Bug Fixes
+
+* 解决iframe无法正常工作 ([4fcc46f](https://github.com/kailong321200875/vue-element-plus-admin/commit/4fcc46fccf747b47909e2079c4f2abc5dbfb1a0c))
+
+## [1.8.6](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.5...v1.8.6) (2022-11-21)
+
+
+### Bug Fixes
+
+* 修复Search组件无法默认值 ([3368fda](https://github.com/kailong321200875/vue-element-plus-admin/commit/3368fda251bd3ff5a8e0059b3b33f9c0339d236b))
+
+## [1.8.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.4...v1.8.5) (2022-11-17)
+
+
+### Bug Fixes
+
+* 修复Form赋值问题 ([f37cc1b](https://github.com/kailong321200875/vue-element-plus-admin/commit/f37cc1b5801add3ada168dbbcf4cd2c340f0e30d))
+
+## [1.8.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.3...v1.8.4) (2022-11-07)
+
+
+### Bug Fixes
+
+* 修复option禁用属性无效 ([0b671e9](https://github.com/kailong321200875/vue-element-plus-admin/commit/0b671e914e396c7666ad5e34768a6e29f7dfbd33))
+
+
+### Styling
+
+* input默认宽度与select对齐 ([0b671e9](https://github.com/kailong321200875/vue-element-plus-admin/commit/0b671e914e396c7666ad5e34768a6e29f7dfbd33))
+
+## [1.8.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.2...v1.8.3) (2022-10-28)
+
+
+### Performance Improvements
+
+* 优化描述组件 ([73ecc98](https://github.com/kailong321200875/vue-element-plus-admin/commit/73ecc98671d430013920246d98ce9ab1752e56eb))
+
+## [1.8.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.1...v1.8.2) (2022-10-18)
+
+
+### Bug Fixes
+
+* Correct spelling of words(aciton →action) ([eb405b2](https://github.com/kailong321200875/vue-element-plus-admin/commit/eb405b2a9041ca0ad4455db79bf617ec910dc485))
+* Correct spelling of words(tigger →trigger) ([c2ca2d7](https://github.com/kailong321200875/vue-element-plus-admin/commit/c2ca2d736c92e02380923a6741450844acb41a38))
+
+## [1.8.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.8.0...v1.8.1) (2022-10-11)
+
+
+### Bug Fixes
+
+* 修复cutMenu收起时 ([993af6b](https://github.com/kailong321200875/vue-element-plus-admin/commit/993af6bb6576249e66e0c0ea592ebf851f65ab8c))
+
+
+### Styling
+
+* cutMenu层级样式 ([32d2408](https://github.com/kailong321200875/vue-element-plus-admin/commit/32d2408588c487cff2cf73e3cc132e5105ff4459))
+
+## [1.8.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.7.1...v1.8.0) (2022-10-10)
+
+
+### Features
+
+* types优化 ([3351155](https://github.com/kailong321200875/vue-element-plus-admin/commit/33511553cd9055b036b2d7491f9c2eda123f8b22))
+
+
+### Styling
+
+* 优化第四种布局 ([122fa62](https://github.com/kailong321200875/vue-element-plus-admin/commit/122fa62d859413d16175e0d97c7bf13f232dbb3a))
+
+## [1.7.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.7.0...v1.7.1) (2022-10-10)
+
+
+### Bug Fixes
+
+* 修正types提示错误 ([ef3e006](https://github.com/kailong321200875/vue-element-plus-admin/commit/ef3e006859dcd8b93ffb7cffcaeae24cbb330f2a))
+
+## [1.7.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.6...v1.7.0) (2022-10-09)
+
+
+### Features
+
+* type抽离 ([8b4fa1a](https://github.com/kailong321200875/vue-element-plus-admin/commit/8b4fa1aa21aa2c1379288315ccd64a6f3375be51))
+
+## [1.6.6](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.5...v1.6.6) (2022-10-09)
+
+
+### Bug Fixes
+
+* table search params ([a62929a](https://github.com/kailong321200875/vue-element-plus-admin/commit/a62929a8dac21028d3dd1cddf98189492c33b093))
+
+## [1.6.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.4...v1.6.5) (2022-10-08)
+
+
+### Bug Fixes
+
+* The attribute of option does not work ([d946920](https://github.com/kailong321200875/vue-element-plus-admin/commit/d946920e61ed81beacf9f1f8be7ee1f50505f64d))
+
+
+### Performance Improvements
+
+* perf store ([d416178](https://github.com/kailong321200875/vue-element-plus-admin/commit/d416178d69ca6100be4b635922b1a22d27629f08))
+* token test ([b320e65](https://github.com/kailong321200875/vue-element-plus-admin/commit/b320e658d1a559a6eaebdf374d63649c223c2ecd))
+
+## [1.6.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.3...v1.6.4) (2022-09-21)
+
+
+### Bug Fixes
+
+* fix bug ([da39f3b](https://github.com/kailong321200875/vue-element-plus-admin/commit/da39f3bc904ca2d80f432a31709725f9a57deb19))
+
+## [1.6.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.2...v1.6.3) (2022-08-20)
+
+
+### Bug Fixes
+
+* 修复重定向错误 ([89d03fd](https://github.com/kailong321200875/vue-element-plus-admin/commit/89d03fd067e7aca565ceb84ea9276f340bbfcb60))
+
+
+### Styling
+
+* 调整样式 ([d29e151](https://github.com/kailong321200875/vue-element-plus-admin/commit/d29e151f8a660031a685f6ef9f789532b1b7b58b))
+
+## [1.6.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.1...v1.6.2) (2022-08-13)
+
+
+### Styling
+
+* Misspelling ([c43e833](https://github.com/kailong321200875/vue-element-plus-admin/commit/c43e833582e4f14ac78b0683f1eb3bdeb9fb4821))
+* perfect tableDemo ([c589edd](https://github.com/kailong321200875/vue-element-plus-admin/commit/c589edd960b23ad0c8b56d2c7880b61014114d45))
+
+
+### Code Refactoring
+
+* refactor axios ([0980640](https://github.com/kailong321200875/vue-element-plus-admin/commit/0980640f65fc80e3e58ba49e98db10b7b1b80077))
+
+## [1.6.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.6.0...v1.6.1) (2022-07-30)
+
+
+### Bug Fixes
+
+* fix menu active bug ([ff59fc7](https://github.com/kailong321200875/vue-element-plus-admin/commit/ff59fc7e133202945360a7e210f9cdf3a4a89dd7))
+* Pie chart data not updated ([55d4ce7](https://github.com/kailong321200875/vue-element-plus-admin/commit/55d4ce7e35ff9a0c5590bc3589160cfd304d3ae5))
+
+
+### Performance Improvements
+
+* add static router ([55522b0](https://github.com/kailong321200875/vue-element-plus-admin/commit/55522b0661a8df3ad3c8afafcc9f8fcb162c5a00))
+
+
+### Styling
+
+* tagviews styles update ([bff7d93](https://github.com/kailong321200875/vue-element-plus-admin/commit/bff7d9370db7a9c171828721bb99643dac2f235d))
+
+## [1.6.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.4...v1.6.0) (2022-07-18)
+
+
+### Features
+
+* 添加按钮权限 ([7bef662](https://github.com/kailong321200875/vue-element-plus-admin/commit/7bef662db1e91aa8164e9f7a92de3fe4480a3c3b))
+
+
+### Performance Improvements
+
+* 移除md5依赖 ([a123097](https://github.com/kailong321200875/vue-element-plus-admin/commit/a123097f1f38eac45e945c7d3fdccafc16ea9b69))
+
+
+### Styling
+
+* 压缩图片尺寸 ([ae3c565](https://github.com/kailong321200875/vue-element-plus-admin/commit/ae3c5657b604ffbdae5ce3ce3603626ad4acc5e5))
+
+
+### Docs
+
+* vite2 to vite3 ([b3918b9](https://github.com/kailong321200875/vue-element-plus-admin/commit/b3918b9c3c5de4b48811ec95967851cfb3c231e1))
+* vite2 to vite3 ([aaf07de](https://github.com/kailong321200875/vue-element-plus-admin/commit/aaf07de77aa600332880a894faa35757f787c012))
+
+## [1.6.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.4...v1.6.0) (2022-07-18)
+
+
+### Features
+
+* 添加按钮权限 ([7bef662](https://github.com/kailong321200875/vue-element-plus-admin/commit/7bef662db1e91aa8164e9f7a92de3fe4480a3c3b))
+
+
+### Performance Improvements
+
+* 移除md5依赖 ([a123097](https://github.com/kailong321200875/vue-element-plus-admin/commit/a123097f1f38eac45e945c7d3fdccafc16ea9b69))
+
+
+### Styling
+
+* 压缩图片尺寸 ([ae3c565](https://github.com/kailong321200875/vue-element-plus-admin/commit/ae3c5657b604ffbdae5ce3ce3603626ad4acc5e5))
+
+
+### Docs
+
+* vite2 to vite3 ([b3918b9](https://github.com/kailong321200875/vue-element-plus-admin/commit/b3918b9c3c5de4b48811ec95967851cfb3c231e1))
+* vite2 to vite3 ([aaf07de](https://github.com/kailong321200875/vue-element-plus-admin/commit/aaf07de77aa600332880a894faa35757f787c012))
+
+## [1.5.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.3...v1.5.4) (2022-07-16)
+
+
+### Bug Fixes
+
+* fix build:test error ([14530cf](https://github.com/kailong321200875/vue-element-plus-admin/commit/14530cf790bfbbe37c72fa831f0376bbb4209e9d))
+
+## [1.5.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.2...v1.5.3) (2022-07-01)
+
+
+### Bug Fixes
+
+* fix useCrudSchemas not work ([0a855b9](https://github.com/kailong321200875/vue-element-plus-admin/commit/0a855b93e282dfe7863b3fce31dde5d7e0d3e2b6))
+
+## [1.5.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.1...v1.5.2) (2022-07-01)
+
+
+### Performance Improvements
+
+* add useCrudSchemas demo ([ca3ce54](https://github.com/kailong321200875/vue-element-plus-admin/commit/ca3ce54630b723d87415b14c642440d6734876ff))
+
+## [1.5.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.5.0...v1.5.1) (2022-07-01)
+
+
+### Bug Fixes
+
+* change showMainRoute to canTo ([5e292f8](https://github.com/kailong321200875/vue-element-plus-admin/commit/5e292f8a2b2ded7297a2a76893e113ac81517d23))
+
+
+### Performance Improvements
+
+* dialog combine with form ([34aefb6](https://github.com/kailong321200875/vue-element-plus-admin/commit/34aefb64ab9237521a1225925264818eebff9ad3))
+* dynamic options demo ([1acb4d7](https://github.com/kailong321200875/vue-element-plus-admin/commit/1acb4d7e8f449ba342699f1b4387ac2404a4c1fb))
+* dynamic options demo ([9a3b617](https://github.com/kailong321200875/vue-element-plus-admin/commit/9a3b6177aa0fbc99c86c5073a1c6c696e1eaf890))
+* useCrudSchemas cutom label ([7864d83](https://github.com/kailong321200875/vue-element-plus-admin/commit/7864d830e2134d814609e722b7bad1754ea9460e))
+
+## [1.5.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.5...v1.5.0) (2022-06-25)
+
+
+### Features
+
+* refactoring API ([37b7583](https://github.com/kailong321200875/vue-element-plus-admin/commit/37b75839a591648b145065432efb1dc8c7a3b917))
+
+
+### Bug Fixes
+
+* 修复axios已知问题 ([537af57](https://github.com/kailong321200875/vue-element-plus-admin/commit/537af57a0aaa24c88ebe75acf52dc0403a58b04b))
+
+
+### Performance Improvements
+
+* perf axios config ([39edd84](https://github.com/kailong321200875/vue-element-plus-admin/commit/39edd84023109a84683c21ea33e41bd024756520))
+
+## [1.4.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.4...v1.4.5) (2022-06-09)
+
+
+### Bug Fixes
+
+* fix tagsview not work ([d88e051](https://github.com/kailong321200875/vue-element-plus-admin/commit/d88e0514349e877f1c5280a48f9b1bd2bfd622bf))
+* fix tagsview not work ([1bf2d4c](https://github.com/kailong321200875/vue-element-plus-admin/commit/1bf2d4c77287fdca7ed1cb8c9998a53f1375dc6f))
+
+
+### Types
+
+* fix types error ([586486a](https://github.com/kailong321200875/vue-element-plus-admin/commit/586486a68d4bf2a024e50a79945b4007324f642d))
+
+## [1.4.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.3...v1.4.4) (2022-06-06)
+
+
+### Types
+
+* fix type error ([d66f12e](https://github.com/kailong321200875/vue-element-plus-admin/commit/d66f12e0e77f6acf485bae06509d9ea4abcd1eaa))
+
+### [1.4.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.2...v1.4.3) (2022-06-01)
+
+
+### Bug Fixes
+
+* multiple requests when pageSize change and currentPage isn't 1 ([f71a250](https://github.com/kailong321200875/vue-element-plus-admin/commit/f71a2503bc521c01e7102feecf4ec39a5224a6bb))
+
+### [1.4.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.1...v1.4.2) (2022-05-15)
+
+
+### Styling
+
+* fix dark mode bug ([2f9fd5d](https://github.com/kailong321200875/vue-element-plus-admin/commit/2f9fd5d21550d771ec12ae3540b975e2eebcd25b))
+
+### [1.4.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.4.0...v1.4.1) (2022-05-12)
+
+
+### Bug Fixes
+
+* the warning of VSCode extensions ([a368c21](https://github.com/kailong321200875/vue-element-plus-admin/commit/a368c21fb9c41f98f31f51586a2023076a8a9132))
+
+## [1.4.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.3.2...v1.4.0) (2022-05-10)
+
+
+### Features
+
+* add dark mode ([0758a6a](https://github.com/kailong321200875/vue-element-plus-admin/commit/0758a6a9d83170e53d45d39c3313e52ff5885746))
+
+### [1.3.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.3.1...v1.3.2) (2022-05-07)
+
+
+### Bug Fixes
+
+* fix the problem that the page is stuck in top mode ([8d01f48](https://github.com/kailong321200875/vue-element-plus-admin/commit/8d01f48d5098195b10c03b3cb3a0f485ebc9e018))
+
+### [1.3.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.3.0...v1.3.1) (2022-05-06)
+
+
+### Bug Fixes
+
+* spelling 'useRenderChcekbox' ([ee92f03](https://github.com/kailong321200875/vue-element-plus-admin/commit/ee92f039bea4307ccfb819728d3e2ed04fa00e03))
+
+## [1.3.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.13...v1.3.0) (2022-04-26)
+
+
+### Features
+
+* add useCrudSchemas hook ([00d947e](https://github.com/kailong321200875/vue-element-plus-admin/commit/00d947e2f81105194b0622d33768f999e37ad28a))
+
+
+### Bug Fixes
+
+* fix Table slot warning ([0eac05d](https://github.com/kailong321200875/vue-element-plus-admin/commit/0eac05d4f973ff7b15e00973f6e96595a3cd6d43))
+
+
+### Code Refactoring
+
+* refactor useAxios ([185f1e6](https://github.com/kailong321200875/vue-element-plus-admin/commit/185f1e6e210ecaac28ebfdee4198b7ca2eaa0933))
+
+
+### Build System
+
+* add url ([ab0f59a](https://github.com/kailong321200875/vue-element-plus-admin/commit/ab0f59ac91a077cf060923fa76e6d57e05d0b21b))
+* update plugins ([c475a61](https://github.com/kailong321200875/vue-element-plus-admin/commit/c475a610c19094034306f2dc665e240c7c117f87))
+* update plugins ([dfedbc7](https://github.com/kailong321200875/vue-element-plus-admin/commit/dfedbc74fdb2c819a96b6263849bdaab59b9e337))
+
+### [1.2.13](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.12...v1.2.13) (2022-04-18)
+
+
+### Performance Improvements
+
+* Editor component support v-model ([d77f8e3](https://github.com/kailong321200875/vue-element-plus-admin/commit/d77f8e334d77ee43c9ee0f411733f7397b278bc0))
+
+### [1.2.12](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.11...v1.2.12) (2022-04-17)
+
+
+### Bug Fixes
+
+* fixed spelling 'ElememtPlusSzie' ([5dbbc60](https://github.com/kailong321200875/vue-element-plus-admin/commit/5dbbc608640d93fe68fec6f58fdb30a43e02aada))
+
+### [1.2.11](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.10...v1.2.11) (2022-04-14)
+
+
+### Bug Fixes
+
+* fix the error reported by the Editor component ([7dc6d8a](https://github.com/kailong321200875/vue-element-plus-admin/commit/7dc6d8a9d7289bfaf27f972e9ca1773c0a1ddd7d))
+* fix the error reported by the Editor component ([90ef985](https://github.com/kailong321200875/vue-element-plus-admin/commit/90ef9856a0885fa812339cb7047ecc98b86c7b73))
+
+
+### Performance Improvements
+
+* add tagsViewIcon setting ([d395f03](https://github.com/kailong321200875/vue-element-plus-admin/commit/d395f03a57a9265f1d39b3220fc7c9b983efee30))
+* add uniqueopened setting ([b060319](https://github.com/kailong321200875/vue-element-plus-admin/commit/b0603199a5ae0ee923483dad449f49220d36f444))
+
+
+### Build System
+
+* update plugins ([2ee4954](https://github.com/kailong321200875/vue-element-plus-admin/commit/2ee49549e7b601af26ef5204f7648d271f3348f2))
+
+
+### Styling
+
+* add layout background color ([9b614fe](https://github.com/kailong321200875/vue-element-plus-admin/commit/9b614fe89288538197c50f164586aeed7836b7a8))
+
+### [1.2.10](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.9...v1.2.10) (2022-04-12)
+
+
+### Bug Fixes
+
+* fix bug ([327522f](https://github.com/kailong321200875/vue-element-plus-admin/commit/327522f2b73ae0e11f8ebbc39394b06029ce0b65))
+
+
+### Styling
+
+* modify the commitlint package manager ([ba7e722](https://github.com/kailong321200875/vue-element-plus-admin/commit/ba7e7224ab58612548519415f5429c32827a61de))
+
+### [1.2.9](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.8...v1.2.9) (2022-04-12)
+
+
+### Docs
+
+* update changlog ([e37273d](https://github.com/kailong321200875/vue-element-plus-admin/commit/e37273d95d29a3bb752604658d550264aacdc979))
+
+### [1.2.8](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.7...v1.2.8) (2022-04-11)
+
+### Build System
+
+- update plugins ([00a573a](https://github.com/kailong321200875/vue-element-plus-admin/commit/00a573af3f455395b4ee2ab99a03f3103d466e9c))
+
+### Docs
+
+- update changlog ([62fc183](https://github.com/kailong321200875/vue-element-plus-admin/commit/62fc1839fdff3a4d06a7db4cf3f8ce2cb9aee681))
+
+### [1.2.7](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.6...v1.2.7) (2022-04-10)
+
+### Build System
+
+- update plugins ([f13a91d](https://github.com/kailong321200875/vue-element-plus-admin/commit/f13a91dd460b1dcdbd17aef723ab3ca2b01c34f0))
+
+### Styling
+
+- .bhs code formatting ([57b2707](https://github.com/kailong321200875/vue-element-plus-admin/commit/57b27071e9a33423c46542a5d0e5d5c2e9a3b718))
+
+### [1.2.6](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.5...v1.2.6) (2022-04-08)
+
+### Build System
+
+- update plugins ([d645892](https://github.com/kailong321200875/vue-element-plus-admin/commit/d645892cde2f7f43215a2ba1776ee94a322437bf))
+
+### [1.2.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.4...v1.2.5) (2022-04-08)
+
+### Performance Improvements
+
+- add plop ([fa54a17](https://github.com/kailong321200875/vue-element-plus-admin/commit/fa54a1704ffd93f7b42dbeb1229bc4868d2d3a6a))
+
+### Build System
+
+- update plugins ([18c6bd8](https://github.com/kailong321200875/vue-element-plus-admin/commit/18c6bd868622d954b51ea34e37516361ad4eb540))
+
+### Styling
+
+- fix padding and background color ([f8c9d54](https://github.com/kailong321200875/vue-element-plus-admin/commit/f8c9d54687edafd92f5b61bf5288bb1188c73f01))
+
+### [1.2.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.3...v1.2.4) (2022-04-06)
+
+### Bug Fixes
+
+- add Sticky props comment ([46133b3](https://github.com/kailong321200875/vue-element-plus-admin/commit/46133b3ff39d48d11cbcaa1f20a271118f48eb29))
+- fix bug ([179ca06](https://github.com/kailong321200875/vue-element-plus-admin/commit/179ca064ba8adbb3b063d9798ec1930ccc68e459))
+- fix remove unnecessary variables ([ca01cbf](https://github.com/kailong321200875/vue-element-plus-admin/commit/ca01cbfd98b63a0d76190fe8d43097fdc9df74e6))
+- fix style ([17c8fea](https://github.com/kailong321200875/vue-element-plus-admin/commit/17c8fea93811d9d9b708808484f5c907d761fcf1))
+- remove ContentDetailWrap style ([4ceaa9d](https://github.com/kailong321200875/vue-element-plus-admin/commit/4ceaa9d7816369d0dcaf3e18e4cdbbd6165cef88))
+
+### [1.2.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.2...v1.2.3) (2022-03-31)
+
+### Bug Fixes
+
+- fix refresh with query ([e94020f](https://github.com/kailong321200875/vue-element-plus-admin/commit/e94020ff541a061599486c0003258f1dbf13aba8))
+
+### [1.2.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.1...v1.2.2) (2022-03-30)
+
+### Bug Fixes
+
+- fix avatar height bug ([cd4ab76](https://github.com/kailong321200875/vue-element-plus-admin/commit/cd4ab767018941777174d7837045f5259d1cc403))
+- fix parmas to params ([2c7211c](https://github.com/kailong321200875/vue-element-plus-admin/commit/2c7211c89d7299ffc0a36bef8999b3c201dbaf4a))
+
+### [1.2.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.2.0...v1.2.1) (2022-03-29)
+
+### Bug Fixes
+
+- fix invalid paging ([ad184ee](https://github.com/kailong321200875/vue-element-plus-admin/commit/ad184ee9c0619da36f1ca3f26e67f18f88488523))
+
+### Build System
+
+- update plugins ([0c7276f](https://github.com/kailong321200875/vue-element-plus-admin/commit/0c7276feadaedef83e6a4ad9d457e26d408698a8))
+
+## [1.2.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.14...v1.2.0) (2022-03-27)
+
+### Features
+
+- add hooks demo ([c43f39e](https://github.com/kailong321200875/vue-element-plus-admin/commit/c43f39efef296266c64cc24690717d07fa0bcb85))
+- add inputPassword demo ([8f8b126](https://github.com/kailong321200875/vue-element-plus-admin/commit/8f8b1260e75df6998ebea617f62d4ab6be81d721))
+
+### Docs
+
+- update LICENSE ([69d3dcc](https://github.com/kailong321200875/vue-element-plus-admin/commit/69d3dcc7edf69e9b4e3042ddb11faa85ec7d39e2))
+
+### Styling
+
+- modify the function name to make it more semantic ([046ae51](https://github.com/kailong321200875/vue-element-plus-admin/commit/046ae512f02df2d3f08134949b9376a061c1eef3))
+- update Footer component presentation ([d4a9ba3](https://github.com/kailong321200875/vue-element-plus-admin/commit/d4a9ba3aa6758b8aac18b30e1a6b9501baff826c))
+- update Icon demo ([8597122](https://github.com/kailong321200875/vue-element-plus-admin/commit/85971227cd3055ea280cf493c7c42b250c1515da))
+
+### Tests
+
+- test push first commit ([a67bb48](https://github.com/kailong321200875/vue-element-plus-admin/commit/a67bb48f269651a2dcd01b9e33d10f20c42d76ee))
+
+### Build System
+
+- update plugins ([9c13d92](https://github.com/kailong321200875/vue-element-plus-admin/commit/9c13d92b36a2a7c95b9edb7821367fc8f0ac6658))
+- update server port ([d2be8c1](https://github.com/kailong321200875/vue-element-plus-admin/commit/d2be8c1a307a3c5daf363bd7f1d21e574598de5c))
+
+### [1.1.14](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.13...v1.1.14) (2022-03-22)
+
+### Bug Fixes
+
+- fix the bug that the form search function is invalid of the example-dialog page ([9ec30e7](https://github.com/kailong321200875/vue-element-plus-admin/commit/9ec30e719f89865497dbb1321be1df906f59f14e))
+
+### [1.1.13](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.12...v1.1.13) (2022-03-17)
+
+### Build System
+
+- update plugins ([a2d0313](https://github.com/kailong321200875/vue-element-plus-admin/commit/a2d03137899f9b16fc1d4a09a23576cd74e7950e))
+
+### [1.1.12](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.11...v1.1.12) (2022-03-15)
+
+### Build System
+
+- update plugins ([fee2252](https://github.com/kailong321200875/vue-element-plus-admin/commit/fee2252930b05b709d0c012e809568c4ed32bd89))
+
+### [1.1.11](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.10...v1.1.11) (2022-03-15)
+
+### Bug Fixes
+
+- fix the problem of blank bar when toggle the TagsView component ([b1d9771](https://github.com/kailong321200875/vue-element-plus-admin/commit/b1d9771c750709fe45061d13299a85dbbd6ead25))
+- fix the problem that no reaction when copy setting config in http page ([61e0e33](https://github.com/kailong321200875/vue-element-plus-admin/commit/61e0e33c64d6a889fe6ed80d27a10cf8b201d21a))
+
+### [1.1.10](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.9...v1.1.10) (2022-03-13)
+
+### Build System
+
+- update plugins ([0b525c8](https://github.com/kailong321200875/vue-element-plus-admin/commit/0b525c875075a28288e92243b205b337f85ab550))
+
+### [1.1.9](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.8...v1.1.9) (2022-03-07)
+
+### Build System
+
+- update plugins ([1456fd4](https://github.com/kailong321200875/vue-element-plus-admin/commit/1456fd49ec9abbfe1f25aeadfe5fed54fec07394))
+
+### [1.1.8](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.7...v1.1.8) (2022-03-07)
+
+### Docs
+
+- update changelog ([bf09441](https://github.com/kailong321200875/vue-element-plus-admin/commit/bf09441852e59b0d07d4949a33de75958696817f))
+
+### [1.1.7](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.6...v1.1.7) (2022-03-06)
+
+### Styling
+
+- add labelMessage attribute to Form component ([8c42790](https://github.com/kailong321200875/vue-element-plus-admin/commit/8c427907843ccb2dfd882d27c1e8a894c5616487))
+
+### [1.1.6](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.5...v1.1.6) (2022-03-04)
+
+### Bug Fixes
+
+- fix the problem that the tree data of Table component cannot be displayed ([bf83d3e](https://github.com/kailong321200875/vue-element-plus-admin/commit/bf83d3efbad9097f245c32cc07d1178580cec4e3))
+
+### [1.1.5](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.4...v1.1.5) (2022-03-02)
+
+### Bug Fixes
+
+- fix the problem of tagsview error when loginout ([835d76a](https://github.com/kailong321200875/vue-element-plus-admin/commit/835d76ae87b950106f957976ebc8f6f2e8842ddf))
+
+### Build System
+
+- update plugins ([de34bb1](https://github.com/kailong321200875/vue-element-plus-admin/commit/de34bb193d6c844dbc1cec38db5f61b3f95e19f2))
+
+### Styling
+
+- fix tabMenu z-index bug ([8b3be02](https://github.com/kailong321200875/vue-element-plus-admin/commit/8b3be02368a1bddb7dc78f18adbea7f4ebfe75d6))
+- fix tags-view style bug ([ebff817](https://github.com/kailong321200875/vue-element-plus-admin/commit/ebff81777b9c0b839256b83e321ecbdbff25fc73))
+
+### [1.1.4](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.3...v1.1.4) (2022-03-01)
+
+### CI
+
+- update workflow ([0490d18](https://github.com/kailong321200875/vue-element-plus-admin/commit/0490d18145cb0d9c4b066ab01a2c10cb527e38ba))
+- update workflow ([51f7bca](https://github.com/kailong321200875/vue-element-plus-admin/commit/51f7bca6034902b251d081ee383b0d796782d434))
+
+### [1.1.3](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.2...v1.1.3) (2022-03-01)
+
+### CI
+
+- update workflow ([91cc5c5](https://github.com/kailong321200875/vue-element-plus-admin/commit/91cc5c595cadc5695d8f54bdc4922d8f04439f24))
+
+### [1.1.2](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.1...v1.1.2) (2022-03-01)
+
+### Workflows
+
+- update workflow ([d9708aa](https://github.com/kailong321200875/vue-element-plus-admin/commit/d9708aae5bc0cb795bb0fbf8d17df753cc88ba1d))
+
+### [1.1.1](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.1.0...v1.1.1) (2022-03-01)
+
+### Workflows
+
+- update workflow ([085328a](https://github.com/kailong321200875/vue-element-plus-admin/commit/085328aba8c4f356bf7915a6bbdc1ec4f46ceeda))
+
+## [1.1.0](https://github.com/kailong321200875/vue-element-plus-admin/compare/v1.0.3...v1.1.0) (2022-03-01)
+
+### Features
+
+- 🎸 layout 三种布局重构完成 ([429e428](https://github.com/kailong321200875/vue-element-plus-admin/commit/429e42809cef33a33662e41ad50297217d128b8c))
+- 🎸 layout 布局重构 �[bd24b92](https://github.com/kailong321200875/vue-element-plus-admin/commit/bd24b92acb279343dbaf83b74f1ed2a3f57f1003))
+- 🎸 Table 组件重构完成并给出相应示 �[35879f8](https://github.com/kailong321200875/vue-element-plus-admin/commit/35879f8ecc0ffa76122a336e2eaa93ecfb408c1d))
+- 🎸 v0.0.4 发布 ([a58dc1b](https://github.com/kailong321200875/vue-element-plus-admin/commit/a58dc1b1c2774974782ef6d116b8805975b82b1c))
+- 🎸 初始化项 �[26d4c7c](https://github.com/kailong321200875/vue-element-plus-admin/commit/26d4c7c56894cf2031b3a7cce08d53c37f4a49e3))
+- 🎸 初版完成 ([5bfe4d2](https://github.com/kailong321200875/vue-element-plus-admin/commit/5bfe4d236fd9c2841da100f34c980b4572b67b20))
+- 🎸 新增 Detail 详情组件并给出相应示 �[e77a931](https://github.com/kailong321200875/vue-element-plus-admin/commit/e77a931ef2d2967a9717e27b187d68512c01284f))
+- 🎸 新增二维码组 �[85555ee](https://github.com/kailong321200875/vue-element-plus-admin/commit/85555eef7dc7d72cb701bdd81044ba8fb8e72acc))
+- 🎸 新增全局配置 ([f8405a6](https://github.com/kailong321200875/vue-element-plus-admin/commit/f8405a63c9b1288fbe95bae235b65a08e8fae8d2))
+- 🎸 新增固定 � 级菜单配 �[4c4903e](https://github.com/kailong321200875/vue-element-plus-admin/commit/4c4903e806c8818e320108cc3e5279d728061c29))
+- 🎸 新增权限管理及相关示例文 �[32b6583](https://github.com/kailong321200875/vue-element-plus-admin/commit/32b6583099646b2ee622ac7b35388468769b91b8))
+- 🎸 显示更多组建 � 发中 ([fa9f24d](https://github.com/kailong321200875/vue-element-plus-admin/commit/fa9f24d5da8d2e40d7c3661eabacb8f0474a7bf2))
+- 🎸 权限管理 � 发中 ([38f5211](https://github.com/kailong321200875/vue-element-plus-admin/commit/38f521174ba9eba750fee4516141d7a267f1c4ce))
+- 🎸 权限管理 � 发中 ([6d7ea66](https://github.com/kailong321200875/vue-element-plus-admin/commit/6d7ea6694d8299332018a6689bcd82502a9a552c))
+- 🎸 综合实例重构 �[5142e6e](https://github.com/kailong321200875/vue-element-plus-admin/commit/5142e6e323cb20c89a97398bf41d32c93ce42cad))
+- 🎸 重构 layout ([7ede021](https://github.com/kailong321200875/vue-element-plus-admin/commit/7ede02141e258ab4c88e9b4daad966513d4dbe68))
+- 🎸 重构 layout-classic 布局 ([29d9c98](https://github.com/kailong321200875/vue-element-plus-admin/commit/29d9c988605b822195900268da6bc3f3b0b9c770))
+- 🎸 重构 sider 组件 �[51313d7](https://github.com/kailong321200875/vue-element-plus-admin/commit/51313d7116c7ab2ded7e3a65514ea9ac413edecd))
+- Add analysis api ([83327ea](https://github.com/kailong321200875/vue-element-plus-admin/commit/83327ea763ebb233bb540513276ffa288fbcb4a1))
+- Add analysis demo ([cd06934](https://github.com/kailong321200875/vue-element-plus-admin/commit/cd069340fc5157535fdc82e792c6b6dce7d7a97e))
+- Add count-to demo ([d3fbd3a](https://github.com/kailong321200875/vue-element-plus-admin/commit/d3fbd3a06c3b802fc863b4dc8013122c14bd16f2))
+- Add Descriptions component and add Descriptions demo ([7ad46f8](https://github.com/kailong321200875/vue-element-plus-admin/commit/7ad46f828d626a87699cd4d3a959a5634577d580))
+- Add Dialog component and add dailog demo ([a18ad8f](https://github.com/kailong321200875/vue-element-plus-admin/commit/a18ad8f4a89b78c73e57d8d2543494243f656d05))
+- add doucment link ([53201ae](https://github.com/kailong321200875/vue-element-plus-admin/commit/53201ae97a425714871d99e8847a3672ba0d389f))
+- Add dynamic route ([9d926b2](https://github.com/kailong321200875/vue-element-plus-admin/commit/9d926b2760b75e1d8e71a68dc7ff6c5026223a43))
+- Add Editor component and add editor demo ([3fb3e8d](https://github.com/kailong321200875/vue-element-plus-admin/commit/3fb3e8da39d816bcf4aedb65d40c7052bdb6d8bf))
+- Add Error component ([7411dbc](https://github.com/kailong321200875/vue-element-plus-admin/commit/7411dbc9fd8f122187c86a11523b49c88cc71a8c))
+- Add example-dialog demo ([262f421](https://github.com/kailong321200875/vue-element-plus-admin/commit/262f4211cf53aef30a32f4b88e88fb1b9246ffcb))
+- Add example-page demo ([1492f91](https://github.com/kailong321200875/vue-element-plus-admin/commit/1492f9119aa2960cc05956218e6d151c8b316875))
+- Add form demo ([472f574](https://github.com/kailong321200875/vue-element-plus-admin/commit/472f574f42f8f31c4e6047043ac755ba5fb35b7b))
+- Add form demo ([e6f9580](https://github.com/kailong321200875/vue-element-plus-admin/commit/e6f95803316bb5df2d1060285c1d591a79340721))
+- Add form demo ([543156f](https://github.com/kailong321200875/vue-element-plus-admin/commit/543156f328350bd12e71a41c872e547e41cda7fe))
+- Add form demo ([7795d2a](https://github.com/kailong321200875/vue-element-plus-admin/commit/7795d2a4fe3dbc9849ddc7c1d3e2d9215dc66f56))
+- Add guide demo ([0832194](https://github.com/kailong321200875/vue-element-plus-admin/commit/0832194e6131051416edff7c2eac6b0a016ffd80))
+- Add highlight demo ([eb206b0](https://github.com/kailong321200875/vue-element-plus-admin/commit/eb206b0cc31ac7da3dfd8b3d4b874061c5c91d53))
+- Add Icon demo ([e4b7a76](https://github.com/kailong321200875/vue-element-plus-admin/commit/e4b7a769126d6f0fca424007c294ff229eefcb35))
+- Add ImageViewer component and add ImageViewer demo ([af9fc0a](https://github.com/kailong321200875/vue-element-plus-admin/commit/af9fc0a4aded3ec08746ddeaeabac4c3cfa9463d))
+- Add Infotip component ([e4b7a76](https://github.com/kailong321200875/vue-element-plus-admin/commit/e4b7a769126d6f0fca424007c294ff229eefcb35))
+- Add infotip demo ([dbf3b0f](https://github.com/kailong321200875/vue-element-plus-admin/commit/dbf3b0f5a333ccef524bbac825035b0c6dc78ec9))
+- Add Qrcode component and add qrcode demo ([535a31b](https://github.com/kailong321200875/vue-element-plus-admin/commit/535a31b35eb6a76589f602fd96dcf91f46f349b0))
+- Add Search component and add search demo ([33eca8a](https://github.com/kailong321200875/vue-element-plus-admin/commit/33eca8a97d59f5cc453e1a60ee81b1519527d0f1))
+- Add Table component and add useTable hook ([17e8e7c](https://github.com/kailong321200875/vue-element-plus-admin/commit/17e8e7cda9a009818f11cfa0429ce0f9adc00be5))
+- Add useScrollTo hook ([7d7fd9e](https://github.com/kailong321200875/vue-element-plus-admin/commit/7d7fd9ed646d2b68cec0547ad8e65b0404bb95bb))
+- Add useWatermark hook and add useWatermark demo ([d3fbd3a](https://github.com/kailong321200875/vue-element-plus-admin/commit/d3fbd3a06c3b802fc863b4dc8013122c14bd16f2))
+- Add workplace api ([cb558f8](https://github.com/kailong321200875/vue-element-plus-admin/commit/cb558f8af9dfef2ba2879f021db395ee79e8c8d4))
+- **Animate:** Add animate.css ([1436543](https://github.com/kailong321200875/vue-element-plus-admin/commit/1436543a5c599f651ed7805165ea83b9ebcddef5))
+- **Breadcrumbe:** Add Breadcrumb component ([4612e55](https://github.com/kailong321200875/vue-element-plus-admin/commit/4612e5544bcd626d686972e5cb874d0aa4af08b3))
+- **component:** Add CountTo component and Echart component ([e20fa76](https://github.com/kailong321200875/vue-element-plus-admin/commit/e20fa76cad0894a69fd04c81c2108faabf392684))
+- **component:** Add Footer component ([dad7330](https://github.com/kailong321200875/vue-element-plus-admin/commit/dad733063413c79eca61c6cb5ff671b35933a85f))
+- **component:** Add Footer component ([f81e996](https://github.com/kailong321200875/vue-element-plus-admin/commit/f81e996a426538aeaa2aa37a540395dcf360a09c))
+- **Component:** Add Highlight component ([c53fa56](https://github.com/kailong321200875/vue-element-plus-admin/commit/c53fa562e540447df082e35c7f26e56f2426e430))
+- **component:** Add namespace of class ([d847ccb](https://github.com/kailong321200875/vue-element-plus-admin/commit/d847ccb098edc72fe55c1f8459bf149453a3b73d))
+- **Component:** Setting component add copy button ([e496096](https://github.com/kailong321200875/vue-element-plus-admin/commit/e496096539e6a56b0761a625c9d59210facc5432))
+- **ContextMenu:** Add ContextMenu component ([349ac9d](https://github.com/kailong321200875/vue-element-plus-admin/commit/349ac9d3989d77e5246cecf0006dd8d83c489990))
+- Detail 组件重构完成 ([7f5ef99](https://github.com/kailong321200875/vue-element-plus-admin/commit/7f5ef99ccc32b03f7be21f70c333bb8e679c7d93))
+- Highlight 组件重构 ([34221f3](https://github.com/kailong321200875/vue-element-plus-admin/commit/34221f387f5e15a08cdc21edd76ce8d8c5c20fbc))
+- **hooks:** Add useIntro hook ([0832194](https://github.com/kailong321200875/vue-element-plus-admin/commit/0832194e6131051416edff7c2eac6b0a016ffd80))
+- **hooks:** Add useTimeAgo hook ([c53fa56](https://github.com/kailong321200875/vue-element-plus-admin/commit/c53fa562e540447df082e35c7f26e56f2426e430))
+- **I18n:** Add Ii8n ([3810b8c](https://github.com/kailong321200875/vue-element-plus-admin/commit/3810b8c3b26f86c27aa7db479dfb7b0d283d970f))
+- **Layout:** Add classic layout ([839b601](https://github.com/kailong321200875/vue-element-plus-admin/commit/839b6015b8e31bf70e6f0bf0608fa729b028729b))
+- **Layout:** Add cutMenu layout ([ff4dd3a](https://github.com/kailong321200875/vue-element-plus-admin/commit/ff4dd3afbf5c0c7a439c71b0c494b81e0f2c70d4))
+- **Layout:** Add topLeft layout ([71b1c5e](https://github.com/kailong321200875/vue-element-plus-admin/commit/71b1c5e10cade8d1c018d0c5f63c98ba9357bab8))
+- **LocaleDropdown:** Add LocaleDropdown Component ([3810b8c](https://github.com/kailong321200875/vue-element-plus-admin/commit/3810b8c3b26f86c27aa7db479dfb7b0d283d970f))
+- **Logo:** Add Logo component ([958edef](https://github.com/kailong321200875/vue-element-plus-admin/commit/958edefe7bc2bf3ae77520a5d885a9d47e8a37b9))
+- **mock:** Add mock ([3fc7d4d](https://github.com/kailong321200875/vue-element-plus-admin/commit/3fc7d4d39a72056fcf419fe19a9d41d90f945bad))
+- **router:** Add dynamic routing ([b218ccc](https://github.com/kailong321200875/vue-element-plus-admin/commit/b218ccc9cce2ce1363c4a21d22b4d69c43c7b2dc))
+- Search component add expand attribute and expandField attribute ([9b4b317](https://github.com/kailong321200875/vue-element-plus-admin/commit/9b4b31781765d31dec50acc40e2eed91401502d4))
+- **store:** Add localeStore ([3810b8c](https://github.com/kailong321200875/vue-element-plus-admin/commit/3810b8c3b26f86c27aa7db479dfb7b0d283d970f))
+- **store:** Add tagsView store ([349ac9d](https://github.com/kailong321200875/vue-element-plus-admin/commit/349ac9d3989d77e5246cecf0006dd8d83c489990))
+- Table 组件重构 ([07adefb](https://github.com/kailong321200875/vue-element-plus-admin/commit/07adefb89b7555280e6217e09cf81ba7aa5b93c2))
+- **TagsView:** Add TagsView component ([349ac9d](https://github.com/kailong321200875/vue-element-plus-admin/commit/349ac9d3989d77e5246cecf0006dd8d83c489990))
+- **useForm:** Add useForm ([357fc44](https://github.com/kailong321200875/vue-element-plus-admin/commit/357fc44e519c5829567c17f611fcaadee3f9f933))
+- **useNProgress:** Add useNProgress ([c5ab359](https://github.com/kailong321200875/vue-element-plus-admin/commit/c5ab3599c8ea001ff7831b72fefc9e274163fbbb))
+- **useTitle:** Add useTitle ([c5ab359](https://github.com/kailong321200875/vue-element-plus-admin/commit/c5ab3599c8ea001ff7831b72fefc9e274163fbbb))
+- **utils:** Add color utils ([71dfba2](https://github.com/kailong321200875/vue-element-plus-admin/commit/71dfba21c5bc0276689b5aecf0d75e53efdda09f))
+- **VForm:** Add VForm component ([448ac52](https://github.com/kailong321200875/vue-element-plus-admin/commit/448ac5293e48a03840df2bb0b399a8f02aae666e))
+- **VInputPassword:** Add VInputPassword Component ([a1bf7e9](https://github.com/kailong321200875/vue-element-plus-admin/commit/a1bf7e9b552f75d3b87c64904ac9e7c99fc936a5))
+- **Workplace:** Add wrokplace demo ([c53fa56](https://github.com/kailong321200875/vue-element-plus-admin/commit/c53fa562e540447df082e35c7f26e56f2426e430))
+- 综合实例、权限管理重 �[a4bd206](https://github.com/kailong321200875/vue-element-plus-admin/commit/a4bd2068a5d40d146b5b45cb3727ced990147b68))
+- 部分组件重构完成 ([3d96229](https://github.com/kailong321200875/vue-element-plus-admin/commit/3d9622978dc234ef12dbce63e18caf3440563aa0))
+
+### Bug Fixes
+
+- 🐛 删除 Editor 双向绑定,改 �props 传参 ([c395e27](https://github.com/kailong321200875/vue-element-plus-admin/commit/c395e27f67af9f60b151a5484ab5a3c90c4c1d1e))
+- fix Form component setProps not work bug ([48ffc52](https://github.com/kailong321200875/vue-element-plus-admin/commit/48ffc52ca8fa26d8e6a5fa4b8b3001701a1f0732))
+- fix useScrollTo not work bug ([53201ae](https://github.com/kailong321200875/vue-element-plus-admin/commit/53201ae97a425714871d99e8847a3672ba0d389f))
+- 修复 tagsView 无动画效 �[0e3eb4b](https://github.com/kailong321200875/vue-element-plus-admin/commit/0e3eb4ba8b1503e1d221dfda59a3a0001dbdcb56))
+
+### Performance Improvements
+
+- update useForm hook ([8a958cd](https://github.com/kailong321200875/vue-element-plus-admin/commit/8a958cd71d9afbd32b243aac0814bfa3281477cd))
+
+### Code Refactoring
+
+- 💡 综合实例查看详情重构 ([9c26edd](https://github.com/kailong321200875/vue-element-plus-admin/commit/9c26edd5d599b5fb5a832fb547e3d95b6bfa9a98))
+
+### Build System
+
+- Add conventional-changelog-cli plugin ([384485f](https://github.com/kailong321200875/vue-element-plus-admin/commit/384485f6994c6ac33abee506508ab9d35fe658a9))
+- Add conventional-github-releaser plugin ([3cd5c71](https://github.com/kailong321200875/vue-element-plus-admin/commit/3cd5c71899dde3ac3910aef0180d8b39fad51f1b))
+- Add standard-version plugin ([110ce25](https://github.com/kailong321200875/vue-element-plus-admin/commit/110ce257841648e29b247a0338624a188694b6e9))
+- Add vite-plugin-html plugin ([d5b6e2a](https://github.com/kailong321200875/vue-element-plus-admin/commit/d5b6e2a7770eb59aa32839f69da5be37397e3538))
+- delete useless plugin ([c756761](https://github.com/kailong321200875/vue-element-plus-admin/commit/c756761dfc3200156acb228474d3539197ef413b))
+- **pinia:** Add pinia ([2040500](https://github.com/kailong321200875/vue-element-plus-admin/commit/2040500af14d277a79f01eba5eca2a440203cecf))
+- **types:** Add vue-types ([2c41826](https://github.com/kailong321200875/vue-element-plus-admin/commit/2c41826c572268b74a663a6966c548628ac7e280))
+- **unplugin-auto-import:** Delete unplugin-auto-import ([2040500](https://github.com/kailong321200875/vue-element-plus-admin/commit/2040500af14d277a79f01eba5eca2a440203cecf))
+- **unplugin-vue-components:** Delete unplugin-vue-components ([2040500](https://github.com/kailong321200875/vue-element-plus-admin/commit/2040500af14d277a79f01eba5eca2a440203cecf))
+- update plugin ([8d08bc6](https://github.com/kailong321200875/vue-element-plus-admin/commit/8d08bc6fc92258674abdd12834eaa4530ec276dd))
+- update plugins ([3c58042](https://github.com/kailong321200875/vue-element-plus-admin/commit/3c580420a20121845f02c0dd3caca5a74f06a89d))
+- **vite-plugin-style-import:** Add vite-plugin-style-import ([2040500](https://github.com/kailong321200875/vue-element-plus-admin/commit/2040500af14d277a79f01eba5eca2a440203cecf))
+- **vite-plugin-vue-setup-extend:** Delete vite-plugin-vue-setup-extend ([2040500](https://github.com/kailong321200875/vue-element-plus-admin/commit/2040500af14d277a79f01eba5eca2a440203cecf))
+- 修改 vite 配置 ([9991fb4](https://github.com/kailong321200875/vue-element-plus-admin/commit/9991fb4e5c46b9e4016beaade7232e28dc272797))
+- 设置多语 �([45e879e](https://github.com/kailong321200875/vue-element-plus-admin/commit/45e879edeef677b6aa1d2cfe4dd8dc5b76c83c59))
+- 配置代码格式 �[ffdb556](https://github.com/kailong321200875/vue-element-plus-admin/commit/ffdb556a096db247306eae8eecc1b85718314cdd))
+- 集成基础配置 ([ced99de](https://github.com/kailong321200875/vue-element-plus-admin/commit/ced99de9b113a01d9d0b190f6d2c6adc983a3102))
+- 集成基础配置 ([5dbcf23](https://github.com/kailong321200875/vue-element-plus-admin/commit/5dbcf2397ccdec80c695c113f49e8aa9bb6d012c))
+
+### Styling
+
+- 💄 优化 layout 样式 ([37ec378](https://github.com/kailong321200875/vue-element-plus-admin/commit/37ec378f0b2bf83d73ddf0e472aada6aab248f09))
+- 💄 微调样式 ([612b486](https://github.com/kailong321200875/vue-element-plus-admin/commit/612b48673c3389779ccfdd161e2ca80b21d265b2))
+- Add elNamespace ([d847ccb](https://github.com/kailong321200875/vue-element-plus-admin/commit/d847ccb098edc72fe55c1f8459bf149453a3b73d))
+- **appStore:** code style ([641ed68](https://github.com/kailong321200875/vue-element-plus-admin/commit/641ed684fefeb52e2f91e8baab7b610fc74c8d88))
+- **Breadcrumb:** fix Breadcrumb style bug ([8755c86](https://github.com/kailong321200875/vue-element-plus-admin/commit/8755c862b837d90a25b27c01fabe64abf81fc4a2))
+- **breadcrumb:** update disabled text color ([1522e92](https://github.com/kailong321200875/vue-element-plus-admin/commit/1522e925bae37cb9df4de2252d81f717788f4537))
+- change function to arrow function ([4612e55](https://github.com/kailong321200875/vue-element-plus-admin/commit/4612e5544bcd626d686972e5cb874d0aa4af08b3))
+- delete console.log ([49a6bfe](https://github.com/kailong321200875/vue-element-plus-admin/commit/49a6bfe9d81a40e2f5f15b68d7289e1787e89b54))
+- **Icon:** delete default color ([95a2bd8](https://github.com/kailong321200875/vue-element-plus-admin/commit/95a2bd884dd9846a56cda7c4c3ee4a41ce631b7c))
+- level demo style beautification ([dbf3b0f](https://github.com/kailong321200875/vue-element-plus-admin/commit/dbf3b0f5a333ccef524bbac825035b0c6dc78ec9))
+- lint code style ([b292419](https://github.com/kailong321200875/vue-element-plus-admin/commit/b2924190b8996e8208f951e3fadbcb09baddb8df))
+- **Login:** update login styles ([eb68f1d](https://github.com/kailong321200875/vue-element-plus-admin/commit/eb68f1d919e13c07b7d200e9aec53804b2a6dc7b))
+- modify menu z-index attribute ([0d7a778](https://github.com/kailong321200875/vue-element-plus-admin/commit/0d7a7781ce0b5e39f01355d3acdb3f364cabf76d))
+- **TagView:** Vertical center tag ([41281c4](https://github.com/kailong321200875/vue-element-plus-admin/commit/41281c4d541a2744e5df5dff2764cc85465b6a4c))
+
+### Types
+
+- add ImportMetaEnv ([38e0257](https://github.com/kailong321200875/vue-element-plus-admin/commit/38e0257487e4138a74ad1bb4ee4ba004abcfaa12))
+- Adding BfFrom Component types ([8e036f5](https://github.com/kailong321200875/vue-element-plus-admin/commit/8e036f54b56ce8521eb8ec4b7ca21aa9c24f43f2))
+- **BfForm:** Adding BfForm types ([bc9195b](https://github.com/kailong321200875/vue-element-plus-admin/commit/bc9195b21eeb79629a82a04d90e2ac5aa6592928))
+- **BfForm:** Adding BfForm types ([184b468](https://github.com/kailong321200875/vue-element-plus-admin/commit/184b468cd41dcd1cdae11477b9ee2d6e17de1481))
+- **BfForm:** Adding BfForm types ([58cb24d](https://github.com/kailong321200875/vue-element-plus-admin/commit/58cb24d9f8a50be80b5ea793387d582a77a59137))
+- delete useless types ([3fc79c0](https://github.com/kailong321200875/vue-element-plus-admin/commit/3fc79c0ae7acd0929f47e33f96c8d45a90d8f762))
+- **VForm:** Adding VForm types ([7528fe6](https://github.com/kailong321200875/vue-element-plus-admin/commit/7528fe6da60368213d28d9f1b6310d02d3d53282))
+
+### Docs
+
+- ✏️ 修改 readme ([8edb2a3](https://github.com/kailong321200875/vue-element-plus-admin/commit/8edb2a3493dca975036859b5d2c52afaa91f5dbb))
+- ✏️ 更新 readme ([62eeb55](https://github.com/kailong321200875/vue-element-plus-admin/commit/62eeb55330dd4af2a46801c7a19f38a3ef312bbf))
+- Add README.md ([21dcf88](https://github.com/kailong321200875/vue-element-plus-admin/commit/21dcf88ba31957bbdb50c6207d010650daab70fc))
+- Error modifying readme name ([25d5c84](https://github.com/kailong321200875/vue-element-plus-admin/commit/25d5c84e92e68aa72362a14f55aacd946fa5b1b2))
+- update description ([be6ff98](https://github.com/kailong321200875/vue-element-plus-admin/commit/be6ff9899b25cc00519210950d27ee56ac5112e6))
+- update description ([c15aa87](https://github.com/kailong321200875/vue-element-plus-admin/commit/c15aa8755c9c937512c7380a6d03c4d877ef4d87))
+- update README ([27979dc](https://github.com/kailong321200875/vue-element-plus-admin/commit/27979dc6def7d9d8cea62a08d49a6c828be2258b))
+- update README.md ([53201ae](https://github.com/kailong321200875/vue-element-plus-admin/commit/53201ae97a425714871d99e8847a3672ba0d389f))
+- update README.md ([c11823a](https://github.com/kailong321200875/vue-element-plus-admin/commit/c11823abd8a033e14b4c20d17ac941195d39bcfe))
+- 修改 README ([b79a567](https://github.com/kailong321200875/vue-element-plus-admin/commit/b79a56753df55976e749c4494266df052d315416))

+ 21 - 0
LICENSE

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

+ 144 - 0
README.md

@@ -0,0 +1,144 @@
+<div align="center"> <a href="https://github.com/kailong321200875/vue-element-plus-admin"> <img width="100" src="./public/logo.png"> </a> <br> <br>
+
+[![license](https://img.shields.io/github/license/kailong321200875/vue-element-plus-admin.svg)](LICENSE) [![repo-size](https://img.shields.io/github/repo-size/kailong321200875/vue-element-plus-admin.svg)](repo-size) [![last-commit](https://img.shields.io/github/last-commit/kailong321200875/vue-element-plus-admin.svg)](last-commit) [![stars](https://img.shields.io/github/stars/kailong321200875/vue-element-plus-admin.svg)](stars) [![forks](https://img.shields.io/github/forks/kailong321200875/vue-element-plus-admin.svg)](forks) [![release](https://img.shields.io/github/release/kailong321200875/vue-element-plus-admin.svg)](release) [![watchers](https://img.shields.io/github/watchers/kailong321200875/vue-element-plus-admin.svg)](watchers)
+
+<h1>vue-element-plus-admin</h1>
+</div>
+
+**English** | [中文](./README.zh-CN.md)
+
+## Introduction
+
+vue-element-plus-admin is a free and open source middle and background template based on `element-plus`. Developed using the latest mainstream technologies such as `vue3`, `vite` and `typescript`, the out of the box middle and background front-end solution can be used as the starting template of the project and learning reference. And always pay attention to the latest technological trends and update them as soon as possible.
+
+vue-element-plus-admin is positioned as a background integration scheme, which is not suitable for secondary development as a basic template. Because it integrates many functions that you may not use, it will cause a lot of code redundancy. If your project doesn't pay attention to this problem, you can also directly carry out secondary development based on it.
+
+If you need a basic template, please switch to the `mini` branch. `mini` simply integrates some common layout functions such as layout and dynamic menu, which is more suitable for developers to carry out secondary development.
+
+## Feature
+
+- **State of The Art Development**:Use front-end front-end technology development such as Vue3/vite4
+- **TypeScript**: Application-level JavaScript language
+- **Theming**: Configurable themes
+- **International**:Built-in complete internationalization program
+- **Mock Server** Built-in mock data scheme
+- **Authority** Built-in complete dynamic routing permission generation scheme.
+- **Component** Multiple commonly used components are encapsulated twice
+- **Examples** Built-in rich examples
+
+## Preview
+
+- [vue-element-plus-admin](https://element-plus-admin.cn/) - Full version of the github site
+- [vue-element-plus-admin](https://kailong110120130.gitee.io/vue-element-plus-admin) - Full version of the gitee site
+
+account: **admin/admin**
+
+Online examples do not apply to menu filtering by default, but directly use Static routing
+
+## Documentation
+
+[Document Github](https://element-plus-admin-doc.cn/)
+
+[Document Gitee](https://kailong110120130.gitee.io/vue-element-plus-admin-doc)
+
+## Preparation
+
+- [node](http://nodejs.org/) and [git](https://git-scm.com/) - Project development environment
+- [Vite4](https://vitejs.dev/) - Familiar with vite features
+- [Vue3](https://v3.vuejs.org/) - Familiar with Vue basic syntax
+- [TypeScript](https://www.typescriptlang.org/) - Familiar with the basic syntax of `TypeScript`
+- [Es6+](http://es6.ruanyifeng.com/) - Familiar with es6 basic syntax
+- [Vue-Router-Next](https://next.router.vuejs.org/) - Familiar with the basic use of vue-router
+- [Element-Plus](https://element-plus.org/) - Familiar with the basic use of element-plus
+- [Mock.js](https://github.com/nuysoft/Mock) - mockjs basic syntax
+
+## Install and use
+
+- Get the project code
+
+```bash
+git clone https://github.com/kailong321200875/vue-element-plus-admin.git
+```
+
+- Installation dependencies
+
+```bash
+cd vue-element-plus-admin
+
+pnpm install
+
+```
+
+- run
+
+```bash
+pnpm run dev
+```
+
+- build
+
+```bash
+pnpm run build:pro
+```
+
+## Change Log
+
+[CHANGELOG](./CHANGELOG.md)
+
+## How to contribute
+
+You can [Raise an issue](https://github.com/kailong321200875/vue-element-plus-admin/issues/new) Or submit a Pull Request.
+
+**Pull Request:**
+
+1. Fork code
+2. Create your own branch: `git checkout -b feat/xxxx`
+3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`
+4. Push your branch: `git push origin feat/xxxx`
+5. submit `pull request`
+
+## Git Contribution submission specification
+
+- `feat` New features
+- `fix` Fix bugs
+- `docs` document
+- `style` Format and style (changes that do not affect code operation)
+- `refactor` Refactor
+- `perf` Optimize related, such as improving performance and experience
+- `test` Add test
+- `build` Compilation related modifications, changes to project construction or dependencies
+- `ci` Continuous integration modification
+- `chore` Changes in the construction process or auxiliary tools
+- `revert` Rollback to previous version
+- `workflow` Workflow improvement
+- `mod` Uncertain modification classification
+- `wip` Under development
+- `types` type
+
+## Browser support
+
+The `Chrome 80+` browser is recommended for local development
+
+Support modern browsers, not IE
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## Donate
+
+If you find this project helpful, welcome sponsorship to show your support~
+
+[Paypal Me](https://www.paypal.com/paypalme/ckl94)
+
+<img src="https://github.com/kailong321200875/my-image/raw/master/pay.jpg" />
+
+## Group
+
+If you want to join the technical communication group for discussion, please add me as a friend
+
+<img src="https://github.com/kailong321200875/my-image/raw/master/me.jpg" />
+
+## License
+
+[MIT](./LICENSE)

+ 144 - 0
README.zh-CN.md

@@ -0,0 +1,144 @@
+<div align="center"> <a href="https://github.com/kailong321200875/vue-element-plus-admin"> <img width="100" src="./public/logo.png"> </a> <br> <br>
+
+[![license](https://img.shields.io/github/license/kailong321200875/vue-element-plus-admin.svg)](LICENSE) [![repo-size](https://img.shields.io/github/repo-size/kailong321200875/vue-element-plus-admin.svg)](repo-size) [![last-commit](https://img.shields.io/github/last-commit/kailong321200875/vue-element-plus-admin.svg)](last-commit) [![stars](https://img.shields.io/github/stars/kailong321200875/vue-element-plus-admin.svg)](stars) [![forks](https://img.shields.io/github/forks/kailong321200875/vue-element-plus-admin.svg)](forks) [![release](https://img.shields.io/github/release/kailong321200875/vue-element-plus-admin.svg)](release) [![watchers](https://img.shields.io/github/watchers/kailong321200875/vue-element-plus-admin.svg)](watchers)
+
+<h1>vue-element-plus-admin</h1>
+</div>
+
+[English](./README.md) | **中文**
+
+## 介绍
+
+vue-element-plus-admin 是一个基于 `element-plus` 免费开源的中后台模版。使用了最新的`vue3`,`vite`,`TypeScript`等主流技术开发,开箱即用的中后台前端解决方案,可以用来作为项目的启动模版,也可用于学习参考。并且时刻关注着最新技术动向,尽可能的第一时间更新。
+
+vue-element-plus-admin 的定位是后台集成方案,不太适合当基础模板来进行二次开发。因为集成了很多你可能用不到的功能,会造成不少的代码冗余。如果你的项目不关注这方面的问题,也可以直接基于它进行二次开发。
+
+如需要基础模版,请切换到 `mini` 分支,`mini` 只简单集成了一些如:布局、动态菜单等常用布局功能,更适合开发者进行二次开发。
+
+## 特性
+
+- **最新技术栈**:使用 Vue3/vite4 等前端前沿技术开发
+- **TypeScript**: 应用程序级 JavaScript 的语言
+- **主题**: 可配置的主题
+- **国际化**:内置完善的国际化方案
+- **自定义数据** 内置 Mock 数据方案
+- **权限** 内置完善的动态路由权限生成方案
+- **组件** 二次封装了多个常用的组件
+- **示例** 内置丰富的示例
+
+## 预览
+
+- [vue-element-plus-admin](https://element-plus-admin.cn/) - 完整版 github 站点
+- [vue-element-plus-admin](https://kailong110120130.gitee.io/vue-element-plus-admin) - 完整版 gitee 站点
+
+帐号:**admin/admin**
+
+在线例子默认不适用菜单过滤,而是直接使用静态路由表
+
+## 文档
+
+[文档地址 Github](https://element-plus-admin-doc.cn/)
+
+[文档地址 Gitee](https://kailong110120130.gitee.io/vue-element-plus-admin-doc)
+
+## 前序准备
+
+- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) - 项目开发环境
+- [Vite4](https://vitejs.dev/) - 熟悉 vite 特性
+- [Vue3](https://v3.vuejs.org/) - 熟悉 Vue 基础语法
+- [TypeScript](https://www.typescriptlang.org/) - 熟悉 `TypeScript` 基本语法
+- [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法
+- [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router 基本使用
+- [Element-Plus](https://element-plus.org/) - element-plus 基本使用
+- [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
+
+## 安装和使用
+
+- 获取代码
+
+```bash
+git clone https://github.com/kailong321200875/vue-element-plus-admin.git
+```
+
+- 安装依赖
+
+```bash
+cd vue-element-plus-admin
+
+pnpm install
+
+```
+
+- 运行
+
+```bash
+pnpm run dev
+```
+
+- 打包
+
+```bash
+pnpm run build:pro
+```
+
+## 更新日志
+
+[更新日志](./CHANGELOG.md)
+
+## 如何贡献
+
+你可以[提一个 issue](https://github.com/kailong321200875/vue-element-plus-admin/issues/new) 或者提交一个 Pull Request。
+
+**Pull Request:**
+
+1. Fork 代码
+2. 创建自己的分支: `git checkout -b feat/xxxx`
+3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'`
+4. 推送您的分支: `git push origin feat/xxxx`
+5. 提交 `pull request`
+
+## Git 贡献提交规范
+
+- `feat` 新功能
+- `fix` 修补 bug
+- `docs` 文档
+- `style` 格式、样式(不影响代码运行的变动)
+- `refactor` 重构(即不是新增功能,也不是修改 BUG 的代码)
+- `perf` 优化相关,比如提升性能、体验
+- `test` 添加测试
+- `build` 编译相关的修改,对项目构建或者依赖的改动
+- `ci` 持续集成修改
+- `chore` 构建过程或辅助工具的变动
+- `revert` 回滚到上一个版本
+- `workflow` 工作流改进
+- `mod` 不确定分类的修改
+- `wip` 开发中
+- `types` 类型
+
+## 浏览器支持
+
+本地开发推荐使用 `Chrome 80+` 浏览器
+
+支持现代浏览器, 不支持 IE
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## Donate
+
+如果你觉得这个项目有帮助,欢迎赞助以示支持~
+
+[Paypal Me](https://www.paypal.com/paypalme/ckl94)
+
+<img src="https://gitee.com/kailong110120130/my-image/raw/master/pay.jpg" />
+
+## 交流群
+
+如果你想进入技术交流群讨论,请添加我为好友
+
+<img src="https://gitee.com/kailong110120130/my-image/raw/master/me.jpg" />
+
+## 许可证
+
+[MIT](./LICENSE)

+ 28 - 0
commitlint.config.js

@@ -0,0 +1,28 @@
+module.exports = {
+  extends: ['@commitlint/config-conventional'],
+  rules: {
+    'type-enum': [
+      2,
+      'always',
+      [
+        'feat', // 新功能(feature)
+        'fix', // 修补bug
+        'docs', // 文档(documentation)
+        'style', // 格式、样式(不影响代码运行的变动)
+        'refactor', // 重构(即不是新增功能,也不是修改BUG的代码)
+        'perf', // 优化相关,比如提升性能、体验
+        'test', // 添加测试
+        'ci', // 持续集成修改
+        'chore', // 构建过程或辅助工具的变动
+        'revert', // 回滚到上一个版本
+        'workflow', // 工作流改进
+        'mod', // 不确定分类的修改
+        'wip', // 开发中
+        'types', // 类型修改
+        'release' // 版本发布
+      ]
+    ],
+    'subject-full-stop': [0, 'never'],
+    'subject-case': [0, 'never']
+  }
+}

+ 142 - 0
index.html

@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" href="/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title><%= title %></title>
+  </head>
+  <body>
+    <div id="app">
+      <style>
+        .app-loading {
+          display: flex;
+          width: 100%;
+          height: 100%;
+          justify-content: center;
+          align-items: center;
+          flex-direction: column;
+          background: #f0f2f5;
+        }
+
+        .app-loading .app-loading-wrap {
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          display: flex;
+          -webkit-transform: translate3d(-50%, -50%, 0);
+          transform: translate3d(-50%, -50%, 0);
+          justify-content: center;
+          align-items: center;
+          flex-direction: column;
+        }
+
+        .app-loading .app-loading-title {
+          margin-bottom: 30px;
+          font-size: 20px;
+          font-weight: bold;
+          text-align: center;
+        }
+
+        .app-loading .app-loading-logo {
+          width: 100px;
+          margin: 0 auto 15px auto;
+        }
+
+        .app-loading .app-loading-item {
+          position: relative;
+          display: inline-block;
+          width: 60px;
+          height: 60px;
+          vertical-align: middle;
+          border-radius: 50%;
+        }
+
+        .app-loading .app-loading-outter {
+          position: absolute;
+          width: 100%;
+          height: 100%;
+          border: 4px solid #2d8cf0;
+          border-bottom: 0;
+          border-left-color: transparent;
+          border-radius: 50%;
+          animation: loader-outter 1.5s cubic-bezier(0.42, 0.61, 0.58, 0.41) infinite;
+        }
+
+        .app-loading .app-loading-inner {
+          position: absolute;
+          top: calc(50% - 20px);
+          left: calc(50% - 20px);
+          width: 40px;
+          height: 40px;
+          border: 4px solid #87bdff;
+          border-right: 0;
+          border-top-color: transparent;
+          border-radius: 50%;
+          animation: loader-inner 1s cubic-bezier(0.42, 0.61, 0.58, 0.41) infinite;
+        }
+
+        @-webkit-keyframes loader-outter {
+          0% {
+            -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+          }
+
+          100% {
+            -webkit-transform: rotate(360deg);
+            transform: rotate(360deg);
+          }
+        }
+
+        @keyframes loader-outter {
+          0% {
+            -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+          }
+
+          100% {
+            -webkit-transform: rotate(360deg);
+            transform: rotate(360deg);
+          }
+        }
+
+        @-webkit-keyframes loader-inner {
+          0% {
+            -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+          }
+
+          100% {
+            -webkit-transform: rotate(-360deg);
+            transform: rotate(-360deg);
+          }
+        }
+
+        @keyframes loader-inner {
+          0% {
+            -webkit-transform: rotate(0deg);
+            transform: rotate(0deg);
+          }
+
+          100% {
+            -webkit-transform: rotate(-360deg);
+            transform: rotate(-360deg);
+          }
+        }
+      </style>
+      <div class="app-loading">
+        <div class="app-loading-wrap">
+          <div class="app-loading-title">
+            <img src="/logo.png" class="app-loading-logo" alt="Logo" />
+            <div class="app-loading-title"><%= title %></div>
+          </div>
+          <div class="app-loading-item">
+            <div class="app-loading-outter"></div>
+            <div class="app-loading-inner"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 18 - 0
mock/_createProductionServer.ts

@@ -0,0 +1,18 @@
+import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
+
+const modules = import.meta.glob('./**/*.ts', {
+  import: 'default',
+  eager: true
+})
+
+const mockModules: any[] = []
+Object.keys(modules).forEach(async (key) => {
+  if (key.includes('_')) {
+    return
+  }
+  mockModules.push(...(modules[key] as any))
+})
+
+export function setupProdMockServer() {
+  createProdMockServer(mockModules)
+}

+ 89 - 0
mock/analysis/index.ts

@@ -0,0 +1,89 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+
+const { code } = config
+
+const timeout = 1
+
+export default [
+  // 分析页统计接口
+  {
+    url: '/analysis/total',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: {
+          users: 102400,
+          messages: 81212,
+          moneys: 9280,
+          shoppings: 13600
+        }
+      }
+    }
+  },
+  // 用户来源
+  {
+    url: '/analysis/userAccessSource',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          { value: 1000, name: 'analysis.directAccess' },
+          { value: 310, name: 'analysis.mailMarketing' },
+          { value: 234, name: 'analysis.allianceAdvertising' },
+          { value: 135, name: 'analysis.videoAdvertising' },
+          { value: 1548, name: 'analysis.searchEngines' }
+        ]
+      }
+    }
+  },
+  // 每周用户活跃量
+  {
+    url: '/analysis/weeklyUserActivity',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          { value: 13253, name: 'analysis.monday' },
+          { value: 34235, name: 'analysis.tuesday' },
+          { value: 26321, name: 'analysis.wednesday' },
+          { value: 12340, name: 'analysis.thursday' },
+          { value: 24643, name: 'analysis.friday' },
+          { value: 1322, name: 'analysis.saturday' },
+          { value: 1324, name: 'analysis.sunday' }
+        ]
+      }
+    }
+  },
+  // 每月销售额
+  {
+    url: '/analysis/monthlySales',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          { estimate: 100, actual: 120, name: 'analysis.january' },
+          { estimate: 120, actual: 82, name: 'analysis.february' },
+          { estimate: 161, actual: 91, name: 'analysis.march' },
+          { estimate: 134, actual: 154, name: 'analysis.april' },
+          { estimate: 105, actual: 162, name: 'analysis.may' },
+          { estimate: 160, actual: 140, name: 'analysis.june' },
+          { estimate: 165, actual: 145, name: 'analysis.july' },
+          { estimate: 114, actual: 250, name: 'analysis.august' },
+          { estimate: 163, actual: 134, name: 'analysis.september' },
+          { estimate: 185, actual: 56, name: 'analysis.october' },
+          { estimate: 118, actual: 99, name: 'analysis.november' },
+          { estimate: 123, actual: 123, name: 'analysis.december' }
+        ]
+      }
+    }
+  }
+] as MockMethod[]

+ 219 - 0
mock/department/index.ts

@@ -0,0 +1,219 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+import { toAnyString } from '@/utils'
+import Mock from 'mockjs'
+
+const { code } = config
+
+const departmentList: any = []
+
+const citys = ['厦门总公司', '北京分公司', '上海分公司', '福州分公司', '深圳分公司', '杭州分公司']
+
+for (let i = 0; i < 5; i++) {
+  let departmentId = toAnyString()
+  departmentList.push({
+    // 部门名称
+    departmentName: citys[i],
+    id: departmentId,
+    createTime: '@datetime',
+    superiorDepartment: '',
+    // 状态
+    status: Mock.Random.integer(0, 1),
+    // 备注
+    remark: '@cword(10, 15)',
+    children: [
+      {
+        // 部门名称
+        departmentName: '研发部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      },
+      {
+        // 部门名称
+        departmentName: '产品部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      },
+      {
+        // 部门名称
+        departmentName: '运营部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      },
+      {
+        // 部门名称
+        departmentName: '市场部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      },
+      {
+        // 部门名称
+        departmentName: '销售部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      },
+      {
+        // 部门名称
+        departmentName: '客服部',
+        createTime: '@datetime',
+        superiorDepartment: departmentId,
+        superiorDepartmentName: citys[i],
+        // 状态
+        status: Mock.Random.integer(0, 1),
+        id: toAnyString(),
+        remark: '@cword(10, 15)'
+      }
+    ]
+  })
+}
+
+export default [
+  // 列表接口
+  {
+    url: '/department/list',
+    method: 'get',
+    response: () => {
+      return {
+        code: code,
+        data: {
+          list: departmentList
+        }
+      }
+    }
+  },
+  {
+    url: '/department/table/list',
+    method: 'get',
+    response: () => {
+      return {
+        code: code,
+        data: {
+          list: departmentList,
+          total: 5
+        }
+      }
+    }
+  },
+  {
+    url: '/department/users',
+    method: 'get',
+    timeout: 1000,
+    response: ({ query }) => {
+      const { pageSize } = query
+      // 根据pageSize来创建数据
+      const mockList: any = []
+      for (let i = 0; i < pageSize; i++) {
+        mockList.push(
+          Mock.mock({
+            // 用户名
+            username: '@cname',
+            // 账号
+            account: '@first',
+            // 邮箱
+            email: '@EMAIL',
+            // 创建时间
+            createTime: '@datetime',
+            // 角色
+            role: '@first',
+            // 用户id
+            id: toAnyString()
+          })
+        )
+      }
+      return {
+        code: code,
+        data: {
+          total: 100,
+          list: mockList
+        }
+      }
+    }
+  },
+  // 保存接口
+  {
+    url: '/department/user/save',
+    method: 'post',
+    timeout: 1000,
+    response: () => {
+      return {
+        code: code,
+        data: 'success'
+      }
+    }
+  },
+  // 删除接口
+  {
+    url: '/department/user/delete',
+    method: 'post',
+    response: ({ body }) => {
+      const ids = body.ids
+      if (!ids) {
+        return {
+          code: 500,
+          message: '请选择需要删除的数据'
+        }
+      } else {
+        return {
+          code: code,
+          data: 'success'
+        }
+      }
+    }
+  },
+  // 保存接口
+  {
+    url: '/department/save',
+    method: 'post',
+    timeout: 1000,
+    response: () => {
+      return {
+        code: code,
+        data: 'success'
+      }
+    }
+  },
+  // 删除接口
+  {
+    url: '/department/delete',
+    method: 'post',
+    response: ({ body }) => {
+      const ids = body.ids
+      if (!ids) {
+        return {
+          code: 500,
+          message: '请选择需要删除的数据'
+        }
+      } else {
+        return {
+          code: code,
+          data: 'success'
+        }
+      }
+    }
+  }
+] as MockMethod[]

+ 63 - 0
mock/dict/index.ts

@@ -0,0 +1,63 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+
+const { code } = config
+
+const timeout = 1
+
+const dictObj: Recordable = {
+  importance: [
+    {
+      value: 0,
+      label: 'tableDemo.commonly'
+    },
+    {
+      value: 1,
+      label: 'tableDemo.good'
+    },
+    {
+      value: 2,
+      label: 'tableDemo.important'
+    }
+  ]
+}
+
+export default [
+  // 字典接口
+  {
+    url: '/dict/list',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: dictObj
+      }
+    }
+  },
+  // 获取某个字典
+  {
+    url: '/dict/one',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          {
+            label: 'test1',
+            value: 0
+          },
+          {
+            label: 'test2',
+            value: 1
+          },
+          {
+            label: 'test3',
+            value: 2
+          }
+        ]
+      }
+    }
+  }
+] as MockMethod[]

+ 248 - 0
mock/menu/index.ts

@@ -0,0 +1,248 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+import Mock from 'mockjs'
+
+const { code } = config
+
+const timeout = 1000
+
+export default [
+  // 列表接口
+  {
+    url: '/menu/list',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: {
+          list: [
+            {
+              path: '/dashboard',
+              component: '#',
+              redirect: '/dashboard/analysis',
+              name: 'Dashboard',
+              status: Mock.Random.integer(0, 1),
+              id: 1,
+              meta: {
+                title: '首页',
+                icon: 'ant-design:dashboard-filled',
+                alwaysShow: true
+              },
+              children: [
+                {
+                  path: 'analysis',
+                  component: 'views/Dashboard/Analysis',
+                  name: 'Analysis',
+                  status: Mock.Random.integer(0, 1),
+                  id: 2,
+                  meta: {
+                    title: '分析页',
+                    noCache: true
+                  }
+                },
+                {
+                  path: 'workplace',
+                  component: 'views/Dashboard/Workplace',
+                  name: 'Workplace',
+                  status: Mock.Random.integer(0, 1),
+                  id: 3,
+                  meta: {
+                    title: '工作台',
+                    noCache: true
+                  }
+                }
+              ]
+            },
+            {
+              path: '/external-link',
+              component: '#',
+              meta: {
+                title: '文档',
+                icon: 'clarity:document-solid'
+              },
+              name: 'ExternalLink',
+              status: Mock.Random.integer(0, 1),
+              id: 4,
+              children: [
+                {
+                  path: 'https://element-plus-admin-doc.cn/',
+                  name: 'DocumentLink',
+                  status: Mock.Random.integer(0, 1),
+                  id: 5,
+                  meta: {
+                    title: '文档'
+                  }
+                }
+              ]
+            },
+            {
+              path: '/level',
+              component: '#',
+              redirect: '/level/menu1/menu1-1/menu1-1-1',
+              name: 'Level',
+              status: Mock.Random.integer(0, 1),
+              id: 6,
+              meta: {
+                title: '菜单',
+                icon: 'carbon:skill-level-advanced'
+              },
+              children: [
+                {
+                  path: 'menu1',
+                  name: 'Menu1',
+                  component: '##',
+                  status: Mock.Random.integer(0, 1),
+                  id: 7,
+                  redirect: '/level/menu1/menu1-1/menu1-1-1',
+                  meta: {
+                    title: '菜单1'
+                  },
+                  children: [
+                    {
+                      path: 'menu1-1',
+                      name: 'Menu11',
+                      component: '##',
+                      status: Mock.Random.integer(0, 1),
+                      id: 8,
+                      redirect: '/level/menu1/menu1-1/menu1-1-1',
+                      meta: {
+                        title: '菜单1-1',
+                        alwaysShow: true
+                      },
+                      children: [
+                        {
+                          path: 'menu1-1-1',
+                          name: 'Menu111',
+                          component: 'views/Level/Menu111',
+                          status: Mock.Random.integer(0, 1),
+                          id: 9,
+                          permission: ['edit', 'add', 'delete'],
+                          meta: {
+                            title: '菜单1-1-1'
+                          }
+                        }
+                      ]
+                    },
+                    {
+                      path: 'menu1-2',
+                      name: 'Menu12',
+                      component: 'views/Level/Menu12',
+                      status: Mock.Random.integer(0, 1),
+                      id: 10,
+                      permission: ['edit', 'add', 'delete'],
+                      meta: {
+                        title: '菜单1-2'
+                      }
+                    }
+                  ]
+                },
+                {
+                  path: 'menu2',
+                  name: 'Menu2Demo',
+                  component: 'views/Level/Menu2',
+                  status: Mock.Random.integer(0, 1),
+                  id: 11,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '菜单2'
+                  }
+                }
+              ]
+            },
+            {
+              path: '/example',
+              component: '#',
+              redirect: '/example/example-dialog',
+              name: 'Example',
+              status: Mock.Random.integer(0, 1),
+              id: 12,
+              meta: {
+                title: '综合示例',
+                icon: 'ep:management',
+                alwaysShow: true
+              },
+              children: [
+                {
+                  path: 'example-dialog',
+                  component: 'views/Example/Dialog/ExampleDialog',
+                  name: 'ExampleDialog',
+                  status: Mock.Random.integer(0, 1),
+                  id: 13,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '综合示例-弹窗',
+                    permission: ['edit', 'add']
+                  }
+                },
+                {
+                  path: 'example-page',
+                  component: 'views/Example/Page/ExamplePage',
+                  name: 'ExamplePage',
+                  status: Mock.Random.integer(0, 1),
+                  id: 14,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '综合示例-页面',
+                    permission: ['edit', 'add']
+                  }
+                },
+                {
+                  path: 'example-add',
+                  component: 'views/Example/Page/ExampleAdd',
+                  name: 'ExampleAdd',
+                  status: Mock.Random.integer(0, 1),
+                  id: 15,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '综合示例-新增',
+                    noTagsView: true,
+                    noCache: true,
+                    hidden: true,
+                    showMainRoute: true,
+                    activeMenu: '/example/example-page',
+                    permission: ['delete', 'add']
+                  }
+                },
+                {
+                  path: 'example-edit',
+                  component: 'views/Example/Page/ExampleEdit',
+                  name: 'ExampleEdit',
+                  status: Mock.Random.integer(0, 1),
+                  id: 16,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '综合示例-编辑',
+                    noTagsView: true,
+                    noCache: true,
+                    hidden: true,
+                    showMainRoute: true,
+                    activeMenu: '/example/example-page',
+                    permission: ['delete', 'add']
+                  }
+                },
+                {
+                  path: 'example-detail',
+                  component: 'views/Example/Page/ExampleDetail',
+                  name: 'ExampleDetail',
+                  status: Mock.Random.integer(0, 1),
+                  id: 17,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '综合示例-详情',
+                    noTagsView: true,
+                    noCache: true,
+                    hidden: true,
+                    showMainRoute: true,
+                    activeMenu: '/example/example-page',
+                    permission: ['delete', 'edit']
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  }
+] as MockMethod[]

+ 1129 - 0
mock/role/index.ts

@@ -0,0 +1,1129 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+import Mock from 'mockjs'
+import { toAnyString } from '@/utils'
+
+const { code } = config
+
+const timeout = 1000
+
+const adminList = [
+  {
+    path: '/dashboard',
+    component: '#',
+    redirect: '/dashboard/analysis',
+    name: 'Dashboard',
+    meta: {
+      title: 'router.dashboard',
+      icon: 'ant-design:dashboard-filled',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'analysis',
+        component: 'views/Dashboard/Analysis',
+        name: 'Analysis',
+        meta: {
+          title: 'router.analysis',
+          noCache: true
+        }
+      },
+      {
+        path: 'workplace',
+        component: 'views/Dashboard/Workplace',
+        name: 'Workplace',
+        meta: {
+          title: 'router.workplace',
+          noCache: true
+        }
+      }
+    ]
+  },
+  {
+    path: '/external-link',
+    component: '#',
+    meta: {},
+    name: 'ExternalLink',
+    children: [
+      {
+        path: 'https://element-plus-admin-doc.cn/',
+        name: 'DocumentLink',
+        meta: {
+          title: 'router.document',
+          icon: 'clarity:document-solid'
+        }
+      }
+    ]
+  },
+  {
+    path: '/guide',
+    component: '#',
+    name: 'Guide',
+    meta: {},
+    children: [
+      {
+        path: 'index',
+        component: 'views/Guide/Guide',
+        name: 'GuideDemo',
+        meta: {
+          title: 'router.guide',
+          icon: 'cib:telegram-plane'
+        }
+      }
+    ]
+  },
+  {
+    path: '/components',
+    component: '#',
+    redirect: '/components/form/default-form',
+    name: 'ComponentsDemo',
+    meta: {
+      title: 'router.component',
+      icon: 'bx:bxs-component',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'form',
+        component: '##',
+        name: 'Form',
+        meta: {
+          title: 'router.form',
+          alwaysShow: true
+        },
+        children: [
+          {
+            path: 'default-form',
+            component: 'views/Components/Form/DefaultForm',
+            name: 'DefaultForm',
+            meta: {
+              title: 'router.defaultForm'
+            }
+          },
+          {
+            path: 'use-form',
+            component: 'views/Components/Form/UseFormDemo',
+            name: 'UseForm',
+            meta: {
+              title: 'UseForm'
+            }
+          }
+        ]
+      },
+      {
+        path: 'table',
+        component: '##',
+        redirect: '/components/table/default-table',
+        name: 'TableDemo',
+        meta: {
+          title: 'router.table',
+          alwaysShow: true
+        },
+        children: [
+          {
+            path: 'default-table',
+            component: 'views/Components/Table/DefaultTable',
+            name: 'DefaultTable',
+            meta: {
+              title: 'router.defaultTable'
+            }
+          },
+          {
+            path: 'use-table',
+            component: 'views/Components/Table/UseTableDemo',
+            name: 'UseTable',
+            meta: {
+              title: 'UseTable'
+            }
+          },
+          {
+            path: 'tree-table',
+            component: 'views/Components/Table/TreeTable',
+            name: 'TreeTable',
+            meta: {
+              title: 'TreeTable'
+            }
+          },
+          {
+            path: 'table-image-preview',
+            component: 'views/Components/Table/TableImagePreview',
+            name: 'TableImagePreview',
+            meta: {
+              title: 'router.PicturePreview'
+            }
+          }
+          // {
+          //   path: 'ref-table',
+          //   component: 'views/Components/Table/RefTable',
+          //   name: 'RefTable',
+          //   meta: {
+          //     title: 'RefTable'
+          //   }
+          // }
+        ]
+      },
+      {
+        path: 'editor-demo',
+        component: '##',
+        redirect: '/components/editor-demo/editor',
+        name: 'EditorDemo',
+        meta: {
+          title: 'router.editor',
+          alwaysShow: true
+        },
+        children: [
+          {
+            path: 'editor',
+            component: 'views/Components/Editor/Editor',
+            name: 'Editor',
+            meta: {
+              title: 'router.richText'
+            }
+          },
+          {
+            path: 'json-editor',
+            component: 'views/Components/Editor/JsonEditor',
+            name: 'JsonEditor',
+            meta: {
+              title: 'router.jsonEditor'
+            }
+          }
+        ]
+      },
+      {
+        path: 'search',
+        component: 'views/Components/Search',
+        name: 'Search',
+        meta: {
+          title: 'router.search'
+        }
+      },
+      {
+        path: 'descriptions',
+        component: 'views/Components/Descriptions',
+        name: 'Descriptions',
+        meta: {
+          title: 'router.descriptions'
+        }
+      },
+      {
+        path: 'image-viewer',
+        component: 'views/Components/ImageViewer',
+        name: 'ImageViewer',
+        meta: {
+          title: 'router.imageViewer'
+        }
+      },
+      {
+        path: 'dialog',
+        component: 'views/Components/Dialog',
+        name: 'Dialog',
+        meta: {
+          title: 'router.dialog'
+        }
+      },
+      {
+        path: 'icon',
+        component: 'views/Components/Icon',
+        name: 'Icon',
+        meta: {
+          title: 'router.icon'
+        }
+      },
+      {
+        path: 'icon-picker',
+        component: 'views/Components/IconPicker',
+        name: 'IconPicker',
+        meta: {
+          title: 'router.iconPicker'
+        }
+      },
+      {
+        path: 'echart',
+        component: 'views/Components/Echart',
+        name: 'Echart',
+        meta: {
+          title: 'router.echart'
+        }
+      },
+      {
+        path: 'count-to',
+        component: 'views/Components/CountTo',
+        name: 'CountTo',
+        meta: {
+          title: 'router.countTo'
+        }
+      },
+      {
+        path: 'qrcode',
+        component: 'views/Components/Qrcode',
+        name: 'Qrcode',
+        meta: {
+          title: 'router.qrcode'
+        }
+      },
+      {
+        path: 'highlight',
+        component: 'views/Components/Highlight',
+        name: 'Highlight',
+        meta: {
+          title: 'router.highlight'
+        }
+      },
+      {
+        path: 'infotip',
+        component: 'views/Components/Infotip',
+        name: 'Infotip',
+        meta: {
+          title: 'router.infotip'
+        }
+      },
+      {
+        path: 'input-password',
+        component: 'views/Components/InputPassword',
+        name: 'InputPassword',
+        meta: {
+          title: 'router.inputPassword'
+        }
+      }
+    ]
+  },
+  {
+    path: '/function',
+    component: '#',
+    redirect: '/function/multipleTabs',
+    name: 'Function',
+    meta: {
+      title: 'router.function',
+      icon: 'ri:function-fill',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'multipleTabs',
+        component: 'views/Function/MultipleTabs',
+        name: 'MultipleTabs',
+        meta: {
+          title: 'router.multipleTabs'
+        }
+      },
+      {
+        path: 'multipleTabs-demo/:id',
+        component: 'views/Function/MultipleTabsDemo',
+        name: 'MultipleTabsDemo',
+        meta: {
+          hidden: true,
+          title: 'router.details',
+          canTo: true
+        }
+      }
+    ]
+  },
+  {
+    path: '/hooks',
+    component: '#',
+    redirect: '/hooks/useWatermark',
+    name: 'Hooks',
+    meta: {
+      title: 'hooks',
+      icon: 'ic:outline-webhook',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'useWatermark',
+        component: 'views/hooks/useWatermark',
+        name: 'UseWatermark',
+        meta: {
+          title: 'useWatermark'
+        }
+      },
+      {
+        path: 'useTagsView',
+        component: 'views/hooks/useTagsView',
+        name: 'UseTagsView',
+        meta: {
+          title: 'useTagsView'
+        }
+      },
+      {
+        path: 'useValidator',
+        component: 'views/hooks/useValidator',
+        name: 'UseValidator',
+        meta: {
+          title: 'useValidator'
+        }
+      },
+      {
+        path: 'useCrudSchemas',
+        component: 'views/hooks/useCrudSchemas',
+        name: 'UseCrudSchemas',
+        meta: {
+          title: 'useCrudSchemas'
+        }
+      }
+    ]
+  },
+  {
+    path: '/level',
+    component: '#',
+    redirect: '/level/menu1/menu1-1/menu1-1-1',
+    name: 'Level',
+    meta: {
+      title: 'router.level',
+      icon: 'carbon:skill-level-advanced'
+    },
+    children: [
+      {
+        path: 'menu1',
+        name: 'Menu1',
+        component: '##',
+        redirect: '/level/menu1/menu1-1/menu1-1-1',
+        meta: {
+          title: 'router.menu1'
+        },
+        children: [
+          {
+            path: 'menu1-1',
+            name: 'Menu11',
+            component: '##',
+            redirect: '/level/menu1/menu1-1/menu1-1-1',
+            meta: {
+              title: 'router.menu11',
+              alwaysShow: true
+            },
+            children: [
+              {
+                path: 'menu1-1-1',
+                name: 'Menu111',
+                component: 'views/Level/Menu111',
+                meta: {
+                  title: 'router.menu111'
+                }
+              }
+            ]
+          },
+          {
+            path: 'menu1-2',
+            name: 'Menu12',
+            component: 'views/Level/Menu12',
+            meta: {
+              title: 'router.menu12'
+            }
+          }
+        ]
+      },
+      {
+        path: 'menu2',
+        name: 'Menu2Demo',
+        component: 'views/Level/Menu2',
+        meta: {
+          title: 'router.menu2'
+        }
+      }
+    ]
+  },
+  {
+    path: '/example',
+    component: '#',
+    redirect: '/example/example-dialog',
+    name: 'Example',
+    meta: {
+      title: 'router.example',
+      icon: 'ep:management',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'example-dialog',
+        component: 'views/Example/Dialog/ExampleDialog',
+        name: 'ExampleDialog',
+        meta: {
+          title: 'router.exampleDialog'
+        }
+      },
+      {
+        path: 'example-page',
+        component: 'views/Example/Page/ExamplePage',
+        name: 'ExamplePage',
+        meta: {
+          title: 'router.examplePage'
+        }
+      },
+      {
+        path: 'example-add',
+        component: 'views/Example/Page/ExampleAdd',
+        name: 'ExampleAdd',
+        meta: {
+          title: 'router.exampleAdd',
+          noTagsView: true,
+          noCache: true,
+          hidden: true,
+          showMainRoute: true,
+          activeMenu: '/example/example-page'
+        }
+      },
+      {
+        path: 'example-edit',
+        component: 'views/Example/Page/ExampleEdit',
+        name: 'ExampleEdit',
+        meta: {
+          title: 'router.exampleEdit',
+          noTagsView: true,
+          noCache: true,
+          hidden: true,
+          showMainRoute: true,
+          activeMenu: '/example/example-page'
+        }
+      },
+      {
+        path: 'example-detail',
+        component: 'views/Example/Page/ExampleDetail',
+        name: 'ExampleDetail',
+        meta: {
+          title: 'router.exampleDetail',
+          noTagsView: true,
+          noCache: true,
+          hidden: true,
+          showMainRoute: true,
+          activeMenu: '/example/example-page'
+        }
+      }
+    ]
+  },
+  {
+    path: '/error',
+    component: '#',
+    redirect: '/error/404',
+    name: 'Error',
+    meta: {
+      title: 'router.errorPage',
+      icon: 'ci:error',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: '404-demo',
+        component: 'views/Error/404',
+        name: '404Demo',
+        meta: {
+          title: '404'
+        }
+      },
+      {
+        path: '403-demo',
+        component: 'views/Error/403',
+        name: '403Demo',
+        meta: {
+          title: '403'
+        }
+      },
+      {
+        path: '500-demo',
+        component: 'views/Error/500',
+        name: '500Demo',
+        meta: {
+          title: '500'
+        }
+      }
+    ]
+  },
+  {
+    path: '/authorization',
+    component: '#',
+    redirect: '/authorization/user',
+    name: 'Authorization',
+    meta: {
+      title: 'router.authorization',
+      icon: 'eos-icons:role-binding',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'department',
+        component: 'views/Authorization/Department/Department',
+        name: 'Department',
+        meta: {
+          title: 'router.department'
+        }
+      },
+      {
+        path: 'user',
+        component: 'views/Authorization/User/User',
+        name: 'User',
+        meta: {
+          title: 'router.user'
+        }
+      },
+      {
+        path: 'menu',
+        component: 'views/Authorization/Menu/Menu',
+        name: 'Menu',
+        meta: {
+          title: 'router.menuManagement'
+        }
+      },
+      {
+        path: 'role',
+        component: 'views/Authorization/Role/Role',
+        name: 'Role',
+        meta: {
+          title: 'router.role'
+        }
+      },
+      {
+        path: 'test',
+        component: 'views/Authorization/Test/Test',
+        name: 'Test',
+        meta: {
+          title: 'router.permission'
+        }
+      }
+    ]
+  }
+]
+
+const testList: string[] = [
+  '/dashboard',
+  '/dashboard/analysis',
+  '/dashboard/workplace',
+  'external-link',
+  'https://element-plus-admin-doc.cn/',
+  '/guide',
+  '/guide/index',
+  '/components',
+  '/components/form',
+  '/components/form/default-form',
+  '/components/form/use-form',
+  '/components/form/ref-form',
+  '/components/table',
+  '/components/table/default-table',
+  '/components/table/use-table',
+  '/components/table/tree-table',
+  '/components/table/table-image-preview',
+  '/components/table/ref-table',
+  '/components/editor-demo',
+  '/components/editor-demo/editor',
+  '/components/editor-demo/json-editor',
+  '/components/search',
+  '/components/descriptions',
+  '/components/image-viewer',
+  '/components/dialog',
+  '/components/icon',
+  '/components/iconPicker',
+  '/components/echart',
+  '/components/count-to',
+  '/components/qrcode',
+  '/components/highlight',
+  '/components/infotip',
+  '/Components/InputPassword',
+  '/Components/Sticky',
+  'function',
+  '/function/multiple-tabs',
+  '/function/multiple-tabs-demo/:id',
+  '/hooks',
+  '/hooks/useWatermark',
+  '/hooks/useTagsView',
+  '/hooks/useValidator',
+  '/hooks/useCrudSchemas',
+  '/level',
+  '/level/menu1',
+  '/level/menu1/menu1-1',
+  '/level/menu1/menu1-1/menu1-1-1',
+  '/level/menu1/menu1-2',
+  '/level/menu2',
+  '/example',
+  '/example/example-dialog',
+  '/example/example-page',
+  '/example/example-add',
+  '/example/example-edit',
+  '/example/example-detail',
+  '/authorization',
+  '/authorization/department',
+  '/authorization/user',
+  '/authorization/role',
+  '/authorization/menu',
+  '/authorization/test',
+  '/error',
+  '/error/404-demo',
+  '/error/403-demo',
+  '/error/500-demo'
+]
+
+const List: any[] = []
+
+const roleNames = ['超级管理员', '管理员', '普通用户', '游客']
+const menus = [
+  [
+    {
+      path: '/dashboard',
+      component: '#',
+      redirect: '/dashboard/analysis',
+      name: 'Dashboard',
+      status: Mock.Random.integer(0, 1),
+      id: 1,
+      meta: {
+        title: '首页',
+        icon: 'ant-design:dashboard-filled',
+        alwaysShow: true
+      },
+      children: [
+        {
+          path: 'analysis',
+          component: 'views/Dashboard/Analysis',
+          name: 'Analysis',
+          status: Mock.Random.integer(0, 1),
+          id: 2,
+          meta: {
+            title: '分析页',
+            noCache: true
+          }
+        },
+        {
+          path: 'workplace',
+          component: 'views/Dashboard/Workplace',
+          name: 'Workplace',
+          status: Mock.Random.integer(0, 1),
+          id: 3,
+          meta: {
+            title: '工作台',
+            noCache: true
+          }
+        }
+      ]
+    },
+    {
+      path: '/external-link',
+      component: '#',
+      meta: {
+        title: '文档',
+        icon: 'clarity:document-solid'
+      },
+      name: 'ExternalLink',
+      status: Mock.Random.integer(0, 1),
+      id: 4,
+      children: [
+        {
+          path: 'https://element-plus-admin-doc.cn/',
+          name: 'DocumentLink',
+          status: Mock.Random.integer(0, 1),
+          id: 5,
+          meta: {
+            title: '文档'
+          }
+        }
+      ]
+    },
+    {
+      path: '/level',
+      component: '#',
+      redirect: '/level/menu1/menu1-1/menu1-1-1',
+      name: 'Level',
+      status: Mock.Random.integer(0, 1),
+      id: 6,
+      meta: {
+        title: '菜单',
+        icon: 'carbon:skill-level-advanced'
+      },
+      children: [
+        {
+          path: 'menu1',
+          name: 'Menu1',
+          component: '##',
+          status: Mock.Random.integer(0, 1),
+          id: 7,
+          redirect: '/level/menu1/menu1-1/menu1-1-1',
+          meta: {
+            title: '菜单1'
+          },
+          children: [
+            {
+              path: 'menu1-1',
+              name: 'Menu11',
+              component: '##',
+              status: Mock.Random.integer(0, 1),
+              id: 8,
+              redirect: '/level/menu1/menu1-1/menu1-1-1',
+              meta: {
+                title: '菜单1-1',
+                alwaysShow: true
+              },
+              children: [
+                {
+                  path: 'menu1-1-1',
+                  name: 'Menu111',
+                  component: 'views/Level/Menu111',
+                  status: Mock.Random.integer(0, 1),
+                  id: 9,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '菜单1-1-1',
+                    permission: ['edit', 'add', 'delete']
+                  }
+                }
+              ]
+            },
+            {
+              path: 'menu1-2',
+              name: 'Menu12',
+              component: 'views/Level/Menu12',
+              status: Mock.Random.integer(0, 1),
+              id: 10,
+              permission: ['edit', 'add', 'delete'],
+              meta: {
+                title: '菜单1-2',
+                permission: ['edit', 'add', 'delete']
+              }
+            }
+          ]
+        },
+        {
+          path: 'menu2',
+          name: 'Menu2Demo',
+          component: 'views/Level/Menu2',
+          status: Mock.Random.integer(0, 1),
+          id: 11,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '菜单2',
+            permission: ['edit', 'add', 'delete']
+          }
+        }
+      ]
+    },
+    {
+      path: '/example',
+      component: '#',
+      redirect: '/example/example-dialog',
+      name: 'Example',
+      status: Mock.Random.integer(0, 1),
+      id: 12,
+      meta: {
+        title: '综合示例',
+        icon: 'ep:management',
+        alwaysShow: true
+      },
+      children: [
+        {
+          path: 'example-dialog',
+          component: 'views/Example/Dialog/ExampleDialog',
+          name: 'ExampleDialog',
+          status: Mock.Random.integer(0, 1),
+          id: 13,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-弹窗',
+            permission: ['edit', 'add', 'delete']
+          }
+        },
+        {
+          path: 'example-page',
+          component: 'views/Example/Page/ExamplePage',
+          name: 'ExamplePage',
+          status: Mock.Random.integer(0, 1),
+          id: 14,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-页面',
+            permission: ['edit', 'add', 'delete']
+          }
+        },
+        {
+          path: 'example-add',
+          component: 'views/Example/Page/ExampleAdd',
+          name: 'ExampleAdd',
+          status: Mock.Random.integer(0, 1),
+          id: 15,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-新增',
+            noTagsView: true,
+            noCache: true,
+            hidden: true,
+            showMainRoute: true,
+            activeMenu: '/example/example-page',
+            permission: ['edit', 'add', 'delete']
+          }
+        },
+        {
+          path: 'example-edit',
+          component: 'views/Example/Page/ExampleEdit',
+          name: 'ExampleEdit',
+          status: Mock.Random.integer(0, 1),
+          id: 16,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-编辑',
+            noTagsView: true,
+            noCache: true,
+            hidden: true,
+            showMainRoute: true,
+            activeMenu: '/example/example-page',
+            permission: ['edit', 'add', 'delete']
+          }
+        },
+        {
+          path: 'example-detail',
+          component: 'views/Example/Page/ExampleDetail',
+          name: 'ExampleDetail',
+          status: Mock.Random.integer(0, 1),
+          id: 17,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-详情',
+            noTagsView: true,
+            noCache: true,
+            hidden: true,
+            showMainRoute: true,
+            activeMenu: '/example/example-page',
+            permission: ['edit', 'add', 'delete']
+          }
+        }
+      ]
+    }
+  ],
+  [
+    {
+      path: '/dashboard',
+      component: '#',
+      redirect: '/dashboard/analysis',
+      name: 'Dashboard',
+      status: Mock.Random.integer(0, 1),
+      id: 1,
+      meta: {
+        title: '首页',
+        icon: 'ant-design:dashboard-filled',
+        alwaysShow: true
+      },
+      children: [
+        {
+          path: 'analysis',
+          component: 'views/Dashboard/Analysis',
+          name: 'Analysis',
+          status: Mock.Random.integer(0, 1),
+          id: 2,
+          meta: {
+            title: '分析页',
+            noCache: true
+          }
+        },
+        {
+          path: 'workplace',
+          component: 'views/Dashboard/Workplace',
+          name: 'Workplace',
+          status: Mock.Random.integer(0, 1),
+          id: 3,
+          meta: {
+            title: '工作台',
+            noCache: true
+          }
+        }
+      ]
+    }
+  ],
+  [
+    {
+      path: '/external-link',
+      component: '#',
+      meta: {
+        title: '文档',
+        icon: 'clarity:document-solid'
+      },
+      name: 'ExternalLink',
+      status: Mock.Random.integer(0, 1),
+      id: 4,
+      children: [
+        {
+          path: 'https://element-plus-admin-doc.cn/',
+          name: 'DocumentLink',
+          status: Mock.Random.integer(0, 1),
+          id: 5,
+          meta: {
+            title: '文档'
+          }
+        }
+      ]
+    },
+    {
+      path: '/level',
+      component: '#',
+      redirect: '/level/menu1/menu1-1/menu1-1-1',
+      name: 'Level',
+      status: Mock.Random.integer(0, 1),
+      id: 6,
+      meta: {
+        title: '菜单',
+        icon: 'carbon:skill-level-advanced'
+      },
+      children: [
+        {
+          path: 'menu1',
+          name: 'Menu1',
+          component: '##',
+          status: Mock.Random.integer(0, 1),
+          id: 7,
+          redirect: '/level/menu1/menu1-1/menu1-1-1',
+          meta: {
+            title: '菜单1'
+          },
+          children: [
+            {
+              path: 'menu1-1',
+              name: 'Menu11',
+              component: '##',
+              status: Mock.Random.integer(0, 1),
+              id: 8,
+              redirect: '/level/menu1/menu1-1/menu1-1-1',
+              meta: {
+                title: '菜单1-1',
+                alwaysShow: true
+              },
+              children: [
+                {
+                  path: 'menu1-1-1',
+                  name: 'Menu111',
+                  component: 'views/Level/Menu111',
+                  status: Mock.Random.integer(0, 1),
+                  id: 9,
+                  permission: ['edit', 'add', 'delete'],
+                  meta: {
+                    title: '菜单1-1-1',
+                    permission: ['edit', 'add', 'delete']
+                  }
+                }
+              ]
+            },
+            {
+              path: 'menu1-2',
+              name: 'Menu12',
+              component: 'views/Level/Menu12',
+              status: Mock.Random.integer(0, 1),
+              id: 10,
+              permission: ['edit', 'add', 'delete'],
+              meta: {
+                title: '菜单1-2',
+                permission: ['edit', 'add', 'delete']
+              }
+            }
+          ]
+        },
+        {
+          path: 'menu2',
+          name: 'Menu2Demo',
+          component: 'views/Level/Menu2',
+          status: Mock.Random.integer(0, 1),
+          id: 11,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '菜单2',
+            permission: ['edit', 'add', 'delete']
+          }
+        }
+      ]
+    }
+  ],
+  [
+    {
+      path: '/example',
+      component: '#',
+      redirect: '/example/example-dialog',
+      name: 'Example',
+      status: Mock.Random.integer(0, 1),
+      id: 12,
+      meta: {
+        title: '综合示例',
+        icon: 'ep:management',
+        alwaysShow: true
+      },
+      children: [
+        {
+          path: 'example-detail',
+          component: 'views/Example/Page/ExampleDetail',
+          name: 'ExampleDetail',
+          status: Mock.Random.integer(0, 1),
+          id: 17,
+          permission: ['edit', 'add', 'delete'],
+          meta: {
+            title: '综合示例-详情',
+            noTagsView: true,
+            noCache: true,
+            hidden: true,
+            showMainRoute: true,
+            activeMenu: '/example/example-page',
+            permission: ['edit', 'add', 'delete']
+          }
+        }
+      ]
+    }
+  ]
+]
+
+for (let i = 0; i < 4; i++) {
+  List.push(
+    Mock.mock({
+      id: toAnyString(),
+      // timestamp: +Mock.Random.date('T'),
+      roleName: roleNames[i],
+      role: '@first',
+      status: Mock.Random.integer(0, 1),
+      createTime: '@datetime',
+      remark: '@cword(10, 15)',
+      menu: menus[i]
+    })
+  )
+}
+
+export default [
+  // 列表接口
+  {
+    url: '/role/list',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: adminList
+      }
+    }
+  },
+  {
+    url: '/role/table',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: {
+          list: List,
+          total: 4
+        }
+      }
+    }
+  },
+  // 列表接口
+  {
+    url: '/role/list2',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: testList
+      }
+    }
+  },
+  {
+    url: '/role/table',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: {
+          list: List,
+          total: 4
+        }
+      }
+    }
+  }
+] as MockMethod[]

+ 256 - 0
mock/table/index.ts

@@ -0,0 +1,256 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+import { toAnyString } from '@/utils'
+import Mock from 'mockjs'
+
+const { code } = config
+
+const timeout = 1
+
+const count = 100
+
+const baseContent =
+  '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
+
+interface ListProps {
+  id: string
+  author: string
+  title: string
+  content: string
+  importance: number
+  display_time: string
+  pageviews: number
+  image_uri: string
+}
+
+interface TreeListProps {
+  id: string
+  author: string
+  title: string
+  content: string
+  importance: number
+  display_time: string
+  pageviews: number
+  children: TreeListProps[]
+}
+
+let List: ListProps[] = []
+
+for (let i = 0; i < count; i++) {
+  List.push(
+    Mock.mock({
+      id: toAnyString(),
+      // timestamp: +Mock.Random.date('T'),
+      author: '@first',
+      title: '@title(5, 10)',
+      content: baseContent,
+      importance: '@integer(1, 3)',
+      display_time: '@datetime',
+      pageviews: '@integer(300, 5000)',
+      image_uri: Mock.Random.image('@integer(300, 5000)x@integer(300, 5000)')
+    })
+  )
+}
+
+const treeList: TreeListProps[] = []
+
+for (let i = 0; i < count; i++) {
+  treeList.push(
+    Mock.mock({
+      id: toAnyString(),
+      // timestamp: +Mock.Random.date('T'),
+      author: '@first',
+      title: '@title(5, 10)',
+      content: baseContent,
+      importance: '@integer(1, 3)',
+      display_time: '@datetime',
+      pageviews: '@integer(300, 5000)',
+      children: [
+        {
+          id: toAnyString(),
+          // timestamp: +Mock.Random.date('T'),
+          author: '@first',
+          title: '@title(5, 10)',
+          content: baseContent,
+          importance: '@integer(1, 3)',
+          display_time: '@datetime',
+          pageviews: '@integer(300, 5000)',
+          children: [
+            {
+              id: toAnyString(),
+              // timestamp: +Mock.Random.date('T'),
+              author: '@first',
+              title: '@title(5, 10)',
+              content: baseContent,
+              importance: '@integer(1, 3)',
+              display_time: '@datetime',
+              pageviews: '@integer(300, 5000)'
+            },
+            {
+              id: toAnyString(),
+              // timestamp: +Mock.Random.date('T'),
+              author: '@first',
+              title: '@title(5, 10)',
+              content: baseContent,
+              importance: '@integer(1, 3)',
+              display_time: '@datetime',
+              pageviews: '@integer(300, 5000)'
+            }
+          ]
+        },
+        {
+          id: toAnyString(),
+          // timestamp: +Mock.Random.date('T'),
+          author: '@first',
+          title: '@title(5, 10)',
+          content: baseContent,
+          importance: '@integer(1, 3)',
+          display_time: '@datetime',
+          pageviews: '@integer(300, 5000)'
+        },
+        {
+          id: toAnyString(),
+          // timestamp: +Mock.Random.date('T'),
+          author: '@first',
+          title: '@title(5, 10)',
+          content: baseContent,
+          importance: '@integer(1, 3)',
+          display_time: '@datetime',
+          pageviews: '@integer(300, 5000)'
+        },
+        {
+          id: toAnyString(),
+          // timestamp: +Mock.Random.date('T'),
+          author: '@first',
+          title: '@title(5, 10)',
+          content: baseContent,
+          importance: '@integer(1, 3)',
+          display_time: '@datetime',
+          pageviews: '@integer(300, 5000)'
+        }
+      ]
+      // image_uri
+    })
+  )
+}
+
+export default [
+  // 树形列表接口
+  {
+    url: '/example/treeList',
+    method: 'get',
+    timeout,
+    response: ({ query }) => {
+      const { title, pageIndex, pageSize } = query
+      const mockList = treeList.filter((item) => {
+        if (title && item.title.indexOf(title) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+      )
+      return {
+        code: code,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 列表接口
+  {
+    url: '/example/list',
+    method: 'get',
+    timeout,
+    response: ({ query }) => {
+      const { title, pageIndex, pageSize } = query
+      const mockList = List.filter((item) => {
+        if (title && item.title.indexOf(title) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+      )
+      return {
+        code: code,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 保存接口
+  {
+    url: '/example/save',
+    method: 'post',
+    timeout,
+    response: ({ body }) => {
+      if (!body.id) {
+        List = [
+          Object.assign(body, {
+            id: toAnyString()
+          })
+        ].concat(List)
+        return {
+          code: code,
+          data: 'success'
+        }
+      } else {
+        List.map((item) => {
+          if (item.id === body.id) {
+            for (const key in item) {
+              item[key] = body[key]
+            }
+          }
+        })
+        return {
+          code: code,
+          data: 'success'
+        }
+      }
+    }
+  },
+  // 详情接口
+  {
+    url: '/example/detail',
+    method: 'get',
+    response: ({ query }) => {
+      const { id } = query
+      for (const example of List) {
+        if (example.id === id) {
+          return {
+            code: code,
+            data: example
+          }
+        }
+      }
+    }
+  },
+  // 删除接口
+  {
+    url: '/example/delete',
+    method: 'post',
+    response: ({ body }) => {
+      const ids = body.ids
+      if (!ids) {
+        return {
+          code: 500,
+          message: '请选择需要删除的数据'
+        }
+      } else {
+        let i = List.length
+        while (i--) {
+          if (ids.indexOf(List[i].id) !== -1) {
+            List.splice(i, 1)
+          }
+        }
+        return {
+          code: code,
+          data: 'success'
+        }
+      }
+    }
+  }
+] as MockMethod[]

+ 93 - 0
mock/user/index.ts

@@ -0,0 +1,93 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+
+const { code } = config
+
+const timeout = 1
+
+const List: {
+  username: string
+  password: string
+  role: string
+  roleId: string
+  permissions: string | string[]
+}[] = [
+  {
+    username: 'admin',
+    password: 'admin',
+    role: 'admin',
+    roleId: '1',
+    permissions: ['*.*.*']
+  },
+  {
+    username: 'test',
+    password: 'test',
+    role: 'test',
+    roleId: '2',
+    permissions: ['example:dialog:create', 'example:dialog:delete']
+  }
+]
+
+export default [
+  // 列表接口
+  {
+    url: '/user/list',
+    method: 'get',
+    response: ({ query }) => {
+      const { username, pageIndex, pageSize } = query
+
+      const mockList = List.filter((item) => {
+        if (username && item.username.indexOf(username) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+      )
+
+      return {
+        code: code,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 登录接口
+  {
+    url: '/user/login',
+    method: 'post',
+    timeout,
+    response: ({ body }) => {
+      const data = body
+      let hasUser = false
+      for (const user of List) {
+        if (user.username === data.username && user.password === data.password) {
+          hasUser = true
+          return {
+            code: code,
+            data: user
+          }
+        }
+      }
+      if (!hasUser) {
+        return {
+          code: 500,
+          message: '账号或密码错误'
+        }
+      }
+    }
+  },
+  // 退出接口
+  {
+    url: '/user/loginOut',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: null
+      }
+    }
+  }
+] as MockMethod[]

+ 172 - 0
mock/workplace/index.ts

@@ -0,0 +1,172 @@
+import config from '@/config/axios/config'
+import { MockMethod } from 'vite-plugin-mock'
+
+const { code } = config
+
+const timeout = 1
+
+export default [
+  // 获取统计
+  {
+    url: '/workplace/total',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: {
+          project: 40,
+          access: 2340,
+          todo: 10
+        }
+      }
+    }
+  },
+  // 获取项目
+  {
+    url: '/workplace/project',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          {
+            name: 'Github',
+            icon: 'akar-icons:github-fill',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          },
+          {
+            name: 'Vue',
+            icon: 'logos:vue',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          },
+          {
+            name: 'Angular',
+            icon: 'logos:angular-icon',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          },
+          {
+            name: 'React',
+            icon: 'logos:react',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          },
+          {
+            name: 'Webpack',
+            icon: 'logos:webpack',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          },
+          {
+            name: 'Vite',
+            icon: 'vscode-icons:file-type-vite',
+            message: 'workplace.introduction',
+            personal: 'Archer',
+            time: new Date()
+          }
+        ]
+      }
+    }
+  },
+  // 获取动态
+  {
+    url: '/workplace/dynamic',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          },
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          },
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          },
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          },
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          },
+          {
+            keys: ['workplace.push', 'Github'],
+            time: new Date()
+          }
+        ]
+      }
+    }
+  },
+  // 获取团队信息
+  {
+    url: '/workplace/team',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          {
+            name: 'Github',
+            icon: 'akar-icons:github-fill'
+          },
+          {
+            name: 'Vue',
+            icon: 'logos:vue'
+          },
+          {
+            name: 'Angular',
+            icon: 'logos:angular-icon'
+          },
+          {
+            name: 'React',
+            icon: 'logos:react'
+          },
+          {
+            name: 'Webpack',
+            icon: 'logos:webpack'
+          },
+          {
+            name: 'Vite',
+            icon: 'vscode-icons:file-type-vite'
+          }
+        ]
+      }
+    }
+  },
+  // 获取指数
+  {
+    url: '/workplace/radar',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: code,
+        data: [
+          { name: 'workplace.quote', max: 65, personal: 42, team: 50 },
+          { name: 'workplace.contribution', max: 160, personal: 30, team: 140 },
+          { name: 'workplace.hot', max: 300, personal: 20, team: 28 },
+          { name: 'workplace.yield', max: 130, personal: 35, team: 35 },
+          { name: 'workplace.follow', max: 100, personal: 80, team: 90 }
+        ]
+      }
+    }
+  }
+] as MockMethod[]

+ 129 - 0
package.json

@@ -0,0 +1,129 @@
+{
+  "name": "vue-element-plus-admin",
+  "version": "2.2.0",
+  "description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
+  "author": "Archer <502431556@qq.com>",
+  "private": false,
+  "scripts": {
+    "i": "pnpm install",
+    "dev": "vite --mode base",
+    "ts:check": "vue-tsc --noEmit --skipLibCheck",
+    "build:pro": "vite build --mode pro",
+    "build:gitee": "vite build --mode gitee",
+    "build:dev": "vite build --mode dev",
+    "build:test": "npm run ts:check && vite build --mode test",
+    "serve:pro": "vite preview --mode pro",
+    "serve:dev": "vite preview --mode dev",
+    "serve:test": "vite preview --mode test",
+    "npm:check": "npx npm-check-updates",
+    "clean": "npx rimraf node_modules",
+    "clean:cache": "npx rimraf node_modules/.cache",
+    "lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
+    "lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,vue,html,md}\"",
+    "lint:style": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
+    "lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
+    "prepare": "husky install",
+    "p": "plop",
+    "icon": "esno ./scripts/icon.ts"
+  },
+  "dependencies": {
+    "@iconify/iconify": "^3.1.1",
+    "@iconify/vue": "^4.1.1",
+    "@vueuse/core": "^10.3.0",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.10",
+    "@zxcvbn-ts/core": "^3.0.3",
+    "animate.css": "^4.1.1",
+    "axios": "^1.4.0",
+    "dayjs": "^1.11.9",
+    "driver.js": "^1.2.1",
+    "echarts": "^5.4.3",
+    "echarts-wordcloud": "^2.1.0",
+    "element-plus": "^2.3.9",
+    "lodash-es": "^4.17.21",
+    "mitt": "^3.0.1",
+    "mockjs": "^1.1.0",
+    "nprogress": "^0.2.0",
+    "pinia": "^2.1.6",
+    "pinia-plugin-persist": "^1.0.0",
+    "qrcode": "^1.5.3",
+    "qs": "^6.11.2",
+    "url": "^0.11.1",
+    "vue": "3.3.4",
+    "vue-i18n": "9.2.2",
+    "vue-json-pretty": "^2.2.4",
+    "vue-router": "^4.2.4",
+    "vue-types": "^5.1.1"
+  },
+  "devDependencies": {
+    "@commitlint/cli": "^17.7.1",
+    "@commitlint/config-conventional": "^17.7.0",
+    "@iconify/json": "^2.2.101",
+    "@intlify/unplugin-vue-i18n": "^0.12.2",
+    "@purge-icons/generated": "^0.9.0",
+    "@types/fs-extra": "^11.0.2",
+    "@types/inquirer": "^9.0.3",
+    "@types/lodash-es": "^4.17.8",
+    "@types/node": "^20.4.10",
+    "@types/nprogress": "^0.2.0",
+    "@types/qrcode": "^1.5.1",
+    "@types/qs": "^6.9.7",
+    "@types/sortablejs": "^1.15.1",
+    "@typescript-eslint/eslint-plugin": "^6.3.0",
+    "@typescript-eslint/parser": "^6.3.0",
+    "@unocss/transformer-variant-group": "^0.55.0",
+    "@vitejs/plugin-legacy": "^4.1.1",
+    "@vitejs/plugin-vue": "^4.2.3",
+    "@vitejs/plugin-vue-jsx": "^3.0.1",
+    "autoprefixer": "^10.4.14",
+    "chalk": "^5.3.0",
+    "consola": "^3.2.3",
+    "eslint": "^8.47.0",
+    "eslint-config-prettier": "^9.0.0",
+    "eslint-define-config": "^1.23.0",
+    "eslint-plugin-prettier": "^5.0.0",
+    "eslint-plugin-vue": "^9.17.0",
+    "esno": "^0.17.0",
+    "fs-extra": "^11.1.1",
+    "husky": "^8.0.3",
+    "inquirer": "^9.2.11",
+    "less": "^4.2.0",
+    "lint-staged": "^13.2.3",
+    "plop": "^3.1.2",
+    "postcss": "^8.4.27",
+    "postcss-html": "^1.5.0",
+    "postcss-less": "^6.0.0",
+    "prettier": "^3.0.1",
+    "rimraf": "^5.0.1",
+    "rollup": "^3.28.0",
+    "stylelint": "^15.10.2",
+    "stylelint-config-html": "^1.1.0",
+    "stylelint-config-recommended": "^13.0.0",
+    "stylelint-config-standard": "^34.0.0",
+    "stylelint-order": "^6.0.3",
+    "terser": "^5.19.2",
+    "typescript": "5.1.6",
+    "unocss": "^0.55.0",
+    "vite": "4.4.9",
+    "vite-plugin-ejs": "^1.6.4",
+    "vite-plugin-eslint": "^1.8.1",
+    "vite-plugin-mock": "2.9.6",
+    "vite-plugin-progress": "^0.0.7",
+    "vite-plugin-purge-icons": "^0.9.2",
+    "vite-plugin-style-import": "2.0.0",
+    "vite-plugin-svg-icons": "^2.0.1",
+    "vue-tsc": "^1.8.8"
+  },
+  "engines": {
+    "node": ">= 14.18.0"
+  },
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/kailong321200875/vue-element-plus-admin.git"
+  },
+  "bugs": {
+    "url": "https://github.com/kailong321200875/vue-element-plus-admin/issues"
+  },
+  "homepage": "https://github.com/kailong321200875/vue-element-plus-admin"
+}

+ 11 - 0
plop/component/component.hbs

@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('{{ name }}')
+</script>
+
+<template>
+  <div :class="`${prefixCls}-{{ name }}`">{{ upperFirstName }}</div>
+</template>

+ 3 - 0
plop/component/index.hbs

@@ -0,0 +1,3 @@
+import {{ upperFirstName }} from './src/{{ upperFirstName }}.vue'
+
+export { {{ upperFirstName }} }

+ 38 - 0
plop/component/prompt.js

@@ -0,0 +1,38 @@
+const toUpperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1)
+
+module.exports = {
+  description: 'Create vue component',
+  prompts: [
+    {
+      type: 'input',
+      name: 'name',
+      message: '请输入组件名称(Please enter the component name)'
+    }
+  ],
+  actions: (data) => {
+    const { name } = data
+    const upperFirstName = toUpperCase(name)
+
+    const actions = []
+    if (name) {
+      actions.push({
+        type: 'add',
+        path: `./src/components/${upperFirstName}/src/${upperFirstName}.vue`,
+        templateFile: './plop/component/component.hbs',
+        data: {
+          name,
+          upperFirstName
+        }
+      }, {
+        type: 'add',
+        path: `./src/components/${upperFirstName}/index.ts`,
+        templateFile: './plop/component/index.hbs',
+        data: {
+          upperFirstName
+        }
+      })
+    }
+
+    return actions
+  }
+}

+ 37 - 0
plop/view/prompt.js

@@ -0,0 +1,37 @@
+const toUpperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1)
+
+module.exports = {
+  description: 'Create vue view',
+  prompts: [
+    {
+      type: 'input',
+      name: 'path',
+      message: '请输入路径(Please enter a path)',
+      default: 'views'
+    },
+    {
+      type: 'input',
+      name: 'name',
+      message: '请输入模块名称(Please enter module name)'
+    }
+  ],
+  actions: (data) => {
+    const { name, path } = data
+    const upperFirstName = toUpperCase(name)
+
+    const actions = []
+    if (name) {
+      actions.push({
+        type: 'add',
+        path: `./src/${path}/${upperFirstName}.vue`,
+        templateFile: './plop/view/view.hbs',
+        data: {
+          name,
+          upperFirstName
+        }
+      })
+    }
+
+    return actions
+  }
+}

+ 7 - 0
plop/view/view.hbs

@@ -0,0 +1,7 @@
+<script setup lang="ts">
+import { ContentWrap } from '@/components/ContentWrap'
+</script>
+
+<template>
+  <ContentWrap title="{{ upperFirstName }}"> {{ name }} </ContentWrap>
+</template>

+ 7 - 0
plopfile.js

@@ -0,0 +1,7 @@
+const viewGenerator = require('./plop/view/prompt.js')
+const componentGenerator = require('./plop/component/prompt.js')
+
+module.exports = function (plop) {
+  plop.setGenerator('view', viewGenerator)
+  plop.setGenerator('component', componentGenerator)
+}

+ 5 - 0
postcss.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  plugins: {
+    autoprefixer: {}
+  }
+}

+ 19 - 0
prettier.config.js

@@ -0,0 +1,19 @@
+module.exports = {
+  printWidth: 100,
+  tabWidth: 2,
+  useTabs: false,
+  semi: false,
+  vueIndentScriptAndStyle: false,
+  singleQuote: true,
+  quoteProps: 'as-needed',
+  bracketSpacing: true,
+  trailingComma: 'none',
+  jsxSingleQuote: false,
+  arrowParens: 'always',
+  insertPragma: false,
+  requirePragma: false,
+  proseWrap: 'never',
+  htmlWhitespaceSensitivity: 'strict',
+  endOfLine: 'auto',
+  rangeStart: 0
+}

BIN
public/favicon.ico


BIN
public/logo.png


+ 71 - 0
scripts/icon.ts

@@ -0,0 +1,71 @@
+import path from 'path'
+import fs from 'fs-extra'
+import inquirer from 'inquirer'
+import chalk from 'chalk'
+import pkg from '../package.json'
+
+interface Icon {
+  name: string
+  prefix: string
+  icons: string[]
+}
+
+async function generateIcon() {
+  const dir = path.resolve(process.cwd(), 'node_modules/@iconify/json')
+
+  const raw = await fs.readJSON(path.join(dir, 'collections.json'))
+
+  const collections = Object.entries(raw).map(([id, v]) => ({
+    ...(v as any),
+    id
+  }))
+
+  const choices = collections.map((item) => ({ key: item.id, value: item.id, name: item.name }))
+
+  inquirer
+    .prompt([
+      // {
+      //   type: 'list',
+      //   name: 'useType',
+      //   choices: [
+      //     { key: 'local', value: 'local', name: 'Local' },
+      //     { key: 'onLine', value: 'onLine', name: 'OnLine' }
+      //   ],
+      //   message: 'How to use icons?'
+      // },
+      {
+        type: 'list',
+        name: 'iconSet',
+        choices: choices,
+        message: 'Select the icon set that needs to be generated?'
+      }
+    ])
+    // ↓命令行问答的答案
+    .then(async (answers) => {
+      const { iconSet } = answers
+      // const isOnLine = useType === 'onLine'
+      const outputDir = path.resolve(process.cwd(), 'src/components/IconPicker/src/data')
+      fs.ensureDir(outputDir)
+      const genCollections = collections.filter((item) => [iconSet].includes(item.id))
+      const prefixSet: string[] = []
+      for (const info of genCollections) {
+        const data = await fs.readJSON(path.join(dir, 'json', `${info.id}.json`))
+        if (data) {
+          const { prefix } = data
+          const icons = Object.keys(data.icons).map((item) => `${prefix}:${item}`)
+
+          await fs.writeFileSync(
+            path.join('src/components/IconPicker/src/data', `icons.${prefix}.ts`),
+            `export default ${JSON.stringify({ name: info.name, prefix, icons })}`
+          )
+          // ↓分类处理完成,push类型名称
+          prefixSet.push(prefix)
+        }
+      }
+      console.log(
+        `✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`
+      )
+    })
+}
+
+generateIcon()

+ 73 - 0
src/App.vue

@@ -0,0 +1,73 @@
+<script setup lang="ts">
+import { computed } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import { usePageStore } from '@/store/modules/page'
+import { ConfigGlobal } from '@/components/ConfigGlobal'
+import { isDark } from '@/utils/is'
+import { useDesign } from '@/hooks/web/useDesign'
+import { useStorage } from '@/hooks/web/useStorage'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('app')
+
+const appStore = useAppStore()
+const pageStore = usePageStore()
+
+const currentSize = computed(() => appStore.getCurrentSize)
+
+const greyMode = computed(() => appStore.getGreyMode)
+
+// 根据浏览器当前主题设置系统主题色
+// const setDefaultTheme = () => {
+//   const { getStorage } = useStorage()
+//   if (getStorage('isDark') !== null) {
+//     appStore.setIsDark(getStorage('isDark'))
+//     return
+//   }
+//   const isDarkTheme = isDark()
+//   appStore.setIsDark(isDarkTheme)
+// }
+
+const setPageData = () => {
+  const { getStorage } = useStorage('localStorage')
+  if (getStorage('pageData') !== null) {
+    pageStore.setAllPageData(getStorage('pageData'))
+    return
+  }
+}
+
+setPageData()
+// setDefaultTheme()
+</script>
+
+<template>
+  <ConfigGlobal :size="currentSize">
+    <RouterView :class="greyMode ? `${prefixCls}-grey-mode` : ''" />
+  </ConfigGlobal>
+</template>
+
+<style lang="less">
+@prefix-cls: ~'@{namespace}-app';
+
+.size {
+  width: 100%;
+  height: 100%;
+}
+
+html,
+body {
+  padding: 0 !important;
+  margin: 0;
+  overflow: hidden;
+  .size;
+
+  #app {
+    .size;
+  }
+}
+
+.@{prefix-cls}-grey-mode {
+  filter: grayscale(100%);
+}
+</style>

+ 15 - 0
src/api/common/index.ts

@@ -0,0 +1,15 @@
+import request from '@/config/axios'
+
+// 获取所有字典
+export const getDictApi = () => {
+  return request.get({ url: '/dict/list' })
+}
+
+// 模拟获取某个字典
+export const getDictOneApi = async () => {
+  return request.get({ url: '/dict/one' })
+}
+
+export const uploadFile = async (data: any) => {
+  return request.post({ url: '/api/sysApk/uploadFile', headersType: 'multipart/form-data', data })
+}

+ 23 - 0
src/api/dashboard/analysis/index.ts

@@ -0,0 +1,23 @@
+import request from '@/config/axios'
+import type {
+  AnalysisTotalTypes,
+  UserAccessSource,
+  WeeklyUserActivity,
+  MonthlySales
+} from './types'
+
+export const getCountApi = (): Promise<IResponse<AnalysisTotalTypes[]>> => {
+  return request.get({ url: '/analysis/total' })
+}
+
+export const getUserAccessSourceApi = (): Promise<IResponse<UserAccessSource[]>> => {
+  return request.get({ url: '/analysis/userAccessSource' })
+}
+
+export const getWeeklyUserActivityApi = (): Promise<IResponse<WeeklyUserActivity[]>> => {
+  return request.get({ url: '/analysis/weeklyUserActivity' })
+}
+
+export const getMonthlySalesApi = (): Promise<IResponse<MonthlySales[]>> => {
+  return request.get({ url: '/analysis/monthlySales' })
+}

+ 22 - 0
src/api/dashboard/analysis/types.ts

@@ -0,0 +1,22 @@
+export type AnalysisTotalTypes = {
+  users: number
+  messages: number
+  moneys: number
+  shoppings: number
+}
+
+export type UserAccessSource = {
+  value: number
+  name: string
+}
+
+export type WeeklyUserActivity = {
+  value: number
+  name: string
+}
+
+export type MonthlySales = {
+  name: string
+  estimate: number
+  actual: number
+}

+ 22 - 0
src/api/dashboard/workplace/index.ts

@@ -0,0 +1,22 @@
+import request from '@/config/axios'
+import type { WorkplaceTotal, Project, Dynamic, Team, RadarData } from './types'
+
+export const getCountApi = (): Promise<IResponse<WorkplaceTotal>> => {
+  return request.get({ url: '/workplace/total' })
+}
+
+export const getProjectApi = (): Promise<IResponse<Project>> => {
+  return request.get({ url: '/workplace/project' })
+}
+
+export const getDynamicApi = (): Promise<IResponse<Dynamic[]>> => {
+  return request.get({ url: '/workplace/dynamic' })
+}
+
+export const getTeamApi = (): Promise<IResponse<Team[]>> => {
+  return request.get({ url: '/workplace/team' })
+}
+
+export const getRadarApi = (): Promise<IResponse<RadarData[]>> => {
+  return request.get({ url: '/workplace/radar' })
+}

+ 30 - 0
src/api/dashboard/workplace/types.ts

@@ -0,0 +1,30 @@
+export type WorkplaceTotal = {
+  project: number
+  access: number
+  todo: number
+}
+
+export type Project = {
+  name: string
+  icon: string
+  message: string
+  personal: string
+  time: Date | number | string
+}
+
+export type Dynamic = {
+  keys: string[]
+  time: Date | number | string
+}
+
+export type Team = {
+  name: string
+  icon: string
+}
+
+export type RadarData = {
+  personal: number
+  team: number
+  max: number
+  name: string
+}

+ 57 - 0
src/api/department/index.ts

@@ -0,0 +1,57 @@
+import request from '@/config/axios'
+import {
+  DepartmentListResponse,
+  DepartmentUserParams,
+  DepartmentUserResponse,
+  UserParams,
+  SysRole,
+  SysUser
+} from './types'
+
+export const getDepartmentApi = () => {
+  return request.get<DepartmentListResponse>({ url: '/department/list' })
+}
+
+export const getUserByIdApi = (params: DepartmentUserParams) => {
+  return request.get<DepartmentUserResponse>({ url: '/department/users', params })
+}
+
+export const deleteUserByIdApi = (ids: string[] | number[]) => {
+  return request.post({ url: '/department/user/delete', data: { ids } })
+}
+
+export const saveUserApi = (data: any) => {
+  return request.post({ url: '/department/user/save', data })
+}
+
+export const saveDepartmentApi = (data: any) => {
+  return request.post({ url: '/department/save', data })
+}
+
+export const deleteDepartmentApi = (ids: string[] | number[]) => {
+  return request.post({ url: '/department/delete', data: { ids } })
+}
+
+export const getDepartmentTableApi = (params: any) => {
+  return request.get({ url: '/department/table/list', params })
+}
+
+export const getUserList = (data: UserParams) => {
+  return request.post<DepartmentUserResponse>({ url: '/api/sysUser/page', data })
+}
+
+export const deleteUserById = (id: number) => {
+  return request.delete({ url: `/api/sysUser/${id}` })
+}
+
+export const getRoleApi = () => {
+  return request.post<SysRole[]>({ url: '/api/sysRole/list' })
+}
+
+export const addUser = (data: any) => {
+  return request.post({ url: '/api/sysUser/add', data })
+}
+
+export const updataUser = (data: any) => {
+  return request.put({ url: '/api/sysUser', data })
+}

+ 62 - 0
src/api/department/types.ts

@@ -0,0 +1,62 @@
+export interface DepartmentItem {
+  id: string
+  departmentName: string
+  children?: DepartmentItem[]
+}
+
+export interface DepartmentListResponse {
+  list: DepartmentItem[]
+}
+
+export interface DepartmentUserParams {
+  pageSize: number
+  pageIndex: number
+  id: string
+  username?: string
+  account?: string
+}
+
+export interface DepartmentUserItem {
+  id: number
+  username: string
+  account: string
+  email: string
+  createTime: string
+  role: string
+  department: DepartmentItem
+}
+
+export interface DepartmentUserResponse {
+  list: DepartmentUserItem[]
+  totalCount: number
+}
+
+export interface UserParams {
+  pageSize: number
+  pageNum: number
+  name?: string
+  account?: string
+}
+
+
+export interface UserResponse {
+  list: DepartmentUserItem[]
+  totalCount: number
+  totalPage: number
+  pageSize: number
+  currPage: number
+}
+
+export interface SysRole {
+  id: number
+  roleName: string
+  createTime: string
+  roleDesc: string
+}
+
+export interface SysUser {
+  id?: number
+  account: string
+  name: string
+  password: string
+}

+ 34 - 0
src/api/login/index.ts

@@ -0,0 +1,34 @@
+import request from '@/config/axios'
+import type { UserType } from './types'
+
+interface RoleParams {
+  roleName: string
+}
+
+export const loginApi = (data: UserType): Promise<IResponse<UserType>> => {
+  return request.post({ url: '/api/login/login', data, headersType: 'application/json' })
+}
+
+export const loginOutApi = (userId: string): Promise<IResponse> => {
+  return request.get({ url: `/api/login/logout/${userId}` })
+}
+
+export const getUserListApi = ({ params }: AxiosConfig) => {
+  return request.get<{
+    code: string
+    data: {
+      list: UserType[]
+      total: number
+    }
+  }>({ url: '/user/list', params })
+}
+
+export const getAdminRoleApi = (
+  params: RoleParams
+): Promise<IResponse<AppCustomRouteRecordRaw[]>> => {
+  return request.get({ url: '/role/list', params })
+}
+
+export const getTestRoleApi = (params: RoleParams): Promise<IResponse<string[]>> => {
+  return request.get({ url: '/role/list2', params })
+}

+ 12 - 0
src/api/login/types.ts

@@ -0,0 +1,12 @@
+export type UserLoginType = {
+  account: string
+  password: string
+}
+
+export type UserType = {
+  account: string
+  password: string
+  role: string
+  roleId: string
+  permissions: string | string[]
+}

+ 18 - 0
src/api/manage/company.ts

@@ -0,0 +1,18 @@
+import request from '@/config/axios'
+// import type { FileData } from './types'
+
+export const getTableListApi = (data: any) => {
+  return request.post({ url: '/api/company/page', data })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.delete({ url: `/api/company/${id}` })
+}
+
+export const saveTableApi = (data: any) => {
+  return request.post({ url: '/api/company', data })
+}
+
+export const updateTableApi = (data: any) => {
+  return request.put({ url: '/api/company', data })
+}

+ 26 - 0
src/api/manage/dict.ts

@@ -0,0 +1,26 @@
+import request from '@/config/axios'
+// import type { FileData } from './types'
+
+export const getTree = (data?: any) => {
+  return request.post({ url: '/api/sysDictionary/showTree', data })
+}
+
+export const getDictPage = (data: any) => {
+  return request.post({ url: '/api/sysDictionary/page', data })
+}
+
+export const getDict = (data: any) => {
+  return request.post({ url: '/api/sysDictionary/list', data })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.delete({ url: `/api/sysDictionary/${id}` })
+}
+
+export const saveTableApi = (data: any) => {
+  return request.post({ url: '/api/sysDictionary', data })
+}
+
+export const updateTableApi = (data: any) => {
+  return request.put({ url: '/api/sysDictionary', data })
+}

+ 18 - 0
src/api/manage/file.ts

@@ -0,0 +1,18 @@
+import request from '@/config/axios'
+// import type { FileData } from './types'
+
+export const getTableListApi = (data: any) => {
+  return request.post({ url: '/api/sysApk/page', data })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.post({ url: `/api/sysApk/deleteApkById/${id}` })
+}
+
+export const saveTableApi = (data: any) => {
+  return request.post({ url: '/api/sysApk/addSysApk', data })
+}
+
+export const updateTableApi = (data: any) => {
+  return request.post({ url: '/api/sysApk/updateSysApk', data })
+}

+ 18 - 0
src/api/manage/img.ts

@@ -0,0 +1,18 @@
+import request from '@/config/axios'
+// import type { FileData } from './types'
+
+export const getTableListApi = (data: any) => {
+  return request.post({ url: '/api/banner/page', data })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.delete({ url: `/api/banner/${id}` })
+}
+
+export const saveTableApi = (data: any) => {
+  return request.post({ url: '/api/banner', data })
+}
+
+export const updateTableApi = (data: any) => {
+  return request.put({ url: '/api/banner', data })
+}

+ 22 - 0
src/api/manage/news.ts

@@ -0,0 +1,22 @@
+import request from '@/config/axios'
+import type { NewsTableData } from './types'
+
+export const getTableListApi = (data: any) => {
+  return request.post({ url: '/api/article/page', data })
+}
+
+export const saveTableApi = (data: Partial<NewsTableData>): Promise<IResponse> => {
+  return request.post({ url: '/api/article', data })
+}
+
+export const updateTableApi = (data: Partial<NewsTableData>): Promise<IResponse> => {
+  return request.put({ url: '/api/article', data })
+}
+
+export const getTableDetApi = (id: string): Promise<IResponse<NewsTableData>> => {
+  return request.get({ url: `/api/article/${id}` })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.delete({ url: `/api/article/${id}` })
+}

+ 22 - 0
src/api/manage/product.ts

@@ -0,0 +1,22 @@
+import request from '@/config/axios'
+import type { ProductTableData } from './types'
+
+export const getTableListApi = (data: any) => {
+  return request.post({ url: '/api/product/page', data })
+}
+
+export const saveTableApi = (data: Partial<ProductTableData>): Promise<IResponse> => {
+  return request.post({ url: '/api/product', data })
+}
+
+export const updateTableApi = (data: Partial<ProductTableData>): Promise<IResponse> => {
+  return request.put({ url: '/api/product', data })
+}
+
+export const getTableDetApi = (id: string): Promise<IResponse<ProductTableData>> => {
+  return request.get({ url: `/api/product/${id}` })
+}
+
+export const delTableListApi = (id: string | number): Promise<IResponse> => {
+  return request.delete({ url: `/api/product/${id}` })
+}

+ 76 - 0
src/api/manage/types.ts

@@ -0,0 +1,76 @@
+export type FileData = {
+  id?: string
+  virtualPath: string
+  updateTime?: string
+  fileName?: string
+  filePath?: string
+}
+
+export type ProductTableData = {
+  id?: string
+  productName: string
+  productPic: string
+  productSpecifications?: string
+  productIntroduction?: string
+  productDetailed?: string
+  productCharacteristic?: string
+  productPrice: number
+  productStock: number
+  remark: string
+}
+
+export type NewsTableData = {
+  id?: string
+  articleContent: string
+  articlePic: string
+  articleTitle: string
+  categoryId?: string
+  articleViews: number
+  introduce: string
+  remark: string
+  updateTime: string
+  videoUrl: string
+  weight: number
+}
+
+export type CompanyData = {
+  id?: string
+  companyAddress?: string
+  companyBrief?: string
+  companyEmail?: string
+  companyName: string
+  companyPhone?: string
+  isActive?: string
+  name?: string
+  phone?: string
+  wechat?: string
+  wechatImg: string
+}
+
+export type ImgData = {
+  id?: string
+  bannerUrl: string
+  updateTime?: string
+  bannerType?: string
+  bannerTarget?: string
+}
+
+export type DictData = {
+  id?: string
+  code?: string
+  name?: string
+  pid?: string
+  showText?: string
+  description?: number
+  isActive?: string
+}
+
+export type DictRowData = {
+  id: string
+  code: string
+  name: string
+  pid?: string
+  showText?: string
+  description?: number
+  isActive: string
+}

+ 5 - 0
src/api/menu/index.ts

@@ -0,0 +1,5 @@
+import request from '@/config/axios'
+
+export const getMenuListApi = () => {
+  return request.get({ url: '/menu/list' })
+}

+ 5 - 0
src/api/role/index.ts

@@ -0,0 +1,5 @@
+import request from '@/config/axios'
+
+export const getRoleListApi = () => {
+  return request.get({ url: '/role/table' })
+}

+ 22 - 0
src/api/table/index.ts

@@ -0,0 +1,22 @@
+import request from '@/config/axios'
+import type { TableData } from './types'
+
+export const getTableListApi = (params: any) => {
+  return request.get({ url: '/example/list', params })
+}
+
+export const getTreeTableListApi = (params: any) => {
+  return request.get({ url: '/example/treeList', params })
+}
+
+export const saveTableApi = (data: Partial<TableData>): Promise<IResponse> => {
+  return request.post({ url: '/example/save', data })
+}
+
+export const getTableDetApi = (id: string): Promise<IResponse<TableData>> => {
+  return request.get({ url: '/example/detail', params: { id } })
+}
+
+export const delTableListApi = (ids: string[] | number[]): Promise<IResponse> => {
+  return request.post({ url: '/example/delete', data: { ids } })
+}

+ 22 - 0
src/api/table/types.ts

@@ -0,0 +1,22 @@
+export type TableData = {
+  id: string
+  author: string
+  title: string
+  content: string
+  importance: number
+  display_time: string
+  pageviews: number
+}
+
+export type ProductTableData = {
+  id?: string
+  productName: string
+  productPic: string
+  productSpecifications: string
+  productIntroduction: string
+  productDetailed: string
+  productCharacteristic: string
+  productPrice: number
+  productStock: number
+  remark: string
+}

BIN
src/assets/imgs/avatar.jpg


BIN
src/assets/imgs/favicon.ico


BIN
src/assets/imgs/logo.png


File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/403.svg


File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/404.svg


File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/500.svg


+ 1 - 0
src/assets/svgs/icon.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.147.062a13 13 0 014.94.945c1.55.63 2.907 1.526 4.069 2.688a13.148 13.148 0 012.761 4.069c.678 1.55 1.017 3.245 1.017 5.086v102.3c0 3.681-1.187 6.733-3.56 9.155-2.373 2.422-5.352 3.633-8.937 3.633H12.992c-3.875 0-7-1.26-9.373-3.779-2.373-2.518-3.56-5.667-3.56-9.445V12.704c0-3.39 1.163-6.345 3.488-8.863C5.872 1.32 8.972.062 12.847.062h102.3zM81.434 109.047c1.744 0 3.003-.412 3.778-1.235.775-.824 1.163-1.914 1.163-3.27 0-1.26-.388-2.325-1.163-3.197-.775-.872-2.034-1.307-3.778-1.307H72.57c.097-.194.145-.485.145-.872V27.09h9.01c1.743 0 2.954-.436 3.633-1.308.678-.872 1.017-1.938 1.017-3.197 0-1.26-.34-2.325-1.017-3.197-.679-.872-1.89-1.308-3.633-1.308H46.268c-1.743 0-2.954.436-3.632 1.308-.678.872-1.018 1.938-1.018 3.197 0 1.26.34 2.325 1.018 3.197.678.872 1.889 1.308 3.632 1.308h8.138v72.075c0 .193.024.339.073.436.048.096.072.242.072.436H46.56c-1.744 0-3.003.435-3.778 1.307-.775.872-1.163 1.938-1.163 3.197 0 1.356.388 2.446 1.163 3.27.775.823 2.034 1.235 3.778 1.235h34.875z"/></svg>

File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/login-bg.svg


File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/login-box-bg.svg


+ 1 - 0
src/assets/svgs/message.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>

+ 1 - 0
src/assets/svgs/money.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>

+ 1 - 0
src/assets/svgs/peoples.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M95.648 118.762c0 5.035-3.563 9.121-7.979 9.121H7.98c-4.416 0-7.979-4.086-7.979-9.121C0 100.519 15.408 83.47 31.152 76.75c-9.099-6.43-15.216-17.863-15.216-30.987v-9.128c0-20.16 14.293-36.518 31.893-36.518s31.894 16.358 31.894 36.518v9.122c0 13.137-6.123 24.556-15.216 30.993 15.738 6.726 31.141 23.769 31.141 42.012z"/><path d="M106.032 118.252h15.867c3.376 0 6.101-3.125 6.101-6.972 0-13.957-11.787-26.984-23.819-32.123 6.955-4.919 11.638-13.66 11.638-23.704v-6.985c0-15.416-10.928-27.926-24.39-27.926-1.674 0-3.306.193-4.89.561 1.936 4.713 3.018 9.974 3.018 15.526v9.121c0 13.137-3.056 23.111-11.066 30.993 14.842 4.41 27.312 23.42 27.541 41.509z"/></svg>

File diff suppressed because it is too large
+ 0 - 0
src/assets/svgs/shopping.svg


+ 3 - 0
src/components/Backtop/index.ts

@@ -0,0 +1,3 @@
+import Backtop from './src/Backtop.vue'
+
+export { Backtop }

+ 16 - 0
src/components/Backtop/src/Backtop.vue

@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import { ElBacktop } from 'element-plus'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls, variables } = useDesign()
+
+const prefixCls = getPrefixCls('backtop')
+</script>
+
+<template>
+  <ElBacktop
+    :class="`${prefixCls}-backtop`"
+    style="z-index: 100"
+    :target="`.${variables.namespace}-layout-content-scrollbar .${variables.elNamespace}-scrollbar__wrap`"
+  />
+</template>

+ 3 - 0
src/components/Breadcrumb/index.ts

@@ -0,0 +1,3 @@
+import Breadcrumb from './src/Breadcrumb.vue'
+
+export { Breadcrumb }

+ 126 - 0
src/components/Breadcrumb/src/Breadcrumb.vue

@@ -0,0 +1,126 @@
+<script lang="tsx">
+import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
+import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
+import { useRouter } from 'vue-router'
+import { usePermissionStore } from '@/store/modules/permission'
+import { filterBreadcrumb } from './helper'
+import { filter, treeToList } from '@/utils/tree'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Icon } from '@/components/Icon'
+import { useAppStore } from '@/store/modules/app'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('breadcrumb')
+
+const appStore = useAppStore()
+
+// 面包屑图标
+const breadcrumbIcon = computed(() => appStore.getBreadcrumbIcon)
+
+export default defineComponent({
+  name: 'Breadcrumb',
+  setup() {
+    const { currentRoute } = useRouter()
+
+    const { t } = useI18n()
+
+    const levelList = ref<AppRouteRecordRaw[]>([])
+
+    const permissionStore = usePermissionStore()
+
+    const menuRouters = computed(() => {
+      const routers = permissionStore.getRouters
+      return filterBreadcrumb(routers)
+    })
+
+    const getBreadcrumb = () => {
+      const currentPath = currentRoute.value.matched.slice(-1)[0].path
+      levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
+        return node.path === currentPath
+      })
+    }
+
+    const renderBreadcrumb = () => {
+      const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
+      return breadcrumbList.map((v) => {
+        const disabled = !v.redirect || v.redirect === 'noredirect'
+        const meta = v.meta
+        return (
+          <ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
+            {meta?.icon && breadcrumbIcon.value ? (
+              <>
+                <Icon icon={meta.icon} class="mr-[5px]"></Icon> {t(v?.meta?.title || '')}
+              </>
+            ) : (
+              t(v?.meta?.title || '')
+            )}
+          </ElBreadcrumbItem>
+        )
+      })
+    }
+
+    watch(
+      () => currentRoute.value,
+      (route: RouteLocationNormalizedLoaded) => {
+        if (route.path.startsWith('/redirect/')) {
+          return
+        }
+        getBreadcrumb()
+      },
+      {
+        immediate: true
+      }
+    )
+
+    return () => (
+      <ElBreadcrumb separator="/" class={`${prefixCls} flex items-center h-full ml-[10px]`}>
+        <TransitionGroup appear enter-active-class="animate__animated animate__fadeInRight">
+          {renderBreadcrumb()}
+        </TransitionGroup>
+      </ElBreadcrumb>
+    )
+  }
+})
+</script>
+
+<style lang="less" scoped>
+@prefix-cls: ~'@{elNamespace}-breadcrumb';
+
+.@{prefix-cls} {
+  :deep(&__item) {
+    display: flex;
+    .@{prefix-cls}__inner {
+      display: flex;
+      align-items: center;
+      color: var(--top-header-text-color);
+
+      &:hover {
+        color: var(--el-color-primary);
+      }
+    }
+  }
+
+  :deep(&__item):not(:last-child) {
+    .@{prefix-cls}__inner {
+      color: var(--top-header-text-color);
+
+      &:hover {
+        color: var(--el-color-primary);
+      }
+    }
+  }
+
+  :deep(&__item):last-child {
+    .@{prefix-cls}__inner {
+      color: var(--el-text-color-placeholder);
+
+      &:hover {
+        color: var(--el-text-color-placeholder);
+      }
+    }
+  }
+}
+</style>

+ 30 - 0
src/components/Breadcrumb/src/helper.ts

@@ -0,0 +1,30 @@
+import { pathResolve } from '@/utils/routerHelper'
+
+export const filterBreadcrumb = (
+  routes: AppRouteRecordRaw[],
+  parentPath = ''
+): AppRouteRecordRaw[] => {
+  const res: AppRouteRecordRaw[] = []
+
+  for (const route of routes) {
+    const meta = route?.meta
+    if (meta.hidden && !meta.canTo) {
+      continue
+    }
+
+    const data: AppRouteRecordRaw =
+      !meta.alwaysShow && route.children?.length === 1
+        ? { ...route.children[0], path: pathResolve(route.path, route.children[0].path) }
+        : { ...route }
+
+    data.path = pathResolve(parentPath, data.path)
+
+    if (data.children) {
+      data.children = filterBreadcrumb(data.children, data.path)
+    }
+    if (data) {
+      res.push(data)
+    }
+  }
+  return res
+}

+ 3 - 0
src/components/Collapse/index.ts

@@ -0,0 +1,3 @@
+import Collapse from './src/Collapse.vue'
+
+export { Collapse }

+ 34 - 0
src/components/Collapse/src/Collapse.vue

@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import { computed, unref } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import { propTypes } from '@/utils/propTypes'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('collapse')
+
+defineProps({
+  color: propTypes.string.def('')
+})
+
+const appStore = useAppStore()
+
+const collapse = computed(() => appStore.getCollapse)
+
+const toggleCollapse = () => {
+  const collapsed = unref(collapse)
+  appStore.setCollapse(!collapsed)
+}
+</script>
+
+<template>
+  <div :class="prefixCls" @click="toggleCollapse">
+    <Icon
+      :size="18"
+      :icon="collapse ? 'ant-design:menu-unfold-outlined' : 'ant-design:menu-fold-outlined'"
+      :color="color"
+      class="cursor-pointer"
+    />
+  </div>
+</template>

+ 5 - 0
src/components/ConfigGlobal/index.ts

@@ -0,0 +1,5 @@
+import ConfigGlobal from './src/ConfigGlobal.vue'
+
+export type { ConfigGlobalTypes } from './src/types'
+
+export { ConfigGlobal }

+ 62 - 0
src/components/ConfigGlobal/src/ConfigGlobal.vue

@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import { provide, computed, watch, onMounted } from 'vue'
+import { propTypes } from '@/utils/propTypes'
+import { ComponentSize, ElConfigProvider } from 'element-plus'
+import { useLocaleStore } from '@/store/modules/locale'
+import { useWindowSize } from '@vueuse/core'
+import { useAppStore } from '@/store/modules/app'
+import { setCssVar } from '@/utils'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { variables } = useDesign()
+
+const appStore = useAppStore()
+
+const props = defineProps({
+  size: propTypes.oneOf<ComponentSize>(['default', 'small', 'large']).def('default')
+})
+
+provide('configGlobal', props)
+
+// 初始化所有主题色
+onMounted(() => {
+  appStore.setCssVarTheme()
+})
+
+const { width } = useWindowSize()
+
+// 监听窗口变化
+watch(
+  () => width.value,
+  (width: number) => {
+    if (width < 768) {
+      !appStore.getMobile ? appStore.setMobile(true) : undefined
+      setCssVar('--left-menu-min-width', '0')
+      appStore.setCollapse(true)
+      appStore.getLayout !== 'classic' ? appStore.setLayout('classic') : undefined
+    } else {
+      appStore.getMobile ? appStore.setMobile(false) : undefined
+      setCssVar('--left-menu-min-width', '64px')
+    }
+  },
+  {
+    immediate: true
+  }
+)
+
+// 多语言相关
+const localeStore = useLocaleStore()
+
+const currentLocale = computed(() => localeStore.currentLocale)
+</script>
+
+<template>
+  <ElConfigProvider
+    :namespace="variables.elNamespace"
+    :locale="currentLocale.elLocale"
+    :message="{ max: 1 }"
+    :size="size"
+  >
+    <slot></slot>
+  </ElConfigProvider>
+</template>

+ 5 - 0
src/components/ConfigGlobal/src/types/index.ts

@@ -0,0 +1,5 @@
+import { ComponentSize } from 'element-plus'
+
+export interface ConfigGlobalTypes {
+  size?: ComponentSize
+}

+ 3 - 0
src/components/ContentDetailWrap/index.ts

@@ -0,0 +1,3 @@
+import ContentDetailWrap from './src/ContentDetailWrap.vue'
+
+export { ContentDetailWrap }

+ 25 - 0
src/components/ContentDetailWrap/src/ContentDetailWrap.vue

@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { ElCard } from 'element-plus'
+import { propTypes } from '@/utils/propTypes'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('content-detail-wrap')
+
+defineProps({
+  title: propTypes.string.def(''),
+  message: propTypes.string.def('')
+})
+</script>
+
+<template>
+  <div :class="[`${prefixCls}-container`, 'relative']">
+    <ElCard :class="[`${prefixCls}-body`, 'mb-20px']" shadow="never">
+      <div class="mb-20px pb-20px" style="border-bottom: 1px solid var(--el-border-color)">
+        <slot name="header"></slot>
+      </div>
+      <slot></slot>
+    </ElCard>
+  </div>
+</template>

+ 3 - 0
src/components/ContentWrap/index.ts

@@ -0,0 +1,3 @@
+import ContentWrap from './src/ContentWrap.vue'
+
+export { ContentWrap }

+ 36 - 0
src/components/ContentWrap/src/ContentWrap.vue

@@ -0,0 +1,36 @@
+<script setup lang="ts">
+import { ElCard, ElTooltip } from 'element-plus'
+import { propTypes } from '@/utils/propTypes'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('content-wrap')
+
+defineProps({
+  title: propTypes.string.def(''),
+  message: propTypes.string.def('')
+})
+</script>
+
+<template>
+  <ElCard :class="[prefixCls]" shadow="never">
+    <template v-if="title" #header>
+      <div class="flex items-center">
+        <span class="text-16px font-700">{{ title }}</span>
+        <ElTooltip v-if="message" effect="dark" placement="right">
+          <template #content>
+            <div class="max-w-200px">{{ message }}</div>
+          </template>
+          <Icon class="ml-5px" icon="bi:question-circle-fill" :size="14" />
+        </ElTooltip>
+        <div class="flex pl-20px flex-grow">
+          <slot name="header"></slot>
+        </div>
+      </div>
+    </template>
+    <div>
+      <slot></slot>
+    </div>
+  </ElCard>
+</template>

+ 12 - 0
src/components/ContextMenu/index.ts

@@ -0,0 +1,12 @@
+import ContextMenu from './src/ContextMenu.vue'
+import { ElDropdown } from 'element-plus'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+
+export type { ContextMenuSchema } from './src/types'
+
+export interface ContextMenuExpose {
+  elDropdownMenuRef: ComponentRef<typeof ElDropdown>
+  tagItem: RouteLocationNormalizedLoaded
+}
+
+export { ContextMenu }

+ 72 - 0
src/components/ContextMenu/src/ContextMenu.vue

@@ -0,0 +1,72 @@
+<script setup lang="ts">
+import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
+import { PropType, ref } from 'vue'
+import { useI18n } from '@/hooks/web/useI18n'
+import { useDesign } from '@/hooks/web/useDesign'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+import { ContextMenuSchema } from './types'
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('context-menu')
+
+const { t } = useI18n()
+
+const emit = defineEmits(['visibleChange'])
+
+const props = defineProps({
+  schema: {
+    type: Array as PropType<ContextMenuSchema[]>,
+    default: () => []
+  },
+  trigger: {
+    type: String as PropType<'click' | 'hover' | 'focus' | 'contextmenu'>,
+    default: 'contextmenu'
+  },
+  tagItem: {
+    type: Object as PropType<RouteLocationNormalizedLoaded>,
+    default: () => ({})
+  }
+})
+
+const command = (item: ContextMenuSchema) => {
+  item.command && item.command(item)
+}
+
+const visibleChange = (visible: boolean) => {
+  emit('visibleChange', visible, props.tagItem)
+}
+
+const elDropdownMenuRef = ref<ComponentRef<typeof ElDropdown>>()
+
+defineExpose({
+  elDropdownMenuRef,
+  tagItem: props.tagItem
+})
+</script>
+
+<template>
+  <ElDropdown
+    ref="elDropdownMenuRef"
+    :class="prefixCls"
+    :trigger="trigger"
+    placement="bottom-start"
+    @command="command"
+    @visible-change="visibleChange"
+    popper-class="v-context-menu-popper"
+  >
+    <slot></slot>
+    <template #dropdown>
+      <ElDropdownMenu>
+        <ElDropdownItem
+          v-for="(item, index) in schema"
+          :key="`dropdown${index}`"
+          :divided="item.divided"
+          :disabled="item.disabled"
+          :command="item"
+        >
+          <Icon :icon="item.icon" /> {{ t(item.label) }}
+        </ElDropdownItem>
+      </ElDropdownMenu>
+    </template>
+  </ElDropdown>
+</template>

+ 7 - 0
src/components/ContextMenu/src/types/index.ts

@@ -0,0 +1,7 @@
+export interface ContextMenuSchema {
+  disabled?: boolean
+  divided?: boolean
+  icon?: string
+  label: string
+  command?: (item: ContextMenuSchema) => void
+}

+ 3 - 0
src/components/CountTo/index.ts

@@ -0,0 +1,3 @@
+import CountTo from './src/CountTo.vue'
+
+export { CountTo }

+ 180 - 0
src/components/CountTo/src/CountTo.vue

@@ -0,0 +1,180 @@
+<script setup lang="ts">
+import { reactive, computed, watch, onMounted, unref, toRef, PropType } from 'vue'
+import { isNumber } from '@/utils/is'
+import { propTypes } from '@/utils/propTypes'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('count-to')
+
+const props = defineProps({
+  startVal: propTypes.number.def(0),
+  endVal: propTypes.number.def(2021),
+  duration: propTypes.number.def(3000),
+  autoplay: propTypes.bool.def(true),
+  decimals: propTypes.number.validate((value: number) => value >= 0).def(0),
+  decimal: propTypes.string.def('.'),
+  separator: propTypes.string.def(','),
+  prefix: propTypes.string.def(''),
+  suffix: propTypes.string.def(''),
+  useEasing: propTypes.bool.def(true),
+  easingFn: {
+    type: Function as PropType<(t: number, b: number, c: number, d: number) => number>,
+    default(t: number, b: number, c: number, d: number) {
+      return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b
+    }
+  }
+})
+
+const emit = defineEmits(['mounted', 'callback'])
+
+const formatNumber = (num: number | string) => {
+  const { decimals, decimal, separator, suffix, prefix } = props
+  num = Number(num).toFixed(decimals)
+  num += ''
+  const x = num.split('.')
+  let x1 = x[0]
+  const x2 = x.length > 1 ? decimal + x[1] : ''
+  const rgx = /(\d+)(\d{3})/
+  if (separator && !isNumber(separator)) {
+    while (rgx.test(x1)) {
+      x1 = x1.replace(rgx, '$1' + separator + '$2')
+    }
+  }
+  return prefix + x1 + x2 + suffix
+}
+
+const state = reactive<{
+  localStartVal: number
+  printVal: number | null
+  displayValue: string
+  paused: boolean
+  localDuration: number | null
+  startTime: number | null
+  timestamp: number | null
+  rAF: any
+  remaining: number | null
+}>({
+  localStartVal: props.startVal,
+  displayValue: formatNumber(props.startVal),
+  printVal: null,
+  paused: false,
+  localDuration: props.duration,
+  startTime: null,
+  timestamp: null,
+  remaining: null,
+  rAF: null
+})
+
+const displayValue = toRef(state, 'displayValue')
+
+onMounted(() => {
+  if (props.autoplay) {
+    start()
+  }
+  emit('mounted')
+})
+
+const getCountDown = computed(() => {
+  return props.startVal > props.endVal
+})
+
+watch([() => props.startVal, () => props.endVal], () => {
+  if (props.autoplay) {
+    start()
+  }
+})
+
+const start = () => {
+  const { startVal, duration } = props
+  state.localStartVal = startVal
+  state.startTime = null
+  state.localDuration = duration
+  state.paused = false
+  state.rAF = requestAnimationFrame(count)
+}
+
+const pauseResume = () => {
+  if (state.paused) {
+    resume()
+    state.paused = false
+  } else {
+    pause()
+    state.paused = true
+  }
+}
+
+const pause = () => {
+  cancelAnimationFrame(state.rAF)
+}
+
+const resume = () => {
+  state.startTime = null
+  state.localDuration = +(state.remaining as number)
+  state.localStartVal = +(state.printVal as number)
+  requestAnimationFrame(count)
+}
+
+const reset = () => {
+  state.startTime = null
+  cancelAnimationFrame(state.rAF)
+  state.displayValue = formatNumber(props.startVal)
+}
+
+const count = (timestamp: number) => {
+  const { useEasing, easingFn, endVal } = props
+  if (!state.startTime) state.startTime = timestamp
+  state.timestamp = timestamp
+  const progress = timestamp - state.startTime
+  state.remaining = (state.localDuration as number) - progress
+  if (useEasing) {
+    if (unref(getCountDown)) {
+      state.printVal =
+        state.localStartVal -
+        easingFn(progress, 0, state.localStartVal - endVal, state.localDuration as number)
+    } else {
+      state.printVal = easingFn(
+        progress,
+        state.localStartVal,
+        endVal - state.localStartVal,
+        state.localDuration as number
+      )
+    }
+  } else {
+    if (unref(getCountDown)) {
+      state.printVal =
+        state.localStartVal -
+        (state.localStartVal - endVal) * (progress / (state.localDuration as number))
+    } else {
+      state.printVal =
+        state.localStartVal +
+        (endVal - state.localStartVal) * (progress / (state.localDuration as number))
+    }
+  }
+  if (unref(getCountDown)) {
+    state.printVal = state.printVal < endVal ? endVal : state.printVal
+  } else {
+    state.printVal = state.printVal > endVal ? endVal : state.printVal
+  }
+  state.displayValue = formatNumber(state.printVal!)
+  if (progress < (state.localDuration as number)) {
+    state.rAF = requestAnimationFrame(count)
+  } else {
+    emit('callback')
+  }
+}
+
+defineExpose({
+  pauseResume,
+  reset,
+  start,
+  pause
+})
+</script>
+
+<template>
+  <span :class="prefixCls">
+    {{ displayValue }}
+  </span>
+</template>

+ 5 - 0
src/components/Descriptions/index.ts

@@ -0,0 +1,5 @@
+import Descriptions from './src/Descriptions.vue'
+
+export type { DescriptionsSchema } from './src/types'
+
+export { Descriptions }

+ 161 - 0
src/components/Descriptions/src/Descriptions.vue

@@ -0,0 +1,161 @@
+<script lang="tsx">
+import { ElCollapseTransition, ElDescriptions, ElDescriptionsItem, ElTooltip } from 'element-plus'
+import { useDesign } from '@/hooks/web/useDesign'
+import { propTypes } from '@/utils/propTypes'
+import { ref, unref, PropType, computed, defineComponent } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import { DescriptionsSchema } from './types'
+import { Icon } from '@/components/Icon'
+import { get } from 'lodash-es'
+
+const appStore = useAppStore()
+
+const mobile = computed(() => appStore.getMobile)
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('descriptions')
+
+export default defineComponent({
+  name: 'Descriptions',
+  props: {
+    title: propTypes.string.def(''),
+    message: propTypes.string.def(''),
+    collapse: propTypes.bool.def(true),
+    border: propTypes.bool.def(true),
+    column: propTypes.number.def(2),
+    size: propTypes.oneOf(['large', 'default', 'small']).def('default'),
+    direction: propTypes.oneOf(['horizontal', 'vertical']).def('horizontal'),
+    extra: propTypes.string.def(''),
+    schema: {
+      type: Array as PropType<DescriptionsSchema[]>,
+      default: () => []
+    },
+    data: {
+      type: Object as PropType<any>,
+      default: () => ({})
+    }
+  },
+  setup(props, { slots, attrs }) {
+    const getBindValue = computed((): any => {
+      const delArr: string[] = ['title', 'message', 'collapse', 'schema', 'data', 'class']
+      const obj = { ...attrs, ...props }
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      if (unref(mobile)) {
+        obj.direction = 'vertical'
+      }
+      return obj
+    })
+
+    const getBindItemValue = (item: DescriptionsSchema) => {
+      const delArr: string[] = ['field']
+      const obj = { ...item }
+      for (const key in obj) {
+        if (delArr.indexOf(key) !== -1) {
+          delete obj[key]
+        }
+      }
+      return obj
+    }
+
+    // 折叠
+    const show = ref(true)
+
+    const toggleClick = () => {
+      if (props.collapse) {
+        show.value = !unref(show)
+      }
+    }
+
+    return () => {
+      return (
+        <div
+          class={[
+            prefixCls,
+            'bg-[var(--el-color-white)] dark:bg-[var(--el-bg-color)] dark:border-[var(--el-border-color)] dark:border-1px'
+          ]}
+        >
+          {props.title ? (
+            <div
+              class={[
+                `${prefixCls}-header`,
+                'relative h-50px flex justify-between items-center layout-border__bottom px-10px cursor-pointer'
+              ]}
+              onClick={toggleClick}
+            >
+              <div class={[`${prefixCls}-header__title`, 'relative font-18px font-bold ml-10px']}>
+                <div class="flex items-center">
+                  {props.title}
+                  {props.message ? (
+                    <ElTooltip content={props.message} placement="right">
+                      <Icon icon="bi:question-circle-fill" class="ml-5px" size={14} />
+                    </ElTooltip>
+                  ) : null}
+                </div>
+              </div>
+              {props.collapse ? <Icon icon={show.value ? 'ep:arrow-down' : 'ep:arrow-up'} /> : null}
+            </div>
+          ) : null}
+
+          <ElCollapseTransition>
+            <div v-show={unref(show)} class={[`${prefixCls}-content`, 'p-20px']}>
+              <ElDescriptions {...unref(getBindValue)}>
+                {{
+                  extra: () => (slots['extra'] ? slots['extra']() : props.extra),
+                  default: () => {
+                    return props.schema.map((item) => {
+                      return (
+                        <ElDescriptionsItem key={item.field} {...getBindItemValue(item)}>
+                          {{
+                            label: () => (item.slots?.label ? item.slots?.label(item) : item.label),
+                            default: () =>
+                              item.slots?.default
+                                ? item.slots?.default(props.data)
+                                : get(props.data, item.field)
+                          }}
+                        </ElDescriptionsItem>
+                      )
+                    })
+                  }
+                }}
+              </ElDescriptions>
+            </div>
+          </ElCollapseTransition>
+        </div>
+      )
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+@prefix-cls: ~'@{namespace}-descriptions';
+
+:deep(.@{elNamespace}-descriptions__header) {
+  display: none !important;
+}
+
+.@{prefix-cls}-header {
+  &__title {
+    &::after {
+      position: absolute;
+      top: 3px;
+      left: -10px;
+      width: 4px;
+      height: 70%;
+      background: var(--el-color-primary);
+      content: '';
+    }
+  }
+}
+
+.@{prefix-cls}-content {
+  :deep(.@{elNamespace}-descriptions__cell) {
+    width: 0;
+  }
+}
+</style>

+ 15 - 0
src/components/Descriptions/src/types/index.ts

@@ -0,0 +1,15 @@
+export interface DescriptionsSchema {
+  span?: number // 占多少分
+  field: string // 字段名
+  label?: string // label名
+  width?: string | number
+  minWidth?: string | number
+  align?: 'left' | 'center' | 'right'
+  labelAlign?: 'left' | 'center' | 'right'
+  className?: string
+  labelClassName?: string
+  slots?: {
+    default?: (...args: any[]) => JSX.Element | null
+    label?: (...args: any[]) => JSX.Element | null
+  }
+}

+ 3 - 0
src/components/Dialog/index.ts

@@ -0,0 +1,3 @@
+import Dialog from './src/Dialog.vue'
+
+export { Dialog }

+ 132 - 0
src/components/Dialog/src/Dialog.vue

@@ -0,0 +1,132 @@
+<script setup lang="ts">
+import { ElDialog, ElScrollbar } from 'element-plus'
+import { propTypes } from '@/utils/propTypes'
+import { computed, useAttrs, ref, unref, useSlots, watch, nextTick } from 'vue'
+import { isNumber } from '@/utils/is'
+
+const slots = useSlots()
+
+const props = defineProps({
+  modelValue: propTypes.bool.def(false),
+  title: propTypes.string.def('Dialog'),
+  fullscreen: propTypes.bool.def(true),
+  maxHeight: propTypes.oneOfType([String, Number]).def('400px')
+})
+
+const getBindValue = computed(() => {
+  const delArr: string[] = ['fullscreen', 'title', 'maxHeight']
+  const attrs = useAttrs()
+  const obj = { ...attrs, ...props }
+  for (const key in obj) {
+    if (delArr.indexOf(key) !== -1) {
+      delete obj[key]
+    }
+  }
+  return obj
+})
+
+const isFullscreen = ref(false)
+
+const toggleFull = () => {
+  isFullscreen.value = !unref(isFullscreen)
+}
+
+const dialogHeight = ref(isNumber(props.maxHeight) ? `${props.maxHeight}px` : props.maxHeight)
+
+watch(
+  () => isFullscreen.value,
+  async (val: boolean) => {
+    await nextTick()
+    if (val) {
+      const windowHeight = document.documentElement.offsetHeight
+      dialogHeight.value = `${windowHeight - 55 - 60 - (slots.footer ? 63 : 0)}px`
+    } else {
+      dialogHeight.value = isNumber(props.maxHeight) ? `${props.maxHeight}px` : props.maxHeight
+    }
+  },
+  {
+    immediate: true
+  }
+)
+
+const dialogStyle = computed(() => {
+  return {
+    height: unref(dialogHeight)
+  }
+})
+</script>
+
+<template>
+  <ElDialog
+    v-bind="getBindValue"
+    :fullscreen="isFullscreen"
+    destroy-on-close
+    lock-scroll
+    draggable
+    top="0"
+    :close-on-click-modal="false"
+    :show-close="false"
+  >
+    <template #header="{ close }">
+      <div class="flex justify-between items-center h-54px pl-15px pr-15px relative">
+        <slot name="title">
+          {{ title }}
+        </slot>
+        <div
+          class="h-54px flex justify-between items-center absolute top-[50%] right-15px translate-y-[-50%]"
+        >
+          <Icon
+            v-if="fullscreen"
+            class="cursor-pointer is-hover !h-54px mr-10px"
+            :icon="isFullscreen ? 'radix-icons:exit-full-screen' : 'radix-icons:enter-full-screen'"
+            color="var(--el-color-info)"
+            hover-color="var(--el-color-primary)"
+            @click="toggleFull"
+          />
+          <Icon
+            class="cursor-pointer is-hover !h-54px"
+            icon="ep:close"
+            hover-color="var(--el-color-primary)"
+            color="var(--el-color-info)"
+            @click="close"
+          />
+        </div>
+      </div>
+    </template>
+
+    <ElScrollbar :style="dialogStyle">
+      <slot></slot>
+    </ElScrollbar>
+
+    <template v-if="slots.footer" #footer>
+      <slot name="footer"></slot>
+    </template>
+  </ElDialog>
+</template>
+
+<style lang="less">
+.@{elNamespace}-overlay-dialog {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.@{elNamespace}-dialog {
+  margin: 0 !important;
+  &__header {
+    margin-right: 0 !important;
+    border-bottom: 1px solid var(--el-border-color);
+    padding: 0;
+    height: 54px;
+  }
+  &__body {
+    padding: 15px !important;
+  }
+  &__footer {
+    border-top: 1px solid var(--el-border-color);
+  }
+  &__headerbtn {
+    top: 0;
+  }
+}
+</style>

+ 3 - 0
src/components/Echart/index.ts

@@ -0,0 +1,3 @@
+import Echart from './src/Echart.vue'
+
+export { Echart }

+ 113 - 0
src/components/Echart/src/Echart.vue

@@ -0,0 +1,113 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts'
+import echarts from '@/plugins/echarts'
+import { debounce } from 'lodash-es'
+import 'echarts-wordcloud'
+import { propTypes } from '@/utils/propTypes'
+import { computed, PropType, ref, unref, watch, onMounted, onBeforeUnmount, onActivated } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import { isString } from '@/utils/is'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls, variables } = useDesign()
+
+const prefixCls = getPrefixCls('echart')
+
+const appStore = useAppStore()
+
+const props = defineProps({
+  options: {
+    type: Object as PropType<EChartsOption>,
+    required: true
+  },
+  width: propTypes.oneOfType([Number, String]).def(''),
+  height: propTypes.oneOfType([Number, String]).def('500px')
+})
+
+const isDark = computed(() => appStore.getIsDark)
+
+const theme = computed(() => {
+  const echartTheme: boolean | string = unref(isDark) ? true : 'auto'
+
+  return echartTheme
+})
+
+const options = computed(() => {
+  return Object.assign(props.options, {
+    darkMode: unref(theme)
+  })
+})
+
+const elRef = ref<ElRef>()
+
+let echartRef: Nullable<echarts.ECharts> = null
+
+const contentEl = ref<Element>()
+
+const styles = computed(() => {
+  const width = isString(props.width) ? props.width : `${props.width}px`
+  const height = isString(props.height) ? props.height : `${props.height}px`
+
+  return {
+    width,
+    height
+  }
+})
+
+const initChart = () => {
+  if (unref(elRef) && props.options) {
+    echartRef = echarts.init(unref(elRef) as HTMLElement)
+    echartRef?.setOption(unref(options))
+  }
+}
+
+watch(
+  () => options.value,
+  (options) => {
+    if (echartRef) {
+      echartRef?.setOption(options)
+    }
+  },
+  {
+    deep: true
+  }
+)
+
+const resizeHandler = debounce(() => {
+  if (echartRef) {
+    echartRef.resize()
+  }
+}, 100)
+
+const contentResizeHandler = async (e: TransitionEvent) => {
+  if (e.propertyName === 'width') {
+    resizeHandler()
+  }
+}
+
+onMounted(() => {
+  initChart()
+
+  window.addEventListener('resize', resizeHandler)
+
+  contentEl.value = document.getElementsByClassName(`${variables.namespace}-layout-content`)[0]
+  unref(contentEl) &&
+    (unref(contentEl) as Element).addEventListener('transitionend', contentResizeHandler)
+})
+
+onBeforeUnmount(() => {
+  window.removeEventListener('resize', resizeHandler)
+  unref(contentEl) &&
+    (unref(contentEl) as Element).removeEventListener('transitionend', contentResizeHandler)
+})
+
+onActivated(() => {
+  if (echartRef) {
+    echartRef.resize()
+  }
+})
+</script>
+
+<template>
+  <div ref="elRef" :class="[$attrs.class, prefixCls]" :style="styles"></div>
+</template>

+ 8 - 0
src/components/Editor/index.ts

@@ -0,0 +1,8 @@
+import Editor from './src/Editor.vue'
+import { IDomEditor } from '@wangeditor/editor'
+
+export interface EditorExpose {
+  getEditorRef: () => Promise<IDomEditor>
+}
+
+export { Editor }

+ 137 - 0
src/components/Editor/src/Editor.vue

@@ -0,0 +1,137 @@
+<script setup lang="ts">
+import { onBeforeUnmount, computed, PropType, unref, nextTick, ref, watch, shallowRef } from 'vue'
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
+import { IDomEditor, IEditorConfig, i18nChangeLanguage } from '@wangeditor/editor'
+import { propTypes } from '@/utils/propTypes'
+import { isNumber } from '@/utils/is'
+import { ElMessage } from 'element-plus'
+import { useLocaleStore } from '@/store/modules/locale'
+
+const localeStore = useLocaleStore()
+
+const currentLocale = computed(() => localeStore.getCurrentLocale)
+
+i18nChangeLanguage(unref(currentLocale).lang)
+
+const props = defineProps({
+  editorId: propTypes.string.def('wangeEditor-1'),
+  height: propTypes.oneOfType([Number, String]).def('500px'),
+  editorConfig: {
+    type: Object as PropType<IEditorConfig>,
+    default: () => undefined
+  },
+  modelValue: propTypes.string.def('')
+})
+
+const emit = defineEmits(['change', 'update:modelValue'])
+
+// 编辑器实例,必须用 shallowRef
+const editorRef = shallowRef<IDomEditor>()
+
+const valueHtml = ref('')
+
+watch(
+  () => props.modelValue,
+  (val: string) => {
+    if (val === unref(valueHtml)) return
+    valueHtml.value = val
+  },
+  {
+    immediate: true
+  }
+)
+
+// 监听
+watch(
+  () => valueHtml.value,
+  (val: string) => {
+    emit('update:modelValue', val)
+  }
+)
+
+const handleCreated = (editor: IDomEditor) => {
+  editorRef.value = editor
+}
+
+// 编辑器配置
+const editorConfig = computed((): IEditorConfig => {
+  return Object.assign(
+    {
+      readOnly: false,
+      customAlert: (s: string, t: string) => {
+        switch (t) {
+          case 'success':
+            ElMessage.success(s)
+            break
+          case 'info':
+            ElMessage.info(s)
+            break
+          case 'warning':
+            ElMessage.warning(s)
+            break
+          case 'error':
+            ElMessage.error(s)
+            break
+          default:
+            ElMessage.info(s)
+            break
+        }
+      },
+      autoFocus: false,
+      scroll: true,
+      uploadImgShowBase64: true
+    },
+    props.editorConfig || {}
+  )
+})
+
+const editorStyle = computed(() => {
+  return {
+    height: isNumber(props.height) ? `${props.height}px` : props.height
+  }
+})
+
+// 回调函数
+const handleChange = (editor: IDomEditor) => {
+  emit('change', editor)
+}
+
+// 组件销毁时,及时销毁编辑器
+onBeforeUnmount(() => {
+  const editor = unref(editorRef.value)
+
+  // 销毁,并移除 editor
+  editor?.destroy()
+})
+
+const getEditorRef = async (): Promise<IDomEditor> => {
+  await nextTick()
+  return unref(editorRef.value) as IDomEditor
+}
+
+defineExpose({
+  getEditorRef
+})
+</script>
+
+<template>
+  <div class="border-1 border-solid border-[var(--el-border-color)] z-10">
+    <!-- 工具栏 -->
+    <Toolbar
+      :editor="editorRef"
+      :editorId="editorId"
+      class="border-0 b-b-1 border-solid border-[var(--el-border-color)]"
+    />
+    <!-- 编辑器 -->
+    <Editor
+      v-model="valueHtml"
+      :editorId="editorId"
+      :defaultConfig="editorConfig"
+      :style="editorStyle"
+      @on-change="handleChange"
+      @on-created="handleCreated"
+    />
+  </div>
+</template>
+
+<style src="@wangeditor/editor/dist/css/style.css"></style>

+ 3 - 0
src/components/Error/index.ts

@@ -0,0 +1,3 @@
+import Error from './src/Error.vue'
+
+export { Error }

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