Browse Source

init:初始化

xiao007 2 months ago
commit
7ab705b9e9
56 changed files with 5283 additions and 0 deletions
  1. 23 0
      .gitignore
  2. 5 0
      auto-imports.d.ts
  3. 47 0
      components.d.ts
  4. 23 0
      index.html
  5. 57 0
      package.json
  6. 17 0
      src/App.vue
  7. 13 0
      src/api/index.ts
  8. 4 0
      src/assets/css/icon.css
  9. 87 0
      src/assets/css/main.css
  10. BIN
      src/assets/img/favicon.ico
  11. BIN
      src/assets/img/img.jpg
  12. 4 0
      src/assets/img/lang.svg
  13. BIN
      src/assets/img/login-bg.png
  14. 8 0
      src/assets/img/logo.svg
  15. BIN
      src/assets/img/ucenter-bg.jpg
  16. 40 0
      src/components/countup.vue
  17. 47 0
      src/components/group.vue
  18. 217 0
      src/components/header.vue
  19. 56 0
      src/components/menu.ts
  20. 144 0
      src/components/ruleform.vue
  21. 90 0
      src/components/sidebar.vue
  22. 66 0
      src/components/table.vue
  23. 69 0
      src/i18n/en.ts
  24. 70 0
      src/i18n/es.ts
  25. 37 0
      src/main.ts
  26. 105 0
      src/router/index.ts
  27. 14 0
      src/store/permiss.ts
  28. 25 0
      src/store/sidebar.ts
  29. 58 0
      src/store/theme.ts
  30. 21 0
      src/store/userInfo.ts
  31. 21 0
      src/types/form-option.ts
  32. 9 0
      src/types/menu.ts
  33. 8 0
      src/types/role.ts
  34. 9 0
      src/types/table.ts
  35. 22 0
      src/types/user.ts
  36. 0 0
      src/utils/china.ts
  37. 23 0
      src/utils/i18n.ts
  38. 34 0
      src/utils/index.ts
  39. 125 0
      src/utils/request.ts
  40. 61 0
      src/views/home.vue
  41. 67 0
      src/views/pages/403.vue
  42. 67 0
      src/views/pages/404.vue
  43. 175 0
      src/views/pages/dashboard.vue
  44. 172 0
      src/views/pages/login.vue
  45. 66 0
      src/views/pages/rule.vue
  46. 205 0
      src/views/pages/theme.vue
  47. 227 0
      src/views/pages/ucenter.vue
  48. 184 0
      src/views/pages/user.vue
  49. 76 0
      src/views/system/role-permission.vue
  50. 162 0
      src/views/system/role.vue
  51. 148 0
      src/views/system/user.vue
  52. 10 0
      src/vite-env.d.ts
  53. 23 0
      tsconfig.json
  54. 9 0
      tsconfig.node.json
  55. 40 0
      vite.config.ts
  56. 1993 0
      yarn.lock

+ 23 - 0
.gitignore

@@ -0,0 +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?

+ 5 - 0
auto-imports.d.ts

@@ -0,0 +1,5 @@
+// Generated by 'unplugin-auto-import'
+export {}
+declare global {
+
+}

+ 47 - 0
components.d.ts

@@ -0,0 +1,47 @@
+// generated by unplugin-vue-components
+// We suggest you to commit this file into source control
+// Read more: https://github.com/vuejs/core/pull/3399
+import '@vue/runtime-core'
+
+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']
+    ElCard: typeof import('element-plus/es')['ElCard']
+    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+    ElCol: typeof import('element-plus/es')['ElCol']
+    ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
+    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
+    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElDropdown: typeof import('element-plus/es')['ElDropdown']
+    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+    ElForm: typeof import('element-plus/es')['ElForm']
+    ElFormItem: typeof import('element-plus/es')['ElFormItem']
+    ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElInput: typeof import('element-plus/es')['ElInput']
+    ElMenu: typeof import('element-plus/es')['ElMenu']
+    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+    ElOption: typeof import('element-plus/es')['ElOption']
+    ElRow: typeof import('element-plus/es')['ElRow']
+    ElSelect: typeof import('element-plus/es')['ElSelect']
+    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTabPane: typeof import('element-plus/es')['ElTabPane']
+    ElTabs: typeof import('element-plus/es')['ElTabs']
+    Group: typeof import('./src/components/group.vue')['default']
+    Header: typeof import('./src/components/header.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    Ruleform: typeof import('./src/components/ruleform.vue')['default']
+    Sidebar: typeof import('./src/components/sidebar.vue')['default']
+    Table: typeof import('./src/components/table.vue')['default']
+  }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
+}

+ 23 - 0
index.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="">
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
+  <!-- <title>直播管理系统</title> -->
+  <link rel="icon" href="./src/assets/img/favicon.ico">
+  <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>
+  </noscript>
+  <div id="app"></div>
+  <script type="module" src="/src/main.ts"></script>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>

+ 57 - 0
package.json

@@ -0,0 +1,57 @@
+{
+	"name": "vue-manage-system",
+	"version": "5.5.0",
+	"private": true,
+	"scripts": {
+		"start": "vite --open",
+		"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",
+		"dompurify": "^3.2.3",
+		"echarts": "^5.5.0",
+		"echarts-wordcloud": "^2.1.0",
+		"element-china-area-data": "^6.1.0",
+		"element-plus": "^2.6.3",
+		"flv.js": "^1.6.2",
+		"js-md5": "^0.8.3",
+		"jsencrypt": "^3.3.2",
+		"lodash": "^4.17.21",
+		"md-editor-v3": "^2.11.2",
+		"nprogress": "^0.2.0",
+		"pinia": "^2.1.7",
+		"sass": "^1.82.0",
+		"svgaplayerweb": "^2.3.2",
+		"video.js": "7",
+		"videojs-contrib-hls": "^5.15.0",
+		"videojs-flash": "^2.2.1",
+		"videojs-flvjs-es6": "^1.0.1",
+		"videojs-swf": "^5.4.2",
+		"vue": "^3.4.5",
+		"vue-cropper": "1.1.1",
+		"vue-echarts": "^6.6.9",
+		"vue-i18n": "^11.0.1",
+		"vue-router": "^4.2.5",
+		"vue-schart": "^2.0.0"
+	},
+	"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"
+	]
+}

+ 17 - 0
src/App.vue

@@ -0,0 +1,17 @@
+<template>
+	<el-config-provider>
+		<router-view />
+	</el-config-provider>
+</template>
+
+<script setup>
+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 lang="scss">
+@import './assets/css/main.css';
+</style>

+ 13 - 0
src/api/index.ts

@@ -0,0 +1,13 @@
+import request from '../utils/request';
+
+export const fetchData = () => {
+    return request('get', './mock/table.json');
+};
+
+export const fetchUserData = () => {
+    return request('get','./mock/user.json');
+};
+
+export const fetchRoleData = () => {
+    return request('get','./mock/role.json');
+};

+ 4 - 0
src/assets/css/icon.css

@@ -0,0 +1,4 @@
+[class*=" el-icon-lx"],
+[class^=el-icon-lx] {
+    font-family: lx-iconfont !important;
+}

+ 87 - 0
src/assets/css/main.css

@@ -0,0 +1,87 @@
+* {
+	margin: 0;
+	padding: 0;
+	outline: 0 !important;
+}
+
+
+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);
+}

BIN
src/assets/img/favicon.ico


BIN
src/assets/img/img.jpg


+ 4 - 0
src/assets/img/lang.svg

@@ -0,0 +1,4 @@
+<svg t="1736389309308" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1229" width="200" height="200">
+  <path d="M862.72 207.36C729.6 53.76 517.12 5.12 332.8 81.92l-48.64 20.48 28.16-46.08c2.56-5.12 2.56-10.24 2.56-15.36-2.56-5.12-5.12-10.24-10.24-12.8-10.24-5.12-20.48-2.56-25.6 7.68L204.8 163.84c-5.12 5.12-5.12 12.8-2.56 15.36 0 5.12 2.56 10.24 7.68 12.8 7.68 5.12 15.36 2.56 23.04-2.56 99.84-87.04 230.4-120.32 360.96-94.72 112.64 23.04 207.36 87.04 271.36 179.2 64 94.72 87.04 207.36 64 320-2.56 7.68 2.56 15.36 7.68 20.48 2.56 0 2.56 2.56 5.12 2.56h2.56c2.56 0 7.68 0 10.24-2.56 5.12-2.56 7.68-7.68 7.68-12.8 33.28-143.36-5.12-286.72-99.84-394.24zM814.08 832c-5.12-2.56-10.24-2.56-15.36-2.56-2.56 0-7.68 2.56-10.24 5.12-138.24 117.76-335.36 135.68-491.52 46.08s-238.08-268.8-204.8-448c0-10.24-5.12-17.92-15.36-20.48-5.12 0-10.24 0-15.36 2.56-5.12 2.56-7.68 7.68-7.68 12.8-35.84 194.56 53.76 389.12 225.28 488.96 125.44 71.68 279.04 81.92 412.16 25.6l48.64-20.48-28.16 48.64c-5.12 10.24-2.56 20.48 7.68 25.6 2.56 2.56 5.12 2.56 10.24 2.56 7.68 0 12.8-2.56 17.92-10.24l74.24-128c2.56-10.24 0-23.04-7.68-28.16z" fill="#ffffff" stroke="#ffffff" stroke-width="36" p-id="1230"></path>
+  <path d="M611.84 573.44l56.32 133.12v2.56h53.76L537.6 268.8v-2.56h-40.96l-186.88 442.88h53.76l56.32-135.68h192z m-12.8-40.96h-166.4l84.48-202.24 81.92 202.24z" fill="#ffffff" stroke="#ffffff" stroke-width="36" p-id="1231"></path>
+</svg>

BIN
src/assets/img/login-bg.png


File diff suppressed because it is too large
+ 8 - 0
src/assets/img/logo.svg


BIN
src/assets/img/ucenter-bg.jpg


+ 40 - 0
src/components/countup.vue

@@ -0,0 +1,40 @@
+<template>
+    <span ref="countRef"></span>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue';
+import { CountUp } from 'countup.js';
+
+const props = defineProps({
+    end: {
+        type: Number,
+        default:()=>0,
+        required: true,
+    },
+    options: {
+        type: Object,
+        default: () => ({}),
+        required: false,
+    },
+});
+
+const countRef = ref(null);
+let countUp;
+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>

+ 47 - 0
src/components/group.vue

@@ -0,0 +1,47 @@
+<template>
+     <el-card
+     class="warp"
+     v-bind="$attrs"
+     v-on="$attrs"
+     >
+     <template #header v-if="props.showHeader">
+       <div class="header-title">{{$t(route.meta.title as string) || props.headerTitle}}</div>
+     </template>
+     <slot></slot>
+     </el-card>
+</template>
+
+<script lang='ts' setup>
+import {ref ,onMounted} from 'vue'
+import { useRoute } from 'vue-router';
+const route = useRoute();
+ const props = defineProps({
+  headerTitle:{
+    type:String,
+    default:''
+  },
+  showHeader:{
+    type:Boolean,
+    default:true
+  }
+}) 
+onMounted(()=>{
+})
+</script>
+
+<style scoped lang="scss">
+.warp{
+  margin-bottom: 18px;
+}
+  .header-title{
+  &::before{
+    content: '';
+    display: inline-block;
+    width: 3px;
+    height: 18px;
+    background: var(--header-bg-color);
+    vertical-align: middle;
+    margin-right: 8px;
+  }
+}
+</style>

+ 217 - 0
src/components/header.vue

@@ -0,0 +1,217 @@
+<template>
+    <div class="header">
+        <!-- 折叠按钮 -->
+        <div class="header-left">
+            <img class="logo" src="../assets/img/logo.svg" alt="" />
+            <div class="web-title">{{ $t('kingCasino') }}</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')">
+                        <i class="el-icon-lx-skin"></i>
+                </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">
+                   
+                        <i class="el-icon-lx-full"></i>
+                </div>
+                <div class="btn-icon" @click="setLanguage">
+                        <img src="../assets/img/lang.svg" style="width: 20px;"/>
+                </div>
+                <!-- 用户头像 -->
+                <el-avatar class="user-avator" :size="30" :src="userInfo.icon || imgurl" />
+                <!-- 用户名下拉菜单 -->
+                <el-dropdown class="user-name" trigger="click" @command="handleCommand">
+                    <span class="el-dropdown-link">
+                      {{ userInfo.username}}
+                        <el-icon class="el-icon--right">
+                            <arrow-down />
+                        </el-icon>
+                    </span>
+                    <template #dropdown>
+                        <el-dropdown-menu>
+                            <!-- <el-dropdown-item command="user">个人中心</el-dropdown-item> -->
+                            <el-dropdown-item divided command="loginout">{{$t('loginout')}}</el-dropdown-item>
+                        </el-dropdown-menu>
+                    </template>
+                </el-dropdown>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup>
+import { onMounted, ref } from 'vue';
+import { useSidebarStore } from '../store/sidebar';
+import { useRouter } from 'vue-router';
+import imgurl from '../assets/img/logo.svg';
+import request from '@/utils/request';
+import { userInfoStore } from '../store/userInfo';
+import { useI18n } from 'vue-i18n';
+const { locale } = useI18n()
+const currentLang = ref(locale.value);
+const userStore = userInfoStore();
+const userInfo = ref({})
+const sidebar = useSidebarStore();
+// 侧边栏折叠
+const collapseChage = () => {
+    sidebar.handleCollapse();
+};
+onMounted(() => {
+  if (localStorage.getItem('userInfo')) {
+    userInfo.value = JSON.parse(localStorage.getItem('userInfo'))
+  }
+    if (document.body.clientWidth < 1500) {
+        collapseChage();
+    }
+});
+
+// 用户名下拉菜单选择事件
+const router = useRouter();
+const loginout = async () => {
+  const res = await request('post', '/api/live/video/user/logout',{username:userInfo.username},'application/x-www-form-urlencoded')
+  if (res.code === 200) {
+    userStore.clearUserInfo();
+      router.push('/login');
+  } 
+};
+const handleCommand = (command) => {
+    if (command == 'loginout') {
+      loginout();
+    } else if (command == 'user') {
+        router.push('/ucenter');
+    }
+};
+
+const setFullScreen = () => {
+    if (document.fullscreenElement) {
+        document.exitFullscreen();
+    } else {
+        document.body.requestFullscreen.call(document.body);
+    }
+};
+const setLanguage = () => {
+  console.log(currentLang.value, 'currentLang');
+  console.log(document.title, 'document.title');
+  
+  const newLang = currentLang.value === 'es' ? 'en' : 'es'; 
+  locale.value = newLang; 
+  currentLang.value = newLang;
+};
+</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>

