Kaynağa Gözat

first commit

DESKTOP-HN5QP3V\Administrator 11 ay önce
işleme
62808f07e6
100 değiştirilmiş dosya ile 4685 ekleme ve 0 silme
  1. 20 0
      .env.base
  2. 38 0
      .env.dev
  3. 38 0
      .env.gitee
  4. 38 0
      .env.pro
  5. 38 0
      .env.test
  6. 8 0
      .eslintignore
  7. 70 0
      .eslintrc.js
  8. 9 0
      .gitignore
  9. 4 0
      .husky/commit-msg
  10. 9 0
      .husky/lintstagedrc.js
  11. 8 0
      .husky/pre-commit
  12. 5 0
      .idea/.gitignore
  13. 7 0
      .idea/inspectionProfiles/Project_Default.xml
  14. 8 0
      .idea/modules.xml
  15. 12 0
      .idea/vue-element-plus-admin-mini.iml
  16. 10 0
      .prettierignore
  17. 6 0
      .stylelintignore
  18. 3 0
      .vscode/extensions.json
  19. 19 0
      .vscode/settings.json
  20. 837 0
      CHANGELOG.md
  21. 21 0
      LICENSE
  22. 132 0
      README.md
  23. 132 0
      README.zh-CN.md
  24. 28 0
      commitlint.config.js
  25. 142 0
      index.html
  26. 18 0
      mock/_createProductionServer.ts
  27. 64 0
      mock/role/index.mock.ts
  28. 326 0
      mock/table/index.mock.ts
  29. 90 0
      mock/user/index.mock.ts
  30. 135 0
      package.json
  31. 11 0
      plop/component/component.hbs
  32. 3 0
      plop/component/index.hbs
  33. 38 0
      plop/component/prompt.js
  34. 37 0
      plop/view/prompt.js
  35. 7 0
      plop/view/view.hbs
  36. 7 0
      plopfile.js
  37. 5 0
      postcss.config.js
  38. 19 0
      prettier.config.js
  39. BIN
      public/favicon.ico
  40. BIN
      public/logo.png
  41. 49 0
      src/App.vue
  42. 24 0
      src/api/login/index.ts
  43. 12 0
      src/api/login/types.ts
  44. 26 0
      src/api/table/index.ts
  45. 7 0
      src/api/table/types.ts
  46. 30 0
      src/api/version/index.ts
  47. 15 0
      src/api/version/types.ts
  48. BIN
      src/assets/imgs/avatar.jpg
  49. BIN
      src/assets/imgs/logo.png
  50. 0 0
      src/assets/svgs/403.svg
  51. 0 0
      src/assets/svgs/404.svg
  52. 0 0
      src/assets/svgs/500.svg
  53. 1 0
      src/assets/svgs/icon.svg
  54. 0 0
      src/assets/svgs/login-bg.svg
  55. 0 0
      src/assets/svgs/login-box-bg.svg
  56. 1 0
      src/assets/svgs/message.svg
  57. 1 0
      src/assets/svgs/money.svg
  58. 1 0
      src/assets/svgs/peoples.svg
  59. 0 0
      src/assets/svgs/shopping.svg
  60. 52 0
      src/axios/config.ts
  61. 41 0
      src/axios/index.ts
  62. 74 0
      src/axios/service.ts
  63. 31 0
      src/axios/types/index.ts
  64. 3 0
      src/components/Backtop/index.ts
  65. 15 0
      src/components/Backtop/src/Backtop.vue
  66. 3 0
      src/components/Breadcrumb/index.ts
  67. 126 0
      src/components/Breadcrumb/src/Breadcrumb.vue
  68. 31 0
      src/components/Breadcrumb/src/helper.ts
  69. 3 0
      src/components/Button/index.ts
  70. 121 0
      src/components/Button/src/Button.vue
  71. 3 0
      src/components/Collapse/index.ts
  72. 34 0
      src/components/Collapse/src/Collapse.vue
  73. 5 0
      src/components/ConfigGlobal/index.ts
  74. 62 0
      src/components/ConfigGlobal/src/ConfigGlobal.vue
  75. 5 0
      src/components/ConfigGlobal/src/types/index.ts
  76. 3 0
      src/components/ContentDetailWrap/index.ts
  77. 25 0
      src/components/ContentDetailWrap/src/ContentDetailWrap.vue
  78. 3 0
      src/components/ContentWrap/index.ts
  79. 33 0
      src/components/ContentWrap/src/ContentWrap.vue
  80. 12 0
      src/components/ContextMenu/index.ts
  81. 72 0
      src/components/ContextMenu/src/ContextMenu.vue
  82. 7 0
      src/components/ContextMenu/src/types/index.ts
  83. 5 0
      src/components/Descriptions/index.ts
  84. 161 0
      src/components/Descriptions/src/Descriptions.vue
  85. 15 0
      src/components/Descriptions/src/types/index.ts
  86. 3 0
      src/components/Dialog/index.ts
  87. 132 0
      src/components/Dialog/src/Dialog.vue
  88. 8 0
      src/components/Editor/index.ts
  89. 137 0
      src/components/Editor/src/Editor.vue
  90. 3 0
      src/components/Error/index.ts
  91. 58 0
      src/components/Error/src/Error.vue
  92. 3 0
      src/components/Footer/index.ts
  93. 22 0
      src/components/Footer/src/Footer.vue
  94. 48 0
      src/components/Form/index.ts
  95. 420 0
      src/components/Form/src/Form.vue
  96. 32 0
      src/components/Form/src/components/useRenderCheckbox.tsx
  97. 32 0
      src/components/Form/src/components/useRenderRadio.tsx
  98. 58 0
      src/components/Form/src/components/useRenderSelect.tsx
  99. 53 0
      src/components/Form/src/helper/componentMap.ts
  100. 162 0
      src/components/Form/src/helper/index.ts

+ 20 - 0
.env.base

@@ -0,0 +1,20 @@
+# 环境
+VITE_NODE_ENV=development
+
+# 接口前缀
+VITE_API_BASE_PATH=
+
+# 打包路径
+VITE_BASE_PATH=/
+
+# 标题
+VITE_APP_TITLE=后台管理
+
+# 是否全量引入element-plus样式
+VITE_USE_ALL_ELEMENT_PLUS_STYLE=true
+
+# 是否开启mock
+VITE_USE_MOCK=true
+
+# 是否使用在线图标
+VITE_USE_ONLINE_ICON=true

+ 38 - 0
.env.dev

@@ -0,0 +1,38 @@
+# 环境
+VITE_NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=
+
+# 打包路径
+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=后台管理
+
+# 是否包分析
+VITE_USE_BUNDLE_ANALYZER=false
+
+# 是否全量引入element-plus样式
+VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
+
+# 是否开启mock
+VITE_USE_MOCK=true
+
+# 是否切割css
+VITE_USE_CSS_SPLIT=true
+
+# 是否使用在线图标
+VITE_USE_ONLINE_ICON=true

+ 38 - 0
.env.gitee

@@ -0,0 +1,38 @@
+# 环境
+VITE_NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=
+
+# 打包路径
+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=后台管理
+
+# 是否包分析
+VITE_USE_BUNDLE_ANALYZER=false
+
+# 是否全量引入element-plus样式
+VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
+
+# 是否开启mock
+VITE_USE_MOCK=true
+
+# 是否切割css
+VITE_USE_CSS_SPLIT=true
+
+# 是否使用在线图标
+VITE_USE_ONLINE_ICON=true

+ 38 - 0
.env.pro

@@ -0,0 +1,38 @@
+# 环境
+VITE_NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=
+
+# 打包路径
+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=后台管理
+
+# 是否包分析
+VITE_USE_BUNDLE_ANALYZER=true
+
+# 是否全量引入element-plus样式
+VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
+
+# 是否开启mock
+VITE_USE_MOCK=true
+
+# 是否切割css
+VITE_USE_CSS_SPLIT=true
+
+# 是否使用在线图标
+VITE_USE_ONLINE_ICON=true

+ 38 - 0
.env.test

