diff --git a/.gitignore b/.gitignore
index 403adbc1..978f3df8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,23 @@
-.DS_Store
-node_modules
-/dist
-
-
-# local env files
-.env.local
-.env.*.local
-
-# Log files
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-
-# Editor directories and files
-.idea
-.vscode
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/README.md b/README.md
index b761442f..0d1616e1 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,10 @@
 # vue-manage-system
 
-<a href="https://github.com/vuejs/vue">
-    <img src="https://img.shields.io/badge/vue-3.1.2-brightgreen.svg" alt="vue">
-  </a>
-  <a href="https://github.com/vuejs/pinia">
-    <img src="https://img.shields.io/badge/pinia-2.0.14-brightgreen.svg" alt="pinia">
-  </a>
-  <a href="https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE">
-    <img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
-  </a>
   <a href="https://github.com/lin-xin/vue-manage-system/releases">
     <img src="https://img.shields.io/github/release/lin-xin/vue-manage-system.svg" alt="GitHub release">
   </a>
-  <a href="https://lin-xin.gitee.io/example/work/#/donate">
-    <img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
+   <a href="https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE">
+    <img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
   </a>
 
 基于 Vue3 + pinia + Element Plus 的后台管理系统解决方案。[线上地址](https://lin-xin.gitee.io/example/work/)
@@ -28,7 +19,7 @@
 
 [<img src="https://static.bestqa.net/logo/bestqa_haowen.png" width="220" height="100">](https://www.bestqa.net/home/index.html)
 
-专业问卷服务,一对一客服,按需定制 
+专业问卷服务,一对一客服,按需定制
 
 ## 支持作者
 
@@ -46,21 +37,20 @@
 -   [x] vite 3
 -   [x] pinia
 -   [x] typescript
--   [x] 登录/注销
+-   [x] 登录/注册
 -   [x] Dashboard
--   [x] 表格
--   [x] Tab 选项卡
--   [x] 表单
+-   [x] 表格/表单
 -   [x] 图表 :bar_chart:
--   [x] 富文本/markdown编辑器
+-   [x] 富文本/markdown 编辑器
 -   [x] 图片拖拽/裁剪上传
 -   [x] 权限管理
 -   [x] 三级菜单
 -   [x] 自定义图标
-
+-   [x] 主题切换
 
 ## 安装步骤
-> 因为使用vite3,node版本需要 14.18+
+
+> 因为使用 vite3,node 版本需要 14.18+
 
 ```
 git clone https://github.com/lin-xin/vue-manage-system.git      // 把模板下载到本地
@@ -74,64 +64,16 @@ npm run dev
 npm run build
 ```
 
-## 组件使用说明与演示
-
-### vue-schart
-
-vue.js 封装 sChart.js 的图表组件。访问地址:[vue-schart](https://github.com/lin-xin/vue-schart#/) 
-
-<p><a href="https://www.npmjs.com/package/vue-schart"><img src="https://img.shields.io/npm/dm/vue-schart.svg" alt="Downloads"></a></p>
-
-```html
-<template>
-    <div>
-        <schart class="wrapper" canvasId="myCanvas" :options="options"></schart>
-    </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue';
-import Schart from "vue-schart"; // 导入Schart组件
-const options = ref({
-    type: "bar",
-    title: {
-        text: "最近一周各品类销售图",
-    },
-    labels: ["周一", "周二", "周三", "周四", "周五"],
-    datasets: [
-        {
-            label: "家电",
-            data: [234, 278, 270, 190, 230],
-        },
-        {
-            label: "百货",
-            data: [164, 178, 190, 135, 160],
-        },
-        {
-            label: "食品",
-            data: [144, 198, 150, 235, 120],
-        },
-    ],
-})
-</script>
-<style>
-    .wrapper {
-        width: 7rem;
-        height: 5rem;
-    }
-</style>
-```
-
 ## 项目截图
 
-### 登录
-
-![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms3.png)
-
 ### 首页
 
 ![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms1.png)
 
+### 登录
+
+![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms3.png)
+
 ## License
 
 [MIT](https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE)
diff --git a/components.d.ts b/components.d.ts
index ca55e424..fe2b2b7f 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -7,17 +7,24 @@ export {}
 
 declare module '@vue/runtime-core' {
   export interface GlobalComponents {
+    Countup: typeof import('./src/components/countup.vue')['default']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
+    ElCalendar: typeof import('element-plus/es')['ElCalendar']
     ElCard: typeof import('element-plus/es')['ElCard']
+    ElCarousel: typeof import('element-plus/es')['ElCarousel']
+    ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
     ElCascader: typeof import('element-plus/es')['ElCascader']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
     ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
     ElCol: typeof import('element-plus/es')['ElCol']
+    ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
+    ElCountdown: typeof import('element-plus/es')['ElCountdown']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
     ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
     ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
     ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@@ -26,6 +33,7 @@ declare module '@vue/runtime-core' {
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElLink: typeof import('element-plus/es')['ElLink']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
@@ -33,9 +41,17 @@ declare module '@vue/runtime-core' {
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElProgress: typeof import('element-plus/es')['ElProgress']
     ElRadio: typeof import('element-plus/es')['ElRadio']
+    ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
     ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
+    ElRate: typeof import('element-plus/es')['ElRate']
+    ElResult: typeof import('element-plus/es')['ElResult']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElSelect: typeof import('element-plus/es')['ElSelect']
+    ElSlider: typeof import('element-plus/es')['ElSlider']
+    ElSpace: typeof import('element-plus/es')['ElSpace']
+    ElStatistic: typeof import('element-plus/es')['ElStatistic']
+    ElStep: typeof import('element-plus/es')['ElStep']
+    ElSteps: typeof import('element-plus/es')['ElSteps']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
     ElTable: typeof import('element-plus/es')['ElTable']
@@ -43,15 +59,23 @@ declare module '@vue/runtime-core' {
     ElTabPane: typeof import('element-plus/es')['ElTabPane']
     ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTag: typeof import('element-plus/es')['ElTag']
+    ElTimeline: typeof import('element-plus/es')['ElTimeline']
+    ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
     ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
+    ElTour: typeof import('element-plus/es')['ElTour']
+    ElTourStep: typeof import('element-plus/es')['ElTourStep']
+    ElTransfer: typeof import('element-plus/es')['ElTransfer']
     ElUpload: typeof import('element-plus/es')['ElUpload']
+    ElWatermark: typeof import('element-plus/es')['ElWatermark']
     Header: typeof import('./src/components/header.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     Sidebar: typeof import('./src/components/sidebar.vue')['default']
+    TableCustom: typeof import('./src/components/table-custom.vue')['default']
     TableDetail: typeof import('./src/components/table-detail.vue')['default']
     TableEdit: typeof import('./src/components/table-edit.vue')['default']
-    Tags: typeof import('./src/components/tags.vue')['default']
+    TableSearch: typeof import('./src/components/table-search.vue')['default']
+    Tabs: typeof import('./src/components/tabs.vue')['default']
   }
 }
diff --git a/index.html b/index.html
index acbcb53e..e25abe55 100644
--- a/index.html
+++ b/index.html
@@ -6,13 +6,13 @@
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <title>vue-manage-system后台管理系统</title>
-  <link rel="stylesheet" href="https://at.alicdn.com/t/font_830376_qzecyukz0s.css">
+  <link rel="stylesheet" href="//at.alicdn.com/t/c/font_830376_92o68tc95je.css">
 </head>
 
 <body>
   <noscript>
     <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
-      Please enable it to continue.</strong>
+        Please enable it to continue.</strong>
   </noscript>
   <div id="app"></div>
   <script type="module" src="/src/main.ts"></script>
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index eeec21e2..00000000
--- a/package-lock.json
+++ /dev/null
@@ -1,1298 +0,0 @@
-{
-	"name": "vue-manage-system",
-	"version": "5.3.0",
-	"lockfileVersion": 1,
-	"requires": true,
-	"dependencies": {
-		"@antfu/utils": {
-			"version": "0.5.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@antfu/utils/-/utils-0.5.2.tgz",
-			"integrity": "sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==",
-			"dev": true
-		},
-		"@babel/parser": {
-			"version": "7.18.11",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@babel/parser/-/parser-7.18.11.tgz",
-			"integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ=="
-		},
-		"@babel/runtime": {
-			"version": "7.18.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@babel/runtime/-/runtime-7.18.9.tgz",
-			"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
-			"requires": {
-				"regenerator-runtime": "^0.13.4"
-			}
-		},
-		"@babel/runtime-corejs3": {
-			"version": "7.18.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz",
-			"integrity": "sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A==",
-			"requires": {
-				"core-js-pure": "^3.20.2",
-				"regenerator-runtime": "^0.13.4"
-			}
-		},
-		"@ctrl/tinycolor": {
-			"version": "3.4.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
-			"integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
-		},
-		"@element-plus/icons-vue": {
-			"version": "2.0.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@element-plus/icons-vue/-/icons-vue-2.0.9.tgz",
-			"integrity": "sha512-okdrwiVeKBmW41Hkl0eMrXDjzJwhQMuKiBOu17rOszqM+LS/yBYpNQNV5Jvoh06Wc+89fMmb/uhzf8NZuDuUaQ=="
-		},
-		"@esbuild/linux-loong64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz",
-			"integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==",
-			"dev": true,
-			"optional": true
-		},
-		"@floating-ui/core": {
-			"version": "0.7.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@floating-ui/core/-/core-0.7.3.tgz",
-			"integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
-		},
-		"@floating-ui/dom": {
-			"version": "0.5.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@floating-ui/dom/-/dom-0.5.4.tgz",
-			"integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
-			"requires": {
-				"@floating-ui/core": "^0.7.3"
-			}
-		},
-		"@nodelib/fs.scandir": {
-			"version": "2.1.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.stat": "2.0.5",
-				"run-parallel": "^1.1.9"
-			}
-		},
-		"@nodelib/fs.stat": {
-			"version": "2.0.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-			"dev": true
-		},
-		"@nodelib/fs.walk": {
-			"version": "1.2.8",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.scandir": "2.1.5",
-				"fastq": "^1.6.0"
-			}
-		},
-		"@rollup/pluginutils": {
-			"version": "4.2.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
-			"integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
-			"dev": true,
-			"requires": {
-				"estree-walker": "^2.0.1",
-				"picomatch": "^2.2.2"
-			}
-		},
-		"@types/lodash": {
-			"version": "4.14.184",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@types/lodash/-/lodash-4.14.184.tgz",
-			"integrity": "sha512-RoZphVtHbxPZizt4IcILciSWiC6dcn+eZ8oX9IWEYfDMcocdd42f7NPI6fQj+6zI8y4E0L7gu2pcZKLGTRaV9Q=="
-		},
-		"@types/lodash-es": {
-			"version": "4.17.6",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@types/lodash-es/-/lodash-es-4.17.6.tgz",
-			"integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==",
-			"requires": {
-				"@types/lodash": "*"
-			}
-		},
-		"@types/marked": {
-			"version": "4.0.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@types/marked/-/marked-4.0.5.tgz",
-			"integrity": "sha512-jMN2moJ+lSf1VZXQo3VXeMCjoXuciVONig8+U0YNBop5aBvQw4qkolx1Nzn1i0T8L2l9IZ3jju6bS1pPwlaY1w=="
-		},
-		"@types/web-bluetooth": {
-			"version": "0.0.15",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz",
-			"integrity": "sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA=="
-		},
-		"@vitejs/plugin-vue": {
-			"version": "3.0.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vitejs/plugin-vue/-/plugin-vue-3.0.3.tgz",
-			"integrity": "sha512-U4zNBlz9mg+TA+i+5QPc3N5lQvdUXENZLO2h0Wdzp56gI1MWhqJOv+6R+d4kOzoaSSq6TnGPBdZAXKOe4lXy6g==",
-			"dev": true
-		},
-		"@volar/code-gen": {
-			"version": "0.38.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@volar/code-gen/-/code-gen-0.38.9.tgz",
-			"integrity": "sha512-n6LClucfA+37rQeskvh9vDoZV1VvCVNy++MAPKj2dT4FT+Fbmty/SDQqnsEBtdEe6E3OQctFvA/IcKsx3Mns0A==",
-			"dev": true,
-			"requires": {
-				"@volar/source-map": "0.38.9"
-			}
-		},
-		"@volar/source-map": {
-			"version": "0.38.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@volar/source-map/-/source-map-0.38.9.tgz",
-			"integrity": "sha512-ba0UFoHDYry+vwKdgkWJ6xlQT+8TFtZg1zj9tSjj4PykW1JZDuM0xplMotLun4h3YOoYfY9K1huY5gvxmrNLIw==",
-			"dev": true
-		},
-		"@volar/vue-code-gen": {
-			"version": "0.38.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@volar/vue-code-gen/-/vue-code-gen-0.38.9.tgz",
-			"integrity": "sha512-tzj7AoarFBKl7e41MR006ncrEmNPHALuk8aG4WdDIaG387X5//5KhWC5Ff3ZfB2InGSeNT+CVUd74M0gS20rjA==",
-			"dev": true,
-			"requires": {
-				"@volar/code-gen": "0.38.9",
-				"@volar/source-map": "0.38.9",
-				"@vue/compiler-core": "^3.2.37",
-				"@vue/compiler-dom": "^3.2.37",
-				"@vue/shared": "^3.2.37"
-			}
-		},
-		"@volar/vue-typescript": {
-			"version": "0.38.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz",
-			"integrity": "sha512-iJMQGU91ADi98u8V1vXd2UBmELDAaeSP0ZJaFjwosClQdKlJQYc6MlxxKfXBZisHqfbhdtrGRyaryulnYtliZw==",
-			"dev": true,
-			"requires": {
-				"@volar/code-gen": "0.38.9",
-				"@volar/source-map": "0.38.9",
-				"@volar/vue-code-gen": "0.38.9",
-				"@vue/compiler-sfc": "^3.2.37",
-				"@vue/reactivity": "^3.2.37"
-			}
-		},
-		"@vue/compiler-core": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/compiler-core/-/compiler-core-3.2.37.tgz",
-			"integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==",
-			"requires": {
-				"@babel/parser": "^7.16.4",
-				"@vue/shared": "3.2.37",
-				"estree-walker": "^2.0.2",
-				"source-map": "^0.6.1"
-			}
-		},
-		"@vue/compiler-dom": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz",
-			"integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==",
-			"requires": {
-				"@vue/compiler-core": "3.2.37",
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"@vue/compiler-sfc": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz",
-			"integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==",
-			"requires": {
-				"@babel/parser": "^7.16.4",
-				"@vue/compiler-core": "3.2.37",
-				"@vue/compiler-dom": "3.2.37",
-				"@vue/compiler-ssr": "3.2.37",
-				"@vue/reactivity-transform": "3.2.37",
-				"@vue/shared": "3.2.37",
-				"estree-walker": "^2.0.2",
-				"magic-string": "^0.25.7",
-				"postcss": "^8.1.10",
-				"source-map": "^0.6.1"
-			},
-			"dependencies": {
-				"magic-string": {
-					"version": "0.25.9",
-					"resolved": "https://repo.huaweicloud.com/repository/npm/magic-string/-/magic-string-0.25.9.tgz",
-					"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
-					"requires": {
-						"sourcemap-codec": "^1.4.8"
-					}
-				}
-			}
-		},
-		"@vue/compiler-ssr": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz",
-			"integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==",
-			"requires": {
-				"@vue/compiler-dom": "3.2.37",
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"@vue/devtools-api": {
-			"version": "6.2.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/devtools-api/-/devtools-api-6.2.1.tgz",
-			"integrity": "sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ=="
-		},
-		"@vue/reactivity": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/reactivity/-/reactivity-3.2.37.tgz",
-			"integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==",
-			"requires": {
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"@vue/reactivity-transform": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz",
-			"integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==",
-			"requires": {
-				"@babel/parser": "^7.16.4",
-				"@vue/compiler-core": "3.2.37",
-				"@vue/shared": "3.2.37",
-				"estree-walker": "^2.0.2",
-				"magic-string": "^0.25.7"
-			},
-			"dependencies": {
-				"magic-string": {
-					"version": "0.25.9",
-					"resolved": "https://repo.huaweicloud.com/repository/npm/magic-string/-/magic-string-0.25.9.tgz",
-					"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
-					"requires": {
-						"sourcemap-codec": "^1.4.8"
-					}
-				}
-			}
-		},
-		"@vue/runtime-core": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/runtime-core/-/runtime-core-3.2.37.tgz",
-			"integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==",
-			"requires": {
-				"@vue/reactivity": "3.2.37",
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"@vue/runtime-dom": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz",
-			"integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==",
-			"requires": {
-				"@vue/runtime-core": "3.2.37",
-				"@vue/shared": "3.2.37",
-				"csstype": "^2.6.8"
-			}
-		},
-		"@vue/server-renderer": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/server-renderer/-/server-renderer-3.2.37.tgz",
-			"integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==",
-			"requires": {
-				"@vue/compiler-ssr": "3.2.37",
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"@vue/shared": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vue/shared/-/shared-3.2.37.tgz",
-			"integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw=="
-		},
-		"@vueuse/core": {
-			"version": "9.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/core/-/core-9.1.0.tgz",
-			"integrity": "sha512-BIroqvXEqt826aE9r3K5cox1zobuPuAzdYJ36kouC2TVhlXvFKIILgFVWrpp9HZPwB3aLzasmG3K87q7TSyXZg==",
-			"requires": {
-				"@types/web-bluetooth": "^0.0.15",
-				"@vueuse/metadata": "9.1.0",
-				"@vueuse/shared": "9.1.0",
-				"vue-demi": "*"
-			}
-		},
-		"@vueuse/metadata": {
-			"version": "9.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/metadata/-/metadata-9.1.0.tgz",
-			"integrity": "sha512-8OEhlog1iaAGTD3LICZ8oBGQdYeMwByvXetOtAOZCJOzyCRSwqwdggTsmVZZ1rkgYIEqgUBk942AsAPwM21s6A=="
-		},
-		"@vueuse/shared": {
-			"version": "9.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/shared/-/shared-9.1.0.tgz",
-			"integrity": "sha512-pB/3njQu4tfJJ78ajELNda0yMG6lKfpToQW7Soe09CprF1k3QuyoNi1tBNvo75wBDJWD+LOnr+c4B5HZ39jY/Q==",
-			"requires": {
-				"vue-demi": "*"
-			}
-		},
-		"acorn": {
-			"version": "8.8.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/acorn/-/acorn-8.8.0.tgz",
-			"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==",
-			"dev": true
-		},
-		"adler-32": {
-			"version": "1.3.1",
-			"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
-			"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A=="
-		},
-		"anymatch": {
-			"version": "3.1.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/anymatch/-/anymatch-3.1.2.tgz",
-			"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-			"dev": true,
-			"requires": {
-				"normalize-path": "^3.0.0",
-				"picomatch": "^2.0.4"
-			}
-		},
-		"async-validator": {
-			"version": "4.2.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/async-validator/-/async-validator-4.2.5.tgz",
-			"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
-		},
-		"asynckit": {
-			"version": "0.4.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/asynckit/-/asynckit-0.4.0.tgz",
-			"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
-		},
-		"axios": {
-			"version": "0.27.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/axios/-/axios-0.27.2.tgz",
-			"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
-			"requires": {
-				"follow-redirects": "^1.14.9",
-				"form-data": "^4.0.0"
-			}
-		},
-		"balanced-match": {
-			"version": "1.0.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/balanced-match/-/balanced-match-1.0.2.tgz",
-			"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-			"dev": true
-		},
-		"binary-extensions": {
-			"version": "2.2.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/binary-extensions/-/binary-extensions-2.2.0.tgz",
-			"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-			"dev": true
-		},
-		"brace-expansion": {
-			"version": "2.0.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/brace-expansion/-/brace-expansion-2.0.1.tgz",
-			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-			"dev": true,
-			"requires": {
-				"balanced-match": "^1.0.0"
-			}
-		},
-		"braces": {
-			"version": "3.0.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/braces/-/braces-3.0.2.tgz",
-			"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-			"dev": true,
-			"requires": {
-				"fill-range": "^7.0.1"
-			}
-		},
-		"cfb": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
-			"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
-			"requires": {
-				"adler-32": "~1.3.0",
-				"crc-32": "~1.2.0"
-			}
-		},
-		"chokidar": {
-			"version": "3.5.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/chokidar/-/chokidar-3.5.3.tgz",
-			"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-			"dev": true,
-			"requires": {
-				"anymatch": "~3.1.2",
-				"braces": "~3.0.2",
-				"fsevents": "~2.3.2",
-				"glob-parent": "~5.1.2",
-				"is-binary-path": "~2.1.0",
-				"is-glob": "~4.0.1",
-				"normalize-path": "~3.0.0",
-				"readdirp": "~3.6.0"
-			}
-		},
-		"codepage": {
-			"version": "1.15.0",
-			"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
-			"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA=="
-		},
-		"combined-stream": {
-			"version": "1.0.8",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/combined-stream/-/combined-stream-1.0.8.tgz",
-			"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-			"requires": {
-				"delayed-stream": "~1.0.0"
-			}
-		},
-		"core-js-pure": {
-			"version": "3.24.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/core-js-pure/-/core-js-pure-3.24.1.tgz",
-			"integrity": "sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg=="
-		},
-		"crc-32": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
-			"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
-		},
-		"cropperjs": {
-			"version": "1.5.12",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/cropperjs/-/cropperjs-1.5.12.tgz",
-			"integrity": "sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw=="
-		},
-		"csstype": {
-			"version": "2.6.20",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/csstype/-/csstype-2.6.20.tgz",
-			"integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA=="
-		},
-		"dayjs": {
-			"version": "1.11.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/dayjs/-/dayjs-1.11.5.tgz",
-			"integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA=="
-		},
-		"debug": {
-			"version": "4.3.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/debug/-/debug-4.3.4.tgz",
-			"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-			"dev": true,
-			"requires": {
-				"ms": "2.1.2"
-			}
-		},
-		"delayed-stream": {
-			"version": "1.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/delayed-stream/-/delayed-stream-1.0.0.tgz",
-			"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
-		},
-		"element-plus": {
-			"version": "2.2.14",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/element-plus/-/element-plus-2.2.14.tgz",
-			"integrity": "sha512-V5Pis0OHhePg1RgVogZrcefaVl8vjVn4Pn9Qsh/t2CbFgjg9kKOYFqf/tuP3ObSXGm3X89hpe0W+nLVAsaFnpw==",
-			"requires": {
-				"@ctrl/tinycolor": "^3.4.1",
-				"@element-plus/icons-vue": "^2.0.6",
-				"@floating-ui/dom": "^0.5.4",
-				"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
-				"@types/lodash": "^4.14.182",
-				"@types/lodash-es": "^4.17.6",
-				"@vueuse/core": "^9.1.0",
-				"async-validator": "^4.2.5",
-				"dayjs": "^1.11.3",
-				"escape-html": "^1.0.3",
-				"lodash": "^4.17.21",
-				"lodash-es": "^4.17.21",
-				"lodash-unified": "^1.0.2",
-				"memoize-one": "^6.0.0",
-				"normalize-wheel-es": "^1.2.0"
-			},
-			"dependencies": {
-				"@popperjs/core": {
-					"version": "npm:@sxzz/popperjs-es@2.11.7",
-					"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
-					"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
-				}
-			}
-		},
-		"esbuild": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild/-/esbuild-0.14.54.tgz",
-			"integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==",
-			"dev": true,
-			"requires": {
-				"@esbuild/linux-loong64": "0.14.54",
-				"esbuild-android-64": "0.14.54",
-				"esbuild-android-arm64": "0.14.54",
-				"esbuild-darwin-64": "0.14.54",
-				"esbuild-darwin-arm64": "0.14.54",
-				"esbuild-freebsd-64": "0.14.54",
-				"esbuild-freebsd-arm64": "0.14.54",
-				"esbuild-linux-32": "0.14.54",
-				"esbuild-linux-64": "0.14.54",
-				"esbuild-linux-arm": "0.14.54",
-				"esbuild-linux-arm64": "0.14.54",
-				"esbuild-linux-mips64le": "0.14.54",
-				"esbuild-linux-ppc64le": "0.14.54",
-				"esbuild-linux-riscv64": "0.14.54",
-				"esbuild-linux-s390x": "0.14.54",
-				"esbuild-netbsd-64": "0.14.54",
-				"esbuild-openbsd-64": "0.14.54",
-				"esbuild-sunos-64": "0.14.54",
-				"esbuild-windows-32": "0.14.54",
-				"esbuild-windows-64": "0.14.54",
-				"esbuild-windows-arm64": "0.14.54"
-			}
-		},
-		"esbuild-android-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz",
-			"integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-android-arm64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz",
-			"integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-darwin-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz",
-			"integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-darwin-arm64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz",
-			"integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-freebsd-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz",
-			"integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-freebsd-arm64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz",
-			"integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-32": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz",
-			"integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz",
-			"integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-arm": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz",
-			"integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-arm64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz",
-			"integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-mips64le": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz",
-			"integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-ppc64le": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz",
-			"integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-riscv64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz",
-			"integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-linux-s390x": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz",
-			"integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-netbsd-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz",
-			"integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-openbsd-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz",
-			"integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-sunos-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz",
-			"integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-windows-32": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz",
-			"integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-windows-64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz",
-			"integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==",
-			"dev": true,
-			"optional": true
-		},
-		"esbuild-windows-arm64": {
-			"version": "0.14.54",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz",
-			"integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==",
-			"dev": true,
-			"optional": true
-		},
-		"escape-html": {
-			"version": "1.0.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/escape-html/-/escape-html-1.0.3.tgz",
-			"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
-		},
-		"escape-string-regexp": {
-			"version": "5.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-			"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-			"dev": true
-		},
-		"estree-walker": {
-			"version": "2.0.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/estree-walker/-/estree-walker-2.0.2.tgz",
-			"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
-		},
-		"fast-glob": {
-			"version": "3.2.11",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/fast-glob/-/fast-glob-3.2.11.tgz",
-			"integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.stat": "^2.0.2",
-				"@nodelib/fs.walk": "^1.2.3",
-				"glob-parent": "^5.1.2",
-				"merge2": "^1.3.0",
-				"micromatch": "^4.0.4"
-			}
-		},
-		"fastq": {
-			"version": "1.13.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/fastq/-/fastq-1.13.0.tgz",
-			"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
-			"dev": true,
-			"requires": {
-				"reusify": "^1.0.4"
-			}
-		},
-		"fill-range": {
-			"version": "7.0.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/fill-range/-/fill-range-7.0.1.tgz",
-			"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-			"dev": true,
-			"requires": {
-				"to-regex-range": "^5.0.1"
-			}
-		},
-		"follow-redirects": {
-			"version": "1.15.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/follow-redirects/-/follow-redirects-1.15.1.tgz",
-			"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
-		},
-		"form-data": {
-			"version": "4.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/form-data/-/form-data-4.0.0.tgz",
-			"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
-			"requires": {
-				"asynckit": "^0.4.0",
-				"combined-stream": "^1.0.8",
-				"mime-types": "^2.1.12"
-			}
-		},
-		"frac": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
-			"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
-		},
-		"fsevents": {
-			"version": "2.3.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/fsevents/-/fsevents-2.3.2.tgz",
-			"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-			"dev": true,
-			"optional": true
-		},
-		"function-bind": {
-			"version": "1.1.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/function-bind/-/function-bind-1.1.1.tgz",
-			"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-			"dev": true
-		},
-		"glob-parent": {
-			"version": "5.1.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/glob-parent/-/glob-parent-5.1.2.tgz",
-			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-			"dev": true,
-			"requires": {
-				"is-glob": "^4.0.1"
-			}
-		},
-		"has": {
-			"version": "1.0.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/has/-/has-1.0.3.tgz",
-			"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-			"dev": true,
-			"requires": {
-				"function-bind": "^1.1.1"
-			}
-		},
-		"is-binary-path": {
-			"version": "2.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/is-binary-path/-/is-binary-path-2.1.0.tgz",
-			"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-			"dev": true,
-			"requires": {
-				"binary-extensions": "^2.0.0"
-			}
-		},
-		"is-core-module": {
-			"version": "2.10.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/is-core-module/-/is-core-module-2.10.0.tgz",
-			"integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==",
-			"dev": true,
-			"requires": {
-				"has": "^1.0.3"
-			}
-		},
-		"is-extglob": {
-			"version": "2.1.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/is-extglob/-/is-extglob-2.1.1.tgz",
-			"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-			"dev": true
-		},
-		"is-glob": {
-			"version": "4.0.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/is-glob/-/is-glob-4.0.3.tgz",
-			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-			"dev": true,
-			"requires": {
-				"is-extglob": "^2.1.1"
-			}
-		},
-		"is-number": {
-			"version": "7.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/is-number/-/is-number-7.0.0.tgz",
-			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-			"dev": true
-		},
-		"jsonc-parser": {
-			"version": "3.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
-			"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==",
-			"dev": true
-		},
-		"local-pkg": {
-			"version": "0.4.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/local-pkg/-/local-pkg-0.4.2.tgz",
-			"integrity": "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==",
-			"dev": true
-		},
-		"lodash": {
-			"version": "4.17.21",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/lodash/-/lodash-4.17.21.tgz",
-			"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
-		},
-		"lodash-es": {
-			"version": "4.17.21",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/lodash-es/-/lodash-es-4.17.21.tgz",
-			"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
-		},
-		"lodash-unified": {
-			"version": "1.0.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/lodash-unified/-/lodash-unified-1.0.2.tgz",
-			"integrity": "sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g=="
-		},
-		"magic-string": {
-			"version": "0.26.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/magic-string/-/magic-string-0.26.2.tgz",
-			"integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==",
-			"dev": true,
-			"requires": {
-				"sourcemap-codec": "^1.4.8"
-			}
-		},
-		"md-editor-v3": {
-			"version": "2.2.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/md-editor-v3/-/md-editor-v3-2.2.1.tgz",
-			"integrity": "sha512-nOd8mlEhvC99l9Y8pDMwEi6EdCAeBp88Ffl24We+2uz3/Iympctm92L1qyNicONJRhtZJacQ4oWTQGMYKGAxVg==",
-			"requires": {
-				"@types/marked": "^4.0.3"
-			}
-		},
-		"memoize-one": {
-			"version": "6.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/memoize-one/-/memoize-one-6.0.0.tgz",
-			"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
-		},
-		"merge2": {
-			"version": "1.4.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/merge2/-/merge2-1.4.1.tgz",
-			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-			"dev": true
-		},
-		"micromatch": {
-			"version": "4.0.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/micromatch/-/micromatch-4.0.5.tgz",
-			"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
-			"dev": true,
-			"requires": {
-				"braces": "^3.0.2",
-				"picomatch": "^2.3.1"
-			}
-		},
-		"mime-db": {
-			"version": "1.52.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/mime-db/-/mime-db-1.52.0.tgz",
-			"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
-		},
-		"mime-types": {
-			"version": "2.1.35",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/mime-types/-/mime-types-2.1.35.tgz",
-			"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-			"requires": {
-				"mime-db": "1.52.0"
-			}
-		},
-		"minimatch": {
-			"version": "5.1.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/minimatch/-/minimatch-5.1.0.tgz",
-			"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
-			"dev": true,
-			"requires": {
-				"brace-expansion": "^2.0.1"
-			}
-		},
-		"mlly": {
-			"version": "0.5.13",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/mlly/-/mlly-0.5.13.tgz",
-			"integrity": "sha512-0SK2fqoan+PMjADs4I2egAtrtNtpjqRez6PDTCeAdGjUQNJCvO5o9v2NEq52WA1jFmMU97qBr/JgdvCquehDbA==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.8.0",
-				"pathe": "^0.3.4",
-				"pkg-types": "^0.3.3",
-				"ufo": "^0.8.5"
-			}
-		},
-		"ms": {
-			"version": "2.1.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/ms/-/ms-2.1.2.tgz",
-			"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-			"dev": true
-		},
-		"nanoid": {
-			"version": "3.3.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/nanoid/-/nanoid-3.3.4.tgz",
-			"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
-		},
-		"normalize-path": {
-			"version": "3.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/normalize-path/-/normalize-path-3.0.0.tgz",
-			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-			"dev": true
-		},
-		"normalize-wheel-es": {
-			"version": "1.2.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
-			"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
-		},
-		"path-parse": {
-			"version": "1.0.7",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/path-parse/-/path-parse-1.0.7.tgz",
-			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-			"dev": true
-		},
-		"pathe": {
-			"version": "0.3.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/pathe/-/pathe-0.3.5.tgz",
-			"integrity": "sha512-grU/QeYP0ChuE5kjU2/k8VtAeODzbernHlue0gTa27+ayGIu3wqYBIPGfP9r5xSqgCgDd4nWrjKXEfxMillByg==",
-			"dev": true
-		},
-		"picocolors": {
-			"version": "1.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/picocolors/-/picocolors-1.0.0.tgz",
-			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
-		},
-		"picomatch": {
-			"version": "2.3.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/picomatch/-/picomatch-2.3.1.tgz",
-			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-			"dev": true
-		},
-		"pinia": {
-			"version": "2.0.20",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/pinia/-/pinia-2.0.20.tgz",
-			"integrity": "sha512-fdHHumXW/0U5HhxmY1emo3I4z85p8NJPdbtFQSlmJXFe3ktuF0pYNVgVtk2q+j2zCtTufY763xzaEMx0t6T59g==",
-			"requires": {
-				"@vue/devtools-api": "^6.2.1",
-				"vue-demi": "*"
-			}
-		},
-		"pkg-types": {
-			"version": "0.3.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/pkg-types/-/pkg-types-0.3.4.tgz",
-			"integrity": "sha512-s214f/xkRpwlwVBToWq9Mu0XlU3HhZMYCnr2var8+jjbavBHh/VCh4pBLsJW29rJ//B1jb4HlpMIaNIMH+W2/w==",
-			"dev": true,
-			"requires": {
-				"jsonc-parser": "^3.1.0",
-				"mlly": "^0.5.13",
-				"pathe": "^0.3.5"
-			}
-		},
-		"postcss": {
-			"version": "8.4.16",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/postcss/-/postcss-8.4.16.tgz",
-			"integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==",
-			"requires": {
-				"nanoid": "^3.3.4",
-				"picocolors": "^1.0.0",
-				"source-map-js": "^1.0.2"
-			}
-		},
-		"queue-microtask": {
-			"version": "1.2.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/queue-microtask/-/queue-microtask-1.2.3.tgz",
-			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-			"dev": true
-		},
-		"readdirp": {
-			"version": "3.6.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/readdirp/-/readdirp-3.6.0.tgz",
-			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-			"dev": true,
-			"requires": {
-				"picomatch": "^2.2.1"
-			}
-		},
-		"regenerator-runtime": {
-			"version": "0.13.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
-			"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
-		},
-		"resolve": {
-			"version": "1.22.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/resolve/-/resolve-1.22.1.tgz",
-			"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
-			"dev": true,
-			"requires": {
-				"is-core-module": "^2.9.0",
-				"path-parse": "^1.0.7",
-				"supports-preserve-symlinks-flag": "^1.0.0"
-			}
-		},
-		"reusify": {
-			"version": "1.0.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/reusify/-/reusify-1.0.4.tgz",
-			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-			"dev": true
-		},
-		"rollup": {
-			"version": "2.77.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/rollup/-/rollup-2.77.3.tgz",
-			"integrity": "sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==",
-			"dev": true,
-			"requires": {
-				"fsevents": "~2.3.2"
-			}
-		},
-		"run-parallel": {
-			"version": "1.2.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/run-parallel/-/run-parallel-1.2.0.tgz",
-			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-			"dev": true,
-			"requires": {
-				"queue-microtask": "^1.2.2"
-			}
-		},
-		"schart.js": {
-			"version": "3.0.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/schart.js/-/schart.js-3.0.4.tgz",
-			"integrity": "sha512-uylb2u9rrHX1jyAuSAJUQON8XTfyDKI9kWj1J3fUlCQCkLVZ4HG4+IiV8qm//Z71dqvLI78QZ/fCBw0reB22Zw=="
-		},
-		"scule": {
-			"version": "0.3.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/scule/-/scule-0.3.2.tgz",
-			"integrity": "sha512-zIvPdjOH8fv8CgrPT5eqtxHQXmPNnV/vHJYffZhE43KZkvULvpCTvOt1HPlFaCZx287INL9qaqrZg34e8NgI4g==",
-			"dev": true
-		},
-		"source-map": {
-			"version": "0.6.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/source-map/-/source-map-0.6.1.tgz",
-			"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-		},
-		"source-map-js": {
-			"version": "1.0.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/source-map-js/-/source-map-js-1.0.2.tgz",
-			"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
-		},
-		"sourcemap-codec": {
-			"version": "1.4.8",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
-			"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
-		},
-		"ssf": {
-			"version": "0.11.2",
-			"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
-			"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
-			"requires": {
-				"frac": "~1.1.2"
-			}
-		},
-		"strip-literal": {
-			"version": "0.4.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/strip-literal/-/strip-literal-0.4.0.tgz",
-			"integrity": "sha512-ql/sBDoJOybTKSIOWrrh8kgUEMjXMwRAkZTD0EwiwxQH/6tTPkZvMIEjp0CRlpi6V5FMiJyvxeRkEi1KrGISoA==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.7.1"
-			}
-		},
-		"supports-preserve-symlinks-flag": {
-			"version": "1.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-			"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-			"dev": true
-		},
-		"to-regex-range": {
-			"version": "5.0.1",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/to-regex-range/-/to-regex-range-5.0.1.tgz",
-			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-			"dev": true,
-			"requires": {
-				"is-number": "^7.0.0"
-			}
-		},
-		"tslib": {
-			"version": "2.4.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/tslib/-/tslib-2.4.0.tgz",
-			"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
-		},
-		"typescript": {
-			"version": "4.7.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/typescript/-/typescript-4.7.4.tgz",
-			"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
-			"dev": true
-		},
-		"ufo": {
-			"version": "0.8.5",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/ufo/-/ufo-0.8.5.tgz",
-			"integrity": "sha512-e4+UtA5IRO+ha6hYklwj6r7BjiGMxS0O+UaSg9HbaTefg4kMkzj4tXzEBajRR+wkxf+golgAWKzLbytCUDMJAA==",
-			"dev": true
-		},
-		"unimport": {
-			"version": "0.6.7",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/unimport/-/unimport-0.6.7.tgz",
-			"integrity": "sha512-EMoVqDjswHkU+nD098QYHXH7Mkw7KwGDQAyeRF2lgairJnuO+wpkhIcmCqrD1OPJmsjkTbJ2tW6Ap8St0PuWZA==",
-			"dev": true,
-			"requires": {
-				"@rollup/pluginutils": "^4.2.1",
-				"escape-string-regexp": "^5.0.0",
-				"fast-glob": "^3.2.11",
-				"local-pkg": "^0.4.2",
-				"magic-string": "^0.26.2",
-				"mlly": "^0.5.7",
-				"pathe": "^0.3.3",
-				"scule": "^0.3.2",
-				"strip-literal": "^0.4.0",
-				"unplugin": "^0.9.0"
-			}
-		},
-		"unplugin": {
-			"version": "0.9.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/unplugin/-/unplugin-0.9.3.tgz",
-			"integrity": "sha512-GWXxizZG+tobNs8fuGTCeilerkkfZTZax2iivuE4pxLaF9wTnPJHOq8tbLKDb5ohVb+2BXNjrU9xx59yWTUnuw==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.8.0",
-				"chokidar": "^3.5.3",
-				"webpack-sources": "^3.2.3",
-				"webpack-virtual-modules": "^0.4.4"
-			}
-		},
-		"unplugin-auto-import": {
-			"version": "0.11.2",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/unplugin-auto-import/-/unplugin-auto-import-0.11.2.tgz",
-			"integrity": "sha512-1+VwBfn9dtiYv9SQLKP1AvZolUbK9xTVeAT+iOcEk4EHSFUlmIqBVLEKI76cifSQTLOJ3rZyPrEgptf3SZNLlQ==",
-			"dev": true,
-			"requires": {
-				"@antfu/utils": "^0.5.2",
-				"@rollup/pluginutils": "^4.2.1",
-				"local-pkg": "^0.4.2",
-				"magic-string": "^0.26.2",
-				"unimport": "^0.6.7",
-				"unplugin": "^0.9.3"
-			}
-		},
-		"unplugin-vue-components": {
-			"version": "0.22.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/unplugin-vue-components/-/unplugin-vue-components-0.22.4.tgz",
-			"integrity": "sha512-2rRZcM9OnJGXnYxQNfaceEYuPeVACcWySIjy8WBwIiN3onr980TmA3XE5pRJFt8zoQrUA+c46oyIq96noLqrEQ==",
-			"dev": true,
-			"requires": {
-				"@antfu/utils": "^0.5.2",
-				"@rollup/pluginutils": "^4.2.1",
-				"chokidar": "^3.5.3",
-				"debug": "^4.3.4",
-				"fast-glob": "^3.2.11",
-				"local-pkg": "^0.4.2",
-				"magic-string": "^0.26.2",
-				"minimatch": "^5.1.0",
-				"resolve": "^1.22.1",
-				"unplugin": "^0.9.0"
-			}
-		},
-		"vite": {
-			"version": "3.0.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vite/-/vite-3.0.9.tgz",
-			"integrity": "sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==",
-			"dev": true,
-			"requires": {
-				"esbuild": "^0.14.47",
-				"fsevents": "~2.3.2",
-				"postcss": "^8.4.16",
-				"resolve": "^1.22.1",
-				"rollup": ">=2.75.6 <2.77.0 || ~2.77.0"
-			}
-		},
-		"vite-plugin-vue-setup-extend": {
-			"version": "0.4.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz",
-			"integrity": "sha512-WMbjPCui75fboFoUTHhdbXzu4Y/bJMv5N9QT9a7do3wNMNHHqrk+Tn2jrSJU0LS5fGl/EG+FEDBYVUeWIkDqXQ==",
-			"dev": true,
-			"requires": {
-				"@vue/compiler-sfc": "^3.2.29",
-				"magic-string": "^0.25.7"
-			},
-			"dependencies": {
-				"magic-string": {
-					"version": "0.25.9",
-					"resolved": "https://repo.huaweicloud.com/repository/npm/magic-string/-/magic-string-0.25.9.tgz",
-					"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
-					"dev": true,
-					"requires": {
-						"sourcemap-codec": "^1.4.8"
-					}
-				}
-			}
-		},
-		"vue": {
-			"version": "3.2.37",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue/-/vue-3.2.37.tgz",
-			"integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==",
-			"requires": {
-				"@vue/compiler-dom": "3.2.37",
-				"@vue/compiler-sfc": "3.2.37",
-				"@vue/runtime-dom": "3.2.37",
-				"@vue/server-renderer": "3.2.37",
-				"@vue/shared": "3.2.37"
-			}
-		},
-		"vue-cropperjs": {
-			"version": "5.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz",
-			"integrity": "sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==",
-			"requires": {
-				"cropperjs": "^1.5.6"
-			}
-		},
-		"vue-demi": {
-			"version": "0.13.8",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue-demi/-/vue-demi-0.13.8.tgz",
-			"integrity": "sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg=="
-		},
-		"vue-router": {
-			"version": "4.1.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue-router/-/vue-router-4.1.3.tgz",
-			"integrity": "sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==",
-			"requires": {
-				"@vue/devtools-api": "^6.1.4"
-			}
-		},
-		"vue-schart": {
-			"version": "2.0.0",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue-schart/-/vue-schart-2.0.0.tgz",
-			"integrity": "sha512-qAu3e5wfMcq26wK1xeHExEWfGpnjfoN1R/9QXblNi+AsU/p52X7tTwhi+Fw7H/otfEufhEY2X7z7emaoF4QO+g==",
-			"requires": {
-				"schart.js": "^3.0.0"
-			}
-		},
-		"vue-tsc": {
-			"version": "0.38.9",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/vue-tsc/-/vue-tsc-0.38.9.tgz",
-			"integrity": "sha512-Yoy5phgvGqyF98Fb4mYqboR4Q149jrdcGv5kSmufXJUq++RZJ2iMVG0g6zl+v3t4ORVWkQmRpsV4x2szufZ0LQ==",
-			"dev": true,
-			"requires": {
-				"@volar/vue-typescript": "0.38.9"
-			}
-		},
-		"wangeditor": {
-			"version": "4.7.15",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/wangeditor/-/wangeditor-4.7.15.tgz",
-			"integrity": "sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==",
-			"requires": {
-				"@babel/runtime": "^7.11.2",
-				"@babel/runtime-corejs3": "^7.11.2",
-				"tslib": "^2.1.0"
-			}
-		},
-		"webpack-sources": {
-			"version": "3.2.3",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/webpack-sources/-/webpack-sources-3.2.3.tgz",
-			"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
-			"dev": true
-		},
-		"webpack-virtual-modules": {
-			"version": "0.4.4",
-			"resolved": "https://repo.huaweicloud.com/repository/npm/webpack-virtual-modules/-/webpack-virtual-modules-0.4.4.tgz",
-			"integrity": "sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==",
-			"dev": true
-		},
-		"wmf": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
-			"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
-		},
-		"word": {
-			"version": "0.3.0",
-			"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
-			"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA=="
-		},
-		"xlsx": {
-			"version": "0.18.5",
-			"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
-			"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
-			"requires": {
-				"adler-32": "~1.3.0",
-				"cfb": "~1.2.1",
-				"codepage": "~1.15.0",
-				"crc-32": "~1.2.1",
-				"ssf": "~0.11.2",
-				"wmf": "~1.0.1",
-				"word": "~0.3.0"
-			}
-		}
-	}
-}
diff --git a/package.json b/package.json
index 06d26155..3423e5a6 100644
--- a/package.json
+++ b/package.json
@@ -1,40 +1,44 @@
-{
-	"name": "vue-manage-system",
-	"version": "5.3.5",
-	"private": true,
-	"scripts": {
-		"dev": "vite",
-		"build": "vue-tsc --noEmit && vite build",
-		"serve": "vite preview"
-	},
-	"dependencies": {
-		"@element-plus/icons-vue": "*",
-		"@wangeditor/editor": "^5.1.23",
-		"@wangeditor/editor-for-vue": "^5.1.12",
-		"axios": "^1.6.3",
-		"element-plus": "^2.4.4",
-		"md-editor-v3": "^2.11.2",
-		"nprogress": "^0.2.0",
-		"pinia": "^2.1.7",
-		"vue": "^3.3.0",
-		"vue-cropperjs": "^5.0.0",
-		"vue-router": "^4.2.5",
-		"vue-schart": "^2.0.0",
-		"xlsx": "^0.18.5"
-	},
-	"devDependencies": {
-		"@vitejs/plugin-vue": "^3.0.0",
-		"@vue/compiler-sfc": "^3.1.2",
-		"typescript": "^4.6.4",
-		"unplugin-auto-import": "^0.11.2",
-		"unplugin-vue-components": "^0.22.4",
-		"vite": "^3.0.0",
-		"vite-plugin-vue-setup-extend": "^0.4.0",
-		"vue-tsc": "^0.38.4"
-	},
-	"browserslist": [
-		"> 1%",
-		"last 2 versions",
-		"not dead"
-	]
-}
+{
+	"name": "vue-manage-system",
+	"version": "5.5.0",
+	"private": true,
+	"scripts": {
+		"dev": "vite",
+		"build": "vue-tsc --noEmit && vite build",
+		"serve": "vite preview"
+	},
+	"dependencies": {
+		"@element-plus/icons-vue": "*",
+		"@wangeditor/editor": "^5.1.23",
+		"@wangeditor/editor-for-vue": "^5.1.12",
+		"axios": "^1.6.3",
+		"countup.js": "^2.8.0",
+		"echarts": "^5.5.0",
+		"echarts-wordcloud": "^2.1.0",
+		"element-plus": "^2.6.3",
+		"md-editor-v3": "^2.11.2",
+		"nprogress": "^0.2.0",
+		"pinia": "^2.1.7",
+		"vue": "^3.4.5",
+		"vue-cropper": "1.1.1",
+		"vue-echarts": "^6.6.9",
+		"vue-router": "^4.2.5",
+		"vue-schart": "^2.0.0",
+		"xlsx": "^0.18.5"
+	},
+	"devDependencies": {
+		"@vitejs/plugin-vue": "^3.0.0",
+		"@vue/compiler-sfc": "^3.1.2",
+		"typescript": "^4.6.4",
+		"unplugin-auto-import": "^0.11.2",
+		"unplugin-vue-components": "^0.22.4",
+		"vite": "^3.0.0",
+		"vite-plugin-vue-setup-extend": "^0.4.0",
+		"vue-tsc": "^0.38.4"
+	},
+	"browserslist": [
+		"> 1%",
+		"last 2 versions",
+		"not dead"
+	]
+}
diff --git a/public/mock/role.json b/public/mock/role.json
new file mode 100644
index 00000000..3ee9f897
--- /dev/null
+++ b/public/mock/role.json
@@ -0,0 +1,46 @@
+{
+    "list": [
+        {
+            "id": 1,
+            "name": "管理员",
+            "key": "admin",
+            "status": true,
+            "permiss": [
+                "0",
+                "1",
+                "11",
+                "12",
+                "13",
+                "2",
+                "21",
+                "22",
+                "23",
+                "24",
+                "3",
+                "31",
+                "32",
+                "33",
+                "331",
+                "332",
+                "4",
+                "41",
+                "42",
+                "5"
+            ]
+        },
+        {
+            "id": 2,
+            "name": "普通用户",
+            "key": "user",
+            "status": true,
+            "permiss": [
+                "0",
+                "1",
+                "11",
+                "12",
+                "13"
+            ]
+        }
+    ],
+    "pageTotal": 2
+}
\ No newline at end of file
diff --git a/public/table.json b/public/mock/table.json
similarity index 85%
rename from public/table.json
rename to public/mock/table.json
index ddd2e322..abbbace5 100644
--- a/public/table.json
+++ b/public/mock/table.json
@@ -1,40 +1,41 @@
-{
-    "list": [{
-            "id": 1,
-            "name": "张三",
-            "money": 123,
-            "address": "广东省东莞市长安镇",
-            "state": "成功",
-            "date": "2019-11-1",
-            "thumb": "https://lin-xin.gitee.io/images/post/wms.png"
-        },
-        {
-            "id": 2,
-            "name": "李四",
-            "money": 456,
-            "address": "广东省广州市白云区",
-            "state": "成功",
-            "date": "2019-10-11",
-            "thumb": "https://lin-xin.gitee.io/images/post/node3.png"
-        },
-        {
-            "id": 3,
-            "name": "王五",
-            "money": 789,
-            "address": "湖南省长沙市",
-            "state": "失败",
-            "date": "2019-11-11",
-            "thumb": "https://lin-xin.gitee.io/images/post/parcel.png"
-        },
-        {
-            "id": 4,
-            "name": "赵六",
-            "money": 1011,
-            "address": "福建省厦门市鼓浪屿",
-            "state": "成功",
-            "date": "2019-10-20",
-            "thumb": "https://lin-xin.gitee.io/images/post/notice.png"
-        }
-    ],
-    "pageTotal": 4
+{
+    "list": [
+        {
+            "id": 1,
+            "name": "张三",
+            "money": 123,
+            "address": "广东省东莞市长安镇",
+            "state": true,
+            "date": "2019-11-1",
+            "thumb": "https://lin-xin.gitee.io/images/post/wms.png"
+        },
+        {
+            "id": 2,
+            "name": "李四",
+            "money": 456,
+            "address": "广东省广州市白云区",
+            "state": true,
+            "date": "2019-10-11",
+            "thumb": "https://lin-xin.gitee.io/images/post/node3.png"
+        },
+        {
+            "id": 3,
+            "name": "王五",
+            "money": 789,
+            "address": "湖南省长沙市",
+            "state": false,
+            "date": "2019-11-11",
+            "thumb": "https://lin-xin.gitee.io/images/post/parcel.png"
+        },
+        {
+            "id": 4,
+            "name": "赵六",
+            "money": 1011,
+            "address": "福建省厦门市鼓浪屿",
+            "state": true,
+            "date": "2019-10-20",
+            "thumb": "https://lin-xin.gitee.io/images/post/notice.png"
+        }
+    ],
+    "pageTotal": 4
 }
\ No newline at end of file
diff --git a/public/mock/user.json b/public/mock/user.json
new file mode 100644
index 00000000..079b73bb
--- /dev/null
+++ b/public/mock/user.json
@@ -0,0 +1,23 @@
+{
+    "list": [
+        {
+            "id": 1,
+            "name": "张三",
+            "password": "123",
+            "email": "123@qq.com",
+            "phone": "12345678944",
+            "date": "2024-01-01",
+            "role": "管理员"
+        },
+        {
+            "id": 2,
+            "name": "李四",
+            "password": "123",
+            "email": "1234@qq.com",
+            "phone": "12345678945",
+            "date": "2024-01-01",
+            "role": "普通用户"
+        }
+    ],
+    "pageTotal": 2
+}
\ No newline at end of file
diff --git a/screenshots/wms1.png b/screenshots/wms1.png
index 1bc275f5..92033483 100644
Binary files a/screenshots/wms1.png and b/screenshots/wms1.png differ
diff --git a/screenshots/wms3.png b/screenshots/wms3.png
index e61c1993..86b96aaf 100644
Binary files a/screenshots/wms3.png and b/screenshots/wms3.png differ
diff --git a/src/App.vue b/src/App.vue
index 8d681855..a8ce72b2 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,14 +1,17 @@
-<template>
-	<el-config-provider :locale="zhCn">
-		<router-view />
-	</el-config-provider>
-</template>
-
-<script setup lang="ts">
-import { ElConfigProvider } from 'element-plus';
-import zhCn from 'element-plus/es/locale/lang/zh-cn';
-</script>
-<style>
-@import './assets/css/main.css';
-@import './assets/css/color-dark.scss';
-</style>
+<template>
+	<el-config-provider :locale="zhCn">
+		<router-view />
+	</el-config-provider>
+</template>
+
+<script setup lang="ts">
+import { ElConfigProvider } from 'element-plus';
+import zhCn from 'element-plus/es/locale/lang/zh-cn';
+import { useThemeStore } from './store/theme';
+
+const theme = useThemeStore();
+theme.initTheme();
+</script>
+<style>
+@import './assets/css/main.css';
+</style>
diff --git a/src/api/index.ts b/src/api/index.ts
index 99d85239..2814587b 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,8 +1,22 @@
-import request from '../utils/request';
-
-export const fetchData = () => {
-    return request({
-        url: 'https://www.fastmock.site/mock/dc695d037038802def4b989ba4650c3f/vms/getUser',
-        method: 'post'
-    });
-};
+import request from '../utils/request';
+
+export const fetchData = () => {
+    return request({
+        url: './mock/table.json',
+        method: 'get'
+    });
+};
+
+export const fetchUserData = () => {
+    return request({
+        url: './mock/user.json',
+        method: 'get'
+    });
+};
+
+export const fetchRoleData = () => {
+    return request({
+        url: './mock/role.json',
+        method: 'get'
+    });
+};
diff --git a/src/assets/css/color-dark.scss b/src/assets/css/color-dark.scss
deleted file mode 100644
index a3e0b865..00000000
--- a/src/assets/css/color-dark.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-.header{
-    background-color: #242f42;
-}
-.login-wrap{
-    background: #324157;
-}
-.plugins-tips{
-    background: #eef1f6;
-}
-.plugins-tips a{
-    color: var(--el-color-primary);
-}
-
-.tags-li.active {
-    border: 1px solid var(--el-color-primary);
-    background-color: var(--el-color-primary);
-}
-.message-title{
-    color: var(--el-color-primary);
-}
-.collapse-btn:hover{
-    background: rgb(40,52,70);
-}
\ No newline at end of file
diff --git a/src/assets/css/main.css b/src/assets/css/main.css
index f6712160..da21f560 100644
--- a/src/assets/css/main.css
+++ b/src/assets/css/main.css
@@ -1,132 +1,95 @@
-* {
-    margin: 0;
-    padding: 0;
-}
-
-html,
-body,
-#app,
-.wrapper {
-    width: 100%;
-    height: 100%;
-    overflow: hidden;
-}
-
-body {
-    font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif;
-}
-
-a {
-    text-decoration: none
-}
-
-
-.content-box {
-    position: absolute;
-    left: 250px;
-    right: 0;
-    top: 70px;
-    bottom: 0;
-    padding-bottom: 30px;
-    -webkit-transition: left .3s ease-in-out;
-    transition: left .3s ease-in-out;
-    background: #f0f0f0;
-}
-
-.content {
-    width: auto;
-    height: 100%;
-    padding: 10px;
-    overflow-y: scroll;
-    box-sizing: border-box;
-}
-
-.content-collapse {
-    left: 65px;
-}
-
-.container {
-    padding: 30px;
-    background: #fff;
-    border: 1px solid #ddd;
-    border-radius: 5px;
-}
-
-.crumbs {
-    margin: 10px 0;
-}
-
-.el-table th {
-    background-color: #f5f7fa !important;
-}
-
-.pagination {
-    margin: 20px 0;
-    text-align: right;
-}
-
-.plugins-tips {
-    padding: 20px 10px;
-    margin-bottom: 20px;
-}
-
-.el-button+.el-tooltip {
-    margin-left: 10px;
-}
-
-.mgb20 {
-    margin-bottom: 20px;
-}
-
-.move-enter-active,
-.move-leave-active {
-    transition: opacity .1s ease;
-}
-
-.move-enter-from,
-.move-leave-to {
-    opacity: 0;
-}
-
-/*BaseForm*/
-
-.form-box {
-    width: 600px;
-}
-
-.form-box .line {
-    text-align: center;
-}
-
-.el-time-panel__content::after,
-.el-time-panel__content::before {
-    margin-top: -7px;
-}
-
-.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) {
-    padding-bottom: 0;
-}
-
-
-[class*=" el-icon-"], [class^=el-icon-] {
-    font-style: normal;
-    font-weight: 400;
-    font-variant: normal;
-    text-transform: none;
-    line-height: 1;
-    vertical-align: baseline;
-    display: inline-block;
-    -webkit-font-smoothing: antialiased;
-    -moz-osx-font-smoothing: grayscale;
-}
-.el-sub-menu [class^=el-icon-] {
-    vertical-align: middle;
-    margin-right: 5px;
-    width: 24px;
-    text-align: center;
-    font-size: 18px;
-}
-
-[hidden]{
-    display: none !important;
-}
\ No newline at end of file
+* {
+	margin: 0;
+	padding: 0;
+	outline: 0 !important;
+}
+
+html,
+body,
+#app,
+.wrapper {
+	width: 100%;
+	height: 100%;
+	overflow: hidden;
+}
+
+body {
+	font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, 'microsoft yahei', arial, STHeiTi, sans-serif;
+}
+
+a {
+	text-decoration: none;
+}
+i {
+	font-style: normal;
+}
+
+.container {
+	padding: 30px;
+	background: #fff;
+	border: 1px solid #ddd;
+	border-radius: 5px;
+}
+
+.el-table th {
+	background-color: #f5f7fa !important;
+}
+
+.plugins-tips {
+	padding: 20px 10px;
+	margin-bottom: 20px;
+	background: #eef1f6;
+}
+
+.plugins-tips a {
+	color: var(--el-color-primary);
+}
+
+.el-button + .el-tooltip {
+	margin-left: 10px;
+}
+
+.mgb20 {
+	margin-bottom: 20px;
+}
+.mgb10 {
+	margin-bottom: 10px;
+}
+.mr10 {
+	margin-right: 10px;
+}
+
+.move-enter-active,
+.move-leave-active {
+	transition: opacity 0.1s ease;
+}
+
+.move-enter-from,
+.move-leave-to {
+	opacity: 0;
+}
+
+.el-time-panel__content::after,
+.el-time-panel__content::before {
+	margin-top: -7px;
+}
+
+.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) {
+	padding-bottom: 0;
+}
+
+[hidden] {
+	display: none !important;
+}
+
+.flex-center {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+:root {
+	--header-bg-color: #242f42;
+	--header-text-color: #fff;
+	--active-color: var(--el-color-primary);
+}
diff --git a/src/assets/img/logo.svg b/src/assets/img/logo.svg
new file mode 100644
index 00000000..3d113c9b
--- /dev/null
+++ b/src/assets/img/logo.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 144.08 128.61"><title>&#x8D44;&#x6E90; 82</title><path d="M72.23 128.61c-7.1-.23-11.51-3.72-14.76-9.36C48 102.87 38.43 86.59 29.1 70.16a36 36 0 0 1-4.47-11.35A14.61 14.61 0 0 1 34 42.51c7.49-2.71 15.71-.21 19.67 6.43 7.52 12.56 14.77 25.27 22.12 37.92 3 5.17 5.89 10.43 9 15.51 5 8 3.45 18-4.22 23.31-2.3 1.62-5.52 1.99-8.34 2.93z" fill="#2ef2e9"/><path d="M72.66.33c6-.57 10.39 2.6 13.51 8C95.61 24.69 105 41.1 114.52 57.4c3.9 6.65-.28 17.13-6.39 20.44-8.93 4.83-17.88 1.28-21.86-5.62C76.82 55.86 67.14 39.62 58.11 23 52.06 12 59.61.24 72.66.33z" fill="#fa6663"/><path d="M144.08 15.83c-.58 8.62-6.73 15.57-15.51 15.66-9.31.09-16.87-7-16.95-15.62S119 0 127.87 0c9.13.09 16.22 7 16.21 15.83z" fill="#fbb355"/><path d="M16.24 31.5C7 31.33-.19 24.42 0 15.8.19 7.5 7.19-.06 14.64 0c10.53.08 18.27 6.73 17.61 15.9-.64 8.96-6.25 15.28-16.01 15.6z" fill="#8a56c2"/></svg>
\ No newline at end of file
diff --git a/src/assets/img/ucenter-bg.jpg b/src/assets/img/ucenter-bg.jpg
new file mode 100644
index 00000000..9c190557
Binary files /dev/null and b/src/assets/img/ucenter-bg.jpg differ
diff --git a/src/components/countup.vue b/src/components/countup.vue
new file mode 100644
index 00000000..4e08b0ef
--- /dev/null
+++ b/src/components/countup.vue
@@ -0,0 +1,39 @@
+<template>
+    <span ref="countRef"></span>
+</template>
+
+<script setup lang="ts">
+import { onMounted, ref, watch } from 'vue';
+import { CountUp } from 'countup.js';
+
+const props = defineProps({
+    end: {
+        type: Number,
+        required: true,
+    },
+    options: {
+        type: Object,
+        default: () => ({}),
+        required: false,
+    },
+});
+
+const countRef = ref<any>(null);
+let countUp: any;
+onMounted(() => {
+    countUp = new CountUp(countRef.value, props.end, props.options);
+    if (countUp.error) {
+        console.error(countUp.error);
+        return;
+    }
+    countUp.start();
+});
+
+watch(() => props.end, (newVal) => {
+    if (countUp) {
+        countUp.update(newVal);
+    }
+});
+
+
+</script>
\ No newline at end of file
diff --git a/src/components/header.vue b/src/components/header.vue
index 2c14ace0..54169d58 100644
--- a/src/components/header.vue
+++ b/src/components/header.vue
@@ -1,154 +1,200 @@
-<template>
-	<div class="header">
-		<!-- 折叠按钮 -->
-		<div class="collapse-btn" @click="collapseChage">
-			<el-icon v-if="sidebar.collapse"><Expand /></el-icon>
-			<el-icon v-else><Fold /></el-icon>
-		</div>
-		<div class="logo">后台管理系统</div>
-		<div class="header-right">
-			<div class="header-user-con">
-				<!-- 消息中心 -->
-				<div class="btn-bell" @click="router.push('/tabs')">
-					<el-tooltip
-						effect="dark"
-						:content="message ? `有${message}条未读消息` : `消息中心`"
-						placement="bottom"
-					>
-						<i class="el-icon-lx-notice"></i>
-					</el-tooltip>
-					<span class="btn-bell-badge" v-if="message"></span>
-				</div>
-				<!-- 用户头像 -->
-				<el-avatar class="user-avator" :size="30" :src="imgurl" />
-				<!-- 用户名下拉菜单 -->
-				<el-dropdown class="user-name" trigger="click" @command="handleCommand">
-					<span class="el-dropdown-link">
-						{{ username }}
-						<el-icon class="el-icon--right">
-							<arrow-down />
-						</el-icon>
-					</span>
-					<template #dropdown>
-						<el-dropdown-menu>
-							<a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
-								<el-dropdown-item>项目仓库</el-dropdown-item>
-							</a>
-							<el-dropdown-item command="user">个人中心</el-dropdown-item>
-							<el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
-						</el-dropdown-menu>
-					</template>
-				</el-dropdown>
-			</div>
-		</div>
-	</div>
-</template>
-<script setup lang="ts">
-import { onMounted } from 'vue';
-import { useSidebarStore } from '../store/sidebar';
-import { useRouter } from 'vue-router';
-import imgurl from '../assets/img/img.jpg';
-
-const username: string | null = localStorage.getItem('ms_username');
-const message: number = 2;
-
-const sidebar = useSidebarStore();
-// 侧边栏折叠
-const collapseChage = () => {
-	sidebar.handleCollapse();
-};
-
-onMounted(() => {
-	if (document.body.clientWidth < 1500) {
-		collapseChage();
-	}
-});
-
-// 用户名下拉菜单选择事件
-const router = useRouter();
-const handleCommand = (command: string) => {
-	if (command == 'loginout') {
-		localStorage.removeItem('ms_username');
-		router.push('/login');
-	} else if (command == 'user') {
-		router.push('/user');
-	}
-};
-</script>
-<style scoped>
-.header {
-	position: relative;
-	box-sizing: border-box;
-	width: 100%;
-	height: 70px;
-	font-size: 22px;
-	color: #fff;
-}
-.collapse-btn {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	height: 100%;
-	float: left;
-	padding: 0 21px;
-	cursor: pointer;
-}
-.header .logo {
-	float: left;
-	width: 250px;
-	line-height: 70px;
-}
-.header-right {
-	float: right;
-	padding-right: 50px;
-}
-.header-user-con {
-	display: flex;
-	height: 70px;
-	align-items: center;
-}
-.btn-fullscreen {
-	transform: rotate(45deg);
-	margin-right: 5px;
-	font-size: 24px;
-}
-.btn-bell,
-.btn-fullscreen {
-	position: relative;
-	width: 30px;
-	height: 30px;
-	text-align: center;
-	border-radius: 15px;
-	cursor: pointer;
-	display: flex;
-	align-items: center;
-}
-.btn-bell-badge {
-	position: absolute;
-	right: 4px;
-	top: 0px;
-	width: 8px;
-	height: 8px;
-	border-radius: 4px;
-	background: #f56c6c;
-	color: #fff;
-}
-.btn-bell .el-icon-lx-notice {
-	color: #fff;
-}
-.user-name {
-	margin-left: 10px;
-}
-.user-avator {
-	margin-left: 20px;
-}
-.el-dropdown-link {
-	color: #fff;
-	cursor: pointer;
-	display: flex;
-	align-items: center;
-}
-.el-dropdown-menu__item {
-	text-align: center;
-}
-</style>
+<template>
+	<div class="header">
+		<!-- 折叠按钮 -->
+		<div class="header-left">
+			<img class="logo" src="../assets/img/logo.svg" alt="">
+			<div class="web-title">
+				后台管理系统
+			</div>
+			<div class="collapse-btn" @click="collapseChage">
+				<el-icon v-if="sidebar.collapse">
+					<Expand />
+				</el-icon>
+				<el-icon v-else>
+					<Fold />
+				</el-icon>
+			</div>
+		</div>
+		<div class="header-right">
+			<div class="header-user-con">
+				<div class="btn-icon" @click="router.push('/theme')">
+					<el-tooltip effect="dark" content="设置主题" placement="bottom">
+						<i class="el-icon-lx-skin"></i>
+					</el-tooltip>
+				</div>
+				<div class="btn-icon" @click="router.push('/ucenter')">
+					<el-tooltip effect="dark" :content="message ? `有${message}条未读消息` : `消息中心`" placement="bottom">
+						<i class="el-icon-lx-notice"></i>
+					</el-tooltip>
+					<span class="btn-bell-badge" v-if="message"></span>
+				</div>
+				<div class="btn-icon" @click="setFullScreen">
+					<el-tooltip effect="dark" content="全屏" placement="bottom">
+						<i class="el-icon-lx-full"></i>
+					</el-tooltip>
+				</div>
+				<!-- 用户头像 -->
+				<el-avatar class="user-avator" :size="30" :src="imgurl" />
+				<!-- 用户名下拉菜单 -->
+				<el-dropdown class="user-name" trigger="click" @command="handleCommand">
+					<span class="el-dropdown-link">
+						{{ username }}
+						<el-icon class="el-icon--right">
+							<arrow-down />
+						</el-icon>
+					</span>
+					<template #dropdown>
+						<el-dropdown-menu>
+							<a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
+								<el-dropdown-item>项目仓库</el-dropdown-item>
+							</a>
+							<el-dropdown-item command="user">个人中心</el-dropdown-item>
+							<el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
+						</el-dropdown-menu>
+					</template>
+				</el-dropdown>
+			</div>
+		</div>
+	</div>
+</template>
+<script setup lang="ts">
+import { onMounted } from 'vue';
+import { useSidebarStore } from '../store/sidebar';
+import { useRouter } from 'vue-router';
+import imgurl from '../assets/img/img.jpg';
+
+const username: string | null = localStorage.getItem('ms_username');
+const message: number = 2;
+
+const sidebar = useSidebarStore();
+// 侧边栏折叠
+const collapseChage = () => {
+	sidebar.handleCollapse();
+};
+
+onMounted(() => {
+	if (document.body.clientWidth < 1500) {
+		collapseChage();
+	}
+});
+
+// 用户名下拉菜单选择事件
+const router = useRouter();
+const handleCommand = (command: string) => {
+	if (command == 'loginout') {
+		localStorage.removeItem('ms_username');
+		router.push('/login');
+	} else if (command == 'user') {
+		router.push('/ucenter');
+	}
+};
+
+const setFullScreen = () => {
+	if (document.fullscreenElement) {
+		document.exitFullscreen();
+	} else {
+		document.body.requestFullscreen.call(document.body);
+	}
+}
+</script>
+<style scoped>
+.header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	box-sizing: border-box;
+	width: 100%;
+	height: 70px;
+	color: var(--header-text-color);
+	background-color: var(--header-bg-color);
+	border-bottom: 1px solid #ddd;
+}
+
+.header-left {
+	display: flex;
+	align-items: center;
+	padding-left: 20px;
+	height: 100%;
+}
+
+.logo {
+	width: 35px;
+}
+
+.web-title {
+	margin: 0 40px 0 10px;
+	font-size: 22px;
+}
+
+.collapse-btn {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	height: 100%;
+	padding: 0 10px;
+	cursor: pointer;
+	opacity: 0.8;
+	font-size: 22px;
+}
+
+.collapse-btn:hover {
+	opacity: 1;
+}
+
+.header-right {
+	float: right;
+	padding-right: 50px;
+}
+
+.header-user-con {
+	display: flex;
+	height: 70px;
+	align-items: center;
+}
+
+.btn-fullscreen {
+	transform: rotate(45deg);
+	margin-right: 5px;
+	font-size: 24px;
+}
+
+.btn-icon {
+	position: relative;
+	width: 30px;
+	height: 30px;
+	text-align: center;
+	cursor: pointer;
+	display: flex;
+	align-items: center;
+	color: var(--header-text-color);
+	margin: 0 5px;
+	font-size: 20px;
+}
+
+.btn-bell-badge {
+	position: absolute;
+	right: 4px;
+	top: 0px;
+	width: 8px;
+	height: 8px;
+	border-radius: 4px;
+	background: #f56c6c;
+	color: var(--header-text-color);
+}
+
+
+.user-avator {
+	margin: 0 10px 0 20px;
+}
+
+.el-dropdown-link {
+	color: var(--header-text-color);
+	cursor: pointer;
+	display: flex;
+	align-items: center;
+}
+
+.el-dropdown-menu__item {
+	text-align: center;
+}
+</style>
diff --git a/src/components/menu.ts b/src/components/menu.ts
new file mode 100644
index 00000000..2644432b
--- /dev/null
+++ b/src/components/menu.ts
@@ -0,0 +1,221 @@
+import { Menus } from '@/types/menu';
+
+export const menuData: Menus[] = [
+    {
+        id: '0',
+        title: '系统首页',
+        index: '/dashboard',
+        icon: 'Odometer',
+    },
+    {
+        id: '1',
+        title: '系统管理',
+        index: '1',
+        icon: 'HomeFilled',
+        children: [
+            {
+                id: '11',
+                pid: '1',
+                index: '/system-user',
+                title: '用户管理',
+            },
+            {
+                id: '12',
+                pid: '1',
+                index: '/system-role',
+                title: '角色管理',
+            },
+            {
+                id: '13',
+                pid: '1',
+                index: '/system-menu',
+                title: '菜单管理',
+            },
+        ],
+    },
+    {
+        id: '2',
+        title: '组件',
+        index: '2-1',
+        icon: 'Calendar',
+        children: [
+            {
+                id: '21',
+                pid: '3',
+                index: '/form',
+                title: '表单',
+            },
+            {
+                id: '22',
+                pid: '3',
+                index: '/upload',
+                title: '上传',
+            },
+            {
+                id: '23',
+                pid: '2',
+                index: '/carousel',
+                title: '走马灯',
+            },
+            {
+                id: '24',
+                pid: '2',
+                index: '/calendar',
+                title: '日历',
+            },
+            {
+                id: '25',
+                pid: '2',
+                index: '/watermark',
+                title: '水印',
+            },
+            {
+                id: '26',
+                pid: '2',
+                index: '/tour',
+                title: '分布引导',
+            },
+            {
+                id: '27',
+                pid: '2',
+                index: '/steps',
+                title: '步骤条',
+            },
+            {
+                id: '28',
+                pid: '2',
+                index: '/statistic',
+                title: '统计',
+            },
+            {
+                id: '29',
+                pid: '3',
+                index: '29',
+                title: '三级菜单',
+                children: [
+                    {
+                        id: '291',
+                        pid: '29',
+                        index: '/editor',
+                        title: '富文本编辑器',
+                    },
+                    {
+                        id: '292',
+                        pid: '29',
+                        index: '/markdown',
+                        title: 'markdown编辑器',
+                    },
+                ],
+            },
+        ],
+    },
+    {
+        id: '3',
+        title: '表格',
+        index: '3',
+        icon: 'Calendar',
+        children: [
+            {
+                id: '31',
+                pid: '3',
+                index: '/table',
+                title: '基础表格',
+            },
+            {
+                id: '32',
+                pid: '3',
+                index: '/table-editor',
+                title: '可编辑表格',
+            },
+            {
+                id: '33',
+                pid: '3',
+                index: '/import',
+                title: '导入Excel',
+            },
+            {
+                id: '34',
+                pid: '3',
+                index: '/export',
+                title: '导出Excel',
+            },
+        ],
+    },
+    {
+        id: '4',
+        icon: 'PieChart',
+        index: '4',
+        title: '图表',
+        children: [
+            {
+                id: '41',
+                pid: '4',
+                index: '/schart',
+                title: 'schart图表',
+            },
+            {
+                id: '42',
+                pid: '4',
+                index: '/echarts',
+                title: 'echarts图表',
+            },
+        ],
+    },
+    {
+        id: '5',
+        icon: 'Guide',
+        index: '/icon',
+        title: '图标',
+        permiss: '5',
+    },
+    {
+        id: '7',
+        icon: 'Brush',
+        index: '/theme',
+        title: '主题',
+    },
+    {
+        id: '6',
+        icon: 'DocumentAdd',
+        index: '6',
+        title: '附加页面',
+        children: [
+            {
+                id: '61',
+                pid: '6',
+                index: '/ucenter',
+                title: '个人中心',
+            },
+            {
+                id: '62',
+                pid: '6',
+                index: '/login',
+                title: '登录',
+            },
+            {
+                id: '63',
+                pid: '6',
+                index: '/register',
+                title: '注册',
+            },
+            {
+                id: '64',
+                pid: '6',
+                index: '/reset-pwd',
+                title: '重设密码',
+            },
+            {
+                id: '65',
+                pid: '6',
+                index: '/403',
+                title: '403',
+            },
+            {
+                id: '66',
+                pid: '6',
+                index: '/404',
+                title: '404',
+            },
+        ],
+    },
+];
diff --git a/src/components/sidebar.vue b/src/components/sidebar.vue
index 1bfd9b5f..18e8c895 100644
--- a/src/components/sidebar.vue
+++ b/src/components/sidebar.vue
@@ -1,181 +1,90 @@
-<template>
-    <div class="sidebar">
-        <el-menu
-            class="sidebar-el-menu"
-            :default-active="onRoutes"
-            :collapse="sidebar.collapse"
-            background-color="#324157"
-            text-color="#bfcbd9"
-            active-text-color="#20a0ff"
-            unique-opened
-            router
-        >
-            <template v-for="item in items">
-                <template v-if="item.subs">
-                    <el-sub-menu :index="item.index" :key="item.index" v-permiss="item.permiss">
-                        <template #title>
-                            <el-icon>
-                                <component :is="item.icon"></component>
-                            </el-icon>
-                            <span>{{ item.title }}</span>
-                        </template>
-                        <template v-for="subItem in item.subs">
-                            <el-sub-menu
-                                v-if="subItem.subs"
-                                :index="subItem.index"
-                                :key="subItem.index"
-                                v-permiss="item.permiss"
-                            >
-                                <template #title>{{ subItem.title }}</template>
-                                <el-menu-item v-for="(threeItem, i) in subItem.subs" :key="i" :index="threeItem.index">
-                                    {{ threeItem.title }}
-                                </el-menu-item>
-                            </el-sub-menu>
-                            <el-menu-item v-else :index="subItem.index" v-permiss="item.permiss">
-                                {{ subItem.title }}
-                            </el-menu-item>
-                        </template>
-                    </el-sub-menu>
-                </template>
-                <template v-else>
-                    <el-menu-item :index="item.index" :key="item.index" v-permiss="item.permiss">
-                        <el-icon>
-                            <component :is="item.icon"></component>
-                        </el-icon>
-                        <template #title>{{ item.title }}</template>
-                    </el-menu-item>
-                </template>
-            </template>
-        </el-menu>
-    </div>
-</template>
-
-<script setup lang="ts">
-import { computed } from 'vue';
-import { useSidebarStore } from '../store/sidebar';
-import { useRoute } from 'vue-router';
-
-const items = [
-    {
-        icon: 'Odometer',
-        index: '/dashboard',
-        title: '系统首页',
-        permiss: '1',
-    },
-    {
-        icon: 'Calendar',
-        index: '1',
-        title: '表格相关',
-        permiss: '2',
-        subs: [
-            {
-                index: '/table',
-                title: '常用表格',
-                permiss: '2',
-            },
-            {
-                index: '/import',
-                title: '导入Excel',
-                permiss: '2',
-            },
-            {
-                index: '/export',
-                title: '导出Excel',
-                permiss: '2',
-            },
-        ],
-    },
-    {
-        icon: 'DocumentCopy',
-        index: '/tabs',
-        title: 'tab选项卡',
-        permiss: '3',
-    },
-    {
-        icon: 'Edit',
-        index: '3',
-        title: '表单相关',
-        permiss: '4',
-        subs: [
-            {
-                index: '/form',
-                title: '基本表单',
-                permiss: '5',
-            },
-            {
-                index: '/upload',
-                title: '文件上传',
-                permiss: '6',
-            },
-            {
-                index: '4',
-                title: '三级菜单',
-                permiss: '7',
-                subs: [
-                    {
-                        index: '/editor',
-                        title: '富文本编辑器',
-                        permiss: '8',
-                    },
-                    {
-                        index: '/markdown',
-                        title: 'markdown编辑器',
-                        permiss: '9',
-                    },
-                ],
-            },
-        ],
-    },
-    {
-        icon: 'Setting',
-        index: '/icon',
-        title: '自定义图标',
-        permiss: '10',
-    },
-    {
-        icon: 'PieChart',
-        index: '/charts',
-        title: 'schart图表',
-        permiss: '11',
-    },
-    {
-        icon: 'Warning',
-        index: '/permission',
-        title: '权限管理',
-        permiss: '13',
-    },
-    {
-        icon: 'CoffeeCup',
-        index: '/donate',
-        title: '支持作者',
-        permiss: '14',
-    },
-];
-
-const route = useRoute();
-const onRoutes = computed(() => {
-    return route.path;
-});
-
-const sidebar = useSidebarStore();
-</script>
-
-<style scoped>
-.sidebar {
-    display: block;
-    position: absolute;
-    left: 0;
-    top: 70px;
-    bottom: 0;
-    overflow-y: scroll;
-}
-.sidebar::-webkit-scrollbar {
-    width: 0;
-}
-.sidebar-el-menu:not(.el-menu--collapse) {
-    width: 250px;
-}
-.sidebar > ul {
-    height: 100%;
-}
-</style>
+<template>
+    <div class="sidebar">
+        <el-menu
+            class="sidebar-el-menu"
+            :default-active="onRoutes"
+            :collapse="sidebar.collapse"
+            :background-color="sidebar.bgColor"
+            :text-color="sidebar.textColor"
+            router
+        >
+            <template v-for="item in menuData">
+                <template v-if="item.children">
+                    <el-sub-menu :index="item.index" :key="item.index" v-permiss="item.id">
+                        <template #title>
+                            <el-icon>
+                                <component :is="item.icon"></component>
+                            </el-icon>
+                            <span>{{ item.title }}</span>
+                        </template>
+                        <template v-for="subItem in item.children">
+                            <el-sub-menu
+                                v-if="subItem.children"
+                                :index="subItem.index"
+                                :key="subItem.index"
+                                v-permiss="item.id"
+                            >
+                                <template #title>{{ subItem.title }}</template>
+                                <el-menu-item
+                                    v-for="(threeItem, i) in subItem.children"
+                                    :key="i"
+                                    :index="threeItem.index"
+                                >
+                                    {{ threeItem.title }}
+                                </el-menu-item>
+                            </el-sub-menu>
+                            <el-menu-item v-else :index="subItem.index" v-permiss="item.id">
+                                {{ subItem.title }}
+                            </el-menu-item>
+                        </template>
+                    </el-sub-menu>
+                </template>
+                <template v-else>
+                    <el-menu-item :index="item.index" :key="item.index" v-permiss="item.id">
+                        <el-icon>
+                            <component :is="item.icon"></component>
+                        </el-icon>
+                        <template #title>{{ item.title }}</template>
+                    </el-menu-item>
+                </template>
+            </template>
+        </el-menu>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { computed } from 'vue';
+import { useSidebarStore } from '../store/sidebar';
+import { useRoute } from 'vue-router';
+import { menuData } from '@/components/menu';
+
+const route = useRoute();
+const onRoutes = computed(() => {
+    return route.path;
+});
+
+const sidebar = useSidebarStore();
+</script>
+
+<style scoped>
+.sidebar {
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 70px;
+    bottom: 0;
+    overflow-y: scroll;
+}
+
+.sidebar::-webkit-scrollbar {
+    width: 0;
+}
+
+.sidebar-el-menu:not(.el-menu--collapse) {
+    width: 250px;
+}
+
+.sidebar-el-menu {
+    min-height: 100%;
+}
+</style>
diff --git a/src/components/table-custom.vue b/src/components/table-custom.vue
new file mode 100644
index 00000000..7286c6b0
--- /dev/null
+++ b/src/components/table-custom.vue
@@ -0,0 +1,211 @@
+<template>
+    <div>
+        <div class="table-toolbar" v-if="hasToolbar">
+            <div class="table-toolbar-left">
+                <slot name="toolbarBtn"></slot>
+            </div>
+            <div class="table-toolbar-right flex-center">
+                <template v-if="multipleSelection.length > 0">
+                    <el-tooltip effect="dark" content="删除选中" placement="top">
+                        <el-icon class="columns-setting-icon" @click="delSelection(multipleSelection)">
+                            <Delete />
+                        </el-icon>
+                    </el-tooltip>
+                    <el-divider direction="vertical" />
+                </template>
+                <el-tooltip effect="dark" content="刷新" placement="top">
+                    <el-icon class="columns-setting-icon" @click="refresh">
+                        <Refresh />
+                    </el-icon>
+                </el-tooltip>
+                <el-divider direction="vertical" />
+                <el-tooltip effect="dark" content="列设置" placement="top">
+                    <el-dropdown :hide-on-click="false" size="small" trigger="click">
+                        <el-icon class="columns-setting-icon">
+                            <Setting />
+                        </el-icon>
+                        <template #dropdown>
+                            <el-dropdown-menu>
+                                <el-dropdown-item v-for="c in columns">
+                                    <el-checkbox v-model="c.visible" :label="c.label" />
+                                </el-dropdown-item>
+                            </el-dropdown-menu>
+                        </template>
+                    </el-dropdown>
+                </el-tooltip>
+            </div>
+        </div>
+        <el-table class="mgb20" :style="{ width: '100%' }" border :data="tableData" :row-key="rowKey"
+            @selection-change="handleSelectionChange" table-layout="auto">
+            <template v-for="item in columns" :key="item.prop">
+                <el-table-column v-if="item.visible" :prop="item.prop" :label="item.label" :width="item.width"
+                    :type="item.type" :align="item.align || 'center'">
+
+                    <template #default="{ row, column, $index }" v-if="item.type === 'index'">
+                        {{ getIndex($index) }}
+                    </template>
+                    <template #default="{ row, column, $index }" v-if="!item.type">
+                        <slot :name="item.prop" :rows="row" :index="$index">
+                            <template v-if="item.prop == 'operator'">
+                                <el-button type="warning" size="small" :icon="View" @click="viewFunc(row)">
+                                    查看
+                                </el-button>
+                                <el-button type="primary" size="small" :icon="Edit" @click="editFunc(row)">
+                                    编辑
+                                </el-button>
+                                <el-button type="danger" size="small" :icon="Delete" @click="handleDelete(row)">
+                                    删除
+                                </el-button>
+                            </template>
+                            <span v-else-if="item.formatter">
+                                {{ item.formatter(row[item.prop]) }}
+                            </span>
+                            <span v-else>
+                                {{ row[item.prop] }}
+                            </span>
+                        </slot>
+                    </template>
+                </el-table-column>
+            </template>
+        </el-table>
+        <el-pagination v-if="hasPagination" :current-page="currentPage" :page-size="pageSize" :background="true"
+            :layout="layout" :total="total" @current-change="handleCurrentChange" />
+    </div>
+</template>
+
+<script setup lang="ts">
+import { toRefs, PropType, ref } from 'vue'
+import { Delete, Edit, View, Refresh } from '@element-plus/icons-vue';
+import { ElMessageBox } from 'element-plus';
+
+const props = defineProps({
+    // 表格相关
+    tableData: {
+        type: Array,
+        default: []
+    },
+    columns: {
+        type: Array as PropType<any[]>,
+        default: []
+    },
+    rowKey: {
+        type: String,
+        default: 'id'
+    },
+    hasToolbar: {
+        type: Boolean,
+        default: true
+    },
+    //  分页相关
+    hasPagination: {
+        type: Boolean,
+        default: true
+    },
+    total: {
+        type: Number,
+        default: 0
+    },
+    currentPage: {
+        type: Number,
+        default: 1
+    },
+    pageSize: {
+        type: Number,
+        default: 10
+    },
+
+    layout: {
+        type: String,
+        default: 'total, prev, pager, next'
+    },
+    delFunc: {
+        type: Function,
+        default: () => { }
+    },
+    viewFunc: {
+        type: Function,
+        default: () => { }
+    },
+    editFunc: {
+        type: Function,
+        default: () => { }
+    },
+    delSelection: {
+        type: Function,
+        default: () => { }
+    },
+    refresh: {
+        type: Function,
+        default: () => { }
+    },
+    changePage: {
+        type: Function,
+        default: () => { }
+    }
+})
+
+let {
+    tableData,
+    columns,
+    rowKey,
+    hasToolbar,
+    hasPagination,
+    total,
+    currentPage,
+    pageSize,
+    layout,
+} = toRefs(props)
+
+columns.value.forEach((item) => {
+    if (item.visible === undefined) {
+        item.visible = true
+    }
+})
+
+// 当选择项发生变化时会触发该事件
+const multipleSelection = ref([])
+const handleSelectionChange = (selection: any[]) => {
+    multipleSelection.value = selection
+}
+
+// 当前页码变化的事件
+const handleCurrentChange = (val: number) => {
+    props.changePage(val)
+}
+
+const handleDelete = (row) => {
+    ElMessageBox.confirm('确定要删除吗?', '提示', {
+        type: 'warning'
+    })
+        .then(async () => {
+            props.delFunc(row);
+        })
+        .catch(() => { });
+};
+
+const getIndex = (index: number) => {
+    return index + 1 + (currentPage.value - 1) * pageSize.value
+}
+
+</script>
+
+<style scoped>
+.table-toolbar {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-end;
+    margin-bottom: 10px;
+}
+
+.columns-setting-icon {
+    display: block;
+    font-size: 18px;
+    cursor: pointer;
+    color: #676767;
+}
+</style>
+<style>
+.table-header .cell {
+    color: #333;
+}
+</style>
\ No newline at end of file
diff --git a/src/components/table-detail.vue b/src/components/table-detail.vue
index 16064d03..a9ba021c 100644
--- a/src/components/table-detail.vue
+++ b/src/components/table-detail.vue
@@ -1,32 +1,10 @@
 <template>
-	<el-descriptions title="" :column="2" border>
-		<el-descriptions-item>
-			<template #label> 用户ID </template>
-			{{ data.id }}
-		</el-descriptions-item>
-		<el-descriptions-item>
-			<template #label> 用户名 </template>
-			{{ data.name }}
-		</el-descriptions-item>
-		<el-descriptions-item>
-			<template #label> 账户余额 </template>
-			{{ data.money }}
-		</el-descriptions-item>
-		<el-descriptions-item>
-			<template #label> 账户状态 </template>
-			{{ data.state ? '正常' : '异常' }}
-		</el-descriptions-item>
-		<el-descriptions-item :span="2">
-			<template #label> 地址 </template>
-			{{ data.address }}
-		</el-descriptions-item>
-		<el-descriptions-item>
-			<template #label> 日期 </template>
-			{{ data.date }}
-		</el-descriptions-item>
-		<el-descriptions-item>
-			<template #label> 头像 </template>
-			<img :src="data.thumb" style="width: 120px" alt="" />
+	<el-descriptions :title="title" :column="column" border>
+		<el-descriptions-item v-for="item in list" :span="item.span">
+			<template #label> {{ item.label }} </template>
+			<slot :name="item.prop" :rows="row">
+				{{ item.value || row[item.prop] }}
+			</slot>
 		</el-descriptions-item>
 	</el-descriptions>
 </template>
@@ -35,7 +13,9 @@
 const props = defineProps({
 	data: {
 		type: Object,
-		required: true
+		required: true,
 	}
 });
+const { row, title, column = 2, list } = props.data;
+
 </script>
diff --git a/src/components/table-edit.vue b/src/components/table-edit.vue
index 78b4293a..cbf0dc60 100644
--- a/src/components/table-edit.vue
+++ b/src/components/table-edit.vue
@@ -1,38 +1,36 @@
 <template>
-	<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
-		<el-form-item label="用户名" prop="name">
-			<el-input v-model="form.name"></el-input>
-		</el-form-item>
-		<el-form-item label="账户余额" prop="money">
-			<el-input v-model.number="form.money"></el-input>
-		</el-form-item>
-		<el-form-item label="地址" prop="address">
-			<el-input v-model="form.address"></el-input>
-		</el-form-item>
-		<el-form-item label="账户状态" prop="state">
-			<el-switch
-				v-model="form.state"
-				:active-value="1"
-				:inactive-value="0"
-				active-text="正常"
-				inactive-text="异常"
-			></el-switch>
-		</el-form-item>
-		<el-form-item label="注册日期" prop="date">
-			<el-date-picker type="date" v-model="form.date" value-format="YYYY-MM-DD"></el-date-picker>
-		</el-form-item>
-		<el-form-item label="上传头像" prop="thumb">
-			<el-upload
-				class="avatar-uploader"
-				action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
-				:show-file-list="false"
-				:on-success="handleAvatarSuccess"
-				:before-upload="beforeAvatarUpload"
-			>
-				<img v-if="form.thumb" :src="form.thumb" class="avatar" />
-				<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
-			</el-upload>
-		</el-form-item>
+	<el-form ref="formRef" :model="form" :rules="rules" :label-width="options.labelWidth">
+		<el-row>
+			<el-col :span="options.span" v-for="item in options.list">
+				<el-form-item :label="item.label" :prop="item.prop">
+					<!-- 文本框、数字框、下拉框、日期框、开关、上传 -->
+					<el-input v-if="item.type === 'input'" v-model="form[item.prop]" :disabled="item.disabled"
+						:placeholder="item.placeholder" clearable></el-input>
+					<el-input-number v-else-if="item.type === 'number'" v-model="form[item.prop]"
+						:disabled="item.disabled" controls-position="right"></el-input-number>
+					<el-select v-else-if="item.type === 'select'" v-model="form[item.prop]" :disabled="item.disabled"
+						:placeholder="item.placeholder" clearable>
+						<el-option v-for="opt in item.opts" :label="opt.label" :value="opt.value"></el-option>
+					</el-select>
+					<el-date-picker v-else-if="item.type === 'date'" type="date" v-model="form[item.prop]"
+						:value-format="item.format"></el-date-picker>
+					<el-switch v-else-if="item.type === 'switch'" v-model="form[item.prop]"
+						:active-value="item.activeValue" :inactive-value="item.inactiveValue"
+						:active-text="item.activeText" :inactive-text="item.inactiveText"></el-switch>
+					<el-upload v-else-if="item.type === 'upload'" class="avatar-uploader" action="#"
+						:show-file-list="false" :on-success="handleAvatarSuccess">
+						<img v-if="form[item.prop]" :src="form[item.prop]" class="avatar" />
+						<el-icon v-else class="avatar-uploader-icon">
+							<Plus />
+						</el-icon>
+					</el-upload>
+					<slot :name="item.prop" v-else>
+
+					</slot>
+				</el-form-item>
+			</el-col>
+		</el-row>
+
 		<el-form-item>
 			<el-button type="primary" @click="saveEdit(formRef)">保 存</el-button>
 		</el-form-item>
@@ -40,11 +38,16 @@
 </template>
 
 <script lang="ts" setup>
-import { ElMessage, FormInstance, FormRules, UploadProps } from 'element-plus';
-import { ref } from 'vue';
+import { FormOption } from '@/types/form-option';
+import { FormInstance, FormRules, UploadProps } from 'element-plus';
+import { PropType, ref } from 'vue';
 
-const props = defineProps({
-	data: {
+const { options, formData, edit, update } = defineProps({
+	options: {
+		type: Object as PropType<FormOption>,
+		required: true
+	},
+	formData: {
 		type: Object,
 		required: true
 	},
@@ -58,28 +61,23 @@ const props = defineProps({
 	}
 });
 
-const defaultData = {
-	id: '',
-	name: '',
-	address: '',
-	thumb: '',
-	money: 0,
-	state: 0,
-	date: new Date()
-};
 
-const form = ref({ ...(props.edit ? props.data : defaultData) });
+const form = ref({ ...(edit ? formData : {}) });
+
+const rules: FormRules = options.list.map(item => {
+	if (item.required) {
+		return { [item.prop]: [{ required: true, message: `${item.label}不能为空`, trigger: 'blur' }] };
+	}
+	return {};
+}).reduce((acc, cur) => ({ ...acc, ...cur }), {});
+
 
-const rules: FormRules = {
-	name: [{ required: true, message: '用户名', trigger: 'blur' }]
-};
 const formRef = ref<FormInstance>();
 const saveEdit = (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	formEl.validate(valid => {
 		if (!valid) return false;
-		props.update(form.value);
-		ElMessage.success('保存成功!');
+		update(form.value);
 	});
 };
 
@@ -87,16 +85,6 @@ const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) =>
 	form.value.thumb = URL.createObjectURL(uploadFile.raw!);
 };
 
-const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
-	if (rawFile.type !== 'image/jpeg') {
-		ElMessage.error('Avatar picture must be JPG format!');
-		return false;
-	} else if (rawFile.size / 1024 / 1024 > 2) {
-		ElMessage.error('Avatar picture size can not exceed 2MB!');
-		return false;
-	}
-	return true;
-};
 </script>
 
 <style>
diff --git a/src/components/table-search.vue b/src/components/table-search.vue
new file mode 100644
index 00000000..116c3e60
--- /dev/null
+++ b/src/components/table-search.vue
@@ -0,0 +1,60 @@
+<template>
+	<div class="search-container">
+		<el-form ref="searchRef" :model="query" :inline="true">
+			<el-form-item :label="item.label" :prop="item.prop" v-for="item in options">
+				<!-- 文本框、下拉框、日期框 -->
+				<el-input v-if="item.type === 'input'" v-model="query[item.prop]" :disabled="item.disabled"
+					:placeholder="item.placeholder" clearable></el-input>
+				<el-select v-else-if="item.type === 'select'" v-model="query[item.prop]" :disabled="item.disabled"
+					:placeholder="item.placeholder" clearable>
+					<el-option v-for="opt in item.opts" :label="opt.label" :value="opt.value"></el-option>
+				</el-select>
+				<el-date-picker v-else-if="item.type === 'date'" type="date" v-model="query[item.prop]"
+					:value-format="item.format"></el-date-picker>
+			</el-form-item>
+			<el-form-item>
+				<el-button type="primary" :icon="Search" @click="search">搜索</el-button>
+				<el-button :icon="Refresh" @click="resetForm(searchRef)">重置</el-button>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>
+
+<script lang="ts" setup>
+import { FormInstance } from 'element-plus';
+import { Search, Refresh } from '@element-plus/icons-vue';
+import { PropType, ref } from 'vue';
+import { FormOptionList } from '@/types/form-option';
+
+const props = defineProps({
+	query: {
+		type: Object,
+		required: true
+	},
+	options: {
+		type: Array as PropType<Array<FormOptionList>>,
+		required: true
+	},
+	search: {
+		type: Function,
+		default: () => { }
+	}
+});
+
+const searchRef = ref<FormInstance>();
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	formEl.resetFields()
+	props.search();
+}
+</script>
+
+<style scoped>
+.search-container {
+	padding: 20px 30px 0;
+	background-color: #fff;
+	margin-bottom: 10px;
+	border: 1px solid #ddd;
+	border-radius: 5px
+}
+</style>
diff --git a/src/components/tabs.vue b/src/components/tabs.vue
new file mode 100644
index 00000000..4dfd6b95
--- /dev/null
+++ b/src/components/tabs.vue
@@ -0,0 +1,149 @@
+<template>
+	<div class="tabs-container">
+		<el-tabs v-model="activePath" class="tabs" type="card" closable @tab-click="clickTabls" @tab-remove="closeTabs">
+			<el-tab-pane v-for="item in tabs.list" :key="item.path" :label="item.title" :name="item.path"
+				@click="setTags(item)"></el-tab-pane>
+		</el-tabs>
+		<div class="Tabs-close-box">
+			<el-dropdown @command="handleTags">
+				<el-button size="small" type="primary" plain>
+					标签选项
+					<el-icon class="el-icon--right">
+						<arrow-down />
+					</el-icon>
+				</el-button>
+				<template #dropdown>
+					<el-dropdown-menu size="small">
+						<el-dropdown-item command="other">关闭其他</el-dropdown-item>
+						<el-dropdown-item command="current">关闭当前</el-dropdown-item>
+						<el-dropdown-item command="all">关闭所有</el-dropdown-item>
+					</el-dropdown-menu>
+				</template>
+			</el-dropdown>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch } from 'vue';
+import { useTabsStore } from '../store/tabs';
+import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
+
+const route = useRoute();
+const router = useRouter();
+const activePath = ref(route.fullPath)
+const tabs = useTabsStore();
+// 设置标签
+const setTags = (route: any) => {
+	const isExist = tabs.list.some(item => {
+		return item.path === route.fullPath;
+	});
+	if (!isExist) {
+		tabs.setTabsItem({
+			name: route.name,
+			title: route.meta.title,
+			path: route.fullPath
+		});
+	}
+};
+setTags(route);
+onBeforeRouteUpdate(to => {
+	setTags(to);
+});
+
+// 关闭全部标签
+const closeAll = () => {
+	tabs.clearTabs();
+	router.push('/');
+};
+// 关闭其他标签
+const closeOther = () => {
+	const curItem = tabs.list.filter(item => {
+		return item.path === route.fullPath;
+	});
+	tabs.closeTabsOther(curItem);
+};
+const handleTags = (command: string) => {
+	switch (command) {
+		case 'current':
+			// 关闭当前页面的标签页
+			tabs.closeCurrentTag({
+				$router: router,
+				$route: route
+			});
+			break;
+		case 'all':
+			closeAll();
+			break;
+
+		case 'other':
+			closeOther();
+			break;
+	}
+};
+
+const clickTabls = (item: any) => {
+	router.push(item.props.name);
+}
+const closeTabs = (path: any) => {
+	console.log(path);
+	const index = tabs.list.findIndex((item) => item.path === path);
+	tabs.delTabsItem(index);
+	const item = tabs.list[index] ? tabs.list[index] : tabs.list[index - 1];
+	if (item) {
+		path === route.fullPath && router.push(item.path);
+	} else {
+		router.push('/');
+	}
+}
+
+watch(() => route.fullPath, (newVal, oldVal) => {
+	activePath.value = newVal;
+})
+
+</script>
+
+<style scss>
+.tabs-container {
+	position: relative;
+	overflow: hidden;
+	background: #fff;
+	padding: 2px 120px 0 0;
+}
+
+.tabs {
+
+	.el-tabs__header {
+		margin-bottom: 0;
+	}
+
+	.el-tabs__nav {
+		height: 28px;
+	}
+
+	.el-tabs__nav-next,
+	.el-tabs__nav-prev {
+		line-height: 32px;
+	}
+
+	&.el-tabs {
+		--el-tabs-header-height: 28px;
+	}
+
+
+}
+
+.Tabs-close-box {
+	position: absolute;
+	right: 0;
+	top: 0;
+	box-sizing: border-box;
+	padding-top: 1px;
+	text-align: center;
+	width: 110px;
+	height: 30px;
+	background: #fff;
+	box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1);
+	z-index: 10;
+}
+</style>
diff --git a/src/components/tags.vue b/src/components/tags.vue
deleted file mode 100644
index 79a4887b..00000000
--- a/src/components/tags.vue
+++ /dev/null
@@ -1,168 +0,0 @@
-<template>
-	<div class="tags" v-if="tags.show">
-		<ul>
-			<li
-				class="tags-li"
-				v-for="(item, index) in tags.list"
-				:class="{ active: isActive(item.path) }"
-				:key="index"
-			>
-				<router-link :to="item.path" class="tags-li-title">{{ item.title }}</router-link>
-				<el-icon @click="closeTags(index)"><Close /></el-icon>
-			</li>
-		</ul>
-		<div class="tags-close-box">
-			<el-dropdown @command="handleTags">
-				<el-button size="small" type="primary">
-					标签选项
-					<el-icon class="el-icon--right">
-						<arrow-down />
-					</el-icon>
-				</el-button>
-				<template #dropdown>
-					<el-dropdown-menu size="small">
-						<el-dropdown-item command="other">关闭其他</el-dropdown-item>
-						<el-dropdown-item command="all">关闭所有</el-dropdown-item>
-					</el-dropdown-menu>
-				</template>
-			</el-dropdown>
-		</div>
-	</div>
-</template>
-
-<script setup lang="ts">
-import { useTagsStore } from '../store/tags';
-import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
-
-const route = useRoute();
-const router = useRouter();
-const isActive = (path: string) => {
-	return path === route.fullPath;
-};
-
-const tags = useTagsStore();
-// 关闭单个标签
-const closeTags = (index: number) => {
-	const delItem = tags.list[index];
-	tags.delTagsItem(index);
-	const item = tags.list[index] ? tags.list[index] : tags.list[index - 1];
-	if (item) {
-		delItem.path === route.fullPath && router.push(item.path);
-	} else {
-		router.push('/');
-	}
-};
-
-// 设置标签
-const setTags = (route: any) => {
-	const isExist = tags.list.some(item => {
-		return item.path === route.fullPath;
-	});
-	if (!isExist) {
-		if (tags.list.length >= 8) tags.delTagsItem(0);
-		tags.setTagsItem({
-			name: route.name,
-			title: route.meta.title,
-			path: route.fullPath
-		});
-	}
-};
-setTags(route);
-onBeforeRouteUpdate(to => {
-	setTags(to);
-});
-
-// 关闭全部标签
-const closeAll = () => {
-	tags.clearTags();
-	router.push('/');
-};
-// 关闭其他标签
-const closeOther = () => {
-	const curItem = tags.list.filter(item => {
-		return item.path === route.fullPath;
-	});
-	tags.closeTagsOther(curItem);
-};
-const handleTags = (command: string) => {
-	command === 'other' ? closeOther() : closeAll();
-};
-
-// 关闭当前页面的标签页
-// tags.closeCurrentTag({
-//     $router: router,
-//     $route: route
-// });
-</script>
-
-<style>
-.tags {
-	position: relative;
-	height: 30px;
-	overflow: hidden;
-	background: #fff;
-	padding-right: 120px;
-	box-shadow: 0 5px 10px #ddd;
-}
-
-.tags ul {
-	box-sizing: border-box;
-	width: 100%;
-	height: 100%;
-}
-
-.tags-li {
-	display: flex;
-	align-items: center;
-	float: left;
-	margin: 3px 5px 2px 3px;
-	border-radius: 3px;
-	font-size: 12px;
-	overflow: hidden;
-	cursor: pointer;
-	height: 23px;
-	border: 1px solid #e9eaec;
-	background: #fff;
-	padding: 0 5px 0 12px;
-	color: #666;
-	-webkit-transition: all 0.3s ease-in;
-	-moz-transition: all 0.3s ease-in;
-	transition: all 0.3s ease-in;
-}
-
-.tags-li:not(.active):hover {
-	background: #f8f8f8;
-}
-
-.tags-li.active {
-	color: #fff;
-}
-
-.tags-li-title {
-	float: left;
-	max-width: 80px;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-	margin-right: 5px;
-	color: #666;
-}
-
-.tags-li.active .tags-li-title {
-	color: #fff;
-}
-
-.tags-close-box {
-	position: absolute;
-	right: 0;
-	top: 0;
-	box-sizing: border-box;
-	padding-top: 1px;
-	text-align: center;
-	width: 110px;
-	height: 30px;
-	background: #fff;
-	box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1);
-	z-index: 10;
-}
-</style>
diff --git a/src/main.ts b/src/main.ts
index 43ae5c79..d44c9a7c 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,28 +1,28 @@
-import { createApp } from 'vue';
-import { createPinia } from 'pinia';
-import * as ElementPlusIconsVue from '@element-plus/icons-vue';
-import App from './App.vue';
-import router from './router';
-import { usePermissStore } from './store/permiss';
-import 'element-plus/dist/index.css';
-import './assets/css/icon.css';
-
-const app = createApp(App);
-app.use(createPinia());
-app.use(router);
-
-// 注册elementplus图标
-for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-    app.component(key, component);
-}
-// 自定义权限指令
-const permiss = usePermissStore();
-app.directive('permiss', {
-    mounted(el, binding) {
-        if (!permiss.key.includes(String(binding.value))) {
-            el['hidden'] = true;
-        }
-    },
-});
-
-app.mount('#app');
+import { createApp } from 'vue';
+import { createPinia } from 'pinia';
+import * as ElementPlusIconsVue from '@element-plus/icons-vue';
+import App from './App.vue';
+import router from './router';
+import { usePermissStore } from './store/permiss';
+import 'element-plus/dist/index.css';
+import './assets/css/icon.css';
+
+const app = createApp(App);
+app.use(createPinia());
+app.use(router);
+
+// 注册elementplus图标
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+    app.component(key, component);
+}
+// 自定义权限指令
+const permiss = usePermissStore();
+app.directive('permiss', {
+    mounted(el, binding) {
+        if (binding.value && !permiss.key.includes(String(binding.value))) {
+            el['hidden'] = true;
+        }
+    },
+});
+
+app.mount('#app');
diff --git a/src/router/index.ts b/src/router/index.ts
index 5bc3eb40..3edbf8e0 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,185 +1,293 @@
-import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
-import { usePermissStore } from '../store/permiss';
-import Home from '../views/home.vue';
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-
-const routes: RouteRecordRaw[] = [
-    {
-        path: '/',
-        redirect: '/dashboard',
-    },
-    {
-        path: '/',
-        name: 'Home',
-        component: Home,
-        children: [
-            {
-                path: '/dashboard',
-                name: 'dashboard',
-                meta: {
-                    title: '系统首页',
-                    permiss: '1',
-                },
-                component: () => import(/* webpackChunkName: "dashboard" */ '../views/dashboard.vue'),
-            },
-            {
-                path: '/table',
-                name: 'basetable',
-                meta: {
-                    title: '表格',
-                    permiss: '2',
-                },
-                component: () => import(/* webpackChunkName: "table" */ '../views/table.vue'),
-            },
-            {
-                path: '/charts',
-                name: 'basecharts',
-                meta: {
-                    title: '图表',
-                    permiss: '11',
-                },
-                component: () => import(/* webpackChunkName: "charts" */ '../views/charts.vue'),
-            },
-            {
-                path: '/form',
-                name: 'baseform',
-                meta: {
-                    title: '表单',
-                    permiss: '5',
-                },
-                component: () => import(/* webpackChunkName: "form" */ '../views/form.vue'),
-            },
-            {
-                path: '/tabs',
-                name: 'tabs',
-                meta: {
-                    title: 'tab标签',
-                    permiss: '3',
-                },
-                component: () => import(/* webpackChunkName: "tabs" */ '../views/tabs.vue'),
-            },
-            {
-                path: '/donate',
-                name: 'donate',
-                meta: {
-                    title: '鼓励作者',
-                    permiss: '14',
-                },
-                component: () => import(/* webpackChunkName: "donate" */ '../views/donate.vue'),
-            },
-            {
-                path: '/permission',
-                name: 'permission',
-                meta: {
-                    title: '权限管理',
-                    permiss: '13',
-                },
-                component: () => import(/* webpackChunkName: "permission" */ '../views/permission.vue'),
-            },
-            {
-                path: '/upload',
-                name: 'upload',
-                meta: {
-                    title: '上传插件',
-                    permiss: '6',
-                },
-                component: () => import(/* webpackChunkName: "upload" */ '../views/upload.vue'),
-            },
-            {
-                path: '/icon',
-                name: 'icon',
-                meta: {
-                    title: '自定义图标',
-                    permiss: '10',
-                },
-                component: () => import(/* webpackChunkName: "icon" */ '../views/icon.vue'),
-            },
-            {
-                path: '/user',
-                name: 'user',
-                meta: {
-                    title: '个人中心',
-                },
-                component: () => import(/* webpackChunkName: "user" */ '../views/user.vue'),
-            },
-            {
-                path: '/editor',
-                name: 'editor',
-                meta: {
-                    title: '富文本编辑器',
-                    permiss: '8',
-                },
-                component: () => import(/* webpackChunkName: "editor" */ '../views/editor.vue'),
-            },
-            {
-                path: '/markdown',
-                name: 'markdown',
-                meta: {
-                    title: 'markdown编辑器',
-                    permiss: '9',
-                },
-                component: () => import(/* webpackChunkName: "markdown" */ '../views/markdown.vue'),
-            },
-            {
-                path: '/export',
-                name: 'export',
-                meta: {
-                    title: '导出Excel',
-                    permiss: '2',
-                },
-                component: () => import(/* webpackChunkName: "export" */ '../views/export.vue'),
-            },
-            {
-                path: '/import',
-                name: 'import',
-                meta: {
-                    title: '导入Excel',
-                    permiss: '2',
-                },
-                component: () => import(/* webpackChunkName: "import" */ '../views/import.vue'),
-            },
-        ],
-    },
-    {
-        path: '/login',
-        name: 'Login',
-        meta: {
-            title: '登录',
-        },
-        component: () => import(/* webpackChunkName: "login" */ '../views/login.vue'),
-    },
-    {
-        path: '/403',
-        name: '403',
-        meta: {
-            title: '没有权限',
-        },
-        component: () => import(/* webpackChunkName: "403" */ '../views/403.vue'),
-    },
-];
-
-const router = createRouter({
-    history: createWebHashHistory(),
-    routes,
-});
-
-router.beforeEach((to, from, next) => {
-    NProgress.start();
-    const role = localStorage.getItem('ms_username');
-    const permiss = usePermissStore();
-    if (!role && to.path !== '/login') {
-        next('/login');
-    } else if (to.meta.permiss && !permiss.key.includes(to.meta.permiss)) {
-        // 如果没有权限,则进入403
-        next('/403');
-    } else {
-        next();
-    }
-});
-
-router.afterEach(() => {
-    NProgress.done()
-})
-
-export default router;
+import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
+import { usePermissStore } from '../store/permiss';
+import Home from '../views/home.vue';
+import NProgress from 'nprogress';
+import 'nprogress/nprogress.css';
+
+const routes: RouteRecordRaw[] = [
+    {
+        path: '/',
+        redirect: '/dashboard',
+    },
+    {
+        path: '/',
+        name: 'Home',
+        component: Home,
+        children: [
+            {
+                path: '/dashboard',
+                name: 'dashboard',
+                meta: {
+                    title: '系统首页',
+                    permiss: '0',
+                },
+                component: () => import(/* webpackChunkName: "dashboard" */ '../views/dashboard.vue'),
+            },
+            {
+                path: '/system-user',
+                name: 'system-user',
+                meta: {
+                    title: '用户管理',
+                    permiss: '11',
+                },
+                component: () => import(/* webpackChunkName: "system-user" */ '../views/system/user.vue'),
+            },
+            {
+                path: '/system-role',
+                name: 'system-role',
+                meta: {
+                    title: '角色管理',
+                    permiss: '12',
+                },
+                component: () => import(/* webpackChunkName: "system-role" */ '../views/system/role.vue'),
+            },
+            {
+                path: '/system-menu',
+                name: 'system-menu',
+                meta: {
+                    title: '菜单管理',
+                    permiss: '13',
+                },
+                component: () => import(/* webpackChunkName: "system-menu" */ '../views/system/menu.vue'),
+            },
+            {
+                path: '/table',
+                name: 'basetable',
+                meta: {
+                    title: '基础表格',
+                    permiss: '31',
+                },
+                component: () => import(/* webpackChunkName: "table" */ '../views/table/basetable.vue'),
+            },
+            {
+                path: '/table-editor',
+                name: 'table-editor',
+                meta: {
+                    title: '可编辑表格',
+                    permiss: '32',
+                },
+                component: () => import(/* webpackChunkName: "table-editor" */ '../views/table/table-editor.vue'),
+            },
+            {
+                path: '/schart',
+                name: 'schart',
+                meta: {
+                    title: 'schart图表',
+                    permiss: '41',
+                },
+                component: () => import(/* webpackChunkName: "schart" */ '../views/chart/schart.vue'),
+            },
+            {
+                path: '/echarts',
+                name: 'echarts',
+                meta: {
+                    title: 'echarts图表',
+                    permiss: '42',
+                },
+                component: () => import(/* webpackChunkName: "echarts" */ '../views/chart/echarts.vue'),
+            },
+
+            {
+                path: '/icon',
+                name: 'icon',
+                meta: {
+                    title: '图标',
+                    permiss: '5',
+                },
+                component: () => import(/* webpackChunkName: "icon" */ '../views/pages/icon.vue'),
+            },
+            {
+                path: '/ucenter',
+                name: 'ucenter',
+                meta: {
+                    title: '个人中心',
+                },
+                component: () => import(/* webpackChunkName: "ucenter" */ '../views/pages/ucenter.vue'),
+            },
+            {
+                path: '/editor',
+                name: 'editor',
+                meta: {
+                    title: '富文本编辑器',
+                    permiss: '291',
+                },
+                component: () => import(/* webpackChunkName: "editor" */ '../views/pages/editor.vue'),
+            },
+            {
+                path: '/markdown',
+                name: 'markdown',
+                meta: {
+                    title: 'markdown编辑器',
+                    permiss: '292',
+                },
+                component: () => import(/* webpackChunkName: "markdown" */ '../views/pages/markdown.vue'),
+            },
+            {
+                path: '/export',
+                name: 'export',
+                meta: {
+                    title: '导出Excel',
+                    permiss: '34',
+                },
+                component: () => import(/* webpackChunkName: "export" */ '../views/table/export.vue'),
+            },
+            {
+                path: '/import',
+                name: 'import',
+                meta: {
+                    title: '导入Excel',
+                    permiss: '33',
+                },
+                component: () => import(/* webpackChunkName: "import" */ '../views/table/import.vue'),
+            },
+            {
+                path: '/theme',
+                name: 'theme',
+                meta: {
+                    title: '主题设置',
+                    permiss: '7',
+                },
+                component: () => import(/* webpackChunkName: "theme" */ '../views/pages/theme.vue'),
+            },
+            {
+                path: '/calendar',
+                name: 'calendar',
+                meta: {
+                    title: '日历',
+                    permiss: '24',
+                },
+                component: () => import(/* webpackChunkName: "calendar" */ '../views/element/calendar.vue'),
+            },
+            {
+                path: '/watermark',
+                name: 'watermark',
+                meta: {
+                    title: '水印',
+                    permiss: '25',
+                },
+                component: () => import(/* webpackChunkName: "watermark" */ '../views/element/watermark.vue'),
+            },
+            {
+                path: '/carousel',
+                name: 'carousel',
+                meta: {
+                    title: '走马灯',
+                    permiss: '23',
+                },
+                component: () => import(/* webpackChunkName: "carousel" */ '../views/element/carousel.vue'),
+            },
+            {
+                path: '/tour',
+                name: 'tour',
+                meta: {
+                    title: '分步引导',
+                    permiss: '26',
+                },
+                component: () => import(/* webpackChunkName: "tour" */ '../views/element/tour.vue'),
+            },
+            {
+                path: '/steps',
+                name: 'steps',
+                meta: {
+                    title: '步骤条',
+                    permiss: '27',
+                },
+                component: () => import(/* webpackChunkName: "steps" */ '../views/element/steps.vue'),
+            },
+            {
+                path: '/form',
+                name: 'forms',
+                meta: {
+                    title: '表单',
+                    permiss: '21',
+                },
+                component: () => import(/* webpackChunkName: "form" */ '../views/element/form.vue'),
+            },
+            {
+                path: '/upload',
+                name: 'upload',
+                meta: {
+                    title: '上传',
+                    permiss: '22',
+                },
+                component: () => import(/* webpackChunkName: "upload" */ '../views/element/upload.vue'),
+            },
+            {
+                path: '/statistic',
+                name: 'statistic',
+                meta: {
+                    title: '统计',
+                    permiss: '28',
+                },
+                component: () => import(/* webpackChunkName: "statistic" */ '../views/element/statistic.vue'),
+            },
+        ],
+    },
+    {
+        path: '/login',
+        meta: {
+            title: '登录',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "login" */ '../views/pages/login.vue'),
+    },
+    {
+        path: '/register',
+        meta: {
+            title: '注册',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "register" */ '../views/pages/register.vue'),
+    },
+    {
+        path: '/reset-pwd',
+        meta: {
+            title: '重置密码',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "reset-pwd" */ '../views/pages/reset-pwd.vue'),
+    },
+    {
+        path: '/403',
+        meta: {
+            title: '没有权限',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "403" */ '../views/pages/403.vue'),
+    },
+    {
+        path: '/404',
+        meta: {
+            title: '找不到页面',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "404" */ '../views/pages/404.vue'),
+    },
+    { path: '/:path(.*)', redirect: '/404' },
+];
+
+const router = createRouter({
+    history: createWebHashHistory(),
+    routes,
+});
+
+router.beforeEach((to, from, next) => {
+    NProgress.start();
+    const role = localStorage.getItem('ms_username');
+    const permiss = usePermissStore();
+
+    if (!role && to.meta.noAuth !== true) {
+        next('/login');
+    } else if (to.meta.permiss && !permiss.key.includes(to.meta.permiss)) {
+        // 如果没有权限,则进入403
+        next('/403');
+    } else {
+        next();
+    }
+});
+
+router.afterEach(() => {
+    NProgress.done();
+});
+
+export default router;
diff --git a/src/store/permiss.ts b/src/store/permiss.ts
index 504d78ff..ac505b15 100644
--- a/src/store/permiss.ts
+++ b/src/store/permiss.ts
@@ -1,23 +1,58 @@
-import { defineStore } from 'pinia';
-
-interface ObjectList {
-	[key: string]: string[];
-}
-
-export const usePermissStore = defineStore('permiss', {
-	state: () => {
-		const keys = localStorage.getItem('ms_keys');
-		return {
-			key: keys ? JSON.parse(keys) : <string[]>[],
-			defaultList: <ObjectList>{
-				admin: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'],
-				user: ['1', '2', '3', '11', '13', '14', '15']
-			}
-		};
-	},
-	actions: {
-		handleSet(val: string[]) {
-			this.key = val;
-		}
-	}
-});
+import { defineStore } from 'pinia';
+
+interface ObjectList {
+    [key: string]: string[];
+}
+
+export const usePermissStore = defineStore('permiss', {
+    state: () => {
+        const keys = localStorage.getItem('ms_keys');
+        return {
+            key: keys ? JSON.parse(keys) : <string[]>[],
+            defaultList: <ObjectList>{
+                admin: [
+                    '0',
+                    '1',
+                    '11',
+                    '12',
+                    '13',
+                    '2',
+                    '21',
+                    '22',
+                    '23',
+                    '24',
+                    '25',
+                    '26',
+                    '27',
+                    '28',
+                    '29',
+                    '291',
+                    '292',
+                    '3',
+                    '31',
+                    '32',
+                    '33',
+                    '34',
+                    '4',
+                    '41',
+                    '42',
+                    '5',
+                    '7',
+                    '6',
+                    '61',
+                    '62',
+                    '63',
+                    '64',
+                    '65',
+                    '66',
+                ],
+                user: ['0', '1', '11', '12', '13'],
+            },
+        };
+    },
+    actions: {
+        handleSet(val: string[]) {
+            this.key = val;
+        },
+    },
+});
diff --git a/src/store/sidebar.ts b/src/store/sidebar.ts
index ab7a146d..78d4c54d 100644
--- a/src/store/sidebar.ts
+++ b/src/store/sidebar.ts
@@ -1,15 +1,25 @@
-import { defineStore } from 'pinia';
-
-export const useSidebarStore = defineStore('sidebar', {
-	state: () => {
-		return {
-			collapse: false
-		};
-	},
-	getters: {},
-	actions: {
-		handleCollapse() {
-			this.collapse = !this.collapse;
-		}
-	}
-});
+import { defineStore } from 'pinia';
+
+export const useSidebarStore = defineStore('sidebar', {
+	state: () => {
+		return {
+			collapse: false,
+			bgColor: localStorage.getItem('sidebar-bg-color') || '#324157',
+			textColor: localStorage.getItem('sidebar-text-color') || '#bfcbd9'
+		};
+	},
+	getters: {},
+	actions: {
+		handleCollapse() {
+			this.collapse = !this.collapse;
+		},
+		setBgColor(color: string) {
+			this.bgColor = color;
+			localStorage.setItem('sidebar-bg-color', color);
+		},
+		setTextColor(color: string) {
+			this.textColor = color;
+			localStorage.setItem('sidebar-text-color', color);
+		}
+	}
+});
diff --git a/src/store/tags.ts b/src/store/tabs.ts
similarity index 79%
rename from src/store/tags.ts
rename to src/store/tabs.ts
index 7f8ff18b..b63719e0 100644
--- a/src/store/tags.ts
+++ b/src/store/tabs.ts
@@ -1,53 +1,53 @@
-import { defineStore } from 'pinia';
-
-interface ListItem {
-	name: string;
-	path: string;
-	title: string;
-}
-
-export const useTagsStore = defineStore('tags', {
-	state: () => {
-		return {
-			list: <ListItem[]>[]
-		};
-	},
-	getters: {
-		show: state => {
-			return state.list.length > 0;
-		},
-		nameList: state => {
-			return state.list.map(item => item.name);
-		}
-	},
-	actions: {
-		delTagsItem(index: number) {
-			this.list.splice(index, 1);
-		},
-		setTagsItem(data: ListItem) {
-			this.list.push(data);
-		},
-		clearTags() {
-			this.list = [];
-		},
-		closeTagsOther(data: ListItem[]) {
-			this.list = data;
-		},
-		closeCurrentTag(data: any) {
-			for (let i = 0, len = this.list.length; i < len; i++) {
-				const item = this.list[i];
-				if (item.path === data.$route.fullPath) {
-					if (i < len - 1) {
-						data.$router.push(this.list[i + 1].path);
-					} else if (i > 0) {
-						data.$router.push(this.list[i - 1].path);
-					} else {
-						data.$router.push('/');
-					}
-					this.list.splice(i, 1);
-					break;
-				}
-			}
-		}
-	}
-});
+import { defineStore } from 'pinia';
+
+interface ListItem {
+	name: string;
+	path: string;
+	title: string;
+}
+
+export const useTabsStore = defineStore('tabs', {
+	state: () => {
+		return {
+			list: <ListItem[]>[]
+		};
+	},
+	getters: {
+		show: state => {
+			return state.list.length > 0;
+		},
+		nameList: state => {
+			return state.list.map(item => item.name);
+		}
+	},
+	actions: {
+		delTabsItem(index: number) {
+			this.list.splice(index, 1);
+		},
+		setTabsItem(data: ListItem) {
+			this.list.push(data);
+		},
+		clearTabs() {
+			this.list = [];
+		},
+		closeTabsOther(data: ListItem[]) {
+			this.list = data;
+		},
+		closeCurrentTag(data: any) {
+			for (let i = 0, len = this.list.length; i < len; i++) {
+				const item = this.list[i];
+				if (item.path === data.$route.fullPath) {
+					if (i < len - 1) {
+						data.$router.push(this.list[i + 1].path);
+					} else if (i > 0) {
+						data.$router.push(this.list[i - 1].path);
+					} else {
+						data.$router.push('/');
+					}
+					this.list.splice(i, 1);
+					break;
+				}
+			}
+		}
+	}
+});
diff --git a/src/store/theme.ts b/src/store/theme.ts
new file mode 100644
index 00000000..faf228d2
--- /dev/null
+++ b/src/store/theme.ts
@@ -0,0 +1,58 @@
+import { mix, setProperty } from '@/utils';
+import { defineStore } from 'pinia';
+
+export const useThemeStore = defineStore('theme', {
+    state: () => {
+        return {
+            primary: '',
+            success: '',
+            warning: '',
+            danger: '',
+            info: '',
+            headerBgColor: '#242f42',
+            headerTextColor: '#fff',
+        };
+    },
+    getters: {},
+    actions: {
+        initTheme() {
+            ['primary', 'success', 'warning', 'danger', 'info'].forEach((type) => {
+                const color = localStorage.getItem(`theme-${type}`) || '';
+                if (color) {
+                    this.setPropertyColor(color, type); // 设置主题色
+                }
+            });
+            const headerBgColor = localStorage.getItem('header-bg-color');
+            headerBgColor && this.setHeaderBgColor(headerBgColor);
+            const headerTextColor = localStorage.getItem('header-text-color');
+            headerTextColor && this.setHeaderTextColor(headerTextColor);
+        },
+        resetTheme() {
+            ['primary', 'success', 'warning', 'danger', 'info'].forEach((type) => {
+                this.setPropertyColor('', type); // 重置主题色
+            });
+        },
+        setPropertyColor(color: string, type: string = 'primary') {
+            this[type] = color;
+            setProperty(`--el-color-${type}`, color);
+            localStorage.setItem(`theme-${type}`, color);
+            this.setThemeLight(type);
+        },
+        setThemeLight(type: string = 'primary') {
+            [3, 5, 7, 8, 9].forEach((v) => {
+                setProperty(`--el-color-${type}-light-${v}`, mix('#ffffff', this[type], v / 10));
+            });
+            setProperty(`--el-color-${type}-dark-2`, mix('#ffffff', this[type], 0.2));
+        },
+        setHeaderBgColor(color: string) {
+            this.headerBgColor = color;
+            setProperty('--header-bg-color', color);
+            localStorage.setItem(`header-bg-color`, color);
+        },
+        setHeaderTextColor(color: string) {
+            this.headerTextColor = color;
+            setProperty('--header-text-color', color);
+            localStorage.setItem(`header-text-color`, color);
+        }
+    }
+});
\ No newline at end of file
diff --git a/src/types/form-option.ts b/src/types/form-option.ts
new file mode 100644
index 00000000..8432704c
--- /dev/null
+++ b/src/types/form-option.ts
@@ -0,0 +1,21 @@
+export interface FormOption {
+    list: FormOptionList[];
+    labelWidth?: number | string;
+    span?: number;
+
+}
+
+export interface FormOptionList {
+    prop: string;
+    label: string;
+    type: string;
+    placeholder?: string;
+    disabled?: boolean;
+    opts?: any[];
+    format?: string;
+    activeValue?: any;
+    inactiveValue?: any;
+    activeText?: string;
+    inactiveText?: string;
+    required?: boolean;
+}
\ No newline at end of file
diff --git a/src/types/menu.ts b/src/types/menu.ts
new file mode 100644
index 00000000..8002ac08
--- /dev/null
+++ b/src/types/menu.ts
@@ -0,0 +1,9 @@
+export interface Menus {
+    id: string;
+    pid?: string;
+    icon?: string;
+    index: string;
+    title: string;
+    permiss?: string;
+    children?: Menus[];
+}
\ No newline at end of file
diff --git a/src/types/role.ts b/src/types/role.ts
new file mode 100644
index 00000000..26d4ace1
--- /dev/null
+++ b/src/types/role.ts
@@ -0,0 +1,8 @@
+
+export interface Role {
+    id: number;
+    name: string;
+    key: string;
+    status: boolean;
+    permiss: string[]
+}
\ No newline at end of file
diff --git a/src/types/table.ts b/src/types/table.ts
new file mode 100644
index 00000000..578f4621
--- /dev/null
+++ b/src/types/table.ts
@@ -0,0 +1,9 @@
+export interface TableItem {
+    id: number;
+    name: string;
+    thumb: string;
+    money: number;
+    state: string;
+    date: string;
+    address: string;
+}
\ No newline at end of file
diff --git a/src/types/user.ts b/src/types/user.ts
new file mode 100644
index 00000000..42695c84
--- /dev/null
+++ b/src/types/user.ts
@@ -0,0 +1,16 @@
+
+export interface User {
+    id: number;
+    name: string;
+    password: string;
+    email: string;
+    phone: string;
+    role: string;
+    date: string;
+}
+
+export interface Register {
+    username: string;
+    password: string;
+    email: string;
+}
\ No newline at end of file
diff --git a/src/utils/china.ts b/src/utils/china.ts
new file mode 100644
index 00000000..c2042104
--- /dev/null
+++ b/src/utils/china.ts
@@ -0,0 +1,3 @@
+let chinaMap:any = {"type":"FeatureCollection","features":[{"id":"710000","geometry":{"type":"MultiPolygon","coordinates":[["@@°Ü¯Û","@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚäœnÜƤɊĂǀĆĴžĤNJŨxĚĮǂƺòƌ‚–âÔ®ĮXŦţƸZûЋƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ™¿IċããF¥ĘWǬÏĶñÄ","@@\\p|WoYG¿¥I†j@ž","@@…¡‰@ˆV^RqˆBbAŒnTXe„†žQr™©C","@@ÆEE—„kWqë Iœ"]],"encodeOffsets":[[[122886,24033],[123335,22980],[122375,24193],[122518,24117],[124427,22618]]]},"properties":{"cp":[121.509062,25.044332],"name":"台湾","childNum":5}},{"id":"130000","geometry":{"type":"MultiPolygon","coordinates":[["@@\\a“M`ǽÓnUK…Ĝēs¤­©yrý§uģŒc†JŠ»eIˆ€P]‚ªr‰ºc_ħ²G¼s`jΟnüsœľP","@@U`Ts¿mĂ","@@FŸƒ•›Oh‡đ©OŸ›iÃ`ww^ƒÌkŸ‘ÑH«ƇǤŗĺtFu…{Z}Ö@U‡´…ʚLg®¯Oı°ÃwŸ ^˜—€VbÉs‡ˆmA…ê]]w„§›RRl£‡ŭuw›N—Á`ÇFēÝčȻŽuT¡Ĺ—¯Õ¯sŗő£YªhV’ƍ£ƅnëYNgƒq¼ś¿µı²UºÝUąŽąŖóŒxV@tˆƯŒJ”]eƒR¾fe|rHA˜|h~Ėƍl§ÏŠjVë` ØoˆÅbbx³^zÃĶš¶Sj®A”yÂhðk`š«P€”ˈµEF†Û¬Y¨Ļrõqi¼‰Wi°§’б²°`[ˆÀ|ĠO@ÆxO\\tŽa\\p_Zõ^û{ġŒȧXýĪÓjùÎRb›š^λj{íděYfíÙTyŽ‰mńŵōHim½’éŅ­aVcř§ax¹XŻác‡žWU£ôãºQ¨÷Ñws¥qEH‰Ù|‰›šYQoŕÇyáĂ£MðoťÊ‰P¡mšWO¡€v†{ôvîēÜISpÌhp¨ ‘j†deŔQÖj˜X³à™Ĉ[n`Yp@Už–cM`’RKhŒEbœ”pŞlNut®Etq‚nsÁŠgA‹iú‹oH‡qCX‡”hfgu“~ϋWP½¢G^}¯ÅīGCŸÑ^ãziMáļMTÃƘrMc|O_ž¯Ŏ´|‡morDkO\\mĆJfl@cĢ¬¢aĦtRıҙXòë¬WP{ŵǫƝ…›īÛ÷ąV×qƥV¿aȉd³B›qPBm›aËđŻģm“Å®VŠ¹d^K‡KoŸnYg“¯Xhqa”Ldu¥•ÍpDž¡KąÅƒkĝęěhq‡}HyÓ]¹ǧ£…Í÷¿qá•gPmoeœi‰¤o^á¾ZE‡˜Y^…Ný{n•ƒOl±Í“@M’ċèk§da‹‘NaÇį¿]ø‰RiiñE‰€ū‹i„DZàUtėGylƒ}ŒÓM}€jpEC~¡FtoQi‘šHkk{ILgĽxqÈƋÄd–eVŽDJj£€J|Ådz•Ft~žKŨ¸IÆv|”‡¢r}膎onb˜}`RÎÄn°ÒdÞ²„^®’lnÐèĄlðӜ×]ªÆ}LiĂ±Ö`^°Ç¶p®đDcœŋ`–ZÔ’¶êqvFƚ†N®ĆTH®¦O’¾ŠIbÐã´BĐɢŴÆíȦp–ĐÞXR€·nndOž¤’OÀĈƒ­Qg˜µFo|gȒęSWb©osx|hYh•gŃfmÖĩnº€T̒Sp›¢dYĤ¶UĈjl’ǐpäðëx³kÛfw²Xjz~ÂqbTŠÑ„ěŨ@|oM‡’zv¢ZrÃVw¬ŧĖ¸fŒ°ÐT€ªqŽs{Sž¯r æÝl¼ÖĞ džiGʂJ™¼lr}~K¨ŸƐÌWö€™¼œÞ°nÞoĦLš†|C~“D©|q]SvK€ÑcwpÏρ†ĿćènĪWlĄkT}¬Tpš~ƒ®Hgd„‰†˒劔ŽBVt„EÀ¢ôPĎƗè@~‚k–ü\\rÊĔÖæW_§¼F˜†´©òDòj’ˆYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkv‚GpuARhÞÆǶgʊTǼƹS£¨¡ù³ŘÍ]¿Ây™ôEP xX¶¹܇O¡“gÚ¡IwÃ鑦ÅB‡Ï|Ç°…N«úmH¯‹âŸbę†U~xĈbȒ{^xÖlDž•¸dɂ‡„~"]],"encodeOffsets":[[[120023,41045],[121616,39981],[122102,42307]]]},"properties":{"cp":[114.502461,38.045474],"name":"河北","childNum":3}},{"id":"140000","geometry":{"type":"Polygon","coordinates":["@@žħÜ_ªlìwGkÛÃǏok‘ćiµVZģ¡coœ‘TS˹ĪmnÕńe–hZg{gtwªpXaĚThȑp{¶Eh—®RćƑP¿£‘PmcªaJyý{ƒýȥoÅîɡųAďä³aωJ‘½¥PG­ąSM­sWz½µÛ€‘YӀŖgxoOkĒCo­Èµ]¯_²ÕjāŽK~©ÅØ^ԛkïçămϑk]­±ƒcݯÑÃmQÍ~_a—pm…~ç¡q“ˆu{JÅŧ·Ls}–EyÁÆcI{¤IiCfUc•ƌÃp§]웫vD@¡SÀ‘µM‚ÅwuŽYY‡¡DbÑc¡hƒ×]nkoQdaMç~eD•ÛtT‰©±@¥ù@É¡‰ZcW|WqOJmĩl«ħşvOÓ«IqăV—¥ŸD[mI~Ó¢cehiÍ]Ɠ~ĥqXŠ·eƷœn±“}v•[ěďŽŕ]_‘œ•`‰¹ƒ§ÕōI™o©b­s^}Ét±ū«³p£ÿ¥WÑxçÁ«h×u׌¥ř„‹¾dÒ{ºvĴÎêÌɊ²¶€ü¨|ÞƸµȲ‘LLúÉƎ¤ϊęĔV`„_bª‹S^|ŸdŠzY|dz¥p†ZbÆ£¶ÒK}tĦÔņƠ‚PYzn€ÍvX¶Ěn ĠÔ„zý¦ª˜÷žÑĸَUȌ¸‚dòÜJð´’ìúNM¬ŒXZ´‘¤ŊǸ_tldIš{¦ƀðĠȤ¥NehXnYG‚‡R° ƬDj¬¸|CĞ„Kq‚ºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBŒÊ”TœĞšHƘÁĪËĖ’šĴŞ–ȀœÆÿȄlŤĒö„t”νî¼ĨXhŒ‘˜|ªM¤ÐzÞĩ҃S‰rao³"],"encodeOffsets":[[117016,41452]]},"properties":{"cp":[112.549248,37.857014],"name":"山西","childNum":1}},{"id":"150000","geometry":{"type":"MultiPolygon","coordinates":[["@@ǪƫÌÛM…Ă[`՞Cn}¶Vc…ê“sƒ–¯‹PqƒFB…‰|S•³C|kñ•H‹d‘iÄ¥sˆʼnő…PóÑÑE^‘ÅPpy_YtS™hQ·aHwsOnʼnÚs©iqj›‰€USiº]ïWš‰«gW¡A–R붛ijʕ…Œů`çõh]y»ǃŸǛҤxÒm~zf}pf|ÜroÈzrKÈĵSƧ„ż؜Ġu~è¬vîS¼™Ăh–šĖMÈÄw‚\\fŦ°W ¢¾luŸD„wŠ\\Ŗĝ","@@ƒGVu»A—ylßí¹ãe’“]Eāò³C¹ð“¾ˆ²iŒÒAdkò^P“²CǜңDŽ z¼g^èöŰ_‹‚–†IJĕꄜ}gÁnUI«m‰…„‹]j‡vV¼euhwqA„aW˜ƒ_µj…»çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáG“›OUۗOB±•XŸkŇ¹£k|e]ol™ŸkVͼÕqtaÏõjgÁ£§U^Œ”RLˆËnX°Ç’Bz†^~wfvˆypV ¯„ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyx‹þp]Évïè‘vƀnÂĴÖ@‚‰†V~Ĉ™Š³MEˆĸÅĖt—ējyÄDXÄxGQuv_›i¦aBçw‘˛wD™©{ŸtāmQ€{EJ§KPśƘƿ¥@‰sCT•É}ɃwˆƇy±ŸgÑ“}T[÷kÐ禫…SÒ¥¸ëBX½‰HáŵÀğtSÝÂa[ƣ°¯¦P]£ġ“–“Òk®G²„èQ°óMq}EŠóƐÇ\\ƒ‡@áügQ͋u¥Fƒ“T՛¿Jû‡]|mvāÎYua^WoÀa·­ząÒot׶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶—ˆ¿A•†‹[¡Œ{d×uQAƒ›M•xV‹vMOmăl«ct[wº_šÇʊŽŸjb£ĦS_é“QZ“_lwgOiýe`YYJq¥IÁˆdz£ÙË[ÕªuƏ³ÍT—s·bÁĽäė[›b[ˆŗfãcn¥îC¿÷µ[ŏÀQ­ōšĉm¿Á^£mJVm‡—L[{Ï_£›F¥Ö{ŹA}…×Wu©ÅaųijƳhB{·TQqÙIķˑZđ©Yc|M¡…L•eVUóK_QWk’_ĥ‘¿ãZ•»X\\ĴuUƒè‡lG®ěłTĠğDє›žG‚ÆÍz]‹±…ŭ©ŸÅ’]ŒÅÐ}UË¥©Tċ™ïxgckfWgi\\ÏĒ¥HkµE˜ë{»ÏetcG±ahUiñiWsɁˆ·c–C‚Õk]wȑ|ća}w…VaĚ᠞ŒG°ùnM¬¯†{ȈÐÆA’¥ÄêJxÙ¢”hP¢Ûˆº€µwWOŸóFŽšÁz^ÀŗÎú´§¢T¤ǻƺSė‰ǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇq‡Z‘ñiñC³ª—…»E`¨åXēÕqÉû[l•}ç@čƘóO¿¡ƒFUsA‰“ʽīccšocƒ‚ƒÇS}„“£‡IS~ălkĩXçmĈ…ŀЂoÐdxÒuL^T{r@¢‘žÍƒĝKén£kQ™‰yšÅõËXŷƏL§~}kqš»IHėDžjĝŸ»ÑÞoŸå°qTt|r©ÏS‹¯·eŨĕx«È[eMˆ¿yuˆ‘pN~¹ÏyN£{©’—g‹ħWí»Í¾s“əšDž_ÃĀɗ±ą™ijĉʍŌŷ—S›É“A‹±åǥɋ@럣R©ąP©}ĹªƏj¹erƒLDĝ·{i«ƫC½ÉshVz…GS|úþX”gp›{ÁX¿Ÿć{ƱȏñZáĔyoÁhA™}ŅĆfdʼn„_¹„Y°ėǩÑ¡H¯¶oMQqð¡Ë™|‘Ñ`ƭŁX½·óۓxğįÅcQ‡ˆ“ƒs«tȋDžF“Ÿù^i‘t«Č¯[›hAi©á¥ÇĚ×l|¹y¯Kȝqgů{ñǙµï‚ċ™Ĺz—Śȭ¶¡˜›oŽäÕG\\ďT¿Òõr¯œŸLguÏYęRƩšɷŌO\\İТæ^Ŋ IJȶȆbÜGŽĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľƒ]ėl¥Ë‡ĭûÁ„ƒėéV©±ćn©­ȇžÍq¯½•YÃÔʼn“ÉNѝÅÝy¹NqáʅDǡËñ­ƁYÅy̱os§ȋµʽǘǏƬɱà‘ưN¢ƔÊuľýľώȪƺɂļžxœZĈ}ÌʼnŪ˜ĺœŽĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~Ǎ›¼ȳÐUf†dIxÿ\\G ˆzâɏÙOº·pqy£†@ŒŠqþ@Ǟ˽IBäƣzsÂZ†ÁàĻdñ°ŕzéØűzșCìDȐĴĺf®ŽÀľưø@ɜÖÞKĊŇƄ§‚͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФԂ¤ƌžĞ̪Qʤ´¼mȠJˀŸƲÀɠmɆŠDŽĜƠ´ǠN~€ʢĜ‚¶ƌĆĘźʆȬ˪ĚĒ¸ĞGȖƴƀj`ĢçĶāàŃºēĢƒĖćšYŒÀŎüôQÐÂŎŞdžŞêƖš˜oˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^žªƂ`ªt¾äƚêĦĀ¼Ð€Ĕǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDĝŒ|ø˂˜ƮÐ¬ɚwɲFjĔ²Äw°dždÀɞ_ĸdîàŎjʜêTЪŌ‡ŜWÈ|tqĢUB~´°ÎFC•ŽU¼pĀēƄN¦¾O¶ŠłKĊOj“Ě”j´ĜYp˜{¦„ˆSĚÍ\\Tš×ªV–÷Ší¨ÅDK°ßtŇĔKš¨ǵÂcḷ̌ĚǣȄĽF‡lġUĵœŇ‹ȣFʉɁƒMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFŽxúQ„Er´W„rh¤Ɛ \\talĈDJ˜Ü|[Pll̚¸ƎGú´Pž¬W¦†^¦–H]prR“n|or¾wLVnÇIujkmon£cX^Bh`¥V”„¦U¤¸}€xRj–[^xN[~ªŠxQ„‚[`ªHÆÂExx^wšN¶Ê˜|¨ì†˜€MrœdYp‚oRzNy˜ÀDs~€bcfÌ`L–¾n‹|¾T‚°c¨È¢a‚r¤–`[|òDŞĔöxElÖdH„ÀI`„Ď\\Àì~ƎR¼tf•¦^¢ķ¶e”ÐÚMŒptgj–„ɡČÅyġLû™ŇV®ŠÄÈƀ†Ď°P|ªVV†ªj–¬ĚÒêp¬–E|ŬÂ_~¼rƐK fˆ{ĘFĒœƌXưăkÃĄ}nµ–oŸ×q£ç­kX‘{uĩ«āíÓUŅÝVUŌ]€Ť¥lyň[€oi{¦‹L‡ĸ…Ħ^ôâJˆ¨^UZðڔĒL„¿Ì‹ˆfŒ£K£ʺ™oqNŸƒwğc`ue—tOj×°KJ±qƒÆġm‰Ěŗos¬…qehqsuœƒH{¸kH¡Š…ÊRǪÇƌbȆ¢´ä܍¢NìÉʖ¦â©Ɨؗ"]],"encodeOffsets":[[[128500,52752],[127089,51784]]]},"properties":{"cp":[111.670801,40.818311],"name":"内蒙古","childNum":2}},{"id":"210000","geometry":{"type":"MultiPolygon","coordinates":[["@@L–Ž@@s‘]","@@MnNm","@@d†c","@@eÀ‚C@b‚“‰","@@f‡…Xwkbr–Ä`qg","@@^jtWQ","@@~ Y[c","@@I`ĖN^_¿Z‚ÁM","@@Ïxnj{q_×^Gigp","@@iX¶B…Y","@@„Y…Z","@@L_yG`b","@@^WqCTZ","@@\\[“‹§t|”ž]","@@m`p[","@@@œé^B†‡ntˆaÊU—˜Ÿ]x ¯ÄPIJ­°h€ʙK³†VˆÕ@Y~†|EvĹsDŽ¦­L^p²ŸÒG ’Ël]„xxÄ_˜fT¤Ď¤cŽœP„–C¨¸TVjbgH²sdÎdHt`Bˆ—²¬GJję¶[ÐhjeXdlwhšðSȦªVÊπ‹Æ‘Z˜ÆŶ®²†^ŒÎyÅ‚Hœń“ĚDMħĜŁH­ˆk„çvV[ij¼W–‚YÀäĦ’‘`XlžR`žôLUVžfK–¢†{NZdĒª’YĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~†źBŽ|¦ÕœEž¤Ð`\\|Kˆ˜UnnI]¤ÀÂĊnŎ™R®Ő¿¶\\ÀøíDm¦ÎbŨab‰œaĘ\\ľã‚¸a˜tÎSƐ´©v\\ÖÚÌǴ¤Â‡¨JKr€Z_Z€fjþhPkx€`Y”’RIŒjJcVf~sCN¤ ˆE‚œhæm‰–sHy¨SðÑÌ\\\\ŸĐRÊwS¥fqŒßýáЍÙÉÖ[^¯ǤŲ„ê´\\¦¬ĆPM¯£Ÿˆ»uïpùzEx€žanµyoluqe¦W^£ÊL}ñrkqWňûP™‰UP¡ôJŠoo·ŒU}£Œ„[·¨@XŒĸŸ“‹‹DXm­Ûݏº‡›GU‹CÁª½{íĂ^cj‡k“¶Ã[q¤“LÉö³cux«|Zdƒ²BWÇ®Yß½ve±ÃC•ý£W{Ú^’q^sÑ·¨‹ËMƒr“¹·C¥‡GD›rí@wÕKţ݋˜Ÿ«V·i}xËÍ÷‘i©ĝ‡ɝǡ]ƒˆ{c™±OW‹³Ya±Ÿ‰_穂Hžĕoƫ€Ňqƒr³‰Lys[„ñ³¯OS–ďOMisZ†±ÅFC¥Pq{‚Ã[Pg}\\—¿ghćO…•k^ĩÁXaĕËĥM­oEqqZûěʼn³F‘¦oĵ—hŸÕP{¯~TÍlª‰N‰ßY“Ð{Ps{ÃVU™™eĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀff‘dF~ˆ€ĀeĖ€d`sx² šƒ®EĦ¦–šdQ‹Âd^~ăÔHˆ¦\\›LKpĄVez¤NP ǹӗR™ÆąJSh­a[¦´Âghwm€BÐ¨źhI|žVVŽ—Ž|p] Â¼èNä¶ÜBÖ¼“L`‚¼bØæŒKV”ŸpoœúNZÞÒKxpw|ÊEMnzEQšŽIZ”ŽZ‡NBˆčÚFÜçmĩ‚WĪñt‘ÞĵÇñZ«uD‚±|ƏlǗw·±PmÍa‰–da‡ CL‡Ǒkùó¡³Ï«QaċϑOÃ¥ÕđQȥċƭy‹³ÁA"]],"encodeOffsets":[[[123686,41445],[126019,40435],[124393,40128],[126117,39963],[125322,40140],[126686,40700],[126041,40374],[125584,40168],[125509,40217],[125453,40165],[125362,40214],[125280,40291],[125774,39997],[125976,40496],[125822,39993],[122731,40949]]]},"properties":{"cp":[123.429096,41.796767],"name":"辽宁","childNum":16}},{"id":"220000","geometry":{"type":"Polygon","coordinates":["@@ñr½ÉKāGÁ¤ia É‰™È¹`\\xs€¬dĆkNnuNUŒ–wœNx¶c¸‹|\\¢…ŒGªóĄ~RãÖÎĢù‚đŴÕhQŽxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp‚]vbÍZuĂ{nˆ^IüœÀSք”¦EŒvRÎûh@℈[‚Əȉô~FNr¯ôçR±ƒ­HÑl•’Ģ–^¤¢‚OðŸŽætxsŒ]ÞÁTĠs¶¿âƊGW¾ìA¦·TѬ†è¥€ÏÐJ¨¼ÒÖ¼ƒƦɄxÊ~S–tD@ŠĂ¼Ŵ¡jlºWžvЉˆzƦZЎ²CH— „Axiukd‹ŒGgetqmcžÛ£Ozy¥cE}|…¾cZ…k‚‰¿uŐã[oxGikfeäT@…šSUwpiÚFM©’£è^ڟ‚`@v¶eň†f h˜eP¶žt“äOlÔUgƒÞzŸU`lœ}ÔÆUvØ_Ō¬Öi^ĉi§²ÃŠB~¡Ĉ™ÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYx‘ƘDVÇĺĿg¿cwÅ\\¹˜¥Yĭlœ¤žOv†šLjM_a W`zļMž·\\swqÝSA‡š—q‰Śij¯Š‘°kŠRē°wx^Đkǂғ„œž“œŽ„‹\\]˜nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°“G³¼XÀ““™¤¹i´o¤ŃšŸÈ`̃DzÄUĞd\\i֚ŒˆmÈBĤÜɲDEh LG¾ƀľ{WaŒYÍȏĢĘÔRîĐj‹}Ǟ“ccj‡oUb½š{“h§Ǿ{K‹ƖµÎ÷žGĄØŜçưÌs«l›•yiē«‹`姝H¥Ae^§„GK}iã\\c]v©ģZ“mÃ|“[M}ģTɟĵ‘Â`À–çm‰‘FK¥ÚíÁbXš³ÌQґHof{‰]e€pt·GŋĜYünĎųVY^’˜ydõkÅZW„«WUa~U·Sb•wGçǑ‚“iW^q‹F‚“›uNĝ—·Ew„‹UtW·Ýďæ©PuqEzwAV•—XR‰ãQ`­©GŠY…Yhc•UGorBd}ģɇb¡·µMicF«—YƅŒ»…é\\ƒɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ý‘L¡‘ûŸsT\\rke™\\PnwAK‚y}’ywdS™efµ]UhĿD@mÿvašÙNSkCun…cÿ`l‚‰W‹„ėVâ¦÷~^fÏ~œvwHCŽį„`xqT­­ƒlW«ï¸skm‹‹ßEG“qd¯•‹R…©ÝŽ¯¯S†\\cZ¹iűƏCuƍÓX‡oR}“M^o•£…R}oªU­F…uuXHlEŕ‡€Ï©¤ßgXˆþ¤D–²ÄufàÀ­XXȱAc„{Yw¬dvõ´KÊ£”\\rµÄl”iˆdā]|DÂVŒœH¹ˆÞ®ÜWnŒC”Œķ W‹§@\\¸‹ƒ~¤‹Vp¸‰póIO¢ŠVOšŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúvð‡¼¤ N°ąO¥«³[ƒéǣű]°Õ\\ÚÊĝŽôîŇÔaâŸBYlďQ[ Ë[ïÒ¥RI|‘`jž]P"],"encodeOffsets":[[126831,44503]]},"properties":{"cp":[125.3245,43.886841],"name":"吉林","childNum":1}},{"id":"230000","geometry":{"type":"MultiPolygon","coordinates":[["@@UƒµNÿ¥īè灋•HÍøƕ¶LŒǽ|g¨|”™Ža¾pViˆdd”~ÈiŒíďÓQġėǐZ΋ŽXb½|ſÃH½ŸKFgɱCģÛÇA‡n™‹jÕc[VĝDZÃ˄Ç_™ £ń³pŽj£º”š¿”»WH´¯”U¸đĢmžtĜyzzNN|g¸÷äűѱĉā~mq^—Œ[ƒ”››”ƒǁÑďlw]¯xQĔ‰¯l‰’€°řĴrŠ™˜BˆÞTxr[tŽ¸ĻN_yŸX`biN™Ku…P›£k‚ZĮ—¦[ºxÆÀdhŽĹŀUÈƗCw’áZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFćš}¢‰A±Äj¨]ĊÕjŋ«×`VuÓś~_kŷVÝyh„“VkÄãPs”Oµ—fŸge‚Ň…µf@u_Ù ÙcŸªNªÙEojVx™T@†ãSefjlwH\\pŏäÀvŠŽlY†½d{†F~¦dyz¤PÜndsrhf‹HcŒvlwjFœ£G˜±DύƥY‡yϊu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|Cš˜zxAè¥bœfudTrFWÁ¹Am|˜ĔĕsķÆF‡´Nš‰}ć…UŠÕ@Áijſmužç’uð^ÊýowŒFzØÎĕNőžǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°ƒUŸzou‡xe]}Ž…AyȑW¯ÌmK‡“Q]‹Īºif¸ÄX|sZt|½ÚUΠlkš^p{f¤lˆºlÆW –€A²˜PVܜPH”Êâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi†`¶—„bXƒrBgxfv»ŽuUiˆŒ^v~”J¬mVp´£Œ´VWrnP½ì¢BX‚¬h™ŠðX¹^TjVœŠriªj™tŊÄm€tPGx¸bgRšŽsT`ZozÆO]’ÒFô҆Oƒ‡ŊŒvŞ”p’cGŒêŠsx´DR–Œ{A†„EOr°Œ•žx|íœbˆ³Wm~DVjºéNN†Ëܲɶ­GƒxŷCStŸ}]ûō•SmtuÇÃĕN•™āg»šíT«u}ç½BĵÞʣ¥ëÊ¡Mێ³ãȅ¡ƋaǩÈÉQ‰†G¢·lG|›„tvgrrf«†ptęŘnŠÅĢr„I²¯LiØsPf˜_vĠd„xM prʹšL¤‹¤‡eˌƒÀđK“žïÙVY§]I‡óáĥ]ķ†Kˆ¥Œj|pŇ\\kzţ¦šnņäÔVĂîĪ¬|vW’®l¤èØr‚˜•xm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄ–Ą»ƢjȦOǺ¨ìSŖÆƬy”Qœv`–cwƒZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨS’Œfm Ċ‚ƀP̎ēz©Ċ‚ÄÕÊmgŸÇsJ¥ƔˆŊśæ’΁Ñqv¿íUOµª‰ÂnĦÁ_½ä@ê텣P}Ġ[@gġ}g“ɊדûÏWXá¢užƻÌsNͽƎÁ§č՛AēeL³àydl›¦ĘVçŁpśdžĽĺſʃQíÜçÛġԏsĕ¬—Ǹ¯YßċġHµ ¡eå`ļƒrĉŘóƢFì“ĎWøxÊk†”ƈdƬv|–I|·©NqńRŀƒ¤é”eŊœŀ›ˆàŀU²ŕƀB‚Q£Ď}L¹Îk@©ĈuǰųǨ”Ú§ƈnTËÇéƟÊcfčŤ^Xm‡—HĊĕË«W·ċëx³ǔķÐċJā‚wİ_ĸ˜Ȁ^ôWr­°oú¬Ħ…ŨK~”ȰCĐ´Ƕ£’fNÎèâw¢XnŮeÂÆĶŽ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®‚ØCÔ ŬGƠ”ƦYĜ‡ĘÜƬDJ—g_ͥœ@čŅĻA“¶¯@wÎqC½Ĉ»NŸăëK™ďÍQ“Ùƫ[«Ãí•gßÔÇOÝáW‘ñuZ“¯ĥ€Ÿŕā¡ÑķJu¤E Ÿå¯°WKɱ_d_}}vyŸõu¬ï¹ÓU±½@gÏ¿rýD‰†g…Cd‰µ—°MFYxw¿CG£‹Rƛ½Õ{]L§{qqąš¿BÇƻğëšܭNJË|c²}Fµ}›ÙRsÓpg±ŠQNqǫŋRwŕnéÑÉKŸ†«SeYR…ŋ‹@{¤SJ}šD Ûǖ֍Ÿ]gr¡µŷjqWÛham³~S«“„›Ü[","@@ƨƒĶTLÇyqpÇÛqe{~oyen}s‰`q‡iXG”ù]Ëp½“©lɇÁp]Þñ´FÔ^f‘äîºkà˜z¼BUv¬D"]],"encodeOffsets":[[[134456,44547],[127123,51780]]]},"properties":{"cp":[126.642464,45.756967],"name":"黑龙江","childNum":2}},{"id":"320000","geometry":{"type":"Polygon","coordinates":["@@Õg^vÁbnÀ‹`Jnĝ¬ŽòM¶ĘšTÖŒb‚˜e¦¦€{¸ZâćNpŒ©žHp|`ˆmjhŠSEb\\afv`sz^lkŽlj‹Ätg‹¤D˜­¾Xš¿À’|ДiZ„ȀåB·î}GL¢õcßjaŸyBFµÏC^ĭ•cÙt¿sğH]j{s©HM¢ƒQnDÀ©DaÜތ·jgàiDbPufjDk`dPOîƒhw¡ĥ‡¥šG˜ŸP²ĐobºrY†„î¶aHŢ´ ]´‚rılw³r_{£DB_Ûdåuk|ˆŨ¯F Cºyr{XFy™e³Þċ‡¿Â™kĭB¿„MvÛpm`rÚã”@Ę¹hågËÖƿxnlč¶Åì½Ot¾dJlŠVJʜǀœŞqvnOŠ^ŸJ”Z‘ż·Q}ê͎ÅmµÒ]Žƍ¦Dq}¬R^èĂ´ŀĻĊIԒtžIJyQŐĠMNtœR®òLh‰›Ěs©»œ}OӌGZz¶A\\jĨFˆäOĤ˜HYš†JvÞHNiÜaϚɖnFQlšNM¤ˆB´ĄNöɂtp–ŬdZÅgl•muÇUšŽ“އÚb¤uŃJŴu»¹Ą•lȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Y™rřl¥’i`ã__¢ćSÅr[Çq^ùzWmOĈaŐÝɞï²ʯʊáĘijĒǭPħ͍ôƋĝÄ͎ī‰çÛɈǥ£­ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ—¡RLčiXy‡ÅNïă¡¸iĔϑNÌķoıdōîåŤûHcs}~Ûwbù¹£¦ÓCt‹OPrƒE^ÒoŠg™ĉIµžÛÅʹK…¤½phMˆú`m”R¸¦Pƚg†ÉLRŠs`£¯ãhD„¨|³¤‰C"],"encodeOffsets":[[121451,32518]]},"properties":{"cp":[118.767413,32.041544],"name":"江苏","childNum":1}},{"id":"330000","geometry":{"type":"MultiPolygon","coordinates":[["@@jX^n…","@@sfˆdM‰","@@qP\\xz[_i","@@o\\V’zRZ}mECy","@@‘Rƒ¢‚FX}°[m]","@@Cbœ\\•}","@@e|v\\laus","@@v~s{","@@QxÂF©}","@@¹nŒvÞs©m","@@rQgYIh","@@bi«Z„X","@@p[}ILd","@@À¿|","@@¹dnb’…","@@rS}[Kl","@@g~h}","@@FlCk","@@ůTG°ĄLHm°UF‰","@@OdRe","@@v[u\\","@@FjâL~wyoo~›sµLŒZ","@@¬e¹aH‚","@@\\nÔ¡q]L³ë\\ÿ®ŒQ̆","@@ÊA­©]ª","@@KxŒv{­","@@@hlIk_","@@pWc‡rxp","@@Md|_iA","@@¢…X£½z\\ðpN","@@hlÜ[LykAvyfw^Ež ","@@fp¤MusH","@@®_ma~•LÁ¬’`","@@†@°¡mۛGĕ¨§Ianá[ýƤjfæ‡ÐNž—äGp—","@@iM„t\\","@@Zc[b","@@™X®±GrÆ°Zæĉm","@@Z~dOSo|A¿qZv","@@@`”EN£p","@@|–s—","@@@nDi","@@n…a£¾u‰YL¯‰Qª…mĉÅdMˆ•gÇjcº«•ęœ¬­K­´ƒB«Âącoċ\\xK`cįŧ«®á’[~ıxu·Å”KsËɏc¢Ù\\ĭƛëbf¹­ģSƒĜkáƉÔ­ĈZB{ŠaM‘µ‰fzʼnfÓÔŹŁƋǝÊĉ{ğč±g³ne{ç­ií´S¬‚\\ßðK¦w\\™iqªĭiAu‡A­µ”_W¥ƣO\\lċĢttC¨£t`ˆ™PZäuXßBs‡Ļyek€OđġĵHuXBšµ]׌‡­­\\›°®¬F¢¾pµ¼kŘó¬Wät’¸|@ž•L¨¸µr“ºù³Ù~§WI‹ŸZWŽ®’±Ð¨ÒÉx€`‰²pĜ•rOògtÁZ{üÙ[|˜ûŒK‚wsPlU[}¦Rvn`hsª^–nQ´ĘRWb”‚_ rtČFI֊kŠŠĦPJ¶ÖÀÖJĈĄTĚòžC ²@Pú…Øzœ©PœCÈڜĒ±„hŖ‡l¬â~nm¨f©–iļ«m‡nt–qŒÒTÜÄj“ŠLŽ®E̜Fª²iÊxبžIÈhhst’ˆ’[Ôx†}dtüGæţŔïĬaĸpMËВjē¢·ðĄÆMzˆjWKĎ¢Q¶˜À_꒖_@ı€i«pZ€gf€¤Nrq]§ĂN®«H±‡yƳí¾×ŊďŀĐÏŴǝĂíÀBŖÕªˆŠÁŐTFqĉ¯³ËCĕģi¨hÜ·ƒñt»¯Ï","@@ºwšZRkĕWK "]],"encodeOffsets":[[[125785,31436],[125729,31431],[125513,31380],[125329,30690],[125223,30438],[125115,30114],[124815,29155],[124419,28746],[124095,28635],[124005,28609],[125000,30713],[125111,30698],[125078,30682],[125150,30684],[124014,28103],[125008,31331],[125411,31468],[125329,31479],[125369,31139],[125626,30916],[125417,30956],[125254,30976],[125199,30997],[125095,31058],[125083,30915],[124885,31015],[125218,30798],[124867,30838],[124755,30788],[124802,30809],[125267,30657],[125218,30578],[125200,30562],[125192,30787],[124968,30474],[125167,30396],[125115,30363],[124955,29879],[124714,29781],[124762,29462],[124325,28754],[124863,30077],[125366,31477]]]},"properties":{"cp":[120.153576,30.287459],"name":"浙江","childNum":43}},{"id":"340000","geometry":{"type":"MultiPolygon","coordinates":[["@@^iuLV\\","@@‚e©Edh","@@´CE¶zAXœêeödK¡~H¸íæAˆȽ—d{ďő“À½W—®£ChŒÃsiŒkkly]_teu[bFa‰Tig‡n{]Gqªo‹ĈMYá|·¥f¥—őaSÕė™NµñĞ«ImŒ_m¿Âa]uĜp …Z_§{Cƒäg¤°r[_Yj‰ÆOdý“[ŽI[á·¥“Q_n‡ùgL¾mz›ˆDÜƶĊJhšp“c¹˜O]iŠ]œ¥ jtsggDÑ¡“w×jÉ©±›EFˍ­‰Ki”ÛÃÕYv…s•ˆm¬njĻª•§emná}k«ŕˆƒgđ²Ù›DǤ›í¡ªOy›†×Où±@DŸñSęćăÕIÕ¿IµĥO‰‰‰lJÕÍR›Í|JìĻÒåyķrĕq§ÄĩsWÆߎF¶žX®¿‰mŒ™w…RIޓfßoG‘³¾©uyH‘į{Ɓħ¯AFnuP…ÍÔzšŒV—dàôº^Ðæd´€‡oG¤{S‰¬ćxã}›ŧ×Kǥĩ«žÕOEзÖdÖsƘѨ[’Û^Xr¢¼˜§xvěƵ`K”§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē…ßúLÃϖ_ÈÏ|]ÂÏHl’g`bšežž€n¾¢pU‚h~ƴĖ¶_‚r sĄ~cž”ƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³…]’u}›f…ïQl{skl“oNdŸjŸäËzDvčoQŠďHI¦rb“rHĖ~BmlNž“Ra„ĥTX\\{fÁKÁ®T‚œL‘ŠĄMt›ÊgĀD–ŠĄXœƔvDcÎJbt[¤€D@®hh~kt°ǾzÖ@¾ªdb„YhüóV´ŮŒ¨Üc”±r@J|àuYÇԋG·ĚąĐlŪÚpSJ¨ĸˆLvÞcPæķŨŽ®mАˆál‹sgd×mQ¨ųƩޖ¤IΖs’°ŒKZpĄ|XwWdĎµmkǀwÌÕæhºgBĝâqÙĊz›ÖgņtÀÁÊÆá’hEz|WzqD¹€Ÿ°E‡ŧl{ævÜcA`¤C`|´qžxIJkq^³³ŸGšµbƒíZ…¹qpa±ď OH—¦™Ħˆx¢„gPícOl_iCveaOjCh߸i݋bÛªCC¿€m„RV§¢A|tbkĜEÀtîm‚^g´fÄ"]],"encodeOffsets":[[[121722,32278],[119475,30423],[121606,33646]]]},"properties":{"cp":[117.283042,31.86119],"name":"安徽","childNum":3}},{"id":"350000","geometry":{"type":"MultiPolygon","coordinates":[["@@“zht´}[","@@aj^~ĆGå","@@edœŒH…se","@@@vˆPGsyQ","@@‰sBz‚ddW[O","@@SŽ¨Qy","@@NŽVucW","@@qptB@q","@@‰’¸[iu","@@Q\\pD[_","@@jSwUappI","@@eXª~•","@@AjvFoo","@@fT–›_Çí\\Ÿ™—v|ba¦jZÆy|®","@@IjLg","@@wJI€ˆxš«¼AoNe{M¥Œ","@@K‰±¡Óˆ”Č~N¾™","@@k¡¹Eh~c®uDq‰Zì¡I•~Māe£bN¨gZý¡a±Öcp©PhžI”Ÿ¢Qq…ÇGj‹|¥U™ g[Ky¬ŏ–v@OpˆtÉEŸF„\\@ åA¬ˆV{Xģ‰ĐBy…cpě…¼³Ăp·¤ƒ¥o“hqqÚ¡ŅLsƒ^ᗞ§qlŸÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ß–ėu›ĕeûҍiÁŧS[¡œUŠûŗ½ùěcݧSùĩąSWó«íęACµ›eR—åǃRCÒÇZÍ¢‹ź±^dlsŒtjD¸•‚ZpužÔâÒH¾oLUêÃÔjjēò´ĄW‚ƛ…^Ñ¥‹ĦŸ@Çò–ŠmŒƒOw¡õyJ†yD}¢ďÑÈġfŠZd–a©º²z£šN–ƒjD°Ötj¶¬ZSÎ~¾c°¶Ðm˜x‚O¸¢Pl´žSL|¥žA†ȪĖM’ņIJg®áIJČĒü` ŽQF‡¬h|ÓJ@zµ |ê³È ¸UÖŬŬÀCtrĸr‚]€˜ðŽM¤ĶIJHtÏ A’†žĬkvsq‡^aÎbvŒd–™fÊòSD€´Z^’xPsÞrv‹ƞŀ˜jJd×ŘÉ ®A–ΦĤd€xĆqAŒ†ZR”ÀMźŒnĊ»ŒİÐZ— YX–æJŠyĊ²ˆ·¶q§·–K@·{s‘Xãô«lŗ¶»o½E¡­«¢±¨Yˆ®Ø‹¶^A™vWĶGĒĢžPlzfˆļŽtàAvWYãšO_‡¤sD§ssČġ[kƤPX¦Ž`¶“ž®ˆBBvĪjv©šjx[L¥àï[F…¼ÍË»ğV`«•Ip™}ccÅĥZE‹ãoP…´B@ŠD—¸m±“z«Ƴ—¿å³BRضˆœWlâþäą`“]Z£Tc— ĹGµ¶H™m@_©—kŒ‰¾xĨ‡ôȉðX«½đCIbćqK³Á‹Äš¬OAwã»aLʼn‡ËĥW[“ÂGI—ÂNxij¤D¢ŽîĎÎB§°_JœGsƒ¥E@…¤uć…P‘å†cuMuw¢BI¿‡]zG¹guĮI‹"]],"encodeOffsets":[[[123250,27563],[122541,27268],[123020,27189],[122916,27125],[122887,26845],[122808,26762],[122568,25912],[122778,26197],[122515,26757],[122816,26587],[123388,27005],[122450,26243],[122578,25962],[121255,25103],[120987,24903],[122339,25802],[121042,25093],[122439,26024]]]},"properties":{"cp":[119.306239,26.075302],"name":"福建","childNum":18}},{"id":"360000","geometry":{"type":"Polygon","coordinates":["@@ÖP¬ǦĪØLœŨä~ĈwŠ«|TH£ˆp€c³Ïå¹]ĉđxe{ÎӐ†vOEm°BƂĨİ|G’vz½ª´€H’àp”eJ݆Qšxn‹ÀŠW­žEµàXÅĪt¨ÃĖrÄwÀFÎ|Ă¡”‡WÕ¸cf¥—‘XaęST±m[“r«_gŽmQu~¥V\\OkxtL E¢‹ƒ‘Ú^~ýØkbē–qo슱_Êw§Ñ²ÏƟė¼‹mĉŹ‹¿NQ“…YB‹ąrwģcÍ¥B•Ÿ­ŗÊcØiI—žƝĿuŒqtāwO]‘³YCñTeɕš‹caub͈]trlu€ī…B‘ПGsĵıN£ï—^ķqsq¿DūūV՟·´Ç{éĈý‰ÿ›OEˆR_ŸđûIċâJh­ŅıN‘ȩĕB…¦K{Tk³¡OP·wn—µÏd¯}½TÍ«YiµÕsC¯„iM•¤™­•¦¯P|ÿUHv“he¥oFTu‰õ\\ŽOSs‹MòđƇiaºćXŸĊĵà·çhƃ÷ǜ{‘ígu^›đg’m[ÙxiIN‘¶Õ»lđÕwZSƉv©_ÈëJbVk„ĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B„±’ÌŒK˜y’ñ`w²¹€·Ÿ…`g›ŸsÙfI›ěxŕeykpŽŒudjˆuTfb·hh„¿JdŠ[\\˜„L‚áƔĨƐAĈepˆÀÂMD~ņªe^\\^§„ý©j׍cZ†Ø¨zdÒa¶ˆlҍJŒìõ`oz÷@¤u޸´†ôęöY¼‰HČƶajlÞƩ¥éZ[”|h}^U Œ ¥p„ĄžƦO lt¸Æ €Q\\€ŠaÆ|CnÂOjt­ĚĤd’ÈŒF`’¶„@Ð딠¦ōҞ¨Sêv†HĢÛ@[ƅQoxHŒ—W[ŰîÀt¦DŽ~NĠ¢l–•ĄtZoœCƞÔºCxrpČN˜pj¢{f_Y`_ƒeq’’®Aot`@o‚DXfkp¨|Šs¬\\D‘ÄSfè©Hn¬…^DhÆyøJh“ØxĢĀLʈ„ƠPżċĄwĮ”¶ž"],"encodeOffsets":[[118923,30536]]},"properties":{"cp":[115.892151,28.676493],"name":"江西","childNum":1}},{"id":"370000","geometry":{"type":"MultiPolygon","coordinates":[["@@Xjd]mE","@@itnq","@@Dl@k","@@T‚ŒG—w","@@K¬˜•‰U","@@Wd`c","@@PtMs","@@•LnXlc","@@ppVƒu]Qn","@@cdzAU_","@@udRhnCE…","@@ˆoIƒpP„","@@M{Ŀčwbxƨî’Kš–ÎMĮ]†—ZFˆ½Y]â£ph’™š¶¨râøÀ†ÎǨ¤^ºÄ”Gzˆ~grĚĜlĞƄLĆdž¢Îo¦–cv“Kb€gr°Wh”mZp ˆL]LºcU‰Æ­n”żĤÌĒœbAnrOAœ´žȊcÀbƦUØrĆUÜøœĬƞ†ŶǬĴóò_A̈«ªdÎɜnb²ĦhņBĖ›žįĦåXćì@L¯´ywƕCéõė ƿ¸‘lµ‚Zæyj|BíÂKN„NnoƈfÈMZwšnŐNàúĂsT„JUš›‚L„îVj„ǎ¾Ē؍‚Dz²XPn±ŴPè¸ŔLƔÜƺ_T‘üÃĤBBċȉöA´fa„˜M¨{«M`‡¶d¡ô‰Ö°šmȰBÔjjŒ´PM|”c^d¤u•ƒ¤Û´Œä«ƢfPk¶Môlˆ]Lb„}su^ke{lC‘…M•rDŠÇ­]NÑFsmoõľH‰yGă{{çrnÓE‰‹ƕZGª¹Fj¢ÿ©}ÌCǷ돡ąuhÛ¡^Kx•C`C\\bÅxì²ĝÝ¿_N‰īCȽĿåB¥¢·IŖÕy\\‡¹kx‡Ã£ČáKµË¤ÁçFQ¡„KtŵƋ]CgÏAùSed‡cÚź—ŠuYfƒyMmhUWpSyGwMPqŀ—›Á¼zK›¶†G•­Y§Ëƒ@–´śÇµƕBmœ@Io‚g——Z¯u‹TMx}C‘‰VK‚ï{éƵP—™_K«™pÛÙqċtkkù]gŽ‹Tğwo•ɁsMõ³ă‡AN£™MRkmEʕč™ÛbMjÝGu…IZ™—GPģ‡ãħE[iµBEuŸDPԛ~ª¼ętŠœ]ŒûG§€¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~Ż¸Y’I“] P‰umŝrƿ›‰›Iā‹[x‰edz‹L‘¯v¯s¬ÁY…~}…ťuŁŒg›ƋpÝĄ_ņī¶ÏSR´ÁP~ž¿Cyžċßdwk´Ss•X|t‰`Ä Èð€AªìÎT°¦Dd–€a^lĎDĶÚY°Ž`ĪŴǒˆ”àŠv\\ebŒZH„ŖR¬ŢƱùęO•ÑM­³Fۃaj"]],"encodeOffsets":[[[123806,39303],[123821,39266],[123742,39256],[123702,39203],[123649,39066],[123847,38933],[123580,38839],[123894,37288],[123043,36624],[123344,38676],[123522,38857],[123628,38858],[118267,36772]]]},"properties":{"cp":[117.000923,36.675807],"name":"山东","childNum":13}},{"id":"410000","geometry":{"type":"MultiPolygon","coordinates":[["@@dXD}~Hgq~ÔNŽ‹„~zkĘHVsDzßjƒŬŒŠŢ`Pûàl¢˜\\ÀœEhŽİgÞē X¼`kš„h•ÍL™ùµP³swIÓzeŠĠð†´E®žÚPt†ºIŊ–ʺ˜L«šŕQGƒ‹Yfa[şu“ßǑ‡ĩų_Z¯ĵÙčC]kbc•¥CS¯ëÍB©ïŽÇߊ_{s–WTtž³xlàcȂzÀD}ÂOQ³ÐTĬµ‚ƑпŸghœł‹Ŧv~††}ÂZž«¤lPǕ£ªÝŴÅR§ØnhcŒtâk‡nύ­ľŹUÓÝdKuķ‡I§oTũÙďkęĆH¸ÓŒ\\ăŒ¿PcnS{wBIvɘĽ[GqµuŸŇôYgûƒZcaŽ©@½Õǽys¯}lgg@­C\\£as€IdÍuCQñ[L±ęk·‹ţb¨©kK—’»›KC²‘òGKmĨS`ƒ˜UQ™nk}AGē”sqaJ¥ĐGR‰ĎpCuÌy ã iMc”plk|tRk†ðœev~^‘´†¦ÜŽSí¿_iyjI|ȑ|¿_»d}qŸ^{“Ƈdă}Ÿtqµ`ŷ飩V¡om½ZÙϋÁRD|JOÈpÀ—Rs’•I{ùÓjuµ{t}uËR‘iŸvGŠçJFjµŠåkWꖴMƒHewixGw½Yŷpµú³XU›½ġy™łå‰kÚwZXˆ·l„¢Á¢K”zO„Λ΀jc¼htoDHr…|­J“½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ…Ťƒ]MÛfaQpě±ǽ¾]u­Fu‹÷nƒ™čįADp}AjmcEǒaª³o³ÆÍSƇĈÙDIzçƒñİŸ^ˆKNœ™i—Þñ€[œƒaA²zz‰Ì÷Dœ|[šíijgf‚ÕÞd®|`ƒĆ~„oĠƑô³Ŋ‘D×°¯Csˆø«ì‰UMhTº¨¸ǝêWšÔ„DruÂÇZ£Ćš”PZ„žW”~؋Øv¬gèÂÒw¦X¤Ā´oŬ¬Ž²Ês~€€]®tªašpŎJ¨Öº„_ŠŔ–f”Ő\\Ѝ\\Ĝu–”~m²Ƹ›¸fW‰ĦrƔ}Î^gjdfÔ¡J}\\n C˜¦þWxªJRÔŠu¬ĨĨmF†dM{\\d\\ŠYÊ¢ú@@¦ª²SŠÜsC–}fNècbpRmlØ^g„d¢aÒ¢CZˆZxvÆ¶N¿’¢T@€uCœ¬^ĊðÄn|žlIlŽ—Xhun€[","@@hzUq"]],"encodeOffsets":[[[116744,37216],[116480,33048]]]},"properties":{"cp":[113.665412,34.757975],"name":"河南","childNum":2}},{"id":"420000","geometry":{"type":"MultiPolygon","coordinates":[["@@ASd","@@ls{d","@@¾«}{ra®pîÃ\\™›{øCŠËyyB±„b\\›ò˜Ý˜jK›‡L ]ĎĽÌ’JyÚCƈćÎT´Å´pb©È‘dFin~BCo°BĎĚømvŒ®E^vǾ½Ĝ²Ro‚bÜeNŽ„^ĺ£R†¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I”¾®I†{GqpCgyl{‡£œÍƒÍyPL“¡ƒ¡¸kW‡xYlÙ抚ŁĢzœ¾žV´W¶ùŸo¾ZHxjwfx„GNÁ•³Xéæl¶‰EièIH‰ u’jÌQ~v|sv¶Ôi|ú¢Fh˜Qsğ¦ƒSiŠBg™ÐE^ÁÐ{–čnOÂȞUÎóĔ†ÊēIJ}Z³½Mŧïeyp·uk³DsѨŸL“¶_œÅuèw»—€¡WqÜ]\\‘Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟO‡ƒKÉġÿ×wg”÷IÅzCg†]m«ªGeçÃTC’«[‰t§{loWeC@ps_Bp‘­r‘„f_``Z|ei¡—oċMqow€¹DƝӛDYpûs•–‹Ykıǃ}s¥ç³[§ŸcYŠ§HK„«Qy‰]¢“wwö€¸ïx¼ņ¾Xv®ÇÀµRĠЋžHMž±cÏd„ƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy…¿³x¯N‰o‰|¹H™ÏÛm‹júË~Tš•u˜ęjCöAwě¬R’đl¯ Ñb­‰ŇT†Ŀ_[Œ‘IčĄʿnM¦ğ\\É[T·™k¹œ©oĕ@A¾w•ya¥Y\\¥Âaz¯ãÁ¡k¥ne£Ûw†E©Êō¶˓uoj_Uƒ¡cF¹­[Wv“P©w—huÕyBF“ƒ`R‹qJUw\\i¡{jŸŸEPïÿ½fć…QÑÀQ{ž‚°‡fLԁ~wXg—ītêݾ–ĺ‘Hdˆ³fJd]‹HJ²…E€ƒoU¥†HhwQsƐ»Xmg±çve›]Dm͂PˆoCc¾‹_h”–høYrŊU¶eD°Č_N~øĹĚ·`z’]Äþp¼…äÌQŒv\\rCŒé¾TnkžŐڀÜa‡“¼ÝƆĢ¶Ûo…d…ĔňТJq’Pb ¾|JŒ¾fXŠƐîĨ_Z¯À}úƲ‹N_ĒĊ^„‘ĈaŐyp»CÇĕKŠšñL³ŠġMŒ²wrIÒŭxjb[œžn«øœ˜—æˆàƒ ^²­h¯Ú€ŐªÞ¸€Y²ĒVø}Ā^İ™´‚LŠÚm„¥ÀJÞ{JVŒųÞŃx×sxxƈē ģMř–ÚðòIf–Ċ“Œ\\Ʈ±ŒdʧĘD†vČ_Àæ~DŒċ´A®µ†¨ØLV¦êHÒ¤"]],"encodeOffsets":[[[113712,34000],[115612,30507],[113649,34054]]]},"properties":{"cp":[114.298572,30.584355],"name":"湖北","childNum":3}},{"id":"430000","geometry":{"type":"MultiPolygon","coordinates":[["@@—n„FZw","@@かÆችÔXr—†CO™“…ËR‘ïÿĩ­TooQyšÓ[‹ŅBE¬–ÎÓXa„į§Ã¸G °ITxp‰úxÚij¥Ïš–Ģ¾ŠedžÄ©ĸG…œàGh‚€M¤–Â_U}Ċ}¢pczfŠþg¤€’ÇôAV‘","@@ȴÚŠĖÁĐiO“Ĝ«BxDõĚiv—ž–S™Ì}iùŒžÜnšÐºGŠ{Šp°M°yŠÂÒzJ²Ì ÂcXëöüiáÿñŽőФ‚ùTz²CȆȸǎŪƒƑÐc°dPÎŸğ˶[Ƚu¯½WM¡­Éž“’B·rížnZŸÒ `‡¨GA¾\\pē˜XhÆRC­üWGġu…T靧Ŏѝ©êL•M³}_‘‹E‘Çģc®ęisÁPDmÅ{‰b[Rşs·€kPŸŽƥƒóRo”O‹ŸVŸ~]{g\\“êYƪ¦kÝbiċƵŠGZ»Ěõ…ó·³vŝž£ø@pyö_‹ëŽIkѵ‡bcѧy…×dY؎ªiþžˆUjŸŅ³C}ÁN‡»hĻħƏâƓK—ƒA·³CQ±µ§¿AUŠƑ¹AŠtćOw™D]ŒJUÖgk¯b£‘ylƒ›ZƒFËѱH™­}˜•EbóľA–¡»Ku¦·‘³†åş¥ùBDž^{ÌC´­¦ŷJ£^[†‹—ª¿‡ğ|‹ƅ…•N… skóā‡¹¿€ï]ă~÷O§­@—Vm¡‹Qđ¦¢Ĥ{ºjԏŽŒª¥nf´•~ÕoŸž×Ûą‹Gû¥cÑ[Zœ‰¶˜ŨĪ²SÊǔƐ˜ƀƒ’AÚŌ¦QؼrŭŽ­«}NÏürʬŒmjr€@ĘrTW ­SsdHzƓ^ÇÂyUi¯DÅYlŹu{hTœ}mĉ–¹¥ě‰Dÿë©ıÓ[Oº£ž“¥ót€ł¹MՄžƪƒ`Pš…Di–ÛUŠ¾Å‌ìˆU’ñB“È£ýhe‰dy¡oċ€`pfmjP~‚kZa…ZsÐd°wj§ƒ@€Ĵ®w~^‚kÀÅKvNmX\\¨a“”сqvíó¿F„¤¡@ũÑVw}S@j}¾«pĂr–ªg àÀ²NJ¶¶Dô…K‚|^ª†Ž°LX¾ŴäPĪ±œ£EXd›”^¶›IJÞܓ~‘u¸ǔ˜Ž›MRhsR…e†`ÄofIÔ\\Ø  i”ćymnú¨cj ¢»–GČìƊÿШXeĈĀ¾Oð Fi ¢|[jVxrIQŒ„_E”zAN¦zLU`œcªx”OTu RLĪpUžĪ‚ȴ^ŎµªÉžFx…Ü€f¤ºgIJèy°Áb[¦Zb¦–z½xBĖ@ªpº›˜jS´rVźOd©ʪiĎă’JP‡ž`"]],"encodeOffsets":[[[115640,30489],[112577,27316],[114113,30649]]]},"properties":{"cp":[112.982279,28.19409],"name":"湖南","childNum":3}},{"id":"440000","geometry":{"type":"MultiPolygon","coordinates":[["@@QdˆAsa","@@ƒlxDRm","@@sbhNLo","@@Ă ý","@@WltOY[","@@Krœ]‰S","@@e„~AS}","@@I|„Mym","@@ƒÛ³LSŒž²Q","@@nvºB–ë¥cÕº","@@zdšÛ›JmŠ","@@†°³","@@a yAª¸ËJIx،@€ĀHÉÕZ™o•fo…o","@@šs‰ŗÃÔėAƁ›ZšÄ ~°ČP‚‹ºb","@@‹¶Ý’Ì‚vmĞh¹Ĺ","@@HœŠdSjĒ¢D}war…“u«ZqadY{K","@@elŒ\\LqqO","@@~rMmX","@@f„^E","@@øPªoj÷ÍÝħXČx”°Q¨ıXJp","@@gÇƳˆˆ–m’Žxa†tfu","@@E–ÆC½‘","@@¸B_¶ekWvSi‡vc•}p}Ăº¾NĎyj¦Èm thœ†_®žÄ}ˆ»âUzL™Ë‹²‘Aƒā¡ßH©Ùñ}wkNÕ¹ÇO½¿£ēUlƒaUìIžÇª`ŠuTÅxYĒÖ¼k֞’µ‚MžjJÚwn\\h‘œĒv]îh|’È›Ƅøègž¸Ķß ĉĈWb¹ƀdéʌNTtP[ŠöSvrCZžžaGuœbo´ŖÒÇА~¡zCI…özx¢„Pn‹•‰Èñ @ŒĥÒ¦†]ƜŽX³ăĔñiiÄÓVépKG½Ä‘ÓávYo–C·sit‹iaÀy„ŧΡÈYDÑům}‰ý|m[węõĉZÅxUO}÷N¹³ĉo_qtă“qwµŁYلǝŕ¹tïÛUïmRCº…ˆĭ|µ›ÕÊK™½R‘ē ó]‘–GªęAx–ŸNqSF•|ām‡¡diď×YïYWªʼnOeÚtĐ«zđ¹T…ā‡úE™áÎÁWw헟HcòßÎſ¿Çdğ·ùT×Çūʄ¡XgWÀLJğ·¿ÃˆOj YÇ÷Sğ³kzőõm‰™ĝ—[³‹¡VÙæÅöM̳¹pÁaËýý©D©Ü“JŹƕģGą¤{Ùū…ǘO²«BƱéA—Ò‰ĥ‡¡«BhlmtÃPµyU¯uc“d·w_bŝcīímGOŽ€GBȅ‰ŹãĻFŷŽŕ@Óoo¿ē‹±ß}Ž}ÓF÷tIJWÈCőâUâǙI›ğʼn©I›ijEׅÁ”³AĥDĈ±ÌŒÜӔĨ£L]ĈÙƺZǾĆĖMĸĤfŒÎĵl•ŨnȈ‘ĐtF”Š–FĤ–‚êk¶œ^k°f¶gŠŽœ}®Fa˜f`vXŲxl˜„¦–ÔÁ²¬ÐŸ¦pqÊ̲ˆi€XŸØRDÎ}†Ä@ZĠ’s„x®AR~®ETtĄZ†–ƈfŠŠHâÒÐA†µ\\S¸„^wĖkRzŠalŽŜ|E¨ÈNĀňZTŒ’pBh£\\ŒĎƀuXĖtKL–¶G|Ž»ĺEļĞ~ÜĢÛĊrˆO˜Ùîvd]nˆ¬VœÊĜ°R֟pM††–€ƀ¬HbwžEÀˆ˜©Œž\\…¤]ŸI®¥D³|ˎ]CúAŠ¦…æ’´¥¸Lv¼€•¢ĽBaô–F~—š®²GÌҐEY„„œzk¤’°ahlV՞I^‹šCxĈPŽsB‰ƒºV‰ÀB¶¨R²´D","@@OŽR"]],"encodeOffsets":[[[117381,22988],[116552,22934],[116790,22617],[116973,22545],[116444,22536],[116931,22515],[116496,22490],[116453,22449],[113301,21439],[118726,21604],[118709,21486],[113210,20816],[115482,22082],[113171,21585],[113199,21590],[115232,22102],[115739,22373],[115134,22184],[113056,21175],[119573,21271],[119957,24020],[115859,22356],[116680,26053],[116561,22649]]]},"properties":{"cp":[113.280637,23.125178],"name":"广东","childNum":24}},{"id":"450000","geometry":{"type":"MultiPolygon","coordinates":[["@@H– TI¡U","@@Ɣ_LÊFZg…čP­kini«‹qǀcz͔Y®¬Ů»qR×ō©DՄ‘§ƙǃŵTÉĩ±ŸıdÑnYY›IJvNĆƌØÜ Öp–}e³¦m‹©iÓ|¹Ÿħņ›|ª¦QF¢Â¬ʖovg¿em‡^ucäāmÇÖåB¡Õçĝ}FĻ¼Ĺ{µHK•sLSđƃr‹č¤[Ag‘oS‹ŇYMÿ§Ç{Fśbky‰lQxĕƒ]T·¶[B…ÑÏGáşşƇe€…•ăYSs­FQ}­Bƒw‘tYğÃ@~…C̀Q ×W‡j˱rÉ¥oÏ ±«ÓÂ¥•ƒ€k—ŽwWűŽue_b—­E›~‰µh¯ecl¯›Ïr¯‡Eģ‰•Jƒğƒ}žw³–Ƈē`ãògK_ÛsUʝ“ćğ¶hŒöŒO¤Ǜn³Žc‘`¡yi–ę–‘[ďĵűMę§]X˜Î_‚훘Û]é’ÛUćİÕBƣ±…dƒy¹T^džûÅÑŦ·‡PĻþÙ`K€¦˜…¢ÍeœĥR¿Œ³£[~Œäu¼dl‰t‚†W¸oRM¢ď\\zœ}Æzdvň–{ÎXF¶°Â_„ÒÂÏL©Ö•TmuŸ¼ãl‰›īkiqéfA„·Êµ\\őDc¥ÝF“y›Ôć˜c€űH_hL܋êĺШc}rn`½„Ì@¸¶ªVLŒŠhŒ‹\\•Ţĺk~ŽĠið°|gŒtTĭĸ^x‘vK˜VGréAé‘bUu›MJ‰VÃO¡…qĂXËS‰ģãlýàŸ_ju‡YÛÒB†œG^˜é֊¶§ŽƒEG”ÅzěƒƯ¤Ek‡N[kdåucé¬dnYpAyČ{`]þ±X’\\’ÞÈk‚¡Ĭj†àh„ÂƄ¢H茠Ŕ⪃LƒĒ^Öm¶ħĊAǦė¸zÚGn£¾›rªŀÜt¬@֛ڈSx~øOŒ˜ŶÐÂæȠ\\„ÈÜObĖw^oބLf¬°bI lTØB̈F£Ć¹gñĤaY“t¿¤VSñœK¸¤nM†¼‚JE±„½¸šŠño‹ÜCƆæĪ^ŠĚQÖ¦^‡ˆˆf´Q†üÜʝz¯šlzUĺš@쇀p¶n]sxtx¶@„~ÒĂJb©gk‚{°‚~c°`ԙ¬rV\\“la¼¤ôá`¯¹LC†ÆbŒxEræO‚v[H­˜„[~|aB£ÖsºdAĐzNÂðsŽÞƔ…Ĥªbƒ–ab`ho¡³F«èVZs„\\\\Œ™ÔRzpp®SŽĪº¨ÖƒºN…ij„d`’a”¦¤F³¢@„`¢ĨĀìhYvlŠĆº¦Ċ•~nS›|gźv^kGƄÀè·"]],"encodeOffsets":[[[111707,21520],[113706,26955]]]},"properties":{"cp":[108.320004,22.82402],"name":"广西","childNum":2}},{"id":"460000","geometry":{"type":"Polygon","coordinates":["@@š¦Ŝil¢”XƦ‘ƞò–ïè§ŞCêɕrŧůÇąĻõ™·ĉ³œ̅kÇm@ċȧƒŧĥ‰Ľʉ­ƅſ“ȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀœÐ¾jNðĀÒRŒšZdž™zМŒĊ†¢DÀɘZ"],"encodeOffsets":[[112750,20508]]},"properties":{"cp":[110.33119,20.031971],"name":"海南","childNum":1}},{"id":"510000","geometry":{"type":"MultiPolygon","coordinates":[["@@LqSn","@@ĆOìÛÐ@Ğ™ǔNY{¤Á§d…i“´ezÝúØãwŒƒIŸþËQǦÃqɞSJ»ĂéʔõÔƁİlƞ¹„§Ĭqt‘ÀƄmÀêErĒtD®ċæcQƒ”E®³^ĭ¥©l}äQto˜ŖÜqƎkµ–„ªÔĻĴ¡@Ċ°B²Èw^^RsºTĀ£ŚæœQP‘JvÄz„^Đ¹Æ¯fLà´GC²‘dt˜­ĀRt¼¤ĦOðğfÔðDŨŁĞƘïžPȆ®âbMüÀXZ ¸£@Ś›»»QÉ­™]d“sÖ×_͖_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|Y‹Ô‚ZśÎs´xº±UŒ’ñˆt|O’ĩĠºNbgþŠJy^dÂY Į„]Řz¦gC‚³€R`ĀŠz’¢AjŒ¸CL„¤RÆ»@­Ŏk\\Ç´£YW}z@Z}‰Ã¶“oû¶]´^N‡Ò}èN‚ª–P˜Íy¹`S°´†ATe€VamdUĐwʄvĮÕ\\ƒu‹Æŗ¨Yp¹àZÂm™Wh{á„}WØǍ•Éüw™ga§ßAYŸrÅÂQĀÕ¬LŐý®X˜øxª½Ű¦¦[€—þ„`ÜUÖ´òrÙŠ°²Äk„ijnDX{Uƒ~ET{ļº¦PZc”jF²Ė@Žp˜g€ˆ¨“B{ƒu¨ŦyhoÚD®¯¢˜ WòàFΤ¨GDäz¦kŮPœġq˚¥À]€Ÿ˜eŽâÚ´ªKxī„Pˆ—Ö|æ[xäJÞĥ‚s’NÖ½ž€I†¬nĨY´®Ð—ƐŠ€mD™ŝuäđđEb…e’e_™v¡}ìęNJē}q”É埁T¯µRs¡M@}ůa†a­¯wvƉåZwž\\Z{åû`Ÿ†[±oi•‘JDŦ]‘‰ĕãïrG •réÏ·~ąSfy×͂·ºſƽĵȁŗūmHQ¡Y¡®ÁÃ×t«ƒ­Tƒ¤J–JJŒyJ•ÈŠ`Ohߦ¡uËhIyCjmÿw…ZG……Ti‹SˆsO‰žB²ŸfNmsPaˆ{M{ŠõE‘^Hj}gYpaeuž¯‘oáwHjÁ½M¡pM“–uå‡mni{fk”\\oƒÎqCw†EZ¼K›ĝŠƒAy{m÷L‡wO×SimRI¯rK™õBS«sFe‡]fµ¢óY_ÆPRcue°Cbo׌bd£ŌIHgtrnyPt¦foaXďx›lBowz‹_{ÊéWiêE„GhܸºuFĈIxf®Ž•Y½ĀǙ]¤EyŸF²ċ’w¸¿@g¢§RGv»–áŸW`ÃĵJwi]t¥wO­½a[׈]`Ãi­üL€¦LabbTÀå’c}Íh™Æhˆ‹®BH€î|Ék­¤S†y£„ia©taį·Ɖ`ō¥Uh“O…ƒĝLk}©Fos‰´›Jm„µlŁu—…ø–nÑJWΪ–YÀïAetTžŅ‚ӍG™Ë«bo‰{ıwodƟ½ƒžOġܑµxàNÖ¾P²§HKv¾–]|•B‡ÆåoZ`¡Ø`ÀmºĠ~ÌЧnDž¿¤]wğ@sƒ‰rğu‰~‘Io”[é±¹ ¿žſđӉ@q‹gˆ¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@ỗs›Zϕ‹œÅĭ€Ƌ•ěpwDóÖሯneQˌq·•GCœýS]xŸ·ý‹q³•O՜Œ¶Qzßti{ř‰áÍÇWŝŭñzÇW‹pç¿JŒ™‚Xœĩè½cŒF–ÂLiVjx}\\N†ŇĖ¥Ge–“JA¼ÄHfÈu~¸Æ«dE³ÉMA|b˜Ò…˜ćhG¬CM‚õŠ„ƤąAvƒüV€éŀ‰_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»Ÿ“˜ÕZ³ġqDo‰y`L¬gdp°şŠp¦ėìÅĮZŽ°Iä”h‚‘ˆzŠĵœf²å ›ĚрKp‹IN|‹„Ñz]ń……·FU×é»R³™MƒÉ»GM«€ki€™ér™}Ã`¹ăÞmȝnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ…þTº·àUȞÏʦ¶†I’«dĽĢdĬ¿–»Ĕ׊h\\c¬†ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvw–ˆxBèĻĒ©Ĉ“t@Ğû¸£B¯¨ˋäߜkŽķŒ½ª“ôNԓ~t¼Ŵ„u„œ^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ‘®Z´ğ~Sn|ªWÚ©òzPOȸ‚bð¢|‹øĞŠŒœŠA"]],"encodeOffsets":[[[108815,30935],[100197,35028]]]},"properties":{"cp":[104.065735,30.659462],"name":"四川","childNum":2}},{"id":"520000","geometry":{"type":"MultiPolygon","coordinates":[["@@†G\\†lY£‘cj","@@q‚|ˆ‚mc¯vωV","@@hÑ£Is‡NgßH†›HªķÃh_¹ƒ¡ĝħń¦uيùŽgS¯JHŸ|sÝÅtÁïyMDč»eÕtA¤{b\\}—ƒG®u\\åPFq‹wÅaD…žK°ºâ_£ùbµ”mÁ‹ÛœĹM[q|hlaªāI}тƒµ@swtwm^oµˆD鼊yV™ky°ÉžûÛR…³‚‡eˆ‡¥]RՋěħ[ƅåÛDpŒ”J„iV™™‰ÂF²I…»mN·£›LbÒYb—WsÀbŽ™pki™TZĄă¶HŒq`……ĥ_JŸ¯ae«ƒKpÝx]aĕÛPƒÇȟ[ÁåŵÏő—÷Pw}‡TœÙ@Õs«ĿÛq©½œm¤ÙH·yǥĘĉBµĨÕnđ]K„©„œá‹ŸG纍§Õßg‡ǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊžw¶øV¤w”²Ĉ]ʚKx|`ź¦ÂÈdr„cȁbe¸›`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pН`oÒhŽ¶pa‚^ÓĔ}D»^Xyœ`d˜[Kv…JPhèhCrĂĚÂ^Êƌ wˆZL­Ġ£šÁbrzOIl’MM”ĪŐžËr×ÎeŦŽtw|Œ¢mKjSǘňĂStÎŦEtqFT†¾†E쬬ôxÌO¢Ÿ KŠ³ŀºäY†„”PVgŎ¦Ŋm޼VZwVlŒ„z¤…ž£Tl®ctĽÚó{G­A‡ŒÇgeš~Αd¿æaSba¥KKûj®_ć^\\ؾbP®¦x^sxjĶI_Ä X‚⼕Hu¨Qh¡À@Ëô}Ž±žGNìĎlT¸ˆ…`V~R°tbÕĊ`¸úÛtπFDu€[ƒMfqGH·¥yA‰ztMFe|R‚_Gk†ChZeÚ°to˜v`x‹b„ŒDnÐ{E}šZ˜è€x—†NEފREn˜[Pv@{~rĆAB§‚EO¿|UZ~ì„Uf¨J²ĂÝƀ‚sª–B`„s¶œfvö¦ŠÕ~dÔq¨¸º»uù[[§´sb¤¢zþFœ¢Æ…Àhˆ™ÂˆW\\ıŽËI݊o±ĭŠ£þˆÊs}¡R]ŒěƒD‚g´VG¢‚j±®è†ºÃmpU[Á›‘Œëº°r›ÜbNu¸}Žº¼‡`ni”ºÔXĄ¤¼Ôdaµ€Á_À…†ftQQgœR—‘·Ǔ’v”}Ýלĵ]µœ“Wc¤F²›OĩųãW½¯K‚©…]€{†LóµCIµ±Mß¿hŸ•©āq¬o‚½ž~@i~TUxð´Đhw­ÀEîô‚uĶ‚’“‚b[§nWuMÆJl½]vuıµb"]],"encodeOffsets":[[[112158,27383],[112105,27474],[112095,27476]]]},"properties":{"cp":[106.713478,26.578343],"name":"贵州","childNum":3}},{"id":"530000","geometry":{"type":"Polygon","coordinates":["@@[„ùx½}ÑRH‘YīĺûsÍn‘iEoã½Ya²ė{c¬ĝg•ĂsA•ØÅwď‚õzFjw}—«Dx¿}UũlŸê™@•HÅ­F‰¨ÇoJ´Ónũuą¡Ã¢pÒŌ“Ø TF²‚xa²ËX€‚cʋlHîAßËŁkŻƑŷÉ©h™W­æßU‡“Ës¡¦}•teèƶStǀÇ}Fd£j‹ĈZĆÆ‹¤T‚č\\Dƒ}O÷š£Uˆ§~ŃG™‚åŃDĝ¸œTsd¶¶Bªš¤u¢ŌĎo~t¾ÍŶÒtD¦Ú„iôö‰€z›ØX²ghįh½Û±¯€ÿm·zR¦Ɵ`ªŊÃh¢rOԍ´£Ym¼èêf¯ŪĽn„†cÚbŒw\\zlvWžªâˆ ¦g–mĿBş£¢ƹřbĥkǫßeeZkÙIKueT»sVesb‘aĕ  ¶®dNœĄÄpªyŽ¼—„³BE˜®l‡ŽGœŭCœǶwêżĔÂe„pÍÀQƞpC„–¼ŲÈ­AÎô¶R„ä’Q^Øu¬°š_Èôc´¹ò¨P΢hlϦ´Ħ“Æ´sâDŽŲPnÊD^¯°’Upv†}®BP̪–jǬx–Söwlfòªv€qĸ|`H€­viļ€ndĜ­Ćhň•‚em·FyށqóžSį¯‘³X_ĞçêtryvL¤§z„¦c¦¥jnŞk˜ˆlD¤øz½ĜàžĂŧMÅ|áƆàÊcðÂF܎‚áŢ¥\\\\º™İøÒÐJĴ‡„îD¦zK²ǏÎEh~’CD­hMn^ÌöÄ©ČZÀžaü„fɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~Äqššê€ljN¬¼H„ÊšNQ´ê¼VظE††^ŃÒyŒƒM{ŒJLoÒœęæŸe±Ķ›y‰’‡gã“¯JYÆĭĘëo¥Š‰o¯hcK«z_pŠrC´ĢÖY”—¼ v¸¢RŽÅW³Â§fǸYi³xR´ďUˊ`êĿU„û€uĆBƒƣö‰N€DH«Ĉg†——Ñ‚aB{ÊNF´¬c·Åv}eÇÃGB»”If•¦HňĕM…~[iwjUÁKE•Ž‹¾dĪçW›šI‹èÀŒoÈXòyŞŮÈXâÎŚŠj|àsRy‹µÖ›–Pr´þŒ ¸^wþTDŔ–Hr¸‹žRÌmf‡żÕâCôox–ĜƌÆĮŒ›Ð–œY˜tâŦÔ@]ÈǮƒ\\Ī¼Ä£UsȯLbîƲŚºyh‡rŒŠ@ĒԝƀŸÀ²º\\êp“’JŠ}ĠvŠqt„Ġ@^xÀ£È†¨mËÏğ}n¹_¿¢×Y_æpˆÅ–A^{½•Lu¨GO±Õ½ßM¶w’ÁĢۂP‚›Ƣ¼pcIJxŠ|ap̬HšÐŒŊSfsðBZ¿©“XÏÒK•k†÷Eû¿‰S…rEFsÕūk”óVǥʼniTL‚¡n{‹uxţÏh™ôŝ¬ğōN“‘NJkyPaq™Âğ¤K®‡YŸxÉƋÁ]āęDqçgOg†ILu—\\_gz—]W¼ž~CÔē]bµogpў_oď`´³Țkl`IªºÎȄqÔþž»E³ĎSJ»œ_f·‚adÇqƒÇc¥Á_Źw{™L^ɱćx“U£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣG˛÷Ÿk°_^ý|_zċBZocmø¯hhcæ\\lˆMFlư£Ĝ„ÆyH“„F¨‰µêÕ]—›HA…àӄ^it `þßäkŠĤÎT~Wlÿ¨„ÔPzUC–NVv [jâôDôď[}ž‰z¿–msSh‹¯{jïğl}šĹ[–őŒ‰gK‹©U·µË@¾ƒm_~q¡f¹…ÅË^»‘f³ø}Q•„¡Ö˳gͱ^ǁ…\\ëÃA_—¿bW›Ï[¶ƛ鏝£F{īZgm@|kHǭƁć¦UĔťƒ×ëǟ…eċ¼ȡȘÏíBə£āĘPªij¶“ʼnÿ‡y©n‰ď£G¹¡I›Š±LÉĺÑdĉ܇W¥˜‰}g˜Á†{aqÃ¥aŠıęÏZ—Á`"],"encodeOffsets":[[104636,22969]]},"properties":{"cp":[102.712251,25.040609],"name":"云南","childNum":1}},{"id":"540000","geometry":{"type":"Polygon","coordinates":["@@hžľxŽŖ‰xƒÒVŽ†ºÅâAĪÝȆµę¯Ňa±r_w~uSÕň‘qOj]ɄQ…£Z……UDûoY’»©M[‹L¼qãË{V͕çWViŽ]ë©Ä÷àyƛh›ÚU°ŒŒa”d„cQƒ~Mx¥™caŸÛcSyF—ցk­ŒuRýq¿Ôµ•QĽ³aG{¿FµëªéĜÿª@¬·–K‰·àariĕĀ«V»Ŷ™Ĵū˜gèLǴŇƶaf‹tŒèBŚ£^Šâ†ǐÝ®–šM¦ÁǞÿ¬LhŸŽJ¾óƾƺcxw‹f]Y…´ƒ¦|œQLn°aœdĊ…œ\\¨o’œǀÍŎœ´ĩĀd`tÊQŞŕ|‚¨C^©œĈ¦„¦ÎJĊ{ŽëĎjª²rЉšl`¼Ą[t|¦St辉PŒÜK¸€d˜Ƅı]s¤—î_v¹ÎVòŦj˜£Əsc—¬_Ğ´|Ł˜¦AvŽ¦w`ăaÝaa­¢e¤ı²©ªSªšÈMĄwžÉØŔì@T‘¤—Ę™\\õª@”þo´­xA s”ÂtŎKzó²Çȵ¢rž^nĊ­Æ¬×üGž¢‚³ {âĊ]š™G‚~bÀgVjzlhǶf€žOšfdŠ‰ªB]pj„•TO–tĊ‚n¤}®¦ƒČ¥d¢¼»ddš”Y¼Žt—¢eȤJ¤}Ǿ¡°§¤AГlc@ĝ”sªćļđAç‡wx•UuzEÖġ~AN¹ÄÅȀŻ¦¿ģŁéì±H…ãd«g[؉¼ēÀ•cīľġ¬cJ‘µ…ÐʥVȝ¸ßS¹†ý±ğkƁ¼ą^ɛ¤Ûÿ‰b[}¬ōõÃ]ËNm®g@•Bg}ÍF±ǐyL¥íCˆƒIij€Ï÷њį[¹¦[⚍EÛïÁÉdƅß{âNÆāŨߝ¾ě÷yC£‡k­´ÓH@¹†TZ¥¢įƒ·ÌAЧ®—Zc…v½ŸZ­¹|ŕWZqgW“|ieZÅYVӁqdq•bc²R@†c‡¥Rã»Ge†ŸeƃīQ•}J[ғK…¬Ə|o’ėjġĠÑN¡ð¯EBčnwôɍėªƒ²•CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛ†ęgſ¶ҍć`ĘąŌJޚä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷‡f±iMݑ›‰@ĥ°G¬ÃM¥n£Øą‚ğ¯ß”§aëbéüÑOčœk£{\\‘eµª×M‘šÉfm«Ƒ{Å׃Gŏǩãy³©WÑăû‚··‘Q—òı}¯ã‰I•éÕÂZ¨īès¶ZÈsŽæĔTŘvŽgÌsN@îá¾ó@‰˜ÙwU±ÉT廣TđŸWxq¹Zo‘b‹s[׌¯cĩv‡Œėŧ³BM|¹k‰ªħ—¥TzNYnݍßpęrñĠĉRS~½ŠěVVŠµ‚õ‡«ŒM££µB•ĉ¥áºae~³AuĐh`Ü³ç@BۘïĿa©|z²Ý¼D”£àč²‹ŸƒIƒû›I ā€óK¥}rÝ_Á´éMaň¨€~ªSĈ½Ž½KÙóĿeƃÆBŽ·¬ën×W|Uº}LJrƳ˜lŒµ`bÔ`QˆˆÐÓ@s¬ñIŒÍ@ûws¡åQÑßÁ`ŋĴ{Ī“T•ÚÅTSij‚‹Yo|Ç[ǾµMW¢ĭiÕØ¿@˜šMh…pÕ]j†éò¿OƇĆƇp€êĉâlØw–ěsˆǩ‚ĵ¸c…bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB™Š\\”qTGªÇĜçPoŠÿfñòą¦óQīÈáP•œābß{ƒZŗĸIæńhnszÁCËìñšÏ·ąĚÝUm®ó­L·ăU›Èíoù´Êj°ŁŤ_uµ^‘°Œìǖ@tĶĒ¡Æ‡M³Ģ«˜İĨÅ®ğ†RŽāð“ggheÆ¢z‚Ê©Ô\\°ÝĎz~ź¤Pn–MĪÖB£Ÿk™n鄧żćŠ˜ĆK„Ē°¼L¶è‰âz¨u¦¥LDĘz¬ýÎmĘd¾ß”Fz“hg²™Fy¦ĝ¤ċņbΛ@y‚Ąæm°NĮZRÖíŽJ²öLĸÒ¨Y®ƌÐV‰à˜tt_ڀÂyĠzž]Ţh€zĎ{†ĢX”ˆc|šÐqŽšfO¢¤ög‚ÌHNŽ„PKŖœŽ˜Uú´xx[xˆvĐCûĀŠìÖT¬¸^}Ìsòd´_Ž‡KgžLĴ…ÀBon|H@–Êx˜—¦BpŰˆŌ¿fµƌA¾zLjRxŠ¶F”œkĄźRzŀˆ~¶[”´Hnª–VƞuĒ­È¨ƎcƽÌm¸ÁÈM¦x͊ëÀxdžB’šú^´W†£–d„kɾĬpœw‚˂ØɦļĬIŚœÊ•n›Ŕa¸™~J°î”lɌxĤÊÈðhÌ®‚g˜T´øŽàCˆŽÀ^ªerrƘdž¢İP|Ė ŸWœªĦ^¶´ÂL„aT±üWƜ˜ǀRšŶUńšĖ[QhlLüA†‹Ü\\†qR›Ą©"],"encodeOffsets":[[90849,37210]]},"properties":{"cp":[91.132212,29.660361],"name":"西藏","childNum":1}},{"id":"610000","geometry":{"type":"Polygon","coordinates":["@@¸œÂW¢xR­—ƒFq§uF—Œ@NŸ¢XLƒŠRMº[ğȣſï|¥J™kc`sʼnǷ’£Y³‹WN«ùM‘ëï³ÛIg÷±mTșڍÒķø©—þ¥ƒy‚ÓŸğęmWµÎumZyOŅƟĥÓ~sÑL¤µaŅY¦ocyZ{‰y c]{ŒTa©ƒ`U_Ěē£ωÊƍKù’K¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑd‘ŠìUYƒŽO‘uF–ÕÈYvÁCqӃT•Ǣí§·S¹NgŠV¬ë÷Át‡°Dد’C´ʼnƒópģ}„ąiE˅FŸŸéGU¥×K…§­¶³B‹Č}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO…ñJÙïŚ•ĤNĔŸwƇˆÄŠńwĪ­Šo[„_KÓª³“ÙnK‰Çƒěœÿ]ď€ă_d©·©Ýŏ°Ù®g]±„Ÿ‡ßš×¥¬÷m\\›iaǑkěX{¢|ZKlçhLt€Ňîŵ€œè[€É@ƉĄEœ‡tƇÏ˜³­ħZ«mJ…›×¾‘MtÝĦ£IwÄå\\Õ{‡˜ƒOwĬ©LÙ³ÙT“ª¿^™¦r̛ĢŭO¥lãyC§HÍ£ßEñŸX¡—­°ÙCgpťz‘ˆb`wI„vA|¥”‡—hoĕ@E±“iYd¥OÿµÇvPŒW|mCƒĴŜǂ҈W¶¸AĜh^Wx{@„¬‚­F¸¡„ķn£P|ŸªĴ@^ĠĈæb–Ôc¶l˜Yi…–^Mi˜cĎ°Â[ä€vï¶gv@À“Ĭ·lJ¸sn|¼u~a]’ÆÈtŌºJp’ƒþ£KKf~Š¦UbyäIšĺãn‡Ô¿^­žŵMT–hĠܤko¼Ŏìąǜh`[tŒRd²IJ_œXPrɲ‰l‘‚XžiL§àƒ–¹ŽH˜°Ȧqº®QC—bA†„ŌJ¸ĕÚ³ĺ§ `d¨YjžiZvRĺ±öVKkjGȊĐePОZmļKÀ€‚[ŠŽ`ösìh†ïÎoĬdtKÞ{¬èÒÒBŒÔpIJÇĬJŊ¦±J«ˆ[©ārH€µàåVKe§|P²ÇÓ·vUz‰gnN¾yI@oŸHĆۄķhx“e‘n¡QQ’±”ƝJ‹ǖRbzy€¸ËАl›¼EºpĤ¼Œx¼½~Ğ’”à@†ÚüdK^ˆmÌSjˆp²—ȮµšûG™Ħ}Ħšðǚ¶òƄ€jɂz°{ºØkÈęâ¦jª‚Bg‚\\œċ°s¬Ž’]jžú ‚E”Ȍdž¬s„t‡”RˆÆdĠݎwܔ¸ôW¾ƮłÒ_{’Ìšû¼„jº¹¢GǪÒ¯ĘƒZ`ºŊƒecņąš~BÂgzpâēòYƲȐπ"],"encodeOffsets":[[113634,40474]]},"properties":{"cp":[108.948024,34.263161],"name":"陕西","childNum":1}},{"id":"620000","geometry":{"type":"MultiPolygon","coordinates":[["@@Vu_^","@@ų‹EĠtt~nkh`Q‰¦ÅÄÜdw˜Ab×ĠąJˆ¤DüègĺqBqœj°lI¡Ĩ¶šĖIHdš‰ŠjΑBŠ°aZˆ¢KJŽ’O[|A£žDx}Nì•HUnrk„ kp€¼Y kMJn[aG‚áÚÏ[½rc†}aQxOgsPMnUs‡nc‹Z…ž–sKúvA›t„Þġ’£®ĀYKdnFwš¢JE°”Latf`¼h¬we|€Æ‡šbj}GA€·~WŽ”—`†¢MC¤tL©IJ°qdf”O‚“bÞĬ¹ttu`^ZúE`Œ[@„Æsîz®¡’C„ƳƜG²“R‘¢R’m”fŽwĸg܃‚ą G@pzJM½mŠhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬‡²I‚¥IʼnÈīoı‹ÓÑAçÑ|«LÝcspīðÍg…të_õ‰\\ĉñLYnĝg’ŸRǡÁiHLlõUĹ²uQjYi§Z_c¨Ÿ´ĹĖÙ·ŋI…ƒaBD˜­R¹ȥr—¯G•ºß„K¨jWk’ɱŠOq›Wij\\a­‹Q\\sg_ĆǛōëp»£lğۀgS•ŶN®À]ˆÓäm™ĹãJaz¥V}‰Le¤L„ýo‘¹IsŋÅÇ^‘Žbz…³tmEÁ´aŠ¹cčecÇN•ĊãÁ\\č¯—dNj•]j†—ZµkÓda•ćå]ğij@ ©O{¤ĸm¢ƒE·®ƒ«|@Xwg]Aģ±¯‡XǁÑdzªc›wQÚŝñsÕ³ÛV_ýƒ˜¥\\ů¥©¾÷w—Ž©WÕÊĩhÿÖÁRo¸V¬âDb¨šhûx–Ê×nj~Zâƒg|šXÁnßYoº§ZÅŘvŒ[„ĭÖʃuďxcVbnUSf…B¯³_Tzº—ΕO©çMÑ~Mˆ³]µ^püµ”ŠÄY~y@X~¤Z³€[Èōl@®Å¼£QKƒ·Di‹¡By‘ÿ‰Q_´D¥hŗyƒ^ŸĭÁZ]cIzý‰ah¹MĪğP‘s{ò‡‹‘²Vw¹t³Ŝˁ[ŽÑ}X\\gsFŸ£sPAgěp×ëfYHāďÖqēŭOÏë“dLü•\\iŒ”t^c®šRʺ¶—¢H°mˆ‘rYŸ£BŸ¹čIoľu¶uI]vģSQ{ƒUŻ”Å}QÂ|̋°ƅ¤ĩŪU ęĄžÌZҞ\\v˜²PĔ»ƢNHƒĂyAmƂwVmž`”]ȏb•”H`‰Ì¢²ILvĜ—H®¤Dlt_„¢JJÄämèÔDëþgºƫ™”aʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b…ð÷’Žˆ‡®‚”üs”zMzÖĖQdȨý†v§Tè|ªH’þa¸|šÐ ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v†·À|\\ƁĚN´Ĝ€çèÁz]ġ¤²¨QÒŨTIl‡ªťØ}¼˗ƦvÄùØE‹’«Fï˛Iq”ōŒTvāÜŏ‚íÛߜÛV—j³âwGăÂíNOŠˆŠPìyV³ʼnĖýZso§HіiYw[߆\\X¦¥c]ÔƩÜ·«j‡ÐqvÁ¦m^ċ±R™¦΋ƈťĚgÀ»IïĨʗƮŽ°Ɲ˜ĻþÍAƉſ±tÍEÕÞāNU͗¡\\ſčåÒʻĘm ƭÌŹöʥ’ëQ¤µ­ÇcƕªoIýˆ‰Iɐ_mkl³ă‰Ɠ¦j—¡Yz•Ňi–}Msßõ–īʋ —}ƒÁVmŸ_[n}eı­Uĥ¼‘ª•I{ΧDӜƻėoj‘qYhĹT©oūĶ£]ďxĩ‹ǑMĝ‰q`B´ƃ˺Ч—ç~™²ņj@”¥@đ´ί}ĥtPńǾV¬ufӃÉC‹tÓ̻‰…¹£G³€]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼ‚ĤŊɲĖ­KqĘʼn¼ĔDzņɾªǀÞĈĂD†½ĄĎÌŗĞrôñnŽœN¼â¾ʄľԆ|DŽŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿Ľ­ĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY…tÁƤyAã˾J@ǝrý‹‰@¤…rz¸oP¹ɐÚyᐇHŸĀ[Jw…cVeȴϜ»ÈŽĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔ—ĹŊũ~ËUă{ŸĻƹɁύȩþĽvĽƓÉ@ē„ĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶Ž¨c~c¼īŒeXǚ‹\\đ¾JŽwÀďksãA‹fÕ¦L}wa‚o”Z’‹D½†Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LF‹LzĈ„ôe]gx}•|KK}xklL]c¦£fRtív¦†PŨ£","@@Mš T‡¥"]],"encodeOffsets":[[[108619,36299],[108594,36341],[108600,36306]]]},"properties":{"cp":[103.823557,36.058039],"name":"甘肃","childNum":3}},{"id":"630000","geometry":{"type":"MultiPolygon","coordinates":[["@@InJo","@@CƒÆ½OŃĦsΰ~Ē³¦@@“Ņiš±è}ؘƄ˹A³r_ĞŠǒNĪŒĐw¤^ŬĵªpĺSZg’rpiƼĘԛ¨C|͖J’©Ħ»®VIJ~f\\m `Un„˜~ʌŸ•ĬàöNt•~ňjy–¢Zi˜Ɣ¥ĄŠk´nl`JʇŠJþ©pdƖ®È£¶ìRʦ‘źõƮËnŸʼėæÑƀĎ[‚˜¢VÎĂMÖÝÎF²sƊƀÎBļýƞ—¯ʘƭðħ¼Jh¿ŦęΌƇš¥²Q]Č¥nuÂÏriˆ¸¬ƪÛ^Ó¦d€¥[Wà…x\\ZŽjҕ¨GtpþYŊĕ´€zUO뇉P‰îMĄÁxH´á˜iÜUà›îÜՁĂÛSuŎ‹r“œJð̬EŒ‘FÁú×uÃÎkr“Ē{V}İ«O_ÌËĬ©ŽÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u…ºµ[gt£¸OƤĿéYŸõ·kĀŸq]juw¥Dĩƍ€õÇPéĽG‘ž©ã‡¤G…uȧþRcÕĕNy“yût“ˆ­‡ø‘†ï»a½ē¿BMoį£ŸÍj}éZËqbʍš“Ƭh¹ìÿÓAçãnIáI`ƒks£CG­ě˜Uy×Cy•…’Ÿ@¶ʡÊBnāzG„ơMē¼±O÷õJËĚăVŸĪũƆ£Œ¯{ËL½Ìzż“„VR|ĠTbuvJvµhĻĖH”Aëáa…­OÇðñęNw‡…œľ·L›mI±íĠĩPÉ×®ÿs—’cB³±JKßĊ«`…ađ»·QAmO’‘Vţéÿ¤¹SQt]]Çx€±¯A@ĉij¢Óļ©•ƒl¶ÅÛr—ŕspãRk~¦ª]Į­´“FR„åd­ČsCqđéFn¿Åƃm’Éx{W©ºƝºįkÕƂƑ¸wWūЩÈFž£\\tÈ¥ÄRÈýÌJ ƒlGr^×äùyÞ³fj”c†€¨£ÂZ|ǓMĝšÏ@ëÜőR‹›ĝ‰Œ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³’­ÞIňµç½©C¡į÷¯B»|St»›]vƒųƒs»”}MÓ ÿʪƟǭA¡fs˜»PY¼c¡»¦c„ċ­¥£~msĉP•–Siƒ^o©A‰Šec‚™PeǵŽkg‚yUi¿h}aH™šĉ^|ᴟ¡HØûÅ«ĉ®]m€¡qċ¶±ÈyôōLÁst“BŸ®wn±ă¥HSòėš£˜S’ë@לÊăxÇN©™©T±ª£IJ¡fb®ÞbŽb_Ą¥xu¥B—ž{łĝ³«`d˜Ɛt—¤ťiñžÍUuºí`£˜^tƃIJc—·ÛLO‹½Šsç¥Ts{ă\\_»™kϊ±q©čiìĉ|ÍIƒ¥ć¥›€]ª§D{ŝŖÉR_sÿc³Īō›ƿΑ›§p›[ĉ†›c¯bKm›R¥{³„Z†e^ŽŒwx¹dƽŽôIg §Mĕ ƹĴ¿—ǣÜ̓]‹Ý–]snåA{‹eŒƭ`ǻŊĿ\\ijŬű”YÂÿ¬jĖqŽßbŠ¸•L«¸©@ěĀ©ê¶ìÀEH|´bRľž–Ó¶rÀQþ‹vl®Õ‚E˜TzÜdb ˜hw¤{LR„ƒd“c‹b¯‹ÙVgœ‚ƜßzÃô쮍^jUèXΖ|UäÌ»rKŽ\\ŒªN‘¼pZCü†VY††¤ɃRi^rPҒTÖ}|br°qňbĚ°ªiƶGQ¾²„x¦PœmlŜ‘[Ĥ¡ΞsĦŸÔÏâ\\ªÚŒU\\f…¢N²§x|¤§„xĔsZPòʛ²SÐqF`ª„VƒÞŜĶƨVZŒÌL`ˆ¢dŐIqr\\oäõ–F礻Ŷ×h¹]Clـ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ”´ÃbEÄlbʔC”|CˆŮˆk„Ʈ[ʼ¬ňœ´KŮÈΰÌĪ¶ƶlð”ļA†TUvdTŠG†º̼ŠÔ€ŒsÊDԄveMg"]],"encodeOffsets":[[[105308,37219],[95370,40081]]]},"properties":{"cp":[101.778916,36.623178],"name":"青海","childNum":2}},{"id":"640000","geometry":{"type":"Polygon","coordinates":["@@KëÀęĞ«OęȿȕŸı]ʼn¡åįÕÔ«Ǵõƪ™ĚQÐZhv K°›öqÀѐS[ÃÖHƖčË‡nL]ûc…Ùß@‚“ĝ‘¾}w»»‹oģF¹œ»kÌÏ·{zPƒ§B­¢íyÅt@ƒ@áš]Yv_ssģ¼i߁”ĻL¾ġsKD£¡N_…“˜X¸}B~Haiˆ™Åf{«x»ge_bs“KF¯¡Ix™mELcÿZ¤­Ģ‘ƒÝœsuBLù•t†ŒYdˆmVtNmtOPhRw~bd…¾qÐ\\âÙH\\bImlNZŸ»loƒŸqlVm–Gā§~QCw¤™{A\\‘PKŸNY‡¯bF‡kC¥’sk‹Šs_Ã\\ă«¢ħkJi¯r›rAhĹûç£CU‡ĕĊ_ԗBixÅُĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~–hw^‚ófćƒKyEŒ­K­zuÔ¡qQ¤xZÑ¢^ļöܾEpž±âbÊÑÆ^fk¬…NC¾‘Œ“YpxbK~¥Že֎ŒäBlt¿Đx½I[ĒǙŒWž‹f»Ĭ}d§dµùEuj¨‚IÆ¢¥dXªƅx¿]mtÏwßRĶŒX¢͎vÆzƂZò®ǢÌʆCrâºMÞzžÆMҔÊÓŊZľ–r°Î®Ȉmª²ĈUªĚøºˆĮ¦ÌĘk„^FłĬhĚiĀĖ¾iİbjË"],"encodeOffsets":[[109366,40242]]},"properties":{"cp":[106.278179,38.46637],"name":"宁夏","childNum":1}},{"id":"650000","geometry":{"type":"Polygon","coordinates":["@@QØĔ²X¨”~ǘBºjʐßØvK”ƔX¨vĊOžÃƒ·¢i@~c—‡ĝe_«”Eš“}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX…ê•Îf`œC‚¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥Oéȇ¿ÖğǤǷÂF҇zÉx[]­Ĥĝ‰œ¦EP}ûƥé¿İƷTėƫœŕƅ™ƱB»Đ±’ēO…¦E–•}‘`cȺrĦáŖuҞª«IJ‡πdƺÏØZƴwʄ¤ĖGЙǂZĶƒèH¶}ÚZצʥĪï|ÇĦMŔ»İĝLj‹ì¥Βœba­¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»›òmqóŘĝč˾ăC…ćāƿÝɽ©DZŅ»ēėŊLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕŠUv£ƁQï“Ƶkŏ½ΉÃŭdzLқʻ«ƭ\\lƒ‡ŭD‡“{ʓDkaFÃÄa“³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍö•€ůʼnT¡c_‡ËKY‹ƧUśĵ„݃U_©rETÏʜ±OñtYwē¨ƒ{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\‚ś’nkO›w¥±ƒT»ƷFɯàĩÞáB¹Æ…ÑUw„੍žĽw]•kE½Èå~‡Æ÷QyŠěCFmĭZī—ŵVÁ™ƿQƛ—ûXS²‰b½KϽĉS›©ŷXĕŸ{ŽĕK·¥Ɨcqq©f¿]‡ßDõU³h—­gËÇïģÉɋw“k¯í}I·šœbmœÉ–ř›īJɥĻˁ×xo›ɹī‡l•c…¤³Xù]‘™DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®Ɲv•Um©³G\\“}µĿ‡QyŹl㓛µEw‰LJQ½yƋBe¶ŋÀů‡ož¥A—˜Éw@•{Gpm¿Aij†ŽKLhˆ³`ñcËtW‚±»ÕS‰ëüÿďD‡u\\wwwù³—V›LŕƒOMËGh£õP¡™er™Ïd{“‡ġWÁ…č|yšg^ğyÁzÙs`—s|ÉåªÇ}m¢Ń¨`x¥’ù^•}ƒÌ¥H«‰Yªƅ”Aйn~ź¯šf¤áÀz„gŠÇDIԝ´AňĀ҄¶ûEYospõD[{ù°]u›Jq•U•|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw €ÞkrťË¿XGÉbřaDü·Ē÷Aê[Ää€I®BÕИÞ_¢āĠpŠÛÄȉĖġDKwbm‡ÄNô‡ŠfœƫVÉvi†dz—H‘‹QµâFšù­Âœ³¦{YGžƒd¢ĚÜO „€{Ö¦ÞÍÀPŒ^b–ƾŠl[‚vt×ĈÍE˨¡Đ~´î¸ùÎh€uè`¸ŸHÕŔVºwĠââWò‡@{œÙNÝ´ə²ȕn{¿¥{l—÷eé^e’ďˆXj©î\\ªÑò˜Üìc\\üqˆÕ[Č¡xoÂċªbØ­Œø|€¶ȴZdÆšońéŒGš\\”¼C°ÌƁn´nxšÊOĨ’Ūƴĸ¢¸òTxÊǪMīИÖŲÃɎOvˆʦƢ~FŽ‡Rěò—¿ġ~åŊœú‰Nšžš¸qŽ’Ę[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾œĄYÒ©ÊfºmԈĘcDoĬMŬ’˜S¤„s²‚”ʘچžȂVŦ –ŽèW°ªB|IJXŔþÈJĦÆæFĚêŠYĂªĂ]øªŖNÞüA€’fɨJ€˜¯ÎrDDšĤ€`€mz\\„§~D¬{vJÂ˜«lµĂb–¤p€ŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMT”‡òP˜÷fØĶK¢ȝ˔Sô¹òEð­”`Ɩ½ǒÂň×äı–§ĤƝ§C~¡‚hlå‚ǺŦŞkâ’~}ŽFøàIJaĞ‚fƠ¥Ž„Ŕdž˜®U¸ˆźXœv¢aƆúŪtŠųƠjd•ƺŠƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬŠ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹œ\\ĜÑŚŸ¶ZƄ³âjĦoâŠȴLʉȮŒĐ­ĚăŽÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§΢{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTŠiƢ¾ªì°`öøu®Ê¾ãÖ"],"encodeOffsets":[[88824,50096]]},"properties":{"cp":[87.617733,43.792818],"name":"新疆","childNum":1}},{"id":"110000","geometry":{"type":"Polygon","coordinates":["@@R„ºaY՜™QaúÍÔiþĩȨWĢ‹ü|Ėu[qb[swP@ÅğP¿{\\‡¯Y²·‘Ѩj¯ŠX\\¯œMSvU¯YIŕY{[fk­VÁ›ûtŷmiÍt_H»Ĩ±d`Š¹­{bw…Yr“³S]§§o¹€qGtm_Sŧ€“oa›‹FLg‘QN_•dV€@Zom_ć\\ߚW´—€ÕiœRcfi…Ÿ’o§ËgToÛJíĔóu…|wP¤™XnO¢ÉŠŦ¯pNÄā¤zâŖÈRpŢZŠœÚ{GŠrFt¦Òx§ø¹RóäV¤XdˆżâºWbwŚ¨Ud®bêņ¾‘jnŎGŃŶŠnzÚScîĚZŠen¬"],"encodeOffsets":[[119421,42013]]},"properties":{"cp":[116.405285,39.904989],"name":"北京","childNum":1}},{"id":"120000","geometry":{"type":"Polygon","coordinates":["@@ŬgX§Ü«E…¶Ḟ“¬O_™ïlÁg“z±AXe™µÄĵ{¶]gitgšIj·›¥ì_iU€‰¨ÐƎk}ĕ{gB—qGf{¿a†U^fI“ư‹³õ{YƒıëNĿžk©ïËZukāA‘īlĕĥs¡bġ«@dekąI[nlPqCnp{ˆō³°`{PNdƗqSÄĻNNâyj]äžÒD ĬH°Æ]~¡HO¾ŒX}ÐxŒgp“gWˆrDGˆŒpù‚Š^L‚ˆrzWxˆZ^¨´T\\|~@I‰zƒ–bĤ‹œjeĊªz£®Ĕvě€L†mV¾Ô_ȔNW~zbĬvG†²ZmDM~”~"],"encodeOffsets":[[120237,41215]]},"properties":{"cp":[117.190182,39.125596],"name":"天津","childNum":1}},{"id":"310000","geometry":{"type":"MultiPolygon","coordinates":[["@@ɧư¬EpƸÁx]‡","@@©„²ƒ","@@”MA‹“˜","@@QpªK†WT…‰‰§¨","@@bŝՕÕEȣÚƥêImɇǦèÜĠŒÚÄÓŴ·ʌÇ","@@S‚ô¤r]ì†ƬįǜûȬɋŠŭ™×^‰sYŒɍDŋ‘ŽąñCG²«ªč@h–_p¯A{‡oloY€¬j@IJ`•gQڙpptǀ^MIJvtbe´Rh@–oj¨ž","@@ÆLH{a}Eo¦"]],"encodeOffsets":[[[124702,32062],[124547,32200],[124808,31991],[124726,32110],[124903,32376],[124065,32166],[124870,31965]]]},"properties":{"cp":[121.472644,31.231706],"name":"上海","childNum":7}},{"id":"500000","geometry":{"type":"Polygon","coordinates":["@@TÂÛ`Ùƅően½S‹êqDu[R‹å͹ˆ÷eXÍy‘¸_ĺę}÷`M¯ċfCVµqʼn÷Z•gg‘Œ^d½pDO‡ÎCnœ^uf²ènh¼WtƏxRGg¦…pV„†FI±ŽG^ŒIc´ec‡’G•ĹÞ½sëÆNä̤“Kӈe¯|‚R¸§L‘ÜkPoïƭNï¶}Gy“wdiù©nkĈzjŸ•@™Óc£»Wă¹Óf§c[µŠo·Ó|MvÛaqœ½«‡èœ’\\ÂoVnŽÓØ͙²«‹bq¿eƒhCž„€‹Ĝ^Qž~ Évý‡ş¤²Į‰pEĶyhsŊwH‹½‡š¿gņ›¡ýE¡ya£³t\\¨\\vú¹¼©·Ñr_oÒý¥‚‘et³]—Et©uÖ¥±ă©KVeëƒ]}wVPÀFA¨ąB}qTjgRemfFm‰QF݅My˜ù•nцAmыCaƒwŒu_p—¯sfۍ_g†“I_pNysBŠ¦zG¸rHe‚„N\\CvEsÐñÚkcD‘ÖĉsaQ¯€}_U‡†zÁēˆ}Ÿ^R •Äd^ÍĸZ¾·¶ƒ`wećJEž¹vÛ·Hgƒ‚éFXjÉê`|yŒpxkAwœWĐpb¥eOsmzwqChóUQl¥F^laf‹anòsr›EvfQdÁUVf—ÎvÜ^efˆtET¬ôA\\œ¢sJŽnQTjP؈xøK|nBz‰„œĞ»LY‚…FDxӄvr“[ehľš•vN”¢o¾NiÂxGp⬐z›bfZo~hGi’]öF|‰|Nb‡tOMn eA±ŠtPT‡LjpYQ|†SH††YĀxinzDJ€Ìg¢và¥Pg‰_–ÇzII‹€II•„£®S¬„Øsμ–¥¨^LšnGIJļIJƤjÎƀƾ¹¸ØÎezĆT¸}êЖqHŸðqĖ䒊¥^CƒIj–²p…\\_ æüY|[YxƊæuž°xb®…Űb@~¢NQt°¶‚S栓Ê~rljĔëĚ¢~šuf`‘‚†fa‚ĔJåĊ†nÔ]„jƎćÊ@Š£¾a®£Ű{ŶĕF‹ègLk{Y|¡ĜWƔtƬJÑxq‹±ĢN´‰òK‰™–LÈüD|s`ŋ’ć]ƒÃ‰`đŒMùƱ¿~Y°ħ`ƏíW‰½eI‹½{aŸ‘OIrÏ¡ĕŇa†p†µÜƃġ‰²"],"encodeOffsets":[[111728,31311]]},"properties":{"cp":[106.504962,29.533155],"name":"重庆","childNum":1}},{"id":"810000","geometry":{"type":"MultiPolygon","coordinates":[["@@AlFi","@@mŽp","@@EpHo","@@rMUw‡AS¬€]","@@ea¢pl¸Eõ¹‡hj[ƒ]ÔCΖ@lj˜¡uBXŸ…•´‹AI¹…[‹yDUˆ]W`çwZkmc–…M›žp€Åv›}I‹oJlcaƒfёKŽ°ä¬XJmРđhI®æÔtSHn€Eˆ„ÒrÄc"]],"encodeOffsets":[[[117111,23002],[117072,22876],[117045,22887],[116882,22747],[116975,23082]]]},"properties":{"cp":[114.173355,22.320048],"name":"香港","childNum":5}},{"id":"820000","geometry":{"type":"Polygon","coordinates":["@@œá—w{ÎrŽ"],"encodeOffsets":[[116285,22746]]},"properties":{"cp":[113.54909,22.198951],"name":"澳门","childNum":1}}],"UTF8Encoding":true}
+
+export default chinaMap;
\ No newline at end of file
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 00000000..9d57118c
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,14 @@
+export const setProperty = (prop: string, val: any, dom = document.documentElement) => {
+    dom.style.setProperty(prop, val);
+};
+
+export const mix = (color1: string, color2: string, weight: number = 0.5): string => {
+    let color = '#';
+    for (let i = 0; i <= 2; i++) {
+        const c1 = parseInt(color1.substring(1 + i * 2, 3 + i * 2), 16);
+        const c2 = parseInt(color2.substring(1 + i * 2, 3 + i * 2), 16);
+        const c = Math.round(c1 * weight + c2 * (1 - weight));
+        color += c.toString(16).padStart(2, '0');
+    }
+    return color;
+};
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 2aaaf771..3453061a 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -1,31 +1,31 @@
-import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
-
-const service: AxiosInstance = axios.create({
-    timeout: 5000
-});
-
-service.interceptors.request.use(
-    (config: InternalAxiosRequestConfig) => {
-        return config;
-    },
-    (error: AxiosError) => {
-        console.log(error);
-        return Promise.reject();
-    }
-);
-
-service.interceptors.response.use(
-    (response: AxiosResponse) => {
-        if (response.status === 200) {
-            return response;
-        } else {
-            Promise.reject();
-        }
-    },
-    (error: AxiosError) => {
-        console.log(error);
-        return Promise.reject();
-    }
-);
-
-export default service;
+import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
+
+const service: AxiosInstance = axios.create({
+    timeout: 5000
+});
+
+service.interceptors.request.use(
+    (config: InternalAxiosRequestConfig) => {
+        return config;
+    },
+    (error: AxiosError) => {
+        console.log(error);
+        return Promise.reject();
+    }
+);
+
+service.interceptors.response.use(
+    (response: AxiosResponse) => {
+        if (response.status === 200) {
+            return response;
+        } else {
+            Promise.reject();
+        }
+    },
+    (error: AxiosError) => {
+        console.log(error);
+        return Promise.reject();
+    }
+);
+
+export default service;
diff --git a/src/views/403.vue b/src/views/403.vue
deleted file mode 100644
index c7132708..00000000
--- a/src/views/403.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-<template>
-	<div class="error-page">
-		<div class="error-code">4<span>0</span>3</div>
-		<div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
-		<div class="error-handle">
-			<router-link to="/">
-				<el-button type="primary" size="large">返回首页</el-button>
-			</router-link>
-			<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
-		</div>
-	</div>
-</template>
-
-<script setup lang="ts" name="403">
-import { useRouter } from 'vue-router';
-
-const router = useRouter();
-const goBack = () => {
-	router.go(-2);
-};
-</script>
-
-<style scoped>
-.error-page {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	flex-direction: column;
-	width: 100%;
-	height: 100%;
-	background: #f3f3f3;
-	box-sizing: border-box;
-}
-.error-code {
-	line-height: 1;
-	font-size: 250px;
-	font-weight: bolder;
-	color: #f02d2d;
-}
-.error-code span {
-	color: #00a854;
-}
-.error-desc {
-	font-size: 30px;
-	color: #777;
-}
-.error-handle {
-	margin-top: 30px;
-	padding-bottom: 200px;
-}
-.error-btn {
-	margin-left: 100px;
-}
-</style>
diff --git a/src/views/404.vue b/src/views/404.vue
deleted file mode 100644
index a4dfcf20..00000000
--- a/src/views/404.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-<template>
-	<div class="error-page">
-		<div class="error-code">4<span>0</span>4</div>
-		<div class="error-desc">啊哦~ 你所访问的页面不存在</div>
-		<div class="error-handle">
-			<router-link to="/">
-				<el-button type="primary" size="large">返回首页</el-button>
-			</router-link>
-			<el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
-		</div>
-	</div>
-</template>
-
-<script setup lang="ts" name="404">
-import { useRouter } from 'vue-router';
-
-const router = useRouter();
-const goBack = () => {
-	router.go(-1);
-};
-</script>
-
-<style scoped>
-.error-page {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	flex-direction: column;
-	width: 100%;
-	height: 100%;
-	background: #f3f3f3;
-	box-sizing: border-box;
-}
-.error-code {
-	line-height: 1;
-	font-size: 250px;
-	font-weight: bolder;
-	color: #2d8cf0;
-}
-.error-code span {
-	color: #00a854;
-}
-.error-desc {
-	font-size: 30px;
-	color: #777;
-}
-.error-handle {
-	margin-top: 30px;
-	padding-bottom: 200px;
-}
-.error-btn {
-	margin-left: 100px;
-}
-</style>
diff --git a/src/views/chart/echarts.vue b/src/views/chart/echarts.vue
new file mode 100644
index 00000000..9b9ef0d9
--- /dev/null
+++ b/src/views/chart/echarts.vue
@@ -0,0 +1,87 @@
+<template>
+    <div class="container">
+        <div class="plugins-tips">
+            vue-echarts:Apache ECharts™ 的 Vue.js 组件。 访问地址:
+            <a href="https://github.com/ecomfe/vue-echarts" target="_blank">vue-echarts</a>
+        </div>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">柱状图</div>
+            </template>
+            <v-chart class="schart" :option="barOptions" />
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">折线图</div>
+            </template>
+            <v-chart class="schart" :option="lineOptions" />
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">饼状图</div>
+            </template>
+            <v-chart class="schart" :option="pieOptions" />
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">环形图</div>
+            </template>
+            <v-chart class="schart" :option="ringOptions" />
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">词云图</div>
+            </template>
+            <v-chart class="schart" :option="wordOptions" />
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">地图</div>
+            </template>
+            <v-chart class="schart" :option="mapOptions" />
+        </el-card>
+    </div>
+</template>
+
+<script setup lang="ts" name="echarts">
+import { registerMap, use } from 'echarts/core';
+import { BarChart, LineChart, PieChart, MapChart } from 'echarts/charts';
+import {
+    GridComponent,
+    TooltipComponent,
+    LegendComponent,
+    TitleComponent,
+    VisualMapComponent,
+} from 'echarts/components';
+import { CanvasRenderer } from 'echarts/renderers';
+import VChart from 'vue-echarts';
+import 'echarts-wordcloud';
+import { barOptions, lineOptions, pieOptions, ringOptions, wordOptions, mapOptions } from './options';
+import chinaMap from '@/utils/china';
+use([
+    CanvasRenderer,
+    BarChart,
+    GridComponent,
+    LineChart,
+    PieChart,
+    MapChart,
+    TooltipComponent,
+    LegendComponent,
+    TitleComponent,
+    VisualMapComponent,
+]);
+registerMap('china', chinaMap);
+</script>
+
+<style scoped>
+.schart {
+    width: 100%;
+    height: 400px;
+}
+
+.content-title {
+    font-weight: 400;
+    font-size: 22px;
+    color: #1f2f3d;
+}
+</style>
diff --git a/src/views/chart/options.ts b/src/views/chart/options.ts
new file mode 100644
index 00000000..75705ca1
--- /dev/null
+++ b/src/views/chart/options.ts
@@ -0,0 +1,345 @@
+import { graphic } from 'echarts/core';
+export const barOptions = {
+    xAxis: {
+        type: 'category',
+        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+    },
+    yAxis: {
+        type: 'value',
+    },
+    tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+            type: 'shadow',
+        },
+    },
+    color: ['#009688', '#f44336'],
+    series: [
+        {
+            data: [120, 200, 150, 80, 70, 110, 130],
+            type: 'bar',
+        },
+        {
+            data: [180, 230, 190, 120, 110, 230, 235],
+            type: 'bar',
+        },
+    ],
+};
+
+export const lineOptions = {
+    tooltip: {
+        trigger: 'axis',
+    },
+    grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '3%',
+        containLabel: true,
+    },
+    xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+    },
+    yAxis: {
+        type: 'value',
+    },
+    color: ['#009688', '#f44336'],
+    series: [
+        {
+            name: 'Email',
+            type: 'line',
+            stack: 'Total',
+            areaStyle: {},
+            smooth: true,
+            data: [120, 132, 101, 134, 90, 230, 210],
+        },
+        {
+            name: 'Union Ads',
+            type: 'line',
+            stack: 'Total',
+            areaStyle: {},
+            smooth: true,
+            data: [220, 182, 191, 234, 290, 330, 310],
+        },
+    ],
+};
+
+export const pieOptions = {
+    title: {
+        text: 'Referer of a Website',
+        subtext: 'Fake Data',
+        left: 'center',
+    },
+    tooltip: {
+        trigger: 'item',
+    },
+    legend: {
+        orient: 'vertical',
+        left: 'left',
+    },
+    series: [
+        {
+            name: 'Access From',
+            type: 'pie',
+            radius: '50%',
+            data: [
+                { value: 1048, name: 'Search Engine' },
+                { value: 735, name: 'Direct' },
+                { value: 580, name: 'Email' },
+                { value: 484, name: 'Union Ads' },
+                { value: 300, name: 'Video Ads' },
+            ],
+            emphasis: {
+                itemStyle: {
+                    shadowBlur: 10,
+                    shadowOffsetX: 0,
+                    shadowColor: 'rgba(0, 0, 0, 0.5)',
+                },
+            },
+        },
+    ],
+};
+
+export const wordOptions = {
+    series: [
+        {
+            type: 'wordCloud',
+            rotationRange: [0, 0],
+            autoSize: {
+                enable: true,
+                minSize: 14,
+            },
+            textStyle: {
+                fontFamily: '微软雅黑,sans-serif',
+                color: function () {
+                    return (
+                        'rgb(' +
+                        [
+                            Math.round(Math.random() * 160),
+                            Math.round(Math.random() * 160),
+                            Math.round(Math.random() * 160),
+                        ].join(',') +
+                        ')'
+                    );
+                },
+            },
+            data: [
+                {
+                    name: 'Vue',
+                    value: 10000,
+                },
+                {
+                    name: 'React',
+                    value: 9000,
+                },
+                {
+                    name: '图表',
+                    value: 4000,
+                },
+                {
+                    name: '产品',
+                    value: 7000,
+                },
+                {
+                    name: 'vue-manage-system',
+                    value: 2000,
+                },
+                {
+                    name: 'element-plus',
+                    value: 6000,
+                },
+                {
+                    name: '管理系统',
+                    value: 5000,
+                },
+                {
+                    name: '前端',
+                    value: 4000,
+                },
+                {
+                    name: '测试',
+                    value: 3000,
+                },
+                {
+                    name: '后端',
+                    value: 8000,
+                },
+                {
+                    name: '软件开发',
+                    value: 6000,
+                },
+                {
+                    name: '程序员',
+                    value: 4000,
+                },
+            ],
+        },
+    ],
+};
+
+export const ringOptions = {
+    tooltip: {
+        trigger: 'item',
+    },
+    legend: {
+        top: '5%',
+        left: 'center',
+    },
+
+    series: [
+        {
+            name: 'Access From',
+            type: 'pie',
+            radius: ['40%', '70%'],
+            avoidLabelOverlap: false,
+            itemStyle: {
+                borderRadius: 10,
+                borderColor: '#fff',
+                borderWidth: 2,
+            },
+            label: {
+                show: false,
+                position: 'center',
+            },
+            emphasis: {
+                label: {
+                    show: true,
+                    fontSize: 40,
+                    fontWeight: 'bold',
+                },
+            },
+            labelLine: {
+                show: false,
+            },
+            data: [
+                { value: 1048, name: 'Search Engine' },
+                { value: 735, name: 'Direct' },
+                { value: 580, name: 'Email' },
+                { value: 484, name: 'Union Ads' },
+                { value: 300, name: 'Video Ads' },
+            ],
+        },
+    ],
+};
+
+export const dashOpt1 = {
+    xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+    },
+    yAxis: {
+        type: 'value',
+    },
+    grid: {
+        top: '2%',
+        left: '2%',
+        right: '3%',
+        bottom: '2%',
+        containLabel: true,
+    },
+    color: ['#009688', '#f44336'],
+    series: [
+        {
+            type: 'line',
+            areaStyle: {
+                color: new graphic.LinearGradient(0, 0, 0, 1, [
+                    {
+                        offset: 0,
+                        color: 'rgba(0, 150, 136,0.8)',
+                    },
+                    {
+                        offset: 1,
+                        color: 'rgba(0, 150, 136,0.2)',
+                    },
+                ]),
+            },
+            smooth: true,
+            data: [120, 132, 301, 134, 90, 230, 210],
+        },
+        {
+            type: 'line',
+            smooth: true,
+            data: [220, 122, 191, 234, 190, 130, 310],
+        },
+    ],
+};
+
+export const dashOpt2 = {
+    legend: {
+        bottom: '1%',
+        left: 'center',
+    },
+    color: ['#3f51b5', '#009688', '#f44336', '#00bcd4', '#1ABC9C'],
+    series: [
+        {
+            type: 'pie',
+            radius: ['40%', '70%'],
+            avoidLabelOverlap: false,
+            itemStyle: {
+                borderRadius: 10,
+                borderColor: '#fff',
+                borderWidth: 2,
+            },
+            data: [
+                { value: 1048, name: '数码' },
+                { value: 735, name: '食品' },
+                { value: 580, name: '母婴' },
+                { value: 484, name: '家电' },
+                { value: 300, name: '运动' },
+            ],
+        },
+    ],
+};
+
+export const mapOptions = {
+    tooltip: {
+        trigger: 'item',
+    },
+    geo: {
+        map: 'china',
+        roam: false,
+        emphasis: {
+            label: {
+                show: false,
+            },
+        },
+    },
+    visualMap: {
+        show: false,
+        min: 0,
+        max: 100,
+        realtime: false,
+        calculable: false,
+        inRange: {
+            color: ['#d2e0f5', '#71A9FF'],
+        },
+    },
+    series: [
+        {
+            geoIndex: 0,
+            name: '地域分布',
+            type: 'map',
+            coordinateSystem: 'geo',
+            map: 'china',
+            data: [
+                { name: '北京', value: 100 },
+                { name: '上海', value: 100 },
+                { name: '广东', value: 100 },
+                { name: '浙江', value: 90 },
+                { name: '江西', value: 80 },
+                { name: '山东', value: 70 },
+                { name: '广西', value: 60 },
+                { name: '河南', value: 50 },
+                { name: '河南', value: 40 },
+                { name: '青海', value: 70 },
+                { name: '河南', value: 30 },
+                { name: '黑龙江', value: 20 },
+                { name: '新疆', value: 20 },
+                { name: '云南', value: 20 },
+                { name: '甘肃', value: 20 },
+            ],
+        },
+    ],
+};
diff --git a/src/views/charts.vue b/src/views/chart/schart.vue
similarity index 64%
rename from src/views/charts.vue
rename to src/views/chart/schart.vue
index 7e4df52a..4e1ac90a 100644
--- a/src/views/charts.vue
+++ b/src/views/chart/schart.vue
@@ -1,127 +1,129 @@
-<template>
-	<div class="container">
-		<div class="plugins-tips">
-			vue-schart:vue.js封装sChart.js的图表组件。 访问地址:
-			<a href="https://github.com/lin-xin/vue-schart" target="_blank">vue-schart</a>
-		</div>
-		<div class="schart-box">
-			<div class="content-title">柱状图</div>
-			<schart class="schart" canvasId="bar" :options="options1"></schart>
-		</div>
-		<div class="schart-box">
-			<div class="content-title">折线图</div>
-			<schart class="schart" canvasId="line" :options="options2"></schart>
-		</div>
-		<div class="schart-box">
-			<div class="content-title">饼状图</div>
-			<schart class="schart" canvasId="pie" :options="options3"></schart>
-		</div>
-		<div class="schart-box">
-			<div class="content-title">环形图</div>
-			<schart class="schart" canvasId="ring" :options="options4"></schart>
-		</div>
-	</div>
-</template>
-
-<script setup lang="ts" name="basecharts">
-import Schart from 'vue-schart';
-
-const options1 = {
-	type: 'bar',
-	title: {
-		text: '最近一周各品类销售图'
-	},
-	bgColor: '#fbfbfb',
-	labels: ['周一', '周二', '周三', '周四', '周五'],
-	datasets: [
-		{
-			label: '家电',
-			fillColor: 'rgba(241, 49, 74, 0.5)',
-			data: [234, 278, 270, 190, 230]
-		},
-		{
-			label: '百货',
-			data: [164, 178, 190, 135, 160]
-		},
-		{
-			label: '食品',
-			data: [144, 198, 150, 235, 120]
-		}
-	]
-};
-const options2 = {
-	type: 'line',
-	title: {
-		text: '最近几个月各品类销售趋势图'
-	},
-	bgColor: '#fbfbfb',
-	labels: ['6月', '7月', '8月', '9月', '10月'],
-	datasets: [
-		{
-			label: '家电',
-			data: [234, 278, 270, 190, 230]
-		},
-		{
-			label: '百货',
-			data: [164, 178, 150, 135, 160]
-		},
-		{
-			label: '食品',
-			data: [114, 138, 200, 235, 190]
-		}
-	]
-};
-const options3 = {
-	type: 'pie',
-	title: {
-		text: '服装品类销售饼状图'
-	},
-	legend: {
-		position: 'left'
-	},
-	bgColor: '#fbfbfb',
-	labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
-	datasets: [
-		{
-			data: [334, 278, 190, 235, 260, 200, 141]
-		}
-	]
-};
-const options4 = {
-	type: 'ring',
-	title: {
-		text: '环形三等分'
-	},
-	showValue: false,
-	legend: {
-		position: 'bottom',
-		bottom: 40
-	},
-	bgColor: '#fbfbfb',
-	labels: ['vue', 'react', 'angular'],
-	datasets: [
-		{
-			data: [500, 500, 500]
-		}
-	]
-};
-</script>
-
-<style scoped>
-.schart-box {
-	display: inline-block;
-	margin: 20px;
-}
-.schart {
-	width: 600px;
-	height: 400px;
-}
-.content-title {
-	clear: both;
-	font-weight: 400;
-	line-height: 50px;
-	margin: 10px 0;
-	font-size: 22px;
-	color: #1f2f3d;
-}
-</style>
+<template>
+	<div class="container">
+		<div class="plugins-tips">
+			vue-schart:vue.js封装sChart.js的图表组件。 访问地址:
+			<a href="https://github.com/lin-xin/vue-schart" target="_blank">vue-schart</a>
+		</div>
+		<el-card class="mgb20" shadow="hover">
+			<template #header>
+				<div class="content-title">柱状图</div>
+			</template>
+			<schart class="schart" canvasId="bar" :options="options1"></schart>
+		</el-card>
+		<el-card class="mgb20" shadow="hover">
+			<template #header>
+				<div class="content-title">折线图</div>
+			</template>
+			<schart class="schart" canvasId="line" :options="options2"></schart>
+		</el-card>
+		<el-card class="mgb20" shadow="hover">
+			<template #header>
+				<div class="content-title">饼状图</div>
+			</template>
+			<schart class="schart" canvasId="pie" :options="options3"></schart>
+		</el-card>
+		<el-card class="mgb20" shadow="hover">
+			<template #header>
+				<div class="content-title">环形图</div>
+			</template>
+			<schart class="schart" canvasId="ring" :options="options4"></schart>
+		</el-card>
+	</div>
+</template>
+
+<script setup lang="ts" name="schart">
+import Schart from 'vue-schart';
+
+const options1 = {
+	type: 'bar',
+	title: {
+		text: '最近一周各品类销售图'
+	},
+	colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
+	labels: ['周一', '周二', '周三', '周四', '周五'],
+	datasets: [
+		{
+			label: '家电',
+			// fillColor: 'rgba(241, 49, 74, 0.5)',
+			data: [234, 278, 270, 190, 230]
+		},
+		{
+			label: '百货',
+			data: [164, 178, 190, 135, 160]
+		},
+		{
+			label: '食品',
+			data: [144, 198, 150, 235, 120]
+		}
+	]
+};
+const options2 = {
+	type: 'line',
+	title: {
+		text: '最近几个月各品类销售趋势图'
+	},
+	colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
+	labels: ['6月', '7月', '8月', '9月', '10月'],
+	datasets: [
+		{
+			label: '家电',
+			data: [234, 278, 270, 190, 230]
+		},
+		{
+			label: '百货',
+			data: [164, 178, 150, 135, 160]
+		},
+		{
+			label: '食品',
+			data: [114, 138, 200, 235, 190]
+		}
+	]
+};
+const options3 = {
+	type: 'pie',
+	title: {
+		text: '服装品类销售饼状图'
+	},
+	legend: {
+		position: 'left'
+	},
+	colorList: ["#2196f3", '#673ab7', "#009688", "#1ABC9C", "#3f51b5", "#f44336", "#00bcd4"],
+	labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
+	datasets: [
+		{
+			data: [334, 278, 190, 235, 260, 200, 141]
+		}
+	]
+};
+const options4 = {
+	type: 'ring',
+	title: {
+		text: '环形三等分'
+	},
+	showValue: false,
+	legend: {
+		position: 'bottom',
+		bottom: 40
+	},
+	colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
+	labels: ['vue', 'react', 'angular'],
+	datasets: [
+		{
+			data: [500, 500, 500]
+		}
+	]
+};
+</script>
+
+<style scoped>
+.schart {
+	width: 100%;
+	height: 400px;
+}
+
+.content-title {
+	font-weight: 400;
+	font-size: 22px;
+	color: #1f2f3d;
+}
+</style>
diff --git a/src/views/dashboard.vue b/src/views/dashboard.vue
index 5e6d0391..5f27a4bc 100644
--- a/src/views/dashboard.vue
+++ b/src/views/dashboard.vue
@@ -1,301 +1,357 @@
-<template>
-	<div>
-		<el-row :gutter="20">
-			<el-col :span="8">
-				<el-card shadow="hover" class="mgb20" style="height: 252px">
-					<div class="user-info">
-						<el-avatar :size="120" :src="imgurl" />
-						<div class="user-info-cont">
-							<div class="user-info-name">{{ name }}</div>
-							<div>{{ role }}</div>
-						</div>
-					</div>
-					<div class="user-info-list">
-						上次登录时间:
-						<span>2022-10-01</span>
-					</div>
-					<div class="user-info-list">
-						上次登录地点:
-						<span>东莞</span>
-					</div>
-				</el-card>
-				<el-card shadow="hover" style="height: 252px">
-					<template #header>
-						<div class="clearfix">
-							<span>语言详情</span>
-						</div>
-					</template>
-					Vue
-					<el-progress :percentage="79.4" color="#42b983"></el-progress>
-					TypeScript
-					<el-progress :percentage="14" color="#f1e05a"></el-progress>
-					CSS
-					<el-progress :percentage="5.6"></el-progress>
-					HTML
-					<el-progress :percentage="1" color="#f56c6c"></el-progress>
-				</el-card>
-			</el-col>
-			<el-col :span="16">
-				<el-row :gutter="20" class="mgb20">
-					<el-col :span="8">
-						<el-card shadow="hover" :body-style="{ padding: '0px' }">
-							<div class="grid-content grid-con-1">
-								<el-icon class="grid-con-icon"><User /></el-icon>
-								<div class="grid-cont-right">
-									<div class="grid-num">1234</div>
-									<div>用户访问量</div>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-					<el-col :span="8">
-						<el-card shadow="hover" :body-style="{ padding: '0px' }">
-							<div class="grid-content grid-con-2">
-								<el-icon class="grid-con-icon"><ChatDotRound /></el-icon>
-								<div class="grid-cont-right">
-									<div class="grid-num">321</div>
-									<div>系统消息</div>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-					<el-col :span="8">
-						<el-card shadow="hover" :body-style="{ padding: '0px' }">
-							<div class="grid-content grid-con-3">
-								<el-icon class="grid-con-icon"><Goods /></el-icon>
-								<div class="grid-cont-right">
-									<div class="grid-num">5000</div>
-									<div>商品数量</div>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-				</el-row>
-				<el-card shadow="hover" style="height: 403px">
-					<template #header>
-						<div class="clearfix">
-							<span>待办事项</span>
-							<el-button style="float: right; padding: 3px 0" text>添加</el-button>
-						</div>
-					</template>
-
-					<el-table :show-header="false" :data="todoList" style="width: 100%">
-						<el-table-column width="40">
-							<template #default="scope">
-								<el-checkbox v-model="scope.row.status"></el-checkbox>
-							</template>
-						</el-table-column>
-						<el-table-column>
-							<template #default="scope">
-								<div
-									class="todo-item"
-									:class="{
-										'todo-item-del': scope.row.status
-									}"
-								>
-									{{ scope.row.title }}
-								</div>
-							</template>
-						</el-table-column>
-					</el-table>
-				</el-card>
-			</el-col>
-		</el-row>
-		<el-row :gutter="20">
-			<el-col :span="12">
-				<el-card shadow="hover">
-					<schart ref="bar" class="schart" canvasId="bar" :options="options"></schart>
-				</el-card>
-			</el-col>
-			<el-col :span="12">
-				<el-card shadow="hover">
-					<schart ref="line" class="schart" canvasId="line" :options="options2"></schart>
-				</el-card>
-			</el-col>
-		</el-row>
-	</div>
-</template>
-
-<script setup lang="ts" name="dashboard">
-import Schart from 'vue-schart';
-import { reactive } from 'vue';
-import imgurl from '../assets/img/img.jpg';
-
-const name = localStorage.getItem('ms_username');
-const role: string = name === 'admin' ? '超级管理员' : '普通用户';
-
-const options = {
-	type: 'bar',
-	title: {
-		text: '最近一周各品类销售图'
-	},
-	xRorate: 25,
-	labels: ['周一', '周二', '周三', '周四', '周五'],
-	datasets: [
-		{
-			label: '家电',
-			data: [234, 278, 270, 190, 230]
-		},
-		{
-			label: '百货',
-			data: [164, 178, 190, 135, 160]
-		},
-		{
-			label: '食品',
-			data: [144, 198, 150, 235, 120]
-		}
-	]
-};
-const options2 = {
-	type: 'line',
-	title: {
-		text: '最近几个月各品类销售趋势图'
-	},
-	labels: ['6月', '7月', '8月', '9月', '10月'],
-	datasets: [
-		{
-			label: '家电',
-			data: [234, 278, 270, 190, 230]
-		},
-		{
-			label: '百货',
-			data: [164, 178, 150, 135, 160]
-		},
-		{
-			label: '食品',
-			data: [74, 118, 200, 235, 90]
-		}
-	]
-};
-const todoList = reactive([
-	{
-		title: '今天要修复100个bug',
-		status: false
-	},
-	{
-		title: '今天要修复100个bug',
-		status: false
-	},
-	{
-		title: '今天要写100行代码加几个bug吧',
-		status: false
-	},
-	{
-		title: '今天要修复100个bug',
-		status: false
-	},
-	{
-		title: '今天要修复100个bug',
-		status: true
-	},
-	{
-		title: '今天要写100行代码加几个bug吧',
-		status: true
-	}
-]);
-</script>
-
-<style scoped>
-.el-row {
-	margin-bottom: 20px;
-}
-
-.grid-content {
-	display: flex;
-	align-items: center;
-	height: 100px;
-}
-
-.grid-cont-right {
-	flex: 1;
-	text-align: center;
-	font-size: 14px;
-	color: #999;
-}
-
-.grid-num {
-	font-size: 30px;
-	font-weight: bold;
-}
-
-.grid-con-icon {
-	font-size: 50px;
-	width: 100px;
-	height: 100px;
-	text-align: center;
-	line-height: 100px;
-	color: #fff;
-}
-
-.grid-con-1 .grid-con-icon {
-	background: rgb(45, 140, 240);
-}
-
-.grid-con-1 .grid-num {
-	color: rgb(45, 140, 240);
-}
-
-.grid-con-2 .grid-con-icon {
-	background: rgb(100, 213, 114);
-}
-
-.grid-con-2 .grid-num {
-	color: rgb(100, 213, 114);
-}
-
-.grid-con-3 .grid-con-icon {
-	background: rgb(242, 94, 67);
-}
-
-.grid-con-3 .grid-num {
-	color: rgb(242, 94, 67);
-}
-
-.user-info {
-	display: flex;
-	align-items: center;
-	padding-bottom: 20px;
-	border-bottom: 2px solid #ccc;
-	margin-bottom: 20px;
-}
-
-.user-info-cont {
-	padding-left: 50px;
-	flex: 1;
-	font-size: 14px;
-	color: #999;
-}
-
-.user-info-cont div:first-child {
-	font-size: 30px;
-	color: #222;
-}
-
-.user-info-list {
-	font-size: 14px;
-	color: #999;
-	line-height: 25px;
-}
-
-.user-info-list span {
-	margin-left: 70px;
-}
-
-.mgb20 {
-	margin-bottom: 20px;
-}
-
-.todo-item {
-	font-size: 14px;
-}
-
-.todo-item-del {
-	text-decoration: line-through;
-	color: #999;
-}
-
-.schart {
-	width: 100%;
-	height: 300px;
-}
-</style>
+<template>
+    <div>
+        <el-row :gutter="20" class="mgb20">
+            <el-col :span="6">
+                <el-card shadow="hover" body-class="card-body">
+                    <el-icon class="card-icon bg1">
+                        <User />
+                    </el-icon>
+                    <div class="card-content">
+                        <countup class="card-num color1" :end="6666" />
+                        <div>用户访问量</div>
+                    </div>
+                </el-card>
+            </el-col>
+            <el-col :span="6">
+                <el-card shadow="hover" body-class="card-body">
+                    <el-icon class="card-icon bg2">
+                        <ChatDotRound />
+                    </el-icon>
+                    <div class="card-content">
+                        <countup class="card-num color2" :end="168" />
+                        <div>系统消息</div>
+                    </div>
+                </el-card>
+            </el-col>
+            <el-col :span="6">
+                <el-card shadow="hover" body-class="card-body">
+                    <el-icon class="card-icon bg3">
+                        <Goods />
+                    </el-icon>
+                    <div class="card-content">
+                        <countup class="card-num color3" :end="8888" />
+                        <div>商品数量</div>
+                    </div>
+                </el-card>
+            </el-col>
+            <el-col :span="6">
+                <el-card shadow="hover" body-class="card-body">
+                    <el-icon class="card-icon bg4">
+                        <ShoppingCartFull />
+                    </el-icon>
+                    <div class="card-content">
+                        <countup class="card-num color4" :end="568" />
+                        <div>今日订单量</div>
+                    </div>
+                </el-card>
+            </el-col>
+        </el-row>
+
+        <el-row :gutter="20" class="mgb20">
+            <el-col :span="18">
+                <el-card shadow="hover">
+                    <div class="card-header">
+                        <p class="card-header-title">订单动态</p>
+                        <p class="card-header-desc">最近一周订单状态,包括订单成交量和订单退货量</p>
+                    </div>
+                    <v-chart class="chart" :option="dashOpt1" />
+                </el-card>
+            </el-col>
+            <el-col :span="6">
+                <el-card shadow="hover">
+                    <div class="card-header">
+                        <p class="card-header-title">品类分布</p>
+                        <p class="card-header-desc">最近一个月销售商品的品类情况</p>
+                    </div>
+                    <v-chart class="chart" :option="dashOpt2" />
+                </el-card>
+            </el-col>
+        </el-row>
+        <el-row :gutter="20">
+            <el-col :span="7">
+                <el-card shadow="hover" :body-style="{ height: '400px' }">
+                    <div class="card-header">
+                        <p class="card-header-title">时间线</p>
+                        <p class="card-header-desc">最新的销售动态和活动信息</p>
+                    </div>
+                    <el-timeline>
+                        <el-timeline-item v-for="(activity, index) in activities" :key="index" :color="activity.color">
+                            <div class="timeline-item">
+                                <div>
+                                    <p>{{ activity.content }}</p>
+                                    <p class="timeline-desc">{{ activity.description }}</p>
+                                </div>
+                                <div class="timeline-time">{{ activity.timestamp }}</div>
+                            </div>
+                        </el-timeline-item>
+                    </el-timeline>
+                </el-card>
+            </el-col>
+            <el-col :span="10">
+                <el-card shadow="hover" :body-style="{ height: '400px' }">
+                    <div class="card-header">
+                        <p class="card-header-title">渠道统计</p>
+                        <p class="card-header-desc">最近一个月的订单来源统计</p>
+                    </div>
+                    <v-chart class="map-chart" :option="mapOptions" />
+                </el-card>
+            </el-col>
+            <el-col :span="7">
+                <el-card shadow="hover" :body-style="{ height: '400px' }">
+                    <div class="card-header">
+                        <p class="card-header-title">排行榜</p>
+                        <p class="card-header-desc">销售商品的热门榜单Top5</p>
+                    </div>
+                    <div>
+                        <div class="rank-item" v-for="(rank, index) in ranks">
+                            <div class="rank-item-avatar">{{ index + 1 }}</div>
+                            <div class="rank-item-content">
+                                <div class="rank-item-top">
+                                    <div class="rank-item-title">{{ rank.title }}</div>
+                                    <div class="rank-item-desc">销量:{{ rank.value }}</div>
+                                </div>
+                                <el-progress
+                                    :show-text="false"
+                                    striped
+                                    :stroke-width="10"
+                                    :percentage="rank.percent"
+                                    :color="rank.color"
+                                />
+                            </div>
+                        </div>
+                    </div>
+                </el-card>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script setup lang="ts" name="dashboard">
+import countup from '@/components/countup.vue';
+import { use, registerMap } from 'echarts/core';
+import { BarChart, LineChart, PieChart, MapChart } from 'echarts/charts';
+import {
+    GridComponent,
+    TooltipComponent,
+    LegendComponent,
+    TitleComponent,
+    VisualMapComponent,
+} from 'echarts/components';
+import { CanvasRenderer } from 'echarts/renderers';
+import VChart from 'vue-echarts';
+import { dashOpt1, dashOpt2, mapOptions } from './chart/options';
+import chinaMap from '@/utils/china';
+use([
+    CanvasRenderer,
+    BarChart,
+    GridComponent,
+    LineChart,
+    PieChart,
+    TooltipComponent,
+    LegendComponent,
+    TitleComponent,
+    VisualMapComponent,
+    MapChart,
+]);
+registerMap('china', chinaMap);
+const activities = [
+    {
+        content: '收藏商品',
+        description: 'xxx收藏了你的商品,就是不买',
+        timestamp: '30分钟前',
+        color: '#00bcd4',
+    },
+    {
+        content: '用户评价',
+        description: 'xxx给了某某商品一个差评,吐血啊',
+        timestamp: '55分钟前',
+        color: '#1ABC9C',
+    },
+    {
+        content: '订单提交',
+        description: 'xxx提交了订单,快去收钱吧',
+        timestamp: '1小时前',
+        color: '#3f51b5',
+    },
+    {
+        content: '退款申请',
+        description: 'xxx申请了仅退款,又要亏钱了',
+        timestamp: '15小时前',
+        color: '#f44336',
+    },
+    {
+        content: '商品上架',
+        description: '运营专员瞒着你上架了一辆飞机',
+        timestamp: '1天前',
+        color: '#009688',
+    },
+];
+
+const ranks = [
+    {
+        title: '手机',
+        value: 10000,
+        percent: 80,
+        color: '#f25e43',
+    },
+    {
+        title: '电脑',
+        value: 8000,
+        percent: 70,
+        color: '#00bcd4',
+    },
+    {
+        title: '相机',
+        value: 6000,
+        percent: 60,
+        color: '#64d572',
+    },
+    {
+        title: '衣服',
+        value: 5000,
+        percent: 55,
+        color: '#e9a745',
+    },
+    {
+        title: '书籍',
+        value: 4000,
+        percent: 50,
+        color: '#009688',
+    },
+];
+</script>
+
+<style>
+.card-body {
+    display: flex;
+    align-items: center;
+    height: 100px;
+    padding: 0;
+}
+</style>
+<style scoped>
+.card-content {
+    flex: 1;
+    text-align: center;
+    font-size: 14px;
+    color: #999;
+    padding: 0 20px;
+}
+
+.card-num {
+    font-size: 30px;
+}
+
+.card-icon {
+    font-size: 50px;
+    width: 100px;
+    height: 100px;
+    text-align: center;
+    line-height: 100px;
+    color: #fff;
+}
+
+.bg1 {
+    background: #2d8cf0;
+}
+
+.bg2 {
+    background: #64d572;
+}
+
+.bg3 {
+    background: #f25e43;
+}
+
+.bg4 {
+    background: #e9a745;
+}
+
+.color1 {
+    color: #2d8cf0;
+}
+
+.color2 {
+    color: #64d572;
+}
+
+.color3 {
+    color: #f25e43;
+}
+
+.color4 {
+    color: #e9a745;
+}
+
+.chart {
+    width: 100%;
+    height: 400px;
+}
+
+.card-header {
+    padding-left: 10px;
+    margin-bottom: 20px;
+}
+
+.card-header-title {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 5px;
+}
+
+.card-header-desc {
+    font-size: 14px;
+    color: #999;
+}
+
+.timeline-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    font-size: 16px;
+    color: #000;
+}
+
+.timeline-time,
+.timeline-desc {
+    font-size: 12px;
+    color: #787878;
+}
+
+.rank-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+}
+
+.rank-item-avatar {
+    width: 40px;
+    height: 40px;
+    border-radius: 50%;
+    background: #f2f2f2;
+    text-align: center;
+    line-height: 40px;
+    margin-right: 10px;
+}
+
+.rank-item-content {
+    flex: 1;
+}
+
+.rank-item-top {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    color: #343434;
+    margin-bottom: 10px;
+}
+
+.rank-item-desc {
+    font-size: 14px;
+    color: #999;
+}
+.map-chart {
+    width: 100%;
+    height: 350px;
+}
+</style>
diff --git a/src/views/donate.vue b/src/views/donate.vue
deleted file mode 100644
index c127e30d..00000000
--- a/src/views/donate.vue
+++ /dev/null
@@ -1,14 +0,0 @@
-<template>
-	<div class="container">
-		<div class="plugins-tips">
-			如果该框架对你有帮助,那就请作者喝杯饮料吧!<el-icon><ColdDrink /></el-icon> 加微信号linxin_20探讨问题。
-		</div>
-		<div>
-			<img src="https://lin-xin.gitee.io/images/weixin.jpg" />
-		</div>
-	</div>
-</template>
-
-<script setup lang="ts" name="donate"></script>
-
-<style></style>
diff --git a/src/views/element/calendar.vue b/src/views/element/calendar.vue
new file mode 100644
index 00000000..1b914747
--- /dev/null
+++ b/src/views/element/calendar.vue
@@ -0,0 +1,82 @@
+<template>
+    <div class="container">
+        <el-calendar v-model="value">
+            <template #date-cell="{ data }">
+                <div>{{ data.date.getDate() }}</div>
+                <div class="notes-container" v-if="notes[data.day.toString()]">
+                    <div class="notes" v-for="note in notes[data.day.toString()]">
+                        <span :class="note.status === 1 ? 'text-success' : 'text-danger'"></span>
+                        <div class="note-title">{{ note.title }}</div>
+                    </div>
+                </div>
+            </template>
+        </el-calendar>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+const today = new Date();
+const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
+const value = ref(today);
+
+const todayDate = today.toISOString().slice(0, 10);
+const yesterdayDate = yesterday.toISOString().slice(0, 10);
+
+const notes: any = {
+    [todayDate]: [
+        { title: '吃饭', status: 1 },
+        { title: '睡觉', status: 0 },
+        { title: '吃饭', status: 1 },
+        { title: '睡觉', status: 0 },
+        { title: '吃饭', status: 1 },
+        { title: '睡觉', status: 0 },
+    ],
+    [yesterdayDate]: [{ title: '参加会议', status: 0 }],
+};
+</script>
+
+<style scoped>
+.notes-container {
+    height: 60px;
+    overflow-y: auto;
+}
+
+.notes-container::-webkit-scrollbar {
+    width: 0;
+}
+
+.notes {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    font-size: 12px;
+}
+
+.notes:hover {
+    background-color: #eee;
+}
+
+.note-title {
+    flex: 1;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    overflow: hidden;
+}
+
+.notes span {
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    margin-right: 5px;
+}
+
+.text-success {
+    background-color: #5cb85c;
+}
+
+.text-danger {
+    background-color: #d9534f;
+}
+</style>
diff --git a/src/views/element/carousel.vue b/src/views/element/carousel.vue
new file mode 100644
index 00000000..dacbf4d4
--- /dev/null
+++ b/src/views/element/carousel.vue
@@ -0,0 +1,66 @@
+<template>
+    <div>
+        <el-card class="mgb20">
+            <template #header>基础用法</template>
+            <el-carousel height="400px">
+                <el-carousel-item v-for="item in 4" :key="item">
+                    <h3>{{ item }}</h3>
+                </el-carousel-item>
+            </el-carousel>
+        </el-card>
+
+        <el-row :gutter="20">
+            <el-col :span="12">
+                <el-card class="mgb20">
+                    <template #header>轮播图</template>
+                    <el-carousel height="300px">
+                        <el-carousel-item v-for="item in imgs" :key="item">
+                            <el-image class="carousel-img" :src="item" fit="cover" />
+                        </el-carousel-item>
+                    </el-carousel>
+                </el-card>
+            </el-col>
+            <el-col :span="12">
+                <el-card class="mgb20">
+                    <template #header>卡片模式</template>
+                    <el-carousel height="300px" type="card">
+                        <el-carousel-item v-for="item in imgs" :key="item">
+                            <el-image class="carousel-img" :src="item" fit="cover" />
+                        </el-carousel-item>
+                    </el-carousel>
+                </el-card>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script lang="ts" setup>
+const imgs = [
+    'https://cdn.pixabay.com/photo/2017/08/07/08/23/sea-2601374_640.jpg',
+    'https://cdn.pixabay.com/photo/2020/02/11/10/24/lake-4839058_640.jpg',
+    'https://cdn.pixabay.com/photo/2024/02/21/08/06/coast-8587004_640.jpg',
+    'https://cdn.pixabay.com/photo/2023/07/29/10/21/grasshopper-8156626_640.jpg',
+];
+</script>
+
+<style scoped>
+.el-carousel__item h3 {
+    color: #475669;
+    line-height: 400px;
+    margin: 0;
+    text-align: center;
+}
+
+.el-carousel__item:nth-child(2n) {
+    background-color: #99a9bf;
+}
+
+.el-carousel__item:nth-child(2n + 1) {
+    background-color: #d3dce6;
+}
+
+.carousel-img {
+    width: 100%;
+    height: 100%;
+}
+</style>
diff --git a/src/views/element/form.vue b/src/views/element/form.vue
new file mode 100644
index 00000000..2c9a78b8
--- /dev/null
+++ b/src/views/element/form.vue
@@ -0,0 +1,189 @@
+<template>
+    <div class="container">
+        <el-radio-group class="mgb20" v-model="labelPosition">
+            <el-radio-button value="left">Left</el-radio-button>
+            <el-radio-button value="right">Right</el-radio-button>
+            <el-radio-button value="top">Top</el-radio-button>
+        </el-radio-group>
+        <el-form ref="formRef" :rules="rules" :model="form" label-width="120px" :label-position="labelPosition">
+            <el-row :gutter="50">
+                <el-col :span="10">
+                    <el-form-item label="文本框" prop="name">
+                        <el-input v-model="form.name"></el-input>
+                    </el-form-item>
+                    <el-form-item label="数字框" prop="num">
+                        <el-input-number v-model="form.num" :min="1" :max="10" />
+                    </el-form-item>
+                    <el-form-item label="日期选择" prop="date">
+                        <el-date-picker type="date" placeholder="选择日期" v-model="form.date"></el-date-picker>
+                    </el-form-item>
+                    <el-form-item label="时间选择" prop="time">
+                        <el-time-picker placeholder="选择时间" v-model="form.time">
+                        </el-time-picker>
+                    </el-form-item>
+                    <el-form-item label="选择器" prop="region">
+                        <el-select v-model="form.region" placeholder="请选择">
+                            <el-option key="小明" label="小明" value="小明"></el-option>
+                            <el-option key="小红" label="小红" value="小红"></el-option>
+                            <el-option key="小白" label="小白" value="小白"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item label="城市级联" prop="options">
+                        <el-cascader :options="options" v-model="form.options"></el-cascader>
+                    </el-form-item>
+                    <el-form-item label="文本框" prop="desc">
+                        <el-input type="textarea" rows="5" v-model="form.desc"></el-input>
+                    </el-form-item>
+                </el-col>
+                <el-col :span="12">
+                    <el-form-item label="评分" prop="rate">
+                        <el-rate v-model="form.rate" allow-half />
+                    </el-form-item>
+                    <el-form-item label="滑块" prop="num">
+                        <el-slider v-model="form.num" :step="1" show-stops :max="10" />
+                    </el-form-item>
+                    <el-form-item label="开关" prop="delivery">
+                        <el-switch v-model="form.delivery"></el-switch>
+                    </el-form-item>
+                    <el-form-item label="颜色选择" prop="color">
+                        <el-color-picker v-model="form.color" />
+                    </el-form-item>
+                    <el-form-item label="多选框" prop="type">
+                        <el-checkbox-group v-model="form.type">
+                            <el-checkbox label="小明" value="小明" name="type"></el-checkbox>
+                            <el-checkbox label="小红" value="小红" name="type"></el-checkbox>
+                            <el-checkbox label="小白" value="小白" name="type"></el-checkbox>
+                        </el-checkbox-group>
+                    </el-form-item>
+                    <el-form-item label="单选框" prop="resource">
+                        <el-radio-group v-model="form.resource">
+                            <el-radio label="小明" value="小明"></el-radio>
+                            <el-radio label="小红" value="小红"></el-radio>
+                            <el-radio label="小白" value="小白"></el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+                    <el-form-item label="穿梭框" prop="transfer">
+                        <el-transfer v-model="form.transfer" :data="transferData" />
+                    </el-form-item>
+                </el-col>
+
+                <el-col :span="24">
+                    <el-form-item>
+                        <el-button type="primary" @click="onSubmit(formRef)">表单提交</el-button>
+                        <el-button @click="onReset(formRef)">重置表单</el-button>
+                    </el-form-item>
+                </el-col>
+            </el-row>
+        </el-form>
+    </div>
+</template>
+
+<script setup lang="ts" name="forms">
+import { reactive, ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import type { FormInstance, FormProps, FormRules } from 'element-plus';
+const labelPosition = ref<FormProps['labelPosition']>('right')
+const options = [
+    {
+        value: 'guangdong',
+        label: '广东省',
+        children: [
+            {
+                value: 'guangzhou',
+                label: '广州市',
+                children: [
+                    {
+                        value: 'tianhe',
+                        label: '天河区',
+                    },
+                    {
+                        value: 'haizhu',
+                        label: '海珠区',
+                    },
+                ],
+            },
+            {
+                value: 'dongguan',
+                label: '东莞市',
+                children: [
+                    {
+                        value: 'changan',
+                        label: '长安镇',
+                    },
+                    {
+                        value: 'humen',
+                        label: '虎门镇',
+                    },
+                ],
+            },
+        ],
+    },
+    {
+        value: 'hunan',
+        label: '湖南省',
+        children: [
+            {
+                value: 'changsha',
+                label: '长沙市',
+                children: [
+                    {
+                        value: 'yuelu',
+                        label: '岳麓区',
+                    },
+                ],
+            },
+        ],
+    },
+];
+const rules: FormRules = {
+    name: [{ required: true, message: '请输入表单名称', trigger: 'blur' }],
+};
+const formRef = ref<FormInstance>();
+const form = reactive({
+    name: '',
+    region: '',
+    date: '',
+    time: '',
+    delivery: true,
+    type: ['小明'],
+    resource: '小红',
+    desc: '',
+    options: [],
+    color: '',
+    num: 1,
+    rate: 0,
+    transfer: [],
+
+});
+const generateData = () => {
+    const data = []
+    for (let i = 1; i <= 15; i++) {
+        data.push({
+            key: i,
+            label: `Option ${i}`,
+            disabled: i % 4 === 0,
+        })
+    }
+    return data
+}
+
+const transferData = ref(generateData())
+// 提交
+const onSubmit = (formEl: FormInstance | undefined) => {
+    // 表单校验
+    if (!formEl) return;
+    formEl.validate((valid) => {
+        if (valid) {
+            console.log(form);
+            ElMessage.success('提交成功!');
+        } else {
+            return false;
+        }
+    });
+};
+// 重置
+const onReset = (formEl: FormInstance | undefined) => {
+    if (!formEl) return;
+    formEl.resetFields();
+};
+</script>
\ No newline at end of file
diff --git a/src/views/element/statistic.vue b/src/views/element/statistic.vue
new file mode 100644
index 00000000..2284a4aa
--- /dev/null
+++ b/src/views/element/statistic.vue
@@ -0,0 +1,340 @@
+<template>
+    <div>
+
+
+        <el-card class="mgb20" shadow="hover">
+            <template #header>基础用法</template>
+            <el-row>
+                <el-col :span="6" style="text-align: center">
+                    <el-statistic title="Daily active users" :value="268500" />
+                </el-col>
+                <el-col :span="6" style="text-align: center">
+                    <el-statistic :value="138">
+                        <template #title>
+                            <div style="display: inline-flex; align-items: center">
+                                Ratio of men to women
+                            </div>
+                        </template>
+                        <template #suffix>/100</template>
+                    </el-statistic>
+                </el-col>
+                <el-col :span="6" style="text-align: center">
+                    <el-statistic title="数字滚动" :value="outputValue" />
+                </el-col>
+                <el-col :span="6" style="text-align: center">
+                    <el-countdown title="倒计时" :value="value" />
+                </el-col>
+            </el-row>
+        </el-card>
+
+        <el-card class="mgb20" shadow="hover">
+            <template #header>CountUp.js</template>
+            <div class="plugins-tips">
+                countup.js:用于快速创建以更有趣的方式显示数字数据的动画。 访问地址:
+                <a href="https://github.com/inorganik/countUp.js" target="_blank">countUp.js</a>
+            </div>
+            <el-row>
+                <el-col :span="8" style="text-align: center">
+                    <p>基础用法</p>
+                    <countup class="countup" :end="6666" />
+                </el-col>
+                <el-col :span="8" style="text-align: center">
+                    <p>具体配置</p>
+                    <countup class="countup" :end="8888.5" :options="options" />
+                </el-col>
+                <el-col :span="8" style="text-align: center">
+                    <p>更新数值</p>
+                    <countup class="countup" :end="value1" />
+                </el-col>
+            </el-row>
+        </el-card>
+        <el-card class="mgb20" shadow="never">
+            <template #header>统计卡片</template>
+
+            <el-row :gutter="20" class="mgb20">
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon color1">
+                            <User />
+                        </el-icon>
+                        <div class="card-content text-right">
+                            <el-statistic title="日活跃用户量" :value="268500" />
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon color2">
+                            <ChatDotRound />
+                        </el-icon>
+                        <div class="card-content text-right">
+                            <el-statistic title="系统消息" :value="16800" />
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon color3">
+                            <Goods />
+                        </el-icon>
+                        <div class="card-content text-right">
+                            <el-statistic title="商品数量" :value="8888" />
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon color4">
+                            <ShoppingCartFull />
+                        </el-icon>
+                        <div class="card-content text-right">
+                            <el-statistic title="今日订单量" :value="56888" />
+                        </div>
+                    </el-card>
+                </el-col>
+            </el-row>
+            <el-row :gutter="20" class="mgb20">
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <div class="card-content text-left">
+                            <el-statistic :value-style="{ color: '#2d8cf0' }" title="日活跃用户量" :value="268500" />
+                        </div>
+                        <el-icon class="card-icon color1">
+                            <User />
+                        </el-icon>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <div class="card-content text-left">
+                            <el-statistic :value-style="{ color: '#64d572' }" title="系统消息" :value="16800" />
+                        </div>
+                        <el-icon class="card-icon color2">
+                            <ChatDotRound />
+                        </el-icon>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <div class="card-content text-left">
+                            <el-statistic :value-style="{ color: '#f25e43' }" title="商品数量" :value="8888" />
+                        </div>
+                        <el-icon class="card-icon color3">
+                            <Goods />
+                        </el-icon>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <div class="card-content text-left">
+                            <el-statistic :value-style="{ color: '#e9a745' }" title="今日订单量" :value="56888" />
+                        </div>
+                        <el-icon class="card-icon color4">
+                            <ShoppingCartFull />
+                        </el-icon>
+                    </el-card>
+                </el-col>
+            </el-row>
+            <el-row :gutter="20" class="mgb20">
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon bg1">
+                            <User />
+                        </el-icon>
+                        <div class="card-content">
+                            <countup class="card-num color1" :end="6666" />
+                            <div>用户访问量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon bg2">
+                            <ChatDotRound />
+                        </el-icon>
+                        <div class="card-content">
+                            <countup class="card-num color2" :end="168" />
+                            <div>系统消息</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon bg3">
+                            <Goods />
+                        </el-icon>
+                        <div class="card-content">
+                            <countup class="card-num color3" :end="8888" />
+                            <div>商品数量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body">
+                        <el-icon class="card-icon bg4">
+                            <ShoppingCartFull />
+                        </el-icon>
+                        <div class="card-content">
+                            <countup class="card-num color4" :end="568" />
+                            <div>今日订单量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+            </el-row>
+            <el-row :gutter="20" class="mgb20">
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body bg1">
+                        <el-icon class="card-icon ">
+                            <User />
+                        </el-icon>
+                        <div class="card-content color0">
+                            <countup class="card-num" :end="6666" />
+                            <div>用户访问量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body bg2">
+                        <el-icon class="card-icon">
+                            <ChatDotRound />
+                        </el-icon>
+                        <div class="card-content color0">
+                            <countup class="card-num" :end="168" />
+                            <div>系统消息</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body bg3">
+                        <el-icon class="card-icon">
+                            <Goods />
+                        </el-icon>
+                        <div class="card-content color0">
+                            <countup class="card-num " :end="8888" />
+                            <div>商品数量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+                <el-col :span="6">
+                    <el-card shadow="hover" body-class="card-body bg4">
+                        <el-icon class="card-icon">
+                            <ShoppingCartFull />
+                        </el-icon>
+                        <div class="card-content color0">
+                            <countup class="card-num " :end="568" />
+                            <div>今日订单量</div>
+                        </div>
+                    </el-card>
+                </el-col>
+            </el-row>
+        </el-card>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue'
+import { useTransition } from '@vueuse/core'
+import countup from '@/components/countup.vue';
+
+const source = ref(0)
+const outputValue = useTransition(source, {
+    duration: 1500,
+})
+source.value = 172000
+
+const value = ref(Date.now() + 1000 * 60 * 60 * 7)
+const value1 = ref(1000);
+setTimeout(() => {
+    value1.value = 8000;
+}, 5000);
+const options = {
+    startVal: 1000,
+    decimalPlaces: 2,
+    duration: 5,
+    useGrouping: false,
+    prefix: '$',
+    separator: ',',
+    decimal: '.',
+    suffix: '',
+}
+</script>
+
+<style>
+.card-body {
+    display: flex;
+    align-items: center;
+    height: 100px;
+    padding: 0;
+}
+
+.bg1 {
+    background: #2d8cf0;
+}
+
+.bg2 {
+    background: #64d572;
+}
+
+.bg3 {
+    background: #f25e43;
+}
+
+.bg4 {
+    background: #e9a745;
+}
+</style>
+<style scoped>
+.countup {
+    font-size: 24px;
+}
+
+.card-content {
+    flex: 1;
+    text-align: center;
+    font-size: 14px;
+    color: #999;
+    padding: 0 20px;
+}
+
+.card-num {
+    font-size: 30px;
+}
+
+.card-icon {
+    font-size: 50px;
+    width: 100px;
+    height: 100px;
+    text-align: center;
+    line-height: 100px;
+    color: #fff;
+}
+
+
+.color0 {
+    color: #fff;
+}
+
+.color1 {
+    color: #2d8cf0;
+}
+
+.color2 {
+    color: #64d572;
+}
+
+.color3 {
+    color: #f25e43;
+}
+
+.color4 {
+    color: #e9a745;
+}
+
+.text-right {
+    text-align: right;
+}
+
+.text-left {
+    text-align: left;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/element/steps.vue b/src/views/element/steps.vue
new file mode 100644
index 00000000..dec0ce1f
--- /dev/null
+++ b/src/views/element/steps.vue
@@ -0,0 +1,61 @@
+<template>
+    <div class="container">
+        <div class="step-div" v-if="step === 0">
+            <p>输入注册时的邮箱,我们会发送验证码到您的邮箱</p>
+            <el-input placeholder="请输入邮箱"></el-input>
+            <el-button class="step-btn" type="primary" @click="step++">下一步</el-button>
+        </div>
+        <div class="step-div" v-else-if="step === 1">
+            <p>验证码已发送至您的邮箱,请输入验证码</p>
+            <el-input placeholder="请输入验证码"></el-input>
+            <el-button class="step-btn" type="primary" @click="step++">下一步</el-button>
+        </div>
+
+        <div class="step-div" v-else-if="step === 2">
+            <p>请输入6位以上密码</p>
+            <el-input placeholder="请输入新密码"></el-input>
+            <el-button class="step-btn" type="primary" @click="step++">保存</el-button>
+        </div>
+        <div v-else>
+            <el-result icon="success" title="保存成功" sub-title="请退出后重新登录"></el-result>
+        </div>
+        <el-steps class="step-style" :active="step" align-center finish-status="success">
+            <el-step title="Step 1" description="填写邮箱" />
+            <el-step title="Step 2" description="填写验证码" />
+            <el-step title="Step 3" description="修改密码" />
+        </el-steps>
+        <el-steps class="step-style" :active="step" finish-status="success" simple>
+            <el-step title="填写邮箱" />
+            <el-step title="填写验证码" />
+            <el-step title="修改密码" />
+        </el-steps>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+const step = ref(0)
+</script>
+
+<style scoped>
+.step-div {
+    max-width: 500px;
+    margin: 0 auto;
+}
+
+.step-div p {
+    margin-bottom: 20px;
+    color: #787878;
+}
+
+.step-btn {
+    display: block;
+    width: 100%;
+    margin: 20px 0;
+}
+
+.step-style {
+    max-width: 800px;
+    margin: 40px auto;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/element/tabs.vue b/src/views/element/tabs.vue
new file mode 100644
index 00000000..884ea0be
--- /dev/null
+++ b/src/views/element/tabs.vue
@@ -0,0 +1,116 @@
+<template>
+	<el-tabs v-model="message" type="card">
+		<el-tab-pane :label="`未读消息(${state.unread.length})`" name="first">
+			<el-table :data="state.unread" :show-header="false" style="width: 100%">
+				<el-table-column>
+					<template #default="scope">
+						<span class="message-title">{{ scope.row.title }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column prop="date" width="180"></el-table-column>
+				<el-table-column width="120">
+					<template #default="scope">
+						<el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<div class="handle-row">
+				<el-button type="primary">全部标为已读</el-button>
+			</div>
+		</el-tab-pane>
+		<el-tab-pane :label="`已读消息(${state.read.length})`" name="second">
+			<template v-if="message === 'second'">
+				<el-table :data="state.read" :show-header="false" style="width: 100%">
+					<el-table-column>
+						<template #default="scope">
+							<span class="message-title">{{ scope.row.title }}</span>
+						</template>
+					</el-table-column>
+					<el-table-column prop="date" width="180"></el-table-column>
+					<el-table-column width="120">
+						<template #default="scope">
+							<el-button type="danger" size="small" @click="handleDel(scope.$index)">删除</el-button>
+						</template>
+					</el-table-column>
+				</el-table>
+				<div class="handle-row">
+					<el-button type="danger">删除全部</el-button>
+				</div>
+			</template>
+		</el-tab-pane>
+		<el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
+			<template v-if="message === 'third'">
+				<el-table :data="state.recycle" :show-header="false" style="width: 100%">
+					<el-table-column>
+						<template #default="scope">
+							<span class="message-title">{{ scope.row.title }}</span>
+						</template>
+					</el-table-column>
+					<el-table-column prop="date" width="180"></el-table-column>
+					<el-table-column width="120">
+						<template #default="scope">
+							<el-button size="small" @click="handleRestore(scope.$index)">还原</el-button>
+						</template>
+					</el-table-column>
+				</el-table>
+				<div class="handle-row">
+					<el-button type="danger">清空回收站</el-button>
+				</div>
+			</template>
+		</el-tab-pane>
+	</el-tabs>
+</template>
+
+<script setup lang="ts" name="tabs">
+import { ref, reactive } from 'vue';
+
+const message = ref('first');
+const state = reactive({
+	unread: [
+		{
+			date: '2018-04-19 20:00:00',
+			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
+		},
+		{
+			date: '2018-04-19 21:00:00',
+			title: '今晚12点整发大红包,先到先得'
+		}
+	],
+	read: [
+		{
+			date: '2018-04-19 20:00:00',
+			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
+		}
+	],
+	recycle: [
+		{
+			date: '2018-04-19 20:00:00',
+			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
+		}
+	]
+});
+
+const handleRead = (index: number) => {
+	const item = state.unread.splice(index, 1);
+	state.read = item.concat(state.read);
+};
+const handleDel = (index: number) => {
+	const item = state.read.splice(index, 1);
+	state.recycle = item.concat(state.recycle);
+};
+const handleRestore = (index: number) => {
+	const item = state.recycle.splice(index, 1);
+	state.read = item.concat(state.read);
+};
+</script>
+
+<style>
+.message-title {
+	cursor: pointer;
+	color: var(--el-color-primary);
+}
+
+.handle-row {
+	margin-top: 30px;
+}
+</style>
diff --git a/src/views/element/tour.vue b/src/views/element/tour.vue
new file mode 100644
index 00000000..027f5079
--- /dev/null
+++ b/src/views/element/tour.vue
@@ -0,0 +1,33 @@
+<template>
+    <div class="container">
+        <el-button type="primary" @click="open = true">开始引导</el-button>
+
+        <el-divider />
+
+        <el-space>
+            <el-button ref="ref1">上传</el-button>
+            <el-button ref="ref2" type="primary">保存</el-button>
+            <el-button ref="ref3" :icon="MoreFilled" />
+        </el-space>
+
+        <el-tour v-model="open">
+            <el-tour-step :target="ref1?.$el" title="上传文件">
+                <img style="width: 120px" src="../../assets/img/img.jpg" alt="tour.png" />
+                <div>点击这里选择文件</div>
+            </el-tour-step>
+            <el-tour-step :target="ref2?.$el" title="保存" description="点击进行上传" />
+            <el-tour-step :target="ref3?.$el" title="更多操作" description="点击查看更多操作" />
+        </el-tour>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { MoreFilled } from '@element-plus/icons-vue'
+
+const ref1 = ref()
+const ref2 = ref()
+const ref3 = ref()
+
+const open = ref(false)
+</script>
\ No newline at end of file
diff --git a/src/views/upload.vue b/src/views/element/upload.vue
similarity index 67%
rename from src/views/upload.vue
rename to src/views/element/upload.vue
index 960edc3f..146b2414 100644
--- a/src/views/upload.vue
+++ b/src/views/element/upload.vue
@@ -1,48 +1,44 @@
-<template>
-    <div class="container">
-        <div class="content-title">支持拖拽</div>
-        <div class="plugins-tips">
-            Element Plus自带上传组件。 访问地址:
-            <a href="https://element-plus.org/zh-CN/component/upload.html" target="_blank">Element Plus Upload</a>
-        </div>
-        <el-upload
-            class="upload-demo"
-            drag
-            action="http://jsonplaceholder.typicode.com/api/posts/"
-            multiple
-            :on-change="handle"
-        >
-            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
-            <div class="el-upload__text">
-                将文件拖到此处,或
-                <em>点击上传</em>
-            </div>
-        </el-upload>
-
-        <div class="content-title">支持裁剪</div>
-        <div class="plugins-tips">
-            vue-cropperjs:一个封装了 cropperjs 的 Vue 组件。 访问地址:
-            <a href="https://github.com/Agontuk/vue-cropperjs" target="_blank">vue-cropperjs</a>。 示例请查看
-            <router-link to="/user">个人中心</router-link>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts">
-const handle = (rawFile: any) => {
-    console.log(rawFile);
-};
-</script>
-
-<style scoped>
-.content-title {
-    font-weight: 400;
-    line-height: 50px;
-    margin: 10px 0;
-    font-size: 22px;
-    color: #1f2f3d;
-}
-.upload-demo {
-    width: 360px;
-}
-</style>
+<template>
+    <div class="container">
+        <div class="content-title">支持拖拽</div>
+        <div class="plugins-tips">
+            Element Plus自带上传组件。 访问地址:
+            <a href="https://element-plus.org/zh-CN/component/upload.html" target="_blank">Element Plus Upload</a>
+        </div>
+        <el-upload class="upload-demo" drag action="http://jsonplaceholder.typicode.com/api/posts/" multiple
+            :on-change="handle">
+            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+            <div class="el-upload__text">
+                将文件拖到此处,或
+                <em>点击上传</em>
+            </div>
+        </el-upload>
+
+        <div class="content-title">支持裁剪</div>
+        <div class="plugins-tips">
+            vue-cropper:一个简单的vue图片裁剪插件。 访问地址:
+            <a href="https://github.com/xyxiao001/vue-cropper" target="_blank">vue-cropper</a>。 示例请查看
+            <router-link to="/ucenter">个人中心-我的头像</router-link>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+const handle = (rawFile: any) => {
+    console.log(rawFile);
+};
+</script>
+
+<style scoped>
+.content-title {
+    font-weight: 400;
+    line-height: 50px;
+    margin: 10px 0;
+    font-size: 22px;
+    color: #1f2f3d;
+}
+
+.upload-demo {
+    width: 360px;
+}
+</style>
diff --git a/src/views/element/watermark.vue b/src/views/element/watermark.vue
new file mode 100644
index 00000000..a381128e
--- /dev/null
+++ b/src/views/element/watermark.vue
@@ -0,0 +1,62 @@
+<template>
+    <div class="container">
+        <el-row :gutter="20">
+            <el-col :span="18">
+                <el-watermark :content="config.content" :font="config.font" :z-index="config.zIndex"
+                    :rotate="config.rotate" :gap="config.gap" :offset="config.offset">
+                    <div style="height: 600px" />
+                </el-watermark>
+            </el-col>
+            <el-col :span="6">
+                <el-form class="form" :model="config" label-position="top" label-width="50px">
+                    <el-form-item label="Content">
+                        <el-input v-model="config.content" />
+                    </el-form-item>
+                    <el-form-item label="Color">
+                        <el-color-picker v-model="config.font.color" show-alpha />
+                    </el-form-item>
+                    <el-form-item label="FontSize">
+                        <el-slider v-model="config.font.fontSize" />
+                    </el-form-item>
+                    <el-form-item label="zIndex">
+                        <el-slider v-model="config.zIndex" />
+                    </el-form-item>
+                    <el-form-item label="Rotate">
+                        <el-slider v-model="config.rotate" :min="-180" :max="180" />
+                    </el-form-item>
+                    <el-form-item label="Gap">
+                        <el-space>
+                            <el-input-number v-model="config.gap[0]" controls-position="right" />
+                            <el-input-number v-model="config.gap[1]" controls-position="right" />
+                        </el-space>
+                    </el-form-item>
+                    <el-form-item label="Offset">
+                        <el-space>
+                            <el-input-number v-model="config.offset[0]" placeholder="offsetLeft"
+                                controls-position="right" />
+                            <el-input-number v-model="config.offset[1]" placeholder="offsetTop"
+                                controls-position="right" />
+                        </el-space>
+                    </el-form-item>
+                </el-form>
+            </el-col>
+        </el-row>
+
+    </div>
+</template>
+
+<script setup lang="ts">
+import { reactive } from 'vue'
+
+const config = reactive({
+    content: 'vue-manage-system',
+    font: {
+        fontSize: 16,
+        color: 'rgba(0, 0, 0, 0.15)',
+    },
+    zIndex: -1,
+    rotate: -22,
+    gap: [100, 100] as [number, number],
+    offset: [] as unknown as [number, number],
+})
+</script>
\ No newline at end of file
diff --git a/src/views/form.vue b/src/views/form.vue
deleted file mode 100644
index 75609aeb..00000000
--- a/src/views/form.vue
+++ /dev/null
@@ -1,156 +0,0 @@
-<template>
-    <div class="container">
-        <div class="form-box">
-            <el-form ref="formRef" :rules="rules" :model="form" label-width="80px">
-                <el-form-item label="表单名称" prop="name">
-                    <el-input v-model="form.name"></el-input>
-                </el-form-item>
-                <el-form-item label="选择器" prop="region">
-                    <el-select v-model="form.region" placeholder="请选择">
-                        <el-option key="小明" label="小明" value="小明"></el-option>
-                        <el-option key="小红" label="小红" value="小红"></el-option>
-                        <el-option key="小白" label="小白" value="小白"></el-option>
-                    </el-select>
-                </el-form-item>
-                <el-form-item label="日期时间">
-                    <el-col :span="11">
-                        <el-form-item prop="date1">
-                            <el-date-picker
-                                type="date"
-                                placeholder="选择日期"
-                                v-model="form.date1"
-                                style="width: 100%"
-                            ></el-date-picker>
-                        </el-form-item>
-                    </el-col>
-                    <el-col class="line" :span="2">-</el-col>
-                    <el-col :span="11">
-                        <el-form-item prop="date2">
-                            <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%">
-                            </el-time-picker>
-                        </el-form-item>
-                    </el-col>
-                </el-form-item>
-                <el-form-item label="城市级联" prop="options">
-                    <el-cascader :options="options" v-model="form.options"></el-cascader>
-                </el-form-item>
-                <el-form-item label="选择开关" prop="delivery">
-                    <el-switch v-model="form.delivery"></el-switch>
-                </el-form-item>
-                <el-form-item label="多选框" prop="type">
-                    <el-checkbox-group v-model="form.type">
-                        <el-checkbox label="小明" name="type"></el-checkbox>
-                        <el-checkbox label="小红" name="type"></el-checkbox>
-                        <el-checkbox label="小白" name="type"></el-checkbox>
-                    </el-checkbox-group>
-                </el-form-item>
-                <el-form-item label="单选框" prop="resource">
-                    <el-radio-group v-model="form.resource">
-                        <el-radio label="小明"></el-radio>
-                        <el-radio label="小红"></el-radio>
-                        <el-radio label="小白"></el-radio>
-                    </el-radio-group>
-                </el-form-item>
-                <el-form-item label="文本框" prop="desc">
-                    <el-input type="textarea" rows="5" v-model="form.desc"></el-input>
-                </el-form-item>
-                <el-form-item>
-                    <el-button type="primary" @click="onSubmit(formRef)">表单提交</el-button>
-                    <el-button @click="onReset(formRef)">重置表单</el-button>
-                </el-form-item>
-            </el-form>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts" name="baseform">
-import { reactive, ref } from 'vue';
-import { ElMessage } from 'element-plus';
-import type { FormInstance, FormRules } from 'element-plus';
-
-const options = [
-    {
-        value: 'guangdong',
-        label: '广东省',
-        children: [
-            {
-                value: 'guangzhou',
-                label: '广州市',
-                children: [
-                    {
-                        value: 'tianhe',
-                        label: '天河区',
-                    },
-                    {
-                        value: 'haizhu',
-                        label: '海珠区',
-                    },
-                ],
-            },
-            {
-                value: 'dongguan',
-                label: '东莞市',
-                children: [
-                    {
-                        value: 'changan',
-                        label: '长安镇',
-                    },
-                    {
-                        value: 'humen',
-                        label: '虎门镇',
-                    },
-                ],
-            },
-        ],
-    },
-    {
-        value: 'hunan',
-        label: '湖南省',
-        children: [
-            {
-                value: 'changsha',
-                label: '长沙市',
-                children: [
-                    {
-                        value: 'yuelu',
-                        label: '岳麓区',
-                    },
-                ],
-            },
-        ],
-    },
-];
-const rules: FormRules = {
-    name: [{ required: true, message: '请输入表单名称', trigger: 'blur' }],
-};
-const formRef = ref<FormInstance>();
-const form = reactive({
-    name: '',
-    region: '',
-    date1: '',
-    date2: '',
-    delivery: true,
-    type: ['小明'],
-    resource: '小红',
-    desc: '',
-    options: [],
-});
-// 提交
-const onSubmit = (formEl: FormInstance | undefined) => {
-    // 表单校验
-    if (!formEl) return;
-    formEl.validate((valid) => {
-        if (valid) {
-            console.log(form);
-            ElMessage.success('提交成功!');
-        } else {
-            return false;
-        }
-    });
-};
-// 重置
-const onReset = (formEl: FormInstance | undefined) => {
-    if (!formEl) return;
-    formEl.resetFields();
-};
-</script>
diff --git a/src/views/home.vue b/src/views/home.vue
index e8ba189a..bb8e7e17 100644
--- a/src/views/home.vue
+++ b/src/views/home.vue
@@ -1,26 +1,56 @@
-<template>
-	<v-header />
-	<v-sidebar />
-	<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
-		<v-tags></v-tags>
-		<div class="content">
-			<router-view v-slot="{ Component }">
-				<transition name="move" mode="out-in">
-					<keep-alive :include="tags.nameList">
-						<component :is="Component"></component>
-					</keep-alive>
-				</transition>
-			</router-view>
-		</div>
-	</div>
-</template>
-<script setup lang="ts">
-import { useSidebarStore } from '../store/sidebar';
-import { useTagsStore } from '../store/tags';
-import vHeader from '../components/header.vue';
-import vSidebar from '../components/sidebar.vue';
-import vTags from '../components/tags.vue';
-
-const sidebar = useSidebarStore();
-const tags = useTagsStore();
-</script>
+<template>
+	<v-header />
+	<v-sidebar />
+	<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
+		<v-tabs></v-tabs>
+		<div class="content">
+			<router-view v-slot="{ Component }">
+				<transition name="move" mode="out-in">
+					<keep-alive :include="tabs.nameList">
+						<component :is="Component"></component>
+					</keep-alive>
+				</transition>
+			</router-view>
+		</div>
+	</div>
+</template>
+<script setup lang="ts">
+import { useSidebarStore } from '@/store/sidebar';
+import { useTabsStore } from '@/store/tabs';
+import vHeader from '@/components/header.vue';
+import vSidebar from '@/components/sidebar.vue';
+import vTabs from '@/components/tabs.vue';
+
+const sidebar = useSidebarStore();
+const tabs = useTabsStore();
+</script>
+
+<style>
+.content-box {
+	position: absolute;
+	left: 250px;
+	right: 0;
+	top: 70px;
+	bottom: 0;
+	padding-bottom: 30px;
+	-webkit-transition: left 0.3s ease-in-out;
+	transition: left 0.3s ease-in-out;
+	background: #eef0fc;
+}
+
+.content {
+	width: auto;
+	height: 100%;
+	padding: 20px;
+	overflow-y: scroll;
+	box-sizing: border-box;
+}
+
+.content::-webkit-scrollbar {
+	width: 0;
+}
+
+.content-collapse {
+	left: 65px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/pages/403.vue b/src/views/pages/403.vue
new file mode 100644
index 00000000..eacb8926
--- /dev/null
+++ b/src/views/pages/403.vue
@@ -0,0 +1,67 @@
+<template>
+	<div class="error-page">
+		<div class="error-box">
+			<div class="error-code">403</div>
+			<div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
+			<div class="error-handle">
+				<router-link to="/">
+					<el-button type="primary" size="large">返回首页</el-button>
+				</router-link>
+				<el-button class="error-btn" size="large" @click="goBack">返回上一页</el-button>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts" name="403">
+import { useRouter } from 'vue-router';
+
+const router = useRouter();
+const goBack = () => {
+	router.go(-2);
+};
+</script>
+
+<style scoped>
+.error-page {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+	width: 100%;
+	height: 100%;
+	background: #eef0fc;
+	box-sizing: border-box;
+}
+
+.error-box {
+	width: 400px;
+	background-color: #fff;
+	padding: 80px 50px;
+	border-radius: 5px;
+}
+
+.error-code {
+	line-height: 1;
+	font-size: 100px;
+	font-weight: bold;
+	color: var(--el-color-primary);
+	margin-bottom: 20px;
+	text-align: center
+}
+
+.error-desc {
+	font-size: 20px;
+	color: #777;
+	text-align: center
+}
+
+.error-handle {
+	margin-top: 50px;
+	text-align: center;
+}
+
+.error-btn {
+	margin-left: 100px;
+}
+</style>
diff --git a/src/views/pages/404.vue b/src/views/pages/404.vue
new file mode 100644
index 00000000..31bae0df
--- /dev/null
+++ b/src/views/pages/404.vue
@@ -0,0 +1,67 @@
+<template>
+	<div class="error-page">
+		<div class="error-box">
+			<div class="error-code">404</div>
+			<div class="error-desc">啊哦~ 你所访问的页面不存在</div>
+			<div class="error-handle">
+				<router-link to="/">
+					<el-button type="primary" size="large">返回首页</el-button>
+				</router-link>
+				<el-button class="error-btn" size="large" @click="goBack">返回上一页</el-button>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts" name="404">
+import { useRouter } from 'vue-router';
+
+const router = useRouter();
+const goBack = () => {
+	router.go(-1);
+};
+</script>
+
+<style scoped>
+.error-page {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+	width: 100%;
+	height: 100%;
+	background: #eef0fc;
+	box-sizing: border-box;
+}
+
+.error-box {
+	width: 400px;
+	background-color: #fff;
+	padding: 80px 50px;
+	border-radius: 5px;
+}
+
+.error-code {
+	line-height: 1;
+	font-size: 100px;
+	font-weight: bold;
+	color: var(--el-color-primary);
+	margin-bottom: 20px;
+	text-align: center
+}
+
+.error-desc {
+	font-size: 20px;
+	color: #777;
+	text-align: center
+}
+
+.error-handle {
+	margin-top: 50px;
+	text-align: center;
+}
+
+.error-btn {
+	margin-left: 100px;
+}
+</style>
diff --git a/src/views/editor.vue b/src/views/pages/editor.vue
similarity index 100%
rename from src/views/editor.vue
rename to src/views/pages/editor.vue
diff --git a/src/views/icon.vue b/src/views/pages/icon.vue
similarity index 51%
rename from src/views/icon.vue
rename to src/views/pages/icon.vue
index 0b01ff3d..c08d8c4b 100644
--- a/src/views/icon.vue
+++ b/src/views/pages/icon.vue
@@ -1,212 +1,257 @@
-<template>
-	<div class="container">
-		<h2>使用方法</h2>
-		<p style="line-height: 50px">
-			直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{ iconList.length }}个图标)
-		</p>
-		<p class="example-p">
-			<i class="el-icon-lx-redpacket_fill" style="font-size: 30px; color: #ff5900"></i>
-			<span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
-		</p>
-		<p class="example-p">
-			<i class="el-icon-lx-weibo" style="font-size: 30px; color: #fd5656"></i>
-			<span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
-		</p>
-		<p class="example-p">
-			<i class="el-icon-lx-emojifill" style="font-size: 30px; color: #ffc300"></i>
-			<span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
-		</p>
-		<br />
-		<h2>图标</h2>
-		<div class="search-box">
-			<el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
-		</div>
-		<ul>
-			<li class="icon-li" v-for="(item, index) in list" :key="index">
-				<div class="icon-li-content">
-					<i :class="`el-icon-lx-${item}`"></i>
-					<span>{{ item }}</span>
-				</div>
-			</li>
-		</ul>
-	</div>
-</template>
-
-<script setup lang="ts" name="icon">
-import { computed, ref } from 'vue';
-
-const iconList: Array<string> = [
-	'attentionforbid',
-	'attentionforbidfill',
-	'attention',
-	'attentionfill',
-	'tag',
-	'tagfill',
-	'people',
-	'peoplefill',
-	'notice',
-	'noticefill',
-	'mobile',
-	'mobilefill',
-	'voice',
-	'voicefill',
-	'unlock',
-	'lock',
-	'home',
-	'homefill',
-	'delete',
-	'deletefill',
-	'notification',
-	'notificationfill',
-	'notificationforbidfill',
-	'like',
-	'likefill',
-	'comment',
-	'commentfill',
-	'camera',
-	'camerafill',
-	'warn',
-	'warnfill',
-	'time',
-	'timefill',
-	'location',
-	'locationfill',
-	'favor',
-	'favorfill',
-	'skin',
-	'skinfill',
-	'news',
-	'newsfill',
-	'record',
-	'recordfill',
-	'emoji',
-	'emojifill',
-	'message',
-	'messagefill',
-	'goods',
-	'goodsfill',
-	'crown',
-	'crownfill',
-	'move',
-	'add',
-	'hot',
-	'hotfill',
-	'service',
-	'servicefill',
-	'present',
-	'presentfill',
-	'pic',
-	'picfill',
-	'rank',
-	'rankfill',
-	'male',
-	'female',
-	'down',
-	'top',
-	'recharge',
-	'rechargefill',
-	'forward',
-	'forwardfill',
-	'info',
-	'infofill',
-	'redpacket',
-	'redpacket_fill',
-	'roundadd',
-	'roundaddfill',
-	'friendadd',
-	'friendaddfill',
-	'cart',
-	'cartfill',
-	'more',
-	'moreandroid',
-	'back',
-	'right',
-	'shop',
-	'shopfill',
-	'question',
-	'questionfill',
-	'roundclose',
-	'roundclosefill',
-	'roundcheck',
-	'roundcheckfill',
-	'global',
-	'mail',
-	'punch',
-	'exit',
-	'upload',
-	'read',
-	'file',
-	'link',
-	'full',
-	'group',
-	'friend',
-	'profile',
-	'addressbook',
-	'calendar',
-	'text',
-	'copy',
-	'share',
-	'wifi',
-	'vipcard',
-	'weibo',
-	'remind',
-	'refresh',
-	'filter',
-	'settings',
-	'scan',
-	'qrcode',
-	'cascades',
-	'apps',
-	'sort',
-	'searchlist',
-	'search',
-	'edit'
-];
-const keyword = ref('');
-const list = computed(() => {
-	return iconList.filter(item => {
-		return item.indexOf(keyword.value) !== -1;
-	});
-});
-</script>
-
-<style scoped>
-.example-p {
-	height: 45px;
-	display: flex;
-	align-items: center;
-}
-.search-box {
-	text-align: center;
-	margin-top: 10px;
-}
-.search {
-	width: 300px;
-}
-ul,
-li {
-	list-style: none;
-}
-.icon-li {
-	display: inline-block;
-	padding: 10px;
-	width: 120px;
-	height: 120px;
-}
-.icon-li-content {
-	display: flex;
-	height: 100%;
-	flex-direction: column;
-	align-items: center;
-	justify-content: center;
-	cursor: pointer;
-}
-.icon-li-content i {
-	font-size: 36px;
-	color: #606266;
-}
-.icon-li-content span {
-	margin-top: 10px;
-	color: #787878;
-}
-</style>
+<template>
+
+	<el-tabs type="border-card">
+		<el-tab-pane label="自定义图标">
+			<h2>使用方法</h2>
+			<p style="line-height: 50px">
+				直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{ iconList.length }}个图标)
+			</p>
+			<p class="example-p">
+				<i class="el-icon-lx-redpacket_fill" style="font-size: 30px; color: #ff5900"></i>
+				<span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
+			</p>
+			<p class="example-p">
+				<i class="el-icon-lx-weibo" style="font-size: 30px; color: #fd5656"></i>
+				<span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
+			</p>
+			<p class="example-p">
+				<i class="el-icon-lx-emojifill" style="font-size: 30px; color: #ffc300"></i>
+				<span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
+			</p>
+			<br />
+			<h2>图标</h2>
+			<div class="search-box">
+				<el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
+			</div>
+			<ul>
+				<li class="icon-li" v-for="(item, index) in list" :key="index">
+					<div class="icon-li-content">
+						<i :class="`el-icon-lx-${item}`"></i>
+						<span>{{ item }}</span>
+					</div>
+				</li>
+			</ul>
+		</el-tab-pane>
+		<el-tab-pane label="Element图标">
+			<el-link type="primary" href="https://element-plus.org/zh-CN/component/icon.html#icon-collection"
+				target="_blank">前往官方文档查看</el-link>
+		</el-tab-pane>
+	</el-tabs>
+</template>
+
+<script setup lang="ts" name="icon">
+import { computed, ref } from 'vue';
+
+const iconList: Array<string> = [
+	'attentionforbid',
+	'attentionforbidfill',
+	'attention',
+	'attentionfill',
+	'tag',
+	'tagfill',
+	'people',
+	'peoplefill',
+	'notice',
+	'noticefill',
+	'mobile',
+	'mobilefill',
+	'voice',
+	'voicefill',
+	'unlock',
+	'lock',
+	'home',
+	'homefill',
+	'delete',
+	'deletefill',
+	'notification',
+	'notificationfill',
+	'notificationforbidfill',
+	'like',
+	'likefill',
+	'comment',
+	'commentfill',
+	'camera',
+	'camerafill',
+	'warn',
+	'warnfill',
+	'time',
+	'timefill',
+	'location',
+	'locationfill',
+	'favor',
+	'favorfill',
+	'skin',
+	'skinfill',
+	'news',
+	'newsfill',
+	'record',
+	'recordfill',
+	'emoji',
+	'emojifill',
+	'message',
+	'messagefill',
+	'goods',
+	'goodsfill',
+	'crown',
+	'crownfill',
+	'move',
+	'add',
+	'hot',
+	'hotfill',
+	'service',
+	'servicefill',
+	'present',
+	'presentfill',
+	'pic',
+	'picfill',
+	'rank',
+	'rankfill',
+	'male',
+	'female',
+	'down',
+	'top',
+	'recharge',
+	'rechargefill',
+	'forward',
+	'forwardfill',
+	'info',
+	'infofill',
+	'redpacket',
+	'redpacket_fill',
+	'roundadd',
+	'roundaddfill',
+	'friendadd',
+	'friendaddfill',
+	'cart',
+	'cartfill',
+	'more',
+	'moreandroid',
+	'back',
+	'right',
+	'shop',
+	'shopfill',
+	'question',
+	'questionfill',
+	'roundclose',
+	'roundclosefill',
+	'roundcheck',
+	'roundcheckfill',
+	'global',
+	'mail',
+	'punch',
+	'exit',
+	'upload',
+	'read',
+	'file',
+	'link',
+	'full',
+	'group',
+	'friend',
+	'profile',
+	'addressbook',
+	'calendar',
+	'text',
+	'copy',
+	'share',
+	'wifi',
+	'vipcard',
+	'weibo',
+	'remind',
+	'refresh',
+	'filter',
+	'settings',
+	'scan',
+	'qrcode',
+	'cascades',
+	'apps',
+	'sort',
+	'searchlist',
+	'search',
+	'edit',
+	'apple-line',
+	'baidu-fill',
+	'amazon-fill',
+	'netease-cloud-music-fill',
+	'qq-line',
+	'wechat-fill',
+	'alipay-fill',
+	'android-fill',
+	'android-line',
+	'whatsapp-line',
+	'whatsapp-fill',
+	'bilibili-fill',
+	'chrome-fill',
+	'dingding-fill',
+	'dingding-line',
+	'apple-fill',
+	'github-fill',
+	'qq-fill',
+	'wechat-pay-fill',
+	'windows-line',
+	'windows-fill',
+	'youtube-line',
+	'youtube-fill',
+	'wechat-pay-line',
+	'zhihu-line'
+];
+
+const keyword = ref('');
+const list = computed(() => {
+	return iconList.filter(item => {
+		return item.indexOf(keyword.value) !== -1;
+	});
+});
+</script>
+
+<style scoped>
+.example-p {
+	height: 45px;
+	display: flex;
+	align-items: center;
+}
+
+.search-box {
+	text-align: center;
+	margin-top: 10px;
+}
+
+.search {
+	width: 300px;
+}
+
+ul,
+li {
+	list-style: none;
+}
+
+.icon-li {
+	display: inline-block;
+	padding: 10px;
+	width: 120px;
+	height: 120px;
+}
+
+.icon-li-content {
+	display: flex;
+	height: 100%;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	cursor: pointer;
+}
+
+.icon-li-content i {
+	font-size: 36px;
+	color: #606266;
+}
+
+.icon-li-content span {
+	margin-top: 10px;
+	color: #787878;
+}
+
+.iframe {
+	width: 100%;
+	height: 700px;
+}
+</style>
diff --git a/src/views/login.vue b/src/views/pages/login.vue
similarity index 56%
rename from src/views/login.vue
rename to src/views/pages/login.vue
index 38a0b4ea..16ef0472 100644
--- a/src/views/login.vue
+++ b/src/views/pages/login.vue
@@ -1,136 +1,172 @@
-<template>
-    <div class="login-wrap">
-        <div class="ms-login">
-            <div class="ms-title">后台管理系统</div>
-            <el-form :model="param" :rules="rules" ref="login" label-width="0px" class="ms-content">
-                <el-form-item prop="username">
-                    <el-input v-model="param.username" placeholder="username">
-                        <template #prepend>
-                            <el-button :icon="User"></el-button>
-                        </template>
-                    </el-input>
-                </el-form-item>
-                <el-form-item prop="password">
-                    <el-input
-                        type="password"
-                        placeholder="password"
-                        v-model="param.password"
-                        @keyup.enter="submitForm(login)"
-                    >
-                        <template #prepend>
-                            <el-button :icon="Lock"></el-button>
-                        </template>
-                    </el-input>
-                </el-form-item>
-                <div class="login-btn">
-                    <el-button type="primary" @click="submitForm(login)">登录</el-button>
-                </div>
-                <el-checkbox class="login-tips" v-model="checked" label="记住密码" size="large" />
-                <p class="login-tips">Tips : 用户名和密码随便填。</p>
-            </el-form>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts">
-import { ref, reactive } from 'vue';
-import { useTagsStore } from '../store/tags';
-import { usePermissStore } from '../store/permiss';
-import { useRouter } from 'vue-router';
-import { ElMessage } from 'element-plus';
-import type { FormInstance, FormRules } from 'element-plus';
-import { Lock, User } from '@element-plus/icons-vue';
-
-interface LoginInfo {
-    username: string;
-    password: string;
-}
-
-const lgStr = localStorage.getItem('login-param');
-const defParam = lgStr ? JSON.parse(lgStr) : null;
-const checked = ref(lgStr ? true : false);
-
-const router = useRouter();
-const param = reactive<LoginInfo>({
-    username: defParam ? defParam.username : '',
-    password: defParam ? defParam.password : '',
-});
-
-const rules: FormRules = {
-    username: [
-        {
-            required: true,
-            message: '请输入用户名',
-            trigger: 'blur',
-        },
-    ],
-    password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-};
-const permiss = usePermissStore();
-const login = ref<FormInstance>();
-const submitForm = (formEl: FormInstance | undefined) => {
-    if (!formEl) return;
-    formEl.validate((valid: boolean) => {
-        if (valid) {
-            ElMessage.success('登录成功');
-            localStorage.setItem('ms_username', param.username);
-            const keys = permiss.defaultList[param.username == 'admin' ? 'admin' : 'user'];
-            permiss.handleSet(keys);
-            localStorage.setItem('ms_keys', JSON.stringify(keys));
-            router.push('/');
-            if (checked.value) {
-                localStorage.setItem('login-param', JSON.stringify(param));
-            } else {
-                localStorage.removeItem('login-param');
-            }
-        } else {
-            ElMessage.error('登录失败');
-            return false;
-        }
-    });
-};
-
-const tags = useTagsStore();
-tags.clearTags();
-</script>
-
-<style scoped>
-.login-wrap {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    width: 100%;
-    height: 100%;
-    background-image: url(../assets/img/login-bg.jpg);
-    background-size: 100%;
-}
-.ms-title {
-    line-height: 50px;
-    text-align: center;
-    font-size: 20px;
-    color: #333;
-    font-weight: bold;
-    padding-top: 10px;
-}
-.ms-login {
-    width: 350px;
-    border-radius: 5px;
-    background: #fff;
-}
-.ms-content {
-    padding: 10px 30px 30px;
-}
-.login-btn {
-    text-align: center;
-}
-.login-btn button {
-    width: 100%;
-    height: 36px;
-    margin-bottom: 10px;
-}
-.login-tips {
-    font-size: 12px;
-    line-height: 30px;
-    color: #333;
-}
-</style>
+<template>
+    <div class="login-bg">
+        <div class="login-container">
+            <div class="login-header">
+                <img class="logo mr10" src="../../assets/img/logo.svg" alt="" />
+                <div class="login-title">后台管理系统</div>
+            </div>
+            <el-form :model="param" :rules="rules" ref="login" size="large">
+                <el-form-item prop="username">
+                    <el-input v-model="param.username" placeholder="用户名">
+                        <template #prepend>
+                            <el-icon>
+                                <User />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="password">
+                    <el-input
+                        type="password"
+                        placeholder="密码"
+                        v-model="param.password"
+                        @keyup.enter="submitForm(login)"
+                    >
+                        <template #prepend>
+                            <el-icon>
+                                <Lock />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <div class="pwd-tips">
+                    <el-checkbox class="pwd-checkbox" v-model="checked" label="记住密码" />
+                    <el-link type="primary" @click="$router.push('/reset-pwd')">忘记密码</el-link>
+                </div>
+                <el-button class="login-btn" type="primary" size="large" @click="submitForm(login)">登录</el-button>
+                <p class="login-tips">Tips : 用户名和密码随便填。</p>
+                <p class="login-text">
+                    没有账号?<el-link type="primary" @click="$router.push('/register')">立即注册</el-link>
+                </p>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { useTabsStore } from '@/store/tabs';
+import { usePermissStore } from '@/store/permiss';
+import { useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import type { FormInstance, FormRules } from 'element-plus';
+
+interface LoginInfo {
+    username: string;
+    password: string;
+}
+
+const lgStr = localStorage.getItem('login-param');
+const defParam = lgStr ? JSON.parse(lgStr) : null;
+const checked = ref(lgStr ? true : false);
+
+const router = useRouter();
+const param = reactive<LoginInfo>({
+    username: defParam ? defParam.username : '',
+    password: defParam ? defParam.password : '',
+});
+
+const rules: FormRules = {
+    username: [
+        {
+            required: true,
+            message: '请输入用户名',
+            trigger: 'blur',
+        },
+    ],
+    password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
+};
+const permiss = usePermissStore();
+const login = ref<FormInstance>();
+const submitForm = (formEl: FormInstance | undefined) => {
+    if (!formEl) return;
+    formEl.validate((valid: boolean) => {
+        if (valid) {
+            ElMessage.success('登录成功');
+            localStorage.setItem('ms_username', param.username);
+            const keys = permiss.defaultList[param.username == 'admin' ? 'admin' : 'user'];
+            permiss.handleSet(keys);
+            localStorage.setItem('ms_keys', JSON.stringify(keys));
+            router.push('/');
+            if (checked.value) {
+                localStorage.setItem('login-param', JSON.stringify(param));
+            } else {
+                localStorage.removeItem('login-param');
+            }
+        } else {
+            ElMessage.error('登录失败');
+            return false;
+        }
+    });
+};
+
+const tabs = useTabsStore();
+tabs.clearTabs();
+</script>
+
+<style scoped>
+.login-bg {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    background: url(../../assets/img/login-bg.jpg) center/cover no-repeat;
+}
+
+.login-header {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 40px;
+}
+
+.logo {
+    width: 35px;
+}
+
+.login-title {
+    font-size: 22px;
+    color: #333;
+    font-weight: bold;
+}
+
+.login-container {
+    width: 450px;
+    border-radius: 5px;
+    background: #fff;
+    padding: 40px 50px 50px;
+    box-sizing: border-box;
+}
+
+.pwd-tips {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    font-size: 14px;
+    margin: -10px 0 10px;
+    color: #787878;
+}
+
+.pwd-checkbox {
+    height: auto;
+}
+
+.login-btn {
+    display: block;
+    width: 100%;
+}
+
+.login-tips {
+    font-size: 12px;
+    color: #999;
+}
+
+.login-text {
+    display: flex;
+    align-items: center;
+    margin-top: 20px;
+    font-size: 14px;
+    color: #787878;
+}
+</style>
diff --git a/src/views/markdown.vue b/src/views/pages/markdown.vue
similarity index 96%
rename from src/views/markdown.vue
rename to src/views/pages/markdown.vue
index d435f9ca..286b679d 100644
--- a/src/views/markdown.vue
+++ b/src/views/pages/markdown.vue
@@ -1,21 +1,21 @@
-<template>
-	<div class="container">
-		<div class="plugins-tips">
-			md-editor-v3:vue3版本的 markdown 编辑器,配置丰富,请详看文档。 访问地址:
-			<a href="https://imzbf.github.io/md-editor-v3/index" target="_blank">md-editor-v3</a>
-		</div>
-		<md-editor class="mgb20" v-model="text" @on-upload-img="onUploadImg" />
-		<el-button type="primary">提交</el-button>
-	</div>
-</template>
-
-<script setup lang="ts" name="md">
-import { ref } from 'vue';
-import MdEditor from 'md-editor-v3';
-import 'md-editor-v3/lib/style.css';
-
-const text = ref('Hello Editor!');
-const onUploadImg = (files: any) => {
-	console.log(files);
-};
-</script>
+<template>
+	<div class="container">
+		<div class="plugins-tips">
+			md-editor-v3:vue3版本的 markdown 编辑器,配置丰富,请详看文档。 访问地址:
+			<a href="https://imzbf.github.io/md-editor-v3/index" target="_blank">md-editor-v3</a>
+		</div>
+		<md-editor class="mgb20" v-model="text" @on-upload-img="onUploadImg" />
+		<el-button type="primary">提交</el-button>
+	</div>
+</template>
+
+<script setup lang="ts" name="md">
+import { ref } from 'vue';
+import MdEditor from 'md-editor-v3';
+import 'md-editor-v3/lib/style.css';
+
+const text = ref('Hello Editor!');
+const onUploadImg = (files: any) => {
+	console.log(files);
+};
+</script>
diff --git a/src/views/pages/register.vue b/src/views/pages/register.vue
new file mode 100644
index 00000000..c3cdec01
--- /dev/null
+++ b/src/views/pages/register.vue
@@ -0,0 +1,132 @@
+<template>
+    <div class="login-bg">
+        <div class="login-container">
+            <div class="login-header">
+                <img class="logo mr10" src="../../assets/img/logo.svg" alt="">
+                <div class="login-title">
+                    后台管理系统
+                </div>
+            </div>
+            <el-form :model="param" :rules="rules" ref="register" size="large">
+                <el-form-item prop="username">
+                    <el-input v-model="param.username" placeholder="用户名">
+                        <template #prepend>
+                            <el-icon>
+                                <User />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="email">
+                    <el-input v-model="param.email" placeholder="邮箱">
+                        <template #prepend>
+                            <el-icon>
+                                <Message />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="password">
+                    <el-input type="password" placeholder="密码" v-model="param.password"
+                        @keyup.enter="submitForm(register)">
+                        <template #prepend>
+                            <el-icon>
+                                <Lock />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-button class="login-btn" type="primary" size="large" @click="submitForm(register)">注册</el-button>
+                <p class="login-text">已有账号,<el-link type="primary" @click="$router.push('/login')">立即登录</el-link></p>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
+import { Register } from '@/types/user';
+
+const router = useRouter();
+const param = reactive<Register>({
+    username: '',
+    password: '',
+    email: '',
+});
+
+const rules: FormRules = {
+    username: [
+        {
+            required: true,
+            message: '请输入用户名',
+            trigger: 'blur',
+        },
+    ],
+    password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
+    email: [{ required: true, message: '请输入邮箱', trigger: 'blur' }],
+};
+const register = ref<FormInstance>();
+const submitForm = (formEl: FormInstance | undefined) => {
+    if (!formEl) return;
+    formEl.validate((valid: boolean) => {
+        if (valid) {
+            ElMessage.success('注册成功,请登录');
+            router.push('/login');
+        } else {
+            return false;
+        }
+    });
+};
+
+</script>
+
+<style scoped>
+.login-bg {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    background: url(../../assets/img/login-bg.jpg) center/cover no-repeat;
+}
+
+.login-header {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 40px;
+}
+
+.logo {
+    width: 35px;
+}
+
+.login-title {
+    font-size: 22px;
+    color: #333;
+    font-weight: bold;
+}
+
+.login-container {
+    width: 450px;
+    border-radius: 5px;
+    background: #fff;
+    padding: 40px 50px 50px;
+    box-sizing: border-box;
+}
+
+.login-btn {
+    display: block;
+    width: 100%;
+}
+
+.login-text {
+    display: flex;
+    align-items: center;
+    margin-top: 20px;
+    font-size: 14px;
+    color: #787878;
+}
+</style>
diff --git a/src/views/pages/reset-pwd.vue b/src/views/pages/reset-pwd.vue
new file mode 100644
index 00000000..e042b93d
--- /dev/null
+++ b/src/views/pages/reset-pwd.vue
@@ -0,0 +1,97 @@
+<template>
+    <div class="login-bg">
+        <div class="login-container">
+            <div class="reset-title">重置密码</div>
+            <p class="reset-text">输入你的邮箱,我们将发送重置密码邮件</p>
+            <el-form :model="param" :rules="rules" ref="register" size="large">
+                <el-form-item prop="email">
+                    <el-input v-model="param.email" placeholder="邮箱">
+                        <template #prepend>
+                            <el-icon>
+                                <Message />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-button class="login-btn" type="primary" size="large" @click="submitForm(register)">发送邮件</el-button>
+                <p class="login-text"><el-link type="primary" @click="$router.push('/login')">返回登录</el-link></p>
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
+
+const param = ref({
+    email: '',
+});
+
+const rules: FormRules = {
+    email: [
+        { required: true, message: '请输入邮箱', trigger: 'blur' },
+        { pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, message: '请输入正确的邮箱格式', trigger: 'blur' }
+    ],
+};
+const register = ref<FormInstance>();
+const submitForm = (formEl: FormInstance | undefined) => {
+    if (!formEl) return;
+    formEl.validate((valid: boolean) => {
+        if (valid) {
+            ElMessage.success('邮件已发送,请注意查收');
+        } else {
+            return false;
+        }
+    });
+};
+
+</script>
+
+<style scoped>
+.login-bg {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    background: url(../../assets/img/login-bg.jpg) center/cover no-repeat;
+}
+
+.reset-title {
+    text-align: center;
+    font-size: 22px;
+    color: #333;
+    font-weight: bold;
+    margin-bottom: 10px;
+}
+
+.reset-text {
+    text-align: center;
+    font-size: 14px;
+    color: #787878;
+    margin-bottom: 40px;
+}
+
+.login-container {
+    width: 450px;
+    border-radius: 5px;
+    background: #fff;
+    padding: 40px 50px 50px;
+    box-sizing: border-box;
+}
+
+.login-btn {
+    display: block;
+    width: 100%;
+}
+
+.login-text {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-top: 20px;
+    font-size: 14px;
+    color: #333;
+}
+</style>
diff --git a/src/views/pages/theme.vue b/src/views/pages/theme.vue
new file mode 100644
index 00000000..b284ddb4
--- /dev/null
+++ b/src/views/pages/theme.vue
@@ -0,0 +1,205 @@
+<template>
+    <div>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">系统主题</div>
+            </template>
+            <div class="theme-list mgb20">
+                <div class="theme-item" @click="setSystemTheme(item)" v-for="item in system"
+                    :style="{ backgroundColor: item.color, color: '#fff' }">{{ item.name }}
+                </div>
+            </div>
+            <div class="flex-center">
+                <el-button @click="resetSystemTheme">重置主题</el-button>
+            </div>
+        </el-card>
+        <el-card class="mgb20" shadow="hover">
+            <template #header>
+                <div class="content-title">Element-Plus主题</div>
+            </template>
+            <div class="theme-list mgb20">
+                <div class="theme-item" v-for="theme in themes">
+                    <el-button :type="theme.name">{{ theme.name }}</el-button>
+                    <div class="theme-color">{{ theme.color }}</div>
+                    <el-color-picker v-model="color[theme.name]" @change="changeColor(theme.name)" />
+                </div>
+            </div>
+            <div class="flex-center">
+                <el-button @click="resetTheme">重置主题</el-button>
+            </div>
+        </el-card>
+
+        <el-row :gutter="50">
+            <el-col :span="12">
+                <el-card class="mgb20" shadow="hover">
+                    <template #header>
+                        <div class="content-title">头部主题</div>
+                    </template>
+                    <div class="theme-list mgb20">
+                        <div class="theme-item">
+                            <el-button :color="color.headerBgColor">背景颜色</el-button>
+                            <div class="theme-color">{{ color.headerBgColor }}</div>
+                            <el-color-picker v-model="color.headerBgColor"
+                                @change="themeStore.setHeaderBgColor(color.headerBgColor)" />
+                        </div>
+                        <div class="theme-item">
+                            <el-button :color="color.headerTextColor">文字颜色</el-button>
+                            <div class="theme-color">{{ color.headerTextColor }}</div>
+                            <el-color-picker v-model="color.headerTextColor"
+                                @change="themeStore.setHeaderTextColor(color.headerTextColor)" />
+                        </div>
+                    </div>
+                    <div class="flex-center">
+                        <el-button @click="resetHeader">重置主题</el-button>
+                    </div>
+                </el-card>
+            </el-col>
+
+            <el-col :span="12">
+                <el-card class="mgb20" shadow="hover">
+                    <template #header>
+                        <div class="content-title">菜单主题</div>
+                    </template>
+                    <div class="theme-list mgb20">
+                        <div class="theme-item">
+                            <el-button :color="sidebar.bgColor">背景颜色</el-button>
+                            <div class="theme-color">{{ sidebar.bgColor }}</div>
+                            <el-color-picker v-model="sidebarColor.bgColor"
+                                @change="sidebar.setBgColor(sidebarColor.bgColor)" />
+                        </div>
+                        <div class="theme-item">
+                            <el-button :color="sidebar.textColor">文字颜色</el-button>
+                            <div class="theme-color">{{ sidebar.textColor }}</div>
+                            <el-color-picker v-model="sidebarColor.textColor"
+                                @change="sidebar.setTextColor(sidebarColor.textColor)" />
+                        </div>
+                    </div>
+                    <div class="flex-center">
+                        <el-button @click="resetSidebar">重置主题</el-button>
+                    </div>
+                </el-card>
+            </el-col>
+        </el-row>
+
+    </div>
+</template>
+
+<script setup lang="ts">
+import { useSidebarStore } from '@/store/sidebar';
+import { useThemeStore } from '@/store/theme'
+import { reactive } from 'vue';
+const themeStore = useThemeStore();
+const sidebar = useSidebarStore();
+
+const color = reactive({
+    primary: localStorage.getItem('theme-primary') || '#409eff',
+    success: localStorage.getItem('theme-success') || '#67c23a',
+    warning: localStorage.getItem('theme-warning') || '#e6a23c',
+    danger: localStorage.getItem('theme-danger') || '#f56c6c',
+    info: localStorage.getItem('theme-info') || '#909399',
+    headerBgColor: themeStore.headerBgColor,
+    headerTextColor: themeStore.headerTextColor,
+})
+const sidebarColor = reactive({
+    bgColor: sidebar.bgColor,
+    textColor: sidebar.textColor
+})
+const themes = [
+    {
+        name: 'primary',
+        color: themeStore.primary || color.primary
+    },
+    {
+        name: 'success',
+        color: themeStore.success || color.success
+    },
+    {
+        name: 'warning',
+        color: themeStore.warning || color.warning
+    },
+    {
+        name: 'danger',
+        color: themeStore.danger || color.danger
+    },
+    {
+        name: 'info',
+        color: themeStore.info || color.info
+    }
+]
+
+const changeColor = (name: string) => {
+    themeStore.setPropertyColor(color[name], name)
+}
+
+const resetTheme = () => {
+    themeStore.resetTheme()
+}
+const resetHeader = () => {
+    localStorage.removeItem('header-bg-color')
+    localStorage.removeItem('header-text-color')
+    location.reload()
+}
+const resetSidebar = () => {
+    localStorage.removeItem('sidebar-bg-color')
+    localStorage.removeItem('sidebar-text-color')
+    location.reload()
+}
+const system = [
+    {
+        name: '默认',
+        color: '#242f42'
+    },
+    {
+        name: '健康',
+        color: '#1ABC9C'
+    },
+    {
+        name: '优雅',
+        color: '#722ed1'
+    },
+    {
+        name: '热情',
+        color: '#f44336'
+    },
+    {
+        name: '宁静',
+        color: '#00bcd4'
+    }
+]
+const setSystemTheme = (data: any) => {
+    if (data.name === '默认') {
+        resetSystemTheme()
+    } else {
+        themeStore.setHeaderBgColor(data.color)
+        themeStore.setHeaderTextColor('#fff')
+        sidebar.setBgColor('#fff')
+        sidebar.setTextColor('#5b6e88')
+        themeStore.setPropertyColor(data.color, 'primary')
+    }
+}
+const resetSystemTheme = () => {
+    resetTheme();
+    resetHeader();
+    resetSidebar();
+}
+</script>
+
+<style scoped>
+.theme-list {
+    display: flex;
+    justify-content: center;
+}
+
+.theme-item {
+    margin-right: 20px;
+    padding: 30px;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    text-align: center;
+}
+
+.theme-color {
+    color: #787878;
+    margin: 20px 0;
+}
+</style>
diff --git a/src/views/pages/ucenter.vue b/src/views/pages/ucenter.vue
new file mode 100644
index 00000000..2f53081a
--- /dev/null
+++ b/src/views/pages/ucenter.vue
@@ -0,0 +1,270 @@
+<template>
+    <div>
+        <div class="user-container">
+            <el-card class="user-profile" shadow="hover" :body-style="{ padding: '0px' }">
+                <div class="user-profile-bg"></div>
+                <div class="user-avatar-wrap">
+                    <el-avatar class="user-avatar" :size="120" :src="avatarImg" />
+                </div>
+                <div class="user-info">
+                    <div class="info-name">{{ name }}</div>
+                    <div class="info-desc">
+                        <span>@lin-xin</span>
+                        <el-divider direction="vertical" />
+                        <el-link href="https://lin-xin.gitee.io" target="_blank">lin-xin.gitee.io</el-link>
+                    </div>
+                    <div class="info-desc">FE Developer</div>
+                    <div class="info-icon">
+                        <a href="https://github.com/lin-xin" target="_blank"> <i class="el-icon-lx-github-fill"></i></a>
+                        <i class="el-icon-lx-qq-fill"></i>
+                        <i class="el-icon-lx-facebook-fill"></i>
+                        <i class="el-icon-lx-twitter-fill"></i>
+                    </div>
+                </div>
+                <div class="user-footer">
+                    <div class="user-footer-item">
+                        <el-statistic title="Follower" :value="1800" />
+                    </div>
+                    <div class="user-footer-item">
+                        <el-statistic title="Following" :value="666" />
+                    </div>
+                    <div class="user-footer-item">
+                        <el-statistic title="Total Post" :value="888" />
+                    </div>
+                </div>
+            </el-card>
+            <el-card
+                class="user-content"
+                shadow="hover"
+                :body-style="{ padding: '20px 50px', height: '100%', boxSizing: 'border-box' }"
+            >
+                <el-tabs tab-position="left" v-model="activeName">
+                    <el-tab-pane name="label1" label="消息通知" class="user-tabpane">
+                        <TabsComp />
+                    </el-tab-pane>
+                    <el-tab-pane name="label2" label="我的头像" class="user-tabpane">
+                        <div class="crop-wrap" v-if="activeName === 'label2'">
+                            <vueCropper
+                                ref="cropper"
+                                :img="imgSrc"
+                                :autoCrop="true"
+                                :centerBox="true"
+                                :full="true"
+                                mode="contain"
+                            >
+                            </vueCropper>
+                        </div>
+                        <el-button class="crop-demo-btn" type="primary"
+                            >选择图片
+                            <input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
+                        </el-button>
+                        <el-button type="success" @click="saveAvatar">上传并保存</el-button>
+                    </el-tab-pane>
+                    <el-tab-pane name="label3" label="修改密码" class="user-tabpane">
+                        <el-form class="w500" label-position="top">
+                            <el-form-item label="旧密码:">
+                                <el-input type="password" v-model="form.old"></el-input>
+                            </el-form-item>
+                            <el-form-item label="新密码:">
+                                <el-input type="password" v-model="form.new"></el-input>
+                            </el-form-item>
+                            <el-form-item label="确认新密码:">
+                                <el-input type="password" v-model="form.new1"></el-input>
+                            </el-form-item>
+                            <el-form-item>
+                                <el-button type="primary" @click="onSubmit">保存</el-button>
+                            </el-form-item>
+                        </el-form>
+                    </el-tab-pane>
+                    <el-tab-pane name="label4" label="赞赏作者" class="user-tabpane">
+                        <div class="plugins-tips">
+                            如果该框架
+                            <el-link href="https://github.com/lin-xin/vue-manage-system" target="_blank"
+                                >vue-manage-system</el-link
+                            >
+                            对你有帮助,那就请作者喝杯饮料吧!<el-icon>
+                                <ColdDrink />
+                            </el-icon>
+                            加微信号 linxin_20 探讨问题。
+                        </div>
+                        <div>
+                            <img src="https://lin-xin.gitee.io/images/weixin.jpg" />
+                        </div>
+                    </el-tab-pane>
+                </el-tabs>
+            </el-card>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts" name="ucenter">
+import { reactive, ref } from 'vue';
+import { VueCropper } from 'vue-cropper';
+import 'vue-cropper/dist/index.css';
+import avatar from '@/assets/img/img.jpg';
+import TabsComp from '../element/tabs.vue';
+
+const name = localStorage.getItem('ms_username');
+const form = reactive({
+    new1: '',
+    new: '',
+    old: '',
+});
+const onSubmit = () => {};
+
+const activeName = ref('label1');
+
+const avatarImg = ref(avatar);
+const imgSrc = ref(avatar);
+const cropImg = ref('');
+const cropper: any = ref();
+
+const setImage = (e: any) => {
+    const file = e.target.files[0];
+    if (!file.type.includes('image/')) {
+        return;
+    }
+    const reader = new FileReader();
+    reader.onload = (event: any) => {
+        imgSrc.value = event.target.result;
+        cropper.value && cropper.value.replace(event.target.result);
+    };
+    reader.readAsDataURL(file);
+};
+
+const cropImage = () => {
+    cropImg.value = cropper.value?.getCroppedCanvas().toDataURL();
+};
+
+const saveAvatar = () => {
+    avatarImg.value = cropImg.value;
+};
+</script>
+
+<style scoped>
+.user-container {
+    display: flex;
+}
+
+.user-profile {
+    position: relative;
+}
+
+.user-profile-bg {
+    width: 100%;
+    height: 200px;
+    background-image: url('../../assets/img/ucenter-bg.jpg');
+    background-size: cover;
+    background-position: center;
+    background-repeat: no-repeat;
+}
+
+.user-profile {
+    width: 500px;
+    margin-right: 20px;
+    flex: 0 0 auto;
+    align-self: flex-start;
+}
+
+.user-avatar-wrap {
+    position: absolute;
+    top: 135px;
+    width: 100%;
+    text-align: center;
+}
+
+.user-avatar {
+    border: 5px solid #fff;
+    border-radius: 50%;
+    overflow: hidden;
+    box-shadow: 0 7px 12px 0 rgba(62, 57, 107, 0.16);
+}
+
+.user-info {
+    text-align: center;
+    padding: 80px 0 30px;
+}
+
+.info-name {
+    margin: 0 0 20px;
+    font-size: 22px;
+    font-weight: 500;
+    color: #373a3c;
+}
+
+.info-desc {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 5px;
+}
+
+.info-desc,
+.info-desc a {
+    font-size: 18px;
+    color: #55595c;
+}
+
+.info-icon {
+    margin-top: 10px;
+}
+
+.info-icon i {
+    font-size: 30px;
+    margin: 0 10px;
+    color: #343434;
+}
+
+.user-content {
+    flex: 1;
+}
+
+.user-tabpane {
+    padding: 10px 20px;
+}
+
+.crop-wrap {
+    width: 600px;
+    height: 350px;
+    margin-bottom: 20px;
+}
+
+.crop-demo-btn {
+    position: relative;
+}
+
+.crop-input {
+    position: absolute;
+    width: 100px;
+    height: 40px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    cursor: pointer;
+}
+
+.w500 {
+    width: 500px;
+}
+
+.user-footer {
+    display: flex;
+    border-top: 1px solid rgba(83, 70, 134, 0.1);
+}
+
+.user-footer-item {
+    padding: 20px 0;
+    width: 33.3333333333%;
+    text-align: center;
+}
+
+.user-footer > div + div {
+    border-left: 1px solid rgba(83, 70, 134, 0.1);
+}
+</style>
+
+<style>
+.el-tabs.el-tabs--left {
+    height: 100%;
+}
+</style>
diff --git a/src/views/pages/ucenter2.vue b/src/views/pages/ucenter2.vue
new file mode 100644
index 00000000..96b8aec2
--- /dev/null
+++ b/src/views/pages/ucenter2.vue
@@ -0,0 +1,253 @@
+<template>
+	<div class="user-container">
+		<el-card class="user-profile mgb20" shadow="hover" :body-style="{ padding: '0px' }">
+			<div class="user-profile-bg"></div>
+			<div class="user-avatar-wrap">
+				<el-avatar class="user-avatar" :size="120" :src="avatarImg" />
+			</div>
+			<div class="user-info">
+				<div class="info-name">{{ name }}</div>
+				<div class="info-desc">
+					<!-- <span>{{ name }}</span>
+					<el-divider direction="vertical" /> -->
+					<span>FE Developer</span>
+					<el-divider direction="vertical" />
+					<el-link href="https://lin-xin.gitee.io" target="_blank">lin-xin.gitee.io</el-link>
+				</div>
+				<!-- <div class="info-icon">
+					<a href="https://github.com/lin-xin" target="_blank"> <i class="el-icon-lx-github-fill"></i></a>
+					<i class="el-icon-lx-qq-fill"></i>
+					<i class="el-icon-lx-facebook-fill"></i>
+					<i class="el-icon-lx-twitter-fill"></i>
+				</div> -->
+			</div>
+			<!-- <div class="user-footer">
+				<div class="user-footer-item">
+					<el-statistic title="Follower" value="18K" />
+				</div>
+				<div class="user-footer-item">
+					<el-statistic title="Following" :value="666" />
+				</div>
+				<div class="user-footer-item">
+					<el-statistic title="Total Post" :value="888" />
+				</div>
+			</div> -->
+		</el-card>
+		<el-card class="user-content" shadow="hover"
+			:body-style="{ padding: '20px 50px', height: '100%', boxSizing: 'border-box' }">
+			<el-tabs v-model="activeName">
+
+				<el-tab-pane name="label1" label="消息通知" class="user-tabpane">
+					<TabsComp />
+				</el-tab-pane>
+				<el-tab-pane name="label2" label="我的头像" class="user-tabpane">
+					<div class="crop-wrap" v-if="activeName === 'label2'">
+						<vueCropper ref="cropper" :img="imgSrc" :autoCrop="true" :centerBox="true" :full="true"
+							mode="contain">
+						</vueCropper>
+					</div>
+					<el-button class="crop-demo-btn" type="primary">选择图片
+						<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
+					</el-button>
+					<el-button type="success" @click="saveAvatar">上传并保存</el-button>
+				</el-tab-pane>
+				<el-tab-pane name="label3" label="修改密码" class="user-tabpane">
+					<el-form class="w500" label-position="top">
+						<el-form-item label="旧密码:">
+							<el-input type="password" v-model="form.old"></el-input>
+						</el-form-item>
+						<el-form-item label="新密码:">
+							<el-input type="password" v-model="form.new"></el-input>
+						</el-form-item>
+						<el-form-item label="确认新密码:">
+							<el-input type="password" v-model="form.new1"></el-input>
+						</el-form-item>
+						<el-form-item>
+							<el-button type="primary" @click="onSubmit">保存</el-button>
+						</el-form-item>
+					</el-form>
+				</el-tab-pane>
+				<el-tab-pane name="label4" label="赞赏作者" class="user-tabpane">
+					<div class="plugins-tips">
+						如果该框架 <el-link href="https://github.com/lin-xin/vue-manage-system"
+							target="_blank">vue-manage-system</el-link> 对你有帮助,那就请作者喝杯饮料吧!<el-icon>
+							<ColdDrink />
+						</el-icon> 加微信号 linxin_20 探讨问题。
+					</div>
+					<div>
+						<img src="https://lin-xin.gitee.io/images/weixin.jpg" />
+					</div>
+				</el-tab-pane>
+			</el-tabs>
+		</el-card>
+	</div>
+</template>
+
+<script setup lang="ts" name="ucenter">
+import { reactive, ref } from 'vue';
+import { VueCropper } from "vue-cropper"
+import 'vue-cropper/dist/index.css'
+import avatar from '@/assets/img/img.jpg';
+import TabsComp from '../element/tabs.vue';
+
+const name = localStorage.getItem('ms_username');
+const form = reactive({
+	new1: '',
+	new: '',
+	old: ''
+});
+const onSubmit = () => { };
+
+const activeName = ref('label1');
+
+const avatarImg = ref(avatar);
+const imgSrc = ref(avatar);
+const cropImg = ref('');
+const cropper: any = ref();
+
+const setImage = (e: any) => {
+	const file = e.target.files[0];
+	if (!file.type.includes('image/')) {
+		return;
+	}
+	const reader = new FileReader();
+	reader.onload = (event: any) => {
+		imgSrc.value = event.target.result;
+		cropper.value && cropper.value.replace(event.target.result);
+	};
+	reader.readAsDataURL(file);
+};
+
+const cropImage = () => {
+	cropImg.value = cropper.value?.getCroppedCanvas().toDataURL();
+};
+
+const saveAvatar = () => {
+	avatarImg.value = cropImg.value;
+};
+</script>
+
+<style scoped>
+/* .user-container {
+	display: flex;
+} */
+
+.user-profile-bg {
+	width: 100%;
+	height: 150px;
+	background-image: url('../../assets/img/bahnhofsidylle.jpg');
+	background-size: cover;
+	background-position: center;
+	background-repeat: no-repeat;
+}
+
+.user-profile {
+	position: relative;
+	/* width: 500px; */
+	/* margin-right: 20px; */
+	/* flex: 0 0 auto;
+	align-self: flex-start;
+} */
+}
+
+.user-avatar-wrap {
+	position: absolute;
+	top: 90px;
+	width: 100%;
+	text-align: center;
+}
+
+.user-avatar {
+	border: 5px solid #fff;
+	border-radius: 50%;
+	overflow: hidden;
+	box-shadow: 0 7px 12px 0 rgba(62, 57, 107, .16)
+}
+
+.user-info {
+	text-align: center;
+	padding: 70px 0 20px;
+}
+
+.info-name {
+	margin: 0 0 10px;
+	font-size: 22px;
+	font-weight: 500;
+	color: #373a3c;
+}
+
+.info-desc {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.info-desc,
+.info-desc a {
+	font-size: 18px;
+	color: #55595c;
+}
+
+.info-icon {
+	margin-top: 10px;
+}
+
+.info-icon i {
+	font-size: 30px;
+	margin: 0 10px;
+	color: #343434;
+}
+
+.user-content {
+	flex: 1
+}
+
+.user-tabpane {
+	padding: 10px 20px;
+}
+
+.crop-wrap {
+	width: 600px;
+	height: 350px;
+	margin-bottom: 20px;
+}
+
+.crop-demo-btn {
+	position: relative;
+}
+
+.crop-input {
+	position: absolute;
+	width: 100px;
+	height: 40px;
+	left: 0;
+	top: 0;
+	opacity: 0;
+	cursor: pointer;
+}
+
+.w500 {
+	width: 500px;
+}
+
+.user-footer {
+	display: flex;
+	border-top: 1px solid rgba(83, 70, 134, 0.1);
+}
+
+.user-footer-item {
+	padding: 20px 0;
+	width: 33.3333333333%;
+	text-align: center;
+}
+
+.user-footer>div+div {
+	border-left: 1px solid rgba(83, 70, 134, 0.1);
+}
+</style>
+
+<style>
+.el-tabs.el-tabs--left {
+	height: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/permission.vue b/src/views/permission.vue
deleted file mode 100644
index bf83327e..00000000
--- a/src/views/permission.vue
+++ /dev/null
@@ -1,137 +0,0 @@
-<template>
-	<div class="container">
-		<div class="plugins-tips">通过 v-permiss 自定义指令实现权限管理,使用非 admin 账号登录,可查看效果。</div>
-		<div class="mgb20">
-			<span class="label">角色:</span>
-			<el-select v-model="role" @change="handleChange">
-				<el-option label="超级管理员" value="admin"></el-option>
-				<el-option label="普通用户" value="user"></el-option>
-			</el-select>
-		</div>
-		<div class="mgb20 tree-wrapper">
-			<el-tree
-				ref="tree"
-				:data="data"
-				node-key="id"
-				default-expand-all
-				show-checkbox
-				:default-checked-keys="checkedKeys"
-			/>
-		</div>
-		<el-button type="primary" @click="onSubmit">保存权限</el-button>
-	</div>
-</template>
-
-<script setup lang="ts" name="permission">
-import { ref } from 'vue';
-import { ElTree } from 'element-plus';
-import { usePermissStore } from '../store/permiss';
-
-const role = ref<string>('admin');
-
-interface Tree {
-	id: string;
-	label: string;
-	children?: Tree[];
-}
-
-const data: Tree[] = [
-	{
-		id: '1',
-		label: '系统首页'
-	},
-	{
-		id: '2',
-		label: '基础表格',
-		children: [
-			{
-				id: '15',
-				label: '编辑'
-			},
-			{
-				id: '16',
-				label: '删除'
-			}
-		]
-	},
-	{
-		id: '3',
-		label: 'tab选项卡'
-	},
-	{
-		id: '4',
-		label: '表单相关',
-		children: [
-			{
-				id: '5',
-				label: '基本表单'
-			},
-			{
-				id: '6',
-				label: '文件上传'
-			},
-			{
-				id: '7',
-				label: '三级菜单',
-				children: [
-					{
-						id: '8',
-						label: '富文本编辑器'
-					},
-					{
-						id: '9',
-						label: 'markdown编辑器'
-					}
-				]
-			}
-		]
-	},
-	{
-		id: '10',
-		label: '自定义图标'
-	},
-	{
-		id: '11',
-		label: 'schart图表'
-	},
-
-	{
-		id: '13',
-		label: '权限管理'
-	},
-	{
-		id: '14',
-		label: '支持作者'
-	}
-];
-
-const permiss = usePermissStore();
-
-// 获取当前权限
-const checkedKeys = ref<string[]>([]);
-const getPremission = () => {
-	// 请求接口返回权限
-	checkedKeys.value = permiss.defaultList[role.value];
-};
-getPremission();
-
-// 保存权限
-const tree = ref<InstanceType<typeof ElTree>>();
-const onSubmit = () => {
-	// 获取选中的权限
-	console.log(tree.value!.getCheckedKeys(false));
-};
-
-const handleChange = (val: string[]) => {
-	tree.value!.setCheckedKeys(permiss.defaultList[role.value]);
-};
-</script>
-
-<style scoped>
-.tree-wrapper {
-	max-width: 500px;
-}
-.label {
-	font-size: 14px;
-}
-</style>
diff --git a/src/views/system/menu.vue b/src/views/system/menu.vue
new file mode 100644
index 00000000..bde753b5
--- /dev/null
+++ b/src/views/system/menu.vue
@@ -0,0 +1,144 @@
+<template>
+    <div>
+        <div class="container">
+            <TableCustom :columns="columns" :tableData="menuData" row-key="index" :has-pagination="false"
+                :viewFunc="handleView" :delFunc="handleDelete" :editFunc="handleEdit">
+                <template #toolbarBtn>
+                    <el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
+                </template>
+                <template #icon="{ rows }">
+                    <el-icon>
+                        <component :is="rows.icon"></component>
+                    </el-icon>
+                </template>
+            </TableCustom>
+
+        </div>
+        <el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
+            :close-on-click-modal="false" @close="closeDialog">
+            <TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData">
+                <template #parent>
+                    <el-cascader v-model="rowData.pid" :options="cascaderOptions" :props="{ checkStrictly: true }"
+                        clearable />
+                </template>
+            </TableEdit>
+        </el-dialog>
+        <el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
+            <TableDetail :data="viewData">
+                <template #icon="{ rows }">
+                    <el-icon>
+                        <component :is="rows.icon"></component>
+                    </el-icon>
+                </template>
+            </TableDetail>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup lang="ts" name="system-menu">
+import { ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import { CirclePlusFilled } from '@element-plus/icons-vue';
+import { Menus } from '@/types/menu';
+import TableCustom from '@/components/table-custom.vue';
+import TableDetail from '@/components/table-detail.vue';
+import { FormOption } from '@/types/form-option';
+import { menuData } from '@/components/menu';
+
+// 表格相关
+let columns = ref([
+    { prop: 'title', label: '菜单名称', align: 'left' },
+    { prop: 'icon', label: '图标' },
+    { prop: 'index', label: '路由路径' },
+    { prop: 'permiss', label: '权限标识' },
+    { prop: 'operator', label: '操作', width: 250 },
+])
+
+const getOptions = (data: any) => {
+    return data.map(item => {
+        const a: any = {
+            label: item.title,
+            value: item.id,
+        }
+        if (item.children) {
+            a.children = getOptions(item.children)
+        }
+        return a
+    })
+}
+const cascaderOptions = ref(getOptions(menuData));
+
+
+// 新增/编辑弹窗相关
+let options = ref<FormOption>({
+    labelWidth: '100px',
+    span: 12,
+    list: [
+        { type: 'input', label: '菜单名称', prop: 'title', required: true },
+        { type: 'input', label: '路由路径', prop: 'index', required: true },
+        { type: 'input', label: '图标', prop: 'icon' },
+        { type: 'input', label: '权限标识', prop: 'permiss' },
+        { type: 'parent', label: '父菜单', prop: 'parent' },
+    ]
+})
+const visible = ref(false);
+const isEdit = ref(false);
+const rowData = ref<any>({});
+const handleEdit = (row: Menus) => {
+    rowData.value = { ...row };
+    isEdit.value = true;
+    visible.value = true;
+};
+const updateData = () => {
+    closeDialog();
+};
+
+const closeDialog = () => {
+    visible.value = false;
+    isEdit.value = false;
+};
+
+// 查看详情弹窗相关
+const visible1 = ref(false);
+const viewData = ref({
+    row: {},
+    list: []
+});
+const handleView = (row: Menus) => {
+    viewData.value.row = { ...row }
+    viewData.value.list = [
+        {
+            prop: 'id',
+            label: '菜单ID',
+        },
+        {
+            prop: 'pid',
+            label: '父菜单ID',
+        },
+        {
+            prop: 'title',
+            label: '菜单名称',
+        },
+        {
+            prop: 'index',
+            label: '路由路径',
+        },
+        {
+            prop: 'permiss',
+            label: '权限标识',
+        },
+        {
+            prop: 'icon',
+            label: '图标',
+        },
+    ]
+    visible1.value = true;
+};
+
+// 删除相关
+const handleDelete = (row: Menus) => {
+    ElMessage.success('删除成功');
+}
+</script>
+
+<style scoped></style>
\ No newline at end of file
diff --git a/src/views/system/role-permission.vue b/src/views/system/role-permission.vue
new file mode 100644
index 00000000..eb31583c
--- /dev/null
+++ b/src/views/system/role-permission.vue
@@ -0,0 +1,76 @@
+<template>
+    <div>
+        <el-tree
+            class="mgb10"
+            ref="tree"
+            :data="data"
+            node-key="id"
+            default-expand-all
+            show-checkbox
+            :default-checked-keys="checkedKeys"
+        />
+        <el-button type="primary" @click="onSubmit">保存权限</el-button>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { ElTree } from 'element-plus';
+import { menuData } from '@/components/menu';
+
+const props = defineProps({
+    permissOptions: {
+        type: Object,
+        required: true,
+    },
+});
+
+const menuObj = ref({});
+// const data = menuData.map((item) => {
+//     if (item.children) {
+//         menuObj.value[item.id] = item.children.map((sub) => sub.id);
+//     }
+//     return {
+//         id: item.id,
+//         label: item.title,
+//         children: item.children?.map((child) => {
+//             return {
+//                 id: child.id,
+//                 label: child.title,
+//             };
+//         }),
+//     };
+// });
+
+const getTreeData = (data) => {
+    return data.map((item) => {
+        const obj: any = {
+            id: item.id,
+            label: item.title,
+        };
+        if (item.children) {
+            menuObj.value[item.id] = item.children.map((sub) => sub.id);
+            obj.children = getTreeData(item.children);
+        }
+        return obj;
+    });
+};
+const data = getTreeData(menuData);
+const checkData = (data: string[]) => {
+    return data.filter((item) => {
+        return !menuObj.value[item] || data.toString().includes(menuObj.value[item].toString());
+    });
+};
+// 获取当前权限
+const checkedKeys = ref<string[]>(checkData(props.permissOptions.permiss));
+
+// 保存权限
+const tree = ref<InstanceType<typeof ElTree>>();
+const onSubmit = () => {
+    // 获取选中的权限
+    const keys = [...tree.value!.getCheckedKeys(false), ...tree.value!.getHalfCheckedKeys()] as number[];
+    console.log(keys);
+};
+</script>
+
+<style scoped></style>
diff --git a/src/views/system/role.vue b/src/views/system/role.vue
new file mode 100644
index 00000000..fa8a6488
--- /dev/null
+++ b/src/views/system/role.vue
@@ -0,0 +1,162 @@
+<template>
+    <div>
+        <TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
+        <div class="container">
+
+            <TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
+                :delFunc="handleDelete" :page-change="changePage" :editFunc="handleEdit">
+                <template #toolbarBtn>
+                    <el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
+                </template>
+                <template #status="{ rows }">
+                    <el-tag type="success" v-if="rows.status">启用</el-tag>
+                    <el-tag type="danger" v-else>禁用</el-tag>
+                </template>
+                <template #permissions="{ rows }">
+                    <el-button type="primary" size="small" plain @click="handlePermission(rows)">管理</el-button>
+                </template>
+            </TableCustom>
+        </div>
+        <el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
+            :close-on-click-modal="false" @close="closeDialog">
+            <TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" />
+        </el-dialog>
+        <el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
+            <TableDetail :data="viewData">
+                <template #status="{ rows }">
+                    <el-tag type="success" v-if="rows.status">启用</el-tag>
+                    <el-tag type="danger" v-else>禁用</el-tag>
+                </template>
+            </TableDetail>
+        </el-dialog>
+        <el-dialog title="权限管理" v-model="visible2" width="500px" destroy-on-close>
+            <RolePermission :permiss-options="permissOptions" />
+        </el-dialog>
+    </div>
+</template>
+
+<script setup lang="ts" name="system-role">
+import { ref, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { Role } from '@/types/role';
+import { fetchRoleData } from '@/api';
+import TableCustom from '@/components/table-custom.vue';
+import TableDetail from '@/components/table-detail.vue';
+import RolePermission from './role-permission.vue'
+import { CirclePlusFilled } from '@element-plus/icons-vue';
+import { FormOption, FormOptionList } from '@/types/form-option';
+
+// 查询相关
+const query = reactive({
+    name: '',
+});
+const searchOpt = ref<FormOptionList[]>([
+    { type: 'input', label: '角色名称:', prop: 'name' }
+])
+const handleSearch = () => {
+    changePage(1);
+};
+
+// 表格相关
+let columns = ref([
+    { type: 'index', label: '序号', width: 55, align: 'center' },
+    { prop: 'name', label: '角色名称' },
+    { prop: 'key', label: '角色标识' },
+    { prop: 'status', label: '状态' },
+    { prop: 'permissions', label: '权限管理' },
+    { prop: 'operator', label: '操作', width: 250 },
+])
+const page = reactive({
+    index: 1,
+    size: 10,
+    total: 0,
+})
+const tableData = ref<Role[]>([]);
+const getData = async () => {
+    const res = await fetchRoleData()
+    tableData.value = res.data.list;
+    page.total = res.data.pageTotal;
+};
+getData();
+const changePage = (val: number) => {
+    page.index = val;
+    getData();
+};
+
+// 新增/编辑弹窗相关
+const options = ref<FormOption>({
+    labelWidth: '100px',
+    span: 24,
+    list: [
+        { type: 'input', label: '角色名称', prop: 'name', required: true },
+        { type: 'input', label: '角色标识', prop: 'key', required: true },
+        { type: 'switch', label: '状态', prop: 'status', required: false, activeText: '启用', inactiveText: '禁用' },
+    ]
+})
+const visible = ref(false);
+const isEdit = ref(false);
+const rowData = ref({});
+const handleEdit = (row: Role) => {
+    rowData.value = { ...row };
+    isEdit.value = true;
+    visible.value = true;
+};
+const updateData = () => {
+    closeDialog();
+    getData();
+};
+const closeDialog = () => {
+    visible.value = false;
+    isEdit.value = false;
+    rowData.value = {};
+};
+
+// 查看详情弹窗相关
+const visible1 = ref(false);
+const viewData = ref({
+    row: {},
+    list: [],
+    column: 1
+});
+const handleView = (row: Role) => {
+    viewData.value.row = { ...row }
+    viewData.value.list = [
+        {
+            prop: 'id',
+            label: '角色ID',
+        },
+        {
+            prop: 'name',
+            label: '角色名称',
+        },
+        {
+            prop: 'key',
+            label: '角色标识',
+        },
+        {
+            prop: 'status',
+            label: '角色状态',
+        },
+    ]
+    visible1.value = true;
+};
+
+// 删除相关
+const handleDelete = (row: Role) => {
+    ElMessage.success('删除成功');
+}
+
+
+// 权限管理弹窗相关
+const visible2 = ref(false);
+const permissOptions = ref({})
+const handlePermission = (row: Role) => {
+    visible2.value = true;
+    permissOptions.value = {
+        id: row.id,
+        permiss: row.permiss
+    };
+}
+</script>
+
+<style scoped></style>
\ No newline at end of file
diff --git a/src/views/system/user.vue b/src/views/system/user.vue
new file mode 100644
index 00000000..ea3a3d53
--- /dev/null
+++ b/src/views/system/user.vue
@@ -0,0 +1,148 @@
+<template>
+    <div>
+        <TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
+        <div class="container">
+            <TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
+                :delFunc="handleDelete" :page-change="changePage" :editFunc="handleEdit">
+                <template #toolbarBtn>
+                    <el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
+                </template>
+            </TableCustom>
+
+        </div>
+        <el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
+            :close-on-click-modal="false" @close="closeDialog">
+            <TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" />
+        </el-dialog>
+        <el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
+            <TableDetail :data="viewData"></TableDetail>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup lang="ts" name="system-user">
+import { ref, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { CirclePlusFilled } from '@element-plus/icons-vue';
+import { User } from '@/types/user';
+import { fetchUserData } from '@/api';
+import TableCustom from '@/components/table-custom.vue';
+import TableDetail from '@/components/table-detail.vue';
+import TableSearch from '@/components/table-search.vue';
+import { FormOption, FormOptionList } from '@/types/form-option';
+
+// 查询相关
+const query = reactive({
+    name: '',
+});
+const searchOpt = ref<FormOptionList[]>([
+    { type: 'input', label: '用户名:', prop: 'name' }
+])
+const handleSearch = () => {
+    changePage(1);
+};
+
+// 表格相关
+let columns = ref([
+    { type: 'index', label: '序号', width: 55, align: 'center' },
+    { prop: 'name', label: '用户名' },
+    { prop: 'phone', label: '手机号' },
+    { prop: 'role', label: '角色' },
+    { prop: 'operator', label: '操作', width: 250 },
+])
+const page = reactive({
+    index: 1,
+    size: 10,
+    total: 0,
+})
+const tableData = ref<User[]>([]);
+const getData = async () => {
+    const res = await fetchUserData()
+    tableData.value = res.data.list;
+    page.total = res.data.pageTotal;
+};
+getData();
+
+const changePage = (val: number) => {
+    page.index = val;
+    getData();
+};
+
+// 新增/编辑弹窗相关
+let options = ref<FormOption>({
+    labelWidth: '100px',
+    span: 12,
+    list: [
+        { type: 'input', label: '用户名', prop: 'name', required: true },
+        { type: 'input', label: '手机号', prop: 'phone', required: true },
+        { type: 'input', label: '密码', prop: 'password', required: true },
+        { type: 'input', label: '邮箱', prop: 'email', required: true },
+        { type: 'input', label: '角色', prop: 'role', required: true },
+    ]
+})
+const visible = ref(false);
+const isEdit = ref(false);
+const rowData = ref({});
+const handleEdit = (row: User) => {
+    rowData.value = { ...row };
+    isEdit.value = true;
+    visible.value = true;
+};
+const updateData = () => {
+    closeDialog();
+    getData();
+};
+
+const closeDialog = () => {
+    visible.value = false;
+    isEdit.value = false;
+};
+
+// 查看详情弹窗相关
+const visible1 = ref(false);
+const viewData = ref({
+    row: {},
+    list: []
+});
+const handleView = (row: User) => {
+    viewData.value.row = { ...row }
+    viewData.value.list = [
+        {
+            prop: 'id',
+            label: '用户ID',
+        },
+        {
+            prop: 'name',
+            label: '用户名',
+        },
+        {
+            prop: 'password',
+            label: '密码',
+        },
+        {
+            prop: 'email',
+            label: '邮箱',
+        },
+        {
+            prop: 'phone',
+            label: '电话',
+        },
+        {
+            prop: 'role',
+            label: '角色',
+        },
+        {
+            prop: 'date',
+            label: '注册日期',
+        },
+    ]
+    visible1.value = true;
+};
+
+// 删除相关
+const handleDelete = (row: User) => {
+    ElMessage.success('删除成功');
+}
+</script>
+
+<style scoped></style>
\ No newline at end of file
diff --git a/src/views/table.vue b/src/views/table.vue
deleted file mode 100644
index e38c1b6e..00000000
--- a/src/views/table.vue
+++ /dev/null
@@ -1,194 +0,0 @@
-<template>
-	<div>
-		<div class="container">
-			<div class="search-box">
-				<el-input v-model="query.name" placeholder="用户名" class="search-input mr10" clearable></el-input>
-				<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
-				<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
-			</div>
-			<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
-				<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
-				<el-table-column prop="name" label="用户名" align="center"></el-table-column>
-				<el-table-column label="账户余额" align="center">
-					<template #default="scope">¥{{ scope.row.money }}</template>
-				</el-table-column>
-				<el-table-column label="头像(查看大图)" align="center">
-					<template #default="scope">
-						<el-image
-							class="table-td-thumb"
-							:src="scope.row.thumb"
-							:z-index="10"
-							:preview-src-list="[scope.row.thumb]"
-							preview-teleported
-						>
-						</el-image>
-					</template>
-				</el-table-column>
-				<el-table-column prop="address" label="地址" align="center"></el-table-column>
-				<el-table-column label="账户状态" align="center">
-					<template #default="scope">
-						<el-tag :type="scope.row.state ? 'success' : 'danger'">
-							{{ scope.row.state ? '正常' : '异常' }}
-						</el-tag>
-					</template>
-				</el-table-column>
-
-				<el-table-column prop="date" label="注册时间" align="center"></el-table-column>
-				<el-table-column label="操作" width="280" align="center">
-					<template #default="scope">
-						<el-button type="warning" size="small" :icon="View" @click="handleView(scope.row)">
-							查看
-						</el-button>
-						<el-button
-							type="primary"
-							size="small"
-							:icon="Edit"
-							@click="handleEdit(scope.$index, scope.row)"
-							v-permiss="15"
-						>
-							编辑
-						</el-button>
-						<el-button
-							type="danger"
-							size="small"
-							:icon="Delete"
-							@click="handleDelete(scope.$index)"
-							v-permiss="16"
-						>
-							删除
-						</el-button>
-					</template>
-				</el-table-column>
-			</el-table>
-			<div class="pagination">
-				<el-pagination
-					background
-					layout="total, prev, pager, next"
-					:current-page="query.pageIndex"
-					:page-size="query.pageSize"
-					:total="pageTotal"
-					@current-change="handlePageChange"
-				></el-pagination>
-			</div>
-		</div>
-		<el-dialog
-			:title="idEdit ? '编辑用户' : '新增用户'"
-			v-model="visible"
-			width="500px"
-			destroy-on-close
-			:close-on-click-modal="false"
-			@close="closeDialog"
-		>
-			<TableEdit :data="rowData" :edit="idEdit" :update="updateData" />
-		</el-dialog>
-		<el-dialog title="查看用户详情" v-model="visible1" width="700px" destroy-on-close>
-			<TableDetail :data="rowData" />
-		</el-dialog>
-	</div>
-</template>
-
-<script setup lang="ts" name="basetable">
-import { ref, reactive } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { Delete, Edit, Search, CirclePlusFilled, View } from '@element-plus/icons-vue';
-import { fetchData } from '../api/index';
-import TableEdit from '../components/table-edit.vue';
-import TableDetail from '../components/table-detail.vue';
-
-interface TableItem {
-	id: number;
-	name: string;
-	thumb: string;
-	money: number;
-	state: string;
-	date: string;
-	address: string;
-}
-
-const query = reactive({
-	address: '',
-	name: '',
-	pageIndex: 1,
-	pageSize: 10
-});
-const tableData = ref<TableItem[]>([]);
-const pageTotal = ref(0);
-// 获取表格数据
-const getData = async () => {
-	const res = await fetchData();
-	tableData.value = res.data.list;
-	pageTotal.value = res.data.pageTotal || 50;
-};
-getData();
-
-// 查询操作
-const handleSearch = () => {
-	query.pageIndex = 1;
-	getData();
-};
-// 分页导航
-const handlePageChange = (val: number) => {
-	query.pageIndex = val;
-	getData();
-};
-
-// 删除操作
-const handleDelete = (index: number) => {
-	// 二次确认删除
-	ElMessageBox.confirm('确定要删除吗?', '提示', {
-		type: 'warning'
-	})
-		.then(() => {
-			ElMessage.success('删除成功');
-			tableData.value.splice(index, 1);
-		})
-		.catch(() => {});
-};
-
-const visible = ref(false);
-let idx: number = -1;
-const idEdit = ref(false);
-const rowData = ref({});
-const handleEdit = (index: number, row: TableItem) => {
-	idx = index;
-	rowData.value = row;
-	idEdit.value = true;
-	visible.value = true;
-};
-const updateData = (row: TableItem) => {
-	idEdit.value ? (tableData.value[idx] = row) : tableData.value.unshift(row);
-	console.log(tableData.value);
-	closeDialog();
-};
-
-const closeDialog = () => {
-	visible.value = false;
-	idEdit.value = false;
-};
-
-const visible1 = ref(false);
-const handleView = (row: TableItem) => {
-	rowData.value = row;
-	visible1.value = true;
-};
-</script>
-
-<style scoped>
-.search-box {
-	margin-bottom: 20px;
-}
-
-.search-input {
-	width: 200px;
-}
-
-.mr10 {
-	margin-right: 10px;
-}
-.table-td-thumb {
-	display: block;
-	margin: auto;
-	width: 40px;
-	height: 40px;
-}
-</style>
diff --git a/src/views/table/basetable.vue b/src/views/table/basetable.vue
new file mode 100644
index 00000000..198acfd8
--- /dev/null
+++ b/src/views/table/basetable.vue
@@ -0,0 +1,169 @@
+<template>
+	<div>
+		<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
+		<div class="container">
+			<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
+				:delFunc="handleDelete" :editFunc="handleEdit" :refresh="getData" :currentPage="page.index"
+				:changePage="changePage">
+				<template #toolbarBtn>
+					<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
+				</template>
+				<template #money="{ rows }">
+					¥{{ rows.money }}
+				</template>
+				<template #thumb="{ rows }">
+					<el-image class="table-td-thumb" :src="rows.thumb" :z-index="10" :preview-src-list="[rows.thumb]"
+						preview-teleported>
+					</el-image>
+				</template>
+				<template #state="{ rows }">
+					<el-tag :type="rows.state ? 'success' : 'danger'">
+						{{ rows.state ? '正常' : '异常' }}
+					</el-tag>
+				</template>
+			</TableCustom>
+
+		</div>
+		<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
+			:close-on-click-modal="false" @close="closeDialog">
+			<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData">
+				<template #thumb="{ rows }">
+					<img class="table-td-thumb" :src="rows.thumb"></img>
+				</template>
+			</TableEdit>
+		</el-dialog>
+		<el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
+			<TableDetail :data="viewData">
+				<template #thumb="{ rows }">
+					<el-image :src="rows.thumb"></el-image>
+				</template>
+			</TableDetail>
+		</el-dialog>
+	</div>
+</template>
+
+<script setup lang="ts" name="basetable">
+import { ref, reactive } from 'vue';
+import { ElMessage, } from 'element-plus';
+import { CirclePlusFilled } from '@element-plus/icons-vue';
+import { fetchData } from '@/api/index';
+import TableCustom from '@/components/table-custom.vue';
+import TableDetail from '@/components/table-detail.vue';
+import TableSearch from '@/components/table-search.vue';
+import { TableItem } from '@/types/table';
+import { FormOption, FormOptionList } from '@/types/form-option';
+
+// 查询相关
+const query = reactive({
+	name: '',
+});
+const searchOpt = ref<FormOptionList[]>([
+	{ type: 'input', label: '用户名:', prop: 'name' }
+])
+const handleSearch = () => {
+	changePage(1);
+};
+
+// 表格相关
+let columns = ref([
+	{ type: 'selection' },
+	{ type: 'index', label: '序号', width: 55, align: 'center' },
+	{ prop: 'name', label: '用户名' },
+	{ prop: 'money', label: '账户余额' },
+	{ prop: 'thumb', label: '头像' },
+	{ prop: 'state', label: '账户状态' },
+	{ prop: 'operator', label: '操作', width: 250 },
+])
+const page = reactive({
+	index: 1,
+	size: 10,
+	total: 200,
+})
+const tableData = ref<TableItem[]>([]);
+const getData = async () => {
+	const res = await fetchData()
+	tableData.value = res.data.list;
+};
+getData();
+
+const changePage = (val: number) => {
+	page.index = val;
+	getData();
+};
+
+// 新增/编辑弹窗相关
+let options = ref<FormOption>({
+	labelWidth: '100px',
+	span: 24,
+	list: [
+		{ type: 'input', label: '用户名', prop: 'name', required: true },
+		{ type: 'number', label: '账户余额', prop: 'money', required: true },
+		{ type: 'switch', activeText: '正常', inactiveText: '异常', label: '账户状态', prop: 'state', required: true },
+		{ type: 'upload', label: '头像', prop: 'thumb', required: true },
+	]
+})
+const visible = ref(false);
+const isEdit = ref(false);
+const rowData = ref({});
+const handleEdit = (row: TableItem) => {
+	rowData.value = { ...row };
+	isEdit.value = true;
+	visible.value = true;
+};
+const updateData = () => {
+	closeDialog();
+	getData();
+};
+
+const closeDialog = () => {
+	visible.value = false;
+	isEdit.value = false;
+};
+
+// 查看详情弹窗相关
+const visible1 = ref(false);
+const viewData = ref({
+	row: {},
+	list: []
+});
+const handleView = (row: TableItem) => {
+	viewData.value.row = { ...row }
+	viewData.value.list = [
+		{
+			prop: 'id',
+			label: '用户ID',
+		},
+		{
+			prop: 'name',
+			label: '用户名',
+		},
+		{
+			prop: 'money',
+			label: '账户余额',
+		},
+		{
+			prop: 'state',
+			label: '账户状态',
+		},
+		{
+			prop: 'thumb',
+			label: '头像',
+		},
+	]
+	visible1.value = true;
+};
+
+// 删除相关
+const handleDelete = (row: TableItem) => {
+	ElMessage.success('删除成功');
+}
+</script>
+
+<style scoped>
+.table-td-thumb {
+	display: block;
+	margin: auto;
+	width: 40px;
+	height: 40px;
+}
+</style>
diff --git a/src/views/export.vue b/src/views/table/export.vue
similarity index 95%
rename from src/views/export.vue
rename to src/views/table/export.vue
index 21ecf6b2..a2c12898 100644
--- a/src/views/export.vue
+++ b/src/views/table/export.vue
@@ -1,98 +1,98 @@
-<template>
-    <div>
-        <div class="container">
-            <div class="handle-box">
-                <el-button type="primary" @click="exportXlsx">导出Excel</el-button>
-            </div>
-            <el-table :data="tableData" border class="table" header-cell-class-name="table-header">
-                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
-                <el-table-column prop="name" label="姓名"></el-table-column>
-                <el-table-column prop="sno" label="学号"></el-table-column>
-                <el-table-column prop="class" label="班级"></el-table-column>
-                <el-table-column prop="age" label="年龄"></el-table-column>
-                <el-table-column prop="sex" label="性别"></el-table-column>
-            </el-table>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts" name="export">
-import { ref } from 'vue';
-import * as XLSX from 'xlsx';
-
-interface TableItem {
-    id: number;
-    name: string;
-    sno: string;
-    class: string;
-    age: string;
-    sex: string;
-}
-
-const tableData = ref<TableItem[]>([]);
-// 获取表格数据
-const getData = () => {
-    tableData.value = [
-        {
-            id: 1,
-            name: '小明',
-            sno: 'S001',
-            class: '一班',
-            age: '10',
-            sex: '男',
-        },
-        {
-            id: 2,
-            name: '小红',
-            sno: 'S002',
-            class: '一班',
-            age: '9',
-            sex: '女',
-        },
-    ];
-};
-getData();
-
-const list = [['序号', '姓名', '学号', '班级', '年龄', '性别']];
-const exportXlsx = () => {
-    tableData.value.map((item: any, i: number) => {
-        const arr: any[] = [i + 1];
-        arr.push(...[item.name, item.sno, item.class, item.age, item.sex]);
-        list.push(arr);
-    });
-    let WorkSheet = XLSX.utils.aoa_to_sheet(list);
-    let new_workbook = XLSX.utils.book_new();
-    XLSX.utils.book_append_sheet(new_workbook, WorkSheet, '第一页');
-    XLSX.writeFile(new_workbook, `表格.xlsx`);
-};
-</script>
-
-<style scoped>
-.handle-box {
-    margin-bottom: 20px;
-}
-
-.handle-select {
-    width: 120px;
-}
-
-.handle-input {
-    width: 300px;
-}
-.table {
-    width: 100%;
-    font-size: 14px;
-}
-.red {
-    color: #f56c6c;
-}
-.mr10 {
-    margin-right: 10px;
-}
-.table-td-thumb {
-    display: block;
-    margin: auto;
-    width: 40px;
-    height: 40px;
-}
-</style>
+<template>
+    <div>
+        <div class="container">
+            <div class="handle-box">
+                <el-button type="primary" @click="exportXlsx">导出Excel</el-button>
+            </div>
+            <el-table :data="tableData" border class="table" header-cell-class-name="table-header">
+                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
+                <el-table-column prop="name" label="姓名"></el-table-column>
+                <el-table-column prop="sno" label="学号"></el-table-column>
+                <el-table-column prop="class" label="班级"></el-table-column>
+                <el-table-column prop="age" label="年龄"></el-table-column>
+                <el-table-column prop="sex" label="性别"></el-table-column>
+            </el-table>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts" name="export">
+import { ref } from 'vue';
+import * as XLSX from 'xlsx';
+
+interface TableItem {
+    id: number;
+    name: string;
+    sno: string;
+    class: string;
+    age: string;
+    sex: string;
+}
+
+const tableData = ref<TableItem[]>([]);
+// 获取表格数据
+const getData = () => {
+    tableData.value = [
+        {
+            id: 1,
+            name: '小明',
+            sno: 'S001',
+            class: '一班',
+            age: '10',
+            sex: '男',
+        },
+        {
+            id: 2,
+            name: '小红',
+            sno: 'S002',
+            class: '一班',
+            age: '9',
+            sex: '女',
+        },
+    ];
+};
+getData();
+
+const list = [['序号', '姓名', '学号', '班级', '年龄', '性别']];
+const exportXlsx = () => {
+    tableData.value.map((item: any, i: number) => {
+        const arr: any[] = [i + 1];
+        arr.push(...[item.name, item.sno, item.class, item.age, item.sex]);
+        list.push(arr);
+    });
+    let WorkSheet = XLSX.utils.aoa_to_sheet(list);
+    let new_workbook = XLSX.utils.book_new();
+    XLSX.utils.book_append_sheet(new_workbook, WorkSheet, '第一页');
+    XLSX.writeFile(new_workbook, `表格.xlsx`);
+};
+</script>
+
+<style scoped>
+.handle-box {
+    margin-bottom: 20px;
+}
+
+.handle-select {
+    width: 120px;
+}
+
+.handle-input {
+    width: 300px;
+}
+
+.table {
+    width: 100%;
+    font-size: 14px;
+}
+
+.red {
+    color: #f56c6c;
+}
+
+.table-td-thumb {
+    display: block;
+    margin: auto;
+    width: 40px;
+    height: 40px;
+}
+</style>
diff --git a/src/views/import.vue b/src/views/table/import.vue
similarity index 90%
rename from src/views/import.vue
rename to src/views/table/import.vue
index e0ca8c3d..ec65ea5d 100644
--- a/src/views/import.vue
+++ b/src/views/table/import.vue
@@ -1,118 +1,109 @@
-<template>
-    <div>
-        <div class="container">
-            <div class="handle-box">
-                <el-upload
-                    action="#"
-                    :limit="1"
-                    accept=".xlsx, .xls"
-                    :show-file-list="false"
-                    :before-upload="beforeUpload"
-                    :http-request="handleMany"
-                >
-                    <el-button class="mr10" type="success">批量导入</el-button>
-                </el-upload>
-                <el-link href="/template.xlsx" target="_blank">下载模板</el-link>
-            </div>
-            <el-table :data="tableData" border class="table" header-cell-class-name="table-header">
-                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
-                <el-table-column prop="name" label="姓名"></el-table-column>
-                <el-table-column prop="sno" label="学号"></el-table-column>
-                <el-table-column prop="class" label="班级"></el-table-column>
-                <el-table-column prop="age" label="年龄"></el-table-column>
-                <el-table-column prop="sex" label="性别"></el-table-column>
-            </el-table>
-        </div>
-    </div>
-</template>
-
-<script setup lang="ts" name="import">
-import { UploadProps } from 'element-plus';
-import { ref, reactive } from 'vue';
-import * as XLSX from 'xlsx';
-
-interface TableItem {
-    id: number;
-    name: string;
-    sno: string;
-    class: string;
-    age: string;
-    sex: string;
-}
-
-const tableData = ref<TableItem[]>([]);
-// 获取表格数据
-const getData = () => {
-    tableData.value = [
-        {
-            id: 1,
-            name: '小明',
-            sno: 'S001',
-            class: '一班',
-            age: '10',
-            sex: '男',
-        },
-        {
-            id: 2,
-            name: '小红',
-            sno: 'S002',
-            class: '一班',
-            age: '9',
-            sex: '女',
-        },
-    ];
-};
-getData();
-
-const importList = ref<any>([]);
-const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
-    importList.value = await analysisExcel(rawFile);
-    return true;
-};
-const analysisExcel = (file: any) => {
-    return new Promise(function (resolve, reject) {
-        const reader = new FileReader();
-        reader.onload = function (e: any) {
-            const data = e.target.result;
-            let datajson = XLSX.read(data, {
-                type: 'binary',
-            });
-
-            const sheetName = datajson.SheetNames[0];
-            const result = XLSX.utils.sheet_to_json(datajson.Sheets[sheetName]);
-            resolve(result);
-        };
-        reader.readAsBinaryString(file);
-    });
-};
-
-const handleMany = async () => {
-    // 把数据传给服务器后获取最新列表,这里只是示例,不做请求
-    const list = importList.value.map((item: any, index: number) => {
-        return {
-            id: index,
-            name: item['姓名'],
-            sno: item['学号'],
-            class: item['班级'],
-            age: item['年龄'],
-            sex: item['性别'],
-        };
-    });
-    tableData.value.push(...list);
-};
-</script>
-
-<style scoped>
-.handle-box {
-    display: flex;
-    margin-bottom: 20px;
-}
-
-.table {
-    width: 100%;
-    font-size: 14px;
-}
-.mr10 {
-    margin-right: 10px;
-}
-</style>
+<template>
+    <div>
+        <div class="container">
+            <div class="handle-box">
+                <el-upload action="#" :limit="1" accept=".xlsx, .xls" :show-file-list="false"
+                    :before-upload="beforeUpload" :http-request="handleMany">
+                    <el-button class="mr10" type="success">批量导入</el-button>
+                </el-upload>
+                <el-link href="/template.xlsx" target="_blank">下载模板</el-link>
+            </div>
+            <el-table :data="tableData" border class="table" header-cell-class-name="table-header">
+                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
+                <el-table-column prop="name" label="姓名"></el-table-column>
+                <el-table-column prop="sno" label="学号"></el-table-column>
+                <el-table-column prop="class" label="班级"></el-table-column>
+                <el-table-column prop="age" label="年龄"></el-table-column>
+                <el-table-column prop="sex" label="性别"></el-table-column>
+            </el-table>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts" name="import">
+import { UploadProps } from 'element-plus';
+import { ref, reactive } from 'vue';
+import * as XLSX from 'xlsx';
+
+interface TableItem {
+    id: number;
+    name: string;
+    sno: string;
+    class: string;
+    age: string;
+    sex: string;
+}
+
+const tableData = ref<TableItem[]>([]);
+// 获取表格数据
+const getData = () => {
+    tableData.value = [
+        {
+            id: 1,
+            name: '小明',
+            sno: 'S001',
+            class: '一班',
+            age: '10',
+            sex: '男',
+        },
+        {
+            id: 2,
+            name: '小红',
+            sno: 'S002',
+            class: '一班',
+            age: '9',
+            sex: '女',
+        },
+    ];
+};
+getData();
+
+const importList = ref<any>([]);
+const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
+    importList.value = await analysisExcel(rawFile);
+    return true;
+};
+const analysisExcel = (file: any) => {
+    return new Promise(function (resolve, reject) {
+        const reader = new FileReader();
+        reader.onload = function (e: any) {
+            const data = e.target.result;
+            let datajson = XLSX.read(data, {
+                type: 'binary',
+            });
+
+            const sheetName = datajson.SheetNames[0];
+            const result = XLSX.utils.sheet_to_json(datajson.Sheets[sheetName]);
+            resolve(result);
+        };
+        reader.readAsBinaryString(file);
+    });
+};
+
+const handleMany = async () => {
+    // 把数据传给服务器后获取最新列表,这里只是示例,不做请求
+    const list = importList.value.map((item: any, index: number) => {
+        return {
+            id: index,
+            name: item['姓名'],
+            sno: item['学号'],
+            class: item['班级'],
+            age: item['年龄'],
+            sex: item['性别'],
+        };
+    });
+    tableData.value.push(...list);
+};
+</script>
+
+<style scoped>
+.handle-box {
+    display: flex;
+    margin-bottom: 20px;
+}
+
+.table {
+    width: 100%;
+    font-size: 14px;
+}
+</style>
diff --git a/src/views/table/table-editor.vue b/src/views/table/table-editor.vue
new file mode 100644
index 00000000..61bb6f77
--- /dev/null
+++ b/src/views/table/table-editor.vue
@@ -0,0 +1,79 @@
+<template>
+	<div class="container">
+		<TableCustom :columns="columns" :tableData="tableData" :hasToolbar="false" :hasPagination="false">
+			<template #name="{ rows }">
+				<el-input v-if="rows.editing" v-model="rows.name"></el-input>
+				<span v-else>{{ rows.name }}</span>
+			</template>
+			<template #password="{ rows }">
+				<el-input v-if="rows.editing" v-model="rows.password"></el-input>
+				<span v-else>{{ rows.password }}</span>
+			</template>
+			<template #email="{ rows }">
+				<el-input v-if="rows.editing" v-model="rows.email"></el-input>
+				<span v-else>{{ rows.email }}</span>
+			</template>
+			<template #role="{ rows }">
+				<el-select v-if="rows.editing" v-model="rows.role">
+					<el-option label="管理员" value="管理员"></el-option>
+					<el-option label="普通用户" value="普通用户"></el-option>
+				</el-select>
+				<span v-else>{{ rows.role }}</span>
+			</template>
+			<template #operator="{ rows, index }">
+				<template v-if="!rows.editing">
+					<el-button type="primary" size="small" :icon="Edit" @click="handleEdit(rows)">
+						编辑
+					</el-button>
+					<el-button type="danger" size="small" :icon="Delete" @click="">
+						删除
+					</el-button>
+				</template>
+				<template v-else>
+					<el-button type="success" size="small" :icon="Select" @click="rows.editing = false">
+						保存
+					</el-button>
+					<el-button type="default" size="small" :icon="CloseBold" @click="handleCancel(rows, index)">
+						取消
+					</el-button>
+				</template>
+			</template>
+		</TableCustom>
+	</div>
+</template>
+
+<script setup lang="ts" name="table-editor">
+import { ref } from 'vue';
+import { Delete, Edit, CloseBold, Select } from '@element-plus/icons-vue';
+import TableCustom from '@/components/table-custom.vue';
+import { fetchUserData } from '@/api/index';
+
+let columns = ref([
+	{ type: 'index', label: '序号', width: 55, align: 'center' },
+	{ prop: 'name', label: '用户名' },
+	{ prop: 'password', label: '密码' },
+	{ prop: 'email', label: '邮箱' },
+	{ prop: 'role', label: '角色' },
+	{ prop: 'operator', label: '操作', width: 180 },
+])
+const tableData = ref([]);
+const getData = async () => {
+	const res = await fetchUserData();
+	tableData.value = res.data.list;
+};
+getData();
+
+const rowData = ref({})
+
+const handleEdit = (row) => {
+	rowData.value = { ...row };
+	row.editing = true;
+};
+
+const handleCancel = (row, index) => {
+	row.editing = false;
+	tableData.value[index] = { ...rowData.value };
+};
+</script>
+
+<style scoped></style>
diff --git a/src/views/tabs.vue b/src/views/tabs.vue
deleted file mode 100644
index 55b06435..00000000
--- a/src/views/tabs.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-<template>
-	<div class="container">
-		<el-tabs v-model="message">
-			<el-tab-pane :label="`未读消息(${state.unread.length})`" name="first">
-				<el-table :data="state.unread" :show-header="false" style="width: 100%">
-					<el-table-column>
-						<template #default="scope">
-							<span class="message-title">{{ scope.row.title }}</span>
-						</template>
-					</el-table-column>
-					<el-table-column prop="date" width="180"></el-table-column>
-					<el-table-column width="120">
-						<template #default="scope">
-							<el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
-						</template>
-					</el-table-column>
-				</el-table>
-				<div class="handle-row">
-					<el-button type="primary">全部标为已读</el-button>
-				</div>
-			</el-tab-pane>
-			<el-tab-pane :label="`已读消息(${state.read.length})`" name="second">
-				<template v-if="message === 'second'">
-					<el-table :data="state.read" :show-header="false" style="width: 100%">
-						<el-table-column>
-							<template #default="scope">
-								<span class="message-title">{{ scope.row.title }}</span>
-							</template>
-						</el-table-column>
-						<el-table-column prop="date" width="180"></el-table-column>
-						<el-table-column width="120">
-							<template #default="scope">
-								<el-button type="danger" size="small" @click="handleDel(scope.$index)">删除</el-button>
-							</template>
-						</el-table-column>
-					</el-table>
-					<div class="handle-row">
-						<el-button type="danger">删除全部</el-button>
-					</div>
-				</template>
-			</el-tab-pane>
-			<el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
-				<template v-if="message === 'third'">
-					<el-table :data="state.recycle" :show-header="false" style="width: 100%">
-						<el-table-column>
-							<template #default="scope">
-								<span class="message-title">{{ scope.row.title }}</span>
-							</template>
-						</el-table-column>
-						<el-table-column prop="date" width="180"></el-table-column>
-						<el-table-column width="120">
-							<template #default="scope">
-								<el-button size="small" @click="handleRestore(scope.$index)">还原</el-button>
-							</template>
-						</el-table-column>
-					</el-table>
-					<div class="handle-row">
-						<el-button type="danger">清空回收站</el-button>
-					</div>
-				</template>
-			</el-tab-pane>
-		</el-tabs>
-	</div>
-</template>
-
-<script setup lang="ts" name="tabs">
-import { ref, reactive } from 'vue';
-
-const message = ref('first');
-const state = reactive({
-	unread: [
-		{
-			date: '2018-04-19 20:00:00',
-			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
-		},
-		{
-			date: '2018-04-19 21:00:00',
-			title: '今晚12点整发大红包,先到先得'
-		}
-	],
-	read: [
-		{
-			date: '2018-04-19 20:00:00',
-			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
-		}
-	],
-	recycle: [
-		{
-			date: '2018-04-19 20:00:00',
-			title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
-		}
-	]
-});
-
-const handleRead = (index: number) => {
-	const item = state.unread.splice(index, 1);
-	state.read = item.concat(state.read);
-};
-const handleDel = (index: number) => {
-	const item = state.read.splice(index, 1);
-	state.recycle = item.concat(state.recycle);
-};
-const handleRestore = (index: number) => {
-	const item = state.recycle.splice(index, 1);
-	state.read = item.concat(state.read);
-};
-</script>
-
-<style>
-.message-title {
-	cursor: pointer;
-}
-.handle-row {
-	margin-top: 30px;
-}
-</style>
diff --git a/src/views/user.vue b/src/views/user.vue
deleted file mode 100644
index c0728dab..00000000
--- a/src/views/user.vue
+++ /dev/null
@@ -1,174 +0,0 @@
-<template>
-	<div>
-		<el-row :gutter="20">
-			<el-col :span="12">
-				<el-card shadow="hover">
-					<template #header>
-						<div class="clearfix">
-							<span>基础信息</span>
-						</div>
-					</template>
-					<div class="info">
-						<div class="info-image" @click="showDialog">
-							<el-avatar :size="100" :src="avatarImg" />
-							<span class="info-edit">
-								<i class="el-icon-lx-camerafill"></i>
-							</span>
-						</div>
-						<div class="info-name">{{ name }}</div>
-						<div class="info-desc">不可能!我的代码怎么可能会有bug!</div>
-					</div>
-				</el-card>
-			</el-col>
-			<el-col :span="12">
-				<el-card shadow="hover">
-					<template #header>
-						<div class="clearfix">
-							<span>账户编辑</span>
-						</div>
-					</template>
-					<el-form label-width="90px">
-						<el-form-item label="用户名:"> {{ name }} </el-form-item>
-						<el-form-item label="旧密码:">
-							<el-input type="password" v-model="form.old"></el-input>
-						</el-form-item>
-						<el-form-item label="新密码:">
-							<el-input type="password" v-model="form.new"></el-input>
-						</el-form-item>
-						<el-form-item label="个人简介:">
-							<el-input v-model="form.desc"></el-input>
-						</el-form-item>
-						<el-form-item>
-							<el-button type="primary" @click="onSubmit">保存</el-button>
-						</el-form-item>
-					</el-form>
-				</el-card>
-			</el-col>
-		</el-row>
-		<el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
-			<vue-cropper
-				ref="cropper"
-				:src="imgSrc"
-				:ready="cropImage"
-				:zoom="cropImage"
-				:cropmove="cropImage"
-				style="width: 100%; height: 400px"
-			></vue-cropper>
-
-			<template #footer>
-				<span class="dialog-footer">
-					<el-button class="crop-demo-btn" type="primary"
-						>选择图片
-						<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
-					</el-button>
-					<el-button type="primary" @click="saveAvatar">上传并保存</el-button>
-				</span>
-			</template>
-		</el-dialog>
-	</div>
-</template>
-
-<script setup lang="ts" name="user">
-import { reactive, ref } from 'vue';
-import VueCropper from 'vue-cropperjs';
-import 'cropperjs/dist/cropper.css';
-import avatar from '../assets/img/img.jpg';
-
-const name = localStorage.getItem('ms_username');
-const form = reactive({
-	old: '',
-	new: '',
-	desc: '不可能!我的代码怎么可能会有bug!'
-});
-const onSubmit = () => {};
-
-const avatarImg = ref(avatar);
-const imgSrc = ref('');
-const cropImg = ref('');
-const dialogVisible = ref(false);
-const cropper: any = ref();
-
-const showDialog = () => {
-	dialogVisible.value = true;
-	imgSrc.value = avatarImg.value;
-};
-
-const setImage = (e: any) => {
-	const file = e.target.files[0];
-	if (!file.type.includes('image/')) {
-		return;
-	}
-	const reader = new FileReader();
-	reader.onload = (event: any) => {
-		dialogVisible.value = true;
-		imgSrc.value = event.target.result;
-		cropper.value && cropper.value.replace(event.target.result);
-	};
-	reader.readAsDataURL(file);
-};
-
-const cropImage = () => {
-	cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
-};
-
-const saveAvatar = () => {
-	avatarImg.value = cropImg.value;
-	dialogVisible.value = false;
-};
-</script>
-
-<style scoped>
-.info {
-	text-align: center;
-	padding: 35px 0;
-}
-.info-image {
-	position: relative;
-	margin: auto;
-	width: 100px;
-	height: 100px;
-	background: #f8f8f8;
-	border: 1px solid #eee;
-	border-radius: 50px;
-	overflow: hidden;
-}
-
-.info-edit {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	position: absolute;
-	left: 0;
-	top: 0;
-	width: 100%;
-	height: 100%;
-	background: rgba(0, 0, 0, 0.5);
-	opacity: 0;
-	transition: opacity 0.3s ease;
-}
-.info-edit i {
-	color: #eee;
-	font-size: 25px;
-}
-.info-image:hover .info-edit {
-	opacity: 1;
-}
-.info-name {
-	margin: 15px 0 10px;
-	font-size: 24px;
-	font-weight: 500;
-	color: #262626;
-}
-.crop-demo-btn {
-	position: relative;
-}
-.crop-input {
-	position: absolute;
-	width: 100px;
-	height: 40px;
-	left: 0;
-	top: 0;
-	opacity: 0;
-	cursor: pointer;
-}
-</style>
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
index ff773960..56d7ddcb 100644
--- a/src/vite-env.d.ts
+++ b/src/vite-env.d.ts
@@ -1,10 +1,10 @@
-/// <reference types="vite/client" />
-
-declare module '*.vue' {
-  import type { DefineComponent } from 'vue'
-  const component: DefineComponent<{}, {}, any>
-  export default component
-}
-
-declare module 'vue-schart';
-declare module 'vue-cropperjs';
\ No newline at end of file
+/// <reference types="vite/client" />
+
+declare module '*.vue' {
+  import type { DefineComponent } from 'vue'
+  const component: DefineComponent<{}, {}, any>
+  export default component
+}
+
+declare module 'vue-schart';
+declare module 'nprogress'
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index cc6bbf2d..6949ea69 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,18 +1,22 @@
-{
-  "compilerOptions": {
-    "target": "ESNext",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "moduleResolution": "Node",
-    "strict": false,
-    "jsx": "preserve",
-    "sourceMap": true,
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-    "esModuleInterop": true,
-    "lib": ["ESNext", "DOM"],
-    "skipLibCheck": true
-  },
-  "include": ["src/**/*.ts", "src/**/*.d.ts","src/**/*.vue"],
-  "references": [{ "path": "./tsconfig.node.json" }]
-}
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "strict": false,
+    "jsx": "preserve",
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "esModuleInterop": true,
+    "lib": ["ESNext", "DOM"],
+    "skipLibCheck": true,
+    "baseUrl": "./",
+    "paths": {
+      "@/*": ["src/*"]
+    }
+  },
+  "include": ["src/**/*.ts", "src/**/*.d.ts","src/**/*.vue"],
+  "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index 9d31e2ae..1f4ac32f 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -1,9 +1,9 @@
-{
-  "compilerOptions": {
-    "composite": true,
-    "module": "ESNext",
-    "moduleResolution": "Node",
-    "allowSyntheticDefaultImports": true
-  },
-  "include": ["vite.config.ts"]
-}
+{
+  "compilerOptions": {
+    "composite": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/vite.config.ts b/vite.config.ts
index 30ed7089..2875fc54 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,22 +1,31 @@
-import { defineConfig } from 'vite';
-import vue from '@vitejs/plugin-vue';
-import VueSetupExtend from 'vite-plugin-vue-setup-extend';
-import AutoImport from 'unplugin-auto-import/vite';
-import Components from 'unplugin-vue-components/vite';
-import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
-export default defineConfig({
-	base: './',
-	plugins: [
-		vue(),
-		VueSetupExtend(),
-		AutoImport({
-			resolvers: [ElementPlusResolver()]
-		}),
-		Components({
-			resolvers: [ElementPlusResolver()]
-		})
-	],
-	optimizeDeps: {
-		include: ['schart.js']
-	}
-});
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import VueSetupExtend from 'vite-plugin-vue-setup-extend';
+import AutoImport from 'unplugin-auto-import/vite';
+import Components from 'unplugin-vue-components/vite';
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
+export default defineConfig({
+	base: './',
+	plugins: [
+		vue(),
+		VueSetupExtend(),
+		AutoImport({
+			resolvers: [ElementPlusResolver()]
+		}),
+		Components({
+			resolvers: [ElementPlusResolver()]
+		})
+	],
+	optimizeDeps: {
+		include: ['schart.js']
+	},
+	resolve: {
+		alias: {
+			'@': '/src',
+			'~': '/src/assets'
+		}
+	},
+	define: {
+		__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "true",
+	},
+});
diff --git a/yarn.lock b/yarn.lock
index 6b3abe9e..2f954cd5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3,72 +3,70 @@
 
 
 "@antfu/utils@^0.7.0", "@antfu/utils@^0.7.2":
-  version "0.7.2"
-  resolved "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.2.tgz#3bb6f37a6b188056fe9e2f363b6aa735ed65d7ca"
-  integrity sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==
+  version "0.7.7"
+  resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.7.tgz#26ea493a831b4f3a85475e7157be02fb4eab51fb"
+  integrity sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==
 
-"@babel/parser@^7.16.4":
-  version "7.21.2"
-  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
-  integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==
-
-"@babel/parser@^7.23.6":
-  version "7.23.6"
-  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b"
-  integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==
+"@babel/parser@^7.23.9":
+  version "7.24.4"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88"
+  integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==
 
 "@babel/runtime@^7.12.0":
-  version "7.21.0"
-  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
-  integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
+  version "7.24.4"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd"
+  integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==
   dependencies:
-    regenerator-runtime "^0.13.11"
+    regenerator-runtime "^0.14.0"
 
 "@ctrl/tinycolor@^3.4.1":
-  version "3.6.0"
-  resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.0.tgz#53fa5fe9c34faee89469e48f91d51a3766108bc8"
-  integrity sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31"
+  integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
 
 "@element-plus/icons-vue@*", "@element-plus/icons-vue@^2.3.1":
   version "2.3.1"
-  resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
+  resolved "https://registry.yarnpkg.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
   integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
 
 "@esbuild/android-arm@0.15.18":
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz#266d40b8fdcf87962df8af05b76219bc786b4f80"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.18.tgz#266d40b8fdcf87962df8af05b76219bc786b4f80"
   integrity sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==
 
 "@esbuild/linux-loong64@0.15.18":
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz#128b76ecb9be48b60cf5cfc1c63a4f00691a3239"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz#128b76ecb9be48b60cf5cfc1c63a4f00691a3239"
   integrity sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==
 
-"@floating-ui/core@^1.2.1":
-  version "1.2.1"
-  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.2.1.tgz#074182a1d277f94569c50a6b456e62585d463c8e"
-  integrity sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg==
+"@floating-ui/core@^1.0.0":
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1"
+  integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==
+  dependencies:
+    "@floating-ui/utils" "^0.2.1"
 
 "@floating-ui/dom@^1.0.1":
-  version "1.2.1"
-  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.2.1.tgz#8f93906e1a3b9f606ce78afb058e874344dcbe07"
-  integrity sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef"
+  integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==
   dependencies:
-    "@floating-ui/core" "^1.2.1"
+    "@floating-ui/core" "^1.0.0"
+    "@floating-ui/utils" "^0.2.0"
 
-"@jridgewell/sourcemap-codec@^1.4.13":
-  version "1.4.14"
-  resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
-  integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1":
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
+  integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
 
-"@jridgewell/sourcemap-codec@^1.4.15":
+"@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.15":
   version "1.4.15"
-  resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
   integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
 
 "@nodelib/fs.scandir@2.1.5":
   version "2.1.5"
-  resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
   integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
   dependencies:
     "@nodelib/fs.stat" "2.0.5"
@@ -76,12 +74,12 @@
 
 "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
   version "2.0.5"
-  resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
   integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
 
 "@nodelib/fs.walk@^1.2.3":
   version "1.2.8"
-  resolved "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
   integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
   dependencies:
     "@nodelib/fs.scandir" "2.1.5"
@@ -89,13 +87,13 @@
 
 "@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
   version "2.11.7"
-  resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
+  resolved "https://registry.yarnpkg.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
   integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
 
 "@rollup/pluginutils@^5.0.2":
-  version "5.0.2"
-  resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
-  integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0"
+  integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==
   dependencies:
     "@types/estree" "^1.0.0"
     estree-walker "^2.0.2"
@@ -103,39 +101,39 @@
 
 "@transloadit/prettier-bytes@0.0.7":
   version "0.0.7"
-  resolved "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b"
+  resolved "https://registry.yarnpkg.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz#cdb5399f445fdd606ed833872fa0cabdbc51686b"
   integrity sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==
 
 "@types/estree@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
-  integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+  integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
 
 "@types/event-emitter@^0.3.3":
-  version "0.3.3"
-  resolved "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.3.tgz#727032a9fc67565f96bbd78b2e2809275c97d7e7"
-  integrity sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q==
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/@types/event-emitter/-/event-emitter-0.3.5.tgz#ce9b513f72c50dcf0443a12165a93a79ba7a7092"
+  integrity sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==
 
 "@types/lodash-es@^4.17.6":
-  version "4.17.6"
-  resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.6.tgz#c2ed4c8320ffa6f11b43eb89e9eaeec65966a0a0"
-  integrity sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==
+  version "4.17.12"
+  resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b"
+  integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
   dependencies:
     "@types/lodash" "*"
 
 "@types/lodash@*", "@types/lodash@^4.14.182":
-  version "4.14.191"
-  resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
-  integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==
+  version "4.17.0"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.0.tgz#d774355e41f372d5350a4d0714abb48194a489c3"
+  integrity sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==
 
 "@types/web-bluetooth@^0.0.16":
   version "0.0.16"
-  resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
+  resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
   integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
 
 "@uppy/companion-client@^2.2.2":
   version "2.2.2"
-  resolved "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz#c70b42fdcca728ef88b3eebf7ee3e2fa04b4923b"
+  resolved "https://registry.yarnpkg.com/@uppy/companion-client/-/companion-client-2.2.2.tgz#c70b42fdcca728ef88b3eebf7ee3e2fa04b4923b"
   integrity sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==
   dependencies:
     "@uppy/utils" "^4.1.2"
@@ -143,7 +141,7 @@
 
 "@uppy/core@^2.1.1":
   version "2.3.4"
-  resolved "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz#260b85b6bf3aa03cdc67da231f8c69cfbfdcc84a"
+  resolved "https://registry.yarnpkg.com/@uppy/core/-/core-2.3.4.tgz#260b85b6bf3aa03cdc67da231f8c69cfbfdcc84a"
   integrity sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==
   dependencies:
     "@transloadit/prettier-bytes" "0.0.7"
@@ -157,19 +155,19 @@
 
 "@uppy/store-default@^2.1.1":
   version "2.1.1"
-  resolved "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz#62a656a099bdaa012306e054d093754cb2d36e3e"
+  resolved "https://registry.yarnpkg.com/@uppy/store-default/-/store-default-2.1.1.tgz#62a656a099bdaa012306e054d093754cb2d36e3e"
   integrity sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==
 
 "@uppy/utils@^4.1.2", "@uppy/utils@^4.1.3":
   version "4.1.3"
-  resolved "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz#9d0be6ece4df25f228d30ef40be0f14208258ce3"
+  resolved "https://registry.yarnpkg.com/@uppy/utils/-/utils-4.1.3.tgz#9d0be6ece4df25f228d30ef40be0f14208258ce3"
   integrity sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==
   dependencies:
     lodash.throttle "^4.1.1"
 
 "@uppy/xhr-upload@^2.0.3":
   version "2.1.3"
-  resolved "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz#0d4e355332fe0c6eb372d7731315e04d02aeeb18"
+  resolved "https://registry.yarnpkg.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz#0d4e355332fe0c6eb372d7731315e04d02aeeb18"
   integrity sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==
   dependencies:
     "@uppy/companion-client" "^2.2.2"
@@ -178,24 +176,24 @@
 
 "@vitejs/plugin-vue@^3.0.0":
   version "3.2.0"
-  resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz#a1484089dd85d6528f435743f84cdd0d215bbb54"
+  resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.2.0.tgz#a1484089dd85d6528f435743f84cdd0d215bbb54"
   integrity sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==
 
 "@volar/code-gen@0.38.9":
   version "0.38.9"
-  resolved "https://registry.npmmirror.com/@volar/code-gen/-/code-gen-0.38.9.tgz#8fed2c6a472c8f11ce695b08789bcc22b08e7fa6"
+  resolved "https://registry.yarnpkg.com/@volar/code-gen/-/code-gen-0.38.9.tgz#8fed2c6a472c8f11ce695b08789bcc22b08e7fa6"
   integrity sha512-n6LClucfA+37rQeskvh9vDoZV1VvCVNy++MAPKj2dT4FT+Fbmty/SDQqnsEBtdEe6E3OQctFvA/IcKsx3Mns0A==
   dependencies:
     "@volar/source-map" "0.38.9"
 
 "@volar/source-map@0.38.9":
   version "0.38.9"
-  resolved "https://registry.npmmirror.com/@volar/source-map/-/source-map-0.38.9.tgz#935d6def4b4342e8e2d63cd8e6bf9bf1155c58d8"
+  resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-0.38.9.tgz#935d6def4b4342e8e2d63cd8e6bf9bf1155c58d8"
   integrity sha512-ba0UFoHDYry+vwKdgkWJ6xlQT+8TFtZg1zj9tSjj4PykW1JZDuM0xplMotLun4h3YOoYfY9K1huY5gvxmrNLIw==
 
 "@volar/vue-code-gen@0.38.9":
   version "0.38.9"
-  resolved "https://registry.npmmirror.com/@volar/vue-code-gen/-/vue-code-gen-0.38.9.tgz#878f00fec82a2fc300396d70e26b0ea29952f740"
+  resolved "https://registry.yarnpkg.com/@volar/vue-code-gen/-/vue-code-gen-0.38.9.tgz#878f00fec82a2fc300396d70e26b0ea29952f740"
   integrity sha512-tzj7AoarFBKl7e41MR006ncrEmNPHALuk8aG4WdDIaG387X5//5KhWC5Ff3ZfB2InGSeNT+CVUd74M0gS20rjA==
   dependencies:
     "@volar/code-gen" "0.38.9"
@@ -206,7 +204,7 @@
 
 "@volar/vue-typescript@0.38.9":
   version "0.38.9"
-  resolved "https://registry.npmmirror.com/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz#e5dfdc6f0d6dbea683647cd477fafbd483983b35"
+  resolved "https://registry.yarnpkg.com/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz#e5dfdc6f0d6dbea683647cd477fafbd483983b35"
   integrity sha512-iJMQGU91ADi98u8V1vXd2UBmELDAaeSP0ZJaFjwosClQdKlJQYc6MlxxKfXBZisHqfbhdtrGRyaryulnYtliZw==
   dependencies:
     "@volar/code-gen" "0.38.9"
@@ -215,158 +213,93 @@
     "@vue/compiler-sfc" "^3.2.37"
     "@vue/reactivity" "^3.2.37"
 
-"@vue/compiler-core@3.2.47", "@vue/compiler-core@^3.2.37":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
-  integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
+"@vue/compiler-core@3.4.21", "@vue/compiler-core@^3.2.37":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.21.tgz#868b7085378fc24e58c9aed14c8d62110a62be1a"
+  integrity sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==
   dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/shared" "3.2.47"
-    estree-walker "^2.0.2"
-    source-map "^0.6.1"
-
-"@vue/compiler-core@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.4.5.tgz#9565aebaadef8649eb7c8e150a5f4f4e2542667d"
-  integrity sha512-Daka7P1z2AgKjzuueWXhwzIsKu0NkLB6vGbNVEV2iJ8GJTrzraZo/Sk4GWCMRtd/qVi3zwnk+Owbd/xSZbwHtQ==
-  dependencies:
-    "@babel/parser" "^7.23.6"
-    "@vue/shared" "3.4.5"
+    "@babel/parser" "^7.23.9"
+    "@vue/shared" "3.4.21"
     entities "^4.5.0"
     estree-walker "^2.0.2"
     source-map-js "^1.0.2"
 
-"@vue/compiler-dom@3.2.47", "@vue/compiler-dom@^3.2.37":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
-  integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
-  dependencies:
-    "@vue/compiler-core" "3.2.47"
-    "@vue/shared" "3.2.47"
-
-"@vue/compiler-dom@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.4.5.tgz#c53c9d7715b777b1d6d2adcbc491bfd4f9510edd"
-  integrity sha512-J8YlxknJVd90SXFJ4HwGANSAXsx5I0lK30sO/zvYV7s5gXf7gZR7r/1BmZ2ju7RGH1lnc6bpBc6nL61yW+PsAQ==
+"@vue/compiler-dom@3.4.21", "@vue/compiler-dom@^3.2.37":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz#0077c355e2008207283a5a87d510330d22546803"
+  integrity sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==
   dependencies:
-    "@vue/compiler-core" "3.4.5"
-    "@vue/shared" "3.4.5"
+    "@vue/compiler-core" "3.4.21"
+    "@vue/shared" "3.4.21"
 
-"@vue/compiler-sfc@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.4.5.tgz#f93f986dfc5c7f72b9a5e00b48be75d9116cc948"
-  integrity sha512-jauvkDuSSUbP0ebhfNqljhShA90YEfX/0wZ+w40oZF43IjGyWYjqYaJbvMJwGOd+9+vODW6eSvnk28f0SGV7OQ==
+"@vue/compiler-sfc@3.4.21", "@vue/compiler-sfc@^3.1.2", "@vue/compiler-sfc@^3.2.29", "@vue/compiler-sfc@^3.2.37":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz#4af920dc31ab99e1ff5d152b5fe0ad12181145b2"
+  integrity sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==
   dependencies:
-    "@babel/parser" "^7.23.6"
-    "@vue/compiler-core" "3.4.5"
-    "@vue/compiler-dom" "3.4.5"
-    "@vue/compiler-ssr" "3.4.5"
-    "@vue/shared" "3.4.5"
+    "@babel/parser" "^7.23.9"
+    "@vue/compiler-core" "3.4.21"
+    "@vue/compiler-dom" "3.4.21"
+    "@vue/compiler-ssr" "3.4.21"
+    "@vue/shared" "3.4.21"
     estree-walker "^2.0.2"
-    magic-string "^0.30.5"
-    postcss "^8.4.32"
+    magic-string "^0.30.7"
+    postcss "^8.4.35"
     source-map-js "^1.0.2"
 
-"@vue/compiler-sfc@^3.1.2", "@vue/compiler-sfc@^3.2.29", "@vue/compiler-sfc@^3.2.37":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
-  integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.47"
-    "@vue/compiler-dom" "3.2.47"
-    "@vue/compiler-ssr" "3.2.47"
-    "@vue/reactivity-transform" "3.2.47"
-    "@vue/shared" "3.2.47"
-    estree-walker "^2.0.2"
-    magic-string "^0.25.7"
-    postcss "^8.1.10"
-    source-map "^0.6.1"
-
-"@vue/compiler-ssr@3.2.47":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
-  integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
-  dependencies:
-    "@vue/compiler-dom" "3.2.47"
-    "@vue/shared" "3.2.47"
-
-"@vue/compiler-ssr@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.4.5.tgz#d412a4c9b10d69172a5ce0ec78de98dad441a58d"
-  integrity sha512-DDdEcDzj2lWTMfUMMtEpLDhURai9LhM0zSZ219jCt7b2Vyl0/jy3keFgCPMitG0V1S1YG4Cmws3lWHWdxHQOpg==
-  dependencies:
-    "@vue/compiler-dom" "3.4.5"
-    "@vue/shared" "3.4.5"
-
-"@vue/devtools-api@^6.5.0":
-  version "6.5.0"
-  resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
-  integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
-
-"@vue/reactivity-transform@3.2.47":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
-  integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.47"
-    "@vue/shared" "3.2.47"
-    estree-walker "^2.0.2"
-    magic-string "^0.25.7"
-
-"@vue/reactivity@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.4.5.tgz#68bc91cd356eed95dc5e9e0570e3f7becaee578b"
-  integrity sha512-BcWkKvjdvqJwb7BhhFkXPLDCecX4d4a6GATvCduJQDLv21PkPowAE5GKuIE5p6RC07/Lp9FMkkq4AYCTVF5KlQ==
+"@vue/compiler-ssr@3.4.21":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz#b84ae64fb9c265df21fc67f7624587673d324fef"
+  integrity sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==
   dependencies:
-    "@vue/shared" "3.4.5"
+    "@vue/compiler-dom" "3.4.21"
+    "@vue/shared" "3.4.21"
+
+"@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.5.1":
+  version "6.6.1"
+  resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.1.tgz#7c14346383751d9f6ad4bea0963245b30220ef83"
+  integrity sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==
 
-"@vue/reactivity@^3.2.37":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.47.tgz#1d6399074eadfc3ed35c727e2fd707d6881140b6"
-  integrity sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==
+"@vue/reactivity@3.4.21", "@vue/reactivity@^3.2.37":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.21.tgz#affd3415115b8ebf4927c8d2a0d6a24bccfa9f02"
+  integrity sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==
   dependencies:
-    "@vue/shared" "3.2.47"
+    "@vue/shared" "3.4.21"
 
-"@vue/runtime-core@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.4.5.tgz#2bf253a6f6b0430af1aacf0fdfd8f5782feefce9"
-  integrity sha512-wh9ELIOQKeWT9SaUPdLrsxRkZv14jp+SJm9aiQGWio+/MWNM3Lib0wE6CoKEqQ9+SCYyGjDBhTOTtO47kCgbkg==
+"@vue/runtime-core@3.4.21":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.21.tgz#3749c3f024a64c4c27ecd75aea4ca35634db0062"
+  integrity sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==
   dependencies:
-    "@vue/reactivity" "3.4.5"
-    "@vue/shared" "3.4.5"
+    "@vue/reactivity" "3.4.21"
+    "@vue/shared" "3.4.21"
 
-"@vue/runtime-dom@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.4.5.tgz#b43736d66c32f6038778024587592cb9d68495de"
-  integrity sha512-n5ewvOjyG3IEpqGBahdPXODFSpVlSz3H4LF76Sx0XAqpIOqyJ5bIb2PrdYuH2ogBMAQPh+o5tnoH4nJpBr8U0Q==
+"@vue/runtime-dom@3.4.21":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz#91f867ef64eff232cac45095ab28ebc93ac74588"
+  integrity sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==
   dependencies:
-    "@vue/runtime-core" "3.4.5"
-    "@vue/shared" "3.4.5"
+    "@vue/runtime-core" "3.4.21"
+    "@vue/shared" "3.4.21"
     csstype "^3.1.3"
 
-"@vue/server-renderer@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.4.5.tgz#4bfa7aa763217d8b2d4767d2c8d968a9d40352c1"
-  integrity sha512-jOFc/VE87yvifQpNju12VcqimH8pBLxdcT+t3xMeiED1K6DfH9SORyhFEoZlW5TG2Vwfn3Ul5KE+1aC99xnSBg==
+"@vue/server-renderer@3.4.21":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.21.tgz#150751579d26661ee3ed26a28604667fa4222a97"
+  integrity sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==
   dependencies:
-    "@vue/compiler-ssr" "3.4.5"
-    "@vue/shared" "3.4.5"
-
-"@vue/shared@3.2.47", "@vue/shared@^3.2.37":
-  version "3.2.47"
-  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
-  integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
+    "@vue/compiler-ssr" "3.4.21"
+    "@vue/shared" "3.4.21"
 
-"@vue/shared@3.4.5":
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.4.5.tgz#c8b4eb6399a7fc986565ea736d938b3a1579256d"
-  integrity sha512-6XptuzlMvN4l4cDnDw36pdGEV+9njYkQ1ZE0Q6iZLwrKefKaOJyiFmcP3/KBDHbt72cJZGtllAc1GaHe6XGAyg==
+"@vue/shared@3.4.21", "@vue/shared@^3.2.37":
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.21.tgz#de526a9059d0a599f0b429af7037cd0c3ed7d5a1"
+  integrity sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==
 
 "@vueuse/core@^9.1.0":
   version "9.13.0"
-  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
+  resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
   integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
   dependencies:
     "@types/web-bluetooth" "^0.0.16"
@@ -376,33 +309,33 @@
 
 "@vueuse/metadata@9.13.0":
   version "9.13.0"
-  resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
+  resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
   integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
 
 "@vueuse/shared@9.13.0":
   version "9.13.0"
-  resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
+  resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
   integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==
   dependencies:
     vue-demi "*"
 
 "@wangeditor/basic-modules@^1.1.7":
   version "1.1.7"
-  resolved "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz#a9c3ccf4ef53332f29550d59d3676e15f395946f"
+  resolved "https://registry.yarnpkg.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz#a9c3ccf4ef53332f29550d59d3676e15f395946f"
   integrity sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==
   dependencies:
     is-url "^1.2.4"
 
 "@wangeditor/code-highlight@^1.0.3":
   version "1.0.3"
-  resolved "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz#90256857714d5c0cf83ac475aea64db7bf29a7cd"
+  resolved "https://registry.yarnpkg.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz#90256857714d5c0cf83ac475aea64db7bf29a7cd"
   integrity sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==
   dependencies:
     prismjs "^1.23.0"
 
 "@wangeditor/core@^1.1.19":
   version "1.1.19"
-  resolved "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz#f9155f7fd92d03cb1982405b3b82e54c31f1c2b0"
+  resolved "https://registry.yarnpkg.com/@wangeditor/core/-/core-1.1.19.tgz#f9155f7fd92d03cb1982405b3b82e54c31f1c2b0"
   integrity sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==
   dependencies:
     "@types/event-emitter" "^0.3.3"
@@ -414,12 +347,12 @@
 
 "@wangeditor/editor-for-vue@^5.1.12":
   version "5.1.12"
-  resolved "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz#f7d5f239b39cdfc01d31151488de8443fe6edc64"
+  resolved "https://registry.yarnpkg.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz#f7d5f239b39cdfc01d31151488de8443fe6edc64"
   integrity sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==
 
 "@wangeditor/editor@^5.1.23":
   version "5.1.23"
-  resolved "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz#c9d2007b7cb0ceef6b72692b4ee87b01ee2367b3"
+  resolved "https://registry.yarnpkg.com/@wangeditor/editor/-/editor-5.1.23.tgz#c9d2007b7cb0ceef6b72692b4ee87b01ee2367b3"
   integrity sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==
   dependencies:
     "@uppy/core" "^2.1.1"
@@ -446,37 +379,37 @@
 
 "@wangeditor/list-module@^1.0.5":
   version "1.0.5"
-  resolved "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz#3fc0b167acddf885536b45fa0c127f9c6adaea33"
+  resolved "https://registry.yarnpkg.com/@wangeditor/list-module/-/list-module-1.0.5.tgz#3fc0b167acddf885536b45fa0c127f9c6adaea33"
   integrity sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==
 
 "@wangeditor/table-module@^1.1.4":
   version "1.1.4"
-  resolved "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz#757d4a5868b2b658041cd323854a4d707c8347e9"
+  resolved "https://registry.yarnpkg.com/@wangeditor/table-module/-/table-module-1.1.4.tgz#757d4a5868b2b658041cd323854a4d707c8347e9"
   integrity sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==
 
 "@wangeditor/upload-image-module@^1.0.2":
   version "1.0.2"
-  resolved "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz#89e9b9467e10cbc6b11dc5748e08dd23aaebee30"
+  resolved "https://registry.yarnpkg.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz#89e9b9467e10cbc6b11dc5748e08dd23aaebee30"
   integrity sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==
 
 "@wangeditor/video-module@^1.1.4":
   version "1.1.4"
-  resolved "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz#b9df1b3ab2cd53f678b19b4d927e200774a6f532"
+  resolved "https://registry.yarnpkg.com/@wangeditor/video-module/-/video-module-1.1.4.tgz#b9df1b3ab2cd53f678b19b4d927e200774a6f532"
   integrity sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==
 
-acorn@^8.8.2:
-  version "8.8.2"
-  resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
-  integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
+acorn@^8.10.0, acorn@^8.11.3:
+  version "8.11.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
+  integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
 
 adler-32@~1.3.0:
   version "1.3.1"
-  resolved "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
+  resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
   integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
 
 anymatch@~3.1.2:
   version "3.1.3"
-  resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
   integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
   dependencies:
     normalize-path "^3.0.0"
@@ -484,59 +417,59 @@ anymatch@~3.1.2:
 
 async-validator@^4.2.5:
   version "4.2.5"
-  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
+  resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
   integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
 
 asynckit@^0.4.0:
   version "0.4.0"
-  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
   integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
 
 axios@^1.6.3:
-  version "1.6.5"
-  resolved "https://registry.npmmirror.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8"
-  integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==
+  version "1.6.8"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
+  integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
   dependencies:
-    follow-redirects "^1.15.4"
+    follow-redirects "^1.15.6"
     form-data "^4.0.0"
     proxy-from-env "^1.1.0"
 
 balanced-match@^1.0.0:
   version "1.0.2"
-  resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
   integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
 
 binary-extensions@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
-  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
+  integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
 
 brace-expansion@^2.0.1:
   version "2.0.1"
-  resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
   integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
   dependencies:
     balanced-match "^1.0.0"
 
 braces@^3.0.2, braces@~3.0.2:
   version "3.0.2"
-  resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
   integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
   dependencies:
     fill-range "^7.0.1"
 
 cfb@~1.2.1:
   version "1.2.2"
-  resolved "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
+  resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
   integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
   dependencies:
     adler-32 "~1.3.0"
     crc-32 "~1.2.0"
 
-chokidar@^3.5.3:
-  version "3.5.3"
-  resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
-  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+chokidar@^3.5.3, chokidar@^3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+  integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
   dependencies:
     anymatch "~3.1.2"
     braces "~3.0.2"
@@ -550,72 +483,85 @@ chokidar@^3.5.3:
 
 codepage@~1.15.0:
   version "1.15.0"
-  resolved "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
+  resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
   integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
 
 combined-stream@^1.0.8:
   version "1.0.8"
-  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
   integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
   dependencies:
     delayed-stream "~1.0.0"
 
 compute-scroll-into-view@^1.0.20:
   version "1.0.20"
-  resolved "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
+  resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
   integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
 
+countup.js@^2.8.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/countup.js/-/countup.js-2.8.0.tgz#64951f2df3ede28839413d654d8fef28251c32a8"
+  integrity sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ==
+
 crc-32@~1.2.0, crc-32@~1.2.1:
   version "1.2.2"
-  resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
+  resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
   integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
 
-cropperjs@^1.5.6:
-  version "1.5.13"
-  resolved "https://registry.npmmirror.com/cropperjs/-/cropperjs-1.5.13.tgz#eb1682f01d17c70ed5244317091d745c9a249ef8"
-  integrity sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA==
-
 csstype@^3.1.3:
   version "3.1.3"
-  resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
   integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
 
-d@1, d@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.npmmirror.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
-  integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
+d@1, d@^1.0.1, d@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de"
+  integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
   dependencies:
-    es5-ext "^0.10.50"
-    type "^1.0.1"
+    es5-ext "^0.10.64"
+    type "^2.7.2"
 
 dayjs@^1.11.3:
-  version "1.11.7"
-  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
-  integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
+  version "1.11.10"
+  resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
+  integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
 
 debug@^4.3.4:
   version "4.3.4"
-  resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
   integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
   dependencies:
     ms "2.1.2"
 
 delayed-stream@~1.0.0:
   version "1.0.0"
-  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
   integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
 
 dom7@^3.0.0:
   version "3.0.0"
-  resolved "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz#b861ce5d67a6becd7aaa3ad02942ff14b1240331"
+  resolved "https://registry.yarnpkg.com/dom7/-/dom7-3.0.0.tgz#b861ce5d67a6becd7aaa3ad02942ff14b1240331"
   integrity sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==
   dependencies:
     ssr-window "^3.0.0-alpha.1"
 
-element-plus@^2.4.4:
-  version "2.4.4"
-  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.4.tgz#962be40b4843381af04b8f799bfc142072184b8b"
-  integrity sha512-TlKubXJgxwhER0dw+8ULn9hr9kZjraV4R6Q/eidwWUwCKxwXYPBGmMKsZ/85tlxlhMYbcLZd/YZh6G3QkHX4fg==
+echarts-wordcloud@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz#c3de6fe267044f6c3343e4ff0e05eedb01c05096"
+  integrity sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==
+
+echarts@^5.5.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.5.0.tgz#c13945a7f3acdd67c134d8a9ac67e917830113ac"
+  integrity sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==
+  dependencies:
+    tslib "2.3.0"
+    zrender "5.5.0"
+
+element-plus@^2.6.3:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/element-plus/-/element-plus-2.7.0.tgz#1d72b06946c46a6f18e5315610b7f0147b8efb24"
+  integrity sha512-WAiaFLavuWFxof9qwkC27jvkh9nRcNnB506g1vvJSiVaVqjCBWUFCIyJKeN11M1qcv2cS5VV5PfSLjTIkrw87A==
   dependencies:
     "@ctrl/tinycolor" "^3.4.1"
     "@element-plus/icons-vue" "^2.3.1"
@@ -635,21 +581,22 @@ element-plus@^2.4.4:
 
 entities@^4.5.0:
   version "4.5.0"
-  resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
   integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
 
-es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14:
-  version "0.10.62"
-  resolved "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
-  integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
+es5-ext@^0.10.35, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14:
+  version "0.10.64"
+  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714"
+  integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==
   dependencies:
     es6-iterator "^2.0.3"
     es6-symbol "^3.1.3"
+    esniff "^2.0.1"
     next-tick "^1.1.0"
 
 es6-iterator@^2.0.3:
   version "2.0.3"
-  resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+  resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
   integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
   dependencies:
     d "1"
@@ -657,116 +604,116 @@ es6-iterator@^2.0.3:
     es6-symbol "^3.1.1"
 
 es6-symbol@^3.1.1, es6-symbol@^3.1.3:
-  version "3.1.3"
-  resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
-  integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c"
+  integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==
   dependencies:
-    d "^1.0.1"
-    ext "^1.1.2"
+    d "^1.0.2"
+    ext "^1.7.0"
 
 esbuild-android-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz#20a7ae1416c8eaade917fb2453c1259302c637a5"
+  resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz#20a7ae1416c8eaade917fb2453c1259302c637a5"
   integrity sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==
 
 esbuild-android-arm64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz#9cc0ec60581d6ad267568f29cf4895ffdd9f2f04"
+  resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz#9cc0ec60581d6ad267568f29cf4895ffdd9f2f04"
   integrity sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==
 
 esbuild-darwin-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz#428e1730ea819d500808f220fbc5207aea6d4410"
+  resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz#428e1730ea819d500808f220fbc5207aea6d4410"
   integrity sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==
 
 esbuild-darwin-arm64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz#b6dfc7799115a2917f35970bfbc93ae50256b337"
+  resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz#b6dfc7799115a2917f35970bfbc93ae50256b337"
   integrity sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==
 
 esbuild-freebsd-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz#4e190d9c2d1e67164619ae30a438be87d5eedaf2"
+  resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz#4e190d9c2d1e67164619ae30a438be87d5eedaf2"
   integrity sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==
 
 esbuild-freebsd-arm64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz#18a4c0344ee23bd5a6d06d18c76e2fd6d3f91635"
+  resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz#18a4c0344ee23bd5a6d06d18c76e2fd6d3f91635"
   integrity sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==
 
 esbuild-linux-32@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz#9a329731ee079b12262b793fb84eea762e82e0ce"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz#9a329731ee079b12262b793fb84eea762e82e0ce"
   integrity sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==
 
 esbuild-linux-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz#532738075397b994467b514e524aeb520c191b6c"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz#532738075397b994467b514e524aeb520c191b6c"
   integrity sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==
 
 esbuild-linux-arm64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz#5372e7993ac2da8f06b2ba313710d722b7a86e5d"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz#5372e7993ac2da8f06b2ba313710d722b7a86e5d"
   integrity sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==
 
 esbuild-linux-arm@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz#e734aaf259a2e3d109d4886c9e81ec0f2fd9a9cc"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz#e734aaf259a2e3d109d4886c9e81ec0f2fd9a9cc"
   integrity sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==
 
 esbuild-linux-mips64le@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz#c0487c14a9371a84eb08fab0e1d7b045a77105eb"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz#c0487c14a9371a84eb08fab0e1d7b045a77105eb"
   integrity sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==
 
 esbuild-linux-ppc64le@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz#af048ad94eed0ce32f6d5a873f7abe9115012507"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz#af048ad94eed0ce32f6d5a873f7abe9115012507"
   integrity sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==
 
 esbuild-linux-riscv64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz#423ed4e5927bd77f842bd566972178f424d455e6"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz#423ed4e5927bd77f842bd566972178f424d455e6"
   integrity sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==
 
 esbuild-linux-s390x@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz#21d21eaa962a183bfb76312e5a01cc5ae48ce8eb"
+  resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz#21d21eaa962a183bfb76312e5a01cc5ae48ce8eb"
   integrity sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==
 
 esbuild-netbsd-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz#ae75682f60d08560b1fe9482bfe0173e5110b998"
+  resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz#ae75682f60d08560b1fe9482bfe0173e5110b998"
   integrity sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==
 
 esbuild-openbsd-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz#79591a90aa3b03e4863f93beec0d2bab2853d0a8"
+  resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz#79591a90aa3b03e4863f93beec0d2bab2853d0a8"
   integrity sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==
 
 esbuild-sunos-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz#fd528aa5da5374b7e1e93d36ef9b07c3dfed2971"
+  resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz#fd528aa5da5374b7e1e93d36ef9b07c3dfed2971"
   integrity sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==
 
 esbuild-windows-32@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz#0e92b66ecdf5435a76813c4bc5ccda0696f4efc3"
+  resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz#0e92b66ecdf5435a76813c4bc5ccda0696f4efc3"
   integrity sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==
 
 esbuild-windows-64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz#0fc761d785414284fc408e7914226d33f82420d0"
+  resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz#0fc761d785414284fc408e7914226d33f82420d0"
   integrity sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==
 
 esbuild-windows-arm64@0.15.18:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz#5b5bdc56d341d0922ee94965c89ee120a6a86eb7"
+  resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz#5b5bdc56d341d0922ee94965c89ee120a6a86eb7"
   integrity sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==
 
 esbuild@^0.15.9:
   version "0.15.18"
-  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz#ea894adaf3fbc036d32320a00d4d6e4978a2f36d"
+  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.18.tgz#ea894adaf3fbc036d32320a00d4d6e4978a2f36d"
   integrity sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==
   optionalDependencies:
     "@esbuild/android-arm" "0.15.18"
@@ -794,38 +741,48 @@ esbuild@^0.15.9:
 
 escape-html@^1.0.3:
   version "1.0.3"
-  resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
 
 escape-string-regexp@^5.0.0:
   version "5.0.0"
-  resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
   integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
 
+esniff@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
+  integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
+  dependencies:
+    d "^1.0.1"
+    es5-ext "^0.10.62"
+    event-emitter "^0.3.5"
+    type "^2.7.2"
+
 estree-walker@^2.0.2:
   version "2.0.2"
-  resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
+  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
   integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
 
 event-emitter@^0.3.5:
   version "0.3.5"
-  resolved "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+  resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
   integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
   dependencies:
     d "1"
     es5-ext "~0.10.14"
 
-ext@^1.1.2:
+ext@^1.7.0:
   version "1.7.0"
-  resolved "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f"
+  resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f"
   integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==
   dependencies:
     type "^2.7.2"
 
 fast-glob@^3.2.12:
-  version "3.2.12"
-  resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
-  integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+  integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
   dependencies:
     "@nodelib/fs.stat" "^2.0.2"
     "@nodelib/fs.walk" "^1.2.3"
@@ -834,27 +791,27 @@ fast-glob@^3.2.12:
     micromatch "^4.0.4"
 
 fastq@^1.6.0:
-  version "1.15.0"
-  resolved "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
-  integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+  version "1.17.1"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+  integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
   dependencies:
     reusify "^1.0.4"
 
 fill-range@^7.0.1:
   version "7.0.1"
-  resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
   integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
   dependencies:
     to-regex-range "^5.0.1"
 
-follow-redirects@^1.15.4:
-  version "1.15.4"
-  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
-  integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
+follow-redirects@^1.15.6:
+  version "1.15.6"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
+  integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
 
 form-data@^4.0.0:
   version "4.0.0"
-  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
   integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
   dependencies:
     asynckit "^0.4.0"
@@ -863,202 +820,202 @@ form-data@^4.0.0:
 
 frac@~1.1.2:
   version "1.1.2"
-  resolved "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
+  resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
   integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
 
 fsevents@~2.3.2:
-  version "2.3.2"
-  resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
-  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+  integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
 
-function-bind@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+function-bind@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+  integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
 
 glob-parent@^5.1.2, glob-parent@~5.1.2:
   version "5.1.2"
-  resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
   integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
   dependencies:
     is-glob "^4.0.1"
 
-has@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
-  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+hasown@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+  integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
   dependencies:
-    function-bind "^1.1.1"
+    function-bind "^1.1.2"
 
 html-void-elements@^2.0.0:
   version "2.0.1"
-  resolved "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
+  resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f"
   integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
 
 i18next@^20.4.0:
   version "20.6.1"
-  resolved "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345"
+  resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345"
   integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==
   dependencies:
     "@babel/runtime" "^7.12.0"
 
 immer@^9.0.6:
-  version "9.0.19"
-  resolved "https://registry.npmmirror.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b"
-  integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==
+  version "9.0.21"
+  resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+  integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
 
 is-binary-path@~2.1.0:
   version "2.1.0"
-  resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
   integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
   dependencies:
     binary-extensions "^2.0.0"
 
-is-core-module@^2.9.0:
-  version "2.11.0"
-  resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
-  integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
+is-core-module@^2.13.0:
+  version "2.13.1"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+  integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
   dependencies:
-    has "^1.0.3"
+    hasown "^2.0.0"
 
 is-extglob@^2.1.1:
   version "2.1.1"
-  resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
   integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
 
 is-glob@^4.0.1, is-glob@~4.0.1:
   version "4.0.3"
-  resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
   integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
   dependencies:
     is-extglob "^2.1.1"
 
 is-hotkey@^0.2.0:
   version "0.2.0"
-  resolved "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef"
+  resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef"
   integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==
 
 is-number@^7.0.0:
   version "7.0.0"
-  resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
 is-plain-object@^5.0.0:
   version "5.0.0"
-  resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
   integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
 
 is-url@^1.2.4:
   version "1.2.4"
-  resolved "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
+  resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
   integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
 
 jsonc-parser@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
-  integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a"
+  integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==
 
 local-pkg@^0.4.2, local-pkg@^0.4.3:
   version "0.4.3"
-  resolved "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963"
+  resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963"
   integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==
 
 lodash-es@^4.17.21:
   version "4.17.21"
-  resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+  resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
   integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
 
 lodash-unified@^1.0.2:
   version "1.0.3"
-  resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894"
+  resolved "https://registry.yarnpkg.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894"
   integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==
 
 lodash.camelcase@^4.3.0:
   version "4.3.0"
-  resolved "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
   integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
 
 lodash.clonedeep@^4.5.0:
   version "4.5.0"
-  resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
   integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
 
 lodash.debounce@^4.0.8:
   version "4.0.8"
-  resolved "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
   integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
 
 lodash.foreach@^4.5.0:
   version "4.5.0"
-  resolved "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
+  resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
   integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==
 
 lodash.isequal@^4.5.0:
   version "4.5.0"
-  resolved "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
   integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
 
 lodash.throttle@^4.1.1:
   version "4.1.1"
-  resolved "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
+  resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
   integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
 
 lodash.toarray@^4.4.0:
   version "4.4.0"
-  resolved "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
+  resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
   integrity sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==
 
 lodash@^4.17.21:
   version "4.17.21"
-  resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
 magic-string@^0.25.7:
   version "0.25.9"
-  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
   integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
   dependencies:
     sourcemap-codec "^1.4.8"
 
 magic-string@^0.26.7:
   version "0.26.7"
-  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.26.7.tgz#caf7daf61b34e9982f8228c4527474dac8981d6f"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.7.tgz#caf7daf61b34e9982f8228c4527474dac8981d6f"
   integrity sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==
   dependencies:
     sourcemap-codec "^1.4.8"
 
 magic-string@^0.27.0:
   version "0.27.0"
-  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
   integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
   dependencies:
     "@jridgewell/sourcemap-codec" "^1.4.13"
 
-magic-string@^0.30.5:
-  version "0.30.5"
-  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9"
-  integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==
+magic-string@^0.30.7:
+  version "0.30.9"
+  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.9.tgz#8927ae21bfdd856310e07a1bc8dd5e73cb6c251d"
+  integrity sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==
   dependencies:
     "@jridgewell/sourcemap-codec" "^1.4.15"
 
 md-editor-v3@^2.11.2:
   version "2.11.3"
-  resolved "https://registry.npmmirror.com/md-editor-v3/-/md-editor-v3-2.11.3.tgz#f66e653034aeff03aca48d7728ce03c504db8d28"
+  resolved "https://registry.yarnpkg.com/md-editor-v3/-/md-editor-v3-2.11.3.tgz#f66e653034aeff03aca48d7728ce03c504db8d28"
   integrity sha512-SCfS4qMy0HldFdplcIGUMCpSv8qkNWkYShSdv2gTHeViKduA34zV89BOrWcqls2EZSlvt2n3G7nHRzYUvJjDKw==
 
 memoize-one@^6.0.0:
   version "6.0.0"
-  resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
+  resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
   integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
 
 merge2@^1.3.0:
   version "1.4.1"
-  resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
   integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
 
 micromatch@^4.0.4:
   version "4.0.5"
-  resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
   integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
   dependencies:
     braces "^3.0.2"
@@ -1066,222 +1023,213 @@ micromatch@^4.0.4:
 
 mime-db@1.52.0:
   version "1.52.0"
-  resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
   integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
 mime-match@^1.0.2:
   version "1.0.2"
-  resolved "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8"
+  resolved "https://registry.yarnpkg.com/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8"
   integrity sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==
   dependencies:
     wildcard "^1.1.0"
 
 mime-types@^2.1.12:
   version "2.1.35"
-  resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
   integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
   dependencies:
     mime-db "1.52.0"
 
 minimatch@^5.1.1:
   version "5.1.6"
-  resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
   integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
   dependencies:
     brace-expansion "^2.0.1"
 
-mlly@^1.1.0, mlly@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.npmmirror.com/mlly/-/mlly-1.1.1.tgz#f1838b14795e2cc284aa4ebcc76a258a52e6f537"
-  integrity sha512-Jnlh4W/aI4GySPo6+DyTN17Q75KKbLTyFK8BrGhjNP4rxuUjbRWhE6gHg3bs33URWAF44FRm7gdQA348i3XxRw==
+mlly@^1.1.0, mlly@^1.2.0:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.6.1.tgz#0983067dc3366d6314fc5e12712884e6978d028f"
+  integrity sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==
   dependencies:
-    acorn "^8.8.2"
-    pathe "^1.1.0"
-    pkg-types "^1.0.1"
-    ufo "^1.1.0"
+    acorn "^8.11.3"
+    pathe "^1.1.2"
+    pkg-types "^1.0.3"
+    ufo "^1.3.2"
 
 ms@2.1.2:
   version "2.1.2"
-  resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
 namespace-emitter@^2.0.1:
   version "2.0.1"
-  resolved "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz#978d51361c61313b4e6b8cf6f3853d08dfa2b17c"
+  resolved "https://registry.yarnpkg.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz#978d51361c61313b4e6b8cf6f3853d08dfa2b17c"
   integrity sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==
 
-nanoid@^3.1.25, nanoid@^3.2.0, nanoid@^3.3.4:
-  version "3.3.4"
-  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
-  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-
-nanoid@^3.3.7:
+nanoid@^3.1.25, nanoid@^3.2.0, nanoid@^3.3.7:
   version "3.3.7"
-  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
   integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
 
 next-tick@^1.1.0:
   version "1.1.0"
-  resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
+  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
   integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
 
 normalize-path@^3.0.0, normalize-path@~3.0.0:
   version "3.0.0"
-  resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
   integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 
 normalize-wheel-es@^1.2.0:
   version "1.2.0"
-  resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e"
+  resolved "https://registry.yarnpkg.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e"
   integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==
 
 nprogress@^0.2.0:
   version "0.2.0"
-  resolved "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1"
+  resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1"
   integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==
 
 path-parse@^1.0.7:
   version "1.0.7"
-  resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
 
-pathe@^1.0.0, pathe@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.npmmirror.com/pathe/-/pathe-1.1.0.tgz#e2e13f6c62b31a3289af4ba19886c230f295ec03"
-  integrity sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==
+pathe@^1.0.0, pathe@^1.1.0, pathe@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec"
+  integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==
 
 picocolors@^1.0.0:
   version "1.0.0"
-  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
   integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
 
 picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
   version "2.3.1"
-  resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
 pinia@^2.1.7:
   version "2.1.7"
-  resolved "https://registry.npmmirror.com/pinia/-/pinia-2.1.7.tgz#4cf5420d9324ca00b7b4984d3fbf693222115bbc"
+  resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.1.7.tgz#4cf5420d9324ca00b7b4984d3fbf693222115bbc"
   integrity sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==
   dependencies:
     "@vue/devtools-api" "^6.5.0"
     vue-demi ">=0.14.5"
 
-pkg-types@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.0.2.tgz#c233efc5210a781e160e0cafd60c0d0510a4b12e"
-  integrity sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==
+pkg-types@^1.0.1, pkg-types@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868"
+  integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==
   dependencies:
     jsonc-parser "^3.2.0"
-    mlly "^1.1.1"
+    mlly "^1.2.0"
     pathe "^1.1.0"
 
-postcss@^8.1.10, postcss@^8.4.18:
-  version "8.4.21"
-  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
-  integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
-  dependencies:
-    nanoid "^3.3.4"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
-postcss@^8.4.32:
-  version "8.4.33"
-  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
-  integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
+postcss@^8.4.18, postcss@^8.4.35:
+  version "8.4.38"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
+  integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
   dependencies:
     nanoid "^3.3.7"
     picocolors "^1.0.0"
-    source-map-js "^1.0.2"
+    source-map-js "^1.2.0"
 
 preact@^10.5.13:
-  version "10.13.0"
-  resolved "https://registry.npmmirror.com/preact/-/preact-10.13.0.tgz#f8bd3cf257a4dbe41da71a52131b79916d4ca89d"
-  integrity sha512-ERdIdUpR6doqdaSIh80hvzebHB7O6JxycOhyzAeLEchqOq/4yueslQbfnPwXaNhAYacFTyCclhwkEbOumT0tHw==
+  version "10.20.2"
+  resolved "https://registry.yarnpkg.com/preact/-/preact-10.20.2.tgz#0b343299a8c020562311cc25db93b3d832ec5e71"
+  integrity sha512-S1d1ernz3KQ+Y2awUxKakpfOg2CEmJmwOP+6igPx6dgr6pgDvenqYviyokWso2rhHvGtTlWWnJDa7RaPbQerTg==
 
 prismjs@^1.23.0:
   version "1.29.0"
-  resolved "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
+  resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
   integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
 
 proxy-from-env@^1.1.0:
   version "1.1.0"
-  resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+  resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
   integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
 
 queue-microtask@^1.2.2:
   version "1.2.3"
-  resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
   integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
 
 readdirp@~3.6.0:
   version "3.6.0"
-  resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
   integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
   dependencies:
     picomatch "^2.2.1"
 
-regenerator-runtime@^0.13.11:
-  version "0.13.11"
-  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
-  integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+regenerator-runtime@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+  integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+resize-detector@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/resize-detector/-/resize-detector-0.3.0.tgz#fe495112e184695500a8f51e0389f15774cb1cfc"
+  integrity sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ==
 
 resolve@^1.22.1:
-  version "1.22.1"
-  resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
-  integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+  version "1.22.8"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+  integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
   dependencies:
-    is-core-module "^2.9.0"
+    is-core-module "^2.13.0"
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
 reusify@^1.0.4:
   version "1.0.4"
-  resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
 rollup@^2.79.1:
   version "2.79.1"
-  resolved "https://registry.npmmirror.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
   integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
   optionalDependencies:
     fsevents "~2.3.2"
 
 run-parallel@^1.1.9:
   version "1.2.0"
-  resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
   integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
   dependencies:
     queue-microtask "^1.2.2"
 
 schart.js@^3.0.0:
   version "3.0.4"
-  resolved "https://registry.npmmirror.com/schart.js/-/schart.js-3.0.4.tgz#3bfb3e1ebbc63b4f5ce84606ee03fe575355defc"
+  resolved "https://registry.yarnpkg.com/schart.js/-/schart.js-3.0.4.tgz#3bfb3e1ebbc63b4f5ce84606ee03fe575355defc"
   integrity sha512-uylb2u9rrHX1jyAuSAJUQON8XTfyDKI9kWj1J3fUlCQCkLVZ4HG4+IiV8qm//Z71dqvLI78QZ/fCBw0reB22Zw==
 
 scroll-into-view-if-needed@^2.2.28:
   version "2.2.31"
-  resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
+  resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
   integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
   dependencies:
     compute-scroll-into-view "^1.0.20"
 
 scule@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/scule/-/scule-1.0.0.tgz#895e6f4ba887e78d8b9b4111e23ae84fef82376d"
-  integrity sha512-4AsO/FrViE/iDNEPaAQlb77tf0csuq27EsVpy6ett584EcRTp6pTDLoGWVxCD77y5iU5FauOvhsI4o1APwPoSQ==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3"
+  integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==
 
 slate-history@^0.66.0:
   version "0.66.0"
-  resolved "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz#ac63fddb903098ceb4c944433e3f75fe63acf940"
+  resolved "https://registry.yarnpkg.com/slate-history/-/slate-history-0.66.0.tgz#ac63fddb903098ceb4c944433e3f75fe63acf940"
   integrity sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==
   dependencies:
     is-plain-object "^5.0.0"
 
 slate@^0.72.0:
   version "0.72.8"
-  resolved "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz#5a018edf24e45448655293a68bfbcf563aa5ba81"
+  resolved "https://registry.yarnpkg.com/slate/-/slate-0.72.8.tgz#5a018edf24e45448655293a68bfbcf563aa5ba81"
   integrity sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==
   dependencies:
     immer "^9.0.6"
@@ -1289,84 +1237,79 @@ slate@^0.72.0:
     tiny-warning "^1.0.3"
 
 snabbdom@^3.1.0:
-  version "3.5.1"
-  resolved "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.5.1.tgz#25f80ef15b194baea703d9d5441892e369de18e1"
-  integrity sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/snabbdom/-/snabbdom-3.6.2.tgz#57dd66878f6320497fa7f67941df356a045c75a1"
+  integrity sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==
 
-source-map-js@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
-  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-
-source-map@^0.6.1:
-  version "0.6.1"
-  resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
-  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+source-map-js@^1.0.2, source-map-js@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
+  integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
 
 sourcemap-codec@^1.4.8:
   version "1.4.8"
-  resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
   integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
 
 ssf@~0.11.2:
   version "0.11.2"
-  resolved "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
+  resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
   integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
   dependencies:
     frac "~1.1.2"
 
 ssr-window@^3.0.0-alpha.1:
   version "3.0.0"
-  resolved "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz#fd5b82801638943e0cc704c4691801435af7ac37"
+  resolved "https://registry.yarnpkg.com/ssr-window/-/ssr-window-3.0.0.tgz#fd5b82801638943e0cc704c4691801435af7ac37"
   integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
 
 strip-literal@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.npmmirror.com/strip-literal/-/strip-literal-1.0.1.tgz#0115a332710c849b4e46497891fb8d585e404bd2"
-  integrity sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07"
+  integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==
   dependencies:
-    acorn "^8.8.2"
+    acorn "^8.10.0"
 
 supports-preserve-symlinks-flag@^1.0.0:
   version "1.0.0"
-  resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
   integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
 
 tiny-warning@^1.0.3:
   version "1.0.3"
-  resolved "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+  resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
   integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
 
 to-regex-range@^5.0.1:
   version "5.0.1"
-  resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
   integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
   dependencies:
     is-number "^7.0.0"
 
-type@^1.0.1:
-  version "1.2.0"
-  resolved "https://registry.npmmirror.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
-  integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
 
 type@^2.7.2:
   version "2.7.2"
-  resolved "https://registry.npmmirror.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
+  resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
   integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
 
 typescript@^4.6.4:
   version "4.9.5"
-  resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
   integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
 
-ufo@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.npmmirror.com/ufo/-/ufo-1.1.0.tgz#a5c4c814b0a98f7e0ca42c478688663fd3e3c037"
-  integrity sha512-LQc2s/ZDMaCN3QLpa+uzHUOQ7SdV0qgv3VBXOolQGXTaaZpIur6PwUclF5nN2hNkiTRcUugXd1zFOW3FLJ135Q==
+ufo@^1.3.2:
+  version "1.5.3"
+  resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344"
+  integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==
 
 unimport@^1.0.1:
   version "1.3.0"
-  resolved "https://registry.npmmirror.com/unimport/-/unimport-1.3.0.tgz#167ab78e60ea0e36a9a764c7b608ee95d7b2411c"
+  resolved "https://registry.yarnpkg.com/unimport/-/unimport-1.3.0.tgz#167ab78e60ea0e36a9a764c7b608ee95d7b2411c"
   integrity sha512-fOkrdxglsHd428yegH0wPH/6IfaSdDeMXtdRGn6en/ccyzc2aaoxiUTMrJyc6Bu+xoa18RJRPMfLUHEzjz8atw==
   dependencies:
     "@rollup/pluginutils" "^5.0.2"
@@ -1383,7 +1326,7 @@ unimport@^1.0.1:
 
 unplugin-auto-import@^0.11.2:
   version "0.11.5"
-  resolved "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-0.11.5.tgz#84c27e5f230bc1fc9004c162a39b81fcf89da740"
+  resolved "https://registry.yarnpkg.com/unplugin-auto-import/-/unplugin-auto-import-0.11.5.tgz#84c27e5f230bc1fc9004c162a39b81fcf89da740"
   integrity sha512-nvbL2AQwLRR8wbHpJ6L1EBVNmjN045RSedTa4NtsGRkSQFXkI1iKHs4dTqJwcKZsnFrZOAKtLPiN1/oQTObLZw==
   dependencies:
     "@antfu/utils" "^0.7.0"
@@ -1395,7 +1338,7 @@ unplugin-auto-import@^0.11.2:
 
 unplugin-vue-components@^0.22.4:
   version "0.22.12"
-  resolved "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz#39013f77be72d32df9d6ca1599e592a484015612"
+  resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-0.22.12.tgz#39013f77be72d32df9d6ca1599e592a484015612"
   integrity sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==
   dependencies:
     "@antfu/utils" "^0.7.2"
@@ -1410,27 +1353,27 @@ unplugin-vue-components@^0.22.4:
     unplugin "^1.0.1"
 
 unplugin@^1.0.0, unplugin@^1.0.1:
-  version "1.1.0"
-  resolved "https://registry.npmmirror.com/unplugin/-/unplugin-1.1.0.tgz#96a14aa52d7637a56a88dec6baf4a73902f2db87"
-  integrity sha512-I8obQ8Rs/hnkxokRV6g8JKOQFgYNnTd9DL58vcSt5IJ9AkK8wbrtsnzD5hi4BJlvcY536JzfEXj9L6h7j559/A==
+  version "1.10.1"
+  resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.10.1.tgz#8ceda065dc71bc67d923dea0920f05c67f2cd68c"
+  integrity sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==
   dependencies:
-    acorn "^8.8.2"
-    chokidar "^3.5.3"
+    acorn "^8.11.3"
+    chokidar "^3.6.0"
     webpack-sources "^3.2.3"
-    webpack-virtual-modules "^0.5.0"
+    webpack-virtual-modules "^0.6.1"
 
 vite-plugin-vue-setup-extend@^0.4.0:
   version "0.4.0"
-  resolved "https://registry.npmmirror.com/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz#ebbbe265320039b8c6a3b9fcae3b8d152ecf4a13"
+  resolved "https://registry.yarnpkg.com/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz#ebbbe265320039b8c6a3b9fcae3b8d152ecf4a13"
   integrity sha512-WMbjPCui75fboFoUTHhdbXzu4Y/bJMv5N9QT9a7do3wNMNHHqrk+Tn2jrSJU0LS5fGl/EG+FEDBYVUeWIkDqXQ==
   dependencies:
     "@vue/compiler-sfc" "^3.2.29"
     magic-string "^0.25.7"
 
 vite@^3.0.0:
-  version "3.2.5"
-  resolved "https://registry.npmmirror.com/vite/-/vite-3.2.5.tgz#dee5678172a8a0ab3e547ad4148c3d547f90e86a"
-  integrity sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==
+  version "3.2.10"
+  resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.10.tgz#7ac79fead82cfb6b5bf65613cd82fba6dcc81340"
+  integrity sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==
   dependencies:
     esbuild "^0.15.9"
     postcss "^8.4.18"
@@ -1439,83 +1382,89 @@ vite@^3.0.0:
   optionalDependencies:
     fsevents "~2.3.2"
 
-vue-cropperjs@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.npmmirror.com/vue-cropperjs/-/vue-cropperjs-5.0.0.tgz#7f8cbc460737af3831b4ded634c95905198e329e"
-  integrity sha512-RhnC8O33uRZNkn74aiHZwNHnBJOXWlS4P6gsRI0lw4cZlWjKSCywZI9oSI9POlIPI6OYv30jvnHMXGch85tw7w==
-  dependencies:
-    cropperjs "^1.5.6"
+vue-cropper@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/vue-cropper/-/vue-cropper-1.1.1.tgz#e1d2729f7139182a893e8badcb8f33257aa2a40f"
+  integrity sha512-WsqKMpaBf9Osi1LQlE/5AKdD0nHWOy1asLXocaG8NomOWO07jiZi968+/PbMmnD0QbPJOumDQaGuGa13qys85A==
+
+vue-demi@*, vue-demi@>=0.14.5:
+  version "0.14.7"
+  resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.7.tgz#8317536b3ef74c5b09f268f7782e70194567d8f2"
+  integrity sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==
 
-vue-demi@*:
+vue-demi@^0.13.11:
   version "0.13.11"
-  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
+  resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
   integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
 
-vue-demi@>=0.14.5:
-  version "0.14.6"
-  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92"
-  integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
+vue-echarts@^6.6.9:
+  version "6.6.9"
+  resolved "https://registry.yarnpkg.com/vue-echarts/-/vue-echarts-6.6.9.tgz#151372ecd086db985dafeeebd3ea83c8d4d2846b"
+  integrity sha512-mojIq3ZvsjabeVmDthhAUDV8Kgf2Rr/X4lV4da7gEFd1fP05gcSJ0j7wa7HQkW5LlFmF2gdCJ8p4Chas6NNIQQ==
+  dependencies:
+    resize-detector "^0.3.0"
+    vue-demi "^0.13.11"
 
 vue-router@^4.2.5:
-  version "4.2.5"
-  resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.2.5.tgz#b9e3e08f1bd9ea363fdd173032620bc50cf0e98a"
-  integrity sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.3.0.tgz#d5913f27bf68a0a178ee798c3c88be471811a235"
+  integrity sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==
   dependencies:
-    "@vue/devtools-api" "^6.5.0"
+    "@vue/devtools-api" "^6.5.1"
 
 vue-schart@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.npmmirror.com/vue-schart/-/vue-schart-2.0.0.tgz#744f26bbbf3c10bc5a584931e002335970810901"
+  resolved "https://registry.yarnpkg.com/vue-schart/-/vue-schart-2.0.0.tgz#744f26bbbf3c10bc5a584931e002335970810901"
   integrity sha512-qAu3e5wfMcq26wK1xeHExEWfGpnjfoN1R/9QXblNi+AsU/p52X7tTwhi+Fw7H/otfEufhEY2X7z7emaoF4QO+g==
   dependencies:
     schart.js "^3.0.0"
 
 vue-tsc@^0.38.4:
   version "0.38.9"
-  resolved "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-0.38.9.tgz#9e945937667f704325328db8af1cc6bc7314b85e"
+  resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.38.9.tgz#9e945937667f704325328db8af1cc6bc7314b85e"
   integrity sha512-Yoy5phgvGqyF98Fb4mYqboR4Q149jrdcGv5kSmufXJUq++RZJ2iMVG0g6zl+v3t4ORVWkQmRpsV4x2szufZ0LQ==
   dependencies:
     "@volar/vue-typescript" "0.38.9"
 
-vue@^3.3.0:
-  version "3.4.5"
-  resolved "https://registry.npmmirror.com/vue/-/vue-3.4.5.tgz#c08b9d903a20faaf4df7270bf2fa7487741b2294"
-  integrity sha512-VH6nHFhLPjgu2oh5vEBXoNZxsGHuZNr3qf4PHClwJWw6IDqw6B3x+4J+ABdoZ0aJuT8Zi0zf3GpGlLQCrGWHrw==
+vue@^3.4.5:
+  version "3.4.21"
+  resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.21.tgz#69ec30e267d358ee3a0ce16612ba89e00aaeb731"
+  integrity sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==
   dependencies:
-    "@vue/compiler-dom" "3.4.5"
-    "@vue/compiler-sfc" "3.4.5"
-    "@vue/runtime-dom" "3.4.5"
-    "@vue/server-renderer" "3.4.5"
-    "@vue/shared" "3.4.5"
+    "@vue/compiler-dom" "3.4.21"
+    "@vue/compiler-sfc" "3.4.21"
+    "@vue/runtime-dom" "3.4.21"
+    "@vue/server-renderer" "3.4.21"
+    "@vue/shared" "3.4.21"
 
 webpack-sources@^3.2.3:
   version "3.2.3"
-  resolved "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
   integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
 
-webpack-virtual-modules@^0.5.0:
-  version "0.5.0"
-  resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c"
-  integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
+webpack-virtual-modules@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f"
+  integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==
 
 wildcard@^1.1.0:
   version "1.1.2"
-  resolved "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5"
+  resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5"
   integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==
 
 wmf@~1.0.1:
   version "1.0.2"
-  resolved "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
+  resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
   integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
 
 word@~0.3.0:
   version "0.3.0"
-  resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
+  resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
   integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
 
 xlsx@^0.18.5:
   version "0.18.5"
-  resolved "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
+  resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
   integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
   dependencies:
     adler-32 "~1.3.0"
@@ -1525,3 +1474,10 @@ xlsx@^0.18.5:
     ssf "~0.11.2"
     wmf "~1.0.1"
     word "~0.3.0"
+
+zrender@5.5.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.5.0.tgz#54d0d6c4eda81a96d9f60a9cd74dc48ea026bc1e"
+  integrity sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==
+  dependencies:
+    tslib "2.3.0"