+ 56 - 0
src/components/menu.ts

@@ -0,0 +1,56 @@
+import { Menus } from '@/types/menu';
+
+export const menuData: Menus[] = [
+    {
+      id: '0',
+      index: '/user',
+      title: 'userManagement',
+      icon: 'Avatar',
+    },
+    {
+        id: '1',
+        title: 'dataAnalysis',
+        index: '/dashboard',
+        icon: 'Odometer',
+    },
+    {
+      id: '2',
+      title: 'ruleSetting',
+      index: '/rule',
+      icon: 'Tools',
+    },
+    // {
+    //     id: '1',
+    //     title: '直播管理',
+    //     index: '1',
+    //     icon: 'service',
+    //     children: [
+    //         {
+    //             id: '11',
+    //             pid: '1',
+    //             index: '/live-user',
+    //             title: 'userManagement',
+    //         },
+    //     ],
+    // },
+  //   {
+  //     id: '2',
+  //     title: '系统管理',
+  //     index: '2',
+  //     icon: 'setting',
+  //     children: [
+  //         {
+  //             id: '21',
+  //             pid: '2',
+  //             index: '/system-user',
+  //             title: '用户管理',
+  //         },
+  //         {
+  //             id: '22',
+  //             pid: '2',
+  //             index: '/system-role',
+  //             title: '角色管理',
+  //         }
+  //     ],
+  // }
+];

+ 144 - 0
src/components/ruleform.vue

@@ -0,0 +1,144 @@
+<template>
+  <div>
+    <el-form label-suffix=":">
+        <el-form-item>
+          <!-- <el-radio-group v-model="radio1">
+            <el-radio :value="1">
+            <template #default>
+              <div class="deafault">
+                <el-tooltip
+                  class="box-item"
+                  effect="dark"
+                  content="Top Center prompts info"
+                  placement="top"
+                >
+                <el-icon><InfoFilled /></el-icon>
+                </el-tooltip>
+                <span>{{$t('defaultValue')}}</span>
+              </div>
+            </template>
+          </el-radio>
+          <el-radio :label="$t('custom')" :value="2"></el-radio>
+          </el-radio-group> -->
+          <span style="width: 360px;">{{$t('venueTicket')}}:</span>
+        </el-form-item>
+        <el-form-item>
+          <div class="row">
+            <span style="width: 230px;">{{$t('minimumAdmission')}}:</span>
+            <el-input v-model="data.low" :placeholder="$t('pleaseEnter')"></el-input>
+          </div>
+          <div class="row">
+            <span style="width: 200px;">{{$t('maximumTicket')}}:</span>
+            <el-input v-model="data.high" :placeholder="$t('pleaseEnter')"></el-input>
+          </div>
+        </el-form-item>
+        <el-form-item>
+          <span style="width: 360px;">{{$t('roomSize')}}:</span>
+        </el-form-item>
+        <el-form-item>
+          <div class="row">
+            <span style="width: 165px;">{{ $t('paracopsia') }}:</span>
+            <el-input v-model="data.smallBlind" :placeholder="$t('pleaseEnter')"></el-input>
+          </div>
+          <div class="row">
+            <span style="width: 150px;">{{ $t('macroblind') }}:</span>
+            <el-input v-model="data.bigBlind" :placeholder="$t('pleaseEnter')"></el-input>
+          </div>
+        </el-form-item>
+      </el-form>
+      <div style="display: flex;justify-content: end;">
+        <el-button type="primary" @click="updateGame">{{$t('save')}}</el-button>
+      </div>
+      <el-tabs>
+        <el-tab-pane :label="$t('sessionRooms')">
+        <el-form>
+          <el-form-item>
+            <span style="width: 360px;">{{$t('numberRooms')}}:</span>
+          <!-- <el-radio-group v-model="radio1">
+            <el-radio :value="1">
+            <template #default>
+              <div class="deafault">
+                <el-tooltip
+                  class="box-item"
+                  effect="dark"
+                  content="Top Center prompts info"
+                  placement="top"
+                >
+                <el-icon><InfoFilled /></el-icon>
+                </el-tooltip>
+                <span>{{$t('defaultValue')}}</span>
+              </div>
+            </template>
+          </el-radio>
+          <el-radio :label="$t('custom')" :value="2"></el-radio>
+          </el-radio-group> -->
+        </el-form-item>
+        <el-form-item>
+          <div class="row">
+            <span style="width: 160px;">{{$t('quantity')}}:</span>
+            <el-input v-model="data.roomNumber" :placeholder="$t('pleaseEnter')"></el-input>
+          </div>
+        </el-form-item>
+        </el-form>
+        <div style="display: flex;justify-content: end;">
+        <el-button type="primary" @click="updateRoom">{{$t('save')}}</el-button>
+      </div>
+      </el-tab-pane>
+      </el-tabs>
+  </div>
+</template>
+
+<script lang='ts' setup>
+import request from '@/utils/request'
+import i18n from '@/utils/i18n'
+import { ElMessage } from 'element-plus'
+import {ref ,defineProps, reactive, watch,defineEmits} from 'vue'
+const props = defineProps({
+  formData: {
+    type: Object,
+    required: true,
+    default: () => ({
+      low: '',
+      high: '',
+      smallBlind: '',
+      bigBlind: ''
+    })
+  }
+})
+const data = reactive({ ...props.formData })
+const emit = defineEmits()
+watch(
+  () => props.formData,
+  (newVal) => {
+    Object.assign(data, newVal)
+  },
+  { deep: true } 
+)
+const updateGame = async ()=>{
+  const res = await request('post', 'admin/poker/updatePokerGame', Object.assign(data, {gameId:data.id}))
+  if (res.code === 200) {
+    ElMessage.success(i18n.global.t('successfulOperation'))
+    emit('getPageData')
+  }
+  
+}
+const updateRoom = async ()=>{
+  const res = await request('post', 'admin/poker/updatePokerGameRoomNumber', {gameId:data.id, number:data.roomNumber})
+  if (res.code === 200) {
+    ElMessage.success(i18n.global.t('successfulOperation'))
+    emit('getPageData')
+  }
+  
+}
+</script>
+
+<style lang="scss" scoped >
+  .deafault{
+  display: flex;
+  align-items: center;
+}
+.row{
+  display: flex;
+  margin-right: 16px;
+}
+</style>

+ 90 - 0
src/components/sidebar.vue

@@ -0,0 +1,90 @@
+<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" >
+                        <template #title>
+                            <el-icon :class="item.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">
+                                {{ subItem.title }}
+                            </el-menu-item>
+                        </template>
+                    </el-sub-menu>
+                </template>
+                <template v-else>
+                    <el-menu-item :index="item.index" :key="item.index" >
+                        <el-icon :class="item.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>

+ 66 - 0
src/components/table.vue

@@ -0,0 +1,66 @@
+<template>
+    <ElTable
+      :data="props.data"
+      v-bind="$attrs"
+      v-on="$attrs"
+    >
+      <slot name="table"></slot>
+    </ElTable>
+
+      <slot name="sum"></slot>
+    <div class="pagination-container">
+      <ElPagination
+      hide-on-single-page
+      :current-page="props.pagination.pageNo"
+      :page-size="props.pagination.pageSize"
+      :page-sizes="[10, 20, 50, 100]"
+      :total="props.pagination.total"
+      :layout="props.layout"
+      @current-change="handlePageChange"
+      @size-change="handlePageSizeChange"
+      background
+    />
+    </div>
+
+</template>
+
+<script setup>
+import { defineProps, defineEmits } from 'vue';
+import { ElTable, ElPagination } from 'element-plus';
+
+const props = defineProps({
+  data: {
+    type: Array,
+    default: () => []
+  },
+  layout: {
+    type: String,
+    default: 'total, prev, pager, next, sizes, jumper'
+  },
+  pagination: {
+    type: Object,
+    default: () => ({
+      pageNo: 1,
+      pageSize: 10,
+      total: 0
+    })
+  }
+});
+const emit = defineEmits();
+const handlePageChange = (newPage) => {
+  emit('changePage', newPage);
+};
+const handlePageSizeChange = (newSize) => {
+  emit('changePageSize', newSize);
+};
+
+</script>
+<style lang="scss" scoped>
+  .el-pagination {
+    margin-top: 10px;
+  }
+  .pagination-container {
+    display: flex;
+    justify-content: flex-end;
+}
+</style>

+ 69 - 0
src/i18n/en.ts

@@ -0,0 +1,69 @@
+export default {
+  kingCasino:'King Casino management System',
+  Permission:'Permission is insufficient. Please contact the administrator',
+  authorization:'No authorization, token may have expired, please log in again',
+  serverError:'Server error, please try again later',
+  dataLoading:'Data loading...',
+  name:'name',
+  cipher:'cipher',
+  status:'status',
+  enterUsername:'Please enter your username',
+  enterPassword:'Please enter password',
+  userPlaceholder:'Please enter the user name to support fuzzy search',
+  statusPlaceholder:'Please select status',
+  userManagement:'User management',
+  inquire:'inquire',
+  dataAnalysis:'Data analysis',
+  ruleSetting:'Rule setting',
+  themeSetting:'Theme setting',
+  login:'Log in',
+  remember:'Remember the password',
+  noAuthority:'Have no authority',
+  noAuthorityPage:'You do not have permission to access this page',
+  backHome:'Back to home page',
+  returnPage:'Return to previous page',
+  notFound:'Page not found',
+  notFoundPage:'The page you are looking for does not exist',
+  management:'Management background',
+  roomNumber:'Room number',
+  roomPlaceholder:'Please enter the full room number',
+  session:'session',
+  primaryField:'Primary field',
+  intermediateField:'Intermediate field',
+  higherOrderField:'Higher order field',
+  time:'time',
+  loginName:'Login name',
+  nickname:'nickname',
+  telephone:'telephone',
+  mailbox:'mailbox',
+  registrationTime:'Registration time',
+  coin:'coin',
+  controls:'Controls',
+  topUp:'top-up',
+  startDate:'Start date',
+  endDate:'End date',
+  startTime:'Start time',
+  endTime:'End time',
+  disburse:'disburse',
+  royalty:'royalty',
+  totalExpenditure:'Total expenditure',
+  totalCommissions:'Total commissions',
+  successfulOperation:'Successful operation',
+  venueTicket:'Venue ticket configuration',
+  defaultValue:'Default value',
+  custom:'Custom',
+  numberRooms:'The number of rooms configured for each session',
+  pleaseEnter:'Please enter',
+  roomSize:'Match room size blind bet configuration',
+  paracopsia:'paracopsia',
+  macroblind:'macroblind',
+  customizeRoom:'Customize your room ticket configuration',
+  customizeRoomRates:'Customize room rates',
+  save:'save',
+  minimumAdmission:'Minimum admission',
+  maximumTicket:'Maximum ticket',
+  quantity:'quantity',
+  customRoom:'Custom room',
+  sessionRooms:'Number of rooms per session',
+  loginout:'Log out'
+}

+ 70 - 0
src/i18n/es.ts

@@ -0,0 +1,70 @@
+export default {
+  kingCasino:'Sistema de gestión king casino',
+  Permission:'Permisos insuficientes, póngase en contacto con el administrador',
+  authorization:'No autorizado, el token puede haber caducado, por favor inicie sesión de nuevo',
+  serverError:'Error del servidor, inténtelo de nuevo más tarde',
+  dataLoading:'Cargando datos...',
+  name:'Nombre de usuario',
+  cipher:'La contraseña',
+  status:'El estado',
+  enterUsername:'Por favor ingrese su nombre de usuario',
+  enterPassword:'Por favor introduzca el código',
+  userPlaceholder:'Por favor, introduzca su nombre de usuario. Soporte de búsqueda difusa',
+  statusPlaceholder:'Por favor seleccione un estado',
+  userManagement:'Gestión de usuarios',
+  inquire:'consulta',
+  dataAnalysis:'Análisis de datos',
+  ruleSetting:'Configuración de reglas',
+  themeSetting:'Configuración del tema',
+  login:'inicio',
+  remember:'Recordar la contraseña',
+  noAuthority:'Sin permiso',
+  noAuthorityPage:'Usted no tiene permiso para acceder a la página',
+  backHome:'Volver al inicio',
+  returnPage:'Volver a la página anterior',
+  notFound:'Página no encontrada',
+  notFoundPage:'La página que está visitando no existe',
+  management:'Administrar el backoffice',
+  roomNumber:'Número de habitaciones',
+  roomPlaceholder:'Por favor, introduzca el número completo de habitación',
+  session:'Una sesión',
+  primaryField:'Campo primario',
+  intermediateField:'Campo intermedio',
+  higherOrderField:'Campo avanzado',
+  time:'tiempo',
+  loginName:'Iniciar sesión nombre',
+  nickname:'apodo',
+  telephone:'Tel.',
+  mailbox:'dirección',
+   registrationTime:'Hora de registro',
+   coin:'coin',
+   controls:'La operación',
+   topUp:'en',
+  startDate:'Fecha de inicio',
+  endDate:'Fecha de finalización',
+  startTime:'Hora de inicio',
+  endTime:'Hora de fin',
+  disburse:'gastos',
+  royalty:'La maquila',
+  totalExpenditure:'Total de gastos',
+  totalCommissions:'Total de comisiones',
+  successfulOperation:'Éxito de operación',
+  venueTicket:'Configuración de boletos de sesión',
+  defaultValue:'Valor por defecto',
+  custom:'personalizado',
+  numberRooms:'Sesión número de habitaciones configuración',
+  pleaseEnter:'Por favor ingrese',
+  roomSize:'Campo tamaño de sala blind bet configuración',
+  paracopsia:'Pequeño ciegos.',
+  macroblind:'Gran ciegos.',
+  customizeRoom:'Configuración personalizada de entradas de sala',
+  customizeRoomRates:'Tarifas de habitación personalizadas',
+  save:'guardar',
+  minimumAdmission:'El billete mínimo',
+  maximumTicket:'El ticket más alto',
+  quantity:'El número de',
+  customRoom:'Personaliza tu habitación',
+  sessionRooms:'Número de habitaciones',
+  loginout:'Salir del login'
+
+}