@@ -0,0 +1,38 @@
+# 环境
+VITE_NODE_ENV=production
+
+# 接口前缀
+VITE_API_BASE_PATH=
+
+# 打包路径
+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=后台管理
+
+# 是否包分析
+VITE_USE_BUNDLE_ANALYZER=false
+
+# 是否全量引入element-plus样式
+VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
+
+# 是否开启mock
+VITE_USE_MOCK=true
+
+# 是否切割css
+VITE_USE_CSS_SPLIT=false
+
+# 是否使用在线图标
+VITE_USE_ONLINE_ICON=true

+ 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'
+  }
+})

+ 9 - 0
.gitignore

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

+ 4 - 0
.husky/commit-msg

@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+pnpm commitlint --edit "$1"

+ 9 - 0
.husky/lintstagedrc.js

@@ -0,0 +1,9 @@
+module.exports = {
+  '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
+  '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
+  'package.json': ['prettier --write'],
+  '*.vue': ['prettier --write', 'stylelint --fix'],
+  '*.{scss,less,styl,css,html}': ['stylelint --fix', 'prettier --write'],
+  '*.md': ['prettier --write'],
+  '*.hbs': ['prettier --write']
+}

+ 8 - 0
.husky/pre-commit

@@ -0,0 +1,8 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+[ -n "$CI" ] && exit 0
+
+# Format and submit code according to lintstagedrc.js configuration
+npm run ts:check
+npm run lint:lint-staged

+ 5 - 0
.idea/.gitignore

@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 7 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,7 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
+    <inspection_tool class="Stylelint" enabled="true" level="ERROR" enabled_by_default="true" />
+  </profile>
+</component>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/vue-element-plus-admin-mini.iml" filepath="$PROJECT_DIR$/.idea/vue-element-plus-admin-mini.iml" />
+    </modules>
+  </component>
+</project>

+ 12 - 0
.idea/vue-element-plus-admin-mini.iml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/temp" />
+      <excludeFolder url="file://$MODULE_DIR$/tmp" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 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/**/*

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["vue.volar", "lokalise.i18n-ally"]
+}

+ 19 - 0
.vscode/settings.json

@@ -0,0 +1,19 @@
+{
+  "typescript.tsdk": "node_modules/typescript/lib",
+  "prettier.enable": false,
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": "explicit"
+  },
+  "[vue]": {
+    "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
+  },
+  "i18n-ally.localesPaths": ["src/locales"],
+  "i18n-ally.keystyle": "nested",
+  "i18n-ally.sortKeys": true,
+  "i18n-ally.namespace": false,
+  "i18n-ally.enabledParsers": ["ts"],
+  "i18n-ally.sourceLanguage": "en",
+  "i18n-ally.displayLanguage": "zh-CN",
+  "i18n-ally.enabledFrameworks": ["vue", "react"],
+  "god.tsconfig": "./tsconfig.json"
+}

+ 837 - 0
CHANGELOG.md

@@ -0,0 +1,837 @@
+# 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.
+
+## [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.

+ 132 - 0
README.md