+ 37 - 0
src/main.ts

@@ -0,0 +1,37 @@
+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 ElementPlus from 'element-plus';
+import es from 'element-plus/es/locale/lang/es';
+import en from 'element-plus/es/locale/lang/en';
+import 'element-plus/dist/index.css';
+import './assets/css/icon.css';
+import i18n from '@/utils/i18n'
+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.userAuth.includes(String(binding.value))) {
+            el['hidden'] = true;
+        }
+    },
+});
+if (navigator.language.startsWith('es')) {
+  app.use(ElementPlus, { locale: es })
+}else{
+  app.use(ElementPlus, { locale: en })
+}
+app.config.globalProperties.$router = router
+app.use(i18n)
+app.mount('#app');

+ 105 - 0
src/router/index.ts

@@ -0,0 +1,105 @@
+import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
+// import { usePermissStore } from '../store/permiss';
+import Home from '../views/home.vue';
+import NProgress from 'nprogress';
+import i18n from '@/utils/i18n'
+import 'nprogress/nprogress.css';
+
+const routes: RouteRecordRaw[] = [
+    {
+        path: '/',
+        redirect: '/user',
+    },
+    {
+        path: '/',
+        name: 'Home',
+        component: Home,
+        children: [
+            {
+                path: '/user',
+                name: 'user',
+                meta: {
+                    title: 'userManagement'
+                },
+                component: () => import('@/views/pages/user.vue'),
+            },
+            {
+                path: '/dashboard',
+                name: 'dashboard',
+                meta: {
+                    title: 'dataAnalysis'
+                },
+                component: () => import('@/views/pages/dashboard.vue'),
+            },
+            {
+                path: '/rule',
+                name: 'rule',
+                meta: {
+                    title: 'ruleSetting'
+                },
+                component: () => import('@/views/pages/rule.vue'),
+            },
+            {
+              path: '/theme',
+              name: 'theme',
+              meta: {
+                  title: 'themeSetting'
+              },
+              component: () => import(/* webpackChunkName: "theme" */ '../views/pages/theme.vue'),
+          }
+        ],
+    },
+    {
+        path: '/login',
+        meta: {
+            title: 'login',
+            noAuth: true,
+        },
+        component: () => import(/* webpackChunkName: "login" */ '../views/pages/login.vue'),
+    },
+    {
+        path: '/403',
+        meta: {
+            title: 'noAuthority',
+        },
+        component: () => import(/* webpackChunkName: "403" */ '../views/pages/403.vue'),
+    },
+    {
+        path: '/404',
+        meta: {
+            title: 'notFound',
+        },
+        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();
+    if (typeof document !== 'undefined') {
+      document.title = to.meta.title?  i18n.global.t(to.meta.title as string) : i18n.global.t('management') 
+    }
+    const role = localStorage.getItem('token');
+    // const permiss = usePermissStore();
+    if (!role && to.meta.noAuth !== true) {
+
+        next('/login');
+        /* else if (typeof to.meta.permiss == 'string' && permiss.userAuth.includes(to.meta.permiss)) {
+        // 如果没有权限,则进入403
+        next('/403');
+    }*/
+    } else {
+        next();
+    }
+});
+
+router.afterEach(() => {
+    NProgress.done();
+});
+
+export default router;

+ 14 - 0
src/store/permiss.ts

@@ -0,0 +1,14 @@
+import { defineStore } from 'pinia';
+export const usePermissStore = defineStore('permiss', {
+    state: () => {
+        return {
+          userAuth: []
+
+        };
+    },
+    actions: {
+        handleSet(val: string[]) {
+            this.userAuth = val;
+        },
+    },
+});

+ 25 - 0
src/store/sidebar.ts

@@ -0,0 +1,25 @@
+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);
+		}
+	}
+});

+ 58 - 0
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);
+        }
+    }
+});

+ 21 - 0
src/store/userInfo.ts

@@ -0,0 +1,21 @@
+import { defineStore } from 'pinia';
+
+export const userInfoStore = defineStore('userInfo', {
+  state: () => ({
+    userInfo: { }
+  }),
+  actions: {
+    setUserInfo(obj) {
+      if (obj && obj.token && this.userInfo.token !== obj.token) {
+        this.userInfo = obj;
+        localStorage.setItem('userInfo', JSON.stringify(this.userInfo));
+        localStorage.setItem('token', obj.token);
+      }
+    },
+    clearUserInfo() {
+      this.userInfo = {};
+      localStorage.removeItem('userInfo'); 
+      localStorage.removeItem('token');
+    }
+  }
+});

+ 21 - 0
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;
+}

+ 9 - 0
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[];
+}

+ 8 - 0
src/types/role.ts

@@ -0,0 +1,8 @@
+
+export interface Role {
+    id: number;
+    name: string;
+    key: string;
+    status: boolean;
+    permiss: string[]
+}

+ 9 - 0
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;
+}

+ 22 - 0
src/types/user.ts

@@ -0,0 +1,22 @@
+
+export interface User {
+    city: string;
+    birthday: string;
+    createTime: string;
+    email: string;
+    icon: string;
+    label	: string[];
+    password	: string;
+    personalizedSignature	: string;
+    phone	: string;
+    starSign	: string;
+    strongPoint	: string[];
+    username	: string;
+
+}
+
+export interface Register {
+    username: string;
+    password: string;
+    email: string;
+}

File diff suppressed because it is too large
+ 0 - 0
src/utils/china.ts


+ 23 - 0
src/utils/i18n.ts

@@ -0,0 +1,23 @@
+import { createI18n } from 'vue-i18n';
+import es from 'element-plus/es/locale/lang/es';
+import en from 'element-plus/es/locale/lang/en';
+import locen from '@/i18n/en'
+import loces from '@/i18n/es'
+const messages = {
+  'es': {
+    ...es, // 导入 Element Plus 的中文语言包
+    ...loces
+  },
+  'en': {
+    ...en, // 导入 Element Plus 的英文语言包
+    ...locen
+  }
+};
+
+const i18n = createI18n({
+  legacy: false,
+  locale: navigator.language.startsWith('es') ? 'es' : 'en', // 默认语言
+  messages
+});
+
+export default i18n;

+ 34 - 0
src/utils/index.ts

@@ -0,0 +1,34 @@
+import { JSEncrypt } from 'jsencrypt'
+import { md5 } from 'js-md5'
+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;
+};
+export const encryptedData =  (data: any) => {
+  // 创建一个 JSEncrypt 实例
+  let encrypt = new JSEncrypt();
+  
+  // 设置公钥
+  encrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB+o3BYY2/kxg1zjIGmZjNJCc3pdXXv927rAvmDSrTVTdYJ1uTYpnjw4tcUYgX5ABD3LzPZMDhJVT7DMOsb7UEl0sx30m6ZFBGrgrbxhm7t8/Ep1yWT41jgo/BYLOa6zWXBHbMxr12/LEep7SjHngY5QzSF/EuQ6H68xguRaAOXwIDAQAB');
+  
+  // 加密数据
+  let result = encrypt.encrypt(data);
+  
+  return result;
+};
+export const md5Data = (data: any) => {
+  console.log('Data type:', typeof data); // 打印输入数据类型
+  const stringData = typeof data === 'string' ? data : JSON.stringify(data);
+  return md5(stringData);
+};
+

+ 125 - 0
src/utils/request.ts

@@ -0,0 +1,125 @@
+import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
+import { ElMessage } from 'element-plus';
+import { nextTick } from 'vue'
+import router from '@/router/index';
+import i18n from '@/utils/i18n'
+// 创建 axios 实例
+const service: AxiosInstance = axios.create({
+  timeout: 5000,  // 设置请求超时
+});
+
+// 跳转处理方法
+const redirectTo = (path: string) => {
+  nextTick(() => {
+      router.push(path);
+  });
+};
+
+// 设置请求头的 token
+const setAuthHeader = (config: InternalAxiosRequestConfig) => {
+  const token = localStorage.getItem('token');
+  if (token) {
+    config.headers['Authorization'] = `Bearer ${token}`;
+  }
+  return config;
+};
+
+// 将数据转换为 x-www-form-urlencoded 格式
+const convertToFormData = (data: any) => {
+  const formData = new URLSearchParams();
+  for (const key in data) {
+    if (data.hasOwnProperty(key)) {
+      formData.append(key, data[key]);
+    }
+  }
+  return formData;
+};
+
+// 请求拦截器
+service.interceptors.request.use(
+  (config: InternalAxiosRequestConfig) => {
+    // 添加 Authorization 头
+    setAuthHeader(config);
+
+    // 如果是 POST 请求且数据需要以 x-www-form-urlencoded 发送
+    if (config.method === 'post' && config.headers['Content-Type'] === 'application/x-www-form-urlencoded' && config.data) {
+      config.data = convertToFormData(config.data);  // 将数据转换为 x-www-form-urlencoded 格式
+    }
+
+    return config;
+  },
+  (error: AxiosError) => {
+    console.error('Request error:', error);
+    return Promise.reject(error);
+  }
+);
+
+// 响应拦截器
+service.interceptors.response.use(
+  (response: AxiosResponse) => {
+    if (response.data.code === 1002) {
+      localStorage.removeItem('token');
+      ElMessage.error(response.data.message);
+      redirectTo('/login');
+    } else if (response.data.code !== 200) {
+      console.error('Request failed:', response.data.message);
+      ElMessage.error(response.data.message);
+    }
+    return response;
+  },
+  (error: AxiosError) => {
+    const status = error.response?.status;
+
+    // 统一错误处理
+    const handleError = (message: string, path?: string) => {
+      ElMessage.error(i18n.global.t(message));
+      if (path) {
+        redirectTo(path);
+      }
+    };
+
+    if (status === 403) {
+      handleError('Permission', '/403');
+    } else if (status === 401) {
+      handleError('authorization', '/login');
+    } else if (status >= 500) {
+      handleError('serverError');
+    }
+
+    return Promise.reject(error);
+  }
+);
+
+async function request(
+  method: 'get' | 'post' | 'put',
+  url: string,
+  params = {},
+  contentType: 'application/json' | 'application/x-www-form-urlencoded' = 'application/json'
+) {
+  try {
+    let response: AxiosResponse;
+
+    const headers = {
+      'Content-Type': contentType,
+    };
+
+    if (method === 'get') {
+      response = await service.get(url, { params, headers });
+    }
+    else if (method === 'post') {
+      response = await service.post(url, params, { headers });
+    } 
+    else if (method === 'put') {
+      response = await service.put(url, params, { headers });
+    } else {
+      throw new Error(`Unsupported request method: ${method}`);
+    }
+
+    return response.data;
+  } catch (error) {
+    console.error('Request failed:', error);
+    throw error; 
+  }
+}
+
+export default request;

+ 61 - 0
src/views/home.vue

@@ -0,0 +1,61 @@
+<template>
+    <div class="wrapper">
+        <v-header />
+        <v-sidebar />
+        <div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
+            <div class="content">
+              <el-config-provider :locale="locale === 'es' ? es : en">
+                <router-view>
+                </router-view>
+              </el-config-provider>
+            </div>
+        </div>
+    </div>
+</template>
+<script setup lang="ts">
+import { useSidebarStore } from '@/store/sidebar';
+import vHeader from '@/components/header.vue';
+import vSidebar from '@/components/sidebar.vue';
+import { useI18n } from 'vue-i18n';
+import es from 'element-plus/es/locale/lang/es';
+import en from 'element-plus/es/locale/lang/en';
+// import vTabs from '@/components/tabs.vue';
+
+const sidebar = useSidebarStore();
+ 
+  const { locale } = useI18n()
+</script>
+
+<style lang="scss">
+.wrapper {
+    height: 100vh;
+    overflow: hidden;
+}
+.content-box {
+    position: absolute;
+    left: 250px;
+    right: 0;
+    top: 70px;
+    bottom: 0;
+    -webkit-transition: left 0.3s ease-in-out;
+    transition: left 0.3s ease-in-out;
+    background: #eef0fc;
+    overflow: hidden;
+}
+
+.content {
+    width: auto;
+    height: 100%;
+    padding: 20px;
+    overflow-y: scroll;
+    box-sizing: border-box;
+}
+
+.content::-webkit-scrollbar {
+    width: 0;
+}
+
+.content-collapse {
+    left: 65px;
+}
+</style>