@@ -0,0 +1,132 @@
+<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)
+
+<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`, `vite4` 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 `tempalte` branch. `Tempalte` 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 test/test**
+
+`admin` account is used to simulate the control permission of the server, and render whatever the server returns
+
+`test` account is used to simulate the front-end control authority. The server only returns the menu key to be displayed, and the front-end performs matching rendering
+
+## 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 |
+
+## License
+
+[MIT](./LICENSE)

+ 132 - 0
README.zh-CN.md

@@ -0,0 +1,132 @@
+<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)
+
+<h1>vue-element-plus-admin</h1>
+</div>
+
+[English](./README.md) | **中文**
+
+## 介绍
+
+vue-element-plus-admin 是一个基于 `element-plus` 免费开源的中后台模版。使用了最新的`vue3`,`vite4`,`TypeScript`等主流技术开发,开箱即用的中后台前端解决方案,可以用来作为项目的启动模版,也可用于学习参考。并且时刻关注着最新技术动向,尽可能的第一时间更新。
+
+vue-element-plus-admin 的定位是后台集成方案,不太适合当基础模板来进行二次开发。因为集成了很多你可能用不到的功能,会造成不少的代码冗余。如果你的项目不关注这方面的问题,也可以直接基于它进行二次开发。
+
+如需要基础模版,请切换到 `tempalte` 分支,`tempalte` 只简单集成了一些如:布局、动态菜单等常用布局功能,更适合开发者进行二次开发。
+
+## 特性
+
+- **最新技术栈**:使用 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 test/test**
+
+`admin` 帐号用于模拟服务端控制权限,服务端返回什么就渲染什么
+
+`test` 帐号用于模拟前端控制权限,服务端只返回需要显示的菜单 key,前端进行匹配渲染
+
+## 文档
+
+[文档地址 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 |
+
+## 许可证
+
+[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 1s 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('./**/*.mock.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)
+}

+ 64 - 0
mock/role/index.mock.ts

@@ -0,0 +1,64 @@
+import { MockMethod } from 'vite-plugin-mock'
+import { SUCCESS_CODE } from '@/constants'
+
+const timeout = 1000
+
+const adminList = [
+  {
+    path: '/version',
+    name: 'Version',
+    redirect: '/version/version',
+    component: '#',
+    meta: {
+      title: 'router.version',
+      icon: 'carbon:skill-level-advanced',
+      alwaysShow: true
+    },
+    children: [
+      {
+        path: 'version',
+        component: 'views/Version/Version',
+        name: 'VersionList',
+        meta: {
+          title: 'router.version_list',
+          noCache: true,
+          affix: true
+        }
+      },
+      {
+        path: 'test',
+        component: 'views/Version/Test',
+        name: 'VersionTest',
+        meta: {
+          title: 'router.version_test',
+          noCache: true
+        }
+      }
+    ]
+  }
+]
+
+const testList: string[] = [
+  '/level',
+  '/level/menu1',
+  '/level/menu1/menu1-1',
+  '/level/menu1/menu1-1/menu1-1-1',
+  '/level/menu1/menu1-2',
+  '/level/menu2'
+]
+
+export default [
+  // 列表接口
+  {
+    url: '/mock/role/list',
+    method: 'get',
+    timeout,
+    response: ({ query }) => {
+      const { roleName } = query
+      return {
+        code: SUCCESS_CODE,
+        data: roleName === 'admin' ? adminList : testList
+      }
+    }
+  }
+] as MockMethod[]

+ 326 - 0
mock/table/index.mock.ts

@@ -0,0 +1,326 @@
+import Mock from 'mockjs'
+import { SUCCESS_CODE } from '@/constants'
+import { toAnyString } from '@/utils'
+
+const timeout = 1000
+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
+  cdn: string
+  url: string
+  number: string
+  author: string
+  title: string
+  content: string
+  importance: number
+  display_time: any
+  pageviews: number
+  image_uri: string
+  video_uri?: string
+}
+
+interface TreeListProps {
+  id: string
+  author: string
+  title: string
+  content: string
+  importance: number
+  display_time: any
+  image_uri: string
+  pageviews: number
+  video_uri?: string
+  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',
+      cdn: 'https://123123123/com',
+      url: 'https://dsbqj.test.com',
+      number: '1.0.0',
+      title: '@title(5, 10)',
+      content: baseContent,
+      importance: '@integer(1, 3)',
+      display_time: '@datetime',
+      pageviews: '@integer(100, 500)',
+      image_uri: Mock.Random.image('@integer(100, 500)x@integer(100, 500)'),
+      video_uri:
+        '//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4'
+    })
+  )
+}
+
+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)',
+      image_uri: Mock.Random.image('@integer(100, 500)x@integer(100, 500)'),
+      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)',
+          image_uri: Mock.Random.image('@integer(100, 500)x@integer(100, 500)'),
+          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)',
+              image_uri: Mock.Random.image('@integer(100, 500)x@integer(100, 500)')
+            },
+            {
+              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(100, 500)x@integer(100, 500)')
+            }
+          ]
+        },
+        {
+          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(100, 500)x@integer(100, 500)')
+        },
+        {
+          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(100, 500)x@integer(100, 500)')
+        },
+        {
+          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(100, 500)x@integer(100, 500)')
+        }
+      ]
+      // image_uri
+    })
+  )
+}
+
+const cardList = [
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
+    name: 'Alipay',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
+    name: 'Angular',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
+    name: 'Bootstrap',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png',
+    name: 'React',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
+    name: 'Vue',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png',
+    name: 'Webpack',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  }
+]
+
+export default [
+  // 树形列表接口
+  {
+    url: '/mock/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: SUCCESS_CODE,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 列表接口
+  {
+    url: '/mock/example/list',
+    method: 'get',
+    timeout,
+    response: ({ query }) => {
+      console.log('ssssss')
+      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: SUCCESS_CODE,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 保存接口
+  {
+    url: '/mock/example/save',
+    method: 'post',
+    timeout,
+    response: ({ body }) => {
+      if (!body.id) {
+        List = [
+          Object.assign(body, {
+            id: toAnyString()
+          })
+        ].concat(List)
+        return {
+          code: SUCCESS_CODE,
+          data: 'success'
+        }
+      } else {
+        List.map((item) => {
+          if (item.id === body.id) {
+            for (const key in item) {
+              item[key] = body[key]
+            }
+          }
+        })
+        return {
+          code: SUCCESS_CODE,
+          data: 'success'
+        }
+      }
+    }
+  },
+  // 详情接口
+  {
+    url: '/mock/example/detail',
+    method: 'get',
+    response: ({ query }) => {
+      const { id } = query
+      for (const example of List) {
+        if (example.id === id) {
+          return {
+            code: SUCCESS_CODE,
+            data: example
+          }
+        }
+      }
+    }
+  },
+  // 删除接口
+  {
+    url: '/mock/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: SUCCESS_CODE,
+          data: 'success'
+        }
+      }
+    }
+  },
+  {
+    url: '/mock/card/list',
+    method: 'get',
+    timeout,
+    response: ({ query }) => {
+      const { name, pageIndex, pageSize } = query
+      const mockList = cardList.filter((item) => {
+        if (name && item.name.indexOf(name) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+      )
+      return {
+        code: SUCCESS_CODE,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  }
+]

+ 90 - 0
mock/user/index.mock.ts

@@ -0,0 +1,90 @@
+import { SUCCESS_CODE } from '@/constants'
+
+const timeout = 1000
+
+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: '/mock/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: SUCCESS_CODE,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
+  },
+  // 登录接口
+  {
+    url: '/mock/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: SUCCESS_CODE,
+            data: user
+          }
+        }
+      }
+      if (!hasUser) {
+        return {
+          code: 500,
+          message: '账号或密码错误'
+        }
+      }
+    }
+  },
+  // 退出接口
+  {
+    url: '/mock/user/loginOut',
+    method: 'get',
+    timeout,
+    response: () => {
+      return {
+        code: SUCCESS_CODE,
+        data: null
+      }
+    }
+  }
+]

+ 135 - 0
package.json

@@ -0,0 +1,135 @@
+{
+  "name": "vue-element-plus-admin",
+  "version": "2.5.6",
+  "description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。",
+  "author": "Archer <502431556@qq.com>",
+  "private": false,
+  "scripts": {
+    "i": "pnpm install",
+    "dev": "pnpm vite --mode base",
+    "ts:check": "pnpm vue-tsc --noEmit --skipLibCheck",
+    "build:pro": "pnpm vite build --mode pro",
+    "build:gitee": "pnpm vite build --mode gitee",
+    "build:dev": "pnpm vite build --mode dev",
+    "build:test": "pnpm vite build --mode test",
+    "serve:pro": "pnpm vite preview --mode pro",
+    "serve:dev": "pnpm vite preview --mode dev",
+    "serve:test": "pnpm vite preview --mode test",
+    "npm:check": "pnpx npm-check-updates -u",
+    "clean": "pnpx rimraf node_modules",
+    "clean:cache": "pnpx 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"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "@faker-js/faker": "^8.4.0",
+    "@iconify/iconify": "^3.1.1",
+    "@iconify/vue": "^4.1.1",
+    "@vueuse/core": "^10.7.2",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.10",
+    "@zxcvbn-ts/core": "^3.0.4",
+    "animate.css": "^4.1.1",
+    "axios": "^1.6.7",
+    "cropperjs": "^1.6.1",
+    "dayjs": "^1.11.10",
+    "driver.js": "^1.3.1",
+    "echarts": "^5.4.3",
+    "echarts-wordcloud": "^2.1.0",
+    "element-plus": "2.5.5",
+    "lodash-es": "^4.17.21",
+    "mitt": "^3.0.1",
+    "mockjs": "^1.1.0",
+    "nprogress": "^0.2.0",
+    "pinia": "^2.1.7",
+    "pinia-plugin-persistedstate": "^3.2.1",
+    "qrcode": "^1.5.3",
+    "qs": "^6.11.2",
+    "url": "^0.11.3",
+    "vue": "3.4.15",
+    "vue-draggable-plus": "^0.3.5",
+    "vue-i18n": "9.9.1",
+    "vue-json-pretty": "^2.3.0",
+    "vue-router": "^4.2.5",
+    "vue-types": "^5.1.1",
+    "xgplayer": "^3.0.12"
+  },
+  "devDependencies": {
+    "@commitlint/cli": "^18.6.0",
+    "@commitlint/config-conventional": "^18.6.0",
+    "@iconify/json": "^2.2.180",
+    "@intlify/unplugin-vue-i18n": "^2.0.0",
+    "@types/fs-extra": "^11.0.4",
+    "@types/inquirer": "^9.0.7",
+    "@types/lodash-es": "^4.17.12",
+    "@types/node": "^20.11.16",
+    "@types/nprogress": "^0.2.3",
+    "@types/qrcode": "^1.5.5",
+    "@types/qs": "^6.9.11",
+    "@types/sortablejs": "^1.15.7",
+    "@typescript-eslint/eslint-plugin": "^6.21.0",
+    "@typescript-eslint/parser": "^6.21.0",
+    "@unocss/transformer-variant-group": "^0.58.5",
+    "@vitejs/plugin-legacy": "^5.3.0",
+    "@vitejs/plugin-vue": "^5.0.3",
+    "@vitejs/plugin-vue-jsx": "^3.1.0",
+    "autoprefixer": "^10.4.17",
+    "chalk": "^5.3.0",
+    "consola": "^3.2.3",
+    "eslint": "^8.56.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-define-config": "^2.1.0",
+    "eslint-plugin-prettier": "^5.1.3",
+    "eslint-plugin-vue": "^9.21.1",
+    "esno": "^4.0.0",
+    "fs-extra": "^11.2.0",
+    "husky": "^9.0.10",
+    "inquirer": "^9.2.14",
+    "less": "^4.2.0",
+    "lint-staged": "^15.2.2",
+    "plop": "^4.0.1",
+    "postcss": "^8.4.34",
+    "postcss-html": "^1.6.0",
+    "postcss-less": "^6.0.0",
+    "prettier": "^3.2.5",
+    "rimraf": "^5.0.5",
+    "rollup": "^4.9.6",
+    "rollup-plugin-visualizer": "^5.12.0",
+    "stylelint": "^16.2.1",
+    "stylelint-config-html": "^1.1.0",
+    "stylelint-config-recommended": "^14.0.0",
+    "stylelint-config-standard": "^36.0.0",
+    "stylelint-order": "^6.0.4",
+    "terser": "^5.27.0",
+    "typescript": "5.3.3",
+    "unocss": "^0.58.5",
+    "vite": "5.0.12",
+    "vite-plugin-ejs": "^1.7.0",
+    "vite-plugin-eslint": "^1.8.1",
+    "vite-plugin-mock": "2.9.6",
+    "vite-plugin-progress": "^0.0.7",
+    "vite-plugin-purge-icons": "^0.10.0",
+    "vite-plugin-style-import": "2.0.0",
+    "vite-plugin-svg-icons": "^2.0.1",
+    "vue-tsc": "^1.8.27"
+  },
+  "packageManager": "pnpm@8.1.0",
+  "engines": {
+    "node": ">=18.0.0",
+    "pnpm": ">=8.1.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


+ 49 - 0
src/App.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { computed } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+import { ConfigGlobal } from '@/components/ConfigGlobal'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('app')
+
+const appStore = useAppStore()
+
+const currentSize = computed(() => appStore.getCurrentSize)
+
+const greyMode = computed(() => appStore.getGreyMode)
+
+appStore.initTheme()
+</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>

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

@@ -0,0 +1,24 @@
+import request from '@/axios'
+import type { UserType } from './types'
+
+interface RoleParams {
+  roleName: string
+}
+
+export const loginApi = (data: UserType): Promise<IResponse<UserType>> => {
+  return request.post({ url: '/mock/user/login', data })
+}
+
+export const loginOutApi = (): Promise<IResponse> => {
+  return request.get({ url: '/mock/user/loginOut' })
+}
+
+export const getAdminRoleApi = (
+  params: RoleParams
+): Promise<IResponse<AppCustomRouteRecordRaw[]>> => {
+  return request.get({ url: '/mock/role/list', params })
+}
+
+export const getTestRoleApi = (params: RoleParams): Promise<IResponse<string[]>> => {
+  return request.get({ url: '/mock/role/list2', params })
+}

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

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

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

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

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

@@ -0,0 +1,7 @@
+export type TableData = {
+  id: string
+  author: string
+  title: string
+  content: string
+}
+

+ 30 - 0
src/api/version/index.ts

@@ -0,0 +1,30 @@
+import request from '@/axios'
+import type { VersionData } from './types'
+
+export const getVersionListApi = (params: any) => {
+  return request.get({ url: '/web/v1/versions', params })
+}
+
+export const newVersionApi = (data: Partial<VersionData>): Promise<IResponse> => {
+  return request.post({ url: '/web/v1/version', data })
+}
+
+export const editVersionApi = (data: Partial<VersionData>): Promise<IResponse> => {
+  return request.put({ url: '/web/v1/version', data })
+}
+
+export const delVersionApi = (key: any): Promise<IResponse> => {
+  return request.delete({ url: `/web/v1/version/${key}` })
+}
+
+export const syncVersionApi = (): Promise<IResponse> => {
+  return request.post({ url: `/web/v1/version/reload` })
+}
+
+export const test1VersionApi = (data) => {
+  return request.post({ url: `/api/v1/version/check`, data })
+}
+
+export const test2VersionApi = () => {
+  return request.post({ url: `/api/v1/version/server` })
+}

+ 15 - 0
src/api/version/types.ts

@@ -0,0 +1,15 @@
+export type TableData = {
+  id: string
+  author: string
+  title: string
+  content: string
+}
+
+export type VersionData = {
+  version: string
+  cdn: string
+  url: string
+  name: string
+  default: boolean
+}
+

BIN
src/assets/imgs/avatar.jpg


BIN
src/assets/imgs/logo.png


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
src/assets/svgs/403.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
src/assets/svgs/404.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 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>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
src/assets/svgs/login-bg.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 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>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
src/assets/svgs/shopping.svg


+ 52 - 0
src/axios/config.ts

@@ -0,0 +1,52 @@
+import { AxiosResponse, InternalAxiosRequestConfig } from './types'
+import { ElMessage } from 'element-plus'
+import qs from 'qs'
+import { SUCCESS_CODE, TRANSFORM_REQUEST_DATA } from '@/constants'
+import { useUserStoreWithOut } from '@/store/modules/user'
+import { objToFormData } from '@/utils'
+
+const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
+  if (
+    config.method === 'post' &&
+    config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
+  ) {
+    config.data = qs.stringify(config.data)
+  } else if (
+    TRANSFORM_REQUEST_DATA &&
+    config.method === 'post' &&
+    config.headers['Content-Type'] === 'multipart/form-data'
+  ) {
+    config.data = objToFormData(config.data)
+  }
+  if (config.method === 'get' && config.params) {
+    let url = config.url as string
+    url += '?'
+    const keys = Object.keys(config.params)
+    for (const key of keys) {
+      if (config.params[key] !== void 0 && config.params[key] !== null) {
+        url += `${key}=${encodeURIComponent(config.params[key])}&`
+      }
+    }
+    url = url.substring(0, url.length - 1)
+    config.params = {}
+    config.url = url
+  }
+  return config
+}
+
+const defaultResponseInterceptors = (response: AxiosResponse) => {
+  if (response?.config?.responseType === 'blob') {
+    // 如果是文件流,直接过
+    return response
+  } else if (response.data.code === SUCCESS_CODE) {
+    return response.data
+  } else {
+    ElMessage.error(response?.data?.message)
+    if (response?.data?.code === 401) {
+      const userStore = useUserStoreWithOut()
+      userStore.logout()
+    }
+  }
+}
+
+export { defaultResponseInterceptors, defaultRequestInterceptors }

+ 41 - 0
src/axios/index.ts

@@ -0,0 +1,41 @@
+import service from './service'
+import { CONTENT_TYPE } from '@/constants'
+import { useUserStoreWithOut } from '@/store/modules/user'
+
+const request = (option: AxiosConfig) => {
+  const { url, method, params, data, headers, responseType } = option
+  const userStore = useUserStoreWithOut()
+  return service.request({
+    url: url,
+    method,
+    params,
+    data,
+    responseType: responseType,
+    headers: {
+      'Content-Type': CONTENT_TYPE,
+      [userStore.getTokenKey ?? 'Authorization']: userStore.getToken ?? '',
+      ...headers
+    }
+  })
+}
+
+export default {
+  get: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'get', ...option }) as Promise<IResponse<T>>
+  },
+  post: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'post', ...option }) as Promise<IResponse<T>>
+  },
+  delete: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'delete', ...option }) as Promise<IResponse<T>>
+  },
+  put: <T = any>(option: AxiosConfig) => {
+    return request({ method: 'put', ...option }) as Promise<IResponse<T>>
+  },
+  cancelRequest: (url: string | string[]) => {
+    return service.cancelRequest(url)
+  },
+  cancelAllRequest: () => {
+    return service.cancelAllRequest()
+  }
+}

+ 74 - 0
src/axios/service.ts

@@ -0,0 +1,74 @@
+import axios, { AxiosError } from 'axios'
+import { defaultRequestInterceptors, defaultResponseInterceptors } from './config'
+
+import { AxiosInstance, InternalAxiosRequestConfig, RequestConfig, AxiosResponse } from './types'
+import { ElMessage } from 'element-plus'
+import { REQUEST_TIMEOUT } from '@/constants'
+
+export const PATH_URL = import.meta.env.VITE_API_BASE_PATH
+
+const abortControllerMap: Map<string, AbortController> = new Map()
+
+const axiosInstance: AxiosInstance = axios.create({
+  timeout: REQUEST_TIMEOUT,
+  baseURL: PATH_URL
+})
+
+axiosInstance.interceptors.request.use((res: InternalAxiosRequestConfig) => {
+  const controller = new AbortController()
+  const url = res.url || ''
+  res.signal = controller.signal
+  abortControllerMap.set(url, controller)
+  return res
+})
+
+axiosInstance.interceptors.response.use(
+  (res: AxiosResponse) => {
+    const url = res.config.url || ''
+    abortControllerMap.delete(url)
+    // 这里不能做任何处理,否则后面的 interceptors 拿不到完整的上下文了
+    return res
+  },
+  (error: AxiosError) => {
+    console.log('err: ' + error) // for debug
+    ElMessage.error(error.message)
+    return Promise.reject(error)
+  }
+)
+
+axiosInstance.interceptors.request.use(defaultRequestInterceptors)
+axiosInstance.interceptors.response.use(defaultResponseInterceptors)
+
+const service = {
+  request: (config: RequestConfig) => {
+    return new Promise((resolve, reject) => {
+      if (config.interceptors?.requestInterceptors) {
+        config = config.interceptors.requestInterceptors(config as any)
+      }
+
+      axiosInstance
+        .request(config)
+        .then((res) => {
+          resolve(res)
+        })
+        .catch((err: any) => {
+          reject(err)
+        })
+    })
+  },
+  cancelRequest: (url: string | string[]) => {
+    const urlList = Array.isArray(url) ? url : [url]
+    for (const _url of urlList) {
+      abortControllerMap.get(_url)?.abort()
+      abortControllerMap.delete(_url)
+    }
+  },
+  cancelAllRequest() {
+    for (const [_, controller] of abortControllerMap) {
+      controller.abort()
+    }
+    abortControllerMap.clear()
+  }
+}
+
+export default service

+ 31 - 0
src/axios/types/index.ts

@@ -0,0 +1,31 @@
+import type {
+  InternalAxiosRequestConfig,
+  AxiosResponse,
+  AxiosRequestConfig,
+  AxiosInstance,
+  AxiosRequestHeaders,
+  AxiosError
+} from 'axios'
+
+interface RequestInterceptors<T> {
+  // 请求拦截
+  requestInterceptors?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
+  requestInterceptorsCatch?: (err: any) => any
+  // 响应拦截
+  responseInterceptors?: (config: T) => T
+  responseInterceptorsCatch?: (err: any) => any
+}
+
+interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
+  interceptors?: RequestInterceptors<T>
+}
+
+export {
+  AxiosResponse,
+  RequestInterceptors,
+  RequestConfig,
+  AxiosInstance,
+  InternalAxiosRequestConfig,
+  AxiosRequestHeaders,
+  AxiosError
+}

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

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

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

@@ -0,0 +1,15 @@
+<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`"
+    :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, RouteMeta } 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 as RouteMeta
+        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>

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

@@ -0,0 +1,31 @@
+import { pathResolve } from '@/utils/routerHelper'
+import type { RouteMeta } from 'vue-router'
+
+export const filterBreadcrumb = (
+  routes: AppRouteRecordRaw[],
+  parentPath = ''
+): AppRouteRecordRaw[] => {
+  const res: AppRouteRecordRaw[] = []
+
+  for (const route of routes) {
+    const meta = route?.meta as RouteMeta
+    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/Button/index.ts

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

+ 121 - 0
src/components/Button/src/Button.vue

@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import { useDesign } from '@/hooks/web/useDesign'
+import { ElButton, ComponentSize, ButtonType } from 'element-plus'
+import { PropType, Component, computed, unref } from 'vue'
+import { useAppStore } from '@/store/modules/app'
+
+const appStore = useAppStore()
+
+const getTheme = computed(() => appStore.getTheme)
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('button')
+
+const props = defineProps({
+  size: {
+    type: String as PropType<ComponentSize>,
+    default: undefined
+  },
+  type: {
+    type: String as PropType<ButtonType>,
+    default: 'default'
+  },
+  disabled: {
+    type: Boolean,
+    default: false
+  },
+  plain: {
+    type: Boolean,
+    default: false
+  },
+  text: {
+    type: Boolean,
+    default: false
+  },
+  bg: {
+    type: Boolean,
+    default: false
+  },
+  link: {
+    type: Boolean,
+    default: false
+  },
+  round: {
+    type: Boolean,
+    default: false
+  },
+  circle: {
+    type: Boolean,
+    default: false
+  },
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  loadingIcon: {
+    type: [String, Object] as PropType<String | Component>,
+    default: undefined
+  },
+  icon: {
+    type: [String, Object] as PropType<String | Component>,
+    default: undefined
+  },
+  autofocus: {
+    type: Boolean,
+    default: false
+  },
+  nativeType: {
+    type: String as PropType<'button' | 'submit' | 'reset'>,
+    default: 'button'
+  },
+  autoInsertSpace: {
+    type: Boolean,
+    default: false
+  },
+  color: {
+    type: String,
+    default: ''
+  },
+  darker: {
+    type: Boolean,
+    default: false
+  },
+  tag: {
+    type: [String, Object] as PropType<String | Component>,
+    default: 'button'
+  }
+})
+
+const emits = defineEmits(['click'])
+
+const color = computed(() => {
+  const { type } = props
+  if (type === 'primary') {
+    return unref(getTheme).elColorPrimary
+  }
+  return ''
+})
+
+const style = computed(() => {
+  const { type } = props
+  if (type === 'primary') {
+    return '--el-button-text-color: #fff; --el-button-hover-text-color: #fff'
+  }
+  return ''
+})
+</script>
+
+<template>
+  <ElButton
+    :class="`${prefixCls} color-#fff`"
+    v-bind="{ ...props }"
+    :color="color"
+    :style="style"
+    @click="() => emits('click')"
+  >
+    <slot></slot>
+    <slot name="icon"></slot>
+    <slot name="loading"></slot>
+  </ElButton>
+</template>

+ 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 }

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

@@ -0,0 +1,33 @@
+<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>
+    </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
+}