+ 67 - 0
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">{{ $t('noAuthorityPage') }}</div>
+            <div class="error-handle">
+                <router-link to="/">
+                    <el-button type="primary" size="small">{{ $t('backHome') }}</el-button>
+                </router-link>
+                <el-button class="error-btn" size="small" @click="goBack">{{ $t('returnPage') }}</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 lang="scss" scoped>
+.error-page {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    width: 100%;
+    height: 100vh;
+    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>

+ 67 - 0
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">{{ $t('notFoundPage') }}</div>
+            <div class="error-handle">
+                <router-link to="/">
+                    <el-button type="primary" size="small">{{ $t('backHome') }}</el-button>
+                </router-link>
+                <el-button class="error-btn" size="small" @click="goBack">{{ $t('returnPage') }}</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 lang="scss" scoped>
+.error-page {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    width: 100%;
+    height: 100vh;
+    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>

+ 175 - 0
src/views/pages/dashboard.vue

@@ -0,0 +1,175 @@
+<template>
+  <div 
+  v-loading="loading"
+  :element-loading-text="$t('dataLoading')">
+    <Group>
+    <div style="display: flex;">
+      <el-form style="flex: 1; display: flex; flex-wrap: wrap;" label-suffix=":" :model="query">
+        <el-form-item :label="$t('name')" class='label'>
+          <el-input v-model="query.username" :placeholder="$t('userPlaceholder')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('roomNumber')" class='label'>
+          <el-input v-model="query.roomnumber" :placeholder="$t('roomPlaceholder')"></el-input>
+        </el-form-item>
+        <el-form-item :label="$t('session')" class='label'>
+          <el-select v-model="query.changci" clearable >
+            <el-option :label="$t('primaryField')" value="1"></el-option>
+            <el-option :label="$t('intermediateField')" value="2"></el-option>
+            <el-option :label="$t('higherOrderField')" value="3"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item :label="$t('tiem')" class='label'>
+          <div style="display: flex;">
+            <el-date-picker
+          v-model="value2"
+          type="dates"
+          :placeholder="$t('startDate')"
+        />
+        <span>至</span>
+        <el-date-picker
+          v-model="value2"
+          type="dates"
+          :placeholder="$t('endDate')"
+        />
+          </div>
+        </el-form-item>
+      </el-form>
+      <el-button style="align-self: center;" type="primary" @click="searchHandler">{{$t('inquire')}}</el-button>
+    </div>
+  </Group>
+  <Group :show-header="false">
+      <Table 
+      :data="tableData"
+      :pagination="pagination"
+      @changePage="changePage"
+      @changePageSize="changePageSize"
+      >
+        <template #table>
+            <el-table-column :label="$t('loginName')" prop="username"></el-table-column>
+            <el-table-column :label="$t('nickname')" prop="nickname"></el-table-column>
+            <el-table-column :label="$t('roomNumber')" prop="roomnumber"></el-table-column>
+            <el-table-column :label="$t('session')" prop="changci"></el-table-column>
+            <el-table-column :label="$t('startTime')" prop="starttime"></el-table-column>
+            <el-table-column :label="$t('endTime')" prop="endtime"></el-table-column>
+            <el-table-column :label="$t('disburse')" prop="zhichu"></el-table-column>
+            <el-table-column :label="$t('royalty')" prop="ticheng"></el-table-column>
+         </template>
+         <template #sum>
+          <div class="sum">
+            <span class="text">{{ $t('totalExpenditure')}}:<span class="red">850000</span></span>
+            <span class="text">{{$t('totalCommissions')}}:<span class="red">150000</span></span>
+          </div>
+          </template>
+      </Table>
+  </Group>
+  </div>
+</template>
+
+<script setup  name="user">
+import { ref, reactive, onMounted} from 'vue';
+import Group from '@/components/group.vue';
+import Table from '@/components/table.vue';
+import request from '@/utils/request';
+// 查询相关
+const query = reactive({
+  username: ''
+});
+const loading = ref(false);
+const tableData = ref([]);
+// 表格相关
+const pagination = {
+pageNo: 1,
+pageSize: 10,
+total: 0,
+}
+const changePage = (page) => {
+  pagination.pageNo = page
+  feachTableData()
+}
+const changePageSize = (pageSize) => {
+  pagination.pageSize = pageSize
+  feachTableData()
+}
+const searchHandler = () => {
+  pagination.pageNo = 1
+  feachTableData()
+}
+const feachTableData = async() => {
+  loading.value = true
+  const params = {
+      // ...query,
+      ...pagination
+    }
+    try {
+      const res = await request('post', '/admin/user/getUserGameRecordList', params)
+      if (res.code === 200) {
+        loading.value = false
+        pagination.total = res.data.total
+        tableData.value = res.data.records
+      } else {
+        loading.value = false
+      }
+      
+    } catch (error) {
+      console.log(error, 'error');
+      loading.value = false
+    }
+}
+onMounted(() => {
+  feachTableData()
+})
+</script>
+
+<style lang="scss" scoped>
+.avatar-uploader .avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.label{
+  width: 33%;
+  padding-right: 8px;
+  box-sizing: border-box;
+}
+.sum{
+  background: #ebeaea64;
+  text-align: end;
+  padding-right: 18px;
+  border-radius: 3px;
+  .text{
+    line-height: 36px;
+    font-weight: 600;
+    margin-right: 10px;
+  }
+  .red{
+    color: red;
+  }
+}
+
+</style>
+
+<style lang="scss">
+.el-table th, .el-table td {
+  text-align: center !important;
+}
+.avatar-uploader .el-upload {
+  border: 1px dashed var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 136px;
+  height: 136px;
+  text-align: center;
+}
+</style>

+ 172 - 0
src/views/pages/login.vue

@@ -0,0 +1,172 @@
+<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">{{ $t('kingCasino') }}</div>
+            </div>
+            <el-form :model="param" :rules="rules" ref="login">
+                <el-form-item prop="account">
+                    <el-input v-model="param.account" :placeholder="$t('name')">
+                        <template #prepend>
+                            <el-icon>
+                                <User />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="loginPwd">
+                    <el-input
+                        type="password"
+                        :placeholder="$t('cipher')"
+                        v-model="param.loginPwd"
+                        @keyup.enter="submitForm()"
+                    >
+                        <template #prepend>
+                            <el-icon>
+                                <Lock />
+                            </el-icon>
+                        </template>
+                    </el-input>
+                </el-form-item>
+                <el-form-item >
+                  <el-checkbox class="pwd-checkbox" v-model="checked" :label="$t('remember')" />
+                  <!-- <el-link type="primary" @click="$router.push('/reset-pwd')">忘记密码</el-link> -->
+                </el-form-item>
+                <el-button class="login-btn" type="primary" size="default" @click="submitForm()">{{ $t('login') }}</el-button>
+                <!-- <el-form-item > -->
+                  <div style="width: 100%;padding: 0 31%;display: flex;justify-content: space-around;margin-top: 10px; box-sizing: border-box;">
+                    <el-button text type='primary' size="small" @click="setLanguage('en')">English</el-button>
+                    <el-button text type='primary' size="small" @click="setLanguage('es')">Spanish</el-button>
+                  </div>
+                <!-- </el-form-item> -->
+            </el-form>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+// import { usePermissStore } from '@/store/permiss';
+import { useRouter } from 'vue-router';
+import { debounce } from 'lodash';
+import {md5Data} from '@/utils/index';
+import req from '@/utils/request' 
+import { userInfoStore } from '../../store/userInfo';
+import i18n from '@/utils/i18n'
+import { useI18n } from 'vue-i18n';
+const { locale } = useI18n()
+const userInfo = userInfoStore();
+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({
+  account: defParam ? defParam.account : '',
+  loginPwd: defParam ? defParam.loginPwd : ''
+});
+
+const rules = {
+  account: [
+        {
+            required: true,
+            message: i18n.global.t('enterUsername'),
+            trigger: 'blur',
+        },
+    ],
+    loginPwd: [{ required: true, message: i18n.global.t('enterPassword'), trigger: 'blur' }],
+};
+// const permiss = usePermissStore();
+const login = ref(null);
+const setLanguage = (newLang) => {
+  console.log(newLang, 'newLang');
+  
+  locale.value = newLang; 
+};
+const submitForm = debounce(() => {
+    login.value.validate(async (valid) => {
+      if (valid) {
+          const encryptedPassword = md5Data(param.loginPwd);
+        if (typeof encryptedPassword === 'string') {
+          const res = await req('post', '/admin/user/passwordLogin', {...param, loginPwd: encryptedPassword})
+          if (res.code===200) {
+            userInfo.setUserInfo(res.data);
+            if (checked.value) {
+                localStorage.setItem('login-param', JSON.stringify(param));
+            } else {
+                localStorage.removeItem('login-param');
+            }
+            router.push('/');
+          }
+        }
+      }
+    });
+}, 500);
+</script>
+
+<style lang="scss" scoped>
+.login-bg {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100vh;
+    background: url(../../assets/img/login-bg.png) center/cover no-repeat;
+}
+
+.login-header {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 40px;
+}
+
+.logo {
+    width: 35px;
+}
+
+.login-title {
+    font-size: 18px;
+    color: #333;
+    font-weight: bold;
+}
+
+.login-container {
+    width: 450px;
+    border-radius: 5px;
+    background: #ffffffcd;
+    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>

+ 66 - 0
src/views/pages/rule.vue

@@ -0,0 +1,66 @@
+<template>
+  <Group style="height: 100%;">
+    <el-tabs>
+      <el-tab-pane :label="$t('primaryField')">
+        <Ruleform @getPageData="getPageData" :formData="pageData[0]" />
+      </el-tab-pane>
+      <el-tab-pane :label="$t('intermediateField1')">
+        <Ruleform @getPageData="getPageData" :formData="pageData[1]" />
+      </el-tab-pane>
+      <el-tab-pane :label="$t('intermediateField2')">
+        <Ruleform @getPageData="getPageData" :formData="pageData[2]" />
+      </el-tab-pane>
+      <el-tab-pane :label="$t('customRoom')">
+        <el-form :model="formData">
+          <el-form-item>
+            <span style="width: 360px;">{{$t('customizeRoom')}}:</span>
+          </el-form-item>
+          <el-form-item>
+            <div class="row">
+              <span style="width: 280px;">{{$t('customizeRoomRates')}}:</span>
+              <el-input v-model="formData.roomNumber" :placeholder="$t('pleaseEnter')" />
+            </div>
+          </el-form-item>
+        </el-form>
+      </el-tab-pane>
+    </el-tabs>
+  </Group>
+</template>
+
+<script setup name="user">
+import { ref, reactive, onMounted } from 'vue';
+import Group from '@/components/group.vue';
+import Ruleform from '@/components/ruleform.vue';
+import request from '@/utils/request';
+
+const pageData = ref([{}, {}, {}]);
+const formData = reactive({
+  roomNumber: ''
+});
+
+const getPageData = async () => {
+  try {
+    const res = await request('get', '/admin/poker/getPokerGameInfoList');
+    if (res.code === 200) {
+      pageData.value = res.data;
+    } 
+  } catch (error) {
+    console.error('error:', error);
+  }
+};
+
+onMounted(() => {
+  getPageData();
+});
+</script>
+
+<style lang="scss" scoped>
+.deafault {
+  display: flex;
+  align-items: center;
+}
+.row {
+  display: flex;
+  margin-right: 16px;
+}
+</style>

+ 205 - 0
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 lang="scss" 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>

+ 227 - 0
src/views/pages/ucenter.vue

@@ -0,0 +1,227 @@
+<template>
+        <div class="user-container">
+            <group
+                class="user-content"
+                shadow="hover"
+            >
+                <el-tabs tab-position="left" v-model="activeName">
+                    <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-tabs>
+            </group>
+        </div>
+</template>
+
+<script setup 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 group from '@/components/group.vue';
+const name = localStorage.getItem('vuems_name');
+const form = reactive({
+    new1: '',
+    new: '',
+    old: '',
+});
+const onSubmit = () => {};
+
+const activeName = ref('label2');
+
+const avatarImg = ref(avatar);
+const imgSrc = ref(avatar);
+const cropImg = ref('');
+const cropper = ref(null);
+
+const setImage = (e) => {
+    const file = e.target.files[0];
+    if (!file.type.includes('image/')) {
+        return;
+    }
+    const reader = new FileReader();
+    reader.onload = (event) => {
+        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 lang="scss" 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;
+}
+.header-title{
+  &::before{
+    content: '';
+    display: inline-block;
+    width: 3px;
+    height: 18px;
+    background: var(--header-bg-color);
+    /* border-radius: 50%; */
+    vertical-align: middle;
+    margin-right: 8px;
+  }
+}
+.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 lang="scss">
+.el-tabs.el-tabs--left {
+    height: 100%;
+}
+</style>

+ 184 - 0
src/views/pages/user.vue

@@ -0,0 +1,184 @@
+<template>
+  <div 
+  v-loading="loading"
+  :element-loading-text="$t('dataLoading')">
+    <Group>
+    <div style="display: flex;">
+      <el-form style="flex: 1; display: flex;" label-suffix=":" :model="query">
+        <el-form-item :label="$t('name')" style="width: 33%;">
+          <el-input v-model="query.username" :placeholder="$t('userPlaceholder')"></el-input>
+        </el-form-item>
+      </el-form>
+      <el-button type="primary" @click="searchHandler">{{$t('inquire')}}</el-button>
+    </div>
+  </Group>
+  <Group :show-header="false">
+      <Table 
+      :data="tableData"
+      :pagination="pagination"
+      @changePage="changePage"
+      @changePageSize="changePageSize"
+      >
+        <template #table>
+            <!-- <el-table-column type="selection" width="55" /> -->
+            <!-- <el-table-column label="头像" prop="icon">
+              <template #default="scope">
+                <el-avatar :size="60" :src="scope.row.icon?scope.row.icon:'https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png'">
+              </el-avatar>
+              </template>
+            </el-table-column> -->
+            <!-- <el-table-column :label="$t('loginName')" prop="username"></el-table-column> -->
+            <el-table-column :label="$t('nickname')" prop="nickName"></el-table-column>
+            <el-table-column :label="$t('phone')" prop="phone"></el-table-column>
+            <!-- <el-table-column :label="$t('mailbox')" prop="email"></el-table-column> -->
+            <el-table-column :label="$t('registrationTime')" prop="createTime"></el-table-column>
+            <el-table-column :label="$t('coin')" prop="coin"></el-table-column>
+            <el-table-column :label="$t('controls')" width="150">
+              <template #default="scope"> 
+                <div  style="display: flex; flex-direction: column;justify-content: center; align-items: center;">
+                  <el-button text type='primary' size="small"style="margin-left: 12px;" @click="topUp(scope.row)">{{ $t('topUp') }}</el-button>
+                </div>
+              </template>
+            </el-table-column>
+         </template>
+      </Table>
+  </Group>
+  <el-dialog 
+  :title="$t('topUp')"
+  v-model="dialogVisible"
+  append-to-body
+  close-on-click-modal>
+  <el-form :model="formData" ref="formRef" label-suffix=":">
+    <el-form-item :label="$t('topUp')">
+      <el-input v-model="formData.coinValue" :placeholder="$t('pleaseEnter')" clearable ></el-input>
+    </el-form-item>
+  </el-form>
+  <template #footer>
+      <el-button @click="resetForm" size="small">取 消</el-button>
+      <el-button type="primary" @click="submit" size="small">确 定</el-button>
+    </template>
+</el-dialog>
+  </div>
+</template>
+
+<script setup  name="user">
+import { ref, reactive, onMounted} from 'vue';
+import Group from '@/components/group.vue';
+import Table from '@/components/table.vue';
+import request from '@/utils/request';
+import { cloneDeep } from 'lodash';
+import { ElMessage } from 'element-plus';
+// 查询相关
+const query = reactive({
+  username: ''
+});
+const loading = ref(false);
+const dialogVisible = ref(false);
+const tableData = ref([]);
+const formRef = ref(null)
+const formData = reactive({
+  coinValue:''
+})
+let rowClone = {}
+// 表格相关
+const pagination = {
+pageNo: 1,
+pageSize: 10,
+total: 0,
+}
+const changePage = (page) => {
+  pagination.pageNo = page
+  feachTableData()
+}
+const changePageSize = (pageSize) => {
+  pagination.pageSize = pageSize
+  feachTableData()
+}
+const searchHandler = () => {
+  pagination.pageNo = 1
+  feachTableData()
+}
+const resetForm = ()=>{
+  formRef.value.resetFields()
+  dialogVisible.value = false
+  formData.coinValue = ''
+}
+const feachTableData = async() => {
+  loading.value = true
+  const params = {
+      // ...query,
+      ...pagination
+    }
+    try {
+      const res = await request('post', '/admin/user/getUserList', params)
+      if (res.code === 200) {
+        loading.value = false
+        pagination.total = res.data.total
+        tableData.value = res.data.records
+        // tableData.value = [{username:'mock',nickName:'昵称',phone:18688888888,email:'123456@163.com',createTime:'2025-01-16 8:28:56'}]
+      } else {
+        loading.value = false
+      }
+      
+    } catch (error) {
+      console.log(error, 'error');
+      loading.value = false
+    }
+}
+const submit = async() => {
+  console.log(rowClone, 'row');
+  
+  try {
+      const res = await request('post', 'admin/pay/rechargeByHand',{userId:rowClone.id, coin:Number(formData.coinValue)})
+      if (res.code === 200) {
+        resetForm()
+        ElMessage.success(i18n.global.t('successfulOperation'))
+      }
+  } catch (error) {
+    dialogVisible.value = false
+  }
+}
+const topUp = async(row) => {
+  dialogVisible.value = true
+  rowClone = cloneDeep(row)
+  formData.coinValue = row.coin
+}
+onMounted(() => {
+  feachTableData()
+})
+</script>
+
+<style lang="scss" scoped>
+.avatar-uploader .avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+
+</style>
+
+<style lang="scss">
+.el-table th, .el-table td {
+  text-align: center !important;
+}
+.avatar-uploader .el-upload {
+  border: 1px dashed var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: var(--el-color-primary);
+}
+
+.el-icon.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 136px;
+  height: 136px;
+  text-align: center;
+}
+</style>

+ 76 - 0
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 >
+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 = {
+            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) => {
+    return data.filter((item) => {
+        return !menuObj.value[item] || data.toString().includes(menuObj.value[item].toString());
+    });
+};
+// 获取当前权限
+const checkedKeys = ref(checkData(props.permissOptions.permiss));
+
+// 保存权限
+const tree = ref(null);
+const onSubmit = () => {
+    // 获取选中的权限
+    const keys = [...tree.value.getCheckedKeys(false), ...tree.value.getHalfCheckedKeys()];
+    console.log(keys);
+};
+</script>
+
+<style scoped></style>

+ 162 - 0
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([
+    { 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([]);
+const getData = async () => {
+    const res = await fetchRoleData()
+    tableData.value = res.data.list;
+    page.total = res.data.pageTotal;
+};
+getData();
+const changePage = (val) => {
+    page.index = val;
+    getData();
+};
+
+// 新增/编辑弹窗相关
+const options = ref({
+    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) => {
+    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>

+ 148 - 0
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>

+ 10 - 0
src/vite-env.d.ts

@@ -0,0 +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 'nprogress'

+ 23 - 0
tsconfig.json

@@ -0,0 +1,23 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "strict": false,
+    "jsx": "preserve",
+    "allowJs": true,
+    // "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" }]
+}

+ 9 - 0
tsconfig.node.json

@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["vite.config.ts"]
+}

+ 40 - 0
vite.config.ts

@@ -0,0 +1,40 @@
+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",
+	},
+  server: {
+    proxy: {
+      '/admin': {
+        target: 'http://47.122.120.178:6025',  // 目标服务器
+        changeOrigin: true,  // 是否修改请求头中的 origin
+        // rewrite: (path) => path.replace(/^\/api/, ''),  // 重写路径,将 '/api' 移除
+      },
+    },
+  },
+});

+ 1993 - 0
yarn.lock

@@ -0,0 +1,1993 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@antfu/utils@^0.7.0", "@antfu/utils@^0.7.2":
+  version "0.7.10"
+  resolved "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d"
+  integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==
+
+"@babel/helper-string-parser@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
+  integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
+
+"@babel/helper-validator-identifier@^7.25.9":
+  version "7.25.9"
+  resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
+  integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
+
+"@babel/parser@^7.25.3":
+  version "7.26.3"
+  resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
+  integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
+  dependencies:
+    "@babel/types" "^7.26.3"
+
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5":
+  version "7.26.0"
+  resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
+  integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
+  dependencies:
+    regenerator-runtime "^0.14.0"
+
+"@babel/types@^7.26.3":
+  version "7.26.3"
+  resolved "https://registry.npmmirror.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
+  integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
+  dependencies:
+    "@babel/helper-string-parser" "^7.25.9"
+    "@babel/helper-validator-identifier" "^7.25.9"
+
+"@ctrl/tinycolor@^3.4.1":
+  version "3.6.1"
+  resolved "https://registry.npmmirror.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"
+  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"
+  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"
+  integrity sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==
+
+"@floating-ui/core@^1.6.0":
+  version "1.6.8"
+  resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12"
+  integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==
+  dependencies:
+    "@floating-ui/utils" "^0.2.8"
+
+"@floating-ui/dom@^1.0.1":
+  version "1.6.12"
+  resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.6.12.tgz#6333dcb5a8ead3b2bf82f33d6bc410e95f54e556"
+  integrity sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==
+  dependencies:
+    "@floating-ui/core" "^1.6.0"
+    "@floating-ui/utils" "^0.2.8"
+
+"@floating-ui/utils@^0.2.8":
+  version "0.2.8"
+  resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62"
+  integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==
+
+"@intlify/core-base@11.0.1":
+  version "11.0.1"
+  resolved "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.0.1.tgz#f84564a5bd313879b32cea70e6e3d2fe9e1f128b"
+  integrity sha512-NAmhw1l/llM0HZRpagR/ChJTNymW4ll6/4EDSJML5c8L5Hl/+k6UyF8EIgE6DeHpfheQujkSRngauViHqq6jJQ==
+  dependencies:
+    "@intlify/message-compiler" "11.0.1"
+    "@intlify/shared" "11.0.1"
+
+"@intlify/message-compiler@11.0.1":
+  version "11.0.1"
+  resolved "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.0.1.tgz#7c159642e3a3c160dd25a15c17127c69d56b0561"
+  integrity sha512-5RFH8x+Mn3mbjcHXnb6KCXGiczBdiQkWkv99iiA0JpKrNuTAQeW59Pjq/uObMB0eR0shnKYGTkIJxum+DbL3sw==
+  dependencies:
+    "@intlify/shared" "11.0.1"
+    source-map-js "^1.0.2"
+
+"@intlify/shared@11.0.1":
+  version "11.0.1"
+  resolved "https://registry.npmmirror.com/@intlify/shared/-/shared-11.0.1.tgz#25ff7f038bbae903e2bc75bf862b2380fde07cc8"
+  integrity sha512-lH164+aDDptHZ3dBDbIhRa1dOPQUp+83iugpc+1upTOWCnwyC1PVis6rSWNMMJ8VQxvtHQB9JMib48K55y0PvQ==
+
+"@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
+  integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
+
+"@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"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@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"
+  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"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@parcel/watcher-android-arm64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a"
+  integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==
+
+"@parcel/watcher-darwin-arm64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f"
+  integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==
+
+"@parcel/watcher-darwin-x64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb"
+  integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==
+
+"@parcel/watcher-freebsd-x64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82"
+  integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==
+
+"@parcel/watcher-linux-arm-glibc@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42"
+  integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==
+
+"@parcel/watcher-linux-arm-musl@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4"
+  integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==
+
+"@parcel/watcher-linux-arm64-glibc@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03"
+  integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==
+
+"@parcel/watcher-linux-arm64-musl@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732"
+  integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==
+
+"@parcel/watcher-linux-x64-glibc@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d"
+  integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==
+
+"@parcel/watcher-linux-x64-musl@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef"
+  integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==
+
+"@parcel/watcher-win32-arm64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154"
+  integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==
+
+"@parcel/watcher-win32-ia32@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220"
+  integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==
+
+"@parcel/watcher-win32-x64@2.5.0":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7"
+  integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==
+
+"@parcel/watcher@^2.4.1":
+  version "2.5.0"
+  resolved "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10"
+  integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==
+  dependencies:
+    detect-libc "^1.0.3"
+    is-glob "^4.0.3"
+    micromatch "^4.0.5"
+    node-addon-api "^7.0.0"
+  optionalDependencies:
+    "@parcel/watcher-android-arm64" "2.5.0"
+    "@parcel/watcher-darwin-arm64" "2.5.0"
+    "@parcel/watcher-darwin-x64" "2.5.0"
+    "@parcel/watcher-freebsd-x64" "2.5.0"
+    "@parcel/watcher-linux-arm-glibc" "2.5.0"
+    "@parcel/watcher-linux-arm-musl" "2.5.0"
+    "@parcel/watcher-linux-arm64-glibc" "2.5.0"
+    "@parcel/watcher-linux-arm64-musl" "2.5.0"
+    "@parcel/watcher-linux-x64-glibc" "2.5.0"
+    "@parcel/watcher-linux-x64-musl" "2.5.0"
+    "@parcel/watcher-win32-arm64" "2.5.0"
+    "@parcel/watcher-win32-ia32" "2.5.0"
+    "@parcel/watcher-win32-x64" "2.5.0"
+
+"@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"
+  integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
+
+"@rollup/pluginutils@^5.0.2":
+  version "5.1.4"
+  resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a"
+  integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
+  dependencies:
+    "@types/estree" "^1.0.0"
+    estree-walker "^2.0.2"
+    picomatch "^4.0.2"
+
+"@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"
+  integrity sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==
+
+"@types/estree@^1.0.0":
+  version "1.0.6"
+  resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
+  integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
+
+"@types/event-emitter@^0.3.3":
+  version "0.3.5"
+  resolved "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz#ce9b513f72c50dcf0443a12165a93a79ba7a7092"
+  integrity sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==
+
+"@types/lodash-es@^4.17.6":
+  version "4.17.12"
+  resolved "https://registry.npmmirror.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.17.13"
+  resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb"
+  integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==
+
+"@types/trusted-types@^2.0.7":
+  version "2.0.7"
+  resolved "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
+  integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
+
+"@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"
+  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"
+  integrity sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==
+  dependencies:
+    "@uppy/utils" "^4.1.2"
+    namespace-emitter "^2.0.1"
+
+"@uppy/core@^2.1.1":
+  version "2.3.4"
+  resolved "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz#260b85b6bf3aa03cdc67da231f8c69cfbfdcc84a"
+  integrity sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==
+  dependencies:
+    "@transloadit/prettier-bytes" "0.0.7"
+    "@uppy/store-default" "^2.1.1"
+    "@uppy/utils" "^4.1.3"
+    lodash.throttle "^4.1.1"
+    mime-match "^1.0.2"
+    namespace-emitter "^2.0.1"
+    nanoid "^3.1.25"
+    preact "^10.5.13"
+
+"@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"
+  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"
+  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"
+  integrity sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==
+  dependencies:
+    "@uppy/companion-client" "^2.2.2"
+    "@uppy/utils" "^4.1.2"
+    nanoid "^3.1.25"
+
+"@videojs/http-streaming@2.16.3":
+  version "2.16.3"
+  resolved "https://registry.npmmirror.com/@videojs/http-streaming/-/http-streaming-2.16.3.tgz#d9b460c3716436327dbab4b1faeb2a767f05dcef"
+  integrity sha512-91CJv5PnFBzNBvyEjt+9cPzTK/xoVixARj2g7ZAvItA+5bx8VKdk5RxCz/PP2kdzz9W+NiDUMPkdmTsosmy69Q==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    "@videojs/vhs-utils" "3.0.5"
+    aes-decrypter "3.1.3"
+    global "^4.4.0"
+    m3u8-parser "4.8.0"
+    mpd-parser "^0.22.1"
+    mux.js "6.0.1"
+    video.js "^6 || ^7"
+
+"@videojs/vhs-utils@3.0.5", "@videojs/vhs-utils@^3.0.4", "@videojs/vhs-utils@^3.0.5":
+  version "3.0.5"
+  resolved "https://registry.npmmirror.com/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz#665ba70d78258ba1ab977364e2fe9f4d4799c46c"
+  integrity sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    global "^4.4.0"
+    url-toolkit "^2.2.1"
+
+"@videojs/xhr@2.6.0":
+  version "2.6.0"
+  resolved "https://registry.npmmirror.com/@videojs/xhr/-/xhr-2.6.0.tgz#cd897e0ad54faf497961bcce3fa16dc15a26bb80"
+  integrity sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    global "~4.4.0"
+    is-function "^1.0.1"
+
+"@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"
+  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"
+  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"
+  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"
+  integrity sha512-tzj7AoarFBKl7e41MR006ncrEmNPHALuk8aG4WdDIaG387X5//5KhWC5Ff3ZfB2InGSeNT+CVUd74M0gS20rjA==
+  dependencies:
+    "@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@0.38.9":
+  version "0.38.9"
+  resolved "https://registry.npmmirror.com/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz#e5dfdc6f0d6dbea683647cd477fafbd483983b35"
+  integrity sha512-iJMQGU91ADi98u8V1vXd2UBmELDAaeSP0ZJaFjwosClQdKlJQYc6MlxxKfXBZisHqfbhdtrGRyaryulnYtliZw==
+  dependencies:
+    "@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@3.5.13", "@vue/compiler-core@^3.2.37":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz#b0ae6c4347f60c03e849a05d34e5bf747c9bda05"
+  integrity sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==
+  dependencies:
+    "@babel/parser" "^7.25.3"
+    "@vue/shared" "3.5.13"
+    entities "^4.5.0"
+    estree-walker "^2.0.2"
+    source-map-js "^1.2.0"
+
+"@vue/compiler-dom@3.5.13", "@vue/compiler-dom@^3.2.37":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz#bb1b8758dbc542b3658dda973b98a1c9311a8a58"
+  integrity sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==
+  dependencies:
+    "@vue/compiler-core" "3.5.13"
+    "@vue/shared" "3.5.13"
+
+"@vue/compiler-sfc@3.5.13", "@vue/compiler-sfc@^3.1.2", "@vue/compiler-sfc@^3.2.29", "@vue/compiler-sfc@^3.2.37":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz#461f8bd343b5c06fac4189c4fef8af32dea82b46"
+  integrity sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==
+  dependencies:
+    "@babel/parser" "^7.25.3"
+    "@vue/compiler-core" "3.5.13"
+    "@vue/compiler-dom" "3.5.13"
+    "@vue/compiler-ssr" "3.5.13"
+    "@vue/shared" "3.5.13"
+    estree-walker "^2.0.2"
+    magic-string "^0.30.11"
+    postcss "^8.4.48"
+    source-map-js "^1.2.0"
+
+"@vue/compiler-ssr@3.5.13":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz#e771adcca6d3d000f91a4277c972a996d07f43ba"
+  integrity sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==
+  dependencies:
+    "@vue/compiler-dom" "3.5.13"
+    "@vue/shared" "3.5.13"
+
+"@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.6.3", "@vue/devtools-api@^6.6.4":
+  version "6.6.4"
+  resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343"
+  integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==
+
+"@vue/reactivity@3.5.13", "@vue/reactivity@^3.2.37":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz#b41ff2bb865e093899a22219f5b25f97b6fe155f"
+  integrity sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==
+  dependencies:
+    "@vue/shared" "3.5.13"
+
+"@vue/runtime-core@3.5.13":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz#1fafa4bf0b97af0ebdd9dbfe98cd630da363a455"
+  integrity sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==
+  dependencies:
+    "@vue/reactivity" "3.5.13"
+    "@vue/shared" "3.5.13"
+
+"@vue/runtime-dom@3.5.13":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz#610fc795de9246300e8ae8865930d534e1246215"
+  integrity sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==
+  dependencies:
+    "@vue/reactivity" "3.5.13"
+    "@vue/runtime-core" "3.5.13"
+    "@vue/shared" "3.5.13"
+    csstype "^3.1.3"
+
+"@vue/server-renderer@3.5.13":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz#429ead62ee51de789646c22efe908e489aad46f7"
+  integrity sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==
+  dependencies:
+    "@vue/compiler-ssr" "3.5.13"
+    "@vue/shared" "3.5.13"
+
+"@vue/shared@3.5.13", "@vue/shared@^3.2.37":
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f"
+  integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
+
+"@vueuse/core@^9.1.0":
+  version "9.13.0"
+  resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
+  integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
+  dependencies:
+    "@types/web-bluetooth" "^0.0.16"
+    "@vueuse/metadata" "9.13.0"
+    "@vueuse/shared" "9.13.0"
+    vue-demi "*"
+
+"@vueuse/metadata@9.13.0":
+  version "9.13.0"
+  resolved "https://registry.npmmirror.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"
+  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"
+  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"
+  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"
+  integrity sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==
+  dependencies:
+    "@types/event-emitter" "^0.3.3"
+    event-emitter "^0.3.5"
+    html-void-elements "^2.0.0"
+    i18next "^20.4.0"
+    scroll-into-view-if-needed "^2.2.28"
+    slate-history "^0.66.0"
+
+"@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"
+  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"
+  integrity sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==
+  dependencies:
+    "@uppy/core" "^2.1.1"
+    "@uppy/xhr-upload" "^2.0.3"
+    "@wangeditor/basic-modules" "^1.1.7"
+    "@wangeditor/code-highlight" "^1.0.3"
+    "@wangeditor/core" "^1.1.19"
+    "@wangeditor/list-module" "^1.0.5"
+    "@wangeditor/table-module" "^1.1.4"
+    "@wangeditor/upload-image-module" "^1.0.2"
+    "@wangeditor/video-module" "^1.1.4"
+    dom7 "^3.0.0"
+    is-hotkey "^0.2.0"
+    lodash.camelcase "^4.3.0"
+    lodash.clonedeep "^4.5.0"
+    lodash.debounce "^4.0.8"
+    lodash.foreach "^4.5.0"
+    lodash.isequal "^4.5.0"
+    lodash.throttle "^4.1.1"
+    lodash.toarray "^4.4.0"
+    nanoid "^3.2.0"
+    slate "^0.72.0"
+    snabbdom "^3.1.0"
+
+"@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"
+  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"
+  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"
+  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"
+  integrity sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==
+
+"@xmldom/xmldom@^0.8.3":
+  version "0.8.10"
+  resolved "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
+  integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
+
+acorn@^8.10.0, acorn@^8.14.0:
+  version "8.14.0"
+  resolved "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
+  integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
+
+aes-decrypter@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/aes-decrypter/-/aes-decrypter-1.0.3.tgz#9c06b8a5435a5ad09db933f8a014afcf184cc34e"
+  integrity sha512-rsx8pfx7wJsn+ziYbpJ8XA5c93hKAtBCrfydxJqJCMT+qfjipd/B5wC2xHtBcoxyvlqJcpeAo3K55t0lXOn9yQ==
+  dependencies:
+    pkcs7 "^0.2.3"
+
+aes-decrypter@3.1.3:
+  version "3.1.3"
+  resolved "https://registry.npmmirror.com/aes-decrypter/-/aes-decrypter-3.1.3.tgz#65ff5f2175324d80c41083b0e135d1464b12ac35"
+  integrity sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    "@videojs/vhs-utils" "^3.0.5"
+    global "^4.4.0"
+    pkcs7 "^1.0.4"
+
+anymatch@~3.1.2:
+  version "3.1.3"
+  resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+  integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
+async-validator@^4.2.5:
+  version "4.2.5"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.6.3:
+  version "1.7.9"
+  resolved "https://registry.npmmirror.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a"
+  integrity sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==
+  dependencies:
+    follow-redirects "^1.15.6"
+    form-data "^4.0.0"
+    proxy-from-env "^1.1.0"
+
+babel-runtime@^6.9.2:
+  version "6.26.0"
+  resolved "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+binary-extensions@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
+braces@^3.0.3, braces@~3.0.2:
+  version "3.0.3"
+  resolved "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+  integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+  dependencies:
+    fill-range "^7.1.1"
+
+china-division@^2.7.0:
+  version "2.7.0"
+  resolved "https://registry.npmmirror.com/china-division/-/china-division-2.7.0.tgz#4060a4d243be66c7833dea64a48a4038f3e53e74"
+  integrity sha512-4uUPAT+1WfqDh5jytq7omdCmHNk3j+k76zEG/2IqaGcYB90c2SwcixttcypdsZ3T/9tN1TTpBDoeZn+Yw/qBEA==
+
+chokidar@^3.5.3:
+  version "3.6.0"
+  resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+  integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
+  dependencies:
+    anymatch "~3.1.2"
+    braces "~3.0.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"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+chokidar@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
+  integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
+  dependencies:
+    readdirp "^4.0.1"
+
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
+
+confbox@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06"
+  integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==
+
+core-js@^2.4.0:
+  version "2.6.12"
+  resolved "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+  integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
+
+countup.js@^2.8.0:
+  version "2.8.0"
+  resolved "https://registry.npmmirror.com/countup.js/-/countup.js-2.8.0.tgz#64951f2df3ede28839413d654d8fef28251c32a8"
+  integrity sha512-f7xEhX0awl4NOElHulrl4XRfKoNH3rB+qfNSZZyjSZhaAoUk6elvhH+MNxMmlmuUJ2/QNTWPSA7U4mNtIAKljQ==
+
+csstype@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+  integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+d@1, d@^1.0.1, d@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de"
+  integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
+  dependencies:
+    es5-ext "^0.10.64"
+    type "^2.7.2"
+
+dayjs@^1.11.13:
+  version "1.11.13"
+  resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
+  integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
+
+debug@^4.3.4:
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
+  integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
+  dependencies:
+    ms "^2.1.3"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+detect-libc@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+  integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
+
+dom-walk@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.npmmirror.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
+  integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
+
+dom7@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz#b861ce5d67a6becd7aaa3ad02942ff14b1240331"
+  integrity sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==
+  dependencies:
+    ssr-window "^3.0.0-alpha.1"
+
+dompurify@^3.2.3:
+  version "3.2.3"
+  resolved "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.3.tgz#05dd2175225324daabfca6603055a09b2382a4cd"
+  integrity sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==
+  optionalDependencies:
+    "@types/trusted-types" "^2.0.7"
+
+echarts-wordcloud@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz#c3de6fe267044f6c3343e4ff0e05eedb01c05096"
+  integrity sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ==
+
+echarts@^5.5.0:
+  version "5.6.0"
+  resolved "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6"
+  integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==
+  dependencies:
+    tslib "2.3.0"
+    zrender "5.6.1"
+
+element-china-area-data@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.npmmirror.com/element-china-area-data/-/element-china-area-data-6.1.0.tgz#f14b90c0762b21432e097ed5be8423514a0b57e3"
+  integrity sha512-IkpcjwQv2A/2AxFiSoaISZ+oMw1rZCPUSOg5sOCwT5jKc96TaawmKZeY81xfxXsO0QbKxU5LLc6AirhG52hUmg==
+  dependencies:
+    china-division "^2.7.0"
+
+element-plus@^2.6.3:
+  version "2.9.1"
+  resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.1.tgz#00cac40abaafe8806fc77b2552050e14a7693680"
+  integrity sha512-9Agqf/jt4Ugk7EZ6C5LME71sgkvauPCsnvJN12Xid2XVobjufxMGpRE4L7pS4luJMOmFAH3J0NgYEGZT5r+NDg==
+  dependencies:
+    "@ctrl/tinycolor" "^3.4.1"
+    "@element-plus/icons-vue" "^2.3.1"
+    "@floating-ui/dom" "^1.0.1"
+    "@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.13"
+    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"
+
+entities@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+  integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+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.npmmirror.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"
+
+es5-shim@^4.5.1:
+  version "4.6.7"
+  resolved "https://registry.npmmirror.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955"
+  integrity sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==
+
+es6-iterator@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+  integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==
+  dependencies:
+    d "1"
+    es5-ext "^0.10.35"
+    es6-symbol "^3.1.1"
+
+es6-promise@^4.2.8:
+  version "4.2.8"
+  resolved "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+  integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
+es6-symbol@^3.1.1, es6-symbol@^3.1.3:
+  version "3.1.4"
+  resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz#f4e7d28013770b4208ecbf3e0bf14d3bcb557b8c"
+  integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==
+  dependencies:
+    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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  integrity sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==
+
+esbuild@^0.15.9:
+  version "0.15.18"
+  resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.15.18.tgz#ea894adaf3fbc036d32320a00d4d6e4978a2f36d"
+  integrity sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==
+  optionalDependencies:
+    "@esbuild/android-arm" "0.15.18"
+    "@esbuild/linux-loong64" "0.15.18"
+    esbuild-android-64 "0.15.18"
+    esbuild-android-arm64 "0.15.18"
+    esbuild-darwin-64 "0.15.18"
+    esbuild-darwin-arm64 "0.15.18"
+    esbuild-freebsd-64 "0.15.18"
+    esbuild-freebsd-arm64 "0.15.18"
+    esbuild-linux-32 "0.15.18"
+    esbuild-linux-64 "0.15.18"
+    esbuild-linux-arm "0.15.18"
+    esbuild-linux-arm64 "0.15.18"
+    esbuild-linux-mips64le "0.15.18"
+    esbuild-linux-ppc64le "0.15.18"
+    esbuild-linux-riscv64 "0.15.18"
+    esbuild-linux-s390x "0.15.18"
+    esbuild-netbsd-64 "0.15.18"
+    esbuild-openbsd-64 "0.15.18"
+    esbuild-sunos-64 "0.15.18"
+    esbuild-windows-32 "0.15.18"
+    esbuild-windows-64 "0.15.18"
+    esbuild-windows-arm64 "0.15.18"
+
+escape-html@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
+
+esniff@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.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"
+  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"
+  integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+
+ext@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.npmmirror.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.3.2"
+  resolved "https://registry.npmmirror.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"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fastq@^1.6.0:
+  version "1.18.0"
+  resolved "https://registry.npmmirror.com/fastq/-/fastq-1.18.0.tgz#d631d7e25faffea81887fe5ea8c9010e1b36fee0"
+  integrity sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==
+  dependencies:
+    reusify "^1.0.4"
+
+fill-range@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+  integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+flv.js@^1.6.2:
+  version "1.6.2"
+  resolved "https://registry.npmmirror.com/flv.js/-/flv.js-1.6.2.tgz#fa3340fe3f7ee01d3977f7876aee66b8436e5922"
+  integrity sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==
+  dependencies:
+    es6-promise "^4.2.8"
+    webworkify-webpack "^2.1.5"
+
+follow-redirects@^1.15.6:
+  version "1.15.9"
+  resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
+  integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
+
+form-data@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48"
+  integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
+fsevents@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+  integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+global@4.3.2, global@~4.3.0:
+  version "4.3.2"
+  resolved "https://registry.npmmirror.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
+  integrity sha512-/4AybdwIDU4HkCUbJkZdWpe4P6vuw/CUtu+0I1YlLIPe7OlUO7KNJ+q/rO70CW2/NW6Jc6I62++Hzsf5Alu6rQ==
+  dependencies:
+    min-document "^2.19.0"
+    process "~0.5.1"
+
+global@^4.3.0, global@^4.3.1, global@^4.4.0, global@~4.4.0:
+  version "4.4.0"
+  resolved "https://registry.npmmirror.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
+  integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
+  dependencies:
+    min-document "^2.19.0"
+    process "^0.11.10"
+
+hasown@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+  integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+  dependencies:
+    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"
+  integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==
+
+i18next@^20.4.0:
+  version "20.6.1"
+  resolved "https://registry.npmmirror.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.21"
+  resolved "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+  integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+immutable@^5.0.2:
+  version "5.0.3"
+  resolved "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz#aa037e2313ea7b5d400cd9298fa14e404c933db1"
+  integrity sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==
+
+individual@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmmirror.com/individual/-/individual-2.0.0.tgz#833b097dad23294e76117a98fb38e0d9ad61bb97"
+  integrity sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g==
+
+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"
+  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+  dependencies:
+    binary-extensions "^2.0.0"
+
+is-core-module@^2.16.0:
+  version "2.16.1"
+  resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
+  integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
+  dependencies:
+    hasown "^2.0.2"
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-function@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08"
+  integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+  version "4.0.3"
+  resolved "https://registry.npmmirror.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"
+  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"
+  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"
+  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"
+  integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
+
+js-md5@^0.8.3:
+  version "0.8.3"
+  resolved "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz#921bab7efa95bfc9d62b87ee08a57f8fe4305b69"
+  integrity sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==
+
+jsencrypt@^3.3.2:
+  version "3.3.2"
+  resolved "https://registry.npmmirror.com/jsencrypt/-/jsencrypt-3.3.2.tgz#b0f1a2278810c7ba1cb8957af11195354622df7c"
+  integrity sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==
+
+keycode@^2.2.0:
+  version "2.2.1"
+  resolved "https://registry.npmmirror.com/keycode/-/keycode-2.2.1.tgz#09c23b2be0611d26117ea2501c2c391a01f39eff"
+  integrity sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==
+
+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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  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"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+m3u8-parser@2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/m3u8-parser/-/m3u8-parser-2.1.0.tgz#c8170329ec1cd515d0d58bb8b762da9896cb0368"
+  integrity sha512-WbEpQ2FUaNGbJ0YanSeyj9D9ruu4FUvz+ZvebIzI2bSME+PUwcPXO1kKXZkjcPUAFruDikoOI5fWQNIA6JCCOQ==
+
+m3u8-parser@4.8.0:
+  version "4.8.0"
+  resolved "https://registry.npmmirror.com/m3u8-parser/-/m3u8-parser-4.8.0.tgz#4a2d591fdf6f2579d12a327081198df8af83083d"
+  integrity sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    "@videojs/vhs-utils" "^3.0.5"
+    global "^4.4.0"
+
+magic-string@^0.25.7:
+  version "0.25.9"
+  resolved "https://registry.npmmirror.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"
+  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"
+  integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
+  dependencies:
+    "@jridgewell/sourcemap-codec" "^1.4.13"
+
+magic-string@^0.30.11:
+  version "0.30.17"
+  resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
+  integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
+  dependencies:
+    "@jridgewell/sourcemap-codec" "^1.5.0"
+
+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"
+  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"
+  integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
+
+merge2@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4, micromatch@^4.0.5:
+  version "4.0.8"
+  resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+  integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+  dependencies:
+    braces "^3.0.3"
+    picomatch "^2.3.1"
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.npmmirror.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"
+  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"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
+min-document@^2.19.0:
+  version "2.19.0"
+  resolved "https://registry.npmmirror.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
+  integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==
+  dependencies:
+    dom-walk "^0.1.0"
+
+minimatch@^5.1.1:
+  version "5.1.6"
+  resolved "https://registry.npmmirror.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.7.3:
+  version "1.7.3"
+  resolved "https://registry.npmmirror.com/mlly/-/mlly-1.7.3.tgz#d86c0fcd8ad8e16395eb764a5f4b831590cee48c"
+  integrity sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==
+  dependencies:
+    acorn "^8.14.0"
+    pathe "^1.1.2"
+    pkg-types "^1.2.1"
+    ufo "^1.5.4"
+
+mpd-parser@0.22.1, mpd-parser@^0.22.1:
+  version "0.22.1"
+  resolved "https://registry.npmmirror.com/mpd-parser/-/mpd-parser-0.22.1.tgz#bc2bf7d3e56368e4b0121035b055675401871521"
+  integrity sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    "@videojs/vhs-utils" "^3.0.5"
+    "@xmldom/xmldom" "^0.8.3"
+    global "^4.4.0"
+
+ms@^2.1.3:
+  version "2.1.3"
+  resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+mux.js@4.3.2:
+  version "4.3.2"
+  resolved "https://registry.npmmirror.com/mux.js/-/mux.js-4.3.2.tgz#576d537df037dc5ec35ec1316b948d815d35c210"
+  integrity sha512-g0q6DPdvb3yYcoK7ElBGobdSSrhY/RjPt19U7uUc733aqvc5bCS/aCvL9z+448y+IoCZnYDwyZfQBBXMSmGOaQ==
+
+mux.js@6.0.1:
+  version "6.0.1"
+  resolved "https://registry.npmmirror.com/mux.js/-/mux.js-6.0.1.tgz#65ce0f7a961d56c006829d024d772902d28c7755"
+  integrity sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w==
+  dependencies:
+    "@babel/runtime" "^7.11.2"
+    global "^4.4.0"
+
+namespace-emitter@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.npmmirror.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.7:
+  version "3.3.8"
+  resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
+  integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
+
+next-tick@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
+  integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
+
+node-addon-api@^7.0.0:
+  version "7.1.1"
+  resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
+  integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
+
+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"
+  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"
+  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"
+  integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==
+
+parse-headers@^2.0.0:
+  version "2.0.5"
+  resolved "https://registry.npmmirror.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9"
+  integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+pathe@^1.0.0, pathe@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec"
+  integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==
+
+picocolors@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
+  integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
+
+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"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+picomatch@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
+  integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
+
+pinia@^2.1.7:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.com/pinia/-/pinia-2.3.0.tgz#b81f4ac7da1031af8d8f7007686c4b2799a55b9f"
+  integrity sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==
+  dependencies:
+    "@vue/devtools-api" "^6.6.3"
+    vue-demi "^0.14.10"
+
+pkcs7@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.npmmirror.com/pkcs7/-/pkcs7-0.2.3.tgz#22d60666d01065c5f24439098e4a4830452273be"
+  integrity sha512-kJRwmADEQUg+qJyRgWLtpEL9q9cFjZschejTEK3GRjKvnsU9G5WWoe/wKqRgbBoqWdVSeTUKP6vIA3Y72M3rWA==
+
+pkcs7@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.npmmirror.com/pkcs7/-/pkcs7-1.0.4.tgz#6090b9e71160dabf69209d719cbafa538b00a1cb"
+  integrity sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+
+pkg-types@^1.0.1, pkg-types@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.0.tgz#53d915eb99485798c554ad8eb2dc2af7c03006eb"
+  integrity sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==
+  dependencies:
+    confbox "^0.1.8"
+    mlly "^1.7.3"
+    pathe "^1.1.2"
+
+postcss@^8.4.18, postcss@^8.4.48:
+  version "8.4.49"
+  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19"
+  integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==
+  dependencies:
+    nanoid "^3.3.7"
+    picocolors "^1.1.1"
+    source-map-js "^1.2.1"
+
+preact@^10.5.13:
+  version "10.25.4"
+  resolved "https://registry.npmmirror.com/preact/-/preact-10.25.4.tgz#c1d00bee9d7b9dcd06a2311d9951973b506ae8ac"
+  integrity sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==
+
+prismjs@^1.23.0:
+  version "1.29.0"
+  resolved "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
+  integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
+
+process@^0.11.10:
+  version "0.11.10"
+  resolved "https://registry.npmmirror.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+  integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
+
+process@~0.5.1:
+  version "0.5.2"
+  resolved "https://registry.npmmirror.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
+  integrity sha512-oNpcutj+nYX2FjdEW7PGltWhXulAnFlM0My/k48L90hARCOJtvBbQXc/6itV2jDvU5xAAtonP+r6wmQgCcbAUA==
+
+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"
+  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"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+readdirp@^4.0.1:
+  version "4.0.2"
+  resolved "https://registry.npmmirror.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
+  integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==
+
+readdirp@~3.6.0:
+  version "3.6.0"
+  resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+  dependencies:
+    picomatch "^2.2.1"
+
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-runtime@^0.14.0:
+  version "0.14.1"
+  resolved "https://registry.npmmirror.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.npmmirror.com/resize-detector/-/resize-detector-0.3.0.tgz#fe495112e184695500a8f51e0389f15774cb1cfc"
+  integrity sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ==
+
+resolve@^1.22.1:
+  version "1.22.10"
+  resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
+  integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
+  dependencies:
+    is-core-module "^2.16.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"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rollup@^2.79.1:
+  version "2.79.2"
+  resolved "https://registry.npmmirror.com/rollup/-/rollup-2.79.2.tgz#f150e4a5db4b121a21a747d762f701e5e9f49090"
+  integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==
+  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"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
+rust-result@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/rust-result/-/rust-result-1.0.0.tgz#34c75b2e6dc39fe5875e5bdec85b5e0f91536f72"
+  integrity sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==
+  dependencies:
+    individual "^2.0.0"
+
+safe-json-parse@4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/safe-json-parse/-/safe-json-parse-4.0.0.tgz#7c0f578cfccd12d33a71c0e05413e2eca171eaac"
+  integrity sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==
+  dependencies:
+    rust-result "^1.0.0"
+
+sass@^1.82.0:
+  version "1.83.0"
+  resolved "https://registry.npmmirror.com/sass/-/sass-1.83.0.tgz#e36842c0b88a94ed336fd16249b878a0541d536f"
+  integrity sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==
+  dependencies:
+    chokidar "^4.0.0"
+    immutable "^5.0.2"
+    source-map-js ">=0.6.2 <2.0.0"
+  optionalDependencies:
+    "@parcel/watcher" "^2.4.1"
+
+schart.js@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
+  dependencies:
+    compute-scroll-into-view "^1.0.20"
+
+scule@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.npmmirror.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"
+  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"
+  integrity sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==
+  dependencies:
+    immer "^9.0.6"
+    is-plain-object "^5.0.0"
+    tiny-warning "^1.0.3"
+
+snabbdom@^3.1.0:
+  version "3.6.2"
+  resolved "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz#57dd66878f6320497fa7f67941df356a045c75a1"
+  integrity sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==
+
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0, source-map-js@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
+  integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+
+sourcemap-codec@^1.4.8:
+  version "1.4.8"
+  resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
+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"
+  integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
+
+strip-literal@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07"
+  integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==
+  dependencies:
+    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"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+svgaplayerweb@^2.3.2:
+  version "2.3.2"
+  resolved "https://registry.npmmirror.com/svgaplayerweb/-/svgaplayerweb-2.3.2.tgz#15595b8dcc20cf4de4adc3103970b7cf5ae19a84"
+  integrity sha512-QuTvNIgy3W6Mi4h74SczEHUtAwb8m3ax7Ai7xRLUuN6hjJh49RGtWOWq1IuF2I7ECcl0HAYn8FcTn99UDz9UiQ==
+
+tiny-warning@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+tslib@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
+  integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
+
+tsml@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/tsml/-/tsml-1.0.1.tgz#89f8218b9d9e257f47d7f6b56d01c5a4d2c68fc3"
+  integrity sha512-3KmepnH9SUsoOVtg013CRrL7c+AK7ECaquAsJdvu4288EDJuraqBlP4PDXT/rLEJ9YDn4jqLAzRJsnFPx+V6lg==
+
+type@^2.7.2:
+  version "2.7.3"
+  resolved "https://registry.npmmirror.com/type/-/type-2.7.3.tgz#436981652129285cc3ba94f392886c2637ea0486"
+  integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==
+
+typescript@^4.6.4:
+  version "4.9.5"
+  resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+  integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+
+ufo@^1.5.4:
+  version "1.5.4"
+  resolved "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754"
+  integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==
+
+unimport@^1.0.1:
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/unimport/-/unimport-1.3.0.tgz#167ab78e60ea0e36a9a764c7b608ee95d7b2411c"
+  integrity sha512-fOkrdxglsHd428yegH0wPH/6IfaSdDeMXtdRGn6en/ccyzc2aaoxiUTMrJyc6Bu+xoa18RJRPMfLUHEzjz8atw==
+  dependencies:
+    "@rollup/pluginutils" "^5.0.2"
+    escape-string-regexp "^5.0.0"
+    fast-glob "^3.2.12"
+    local-pkg "^0.4.3"
+    magic-string "^0.27.0"
+    mlly "^1.1.0"
+    pathe "^1.0.0"
+    pkg-types "^1.0.1"
+    scule "^1.0.0"
+    strip-literal "^1.0.0"
+    unplugin "^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"
+  integrity sha512-nvbL2AQwLRR8wbHpJ6L1EBVNmjN045RSedTa4NtsGRkSQFXkI1iKHs4dTqJwcKZsnFrZOAKtLPiN1/oQTObLZw==
+  dependencies:
+    "@antfu/utils" "^0.7.0"
+    "@rollup/pluginutils" "^5.0.2"
+    local-pkg "^0.4.2"
+    magic-string "^0.26.7"
+    unimport "^1.0.1"
+    unplugin "^1.0.0"
+
+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"
+  integrity sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==
+  dependencies:
+    "@antfu/utils" "^0.7.2"
+    "@rollup/pluginutils" "^5.0.2"
+    chokidar "^3.5.3"
+    debug "^4.3.4"
+    fast-glob "^3.2.12"
+    local-pkg "^0.4.2"
+    magic-string "^0.27.0"
+    minimatch "^5.1.1"
+    resolve "^1.22.1"
+    unplugin "^1.0.1"
+
+unplugin@^1.0.0, unplugin@^1.0.1:
+  version "1.16.0"
+  resolved "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.0.tgz#ca0f248bf8798cd752dd02e5b381223b737cef72"
+  integrity sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==
+  dependencies:
+    acorn "^8.14.0"
+    webpack-virtual-modules "^0.6.2"
+
+url-toolkit@^2.1.3, url-toolkit@^2.2.1:
+  version "2.2.5"
+  resolved "https://registry.npmmirror.com/url-toolkit/-/url-toolkit-2.2.5.tgz#58406b18e12c58803e14624df5e374f638b0f607"
+  integrity sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==
+
+video.js@7, "video.js@^6 || ^7":
+  version "7.21.6"
+  resolved "https://registry.npmmirror.com/video.js/-/video.js-7.21.6.tgz#a42d817c42d8d91538b72197a0874aeb01c76ce9"
+  integrity sha512-m41TbODrUCToVfK1aljVd296CwDQnCRewpIm5tTXMuV87YYSGw1H+VDOaV45HlpcWSsTWWLF++InDgGJfthfUw==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    "@videojs/http-streaming" "2.16.3"
+    "@videojs/vhs-utils" "^3.0.4"
+    "@videojs/xhr" "2.6.0"
+    aes-decrypter "3.1.3"
+    global "^4.4.0"
+    keycode "^2.2.0"
+    m3u8-parser "4.8.0"
+    mpd-parser "0.22.1"
+    mux.js "6.0.1"
+    safe-json-parse "4.0.0"
+    videojs-font "3.2.0"
+    videojs-vtt.js "^0.15.5"
+
+"video.js@^5.17.0 || ^6.2.0", "video.js@^5.19.1 || ^6.2.0":
+  version "6.13.0"
+  resolved "https://registry.npmmirror.com/video.js/-/video.js-6.13.0.tgz#f9487d46327340fa48ecd51372a2981dbb6cde4c"
+  integrity sha512-36/JR/GhPQSZj0o+GNbhcEYv/b0SkV9SQsjlodAnzMQYN0TA7VhmqrKPYMCi1NGRYu7S9W3OaFCFoUxkYfSVlg==
+  dependencies:
+    babel-runtime "^6.9.2"
+    global "4.3.2"
+    safe-json-parse "4.0.0"
+    tsml "1.0.1"
+    videojs-font "2.1.0"
+    videojs-ie8 "1.1.2"
+    videojs-vtt.js "0.12.6"
+    xhr "2.4.0"
+
+videojs-contrib-hls@^5.15.0:
+  version "5.15.0"
+  resolved "https://registry.npmmirror.com/videojs-contrib-hls/-/videojs-contrib-hls-5.15.0.tgz#fe4957367e5d68b7d23f78ed32e37a9dd892a0a8"
+  integrity sha512-18zbMYZ0XRBKTPEayA9bFTWWrqhT9b4G8+zf0czJLD7Epe5PcK1I/3dflTHQeQ5rwlWir+/XnFU3sMg/B2MMcw==
+  dependencies:
+    aes-decrypter "1.0.3"
+    global "^4.3.0"
+    m3u8-parser "2.1.0"
+    mux.js "4.3.2"
+    url-toolkit "^2.1.3"
+    video.js "^5.19.1 || ^6.2.0"
+    videojs-contrib-media-sources "4.7.2"
+    webwackify "0.1.6"
+
+videojs-contrib-media-sources@4.7.2:
+  version "4.7.2"
+  resolved "https://registry.npmmirror.com/videojs-contrib-media-sources/-/videojs-contrib-media-sources-4.7.2.tgz#0adf929107d5b74cf2c8abb2824c82177e43858e"
+  integrity sha512-e6iCHWBFuV05EGo7v+pS9iepObXnJ9joms467gzi8ZjpKVb3ifha9M0Ja24Rd8JfvYpzjltsgDVtGFDvIg4hQQ==
+  dependencies:
+    global "^4.3.0"
+    mux.js "4.3.2"
+    video.js "^5.17.0 || ^6.2.0"
+    webwackify "0.1.6"
+
+videojs-flash@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.npmmirror.com/videojs-flash/-/videojs-flash-2.2.1.tgz#1a225dbb1ced200ae9bbf15e01fe4a61086d90f1"
+  integrity sha512-mHu6TD12EKkxMvr8tg4AcfV/DuVLff427nneoZom3N9Dd2bv0sJOWwdLPQH1v5BCuAuXAVuAOba56ovTl+G3tQ==
+  dependencies:
+    global "^4.4.0"
+    video.js "^6 || ^7"
+    videojs-swf "5.4.2"
+
+videojs-flvjs-es6@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/videojs-flvjs-es6/-/videojs-flvjs-es6-1.0.1.tgz#eb629c5ef0d1c5aafa89bc4a7714e5091a9a872e"
+  integrity sha512-wAI5ff2tZVW+uftTLyPmS38F4SHmMlxqBFOgXEBqMs2X0N4uIVQK0iCCv5XACXH+oc+mP70D23mJmT8KsoHx0g==
+
+videojs-font@2.1.0:
+  version "2.1.0"
+  resolved "https://registry.npmmirror.com/videojs-font/-/videojs-font-2.1.0.tgz#a25930a67f6c9cfbf2bb88dacb8c6b451f093379"
+  integrity sha512-zFqWpLrXf1q8NtYx5qtZhMC6SLUFScDmR6j+UGPogobxR21lvXShhnzcNNMdOxJUuFLiToJ/BPpFUQwX4xhpvA==
+
+videojs-font@3.2.0:
+  version "3.2.0"
+  resolved "https://registry.npmmirror.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232"
+  integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==
+
+videojs-ie8@1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/videojs-ie8/-/videojs-ie8-1.1.2.tgz#a23d3d8608ad7192b69c6077fc4eb848998d35d9"
+  integrity sha512-0Zb2T4MLkpfZbeGMK/Z93b8Lrepr+rLFoHgQV1CoDeFqXvH7b+Vsd/VHoILGxQrgCSHFQ7mAODR6oyMjuiD4/g==
+  dependencies:
+    es5-shim "^4.5.1"
+
+videojs-swf@5.4.2, videojs-swf@^5.4.2:
+  version "5.4.2"
+  resolved "https://registry.npmmirror.com/videojs-swf/-/videojs-swf-5.4.2.tgz#6964a9bff903b732f3e465314ae478a02a17e8ab"
+  integrity sha512-FGg+Csioa8/A/EacvFefBdb9Z0rSiMlheHDunZnN3xXfUF43jvjawcWFQnZvrv1Cs1nE1LBrHyUZjF7j2mKOLw==
+
+videojs-vtt.js@0.12.6:
+  version "0.12.6"
+  resolved "https://registry.npmmirror.com/videojs-vtt.js/-/videojs-vtt.js-0.12.6.tgz#e078600bda899eaa6f9c3307134cd0c811947b8e"
+  integrity sha512-XFXeGBQiljnElMhwCcZst0RDbZn2n8LU7ZScXryd3a00OaZsHAjdZu/7/RdSr7Z1jHphd45FnOvOQkGK4YrWCQ==
+  dependencies:
+    global "^4.3.1"
+
+videojs-vtt.js@^0.15.5:
+  version "0.15.5"
+  resolved "https://registry.npmmirror.com/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz#567776eaf2a7a928d88b148a8b401ade2406f2ca"
+  integrity sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==
+  dependencies:
+    global "^4.3.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"
+  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.11"
+  resolved "https://registry.npmmirror.com/vite/-/vite-3.2.11.tgz#8d1c8e05ef2f24b04c8693f56d3e01fe8835e6d7"
+  integrity sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==
+  dependencies:
+    esbuild "^0.15.9"
+    postcss "^8.4.18"
+    resolve "^1.22.1"
+    rollup "^2.79.1"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
+vue-cropper@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-1.1.1.tgz#e1d2729f7139182a893e8badcb8f33257aa2a40f"
+  integrity sha512-WsqKMpaBf9Osi1LQlE/5AKdD0nHWOy1asLXocaG8NomOWO07jiZi968+/PbMmnD0QbPJOumDQaGuGa13qys85A==
+
+vue-demi@*, vue-demi@^0.14.10:
+  version "0.14.10"
+  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
+  integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
+
+vue-demi@^0.13.11:
+  version "0.13.11"
+  resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
+  integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
+
+vue-echarts@^6.6.9:
+  version "6.7.3"
+  resolved "https://registry.npmmirror.com/vue-echarts/-/vue-echarts-6.7.3.tgz#30efafc51a4a9de1b8117d3b63e74b0c761ff3ba"
+  integrity sha512-vXLKpALFjbPphW9IfQPOVfb1KjGZ/f8qa/FZHi9lZIWzAnQC1DgnmEK3pJgEkyo6EP7UnX6Bv/V3Ke7p+qCNXA==
+  dependencies:
+    resize-detector "^0.3.0"
+    vue-demi "^0.13.11"
+
+vue-i18n@^11.0.1:
+  version "11.0.1"
+  resolved "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.0.1.tgz#aa4c20d6f7c127bc46028ae3325659be47dd338e"
+  integrity sha512-pWAT8CusK8q9/EpN7V3oxwHwxWm6+Kp2PeTZmRGvdZTkUzMQDpbbmHp0TwQ8xw04XKm23cr6B4GL72y3W8Yekg==
+  dependencies:
+    "@intlify/core-base" "11.0.1"
+    "@intlify/shared" "11.0.1"
+    "@vue/devtools-api" "^6.5.0"
+
+vue-router@^4.2.5:
+  version "4.5.0"
+  resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz#58fc5fe374e10b6018f910328f756c3dae081f14"
+  integrity sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==
+  dependencies:
+    "@vue/devtools-api" "^6.6.4"
+
+vue-schart@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npmmirror.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"
+  integrity sha512-Yoy5phgvGqyF98Fb4mYqboR4Q149jrdcGv5kSmufXJUq++RZJ2iMVG0g6zl+v3t4ORVWkQmRpsV4x2szufZ0LQ==
+  dependencies:
+    "@volar/vue-typescript" "0.38.9"
+
+vue@^3.4.5:
+  version "3.5.13"
+  resolved "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
+  integrity sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==
+  dependencies:
+    "@vue/compiler-dom" "3.5.13"
+    "@vue/compiler-sfc" "3.5.13"
+    "@vue/runtime-dom" "3.5.13"
+    "@vue/server-renderer" "3.5.13"
+    "@vue/shared" "3.5.13"
+
+webpack-virtual-modules@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8"
+  integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==
+
+webwackify@0.1.6:
+  version "0.1.6"
+  resolved "https://registry.npmmirror.com/webwackify/-/webwackify-0.1.6.tgz#1d42a12ac61823d7e345abde084eaaa62a4a95eb"
+  integrity sha512-pGcw1T3HpNnM/UTRQqqRkkkzythSLts05mB+7Gr00B+0VbL0m39dFL5g20rSIEUt9Wrpw+/8k+snxRlUFHhcqA==
+
+webworkify-webpack@^2.1.5:
+  version "2.1.5"
+  resolved "https://registry.npmmirror.com/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz#bf4336624c0626cbe85cf1ffde157f7aa90b1d1c"
+  integrity sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==
+
+wildcard@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5"
+  integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==
+
+xhr@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.npmmirror.com/xhr/-/xhr-2.4.0.tgz#e16e66a45f869861eeefab416d5eff722dc40993"
+  integrity sha512-TUbBsdAuJbX8olk9hsDwGK8P1ri1XlV+PdEWkYw+HQQbpkiBR8PLgD1F3kQDPBs9l4Px34hP9rCYAZOCCAENbw==
+  dependencies:
+    global "~4.3.0"
+    is-function "^1.0.1"
+    parse-headers "^2.0.0"
+    xtend "^4.0.0"
+
+xtend@^4.0.0:
+  version "4.0.2"
+  resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+zrender@5.6.1:
+  version "5.6.1"
+  resolved "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b"
+  integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==
+  dependencies:
+    tslib "2.3.0"

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