+ 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`]}>
+              <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>

+ 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 }

+ 58 - 0
src/components/Error/src/Error.vue

@@ -0,0 +1,58 @@
+<script setup lang="ts">
+import pageError from '@/assets/svgs/404.svg'
+import networkError from '@/assets/svgs/500.svg'
+import noPermission from '@/assets/svgs/403.svg'
+import { propTypes } from '@/utils/propTypes'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ElButton } from 'element-plus'
+
+interface ErrorMap {
+  url: string
+  message: string
+  buttonText: string
+}
+
+const { t } = useI18n()
+
+const errorMap: {
+  [key: string]: ErrorMap
+} = {
+  '404': {
+    url: pageError,
+    message: t('error.pageError'),
+    buttonText: t('error.returnToHome')
+  },
+  '500': {
+    url: networkError,
+    message: t('error.networkError'),
+    buttonText: t('error.returnToHome')
+  },
+  '403': {
+    url: noPermission,
+    message: t('error.noPermission'),
+    buttonText: t('error.returnToHome')
+  }
+}
+
+const props = defineProps({
+  type: propTypes.string.validate((v: string) => ['404', '500', '403'].includes(v)).def('404')
+})
+
+const emit = defineEmits(['errorClick'])
+
+const btnClick = () => {
+  emit('errorClick', props.type)
+}
+</script>
+
+<template>
+  <div class="flex justify-center">
+    <div class="text-center">
+      <img width="350" :src="errorMap[type].url" alt="" />
+      <div class="text-14px text-[var(--el-color-info)]">{{ errorMap[type].message }}</div>
+      <div class="mt-20px">
+        <ElButton type="primary" @click="btnClick">{{ errorMap[type].buttonText }}</ElButton>
+      </div>
+    </div>
+  </div>
+</template>

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

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

+ 22 - 0
src/components/Footer/src/Footer.vue

@@ -0,0 +1,22 @@
+<script setup lang="ts">
+import { useAppStore } from '@/store/modules/app'
+import { computed } from 'vue'
+import { useDesign } from '@/hooks/web/useDesign'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('footer')
+
+const appStore = useAppStore()
+
+const title = computed(() => appStore.getTitle)
+</script>
+
+<template>
+  <div
+    :class="prefixCls"
+    class="shrink-0 text-center text-[var(--el-text-color-placeholder)] bg-[var(--app-content-bg-color)] h-[var(--app-footer-height)] leading-[var(--app-footer-height)] dark:bg-[var(--el-bg-color)]"
+  >
+    Copyright ©2021-present {{ title }}
+  </div>
+</template>

+ 48 - 0
src/components/Form/index.ts

@@ -0,0 +1,48 @@
+import Form from './src/Form.vue'
+import type { FormSchema, FormSetProps } from './src/types'
+export type {
+  ComponentNameEnum,
+  ComponentName,
+  InputComponentProps,
+  AutocompleteComponentProps,
+  InputNumberComponentProps,
+  SelectOption,
+  SelectComponentProps,
+  SelectV2ComponentProps,
+  CascaderComponentProps,
+  SwitchComponentProps,
+  RateComponentProps,
+  ColorPickerComponentProps,
+  TransferComponentProps,
+  RadioOption,
+  RadioGroupComponentProps,
+  RadioButtonComponentProps,
+  CheckboxOption,
+  CheckboxGroupComponentProps,
+  DividerComponentProps,
+  DatePickerComponentProps,
+  DateTimePickerComponentProps,
+  TimePickerComponentProps,
+  TimeSelectComponentProps,
+  ColProps,
+  FormSetProps,
+  FormItemProps,
+  FormSchema,
+  FormProps,
+  PlaceholderModel,
+  InputPasswordComponentProps,
+  TreeSelectComponentProps
+} from './src/types'
+
+export interface FormExpose {
+  setValues: (data: Recordable) => void
+  setProps: (props: Recordable) => void
+  delSchema: (field: string) => void
+  addSchema: (formSchema: FormSchema, index?: number) => void
+  setSchema: (schemaProps: FormSetProps[]) => void
+  formModel: Recordable
+  getComponentExpose: (field: string) => any
+  getFormItemExpose: (field: string) => any
+}
+
+export { Form }

+ 420 - 0
src/components/Form/src/Form.vue

@@ -0,0 +1,420 @@
+<script lang="tsx">
+import { PropType, defineComponent, ref, computed, unref, watch, onMounted } from 'vue'
+import {
+  ElForm,
+  ElFormItem,
+  ElRow,
+  ElCol,
+  FormRules,
+  ComponentSize
+  // FormItemProp
+} from 'element-plus'
+import { componentMap } from './helper/componentMap'
+import { propTypes } from '@/utils/propTypes'
+import { getSlot } from '@/utils/tsxHelper'
+import {
+  setTextPlaceholder,
+  setGridProp,
+  setComponentProps,
+  setItemComponentSlots,
+  initModel
+} from './helper'
+import { useRenderSelect } from './components/useRenderSelect'
+import { useRenderRadio } from './components/useRenderRadio'
+import { useRenderCheckbox } from './components/useRenderCheckbox'
+import { useDesign } from '@/hooks/web/useDesign'
+import { findIndex } from '@/utils'
+import { get, set } from 'lodash-es'
+import { FormProps } from './types'
+import {
+  FormSchema,
+  FormSetProps,
+  ComponentNameEnum,
+  SelectComponentProps,
+  RadioGroupComponentProps,
+  CheckboxGroupComponentProps
+} from './types'
+
+const { renderSelectOptions } = useRenderSelect()
+const { renderRadioOptions } = useRenderRadio()
+const { renderCheckboxOptions } = useRenderCheckbox()
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('form')
+
+export default defineComponent({
+  name: 'Form',
+  props: {
+    // 生成Form的布局结构数组
+    schema: {
+      type: Array as PropType<FormSchema[]>,
+      default: () => []
+    },
+    // 是否需要栅格布局
+    isCol: propTypes.bool.def(true),
+    // 表单数据对象
+    model: {
+      type: Object as PropType<any>,
+      default: () => ({})
+    },
+    // 是否自动设置placeholder
+    autoSetPlaceholder: propTypes.bool.def(true),
+    // 是否自定义内容
+    isCustom: propTypes.bool.def(false),
+    // 表单label宽度
+    labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
+    rules: {
+      type: Object as PropType<FormRules>,
+      default: () => ({})
+    },
+    labelPosition: propTypes.oneOf(['left', 'right', 'top']).def('right'),
+    labelSuffix: propTypes.string.def(''),
+    hideRequiredAsterisk: propTypes.bool.def(false),
+    requireAsteriskPosition: propTypes.oneOf(['left', 'right']).def('left'),
+    showMessage: propTypes.bool.def(true),
+    inlineMessage: propTypes.bool.def(false),
+    statusIcon: propTypes.bool.def(false),
+    validateOnRuleChange: propTypes.bool.def(true),
+    size: {
+      type: String as PropType<ComponentSize>,
+      default: undefined
+    },
+    disabled: propTypes.bool.def(false),
+    scrollToError: propTypes.bool.def(false),
+    scrollToErrorOffset: propTypes.oneOfType([Boolean, Object]).def(undefined)
+    // onValidate: {
+    //   type: Function as PropType<(prop: FormItemProp, isValid: boolean, message: string) => void>,
+    //   default: () => {}
+    // }
+  },
+  emits: ['register'],
+  setup(props, { slots, expose, emit }) {
+    // element form 实例
+    const elFormRef = ref<ComponentRef<typeof ElForm>>()
+
+    const mergeProps = ref<FormProps>({})
+
+    const getProps = computed(() => {
+      const propsObj = { ...props }
+      Object.assign(propsObj, unref(mergeProps))
+      return propsObj
+    })
+
+    // 存储表单实例
+    const formComponents = ref({})
+
+    // 存储form-item实例
+    const formItemComponents = ref({})
+
+    // 表单数据
+    const formModel = ref<Recordable>(props.model)
+
+    onMounted(() => {
+      emit('register', unref(elFormRef)?.$parent, unref(elFormRef))
+    })
+
+    // 对表单赋值
+    const setValues = (data: Recordable = {}) => {
+      formModel.value = Object.assign(unref(formModel), data)
+    }
+
+    const setProps = (props: FormProps = {}) => {
+      mergeProps.value = Object.assign(unref(mergeProps), props)
+    }
+
+    const delSchema = (field: string) => {
+      const { schema } = unref(getProps)
+
+      const index = findIndex(schema, (v: FormSchema) => v.field === field)
+      if (index > -1) {
+        schema.splice(index, 1)
+      }
+    }
+
+    const addSchema = (formSchema: FormSchema, index?: number) => {
+      const { schema } = unref(getProps)
+      if (index !== void 0) {
+        schema.splice(index, 0, formSchema)
+        return
+      }
+      schema.push(formSchema)
+    }
+
+    const setSchema = (schemaProps: FormSetProps[]) => {
+      const { schema } = unref(getProps)
+      for (const v of schema) {
+        for (const item of schemaProps) {
+          if (v.field === item.field) {
+            set(v, item.path, item.value)
+          }
+        }
+      }
+    }
+
+    const getOptions = async (fn: Function, item: FormSchema) => {
+      const options = await fn()
+      setSchema([
+        {
+          field: item.field,
+          path:
+            item.component === ComponentNameEnum.TREE_SELECT
+              ? 'componentProps.data'
+              : 'componentProps.options',
+          value: options
+        }
+      ])
+    }
+
+    /**
+     * @description: 获取表单组件实例
+     * @param filed 表单字段
+     */
+    const getComponentExpose = (filed: string) => {
+      return unref(formComponents)[filed]
+    }
+
+    /**
+     * @description: 获取formItem实例
+     * @param filed 表单字段
+     */
+    const getFormItemExpose = (filed: string) => {
+      return unref(formItemComponents)[filed]
+    }
+
+    const setComponentRefMap = (ref: any, filed: string) => {
+      formComponents.value[filed] = ref
+    }
+
+    const setFormItemRefMap = (ref: any, filed: string) => {
+      formItemComponents.value[filed] = ref
+    }
+
+    expose({
+      setValues,
+      formModel,
+      setProps,
+      delSchema,
+      addSchema,
+      setSchema,
+      getComponentExpose,
+      getFormItemExpose
+    })
+
+    // 监听表单结构化数组,重新生成formModel
+    watch(
+      () => unref(getProps).schema,
+      (schema = []) => {
+        formModel.value = initModel(schema, unref(formModel))
+      },
+      {
+        immediate: true,
+        deep: true
+      }
+    )
+
+    // 渲染包裹标签,是否使用栅格布局
+    const renderWrap = () => {
+      const { isCol } = unref(getProps)
+      const content = isCol ? (
+        <ElRow gutter={20}>{renderFormItemWrap()}</ElRow>
+      ) : (
+        renderFormItemWrap()
+      )
+      return content
+    }
+
+    // 是否要渲染el-col
+    const renderFormItemWrap = () => {
+      // hidden属性表示隐藏,不做渲染
+      const { schema = [], isCol } = unref(getProps)
+
+      return schema
+        .filter((v) => !v.remove && !v.hidden)
+        .map((item) => {
+          // 如果是 Divider 组件,需要自己占用一行
+          const isDivider = item.component === 'Divider'
+          const Com = componentMap['Divider'] as ReturnType<typeof defineComponent>
+          return isDivider ? (
+            <Com {...{ contentPosition: 'left', ...item.componentProps }}>{item?.label}</Com>
+          ) : isCol ? (
+            // 如果需要栅格,需要包裹 ElCol
+            <ElCol {...setGridProp(item.colProps)}>{renderFormItem(item)}</ElCol>
+          ) : (
+            renderFormItem(item)
+          )
+        })
+    }
+
+    // 渲染formItem
+    const renderFormItem = (item: FormSchema) => {
+      // 如果有optionApi,优先使用optionApi
+      if (item.optionApi) {
+        // 内部自动调用接口,不影响其它渲染
+        getOptions(item.optionApi, item)
+      }
+      const formItemSlots: Recordable = {
+        default: () => {
+          if (item?.formItemProps?.slots?.default) {
+            return item?.formItemProps?.slots?.default(formModel.value)
+          } else {
+            const Com = componentMap[item.component as string] as ReturnType<typeof defineComponent>
+
+            const { autoSetPlaceholder } = unref(getProps)
+
+            const componentSlots = (item?.componentProps as any)?.slots || {}
+            const slotsMap: Recordable = {
+              ...setItemComponentSlots(componentSlots)
+            }
+            // // 如果是select组件,并且没有自定义模板,自动渲染options
+            if (item.component === ComponentNameEnum.SELECT) {
+              slotsMap.default = !componentSlots.default
+                ? () => renderSelectOptions(item)
+                : () => {
+                    return componentSlots.default(
+                      unref((item?.componentProps as SelectComponentProps)?.options)
+                    )
+                  }
+            }
+
+            // 虚拟列表
+            if (item.component === ComponentNameEnum.SELECT_V2 && componentSlots.default) {
+              slotsMap.default = ({ item }) => {
+                return componentSlots.default(item)
+              }
+            }
+
+            // 单选框组和按钮样式
+            if (
+              item.component === ComponentNameEnum.RADIO_GROUP ||
+              item.component === ComponentNameEnum.RADIO_BUTTON
+            ) {
+              slotsMap.default = !componentSlots.default
+                ? () => renderRadioOptions(item)
+                : () => {
+                    return componentSlots.default(
+                      unref((item?.componentProps as CheckboxGroupComponentProps)?.options)
+                    )
+                  }
+            }
+
+            // 多选框组和按钮样式
+            if (
+              item.component === ComponentNameEnum.CHECKBOX_GROUP ||
+              item.component === ComponentNameEnum.CHECKBOX_BUTTON
+            ) {
+              slotsMap.default = !componentSlots.default
+                ? () => renderCheckboxOptions(item)
+                : () => {
+                    return componentSlots.default(
+                      unref((item?.componentProps as RadioGroupComponentProps)?.options)
+                    )
+                  }
+            }
+
+            const Comp = () => {
+              // 如果field是多层路径,需要转换成对象
+              const itemVal = computed({
+                get: () => {
+                  return get(formModel.value, item.field)
+                },
+                set: (val) => {
+                  set(formModel.value, item.field, val)
+                }
+              })
+
+              return (
+                <Com
+                  vModel={itemVal.value}
+                  ref={(el: any) => setComponentRefMap(el, item.field)}
+                  {...(autoSetPlaceholder && setTextPlaceholder(item))}
+                  {...setComponentProps(item)}
+                  style={
+                    item.componentProps?.style || {
+                      width: '100%'
+                    }
+                  }
+                >
+                  {{ ...slotsMap }}
+                </Com>
+              )
+            }
+
+            return <>{Comp()}</>
+          }
+        }
+      }
+      if (item?.formItemProps?.slots?.label) {
+        formItemSlots.label = (...args: any[]) => {
+          return (item?.formItemProps?.slots as any)?.label(...args)
+        }
+      }
+      if (item?.formItemProps?.slots?.error) {
+        formItemSlots.error = (...args: any[]) => {
+          return (item?.formItemProps?.slots as any)?.error(...args)
+        }
+      }
+      return (
+        <ElFormItem
+          v-show={!item.hidden}
+          ref={(el: any) => setFormItemRefMap(el, item.field)}
+          {...(item.formItemProps || {})}
+          prop={item.field}
+          label={item.label || ''}
+        >
+          {formItemSlots}
+        </ElFormItem>
+      )
+    }
+
+    // 过滤传入Form组件的属性
+    const getFormBindValue = () => {
+      // 避免在标签上出现多余的属性
+      const delKeys = ['schema', 'isCol', 'autoSetPlaceholder', 'isCustom', 'model']
+      const props = { ...unref(getProps) }
+      for (const key in props) {
+        if (delKeys.indexOf(key) !== -1) {
+          delete props[key]
+        }
+      }
+      return props as FormProps
+    }
+
+    return () => (
+      <ElForm
+        ref={elFormRef}
+        {...getFormBindValue()}
+        model={unref(getProps).isCustom ? unref(getProps).model : formModel}
+        class={prefixCls}
+      >
+        {{
+          // 如果需要自定义,就什么都不渲染,而是提供默认插槽
+          default: () => {
+            const { isCustom } = unref(getProps)
+            return isCustom ? getSlot(slots, 'default') : renderWrap()
+          }
+        }}
+      </ElForm>
+    )
+  }
+})
+</script>
+
+<style lang="less" scoped>
+.@{elNamespace}-form.@{namespace}-form .@{elNamespace}-row {
+  margin-right: 0 !important;
+  margin-left: 0 !important;
+}
+
+.@{elNamespace}-form--inline {
+  :deep(.el-form-item__content) {
+    & > :first-child {
+      min-width: 229.5px;
+    }
+  }
+  .@{elNamespace}-input-number {
+    // 229.5px是兼容el-input-number的最小宽度,
+    min-width: 229.5px;
+  }
+}
+</style>

+ 32 - 0
src/components/Form/src/components/useRenderCheckbox.tsx

@@ -0,0 +1,32 @@
+import { FormSchema, ComponentNameEnum, CheckboxGroupComponentProps } from '../types'
+import { ElCheckbox, ElCheckboxButton } from 'element-plus'
+import { defineComponent } from 'vue'
+
+export const useRenderCheckbox = () => {
+  const renderCheckboxOptions = (item: FormSchema) => {
+    // 如果有别名,就取别名
+    const componentProps = item?.componentProps as CheckboxGroupComponentProps
+    const valueAlias = componentProps?.props?.value || 'value'
+    const labelAlias = componentProps?.props?.label || 'label'
+    const disabledAlias = componentProps?.props?.disabled || 'disabled'
+    const Com = (
+      item.component === ComponentNameEnum.CHECKBOX_GROUP ? ElCheckbox : ElCheckboxButton
+    ) as ReturnType<typeof defineComponent>
+    return componentProps?.options?.map((option) => {
+      const { value, ...other } = option
+      return (
+        <Com
+          {...other}
+          disabled={option[disabledAlias || 'disabled']}
+          label={option[valueAlias || 'value']}
+        >
+          {option[labelAlias || 'label']}
+        </Com>
+      )
+    })
+  }
+
+  return {
+    renderCheckboxOptions
+  }
+}

+ 32 - 0
src/components/Form/src/components/useRenderRadio.tsx

@@ -0,0 +1,32 @@
+import { FormSchema, ComponentNameEnum, RadioGroupComponentProps } from '../types'
+import { ElRadio, ElRadioButton } from 'element-plus'
+import { defineComponent } from 'vue'
+
+export const useRenderRadio = () => {
+  const renderRadioOptions = (item: FormSchema) => {
+    // 如果有别名,就取别名
+    const componentProps = item?.componentProps as RadioGroupComponentProps
+    const valueAlias = componentProps?.props?.value || 'value'
+    const labelAlias = componentProps?.props?.label || 'label'
+    const disabledAlias = componentProps?.props?.disabled || 'disabled'
+    const Com = (
+      item.component === ComponentNameEnum.RADIO_GROUP ? ElRadio : ElRadioButton
+    ) as ReturnType<typeof defineComponent>
+    return componentProps?.options?.map((option) => {
+      const { value, ...other } = option
+      return (
+        <Com
+          {...other}
+          disabled={option[disabledAlias || 'disabled']}
+          label={option[valueAlias || 'value']}
+        >
+          {option[labelAlias || 'label']}
+        </Com>
+      )
+    })
+  }
+
+  return {
+    renderRadioOptions
+  }
+}

+ 58 - 0
src/components/Form/src/components/useRenderSelect.tsx

@@ -0,0 +1,58 @@
+import { ElOption, ElOptionGroup } from 'element-plus'
+import { FormSchema, SelectComponentProps, SelectOption } from '../types'
+
+export const useRenderSelect = () => {
+  // 渲染 select options
+  const renderSelectOptions = (item: FormSchema) => {
+    const componentsProps = item?.componentProps as SelectComponentProps
+    const optionGroupDefaultSlot = componentsProps?.slots?.optionGroupDefault
+    // 如果有别名,就取别名
+    const labelAlias = componentsProps?.props?.label
+    const keyAlias = componentsProps?.props?.key
+    return componentsProps?.options?.map((option) => {
+      if (option?.options?.length) {
+        return optionGroupDefaultSlot ? (
+          optionGroupDefaultSlot(option)
+        ) : (
+          <ElOptionGroup label={option[labelAlias || 'label']} key={option[keyAlias || 'key']}>
+            {{
+              default: () =>
+                option?.options?.map((v) => {
+                  return renderSelectOptionItem(item, v)
+                })
+            }}
+          </ElOptionGroup>
+        )
+      } else {
+        return renderSelectOptionItem(item, option)
+      }
+    })
+  }
+
+  // 渲染 select option item
+  const renderSelectOptionItem = (item: FormSchema, option: SelectOption) => {
+    // 如果有别名,就取别名
+    const componentsProps = item.componentProps as SelectComponentProps
+    const labelAlias = componentsProps?.props?.label
+    const valueAlias = componentsProps?.props?.value
+    const keyAlias = componentsProps?.props?.key
+    const optionDefaultSlot = componentsProps.slots?.optionDefault
+
+    return (
+      <ElOption
+        {...option}
+        key={option[keyAlias || 'key']}
+        label={option[labelAlias || 'label']}
+        value={option[valueAlias || 'value']}
+      >
+        {{
+          default: () => (optionDefaultSlot ? optionDefaultSlot(option) : undefined)
+        }}
+      </ElOption>
+    )
+  }
+
+  return {
+    renderSelectOptions
+  }
+}

+ 53 - 0
src/components/Form/src/helper/componentMap.ts

@@ -0,0 +1,53 @@
+import type { Component } from 'vue'
+import {
+  ElCascader,
+  ElCheckboxGroup,
+  ElColorPicker,
+  ElDatePicker,
+  ElInput,
+  ElInputNumber,
+  ElRadioGroup,
+  ElRate,
+  ElSelect,
+  ElSelectV2,
+  ElSlider,
+  ElSwitch,
+  ElTimePicker,
+  ElTimeSelect,
+  ElTransfer,
+  ElAutocomplete,
+  ElDivider,
+  ElTreeSelect,
+  ElUpload
+} from 'element-plus'
+import { InputPassword } from '@/components/InputPassword'
+import { Editor } from '@/components/Editor'
+import { ComponentName } from '../types'
+
+const componentMap: Recordable<Component, ComponentName> = {
+  RadioGroup: ElRadioGroup,
+  RadioButton: ElRadioGroup,
+  CheckboxGroup: ElCheckboxGroup,
+  CheckboxButton: ElCheckboxGroup,
+  Input: ElInput,
+  Autocomplete: ElAutocomplete,
+  InputNumber: ElInputNumber,
+  Select: ElSelect,
+  Cascader: ElCascader,
+  Switch: ElSwitch,
+  Slider: ElSlider,
+  TimePicker: ElTimePicker,
+  DatePicker: ElDatePicker,
+  Rate: ElRate,
+  ColorPicker: ElColorPicker,
+  Transfer: ElTransfer,
+  Divider: ElDivider,
+  TimeSelect: ElTimeSelect,
+  SelectV2: ElSelectV2,
+  InputPassword: InputPassword,
+  Editor: Editor,
+  TreeSelect: ElTreeSelect,
+  Upload: ElUpload
+}
+
+export { componentMap }

+ 162 - 0
src/components/Form/src/helper/index.ts

@@ -0,0 +1,162 @@
+import { useI18n } from '@/hooks/web/useI18n'
+import { PlaceholderModel, FormSchema, ComponentNameEnum, ColProps } from '../types'
+import { isFunction } from '@/utils/is'
+import { firstUpperCase, humpToDash } from '@/utils'
+import { set, get } from 'lodash-es'
+
+const { t } = useI18n()
+
+/**
+ *
+ * @param schema 对应组件数据
+ * @returns 返回提示信息对象
+ * @description 用于自动设置placeholder
+ */
+export const setTextPlaceholder = (schema: FormSchema): PlaceholderModel => {
+  const textMap = [
+    ComponentNameEnum.INPUT,
+    ComponentNameEnum.AUTOCOMPLETE,
+    ComponentNameEnum.INPUT_NUMBER,
+    ComponentNameEnum.INPUT_PASSWORD
+  ]
+  const selectMap = [
+    ComponentNameEnum.SELECT,
+    ComponentNameEnum.TIME_PICKER,
+    ComponentNameEnum.DATE_PICKER,
+    ComponentNameEnum.TIME_SELECT,
+    ComponentNameEnum.SELECT_V2
+  ]
+  if (textMap.includes(schema?.component as ComponentNameEnum)) {
+    return {
+      placeholder: t('common.inputText')
+    }
+  }
+  if (selectMap.includes(schema?.component as ComponentNameEnum)) {
+    // 一些范围选择器
+    const twoTextMap = ['datetimerange', 'daterange', 'monthrange', 'datetimerange', 'daterange']
+    if (
+      twoTextMap.includes(
+        ((schema?.componentProps as any)?.type ||
+          (schema?.componentProps as any)?.isRange) as string
+      )
+    ) {
+      return {
+        startPlaceholder: t('common.startTimeText'),
+        endPlaceholder: t('common.endTimeText'),
+        rangeSeparator: '-'
+      }
+    } else {
+      return {
+        placeholder: t('common.selectText')
+      }
+    }
+  }
+  return {}
+}
+
+/**
+ *
+ * @param col 内置栅格
+ * @returns 返回栅格属性
+ * @description 合并传入进来的栅格属性
+ */
+export const setGridProp = (col: ColProps = {}): ColProps => {
+  const colProps: ColProps = {
+    // 如果有span,代表用户优先级更高,所以不需要默认栅格
+    ...(col.span
+      ? {}
+      : {
+          xs: 24,
+          sm: 12,
+          md: 12,
+          lg: 12,
+          xl: 12
+        }),
+    ...col
+  }
+  return colProps
+}
+
+/**
+ *
+ * @param item 传入的组件属性
+ * @returns 默认添加 clearable 属性
+ */
+export const setComponentProps = (item: FormSchema): Recordable => {
+  // const notNeedClearable = ['ColorPicker']
+  // 拆分事件并组合
+  const onEvents = (item?.componentProps as any)?.on || {}
+  const newOnEvents: Recordable = {}
+
+  for (const key in onEvents) {
+    if (onEvents[key]) {
+      newOnEvents[`on${firstUpperCase(key)}`] = (...args: any[]) => {
+        onEvents[key](...args)
+      }
+    }
+  }
+
+  const componentProps: Recordable = {
+    clearable: true,
+    ...item.componentProps,
+    ...newOnEvents
+  }
+  // 需要删除额外的属性
+  if (componentProps.slots) {
+    delete componentProps.slots
+  }
+  if (componentProps.on) {
+    delete componentProps.on
+  }
+  return componentProps
+}
+
+/**
+ *
+ * @param formModel 表单数据
+ * @param slotsProps 插槽属性
+ */
+export const setItemComponentSlots = (slotsProps: Recordable = {}): Recordable => {
+  const slotObj: Recordable = {}
+  for (const key in slotsProps) {
+    if (slotsProps[key]) {
+      if (isFunction(slotsProps[key])) {
+        slotObj[humpToDash(key)] = (...args: any[]) => {
+          return slotsProps[key]?.(...args)
+        }
+      } else {
+        slotObj[humpToDash(key)] = () => {
+          return slotsProps[key]
+        }
+      }
+    }
+  }
+  return slotObj
+}
+
+/**
+ *
+ * @param schema Form表单结构化数组
+ * @param formModel FormMoel
+ * @returns FormMoel
+ * @description 生成对应的formModel
+ */
+export const initModel = (schema: FormSchema[], formModel: Recordable) => {
+  const model: Recordable = { ...formModel }
+  schema.map((v) => {
+    if (v.remove) {
+      delete model[v.field]
+    } else if (v.component !== 'Divider') {
+      // const hasField = Reflect.has(model, v.field)
+      const hasField = get(model, v.field)
+      // 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值
+      set(
+        model,
+        v.field,
+        hasField !== void 0 ? get(model, v.field) : v.value !== void 0 ? v.value : undefined
+      )
+      // model[v.field] = hasField ? model[v.field] : v.value !== void 0 ? v.value : undefined
+    }
+  })
+  return model
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor