wangtao hai 1 semana
achega
2072528310
Modificáronse 100 ficheiros con 10859 adicións e 0 borrados
  1. 2 0
      .env
  2. 5 0
      .env.development
  3. 5 0
      .env.production
  4. 5 0
      .env.test
  5. 72 0
      .eslintrc-auto-import.json
  6. 28 0
      .eslintrc.cjs
  7. 30 0
      .gitignore
  8. 8 0
      .prettierrc.json
  9. 22 0
      .run/flow-h5.run.xml
  10. 7 0
      .vscode/extensions.json
  11. 10 0
      Dockerfile
  12. 164 0
      conf/nginx.conf
  13. 12 0
      env.d.ts
  14. 24 0
      index.html
  15. 68 0
      package.json
  16. 6225 0
      pnpm-lock.yaml
  17. 17 0
      postcss.config.js
  18. BIN=BIN
      public/favicon.ico
  19. 21 0
      src/App.vue
  20. 174 0
      src/api/index.ts
  21. 27 0
      src/api/modules/file/file.ts
  22. 60 0
      src/api/modules/flow/activity.ts
  23. 78 0
      src/api/modules/flow/define.ts
  24. 198 0
      src/api/modules/flow/flowDesign.ts
  25. 46 0
      src/api/modules/flow/group.ts
  26. 75 0
      src/api/modules/flow/instance.ts
  27. 96 0
      src/api/modules/flow/model.ts
  28. 137 0
      src/api/modules/flow/task.ts
  29. 66 0
      src/api/modules/oauth/auth.ts
  30. 34 0
      src/api/modules/system/dept.ts
  31. 21 0
      src/api/modules/system/role.ts
  32. 44 0
      src/api/modules/system/user.ts
  33. 1 0
      src/assets/icons/logo.svg
  34. BIN=BIN
      src/assets/images/login_bg.jpg
  35. 40 0
      src/components/Breadcrumb/BreadcrumbItem.vue
  36. 14 0
      src/components/Breadcrumb/index.vue
  37. 121 0
      src/components/Comment/index.vue
  38. 211 0
      src/components/FormParser/index.tsx
  39. 119 0
      src/components/FormParser/type.ts
  40. 176 0
      src/components/FormParser/useForm.ts
  41. 99 0
      src/components/FormParser/useMatch.ts
  42. 42 0
      src/components/OrgSelector/OrgTag.vue
  43. 59 0
      src/components/OrgSelector/index.vue
  44. 94 0
      src/components/Render/components/Calculation.vue
  45. 17 0
      src/components/Render/components/Checkbox.vue
  46. 11 0
      src/components/Render/components/Col.vue
  47. 46 0
      src/components/Render/components/Custom.vue
  48. 93 0
      src/components/Render/components/Date.vue
  49. 86 0
      src/components/Render/components/DateRange.vue
  50. 13 0
      src/components/Render/components/Divider.vue
  51. 155 0
      src/components/Render/components/DynamicTable.vue
  52. 65 0
      src/components/Render/components/FileUpload.vue
  53. 5 0
      src/components/Render/components/Iframe.vue
  54. 65 0
      src/components/Render/components/ImageUpload.vue
  55. 9 0
      src/components/Render/components/Input.vue
  56. 13 0
      src/components/Render/components/Numner.vue
  57. 14 0
      src/components/Render/components/OrgSelector.vue
  58. 5 0
      src/components/Render/components/ProcessSelector.vue
  59. 15 0
      src/components/Render/components/Radio.vue
  60. 17 0
      src/components/Render/components/Rate.vue
  61. 14 0
      src/components/Render/components/RoleSelector.vue
  62. 11 0
      src/components/Render/components/Row.vue
  63. 95 0
      src/components/Render/components/Select.vue
  64. 14 0
      src/components/Render/components/Signature.vue
  65. 13 0
      src/components/Render/components/Slider.vue
  66. 11 0
      src/components/Render/components/Stepper.vue
  67. 18 0
      src/components/Render/components/Switch.vue
  68. 15 0
      src/components/Render/components/Tab.vue
  69. 16 0
      src/components/Render/components/Tabs.vue
  70. 7 0
      src/components/Render/components/Textarea.vue
  71. 61 0
      src/components/Render/components/Time.vue
  72. 38 0
      src/components/Render/components/TimeRange.vue
  73. 40 0
      src/components/Render/components/UserSelector.vue
  74. 40 0
      src/components/Render/components/index.ts
  75. 6 0
      src/components/Render/hooks/CollapseItem.tsx
  76. 13 0
      src/components/Render/hooks/Date.tsx
  77. 8 0
      src/components/Render/hooks/DateRange.tsx
  78. 28 0
      src/components/Render/hooks/FileUpload.tsx
  79. 29 0
      src/components/Render/hooks/ImageUpload.tsx
  80. 9 0
      src/components/Render/hooks/Rate.tsx
  81. 18 0
      src/components/Render/hooks/Select.tsx
  82. 10 0
      src/components/Render/hooks/Textarea.tsx
  83. 18 0
      src/components/Render/hooks/Time.tsx
  84. 13 0
      src/components/Render/hooks/TimeRange.tsx
  85. 10 0
      src/components/Render/hooks/index.ts
  86. 107 0
      src/components/Render/index.tsx
  87. 13 0
      src/components/Render/slots/Checkbox.tsx
  88. 13 0
      src/components/Render/slots/Radio.tsx
  89. 11 0
      src/components/Render/slots/index.ts
  90. 33 0
      src/components/Render/type.ts
  91. 41 0
      src/components/RoleSelector/RoleName.vue
  92. 211 0
      src/components/RoleSelector/RolePicker.vue
  93. 42 0
      src/components/RoleSelector/RoleTag.vue
  94. 58 0
      src/components/RoleSelector/index.vue
  95. 199 0
      src/components/Signature/index.vue
  96. 34 0
      src/components/SvgIcon/index.vue
  97. 57 0
      src/components/Timeline/TimelineItem.vue
  98. 13 0
      src/components/Timeline/index.vue
  99. 41 0
      src/components/UserSelector/OrgName.vue
  100. 45 0
      src/components/UserSelector/UserName.vue

+ 2 - 0
.env

@@ -0,0 +1,2 @@
+# title
+VITE_GLOB_APP_TITLE=Low-Flow

+ 5 - 0
.env.development

@@ -0,0 +1,5 @@
+# 公共基础路径
+VITE_PUBLIC_PATH=/
+
+# 开发环境接口地址
+VITE_API_URL=/api

+ 5 - 0
.env.production

@@ -0,0 +1,5 @@
+# 公共基础路径
+VITE_PUBLIC_PATH=/
+
+# 线上环境接口地址
+VITE_API_URL="https://demo.lowflow.vip/api"

+ 5 - 0
.env.test

@@ -0,0 +1,5 @@
+# 公共基础路径
+VITE_PUBLIC_PATH=/
+
+# 测试环境接口地址
+VITE_API_URL="https://demo.lowflow.vip/api"

+ 72 - 0
.eslintrc-auto-import.json

@@ -0,0 +1,72 @@
+{
+  "globals": {
+    "Component": true,
+    "ComponentPublicInstance": true,
+    "ComputedRef": true,
+    "EffectScope": true,
+    "ExtractDefaultPropTypes": true,
+    "ExtractPropTypes": true,
+    "ExtractPublicPropTypes": true,
+    "InjectionKey": true,
+    "PropType": true,
+    "Ref": true,
+    "VNode": true,
+    "WritableComputedRef": true,
+    "computed": true,
+    "createApp": true,
+    "customRef": true,
+    "defineAsyncComponent": true,
+    "defineComponent": true,
+    "effectScope": true,
+    "getCurrentInstance": true,
+    "getCurrentScope": true,
+    "h": true,
+    "inject": true,
+    "isProxy": true,
+    "isReactive": true,
+    "isReadonly": true,
+    "isRef": true,
+    "markRaw": true,
+    "nextTick": true,
+    "onActivated": true,
+    "onBeforeMount": true,
+    "onBeforeRouteLeave": true,
+    "onBeforeRouteUpdate": true,
+    "onBeforeUnmount": true,
+    "onBeforeUpdate": true,
+    "onDeactivated": true,
+    "onErrorCaptured": true,
+    "onMounted": true,
+    "onRenderTracked": true,
+    "onRenderTriggered": true,
+    "onScopeDispose": true,
+    "onServerPrefetch": true,
+    "onUnmounted": true,
+    "onUpdated": true,
+    "provide": true,
+    "reactive": true,
+    "readonly": true,
+    "ref": true,
+    "resolveComponent": true,
+    "shallowReactive": true,
+    "shallowReadonly": true,
+    "shallowRef": true,
+    "toRaw": true,
+    "toRef": true,
+    "toRefs": true,
+    "toValue": true,
+    "triggerRef": true,
+    "unref": true,
+    "useAttrs": true,
+    "useCssModule": true,
+    "useCssVars": true,
+    "useLink": true,
+    "useRoute": true,
+    "useRouter": true,
+    "useSlots": true,
+    "watch": true,
+    "watchEffect": true,
+    "watchPostEffect": true,
+    "watchSyncEffect": true
+  }
+}

+ 28 - 0
.eslintrc.cjs

@@ -0,0 +1,28 @@
+/* eslint-env node */
+require('@rushstack/eslint-patch/modern-module-resolution')
+
+module.exports = {
+  root: true,
+  'extends': [
+    'plugin:vue/vue3-essential',
+    'eslint:recommended',
+    '@vue/eslint-config-typescript',
+    '@vue/eslint-config-prettier/skip-formatting'
+  ],
+  parserOptions: {
+    ecmaVersion: 'latest'
+  },
+  rules: {
+    // ===============================>>> eslint (http://eslint.cn/docs/rules)
+    'no-var': 'error', // 要求使用 let 或 const 而不是 var
+    'prefer-const': 'off', // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
+    'eqeqeq': 'warn', // 要求使用 === 和 !==
+    // ===============================>>> typeScript (https://typescript-eslint.io/rules)
+    'no-undef': 'off', // 禁止使用未定义的变量
+    // ===============================>>> vue (https://eslint.vuejs.org/rules)
+    'vue/no-mutating-props': ['error', {
+      'shallowOnly': true // 允许修改prop的值,但保持引用不变
+    }],
+    'vue/multi-word-component-names': 'off' // 组件名强制使用短横线连接
+  }
+}

+ 30 - 0
.gitignore

@@ -0,0 +1,30 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo

+ 8 - 0
.prettierrc.json

@@ -0,0 +1,8 @@
+{
+  "$schema": "https://json.schemastore.org/prettierrc",
+  "semi": false,
+  "tabWidth": 2,
+  "singleQuote": true,
+  "printWidth": 100,
+  "trailingComma": "none"
+}

+ 22 - 0
.run/flow-h5.run.xml

@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="flow-h5" type="docker-deploy" factoryName="dockerfile" server-name="阿里云">
+    <deployment type="dockerfile">
+      <settings>
+        <option name="imageTag" value="flow-h5:1.0" />
+        <option name="containerName" value="flow-h5" />
+        <option name="portBindings">
+          <list>
+            <DockerPortBindingImpl>
+              <option name="containerPort" value="2080" />
+              <option name="hostPort" value="2080" />
+            </DockerPortBindingImpl>
+          </list>
+        </option>
+        <option name="commandLineOptions" value="-restart always&#10;-net net-test" />
+        <option name="showCommandPreview" value="true" />
+        <option name="sourceFilePath" value="Dockerfile" />
+      </settings>
+    </deployment>
+    <method v="2" />
+  </configuration>
+</component>

+ 7 - 0
.vscode/extensions.json

@@ -0,0 +1,7 @@
+{
+  "recommendations": [
+    "Vue.volar",
+    "dbaeumer.vscode-eslint",
+    "esbenp.prettier-vscode"
+  ]
+}

+ 10 - 0
Dockerfile

@@ -0,0 +1,10 @@
+# production environment
+FROM nginx:1.25.0-alpine
+# FROM georgjung/nginx-brotli:1.25-alpine
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
+    echo 'Asia/Shanghai' >/etc/timezone
+COPY /dist /usr/share/nginx/html
+RUN rm /etc/nginx/conf.d/default.conf
+COPY ./conf/nginx.conf /etc/nginx/
+EXPOSE 2080
+CMD ["nginx", "-g", "daemon off;"]

+ 164 - 0
conf/nginx.conf

@@ -0,0 +1,164 @@
+
+#user  nobody;
+worker_processes  1;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+    worker_connections  1024;
+}
+
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+
+    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+    #                  '$status $body_bytes_sent "$http_referer" '
+    #                  '"$http_user_agent" "$http_x_forwarded_for"';
+
+    #access_log  logs/access.log  main;
+
+    sendfile        on;
+    tcp_nopush     on;
+    tcp_nodelay     on;
+
+    #keepalive_timeout  0;
+    keepalive_timeout  65;
+
+
+    #开启gzip
+    gzip off;
+    #nginx对于静态文件的处理模块,开启后会寻找以.gz结尾的文件,直接返回,不会占用cpu进行压缩,如果找不到则不进行压缩
+    gzip_static on;
+    #nginx做前端代理时启用该选项,表示无论后端服务器的headers头返回什么信息,都无条件启用压缩
+    gzip_proxied expired no-cache no-store private auth;
+    #低于10kb的资源不压缩
+    gzip_min_length 10k;
+    #设置压缩所需要的缓冲区大小
+    gzip_buffers 4 16k;
+    #设置gzip压缩针对的HTTP协议版本
+    gzip_http_version 1.0;
+    #压缩级别1-9,越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。
+    gzip_comp_level 5;
+    #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片.
+    gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css application/xml;
+    #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
+    gzip_disable "MSIE [1-6]\.";
+    #是否添加“Vary: Accept-Encoding”响应头
+    gzip_vary on;
+
+
+    #ip限流每秒最多1000个请求
+    limit_req_zone $binary_remote_addr zone=myRateLimit:15m rate=1000r/s;
+    #限制并发连接数
+    limit_conn_zone $binary_remote_addr zone=perip:10m;
+    limit_conn_zone $server_name zone=perserver:10m;
+server
+    {
+        listen 2080;
+        server_name webServer;
+        #dist上传的路径
+        root  /usr/share/nginx/html;
+        index index.html index.htm;
+        charset utf-8;
+        proxy_set_header HOST $host;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        # 获取客户端真实IP
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Real-Port $remote_port;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        # 支持websocket连接
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        # 限制并发连接数
+        #limit_conn perip 10; #每个IP最多10个并发连接
+        # 客户端请求体限制10MB
+        client_max_body_size 10m;
+
+        # 避免访问出现 404 错误
+        location / {
+          root  /usr/share/nginx/html;  #dist上传的路径
+          index  index.html index.htm;
+          try_files $uri $uri/ @router;
+        }
+
+        # 生产环境(http)
+        location ^~/api {
+          # 去除api前缀
+          rewrite ^/api/(.*)$ /$1 break;
+          # 代理到后端服务器
+          proxy_pass http://flow-app:9089/;
+          # 限流,每秒最多1000个请求
+          limit_req zone=myRateLimit burst=100 nodelay;
+          #每个IP最多50个并发连接
+          limit_conn perip 50;
+        }
+
+        # 生产环境(socket)
+        location ^~/ws {
+          # 去除ws前缀
+          rewrite ^/ws/(.*)$ /$1 break;
+          # 代理到后端服务器
+          proxy_pass http://flow-app:9089/;
+          # 支持websocket连接
+          proxy_http_version 1.1; # 确保使用 HTTP/1.1
+          proxy_set_header Upgrade $http_upgrade;
+          proxy_set_header Connection "upgrade";
+          proxy_set_header Host $host;
+        }
+
+        error_page   500 502 503 504  /50x.html;
+        location = /50x.html {
+            root   html;
+        }
+
+        location @router {
+          rewrite ^.*$ /index.html last;
+        }
+    }
+
+
+
+    # another virtual host using mix of IP-, name-, and port-based configuration
+    #
+    #server {
+    #    listen       8000;
+    #    listen       somename:8080;
+    #    server_name  somename  alias  another.alias;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+
+    # HTTPS server
+    #
+    #server {
+    #    listen       443 ssl;
+    #    server_name  localhost;
+
+    #    ssl_certificate      cert.pem;
+    #    ssl_certificate_key  cert.key;
+
+    #    ssl_session_cache    shared:SSL:1m;
+    #    ssl_session_timeout  5m;
+
+    #    ssl_ciphers  HIGH:!aNULL:!MD5;
+    #    ssl_prefer_server_ciphers  on;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+}

+ 12 - 0
env.d.ts

@@ -0,0 +1,12 @@
+/// <reference types="vite/client" />
+
+interface ImportMetaEnv {
+  readonly VITE_GLOB_APP_TITLE: string
+  readonly VITE_API_URL: string
+  readonly VITE_PUBLIC_PATH: string
+  readonly BASE_URL: string
+}
+
+interface ImportMeta {
+  readonly env: ImportMetaEnv
+}

+ 24 - 0
index.html

@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <link rel="icon" href="/favicon.ico">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Vite App</title>
+  <script>
+    ;(function() {
+      const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
+      const setting = localStorage.getItem('vueuse-color-scheme') || 'auto'
+      if (setting === 'dark' || (prefersDark && setting !== 'light')) {
+        document.documentElement.classList.toggle('dark', true)
+      }else{
+        document.documentElement.classList.toggle('light', true)
+      }
+    })()
+  </script>
+</head>
+<body>
+<div id="app"></div>
+<script type="module" src="/src/main.ts"></script>
+</body>
+</html>

+ 68 - 0
package.json

@@ -0,0 +1,68 @@
+{
+  "name": "low-flow-h5",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "run-p type-check \"build-only {@}\" --",
+    "build:test": "vite build --mode test",
+    "build:prod": "vite build --mode production",
+    "preview": "vite preview",
+    "build-only": "vite build",
+    "type-check": "vue-tsc --build --force",
+    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
+    "format": "prettier --write src/"
+  },
+  "dependencies": {
+    "@vant/use": "^1.6.0",
+    "@vueuse/core": "^10.10.0",
+    "axios": "^1.7.2",
+    "dayjs": "^1.11.11",
+    "file-saver": "^2.0.5",
+    "less": "^4.2.0",
+    "lodash-es": "^4.17.21",
+    "nprogress": "^0.2.0",
+    "pinia": "^2.1.7",
+    "pinia-plugin-persistedstate": "^3.2.1",
+    "qs": "^6.12.1",
+    "v-perfect-signature": "^1.4.0",
+    "vant": "^4.9.1",
+    "vue": "^3.4.21",
+    "vue-router": "^4.3.0"
+  },
+  "devDependencies": {
+    "@iconify/json": "^2.2.216",
+    "@rushstack/eslint-patch": "^1.8.0",
+    "@tsconfig/node20": "^20.1.4",
+    "@types/file-saver": "^2.0.7",
+    "@types/lodash-es": "^4.17.12",
+    "@types/node": "^20.12.5",
+    "@types/nprogress": "^0.2.3",
+    "@types/qs": "^6.9.15",
+    "@unocss/preset-icons": "^0.60.4",
+    "@unocss/preset-rem-to-px": "^0.60.4",
+    "@vitejs/plugin-vue": "^5.0.4",
+    "@vitejs/plugin-vue-jsx": "^3.1.0",
+    "@vue/eslint-config-prettier": "^9.0.0",
+    "@vue/eslint-config-typescript": "^13.0.0",
+    "@vue/tsconfig": "^0.5.1",
+    "autoprefixer": "^10.4.19",
+    "eslint": "^8.57.0",
+    "eslint-plugin-vue": "^9.23.0",
+    "npm-run-all2": "^6.1.2",
+    "postcss-mobile-forever": "^4.1.4",
+    "prettier": "^3.2.5",
+    "typescript": "~5.4.0",
+    "unocss": "^0.60.4",
+    "unplugin-auto-import": "^0.17.6",
+    "unplugin-vue-components": "^0.27.0",
+    "vite": "^5.2.8",
+    "vite-plugin-compression": "^0.5.1",
+    "vite-plugin-svg-icons": "^2.0.1",
+    "vite-plugin-vue-devtools": "^7.0.25",
+    "vite-plugin-vue-setup-extend": "^0.4.0",
+    "vue-tsc": "^2.0.11"
+  },
+  "packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e"
+}

+ 6225 - 0
pnpm-lock.yaml

@@ -0,0 +1,6225 @@
+lockfileVersion: '9.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+importers:
+
+  .:
+    dependencies:
+      '@vant/use':
+        specifier: ^1.6.0
+        version: 1.6.0(vue@3.4.27(typescript@5.4.5))
+      '@vueuse/core':
+        specifier: ^10.10.0
+        version: 10.10.0(vue@3.4.27(typescript@5.4.5))
+      axios:
+        specifier: ^1.7.2
+        version: 1.7.2
+      dayjs:
+        specifier: ^1.11.11
+        version: 1.11.11
+      file-saver:
+        specifier: ^2.0.5
+        version: 2.0.5
+      less:
+        specifier: ^4.2.0
+        version: 4.2.0
+      lodash-es:
+        specifier: ^4.17.21
+        version: 4.17.21
+      nprogress:
+        specifier: ^0.2.0
+        version: 0.2.0
+      pinia:
+        specifier: ^2.1.7
+        version: 2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5))
+      pinia-plugin-persistedstate:
+        specifier: ^3.2.1
+        version: 3.2.1(pinia@2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5)))
+      qs:
+        specifier: ^6.12.1
+        version: 6.12.1
+      v-perfect-signature:
+        specifier: ^1.4.0
+        version: 1.4.0(vue@3.4.27(typescript@5.4.5))
+      vant:
+        specifier: ^4.9.1
+        version: 4.9.1(vue@3.4.27(typescript@5.4.5))
+      vue:
+        specifier: ^3.4.21
+        version: 3.4.27(typescript@5.4.5)
+      vue-router:
+        specifier: ^4.3.0
+        version: 4.3.2(vue@3.4.27(typescript@5.4.5))
+    devDependencies:
+      '@iconify/json':
+        specifier: ^2.2.216
+        version: 2.2.216
+      '@rushstack/eslint-patch':
+        specifier: ^1.8.0
+        version: 1.10.3
+      '@tsconfig/node20':
+        specifier: ^20.1.4
+        version: 20.1.4
+      '@types/file-saver':
+        specifier: ^2.0.7
+        version: 2.0.7
+      '@types/lodash-es':
+        specifier: ^4.17.12
+        version: 4.17.12
+      '@types/node':
+        specifier: ^20.12.5
+        version: 20.14.1
+      '@types/nprogress':
+        specifier: ^0.2.3
+        version: 0.2.3
+      '@types/qs':
+        specifier: ^6.9.15
+        version: 6.9.15
+      '@unocss/preset-icons':
+        specifier: ^0.60.4
+        version: 0.60.4
+      '@unocss/preset-rem-to-px':
+        specifier: ^0.60.4
+        version: 0.60.4
+      '@vitejs/plugin-vue':
+        specifier: ^5.0.4
+        version: 5.0.5(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))
+      '@vitejs/plugin-vue-jsx':
+        specifier: ^3.1.0
+        version: 3.1.0(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))
+      '@vue/eslint-config-prettier':
+        specifier: ^9.0.0
+        version: 9.0.0(eslint@8.57.0)(prettier@3.3.0)
+      '@vue/eslint-config-typescript':
+        specifier: ^13.0.0
+        version: 13.0.0(eslint-plugin-vue@9.26.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
+      '@vue/tsconfig':
+        specifier: ^0.5.1
+        version: 0.5.1
+      autoprefixer:
+        specifier: ^10.4.19
+        version: 10.4.19(postcss@5.2.18)
+      eslint:
+        specifier: ^8.57.0
+        version: 8.57.0
+      eslint-plugin-vue:
+        specifier: ^9.23.0
+        version: 9.26.0(eslint@8.57.0)
+      npm-run-all2:
+        specifier: ^6.1.2
+        version: 6.2.0
+      postcss-mobile-forever:
+        specifier: ^4.1.4
+        version: 4.1.4(postcss@5.2.18)
+      prettier:
+        specifier: ^3.2.5
+        version: 3.3.0
+      typescript:
+        specifier: ~5.4.0
+        version: 5.4.5
+      unocss:
+        specifier: ^0.60.4
+        version: 0.60.4(postcss@5.2.18)(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      unplugin-auto-import:
+        specifier: ^0.17.6
+        version: 0.17.6(@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5)))(rollup@4.18.0)
+      unplugin-vue-components:
+        specifier: ^0.27.0
+        version: 0.27.0(@babel/parser@7.24.6)(rollup@4.18.0)(vue@3.4.27(typescript@5.4.5))
+      vite:
+        specifier: ^5.2.8
+        version: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+      vite-plugin-compression:
+        specifier: ^0.5.1
+        version: 0.5.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      vite-plugin-svg-icons:
+        specifier: ^2.0.1
+        version: 2.0.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      vite-plugin-vue-devtools:
+        specifier: ^7.0.25
+        version: 7.2.1(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))
+      vite-plugin-vue-setup-extend:
+        specifier: ^0.4.0
+        version: 0.4.0(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      vue-tsc:
+        specifier: ^2.0.11
+        version: 2.0.19(typescript@5.4.5)
+
+packages:
+
+  '@ampproject/remapping@2.3.0':
+    resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+    engines: {node: '>=6.0.0'}
+
+  '@antfu/install-pkg@0.1.1':
+    resolution: {integrity: sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==}
+
+  '@antfu/utils@0.7.8':
+    resolution: {integrity: sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==}
+
+  '@babel/code-frame@7.24.6':
+    resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/compat-data@7.24.6':
+    resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/core@7.24.6':
+    resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/generator@7.24.6':
+    resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-annotate-as-pure@7.24.6':
+    resolution: {integrity: sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-compilation-targets@7.24.6':
+    resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-create-class-features-plugin@7.24.6':
+    resolution: {integrity: sha512-djsosdPJVZE6Vsw3kk7IPRWethP94WHGOhQTc67SNXE0ZzMhHgALw8iGmYS0TD1bbMM0VDROy43od7/hN6WYcA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-environment-visitor@7.24.6':
+    resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-function-name@7.24.6':
+    resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-hoist-variables@7.24.6':
+    resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-member-expression-to-functions@7.24.6':
+    resolution: {integrity: sha512-OTsCufZTxDUsv2/eDXanw/mUZHWOxSbEmC3pP8cgjcy5rgeVPWWMStnv274DV60JtHxTk0adT0QrCzC4M9NWGg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-imports@7.22.15':
+    resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-imports@7.24.6':
+    resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-transforms@7.24.6':
+    resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-optimise-call-expression@7.24.6':
+    resolution: {integrity: sha512-3SFDJRbx7KuPRl8XDUr8O7GAEB8iGyWPjLKJh/ywP/Iy9WOmEfMrsWbaZpvBu2HSYn4KQygIsz0O7m8y10ncMA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-plugin-utils@7.24.6':
+    resolution: {integrity: sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-replace-supers@7.24.6':
+    resolution: {integrity: sha512-mRhfPwDqDpba8o1F8ESxsEkJMQkUF8ZIWrAc0FtWhxnjfextxMWxr22RtFizxxSYLjVHDeMgVsRq8BBZR2ikJQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-simple-access@7.24.6':
+    resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-skip-transparent-expression-wrappers@7.24.6':
+    resolution: {integrity: sha512-jhbbkK3IUKc4T43WadP96a27oYti9gEf1LdyGSP2rHGH77kwLwfhO7TgwnWvxxQVmke0ImmCSS47vcuxEMGD3Q==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-split-export-declaration@7.24.6':
+    resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-string-parser@7.24.6':
+    resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-identifier@7.24.6':
+    resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-option@7.24.6':
+    resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helpers@7.24.6':
+    resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/highlight@7.24.6':
+    resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/parser@7.24.6':
+    resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/plugin-proposal-decorators@7.24.6':
+    resolution: {integrity: sha512-8DjR0/DzlBhz2SVi9a19/N2U5+C3y3rseXuyoKL9SP8vnbewscj1eHZtL6kpEn4UCuUmqEo0mvqyDYRFoN2gpA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-decorators@7.24.6':
+    resolution: {integrity: sha512-gInH8LEqBp+wkwTVihCd/qf+4s28g81FZyvlIbAurHk9eSiItEKG7E0uNK2UdpgsD79aJVAW3R3c85h0YJ0jsw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-attributes@7.24.6':
+    resolution: {integrity: sha512-D+CfsVZousPXIdudSII7RGy52+dYRtbyKAZcvtQKq/NpsivyMVduepzcLqG5pMBugtMdedxdC8Ramdpcne9ZWQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-meta@7.10.4':
+    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-jsx@7.24.6':
+    resolution: {integrity: sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-typescript@7.24.6':
+    resolution: {integrity: sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-modules-commonjs@7.24.6':
+    resolution: {integrity: sha512-JEV8l3MHdmmdb7S7Cmx6rbNEjRCgTQMZxllveHO0mx6uiclB0NflCawlQQ6+o5ZrwjUBYPzHm2XoK4wqGVUFuw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-typescript@7.24.6':
+    resolution: {integrity: sha512-H0i+hDLmaYYSt6KU9cZE0gb3Cbssa/oxWis7PX4ofQzbvsfix9Lbh8SRk7LCPDlLWJHUiFeHU0qRRpF/4Zv7mQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/preset-typescript@7.24.6':
+    resolution: {integrity: sha512-U10aHPDnokCFRXgyT/MaIRTivUu2K/mu0vJlwRS9LxJmJet+PFQNKpggPyFCUtC6zWSBPjvxjnpNkAn3Uw2m5w==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/template@7.24.6':
+    resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/traverse@7.24.6':
+    resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/types@7.24.6':
+    resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@esbuild/aix-ppc64@0.20.2':
+    resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.20.2':
+    resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.20.2':
+    resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.20.2':
+    resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.20.2':
+    resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.20.2':
+    resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.20.2':
+    resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.20.2':
+    resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.20.2':
+    resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.20.2':
+    resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.20.2':
+    resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.20.2':
+    resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.20.2':
+    resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.20.2':
+    resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.20.2':
+    resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.20.2':
+    resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.20.2':
+    resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-x64@0.20.2':
+    resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-x64@0.20.2':
+    resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.20.2':
+    resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.20.2':
+    resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.20.2':
+    resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.20.2':
+    resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+
+  '@eslint-community/eslint-utils@4.4.0':
+    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+  '@eslint-community/regexpp@4.10.1':
+    resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  '@eslint/eslintrc@2.1.4':
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@eslint/js@8.57.0':
+    resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  '@humanwhocodes/config-array@0.11.14':
+    resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+    engines: {node: '>=10.10.0'}
+
+  '@humanwhocodes/module-importer@1.0.1':
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+
+  '@humanwhocodes/object-schema@2.0.3':
+    resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+
+  '@iconify/json@2.2.216':
+    resolution: {integrity: sha512-dS2yVIAel1oIAGnaxR+EJyDRjKV9GGm9tUd8Pd8VEF91HB4HJrsMzkvz23GHDWyIITGdinx4ZUjMz3hOAv+D4Q==}
+
+  '@iconify/types@2.0.0':
+    resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
+
+  '@iconify/utils@2.1.24':
+    resolution: {integrity: sha512-H8r2KpL5uKyrkb3z9/3HD/22JcxqW3BJyjEWZhX2T7DehnYVZthEap1cNsEl/UtCDC3TlpNmwiPX8wg3y8E4dg==}
+
+  '@jridgewell/gen-mapping@0.3.5':
+    resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/resolve-uri@3.1.2':
+    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/set-array@1.2.1':
+    resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/sourcemap-codec@1.4.15':
+    resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+
+  '@jridgewell/trace-mapping@0.3.25':
+    resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+  '@nodelib/fs.scandir@2.1.5':
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.stat@2.0.5':
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.walk@1.2.8':
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+
+  '@pkgr/core@0.1.1':
+    resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
+    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+
+  '@polka/url@1.0.0-next.25':
+    resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
+
+  '@rollup/pluginutils@5.1.0':
+    resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+
+  '@rollup/rollup-android-arm-eabi@4.18.0':
+    resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==}
+    cpu: [arm]
+    os: [android]
+
+  '@rollup/rollup-android-arm64@4.18.0':
+    resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==}
+    cpu: [arm64]
+    os: [android]
+
+  '@rollup/rollup-darwin-arm64@4.18.0':
+    resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@rollup/rollup-darwin-x64@4.18.0':
+    resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
+    resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm-musleabihf@4.18.0':
+    resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-gnu@4.18.0':
+    resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-musl@4.18.0':
+    resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
+    resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-gnu@4.18.0':
+    resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-s390x-gnu@4.18.0':
+    resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-gnu@4.18.0':
+    resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-musl@4.18.0':
+    resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-win32-arm64-msvc@4.18.0':
+    resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@rollup/rollup-win32-ia32-msvc@4.18.0':
+    resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@rollup/rollup-win32-x64-msvc@4.18.0':
+    resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==}
+    cpu: [x64]
+    os: [win32]
+
+  '@rushstack/eslint-patch@1.10.3':
+    resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
+
+  '@trysound/sax@0.2.0':
+    resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
+    engines: {node: '>=10.13.0'}
+
+  '@tsconfig/node20@20.1.4':
+    resolution: {integrity: sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==}
+
+  '@types/estree@1.0.5':
+    resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
+  '@types/file-saver@2.0.7':
+    resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==}
+
+  '@types/lodash-es@4.17.12':
+    resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
+
+  '@types/lodash@4.17.4':
+    resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==}
+
+  '@types/node@20.14.1':
+    resolution: {integrity: sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==}
+
+  '@types/nprogress@0.2.3':
+    resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==}
+
+  '@types/qs@6.9.15':
+    resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
+
+  '@types/svgo@2.6.4':
+    resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
+
+  '@types/web-bluetooth@0.0.20':
+    resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
+
+  '@typescript-eslint/eslint-plugin@7.12.0':
+    resolution: {integrity: sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^7.0.0
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/parser@7.12.0':
+    resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/scope-manager@7.12.0':
+    resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@typescript-eslint/type-utils@7.12.0':
+    resolution: {integrity: sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/types@7.12.0':
+    resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@typescript-eslint/typescript-estree@7.12.0':
+    resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@typescript-eslint/utils@7.12.0':
+    resolution: {integrity: sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+
+  '@typescript-eslint/visitor-keys@7.12.0':
+    resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+
+  '@ungap/structured-clone@1.2.0':
+    resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+
+  '@unocss/astro@0.60.4':
+    resolution: {integrity: sha512-mfWiEVCUP00gxrMewwPfnTuw+ur5b6uIBRH2tIGkvfI21rLyZw8TIF08w7USz9C/47rvzsixBtCqq7v0g3Tw9w==}
+    peerDependencies:
+      vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
+    peerDependenciesMeta:
+      vite:
+        optional: true
+
+  '@unocss/cli@0.60.4':
+    resolution: {integrity: sha512-RFt3BOgtp5ZI+cS6grKKo1DqvUJ/e8iRPwn843u6qSw18guIc4CEVTe5jcDAGuLcL4va9hg2wd4NReUEnMCZ/g==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  '@unocss/config@0.60.4':
+    resolution: {integrity: sha512-ri9P2+YztD5JdPYSLiNjcLf6NgoBbwJDVutP/tQnfYYrE72DQ+j+4vepyxEBa1YaH/X4qsmLJCj+2tI/ufIiog==}
+    engines: {node: '>=14'}
+
+  '@unocss/core@0.60.4':
+    resolution: {integrity: sha512-6tz8KTzC30oB0YikwRQoIpJ6Y6Dg+ZiK3NfCIsH+UX11bh2J2M53as2EL/5VQCqtiUn3YP0ZEzR2d1AWX78RCA==}
+
+  '@unocss/extractor-arbitrary-variants@0.60.4':
+    resolution: {integrity: sha512-USuFGs5CLft9q7IGNdAEp1oliuUns+W7OO0Tx5qtx/oBh6pU/L93lcNNsuuGNrMU8BCmF3atx1/PEmGymgJ7VA==}
+
+  '@unocss/inspector@0.60.4':
+    resolution: {integrity: sha512-PcnrEQ2H7osZho4Nh0+84O4IXzlkF7pvTUe/7FTJYF1HQGWHB/PfOSoyKn7/sF5sED8hMK9RlSJ9YGUH9ioY+g==}
+
+  '@unocss/postcss@0.60.4':
+    resolution: {integrity: sha512-mHha4BoOpCWRRL5EFJqsj+BiYxOBPXUZDFbSWmA8oAMBwcA/yqtnaRF2tqI9CK+CDfhmtbYF64KdTLh9pf6BvQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      postcss: ^8.4.21
+
+  '@unocss/preset-attributify@0.60.4':
+    resolution: {integrity: sha512-J2GWUC0bcmZSXlBGLYUXwWQos/dNzKbq2CKweWVBAmAH9XyfM0mA5CTNBRv05PN1g6C/0z5st7ntUjV6KHJuTg==}
+
+  '@unocss/preset-icons@0.60.4':
+    resolution: {integrity: sha512-UN/dj+nhI3+S06YxCZQPLw3GZy780iaE71dysyhDMdh+Qq2KFVs3d94mr1427fjz/3Y8ZyXkgqyhCFr7UT0bMQ==}
+
+  '@unocss/preset-mini@0.60.4':
+    resolution: {integrity: sha512-ZiHbP69vkyz0xmhqzC4B4PegwV+LPlZOBT7cRhsh0P8oPOQKYOyDRy4rAl+sJBJeIrggn1r1LgN+Z0Xvd8Ytcw==}
+
+  '@unocss/preset-rem-to-px@0.60.4':
+    resolution: {integrity: sha512-ISuIad99jyFewYTPeR1tDOk94+LW4Ry9aKNfnAi6E4AFSEW9g+5MhAsLuI/jWQA/A3uLGBI8fGSM7RhX3PxDOw==}
+
+  '@unocss/preset-tagify@0.60.4':
+    resolution: {integrity: sha512-GxL/W3qkdWWDqXi43qyLbp/BpEj7gMw99KqkO7bmbVi3BVlFggreTFwmQu89pB6iatxGjxnAsc+TsQZqxKftZA==}
+
+  '@unocss/preset-typography@0.60.4':
+    resolution: {integrity: sha512-6j8ySZYEAwMBy9a3Lw3EEfRlcAClti4zvaV0kBtkP4BDZCwlgX2eE1pmw2mTUy+E1yVlXm3NnRzKfDudQUzraA==}
+
+  '@unocss/preset-uno@0.60.4':
+    resolution: {integrity: sha512-AN8ZTtiKSaZNGKZZIqt/JAhMzSY2hHLwhGEOFDrXgjWFr85UlwZzODMDoT58PrU04VlbhN8+0N4lHfLmZCKpiQ==}
+
+  '@unocss/preset-web-fonts@0.60.4':
+    resolution: {integrity: sha512-COfxOQcREFgpsm6nw234pxrr1EV1zWUVYXBZjlH+vk7x8EhaS5BPAXqN6SneIVTTDvEE9U4opAaoEYz5A3XWaQ==}
+
+  '@unocss/preset-wind@0.60.4':
+    resolution: {integrity: sha512-dT/U+RkbL21lDTOP7/mlFZxlBbUAefUzQZINC0BX7vTKvO57G4HxRq62u9xvMGFv38lQ+qXXzKhABVsEPDNpUA==}
+
+  '@unocss/reset@0.60.4':
+    resolution: {integrity: sha512-MEngG4byIHnfb0osvxqU2gBdBkXPPE4z+G9HeEt3JUadWAp2gggm8ojC1/1PoJF5M31loxGEVVrB0FLSKACw3g==}
+
+  '@unocss/rule-utils@0.60.4':
+    resolution: {integrity: sha512-7qUN33NM4T/IwWavm9VIOCZ2+4hLBc0YUGxcMNTDZSFQRQLkWe3N5dOlgwKXtMyMKatZfbIRUKVDUgvEefoCTA==}
+    engines: {node: '>=14'}
+
+  '@unocss/scope@0.60.4':
+    resolution: {integrity: sha512-AOu/qvi4agy0XfGF3QEBbuxVHkVZHpmU0NMBYuxa0B869YZENT87sTM6DVwtvr75CZvACWxv/hcL3lR68uKBjw==}
+
+  '@unocss/transformer-attributify-jsx-babel@0.60.4':
+    resolution: {integrity: sha512-BL4g2gyLpbseu+fOhkAHKNxYcHcn7brQAjXj5k5Yyy6wpwm43lzHYPZtRPrbLVLniqqAN21FzEbtJXCPIHKlHA==}
+
+  '@unocss/transformer-attributify-jsx@0.60.4':
+    resolution: {integrity: sha512-tQwD1T8Juz5F4JHYxTgekCv5olEegAPRZwAgx75pP+X2+PkV670pdXv8zbK0t5q6bvyF53vEVBrgQ9q1xSH9yQ==}
+
+  '@unocss/transformer-compile-class@0.60.4':
+    resolution: {integrity: sha512-zIqKQ7javiCb9Q3fbMvx1QVln8OqvAzWwgCVHsPINzDrDi73KXa3eeCU6GNlsd46tzy0Y9ryRIvW73YS+9Oj1w==}
+
+  '@unocss/transformer-directives@0.60.4':
+    resolution: {integrity: sha512-u3fQI8RszMhUevhJICtQ/bNpAfbh8MEXQf7YNnzUvLvbXGkkoieyU5mj0ray6fbToqxfxVceQtXYcFYIuf4aNg==}
+
+  '@unocss/transformer-variant-group@0.60.4':
+    resolution: {integrity: sha512-R4d16G7s3fDXj9prUNFnJi8cZvH8/XZsqiKDzCBjXNKrbf9zp7YnWD2VaMFjUISgW5kSQjQNSWK84soVNWq3UQ==}
+
+  '@unocss/vite@0.60.4':
+    resolution: {integrity: sha512-af9hhtW11geF56cotKUE16Fr+FirTdV/Al/usjKJ6P5hnCEQnqSHXQDFXL5Y6vXwcvLDmOhHYNrVR8duKgC8Mw==}
+    peerDependencies:
+      vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
+
+  '@vant/popperjs@1.3.0':
+    resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
+
+  '@vant/use@1.6.0':
+    resolution: {integrity: sha512-PHHxeAASgiOpSmMjceweIrv2AxDZIkWXyaczksMoWvKV2YAYEhoizRuk/xFnKF+emUIi46TsQ+rvlm/t2BBCfA==}
+    peerDependencies:
+      vue: ^3.0.0
+
+  '@vitejs/plugin-vue-jsx@3.1.0':
+    resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^4.0.0 || ^5.0.0
+      vue: ^3.0.0
+
+  '@vitejs/plugin-vue@5.0.5':
+    resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    peerDependencies:
+      vite: ^5.0.0
+      vue: ^3.2.25
+
+  '@volar/language-core@2.2.5':
+    resolution: {integrity: sha512-2htyAuxRrAgETmFeUhT4XLELk3LiEcqoW/B8YUXMF6BrGWLMwIR09MFaZYvrA2UhbdAeSyeQ726HaWSWkexUcQ==}
+
+  '@volar/source-map@2.2.5':
+    resolution: {integrity: sha512-wrOEIiZNf4E+PWB0AxyM4tfhkfldPsb3bxg8N6FHrxJH2ohar7aGu48e98bp3pR9HUA7P/pR9VrLmkTrgCCnWQ==}
+
+  '@volar/typescript@2.2.5':
+    resolution: {integrity: sha512-eSV/n75+ppfEVugMC/salZsI44nXDPAyL6+iTYCNLtiLHGJsnMv9GwiDMujrvAUj/aLQyqRJgYtXRoxop2clCw==}
+
+  '@vue/babel-helper-vue-transform-on@1.2.2':
+    resolution: {integrity: sha512-nOttamHUR3YzdEqdM/XXDyCSdxMA9VizUKoroLX6yTyRtggzQMHXcmwh8a7ZErcJttIBIc9s68a1B8GZ+Dmvsw==}
+
+  '@vue/babel-plugin-jsx@1.2.2':
+    resolution: {integrity: sha512-nYTkZUVTu4nhP199UoORePsql0l+wj7v/oyQjtThUVhJl1U+6qHuoVhIvR3bf7eVKjbCK+Cs2AWd7mi9Mpz9rA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    peerDependenciesMeta:
+      '@babel/core':
+        optional: true
+
+  '@vue/babel-plugin-resolve-type@1.2.2':
+    resolution: {integrity: sha512-EntyroPwNg5IPVdUJupqs0CFzuf6lUrVvCspmv2J1FITLeGnUCuoGNNk78dgCusxEiYj6RMkTJflGSxk5aIC4A==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@vue/compiler-core@3.4.27':
+    resolution: {integrity: sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==}
+
+  '@vue/compiler-dom@3.4.27':
+    resolution: {integrity: sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==}
+
+  '@vue/compiler-sfc@3.4.27':
+    resolution: {integrity: sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==}
+
+  '@vue/compiler-ssr@3.4.27':
+    resolution: {integrity: sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==}
+
+  '@vue/devtools-api@6.6.3':
+    resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
+
+  '@vue/devtools-core@7.2.1':
+    resolution: {integrity: sha512-OyWl455UnJIVgZ6lo5WQ79WbDMoXtSRwyNKp9WzCZ0HhuQywIk4qv59KtLRe75uVmtGBde4hXNaSyRm+x9bY6g==}
+
+  '@vue/devtools-kit@7.2.1':
+    resolution: {integrity: sha512-Wak/fin1X0Q8LLIfCAHBrdaaB+R6IdpSXsDByPHbQ3BmkCP0/cIo/oEGp9i0U2+gEqD4L3V9RDjNf1S34DTzQQ==}
+    peerDependencies:
+      vue: ^3.0.0
+
+  '@vue/devtools-shared@7.2.1':
+    resolution: {integrity: sha512-PCJF4UknJmOal68+X9XHyVeQ+idv0LFujkTOIW30+GaMJqwFVN9LkQKX4gLqn61KkGMdJTzQ1bt7EJag3TI6AA==}
+
+  '@vue/eslint-config-prettier@9.0.0':
+    resolution: {integrity: sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==}
+    peerDependencies:
+      eslint: '>= 8.0.0'
+      prettier: '>= 3.0.0'
+
+  '@vue/eslint-config-typescript@13.0.0':
+    resolution: {integrity: sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==}
+    engines: {node: ^18.18.0 || >=20.0.0}
+    peerDependencies:
+      eslint: ^8.56.0
+      eslint-plugin-vue: ^9.0.0
+      typescript: '>=4.7.4'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@vue/language-core@2.0.19':
+    resolution: {integrity: sha512-A9EGOnvb51jOvnCYoRLnMP+CcoPlbZVxI9gZXE/y2GksRWM6j/PrLEIC++pnosWTN08tFpJgxhSS//E9v/Sg+Q==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@vue/reactivity@3.4.27':
+    resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==}
+
+  '@vue/runtime-core@3.4.27':
+    resolution: {integrity: sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==}
+
+  '@vue/runtime-dom@3.4.27':
+    resolution: {integrity: sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==}
+
+  '@vue/server-renderer@3.4.27':
+    resolution: {integrity: sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==}
+    peerDependencies:
+      vue: 3.4.27
+
+  '@vue/shared@3.4.27':
+    resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==}
+
+  '@vue/tsconfig@0.5.1':
+    resolution: {integrity: sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==}
+
+  '@vueuse/core@10.10.0':
+    resolution: {integrity: sha512-vexJ/YXYs2S42B783rI95lMt3GzEwkxzC8Hb0Ndpd8rD+p+Lk/Za4bd797Ym7yq4jXqdSyj3JLChunF/vyYjUw==}
+
+  '@vueuse/metadata@10.10.0':
+    resolution: {integrity: sha512-UNAo2sTCAW5ge6OErPEHb5z7NEAg3XcO9Cj7OK45aZXfLLH1QkexDcZD77HBi5zvEiLOm1An+p/4b5K3Worpug==}
+
+  '@vueuse/shared@10.10.0':
+    resolution: {integrity: sha512-2aW33Ac0Uk0U+9yo3Ypg9s5KcR42cuehRWl7vnUHadQyFvCktseyxxEPBi1Eiq4D2yBGACOnqLZpx1eMc7g5Og==}
+
+  acorn-jsx@5.3.2:
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+  acorn@8.11.3:
+    resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+  ansi-regex@2.1.1:
+    resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
+    engines: {node: '>=0.10.0'}
+
+  ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+
+  ansi-styles@2.2.1:
+    resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
+    engines: {node: '>=0.10.0'}
+
+  ansi-styles@3.2.1:
+    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+    engines: {node: '>=4'}
+
+  ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+
+  ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+
+  anymatch@3.1.3:
+    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+    engines: {node: '>= 8'}
+
+  argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+  arr-diff@4.0.0:
+    resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==}
+    engines: {node: '>=0.10.0'}
+
+  arr-flatten@1.1.0:
+    resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==}
+    engines: {node: '>=0.10.0'}
+
+  arr-union@3.1.0:
+    resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==}
+    engines: {node: '>=0.10.0'}
+
+  array-buffer-byte-length@1.0.1:
+    resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
+    engines: {node: '>= 0.4'}
+
+  array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+
+  array-unique@0.3.2:
+    resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==}
+    engines: {node: '>=0.10.0'}
+
+  arraybuffer.prototype.slice@1.0.3:
+    resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
+    engines: {node: '>= 0.4'}
+
+  assign-symbols@1.0.0:
+    resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
+    engines: {node: '>=0.10.0'}
+
+  asynckit@0.4.0:
+    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+  atob@2.1.2:
+    resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
+    engines: {node: '>= 4.5.0'}
+    hasBin: true
+
+  autoprefixer@10.4.19:
+    resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==}
+    engines: {node: ^10 || ^12 || >=14}
+    hasBin: true
+    peerDependencies:
+      postcss: ^8.1.0
+
+  available-typed-arrays@1.0.7:
+    resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+    engines: {node: '>= 0.4'}
+
+  axios@1.7.2:
+    resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
+
+  balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+  base@0.11.2:
+    resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
+    engines: {node: '>=0.10.0'}
+
+  big.js@5.2.2:
+    resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
+
+  binary-extensions@2.3.0:
+    resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+    engines: {node: '>=8'}
+
+  bluebird@3.7.2:
+    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+
+  boolbase@1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+  brace-expansion@1.1.11:
+    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+  brace-expansion@2.0.1:
+    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+
+  braces@2.3.2:
+    resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
+    engines: {node: '>=0.10.0'}
+
+  braces@3.0.3:
+    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+    engines: {node: '>=8'}
+
+  browserslist@4.23.0:
+    resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+
+  bundle-name@4.1.0:
+    resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
+    engines: {node: '>=18'}
+
+  cac@6.7.14:
+    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+    engines: {node: '>=8'}
+
+  cache-base@1.0.1:
+    resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
+    engines: {node: '>=0.10.0'}
+
+  call-bind@1.0.7:
+    resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+    engines: {node: '>= 0.4'}
+
+  callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+
+  camelcase@6.3.0:
+    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+    engines: {node: '>=10'}
+
+  caniuse-lite@1.0.30001627:
+    resolution: {integrity: sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==}
+
+  chalk@1.1.3:
+    resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
+    engines: {node: '>=0.10.0'}
+
+  chalk@2.4.2:
+    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+    engines: {node: '>=4'}
+
+  chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+
+  chokidar@3.6.0:
+    resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+    engines: {node: '>= 8.10.0'}
+
+  class-utils@0.3.6:
+    resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
+    engines: {node: '>=0.10.0'}
+
+  clone@2.1.2:
+    resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
+    engines: {node: '>=0.8'}
+
+  collection-visit@1.0.0:
+    resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
+    engines: {node: '>=0.10.0'}
+
+  color-convert@1.9.3:
+    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+
+  color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+
+  color-name@1.1.3:
+    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+  color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+  colorette@2.0.20:
+    resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
+  combined-stream@1.0.8:
+    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+    engines: {node: '>= 0.8'}
+
+  commander@7.2.0:
+    resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+    engines: {node: '>= 10'}
+
+  component-emitter@1.3.1:
+    resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
+
+  computeds@0.0.1:
+    resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
+
+  concat-map@0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+  confbox@0.1.7:
+    resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==}
+
+  consola@3.2.3:
+    resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
+    engines: {node: ^14.18.0 || >=16.10.0}
+
+  convert-source-map@2.0.0:
+    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+  copy-anything@2.0.6:
+    resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
+
+  copy-descriptor@0.1.1:
+    resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
+    engines: {node: '>=0.10.0'}
+
+  cors@2.8.5:
+    resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+    engines: {node: '>= 0.10'}
+
+  cross-spawn@7.0.3:
+    resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+    engines: {node: '>= 8'}
+
+  css-select@4.3.0:
+    resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
+
+  css-tree@1.1.3:
+    resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
+    engines: {node: '>=8.0.0'}
+
+  css-tree@2.3.1:
+    resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
+    engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+  css-what@6.1.0:
+    resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+    engines: {node: '>= 6'}
+
+  cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  csso@4.2.0:
+    resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==}
+    engines: {node: '>=8.0.0'}
+
+  csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+  data-view-buffer@1.0.1:
+    resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
+    engines: {node: '>= 0.4'}
+
+  data-view-byte-length@1.0.1:
+    resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
+    engines: {node: '>= 0.4'}
+
+  data-view-byte-offset@1.0.0:
+    resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
+    engines: {node: '>= 0.4'}
+
+  dayjs@1.11.11:
+    resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
+
+  de-indent@1.0.2:
+    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+
+  debug@2.6.9:
+    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  debug@4.3.5:
+    resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  decode-uri-component@0.2.2:
+    resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
+    engines: {node: '>=0.10'}
+
+  deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+  default-browser-id@5.0.0:
+    resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
+    engines: {node: '>=18'}
+
+  default-browser@5.2.1:
+    resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
+    engines: {node: '>=18'}
+
+  define-data-property@1.1.4:
+    resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+    engines: {node: '>= 0.4'}
+
+  define-lazy-prop@3.0.0:
+    resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
+    engines: {node: '>=12'}
+
+  define-properties@1.2.1:
+    resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+    engines: {node: '>= 0.4'}
+
+  define-property@0.2.5:
+    resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==}
+    engines: {node: '>=0.10.0'}
+
+  define-property@1.0.0:
+    resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==}
+    engines: {node: '>=0.10.0'}
+
+  define-property@2.0.2:
+    resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==}
+    engines: {node: '>=0.10.0'}
+
+  defu@6.1.4:
+    resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
+  delayed-stream@1.0.0:
+    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+    engines: {node: '>=0.4.0'}
+
+  destr@2.0.3:
+    resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==}
+
+  dir-glob@3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+
+  doctrine@3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+
+  dom-serializer@0.2.2:
+    resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
+
+  dom-serializer@1.4.1:
+    resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
+
+  domelementtype@1.3.1:
+    resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
+
+  domelementtype@2.3.0:
+    resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+  domhandler@2.4.2:
+    resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==}
+
+  domhandler@4.3.1:
+    resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
+    engines: {node: '>= 4'}
+
+  domutils@1.7.0:
+    resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
+
+  domutils@2.8.0:
+    resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
+
+  duplexer@0.1.2:
+    resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+
+  electron-to-chromium@1.4.789:
+    resolution: {integrity: sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==}
+
+  emojis-list@3.0.0:
+    resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
+    engines: {node: '>= 4'}
+
+  entities@1.1.2:
+    resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
+
+  entities@2.2.0:
+    resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
+
+  entities@4.5.0:
+    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+    engines: {node: '>=0.12'}
+
+  errno@0.1.8:
+    resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
+    hasBin: true
+
+  error-stack-parser-es@0.1.4:
+    resolution: {integrity: sha512-l0uy0kAoo6toCgVOYaAayqtPa2a1L15efxUMEnQebKwLQX2X0OpS6wMMQdc4juJXmxd9i40DuaUHq+mjIya9TQ==}
+
+  es-abstract@1.23.3:
+    resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
+    engines: {node: '>= 0.4'}
+
+  es-define-property@1.0.0:
+    resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+    engines: {node: '>= 0.4'}
+
+  es-errors@1.3.0:
+    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+    engines: {node: '>= 0.4'}
+
+  es-object-atoms@1.0.0:
+    resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
+    engines: {node: '>= 0.4'}
+
+  es-set-tostringtag@2.0.3:
+    resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
+    engines: {node: '>= 0.4'}
+
+  es-to-primitive@1.2.1:
+    resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+    engines: {node: '>= 0.4'}
+
+  esbuild@0.20.2:
+    resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
+    engines: {node: '>=12'}
+    hasBin: true
+
+  escalade@3.1.2:
+    resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
+    engines: {node: '>=6'}
+
+  escape-string-regexp@1.0.5:
+    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+    engines: {node: '>=0.8.0'}
+
+  escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+
+  escape-string-regexp@5.0.0:
+    resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+    engines: {node: '>=12'}
+
+  eslint-config-prettier@9.1.0:
+    resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
+    hasBin: true
+    peerDependencies:
+      eslint: '>=7.0.0'
+
+  eslint-plugin-prettier@5.1.3:
+    resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      '@types/eslint': '>=8.0.0'
+      eslint: '>=8.0.0'
+      eslint-config-prettier: '*'
+      prettier: '>=3.0.0'
+    peerDependenciesMeta:
+      '@types/eslint':
+        optional: true
+      eslint-config-prettier:
+        optional: true
+
+  eslint-plugin-vue@9.26.0:
+    resolution: {integrity: sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
+
+  eslint-scope@7.2.2:
+    resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint-visitor-keys@3.4.3:
+    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint@8.57.0:
+    resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+
+  espree@9.6.1:
+    resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  esquery@1.5.0:
+    resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+    engines: {node: '>=0.10'}
+
+  esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+
+  estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+
+  estree-walker@2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  estree-walker@3.0.3:
+    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+  esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+
+  etag@1.8.1:
+    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+    engines: {node: '>= 0.6'}
+
+  execa@5.1.1:
+    resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+    engines: {node: '>=10'}
+
+  execa@8.0.1:
+    resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+    engines: {node: '>=16.17'}
+
+  expand-brackets@2.1.4:
+    resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
+    engines: {node: '>=0.10.0'}
+
+  extend-shallow@2.0.1:
+    resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
+    engines: {node: '>=0.10.0'}
+
+  extend-shallow@3.0.2:
+    resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==}
+    engines: {node: '>=0.10.0'}
+
+  extglob@2.0.4:
+    resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==}
+    engines: {node: '>=0.10.0'}
+
+  fast-deep-equal@3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+  fast-diff@1.3.0:
+    resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+
+  fast-glob@3.3.2:
+    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+    engines: {node: '>=8.6.0'}
+
+  fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+  fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+  fastq@1.17.1:
+    resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+
+  file-entry-cache@6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  file-saver@2.0.5:
+    resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+
+  fill-range@4.0.0:
+    resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==}
+    engines: {node: '>=0.10.0'}
+
+  fill-range@7.1.1:
+    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+    engines: {node: '>=8'}
+
+  find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+
+  flat-cache@3.2.0:
+    resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+
+  flatted@3.3.1:
+    resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+
+  follow-redirects@1.15.6:
+    resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+
+  for-each@0.3.3:
+    resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+
+  for-in@1.0.2:
+    resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
+    engines: {node: '>=0.10.0'}
+
+  form-data@4.0.0:
+    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+    engines: {node: '>= 6'}
+
+  fraction.js@4.3.7:
+    resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+
+  fragment-cache@0.2.1:
+    resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==}
+    engines: {node: '>=0.10.0'}
+
+  fs-extra@10.1.0:
+    resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
+    engines: {node: '>=12'}
+
+  fs-extra@11.2.0:
+    resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
+    engines: {node: '>=14.14'}
+
+  fs.realpath@1.0.0:
+    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  function-bind@1.1.2:
+    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+  function.prototype.name@1.1.6:
+    resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
+    engines: {node: '>= 0.4'}
+
+  functions-have-names@1.2.3:
+    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+  gensync@1.0.0-beta.2:
+    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+    engines: {node: '>=6.9.0'}
+
+  get-intrinsic@1.2.4:
+    resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+    engines: {node: '>= 0.4'}
+
+  get-stream@6.0.1:
+    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+    engines: {node: '>=10'}
+
+  get-stream@8.0.1:
+    resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+    engines: {node: '>=16'}
+
+  get-symbol-description@1.0.2:
+    resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
+    engines: {node: '>= 0.4'}
+
+  get-value@2.0.6:
+    resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==}
+    engines: {node: '>=0.10.0'}
+
+  glob-parent@5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+
+  glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+
+  glob@7.2.3:
+    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    deprecated: Glob versions prior to v9 are no longer supported
+
+  globals@11.12.0:
+    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+    engines: {node: '>=4'}
+
+  globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+    engines: {node: '>=8'}
+
+  globalthis@1.0.4:
+    resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
+    engines: {node: '>= 0.4'}
+
+  globby@11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+
+  gopd@1.0.1:
+    resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+
+  graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+  graphemer@1.4.0:
+    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+  gzip-size@6.0.0:
+    resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
+    engines: {node: '>=10'}
+
+  has-ansi@2.0.0:
+    resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==}
+    engines: {node: '>=0.10.0'}
+
+  has-bigints@1.0.2:
+    resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+
+  has-flag@1.0.0:
+    resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==}
+    engines: {node: '>=0.10.0'}
+
+  has-flag@3.0.0:
+    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+    engines: {node: '>=4'}
+
+  has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+
+  has-property-descriptors@1.0.2:
+    resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+  has-proto@1.0.3:
+    resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+    engines: {node: '>= 0.4'}
+
+  has-symbols@1.0.3:
+    resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+    engines: {node: '>= 0.4'}
+
+  has-tostringtag@1.0.2:
+    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+    engines: {node: '>= 0.4'}
+
+  has-value@0.3.1:
+    resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==}
+    engines: {node: '>=0.10.0'}
+
+  has-value@1.0.0:
+    resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==}
+    engines: {node: '>=0.10.0'}
+
+  has-values@0.1.4:
+    resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==}
+    engines: {node: '>=0.10.0'}
+
+  has-values@1.0.0:
+    resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==}
+    engines: {node: '>=0.10.0'}
+
+  hasown@2.0.2:
+    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+    engines: {node: '>= 0.4'}
+
+  he@1.2.0:
+    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+    hasBin: true
+
+  hookable@5.5.3:
+    resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
+
+  html-tags@3.3.1:
+    resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
+    engines: {node: '>=8'}
+
+  htmlparser2@3.10.1:
+    resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
+
+  human-signals@2.1.0:
+    resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+    engines: {node: '>=10.17.0'}
+
+  human-signals@5.0.0:
+    resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+    engines: {node: '>=16.17.0'}
+
+  iconv-lite@0.6.3:
+    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+    engines: {node: '>=0.10.0'}
+
+  ignore@5.3.1:
+    resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+    engines: {node: '>= 4'}
+
+  image-size@0.5.5:
+    resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  import-fresh@3.3.0:
+    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+    engines: {node: '>=6'}
+
+  imurmurhash@0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+
+  inflight@1.0.6:
+    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+    deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+  inherits@2.0.4:
+    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+  internal-slot@1.0.7:
+    resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
+    engines: {node: '>= 0.4'}
+
+  is-accessor-descriptor@1.0.1:
+    resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==}
+    engines: {node: '>= 0.10'}
+
+  is-array-buffer@3.0.4:
+    resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
+    engines: {node: '>= 0.4'}
+
+  is-bigint@1.0.4:
+    resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+
+  is-binary-path@2.1.0:
+    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+    engines: {node: '>=8'}
+
+  is-boolean-object@1.1.2:
+    resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+    engines: {node: '>= 0.4'}
+
+  is-buffer@1.1.6:
+    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+
+  is-callable@1.2.7:
+    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+    engines: {node: '>= 0.4'}
+
+  is-core-module@2.13.1:
+    resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+
+  is-data-descriptor@1.0.1:
+    resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==}
+    engines: {node: '>= 0.4'}
+
+  is-data-view@1.0.1:
+    resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
+    engines: {node: '>= 0.4'}
+
+  is-date-object@1.0.5:
+    resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+    engines: {node: '>= 0.4'}
+
+  is-descriptor@0.1.7:
+    resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==}
+    engines: {node: '>= 0.4'}
+
+  is-descriptor@1.0.3:
+    resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==}
+    engines: {node: '>= 0.4'}
+
+  is-docker@3.0.0:
+    resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    hasBin: true
+
+  is-extendable@0.1.1:
+    resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
+    engines: {node: '>=0.10.0'}
+
+  is-extendable@1.0.1:
+    resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==}
+    engines: {node: '>=0.10.0'}
+
+  is-extglob@2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-glob@4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+
+  is-inside-container@1.0.0:
+    resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
+    engines: {node: '>=14.16'}
+    hasBin: true
+
+  is-negative-zero@2.0.3:
+    resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+    engines: {node: '>= 0.4'}
+
+  is-number-object@1.0.7:
+    resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+    engines: {node: '>= 0.4'}
+
+  is-number@3.0.0:
+    resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==}
+    engines: {node: '>=0.10.0'}
+
+  is-number@7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+
+  is-path-inside@3.0.3:
+    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+    engines: {node: '>=8'}
+
+  is-plain-obj@1.1.0:
+    resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
+    engines: {node: '>=0.10.0'}
+
+  is-plain-object@2.0.4:
+    resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
+    engines: {node: '>=0.10.0'}
+
+  is-regex@1.1.4:
+    resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+    engines: {node: '>= 0.4'}
+
+  is-shared-array-buffer@1.0.3:
+    resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
+    engines: {node: '>= 0.4'}
+
+  is-stream@2.0.1:
+    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+    engines: {node: '>=8'}
+
+  is-stream@3.0.0:
+    resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  is-string@1.0.7:
+    resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+    engines: {node: '>= 0.4'}
+
+  is-symbol@1.0.4:
+    resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+    engines: {node: '>= 0.4'}
+
+  is-typed-array@1.1.13:
+    resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
+    engines: {node: '>= 0.4'}
+
+  is-weakref@1.0.2:
+    resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+
+  is-what@3.14.1:
+    resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
+
+  is-windows@1.0.2:
+    resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
+    engines: {node: '>=0.10.0'}
+
+  is-wsl@3.1.0:
+    resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
+    engines: {node: '>=16'}
+
+  isarray@1.0.0:
+    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+
+  isarray@2.0.5:
+    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+  isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+  isobject@2.1.0:
+    resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
+    engines: {node: '>=0.10.0'}
+
+  isobject@3.0.1:
+    resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
+    engines: {node: '>=0.10.0'}
+
+  jiti@1.21.1:
+    resolution: {integrity: sha512-KMXpzEJMsOFyRj6ZpDTnnlJrdr9umUY+eut5vlRvjVixohitnRFIRTFw9MEu9zPlBxTHZo6xD5ftKYiQZuJYQw==}
+    hasBin: true
+
+  js-base64@2.6.4:
+    resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
+
+  js-tokens@4.0.0:
+    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+  js-tokens@9.0.0:
+    resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==}
+
+  js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+
+  jsesc@2.5.2:
+    resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  json-buffer@3.0.1:
+    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+  json-parse-even-better-errors@3.0.2:
+    resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+  json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+  json5@1.0.2:
+    resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+    hasBin: true
+
+  json5@2.2.3:
+    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  jsonfile@6.1.0:
+    resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+
+  keyv@4.5.4:
+    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+  kind-of@3.2.2:
+    resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
+    engines: {node: '>=0.10.0'}
+
+  kind-of@4.0.0:
+    resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==}
+    engines: {node: '>=0.10.0'}
+
+  kind-of@5.1.0:
+    resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==}
+    engines: {node: '>=0.10.0'}
+
+  kind-of@6.0.3:
+    resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+    engines: {node: '>=0.10.0'}
+
+  kolorist@1.8.0:
+    resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+
+  less@4.2.0:
+    resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+
+  loader-utils@1.4.2:
+    resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
+    engines: {node: '>=4.0.0'}
+
+  local-pkg@0.5.0:
+    resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
+    engines: {node: '>=14'}
+
+  locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+
+  lodash-es@4.17.21:
+    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+
+  lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+  lodash@4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+  lru-cache@5.1.1:
+    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+  magic-string@0.25.9:
+    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+
+  magic-string@0.30.10:
+    resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+
+  make-dir@2.1.0:
+    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+    engines: {node: '>=6'}
+
+  map-cache@0.2.2:
+    resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
+    engines: {node: '>=0.10.0'}
+
+  map-visit@1.0.0:
+    resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==}
+    engines: {node: '>=0.10.0'}
+
+  mdn-data@2.0.14:
+    resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
+
+  mdn-data@2.0.30:
+    resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
+
+  memorystream@0.3.1:
+    resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
+    engines: {node: '>= 0.10.0'}
+
+  merge-options@1.0.1:
+    resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==}
+    engines: {node: '>=4'}
+
+  merge-stream@2.0.0:
+    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+  merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+
+  micromatch@3.1.0:
+    resolution: {integrity: sha512-3StSelAE+hnRvMs8IdVW7Uhk8CVed5tp+kLLGlBP6WiRAXS21GPGu/Nat4WNPXj2Eoc24B02SaeoyozPMfj0/g==}
+    engines: {node: '>=0.10.0'}
+
+  micromatch@4.0.7:
+    resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
+    engines: {node: '>=8.6'}
+
+  mime-db@1.52.0:
+    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+    engines: {node: '>= 0.6'}
+
+  mime-types@2.1.35:
+    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+    engines: {node: '>= 0.6'}
+
+  mime@1.6.0:
+    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  mimic-fn@2.1.0:
+    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+    engines: {node: '>=6'}
+
+  mimic-fn@4.0.0:
+    resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+    engines: {node: '>=12'}
+
+  minimatch@3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+  minimatch@9.0.4:
+    resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimist@1.2.8:
+    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+  mitt@3.0.1:
+    resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
+
+  mixin-deep@1.3.2:
+    resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
+    engines: {node: '>=0.10.0'}
+
+  mlly@1.7.0:
+    resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==}
+
+  mrmime@2.0.0:
+    resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
+    engines: {node: '>=10'}
+
+  ms@2.0.0:
+    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
+  ms@2.1.2:
+    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+  muggle-string@0.4.1:
+    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+
+  nanoid@3.3.7:
+    resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  nanomatch@1.2.13:
+    resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
+    engines: {node: '>=0.10.0'}
+
+  natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+  needle@3.3.1:
+    resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
+    engines: {node: '>= 4.4.x'}
+    hasBin: true
+
+  node-fetch-native@1.6.4:
+    resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==}
+
+  node-releases@2.0.14:
+    resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+
+  normalize-path@3.0.0:
+    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+    engines: {node: '>=0.10.0'}
+
+  normalize-range@0.1.2:
+    resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+    engines: {node: '>=0.10.0'}
+
+  npm-normalize-package-bin@3.0.1:
+    resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  npm-run-all2@6.2.0:
+    resolution: {integrity: sha512-wA7yVIkthe6qJBfiJ2g6aweaaRlw72itsFGF6HuwCHKwtwAx/4BY1vVpk6bw6lS8RLMsexoasOkd0aYOmsFG7Q==}
+    engines: {node: ^14.18.0 || >=16.0.0, npm: '>= 8'}
+    hasBin: true
+
+  npm-run-path@4.0.1:
+    resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+    engines: {node: '>=8'}
+
+  npm-run-path@5.3.0:
+    resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  nprogress@0.2.0:
+    resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
+
+  nth-check@2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+  object-assign@4.1.1:
+    resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+    engines: {node: '>=0.10.0'}
+
+  object-copy@0.1.0:
+    resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==}
+    engines: {node: '>=0.10.0'}
+
+  object-inspect@1.13.1:
+    resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+
+  object-keys@1.1.1:
+    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+    engines: {node: '>= 0.4'}
+
+  object-visit@1.0.1:
+    resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==}
+    engines: {node: '>=0.10.0'}
+
+  object.assign@4.1.5:
+    resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
+    engines: {node: '>= 0.4'}
+
+  object.pick@1.3.0:
+    resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==}
+    engines: {node: '>=0.10.0'}
+
+  ofetch@1.3.4:
+    resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==}
+
+  once@1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+  onetime@5.1.2:
+    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+    engines: {node: '>=6'}
+
+  onetime@6.0.0:
+    resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+    engines: {node: '>=12'}
+
+  open@10.1.0:
+    resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
+    engines: {node: '>=18'}
+
+  optionator@0.9.4:
+    resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+    engines: {node: '>= 0.8.0'}
+
+  p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+
+  p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+
+  parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+
+  parse-node-version@1.0.1:
+    resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
+    engines: {node: '>= 0.10'}
+
+  pascalcase@0.1.1:
+    resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
+    engines: {node: '>=0.10.0'}
+
+  path-browserify@1.0.1:
+    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
+  path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+
+  path-is-absolute@1.0.1:
+    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+    engines: {node: '>=0.10.0'}
+
+  path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+
+  path-key@4.0.0:
+    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+    engines: {node: '>=12'}
+
+  path-parse@1.0.7:
+    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+  path-type@4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+
+  pathe@0.2.0:
+    resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
+
+  pathe@1.1.2:
+    resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+
+  perfect-debounce@1.0.0:
+    resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
+
+  perfect-freehand@1.2.2:
+    resolution: {integrity: sha512-eh31l019WICQ03pkF3FSzHxB8n07ItqIQ++G5UV8JX0zVOXzgTGCqnRR0jJ2h9U8/2uW4W4mtGJELt9kEV0CFQ==}
+
+  picocolors@1.0.1:
+    resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
+
+  picomatch@2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+
+  pidtree@0.6.0:
+    resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+    engines: {node: '>=0.10'}
+    hasBin: true
+
+  pify@4.0.1:
+    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+    engines: {node: '>=6'}
+
+  pinia-plugin-persistedstate@3.2.1:
+    resolution: {integrity: sha512-MK++8LRUsGF7r45PjBFES82ISnPzyO6IZx3CH5vyPseFLZCk1g2kgx6l/nW8pEBKxxd4do0P6bJw+mUSZIEZUQ==}
+    peerDependencies:
+      pinia: ^2.0.0
+
+  pinia@2.1.7:
+    resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==}
+    peerDependencies:
+      '@vue/composition-api': ^1.4.0
+      typescript: '>=4.4.4'
+      vue: ^2.6.14 || ^3.3.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+      typescript:
+        optional: true
+
+  pkg-types@1.1.1:
+    resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==}
+
+  posix-character-classes@0.1.1:
+    resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
+    engines: {node: '>=0.10.0'}
+
+  possible-typed-array-names@1.0.0:
+    resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
+    engines: {node: '>= 0.4'}
+
+  postcss-mobile-forever@4.1.4:
+    resolution: {integrity: sha512-/pf7nhOORMrKmniI4fJDUNmj3y/8ENibHvOAeP1Vpd1ulSmq1Q0ZgKtYLQs4CauGHhvZRltLN56yiyX8y3SZFg==}
+    peerDependencies:
+      postcss: ^8.0.0
+
+  postcss-prefix-selector@1.16.1:
+    resolution: {integrity: sha512-Umxu+FvKMwlY6TyDzGFoSUnzW+NOfMBLyC1tAkIjgX+Z/qGspJeRjVC903D7mx7TuBpJlwti2ibXtWuA7fKMeQ==}
+    peerDependencies:
+      postcss: '>4 <9'
+
+  postcss-selector-parser@6.1.0:
+    resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
+    engines: {node: '>=4'}
+
+  postcss-value-parser@4.2.0:
+    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+  postcss@5.2.18:
+    resolution: {integrity: sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==}
+    engines: {node: '>=0.12'}
+
+  postcss@8.4.38:
+    resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
+    engines: {node: ^10 || ^12 || >=14}
+
+  posthtml-parser@0.2.1:
+    resolution: {integrity: sha512-nPC53YMqJnc/+1x4fRYFfm81KV2V+G9NZY+hTohpYg64Ay7NemWWcV4UWuy/SgMupqQ3kJ88M/iRfZmSnxT+pw==}
+
+  posthtml-rename-id@1.0.12:
+    resolution: {integrity: sha512-UKXf9OF/no8WZo9edRzvuMenb6AD5hDLzIepJW+a4oJT+T/Lx7vfMYWT4aWlGNQh0WMhnUx1ipN9OkZ9q+ddEw==}
+
+  posthtml-render@1.4.0:
+    resolution: {integrity: sha512-W1779iVHGfq0Fvh2PROhCe2QhB8mEErgqzo1wpIt36tCgChafP+hbXIhLDOM8ePJrZcFs0vkNEtdibEWVqChqw==}
+    engines: {node: '>=10'}
+
+  posthtml-svg-mode@1.0.3:
+    resolution: {integrity: sha512-hEqw9NHZ9YgJ2/0G7CECOeuLQKZi8HjWLkBaSVtOWjygQ9ZD8P7tqeowYs7WrFdKsWEKG7o+IlsPY8jrr0CJpQ==}
+
+  posthtml@0.9.2:
+    resolution: {integrity: sha512-spBB5sgC4cv2YcW03f/IAUN1pgDJWNWD8FzkyY4mArLUMJW+KlQhlmUdKAHQuPfb00Jl5xIfImeOsf6YL8QK7Q==}
+    engines: {node: '>=0.10.0'}
+
+  prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+
+  prettier-linter-helpers@1.0.0:
+    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+    engines: {node: '>=6.0.0'}
+
+  prettier@3.3.0:
+    resolution: {integrity: sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  proxy-from-env@1.1.0:
+    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+  prr@1.0.1:
+    resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
+
+  punycode@2.3.1:
+    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+    engines: {node: '>=6'}
+
+  qs@6.12.1:
+    resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==}
+    engines: {node: '>=0.6'}
+
+  query-string@4.3.4:
+    resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==}
+    engines: {node: '>=0.10.0'}
+
+  queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+  read-package-json-fast@3.0.2:
+    resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  readable-stream@3.6.2:
+    resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+    engines: {node: '>= 6'}
+
+  readdirp@3.6.0:
+    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+    engines: {node: '>=8.10.0'}
+
+  regex-not@1.0.2:
+    resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==}
+    engines: {node: '>=0.10.0'}
+
+  regexp.prototype.flags@1.5.2:
+    resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
+    engines: {node: '>= 0.4'}
+
+  repeat-element@1.1.4:
+    resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
+    engines: {node: '>=0.10.0'}
+
+  repeat-string@1.6.1:
+    resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
+    engines: {node: '>=0.10'}
+
+  resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+
+  resolve-url@0.2.1:
+    resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
+    deprecated: https://github.com/lydell/resolve-url#deprecated
+
+  resolve@1.22.8:
+    resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+    hasBin: true
+
+  ret@0.1.15:
+    resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
+    engines: {node: '>=0.12'}
+
+  reusify@1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+  rfdc@1.3.1:
+    resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
+
+  rimraf@3.0.2:
+    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    deprecated: Rimraf versions prior to v4 are no longer supported
+    hasBin: true
+
+  rollup@4.18.0:
+    resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==}
+    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+    hasBin: true
+
+  run-applescript@7.0.0:
+    resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
+    engines: {node: '>=18'}
+
+  run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+  safe-array-concat@1.1.2:
+    resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
+    engines: {node: '>=0.4'}
+
+  safe-buffer@5.2.1:
+    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+  safe-regex-test@1.0.3:
+    resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
+    engines: {node: '>= 0.4'}
+
+  safe-regex@1.1.0:
+    resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==}
+
+  safer-buffer@2.1.2:
+    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+  sax@1.4.1:
+    resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
+
+  scule@1.3.0:
+    resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+
+  semver@5.7.2:
+    resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+    hasBin: true
+
+  semver@6.3.1:
+    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+    hasBin: true
+
+  semver@7.6.2:
+    resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  set-function-length@1.2.2:
+    resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+    engines: {node: '>= 0.4'}
+
+  set-function-name@2.0.2:
+    resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+    engines: {node: '>= 0.4'}
+
+  set-value@2.0.1:
+    resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
+    engines: {node: '>=0.10.0'}
+
+  shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+
+  shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+
+  shell-quote@1.8.1:
+    resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
+
+  side-channel@1.0.6:
+    resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+    engines: {node: '>= 0.4'}
+
+  signal-exit@3.0.7:
+    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+  signal-exit@4.1.0:
+    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+    engines: {node: '>=14'}
+
+  sirv@2.0.4:
+    resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
+    engines: {node: '>= 10'}
+
+  slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+
+  snapdragon-node@2.1.1:
+    resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
+    engines: {node: '>=0.10.0'}
+
+  snapdragon-util@3.0.1:
+    resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==}
+    engines: {node: '>=0.10.0'}
+
+  snapdragon@0.8.2:
+    resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==}
+    engines: {node: '>=0.10.0'}
+
+  source-map-js@1.2.0:
+    resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+    engines: {node: '>=0.10.0'}
+
+  source-map-resolve@0.5.3:
+    resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
+    deprecated: See https://github.com/lydell/source-map-resolve#deprecated
+
+  source-map-url@0.4.1:
+    resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==}
+    deprecated: See https://github.com/lydell/source-map-url#deprecated
+
+  source-map@0.5.7:
+    resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+    engines: {node: '>=0.10.0'}
+
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  sourcemap-codec@1.4.8:
+    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+    deprecated: Please use @jridgewell/sourcemap-codec instead
+
+  speakingurl@14.0.1:
+    resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
+    engines: {node: '>=0.10.0'}
+
+  split-string@3.1.0:
+    resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
+    engines: {node: '>=0.10.0'}
+
+  stable@0.1.8:
+    resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
+    deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
+
+  static-extend@0.1.2:
+    resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
+    engines: {node: '>=0.10.0'}
+
+  strict-uri-encode@1.1.0:
+    resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==}
+    engines: {node: '>=0.10.0'}
+
+  string.prototype.trim@1.2.9:
+    resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
+    engines: {node: '>= 0.4'}
+
+  string.prototype.trimend@1.0.8:
+    resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
+
+  string.prototype.trimstart@1.0.8:
+    resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+    engines: {node: '>= 0.4'}
+
+  string_decoder@1.3.0:
+    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
+  strip-ansi@3.0.1:
+    resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==}
+    engines: {node: '>=0.10.0'}
+
+  strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+
+  strip-final-newline@2.0.0:
+    resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+    engines: {node: '>=6'}
+
+  strip-final-newline@3.0.0:
+    resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+    engines: {node: '>=12'}
+
+  strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+
+  strip-literal@2.1.0:
+    resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
+
+  supports-color@2.0.0:
+    resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
+    engines: {node: '>=0.8.0'}
+
+  supports-color@3.2.3:
+    resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==}
+    engines: {node: '>=0.8.0'}
+
+  supports-color@5.5.0:
+    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+    engines: {node: '>=4'}
+
+  supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+
+  supports-preserve-symlinks-flag@1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+
+  svg-baker@1.7.0:
+    resolution: {integrity: sha512-nibslMbkXOIkqKVrfcncwha45f97fGuAOn1G99YwnwTj8kF9YiM6XexPcUso97NxOm6GsP0SIvYVIosBis1xLg==}
+
+  svg-tags@1.0.0:
+    resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
+
+  svgo@2.8.0:
+    resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+
+  synckit@0.8.8:
+    resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+
+  text-table@0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+
+  to-fast-properties@2.0.0:
+    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+    engines: {node: '>=4'}
+
+  to-object-path@0.3.0:
+    resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==}
+    engines: {node: '>=0.10.0'}
+
+  to-regex-range@2.1.1:
+    resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==}
+    engines: {node: '>=0.10.0'}
+
+  to-regex-range@5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+
+  to-regex@3.0.2:
+    resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==}
+    engines: {node: '>=0.10.0'}
+
+  totalist@3.0.1:
+    resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+    engines: {node: '>=6'}
+
+  traverse@0.6.9:
+    resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==}
+    engines: {node: '>= 0.4'}
+
+  ts-api-utils@1.3.0:
+    resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+    engines: {node: '>=16'}
+    peerDependencies:
+      typescript: '>=4.2.0'
+
+  tslib@2.6.3:
+    resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
+
+  type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+
+  type-fest@0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+
+  typed-array-buffer@1.0.2:
+    resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-byte-length@1.0.1:
+    resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-byte-offset@1.0.2:
+    resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
+    engines: {node: '>= 0.4'}
+
+  typed-array-length@1.0.6:
+    resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
+    engines: {node: '>= 0.4'}
+
+  typedarray.prototype.slice@1.0.3:
+    resolution: {integrity: sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==}
+    engines: {node: '>= 0.4'}
+
+  typescript@5.4.5:
+    resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  ufo@1.5.3:
+    resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
+
+  unbox-primitive@1.0.2:
+    resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+
+  unconfig@0.3.13:
+    resolution: {integrity: sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==}
+
+  undici-types@5.26.5:
+    resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
+  unimport@3.7.2:
+    resolution: {integrity: sha512-91mxcZTadgXyj3lFWmrGT8GyoRHWuE5fqPOjg5RVtF6vj+OfM5G6WCzXjuYtSgELE5ggB34RY4oiCSEP8I3AHw==}
+
+  union-value@1.0.1:
+    resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
+    engines: {node: '>=0.10.0'}
+
+  universalify@2.0.1:
+    resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+    engines: {node: '>= 10.0.0'}
+
+  unocss@0.60.4:
+    resolution: {integrity: sha512-KtYVzm1sV1J7hpXFvILPZiJVTni+XzC2vJzKYFTEe80fEGsrL+572YjS3QjZB52TMSppLYJk6WIVTb4mE4RmvQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@unocss/webpack': 0.60.4
+      vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0
+    peerDependenciesMeta:
+      '@unocss/webpack':
+        optional: true
+      vite:
+        optional: true
+
+  unplugin-auto-import@0.17.6:
+    resolution: {integrity: sha512-dmX0Pex5DzMzVuALkexboOZvh51fL/BD6aoPO7qHoTYGlQp0GRKsREv2KMF1lzYI9SXKQiRxAjwzbQnrFFNydQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@nuxt/kit': ^3.2.2
+      '@vueuse/core': '*'
+    peerDependenciesMeta:
+      '@nuxt/kit':
+        optional: true
+      '@vueuse/core':
+        optional: true
+
+  unplugin-vue-components@0.27.0:
+    resolution: {integrity: sha512-77eTEy23sQ0UpzGWnZ9I2mY3cnmXwklz4ITcn3JfxjCoX643ghImkiZ4nFm58sxbdVcc4Fo/o4LIoFnlqEqsSg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@babel/parser': ^7.15.8
+      '@nuxt/kit': ^3.2.2
+      vue: 2 || 3
+    peerDependenciesMeta:
+      '@babel/parser':
+        optional: true
+      '@nuxt/kit':
+        optional: true
+
+  unplugin@1.10.1:
+    resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==}
+    engines: {node: '>=14.0.0'}
+
+  unset-value@1.0.0:
+    resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
+    engines: {node: '>=0.10.0'}
+
+  update-browserslist-db@1.0.16:
+    resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
+    hasBin: true
+    peerDependencies:
+      browserslist: '>= 4.21.0'
+
+  uri-js@4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+  urix@0.1.0:
+    resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
+    deprecated: Please see https://github.com/lydell/urix#deprecated
+
+  use@3.1.1:
+    resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
+    engines: {node: '>=0.10.0'}
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+  v-perfect-signature@1.4.0:
+    resolution: {integrity: sha512-lTHRs4SfWN0nvmBhpajxMRt3ClzwmBcRi5ILjXENgOmTOZ2qBw7y1+J1LwC7uRS1MZMPUpkI8KoClPb/mODK+A==}
+    peerDependencies:
+      '@vue/composition-api': ^1.7.1
+      vue: ^2.6.14 || ^3.2.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  vant@4.9.1:
+    resolution: {integrity: sha512-p7iAKJyACYVwrmrkf3COmbuvzjHrFJ+FAmlyOWbxTS2ovkRs+tNKYjX2iibAl4XnHXBQD+qpX0ogUqE3jE7Isg==}
+    peerDependencies:
+      vue: ^3.0.0
+
+  vary@1.1.2:
+    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+    engines: {node: '>= 0.8'}
+
+  vite-hot-client@0.2.3:
+    resolution: {integrity: sha512-rOGAV7rUlUHX89fP2p2v0A2WWvV3QMX2UYq0fRqsWSvFvev4atHWqjwGoKaZT1VTKyLGk533ecu3eyd0o59CAg==}
+    peerDependencies:
+      vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0
+
+  vite-plugin-compression@0.5.1:
+    resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
+    peerDependencies:
+      vite: '>=2.0.0'
+
+  vite-plugin-inspect@0.8.4:
+    resolution: {integrity: sha512-G0N3rjfw+AiiwnGw50KlObIHYWfulVwaCBUBLh2xTW9G1eM9ocE5olXkEYUbwyTmX+azM8duubi+9w5awdCz+g==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@nuxt/kit': '*'
+      vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0
+    peerDependenciesMeta:
+      '@nuxt/kit':
+        optional: true
+
+  vite-plugin-svg-icons@2.0.1:
+    resolution: {integrity: sha512-6ktD+DhV6Rz3VtedYvBKKVA2eXF+sAQVaKkKLDSqGUfnhqXl3bj5PPkVTl3VexfTuZy66PmINi8Q6eFnVfRUmA==}
+    peerDependencies:
+      vite: '>=2.0.0'
+
+  vite-plugin-vue-devtools@7.2.1:
+    resolution: {integrity: sha512-4k7QNZz0nSojoePQoxnE5fIzi8RU1QJHc0TEg4golv2phZxhBGfjScZD2B8X6bcrRbUQ9CaRKN0dzBs1xtzzNg==}
+    engines: {node: '>=v14.21.3'}
+    peerDependencies:
+      vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0
+
+  vite-plugin-vue-inspector@5.1.2:
+    resolution: {integrity: sha512-M+yH2LlQtVNzJAljQM+61CqDXBvHim8dU5ImGaQuwlo13tMDHue5D7IC20YwDJuWDODiYc/cZBUYspVlyPf2vQ==}
+    peerDependencies:
+      vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0
+
+  vite-plugin-vue-setup-extend@0.4.0:
+    resolution: {integrity: sha512-WMbjPCui75fboFoUTHhdbXzu4Y/bJMv5N9QT9a7do3wNMNHHqrk+Tn2jrSJU0LS5fGl/EG+FEDBYVUeWIkDqXQ==}
+    peerDependencies:
+      vite: '>=2.0.0'
+
+  vite@5.2.12:
+    resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': ^18.0.0 || >=20.0.0
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+
+  vue-demi@0.14.8:
+    resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  vue-eslint-parser@9.4.3:
+    resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '>=6.0.0'
+
+  vue-router@4.3.2:
+    resolution: {integrity: sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==}
+    peerDependencies:
+      vue: ^3.2.0
+
+  vue-template-compiler@2.7.16:
+    resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
+
+  vue-tsc@2.0.19:
+    resolution: {integrity: sha512-JWay5Zt2/871iodGF72cELIbcAoPyhJxq56mPPh+M2K7IwI688FMrFKc/+DvB05wDWEuCPexQJ6L10zSwzzapg==}
+    hasBin: true
+    peerDependencies:
+      typescript: '*'
+
+  vue@3.4.27:
+    resolution: {integrity: sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  webpack-sources@3.2.3:
+    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
+    engines: {node: '>=10.13.0'}
+
+  webpack-virtual-modules@0.6.2:
+    resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+
+  which-boxed-primitive@1.0.2:
+    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+
+  which-typed-array@1.1.15:
+    resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
+    engines: {node: '>= 0.4'}
+
+  which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+
+  word-wrap@1.2.5:
+    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+    engines: {node: '>=0.10.0'}
+
+  wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+  xml-name-validator@4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+
+  yallist@3.1.1:
+    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+  yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+
+snapshots:
+
+  '@ampproject/remapping@2.3.0':
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.5
+      '@jridgewell/trace-mapping': 0.3.25
+
+  '@antfu/install-pkg@0.1.1':
+    dependencies:
+      execa: 5.1.1
+      find-up: 5.0.0
+
+  '@antfu/utils@0.7.8': {}
+
+  '@babel/code-frame@7.24.6':
+    dependencies:
+      '@babel/highlight': 7.24.6
+      picocolors: 1.0.1
+
+  '@babel/compat-data@7.24.6': {}
+
+  '@babel/core@7.24.6':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@babel/code-frame': 7.24.6
+      '@babel/generator': 7.24.6
+      '@babel/helper-compilation-targets': 7.24.6
+      '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6)
+      '@babel/helpers': 7.24.6
+      '@babel/parser': 7.24.6
+      '@babel/template': 7.24.6
+      '@babel/traverse': 7.24.6
+      '@babel/types': 7.24.6
+      convert-source-map: 2.0.0
+      debug: 4.3.5
+      gensync: 1.0.0-beta.2
+      json5: 2.2.3
+      semver: 6.3.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/generator@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+      '@jridgewell/gen-mapping': 0.3.5
+      '@jridgewell/trace-mapping': 0.3.25
+      jsesc: 2.5.2
+
+  '@babel/helper-annotate-as-pure@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-compilation-targets@7.24.6':
+    dependencies:
+      '@babel/compat-data': 7.24.6
+      '@babel/helper-validator-option': 7.24.6
+      browserslist: 4.23.0
+      lru-cache: 5.1.1
+      semver: 6.3.1
+
+  '@babel/helper-create-class-features-plugin@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-annotate-as-pure': 7.24.6
+      '@babel/helper-environment-visitor': 7.24.6
+      '@babel/helper-function-name': 7.24.6
+      '@babel/helper-member-expression-to-functions': 7.24.6
+      '@babel/helper-optimise-call-expression': 7.24.6
+      '@babel/helper-replace-supers': 7.24.6(@babel/core@7.24.6)
+      '@babel/helper-skip-transparent-expression-wrappers': 7.24.6
+      '@babel/helper-split-export-declaration': 7.24.6
+      semver: 6.3.1
+
+  '@babel/helper-environment-visitor@7.24.6': {}
+
+  '@babel/helper-function-name@7.24.6':
+    dependencies:
+      '@babel/template': 7.24.6
+      '@babel/types': 7.24.6
+
+  '@babel/helper-hoist-variables@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-member-expression-to-functions@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-module-imports@7.22.15':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-module-imports@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-environment-visitor': 7.24.6
+      '@babel/helper-module-imports': 7.24.6
+      '@babel/helper-simple-access': 7.24.6
+      '@babel/helper-split-export-declaration': 7.24.6
+      '@babel/helper-validator-identifier': 7.24.6
+
+  '@babel/helper-optimise-call-expression@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-plugin-utils@7.24.6': {}
+
+  '@babel/helper-replace-supers@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-environment-visitor': 7.24.6
+      '@babel/helper-member-expression-to-functions': 7.24.6
+      '@babel/helper-optimise-call-expression': 7.24.6
+
+  '@babel/helper-simple-access@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-skip-transparent-expression-wrappers@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-split-export-declaration@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/helper-string-parser@7.24.6': {}
+
+  '@babel/helper-validator-identifier@7.24.6': {}
+
+  '@babel/helper-validator-option@7.24.6': {}
+
+  '@babel/helpers@7.24.6':
+    dependencies:
+      '@babel/template': 7.24.6
+      '@babel/types': 7.24.6
+
+  '@babel/highlight@7.24.6':
+    dependencies:
+      '@babel/helper-validator-identifier': 7.24.6
+      chalk: 2.4.2
+      js-tokens: 4.0.0
+      picocolors: 1.0.1
+
+  '@babel/parser@7.24.6':
+    dependencies:
+      '@babel/types': 7.24.6
+
+  '@babel/plugin-proposal-decorators@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6)
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/plugin-syntax-decorators': 7.24.6(@babel/core@7.24.6)
+
+  '@babel/plugin-syntax-decorators@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+
+  '@babel/plugin-syntax-import-attributes@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+
+  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+
+  '@babel/plugin-syntax-jsx@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+
+  '@babel/plugin-syntax-typescript@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+
+  '@babel/plugin-transform-modules-commonjs@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6)
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/helper-simple-access': 7.24.6
+
+  '@babel/plugin-transform-typescript@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-annotate-as-pure': 7.24.6
+      '@babel/helper-create-class-features-plugin': 7.24.6(@babel/core@7.24.6)
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/plugin-syntax-typescript': 7.24.6(@babel/core@7.24.6)
+
+  '@babel/preset-typescript@7.24.6(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/helper-validator-option': 7.24.6
+      '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6)
+      '@babel/plugin-transform-modules-commonjs': 7.24.6(@babel/core@7.24.6)
+      '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6)
+
+  '@babel/template@7.24.6':
+    dependencies:
+      '@babel/code-frame': 7.24.6
+      '@babel/parser': 7.24.6
+      '@babel/types': 7.24.6
+
+  '@babel/traverse@7.24.6':
+    dependencies:
+      '@babel/code-frame': 7.24.6
+      '@babel/generator': 7.24.6
+      '@babel/helper-environment-visitor': 7.24.6
+      '@babel/helper-function-name': 7.24.6
+      '@babel/helper-hoist-variables': 7.24.6
+      '@babel/helper-split-export-declaration': 7.24.6
+      '@babel/parser': 7.24.6
+      '@babel/types': 7.24.6
+      debug: 4.3.5
+      globals: 11.12.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/types@7.24.6':
+    dependencies:
+      '@babel/helper-string-parser': 7.24.6
+      '@babel/helper-validator-identifier': 7.24.6
+      to-fast-properties: 2.0.0
+
+  '@esbuild/aix-ppc64@0.20.2':
+    optional: true
+
+  '@esbuild/android-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/android-arm@0.20.2':
+    optional: true
+
+  '@esbuild/android-x64@0.20.2':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/darwin-x64@0.20.2':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.20.2':
+    optional: true
+
+  '@esbuild/linux-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/linux-arm@0.20.2':
+    optional: true
+
+  '@esbuild/linux-ia32@0.20.2':
+    optional: true
+
+  '@esbuild/linux-loong64@0.20.2':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.20.2':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.20.2':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.20.2':
+    optional: true
+
+  '@esbuild/linux-s390x@0.20.2':
+    optional: true
+
+  '@esbuild/linux-x64@0.20.2':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.20.2':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.20.2':
+    optional: true
+
+  '@esbuild/sunos-x64@0.20.2':
+    optional: true
+
+  '@esbuild/win32-arm64@0.20.2':
+    optional: true
+
+  '@esbuild/win32-ia32@0.20.2':
+    optional: true
+
+  '@esbuild/win32-x64@0.20.2':
+    optional: true
+
+  '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
+    dependencies:
+      eslint: 8.57.0
+      eslint-visitor-keys: 3.4.3
+
+  '@eslint-community/regexpp@4.10.1': {}
+
+  '@eslint/eslintrc@2.1.4':
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.3.5
+      espree: 9.6.1
+      globals: 13.24.0
+      ignore: 5.3.1
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@eslint/js@8.57.0': {}
+
+  '@humanwhocodes/config-array@0.11.14':
+    dependencies:
+      '@humanwhocodes/object-schema': 2.0.3
+      debug: 4.3.5
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@humanwhocodes/module-importer@1.0.1': {}
+
+  '@humanwhocodes/object-schema@2.0.3': {}
+
+  '@iconify/json@2.2.216':
+    dependencies:
+      '@iconify/types': 2.0.0
+      pathe: 1.1.2
+
+  '@iconify/types@2.0.0': {}
+
+  '@iconify/utils@2.1.24':
+    dependencies:
+      '@antfu/install-pkg': 0.1.1
+      '@antfu/utils': 0.7.8
+      '@iconify/types': 2.0.0
+      debug: 4.3.5
+      kolorist: 1.8.0
+      local-pkg: 0.5.0
+      mlly: 1.7.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@jridgewell/gen-mapping@0.3.5':
+    dependencies:
+      '@jridgewell/set-array': 1.2.1
+      '@jridgewell/sourcemap-codec': 1.4.15
+      '@jridgewell/trace-mapping': 0.3.25
+
+  '@jridgewell/resolve-uri@3.1.2': {}
+
+  '@jridgewell/set-array@1.2.1': {}
+
+  '@jridgewell/sourcemap-codec@1.4.15': {}
+
+  '@jridgewell/trace-mapping@0.3.25':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.4.15
+
+  '@nodelib/fs.scandir@2.1.5':
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+
+  '@nodelib/fs.stat@2.0.5': {}
+
+  '@nodelib/fs.walk@1.2.8':
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.17.1
+
+  '@pkgr/core@0.1.1': {}
+
+  '@polka/url@1.0.0-next.25': {}
+
+  '@rollup/pluginutils@5.1.0(rollup@4.18.0)':
+    dependencies:
+      '@types/estree': 1.0.5
+      estree-walker: 2.0.2
+      picomatch: 2.3.1
+    optionalDependencies:
+      rollup: 4.18.0
+
+  '@rollup/rollup-android-arm-eabi@4.18.0':
+    optional: true
+
+  '@rollup/rollup-android-arm64@4.18.0':
+    optional: true
+
+  '@rollup/rollup-darwin-arm64@4.18.0':
+    optional: true
+
+  '@rollup/rollup-darwin-x64@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm-musleabihf@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-gnu@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-musl@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-riscv64-gnu@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-s390x-gnu@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-x64-gnu@4.18.0':
+    optional: true
+
+  '@rollup/rollup-linux-x64-musl@4.18.0':
+    optional: true
+
+  '@rollup/rollup-win32-arm64-msvc@4.18.0':
+    optional: true
+
+  '@rollup/rollup-win32-ia32-msvc@4.18.0':
+    optional: true
+
+  '@rollup/rollup-win32-x64-msvc@4.18.0':
+    optional: true
+
+  '@rushstack/eslint-patch@1.10.3': {}
+
+  '@trysound/sax@0.2.0': {}
+
+  '@tsconfig/node20@20.1.4': {}
+
+  '@types/estree@1.0.5': {}
+
+  '@types/file-saver@2.0.7': {}
+
+  '@types/lodash-es@4.17.12':
+    dependencies:
+      '@types/lodash': 4.17.4
+
+  '@types/lodash@4.17.4': {}
+
+  '@types/node@20.14.1':
+    dependencies:
+      undici-types: 5.26.5
+
+  '@types/nprogress@0.2.3': {}
+
+  '@types/qs@6.9.15': {}
+
+  '@types/svgo@2.6.4':
+    dependencies:
+      '@types/node': 20.14.1
+
+  '@types/web-bluetooth@0.0.20': {}
+
+  '@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@eslint-community/regexpp': 4.10.1
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/type-utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.12.0
+      eslint: 8.57.0
+      graphemer: 1.4.0
+      ignore: 5.3.1
+      natural-compare: 1.4.0
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.12.0
+      debug: 4.3.5
+      eslint: 8.57.0
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/scope-manager@7.12.0':
+    dependencies:
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/visitor-keys': 7.12.0
+
+  '@typescript-eslint/type-utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      debug: 4.3.5
+      eslint: 8.57.0
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/types@7.12.0': {}
+
+  '@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/visitor-keys': 7.12.0
+      debug: 4.3.5
+      globby: 11.1.0
+      is-glob: 4.0.3
+      minimatch: 9.0.4
+      semver: 7.6.2
+      ts-api-utils: 1.3.0(typescript@5.4.5)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
+      eslint: 8.57.0
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+
+  '@typescript-eslint/visitor-keys@7.12.0':
+    dependencies:
+      '@typescript-eslint/types': 7.12.0
+      eslint-visitor-keys: 3.4.3
+
+  '@ungap/structured-clone@1.2.0': {}
+
+  '@unocss/astro@0.60.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/reset': 0.60.4
+      '@unocss/vite': 0.60.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+    optionalDependencies:
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - rollup
+
+  '@unocss/cli@0.60.4(rollup@4.18.0)':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      '@unocss/config': 0.60.4
+      '@unocss/core': 0.60.4
+      '@unocss/preset-uno': 0.60.4
+      cac: 6.7.14
+      chokidar: 3.6.0
+      colorette: 2.0.20
+      consola: 3.2.3
+      fast-glob: 3.3.2
+      magic-string: 0.30.10
+      pathe: 1.1.2
+      perfect-debounce: 1.0.0
+    transitivePeerDependencies:
+      - rollup
+
+  '@unocss/config@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      unconfig: 0.3.13
+
+  '@unocss/core@0.60.4': {}
+
+  '@unocss/extractor-arbitrary-variants@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/inspector@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+      gzip-size: 6.0.0
+      sirv: 2.0.4
+
+  '@unocss/postcss@0.60.4(postcss@5.2.18)':
+    dependencies:
+      '@unocss/config': 0.60.4
+      '@unocss/core': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+      css-tree: 2.3.1
+      fast-glob: 3.3.2
+      magic-string: 0.30.10
+      postcss: 5.2.18
+
+  '@unocss/preset-attributify@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/preset-icons@0.60.4':
+    dependencies:
+      '@iconify/utils': 2.1.24
+      '@unocss/core': 0.60.4
+      ofetch: 1.3.4
+    transitivePeerDependencies:
+      - supports-color
+
+  '@unocss/preset-mini@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/extractor-arbitrary-variants': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+
+  '@unocss/preset-rem-to-px@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/preset-tagify@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/preset-typography@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/preset-mini': 0.60.4
+
+  '@unocss/preset-uno@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/preset-mini': 0.60.4
+      '@unocss/preset-wind': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+
+  '@unocss/preset-web-fonts@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      ofetch: 1.3.4
+
+  '@unocss/preset-wind@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/preset-mini': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+
+  '@unocss/reset@0.60.4': {}
+
+  '@unocss/rule-utils@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      magic-string: 0.30.10
+
+  '@unocss/scope@0.60.4': {}
+
+  '@unocss/transformer-attributify-jsx-babel@0.60.4':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6)
+      '@babel/preset-typescript': 7.24.6(@babel/core@7.24.6)
+      '@unocss/core': 0.60.4
+    transitivePeerDependencies:
+      - supports-color
+
+  '@unocss/transformer-attributify-jsx@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/transformer-compile-class@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/transformer-directives@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+      '@unocss/rule-utils': 0.60.4
+      css-tree: 2.3.1
+
+  '@unocss/transformer-variant-group@0.60.4':
+    dependencies:
+      '@unocss/core': 0.60.4
+
+  '@unocss/vite@0.60.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      '@unocss/config': 0.60.4
+      '@unocss/core': 0.60.4
+      '@unocss/inspector': 0.60.4
+      '@unocss/scope': 0.60.4
+      '@unocss/transformer-directives': 0.60.4
+      chokidar: 3.6.0
+      fast-glob: 3.3.2
+      magic-string: 0.30.10
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - rollup
+
+  '@vant/popperjs@1.3.0': {}
+
+  '@vant/use@1.6.0(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      vue: 3.4.27(typescript@5.4.5)
+
+  '@vitejs/plugin-vue-jsx@3.1.0(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6)
+      '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.6)
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+      vue: 3.4.27(typescript@5.4.5)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vitejs/plugin-vue@5.0.5(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+      vue: 3.4.27(typescript@5.4.5)
+
+  '@volar/language-core@2.2.5':
+    dependencies:
+      '@volar/source-map': 2.2.5
+
+  '@volar/source-map@2.2.5':
+    dependencies:
+      muggle-string: 0.4.1
+
+  '@volar/typescript@2.2.5':
+    dependencies:
+      '@volar/language-core': 2.2.5
+      path-browserify: 1.0.1
+
+  '@vue/babel-helper-vue-transform-on@1.2.2': {}
+
+  '@vue/babel-plugin-jsx@1.2.2(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/helper-module-imports': 7.22.15
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6)
+      '@babel/template': 7.24.6
+      '@babel/traverse': 7.24.6
+      '@babel/types': 7.24.6
+      '@vue/babel-helper-vue-transform-on': 1.2.2
+      '@vue/babel-plugin-resolve-type': 1.2.2(@babel/core@7.24.6)
+      camelcase: 6.3.0
+      html-tags: 3.3.1
+      svg-tags: 1.0.0
+    optionalDependencies:
+      '@babel/core': 7.24.6
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vue/babel-plugin-resolve-type@1.2.2(@babel/core@7.24.6)':
+    dependencies:
+      '@babel/code-frame': 7.24.6
+      '@babel/core': 7.24.6
+      '@babel/helper-module-imports': 7.22.15
+      '@babel/helper-plugin-utils': 7.24.6
+      '@babel/parser': 7.24.6
+      '@vue/compiler-sfc': 3.4.27
+
+  '@vue/compiler-core@3.4.27':
+    dependencies:
+      '@babel/parser': 7.24.6
+      '@vue/shared': 3.4.27
+      entities: 4.5.0
+      estree-walker: 2.0.2
+      source-map-js: 1.2.0
+
+  '@vue/compiler-dom@3.4.27':
+    dependencies:
+      '@vue/compiler-core': 3.4.27
+      '@vue/shared': 3.4.27
+
+  '@vue/compiler-sfc@3.4.27':
+    dependencies:
+      '@babel/parser': 7.24.6
+      '@vue/compiler-core': 3.4.27
+      '@vue/compiler-dom': 3.4.27
+      '@vue/compiler-ssr': 3.4.27
+      '@vue/shared': 3.4.27
+      estree-walker: 2.0.2
+      magic-string: 0.30.10
+      postcss: 8.4.38
+      source-map-js: 1.2.0
+
+  '@vue/compiler-ssr@3.4.27':
+    dependencies:
+      '@vue/compiler-dom': 3.4.27
+      '@vue/shared': 3.4.27
+
+  '@vue/devtools-api@6.6.3': {}
+
+  '@vue/devtools-core@7.2.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      '@vue/devtools-kit': 7.2.1(vue@3.4.27(typescript@5.4.5))
+      '@vue/devtools-shared': 7.2.1
+      mitt: 3.0.1
+      nanoid: 3.3.7
+      pathe: 1.1.2
+      vite-hot-client: 0.2.3(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+    transitivePeerDependencies:
+      - vite
+      - vue
+
+  '@vue/devtools-kit@7.2.1(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      '@vue/devtools-shared': 7.2.1
+      hookable: 5.5.3
+      mitt: 3.0.1
+      perfect-debounce: 1.0.0
+      speakingurl: 14.0.1
+      vue: 3.4.27(typescript@5.4.5)
+
+  '@vue/devtools-shared@7.2.1':
+    dependencies:
+      rfdc: 1.3.1
+
+  '@vue/eslint-config-prettier@9.0.0(eslint@8.57.0)(prettier@3.3.0)':
+    dependencies:
+      eslint: 8.57.0
+      eslint-config-prettier: 9.1.0(eslint@8.57.0)
+      eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.0)
+      prettier: 3.3.0
+    transitivePeerDependencies:
+      - '@types/eslint'
+
+  '@vue/eslint-config-typescript@13.0.0(eslint-plugin-vue@9.26.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)':
+    dependencies:
+      '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      eslint: 8.57.0
+      eslint-plugin-vue: 9.26.0(eslint@8.57.0)
+      vue-eslint-parser: 9.4.3(eslint@8.57.0)
+    optionalDependencies:
+      typescript: 5.4.5
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vue/language-core@2.0.19(typescript@5.4.5)':
+    dependencies:
+      '@volar/language-core': 2.2.5
+      '@vue/compiler-dom': 3.4.27
+      '@vue/shared': 3.4.27
+      computeds: 0.0.1
+      minimatch: 9.0.4
+      path-browserify: 1.0.1
+      vue-template-compiler: 2.7.16
+    optionalDependencies:
+      typescript: 5.4.5
+
+  '@vue/reactivity@3.4.27':
+    dependencies:
+      '@vue/shared': 3.4.27
+
+  '@vue/runtime-core@3.4.27':
+    dependencies:
+      '@vue/reactivity': 3.4.27
+      '@vue/shared': 3.4.27
+
+  '@vue/runtime-dom@3.4.27':
+    dependencies:
+      '@vue/runtime-core': 3.4.27
+      '@vue/shared': 3.4.27
+      csstype: 3.1.3
+
+  '@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      '@vue/compiler-ssr': 3.4.27
+      '@vue/shared': 3.4.27
+      vue: 3.4.27(typescript@5.4.5)
+
+  '@vue/shared@3.4.27': {}
+
+  '@vue/tsconfig@0.5.1': {}
+
+  '@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      '@types/web-bluetooth': 0.0.20
+      '@vueuse/metadata': 10.10.0
+      '@vueuse/shared': 10.10.0(vue@3.4.27(typescript@5.4.5))
+      vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
+  '@vueuse/metadata@10.10.0': {}
+
+  '@vueuse/shared@10.10.0(vue@3.4.27(typescript@5.4.5))':
+    dependencies:
+      vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
+  acorn-jsx@5.3.2(acorn@8.11.3):
+    dependencies:
+      acorn: 8.11.3
+
+  acorn@8.11.3: {}
+
+  ajv@6.12.6:
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+
+  ansi-regex@2.1.1: {}
+
+  ansi-regex@5.0.1: {}
+
+  ansi-styles@2.2.1: {}
+
+  ansi-styles@3.2.1:
+    dependencies:
+      color-convert: 1.9.3
+
+  ansi-styles@4.3.0:
+    dependencies:
+      color-convert: 2.0.1
+
+  ansi-styles@6.2.1: {}
+
+  anymatch@3.1.3:
+    dependencies:
+      normalize-path: 3.0.0
+      picomatch: 2.3.1
+
+  argparse@2.0.1: {}
+
+  arr-diff@4.0.0: {}
+
+  arr-flatten@1.1.0: {}
+
+  arr-union@3.1.0: {}
+
+  array-buffer-byte-length@1.0.1:
+    dependencies:
+      call-bind: 1.0.7
+      is-array-buffer: 3.0.4
+
+  array-union@2.1.0: {}
+
+  array-unique@0.3.2: {}
+
+  arraybuffer.prototype.slice@1.0.3:
+    dependencies:
+      array-buffer-byte-length: 1.0.1
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+      is-array-buffer: 3.0.4
+      is-shared-array-buffer: 1.0.3
+
+  assign-symbols@1.0.0: {}
+
+  asynckit@0.4.0: {}
+
+  atob@2.1.2: {}
+
+  autoprefixer@10.4.19(postcss@5.2.18):
+    dependencies:
+      browserslist: 4.23.0
+      caniuse-lite: 1.0.30001627
+      fraction.js: 4.3.7
+      normalize-range: 0.1.2
+      picocolors: 1.0.1
+      postcss: 5.2.18
+      postcss-value-parser: 4.2.0
+
+  available-typed-arrays@1.0.7:
+    dependencies:
+      possible-typed-array-names: 1.0.0
+
+  axios@1.7.2:
+    dependencies:
+      follow-redirects: 1.15.6
+      form-data: 4.0.0
+      proxy-from-env: 1.1.0
+    transitivePeerDependencies:
+      - debug
+
+  balanced-match@1.0.2: {}
+
+  base@0.11.2:
+    dependencies:
+      cache-base: 1.0.1
+      class-utils: 0.3.6
+      component-emitter: 1.3.1
+      define-property: 1.0.0
+      isobject: 3.0.1
+      mixin-deep: 1.3.2
+      pascalcase: 0.1.1
+
+  big.js@5.2.2: {}
+
+  binary-extensions@2.3.0: {}
+
+  bluebird@3.7.2: {}
+
+  boolbase@1.0.0: {}
+
+  brace-expansion@1.1.11:
+    dependencies:
+      balanced-match: 1.0.2
+      concat-map: 0.0.1
+
+  brace-expansion@2.0.1:
+    dependencies:
+      balanced-match: 1.0.2
+
+  braces@2.3.2:
+    dependencies:
+      arr-flatten: 1.1.0
+      array-unique: 0.3.2
+      extend-shallow: 2.0.1
+      fill-range: 4.0.0
+      isobject: 3.0.1
+      repeat-element: 1.1.4
+      snapdragon: 0.8.2
+      snapdragon-node: 2.1.1
+      split-string: 3.1.0
+      to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
+
+  braces@3.0.3:
+    dependencies:
+      fill-range: 7.1.1
+
+  browserslist@4.23.0:
+    dependencies:
+      caniuse-lite: 1.0.30001627
+      electron-to-chromium: 1.4.789
+      node-releases: 2.0.14
+      update-browserslist-db: 1.0.16(browserslist@4.23.0)
+
+  bundle-name@4.1.0:
+    dependencies:
+      run-applescript: 7.0.0
+
+  cac@6.7.14: {}
+
+  cache-base@1.0.1:
+    dependencies:
+      collection-visit: 1.0.0
+      component-emitter: 1.3.1
+      get-value: 2.0.6
+      has-value: 1.0.0
+      isobject: 3.0.1
+      set-value: 2.0.1
+      to-object-path: 0.3.0
+      union-value: 1.0.1
+      unset-value: 1.0.0
+
+  call-bind@1.0.7:
+    dependencies:
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      get-intrinsic: 1.2.4
+      set-function-length: 1.2.2
+
+  callsites@3.1.0: {}
+
+  camelcase@6.3.0: {}
+
+  caniuse-lite@1.0.30001627: {}
+
+  chalk@1.1.3:
+    dependencies:
+      ansi-styles: 2.2.1
+      escape-string-regexp: 1.0.5
+      has-ansi: 2.0.0
+      strip-ansi: 3.0.1
+      supports-color: 2.0.0
+
+  chalk@2.4.2:
+    dependencies:
+      ansi-styles: 3.2.1
+      escape-string-regexp: 1.0.5
+      supports-color: 5.5.0
+
+  chalk@4.1.2:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+
+  chokidar@3.6.0:
+    dependencies:
+      anymatch: 3.1.3
+      braces: 3.0.3
+      glob-parent: 5.1.2
+      is-binary-path: 2.1.0
+      is-glob: 4.0.3
+      normalize-path: 3.0.0
+      readdirp: 3.6.0
+    optionalDependencies:
+      fsevents: 2.3.3
+
+  class-utils@0.3.6:
+    dependencies:
+      arr-union: 3.1.0
+      define-property: 0.2.5
+      isobject: 3.0.1
+      static-extend: 0.1.2
+
+  clone@2.1.2: {}
+
+  collection-visit@1.0.0:
+    dependencies:
+      map-visit: 1.0.0
+      object-visit: 1.0.1
+
+  color-convert@1.9.3:
+    dependencies:
+      color-name: 1.1.3
+
+  color-convert@2.0.1:
+    dependencies:
+      color-name: 1.1.4
+
+  color-name@1.1.3: {}
+
+  color-name@1.1.4: {}
+
+  colorette@2.0.20: {}
+
+  combined-stream@1.0.8:
+    dependencies:
+      delayed-stream: 1.0.0
+
+  commander@7.2.0: {}
+
+  component-emitter@1.3.1: {}
+
+  computeds@0.0.1: {}
+
+  concat-map@0.0.1: {}
+
+  confbox@0.1.7: {}
+
+  consola@3.2.3: {}
+
+  convert-source-map@2.0.0: {}
+
+  copy-anything@2.0.6:
+    dependencies:
+      is-what: 3.14.1
+
+  copy-descriptor@0.1.1: {}
+
+  cors@2.8.5:
+    dependencies:
+      object-assign: 4.1.1
+      vary: 1.1.2
+
+  cross-spawn@7.0.3:
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+
+  css-select@4.3.0:
+    dependencies:
+      boolbase: 1.0.0
+      css-what: 6.1.0
+      domhandler: 4.3.1
+      domutils: 2.8.0
+      nth-check: 2.1.1
+
+  css-tree@1.1.3:
+    dependencies:
+      mdn-data: 2.0.14
+      source-map: 0.6.1
+
+  css-tree@2.3.1:
+    dependencies:
+      mdn-data: 2.0.30
+      source-map-js: 1.2.0
+
+  css-what@6.1.0: {}
+
+  cssesc@3.0.0: {}
+
+  csso@4.2.0:
+    dependencies:
+      css-tree: 1.1.3
+
+  csstype@3.1.3: {}
+
+  data-view-buffer@1.0.1:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+
+  data-view-byte-length@1.0.1:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+
+  data-view-byte-offset@1.0.0:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+
+  dayjs@1.11.11: {}
+
+  de-indent@1.0.2: {}
+
+  debug@2.6.9:
+    dependencies:
+      ms: 2.0.0
+
+  debug@4.3.5:
+    dependencies:
+      ms: 2.1.2
+
+  decode-uri-component@0.2.2: {}
+
+  deep-is@0.1.4: {}
+
+  default-browser-id@5.0.0: {}
+
+  default-browser@5.2.1:
+    dependencies:
+      bundle-name: 4.1.0
+      default-browser-id: 5.0.0
+
+  define-data-property@1.1.4:
+    dependencies:
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      gopd: 1.0.1
+
+  define-lazy-prop@3.0.0: {}
+
+  define-properties@1.2.1:
+    dependencies:
+      define-data-property: 1.1.4
+      has-property-descriptors: 1.0.2
+      object-keys: 1.1.1
+
+  define-property@0.2.5:
+    dependencies:
+      is-descriptor: 0.1.7
+
+  define-property@1.0.0:
+    dependencies:
+      is-descriptor: 1.0.3
+
+  define-property@2.0.2:
+    dependencies:
+      is-descriptor: 1.0.3
+      isobject: 3.0.1
+
+  defu@6.1.4: {}
+
+  delayed-stream@1.0.0: {}
+
+  destr@2.0.3: {}
+
+  dir-glob@3.0.1:
+    dependencies:
+      path-type: 4.0.0
+
+  doctrine@3.0.0:
+    dependencies:
+      esutils: 2.0.3
+
+  dom-serializer@0.2.2:
+    dependencies:
+      domelementtype: 2.3.0
+      entities: 2.2.0
+
+  dom-serializer@1.4.1:
+    dependencies:
+      domelementtype: 2.3.0
+      domhandler: 4.3.1
+      entities: 2.2.0
+
+  domelementtype@1.3.1: {}
+
+  domelementtype@2.3.0: {}
+
+  domhandler@2.4.2:
+    dependencies:
+      domelementtype: 1.3.1
+
+  domhandler@4.3.1:
+    dependencies:
+      domelementtype: 2.3.0
+
+  domutils@1.7.0:
+    dependencies:
+      dom-serializer: 0.2.2
+      domelementtype: 1.3.1
+
+  domutils@2.8.0:
+    dependencies:
+      dom-serializer: 1.4.1
+      domelementtype: 2.3.0
+      domhandler: 4.3.1
+
+  duplexer@0.1.2: {}
+
+  electron-to-chromium@1.4.789: {}
+
+  emojis-list@3.0.0: {}
+
+  entities@1.1.2: {}
+
+  entities@2.2.0: {}
+
+  entities@4.5.0: {}
+
+  errno@0.1.8:
+    dependencies:
+      prr: 1.0.1
+    optional: true
+
+  error-stack-parser-es@0.1.4: {}
+
+  es-abstract@1.23.3:
+    dependencies:
+      array-buffer-byte-length: 1.0.1
+      arraybuffer.prototype.slice: 1.0.3
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      data-view-buffer: 1.0.1
+      data-view-byte-length: 1.0.1
+      data-view-byte-offset: 1.0.0
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      es-object-atoms: 1.0.0
+      es-set-tostringtag: 2.0.3
+      es-to-primitive: 1.2.1
+      function.prototype.name: 1.1.6
+      get-intrinsic: 1.2.4
+      get-symbol-description: 1.0.2
+      globalthis: 1.0.4
+      gopd: 1.0.1
+      has-property-descriptors: 1.0.2
+      has-proto: 1.0.3
+      has-symbols: 1.0.3
+      hasown: 2.0.2
+      internal-slot: 1.0.7
+      is-array-buffer: 3.0.4
+      is-callable: 1.2.7
+      is-data-view: 1.0.1
+      is-negative-zero: 2.0.3
+      is-regex: 1.1.4
+      is-shared-array-buffer: 1.0.3
+      is-string: 1.0.7
+      is-typed-array: 1.1.13
+      is-weakref: 1.0.2
+      object-inspect: 1.13.1
+      object-keys: 1.1.1
+      object.assign: 4.1.5
+      regexp.prototype.flags: 1.5.2
+      safe-array-concat: 1.1.2
+      safe-regex-test: 1.0.3
+      string.prototype.trim: 1.2.9
+      string.prototype.trimend: 1.0.8
+      string.prototype.trimstart: 1.0.8
+      typed-array-buffer: 1.0.2
+      typed-array-byte-length: 1.0.1
+      typed-array-byte-offset: 1.0.2
+      typed-array-length: 1.0.6
+      unbox-primitive: 1.0.2
+      which-typed-array: 1.1.15
+
+  es-define-property@1.0.0:
+    dependencies:
+      get-intrinsic: 1.2.4
+
+  es-errors@1.3.0: {}
+
+  es-object-atoms@1.0.0:
+    dependencies:
+      es-errors: 1.3.0
+
+  es-set-tostringtag@2.0.3:
+    dependencies:
+      get-intrinsic: 1.2.4
+      has-tostringtag: 1.0.2
+      hasown: 2.0.2
+
+  es-to-primitive@1.2.1:
+    dependencies:
+      is-callable: 1.2.7
+      is-date-object: 1.0.5
+      is-symbol: 1.0.4
+
+  esbuild@0.20.2:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.20.2
+      '@esbuild/android-arm': 0.20.2
+      '@esbuild/android-arm64': 0.20.2
+      '@esbuild/android-x64': 0.20.2
+      '@esbuild/darwin-arm64': 0.20.2
+      '@esbuild/darwin-x64': 0.20.2
+      '@esbuild/freebsd-arm64': 0.20.2
+      '@esbuild/freebsd-x64': 0.20.2
+      '@esbuild/linux-arm': 0.20.2
+      '@esbuild/linux-arm64': 0.20.2
+      '@esbuild/linux-ia32': 0.20.2
+      '@esbuild/linux-loong64': 0.20.2
+      '@esbuild/linux-mips64el': 0.20.2
+      '@esbuild/linux-ppc64': 0.20.2
+      '@esbuild/linux-riscv64': 0.20.2
+      '@esbuild/linux-s390x': 0.20.2
+      '@esbuild/linux-x64': 0.20.2
+      '@esbuild/netbsd-x64': 0.20.2
+      '@esbuild/openbsd-x64': 0.20.2
+      '@esbuild/sunos-x64': 0.20.2
+      '@esbuild/win32-arm64': 0.20.2
+      '@esbuild/win32-ia32': 0.20.2
+      '@esbuild/win32-x64': 0.20.2
+
+  escalade@3.1.2: {}
+
+  escape-string-regexp@1.0.5: {}
+
+  escape-string-regexp@4.0.0: {}
+
+  escape-string-regexp@5.0.0: {}
+
+  eslint-config-prettier@9.1.0(eslint@8.57.0):
+    dependencies:
+      eslint: 8.57.0
+
+  eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.0):
+    dependencies:
+      eslint: 8.57.0
+      prettier: 3.3.0
+      prettier-linter-helpers: 1.0.0
+      synckit: 0.8.8
+    optionalDependencies:
+      eslint-config-prettier: 9.1.0(eslint@8.57.0)
+
+  eslint-plugin-vue@9.26.0(eslint@8.57.0):
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      eslint: 8.57.0
+      globals: 13.24.0
+      natural-compare: 1.4.0
+      nth-check: 2.1.1
+      postcss-selector-parser: 6.1.0
+      semver: 7.6.2
+      vue-eslint-parser: 9.4.3(eslint@8.57.0)
+      xml-name-validator: 4.0.0
+    transitivePeerDependencies:
+      - supports-color
+
+  eslint-scope@7.2.2:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+
+  eslint-visitor-keys@3.4.3: {}
+
+  eslint@8.57.0:
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@eslint-community/regexpp': 4.10.1
+      '@eslint/eslintrc': 2.1.4
+      '@eslint/js': 8.57.0
+      '@humanwhocodes/config-array': 0.11.14
+      '@humanwhocodes/module-importer': 1.0.1
+      '@nodelib/fs.walk': 1.2.8
+      '@ungap/structured-clone': 1.2.0
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.3
+      debug: 4.3.5
+      doctrine: 3.0.0
+      escape-string-regexp: 4.0.0
+      eslint-scope: 7.2.2
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      esquery: 1.5.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.24.0
+      graphemer: 1.4.0
+      ignore: 5.3.1
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      is-path-inside: 3.0.3
+      js-yaml: 4.1.0
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.4
+      strip-ansi: 6.0.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+
+  espree@9.6.1:
+    dependencies:
+      acorn: 8.11.3
+      acorn-jsx: 5.3.2(acorn@8.11.3)
+      eslint-visitor-keys: 3.4.3
+
+  esquery@1.5.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  esrecurse@4.3.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  estraverse@5.3.0: {}
+
+  estree-walker@2.0.2: {}
+
+  estree-walker@3.0.3:
+    dependencies:
+      '@types/estree': 1.0.5
+
+  esutils@2.0.3: {}
+
+  etag@1.8.1: {}
+
+  execa@5.1.1:
+    dependencies:
+      cross-spawn: 7.0.3
+      get-stream: 6.0.1
+      human-signals: 2.1.0
+      is-stream: 2.0.1
+      merge-stream: 2.0.0
+      npm-run-path: 4.0.1
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+      strip-final-newline: 2.0.0
+
+  execa@8.0.1:
+    dependencies:
+      cross-spawn: 7.0.3
+      get-stream: 8.0.1
+      human-signals: 5.0.0
+      is-stream: 3.0.0
+      merge-stream: 2.0.0
+      npm-run-path: 5.3.0
+      onetime: 6.0.0
+      signal-exit: 4.1.0
+      strip-final-newline: 3.0.0
+
+  expand-brackets@2.1.4:
+    dependencies:
+      debug: 2.6.9
+      define-property: 0.2.5
+      extend-shallow: 2.0.1
+      posix-character-classes: 0.1.1
+      regex-not: 1.0.2
+      snapdragon: 0.8.2
+      to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
+
+  extend-shallow@2.0.1:
+    dependencies:
+      is-extendable: 0.1.1
+
+  extend-shallow@3.0.2:
+    dependencies:
+      assign-symbols: 1.0.0
+      is-extendable: 1.0.1
+
+  extglob@2.0.4:
+    dependencies:
+      array-unique: 0.3.2
+      define-property: 1.0.0
+      expand-brackets: 2.1.4
+      extend-shallow: 2.0.1
+      fragment-cache: 0.2.1
+      regex-not: 1.0.2
+      snapdragon: 0.8.2
+      to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
+
+  fast-deep-equal@3.1.3: {}
+
+  fast-diff@1.3.0: {}
+
+  fast-glob@3.3.2:
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.7
+
+  fast-json-stable-stringify@2.1.0: {}
+
+  fast-levenshtein@2.0.6: {}
+
+  fastq@1.17.1:
+    dependencies:
+      reusify: 1.0.4
+
+  file-entry-cache@6.0.1:
+    dependencies:
+      flat-cache: 3.2.0
+
+  file-saver@2.0.5: {}
+
+  fill-range@4.0.0:
+    dependencies:
+      extend-shallow: 2.0.1
+      is-number: 3.0.0
+      repeat-string: 1.6.1
+      to-regex-range: 2.1.1
+
+  fill-range@7.1.1:
+    dependencies:
+      to-regex-range: 5.0.1
+
+  find-up@5.0.0:
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+
+  flat-cache@3.2.0:
+    dependencies:
+      flatted: 3.3.1
+      keyv: 4.5.4
+      rimraf: 3.0.2
+
+  flatted@3.3.1: {}
+
+  follow-redirects@1.15.6: {}
+
+  for-each@0.3.3:
+    dependencies:
+      is-callable: 1.2.7
+
+  for-in@1.0.2: {}
+
+  form-data@4.0.0:
+    dependencies:
+      asynckit: 0.4.0
+      combined-stream: 1.0.8
+      mime-types: 2.1.35
+
+  fraction.js@4.3.7: {}
+
+  fragment-cache@0.2.1:
+    dependencies:
+      map-cache: 0.2.2
+
+  fs-extra@10.1.0:
+    dependencies:
+      graceful-fs: 4.2.11
+      jsonfile: 6.1.0
+      universalify: 2.0.1
+
+  fs-extra@11.2.0:
+    dependencies:
+      graceful-fs: 4.2.11
+      jsonfile: 6.1.0
+      universalify: 2.0.1
+
+  fs.realpath@1.0.0: {}
+
+  fsevents@2.3.3:
+    optional: true
+
+  function-bind@1.1.2: {}
+
+  function.prototype.name@1.1.6:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      functions-have-names: 1.2.3
+
+  functions-have-names@1.2.3: {}
+
+  gensync@1.0.0-beta.2: {}
+
+  get-intrinsic@1.2.4:
+    dependencies:
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      has-proto: 1.0.3
+      has-symbols: 1.0.3
+      hasown: 2.0.2
+
+  get-stream@6.0.1: {}
+
+  get-stream@8.0.1: {}
+
+  get-symbol-description@1.0.2:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+
+  get-value@2.0.6: {}
+
+  glob-parent@5.1.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob-parent@6.0.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob@7.2.3:
+    dependencies:
+      fs.realpath: 1.0.0
+      inflight: 1.0.6
+      inherits: 2.0.4
+      minimatch: 3.1.2
+      once: 1.4.0
+      path-is-absolute: 1.0.1
+
+  globals@11.12.0: {}
+
+  globals@13.24.0:
+    dependencies:
+      type-fest: 0.20.2
+
+  globalthis@1.0.4:
+    dependencies:
+      define-properties: 1.2.1
+      gopd: 1.0.1
+
+  globby@11.1.0:
+    dependencies:
+      array-union: 2.1.0
+      dir-glob: 3.0.1
+      fast-glob: 3.3.2
+      ignore: 5.3.1
+      merge2: 1.4.1
+      slash: 3.0.0
+
+  gopd@1.0.1:
+    dependencies:
+      get-intrinsic: 1.2.4
+
+  graceful-fs@4.2.11: {}
+
+  graphemer@1.4.0: {}
+
+  gzip-size@6.0.0:
+    dependencies:
+      duplexer: 0.1.2
+
+  has-ansi@2.0.0:
+    dependencies:
+      ansi-regex: 2.1.1
+
+  has-bigints@1.0.2: {}
+
+  has-flag@1.0.0: {}
+
+  has-flag@3.0.0: {}
+
+  has-flag@4.0.0: {}
+
+  has-property-descriptors@1.0.2:
+    dependencies:
+      es-define-property: 1.0.0
+
+  has-proto@1.0.3: {}
+
+  has-symbols@1.0.3: {}
+
+  has-tostringtag@1.0.2:
+    dependencies:
+      has-symbols: 1.0.3
+
+  has-value@0.3.1:
+    dependencies:
+      get-value: 2.0.6
+      has-values: 0.1.4
+      isobject: 2.1.0
+
+  has-value@1.0.0:
+    dependencies:
+      get-value: 2.0.6
+      has-values: 1.0.0
+      isobject: 3.0.1
+
+  has-values@0.1.4: {}
+
+  has-values@1.0.0:
+    dependencies:
+      is-number: 3.0.0
+      kind-of: 4.0.0
+
+  hasown@2.0.2:
+    dependencies:
+      function-bind: 1.1.2
+
+  he@1.2.0: {}
+
+  hookable@5.5.3: {}
+
+  html-tags@3.3.1: {}
+
+  htmlparser2@3.10.1:
+    dependencies:
+      domelementtype: 1.3.1
+      domhandler: 2.4.2
+      domutils: 1.7.0
+      entities: 1.1.2
+      inherits: 2.0.4
+      readable-stream: 3.6.2
+
+  human-signals@2.1.0: {}
+
+  human-signals@5.0.0: {}
+
+  iconv-lite@0.6.3:
+    dependencies:
+      safer-buffer: 2.1.2
+    optional: true
+
+  ignore@5.3.1: {}
+
+  image-size@0.5.5: {}
+
+  import-fresh@3.3.0:
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
+
+  imurmurhash@0.1.4: {}
+
+  inflight@1.0.6:
+    dependencies:
+      once: 1.4.0
+      wrappy: 1.0.2
+
+  inherits@2.0.4: {}
+
+  internal-slot@1.0.7:
+    dependencies:
+      es-errors: 1.3.0
+      hasown: 2.0.2
+      side-channel: 1.0.6
+
+  is-accessor-descriptor@1.0.1:
+    dependencies:
+      hasown: 2.0.2
+
+  is-array-buffer@3.0.4:
+    dependencies:
+      call-bind: 1.0.7
+      get-intrinsic: 1.2.4
+
+  is-bigint@1.0.4:
+    dependencies:
+      has-bigints: 1.0.2
+
+  is-binary-path@2.1.0:
+    dependencies:
+      binary-extensions: 2.3.0
+
+  is-boolean-object@1.1.2:
+    dependencies:
+      call-bind: 1.0.7
+      has-tostringtag: 1.0.2
+
+  is-buffer@1.1.6: {}
+
+  is-callable@1.2.7: {}
+
+  is-core-module@2.13.1:
+    dependencies:
+      hasown: 2.0.2
+
+  is-data-descriptor@1.0.1:
+    dependencies:
+      hasown: 2.0.2
+
+  is-data-view@1.0.1:
+    dependencies:
+      is-typed-array: 1.1.13
+
+  is-date-object@1.0.5:
+    dependencies:
+      has-tostringtag: 1.0.2
+
+  is-descriptor@0.1.7:
+    dependencies:
+      is-accessor-descriptor: 1.0.1
+      is-data-descriptor: 1.0.1
+
+  is-descriptor@1.0.3:
+    dependencies:
+      is-accessor-descriptor: 1.0.1
+      is-data-descriptor: 1.0.1
+
+  is-docker@3.0.0: {}
+
+  is-extendable@0.1.1: {}
+
+  is-extendable@1.0.1:
+    dependencies:
+      is-plain-object: 2.0.4
+
+  is-extglob@2.1.1: {}
+
+  is-glob@4.0.3:
+    dependencies:
+      is-extglob: 2.1.1
+
+  is-inside-container@1.0.0:
+    dependencies:
+      is-docker: 3.0.0
+
+  is-negative-zero@2.0.3: {}
+
+  is-number-object@1.0.7:
+    dependencies:
+      has-tostringtag: 1.0.2
+
+  is-number@3.0.0:
+    dependencies:
+      kind-of: 3.2.2
+
+  is-number@7.0.0: {}
+
+  is-path-inside@3.0.3: {}
+
+  is-plain-obj@1.1.0: {}
+
+  is-plain-object@2.0.4:
+    dependencies:
+      isobject: 3.0.1
+
+  is-regex@1.1.4:
+    dependencies:
+      call-bind: 1.0.7
+      has-tostringtag: 1.0.2
+
+  is-shared-array-buffer@1.0.3:
+    dependencies:
+      call-bind: 1.0.7
+
+  is-stream@2.0.1: {}
+
+  is-stream@3.0.0: {}
+
+  is-string@1.0.7:
+    dependencies:
+      has-tostringtag: 1.0.2
+
+  is-symbol@1.0.4:
+    dependencies:
+      has-symbols: 1.0.3
+
+  is-typed-array@1.1.13:
+    dependencies:
+      which-typed-array: 1.1.15
+
+  is-weakref@1.0.2:
+    dependencies:
+      call-bind: 1.0.7
+
+  is-what@3.14.1: {}
+
+  is-windows@1.0.2: {}
+
+  is-wsl@3.1.0:
+    dependencies:
+      is-inside-container: 1.0.0
+
+  isarray@1.0.0: {}
+
+  isarray@2.0.5: {}
+
+  isexe@2.0.0: {}
+
+  isobject@2.1.0:
+    dependencies:
+      isarray: 1.0.0
+
+  isobject@3.0.1: {}
+
+  jiti@1.21.1: {}
+
+  js-base64@2.6.4: {}
+
+  js-tokens@4.0.0: {}
+
+  js-tokens@9.0.0: {}
+
+  js-yaml@4.1.0:
+    dependencies:
+      argparse: 2.0.1
+
+  jsesc@2.5.2: {}
+
+  json-buffer@3.0.1: {}
+
+  json-parse-even-better-errors@3.0.2: {}
+
+  json-schema-traverse@0.4.1: {}
+
+  json-stable-stringify-without-jsonify@1.0.1: {}
+
+  json5@1.0.2:
+    dependencies:
+      minimist: 1.2.8
+
+  json5@2.2.3: {}
+
+  jsonfile@6.1.0:
+    dependencies:
+      universalify: 2.0.1
+    optionalDependencies:
+      graceful-fs: 4.2.11
+
+  keyv@4.5.4:
+    dependencies:
+      json-buffer: 3.0.1
+
+  kind-of@3.2.2:
+    dependencies:
+      is-buffer: 1.1.6
+
+  kind-of@4.0.0:
+    dependencies:
+      is-buffer: 1.1.6
+
+  kind-of@5.1.0: {}
+
+  kind-of@6.0.3: {}
+
+  kolorist@1.8.0: {}
+
+  less@4.2.0:
+    dependencies:
+      copy-anything: 2.0.6
+      parse-node-version: 1.0.1
+      tslib: 2.6.3
+    optionalDependencies:
+      errno: 0.1.8
+      graceful-fs: 4.2.11
+      image-size: 0.5.5
+      make-dir: 2.1.0
+      mime: 1.6.0
+      needle: 3.3.1
+      source-map: 0.6.1
+
+  levn@0.4.1:
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+
+  loader-utils@1.4.2:
+    dependencies:
+      big.js: 5.2.2
+      emojis-list: 3.0.0
+      json5: 1.0.2
+
+  local-pkg@0.5.0:
+    dependencies:
+      mlly: 1.7.0
+      pkg-types: 1.1.1
+
+  locate-path@6.0.0:
+    dependencies:
+      p-locate: 5.0.0
+
+  lodash-es@4.17.21: {}
+
+  lodash.merge@4.6.2: {}
+
+  lodash@4.17.21: {}
+
+  lru-cache@5.1.1:
+    dependencies:
+      yallist: 3.1.1
+
+  magic-string@0.25.9:
+    dependencies:
+      sourcemap-codec: 1.4.8
+
+  magic-string@0.30.10:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
+
+  make-dir@2.1.0:
+    dependencies:
+      pify: 4.0.1
+      semver: 5.7.2
+    optional: true
+
+  map-cache@0.2.2: {}
+
+  map-visit@1.0.0:
+    dependencies:
+      object-visit: 1.0.1
+
+  mdn-data@2.0.14: {}
+
+  mdn-data@2.0.30: {}
+
+  memorystream@0.3.1: {}
+
+  merge-options@1.0.1:
+    dependencies:
+      is-plain-obj: 1.1.0
+
+  merge-stream@2.0.0: {}
+
+  merge2@1.4.1: {}
+
+  micromatch@3.1.0:
+    dependencies:
+      arr-diff: 4.0.0
+      array-unique: 0.3.2
+      braces: 2.3.2
+      define-property: 1.0.0
+      extend-shallow: 2.0.1
+      extglob: 2.0.4
+      fragment-cache: 0.2.1
+      kind-of: 5.1.0
+      nanomatch: 1.2.13
+      object.pick: 1.3.0
+      regex-not: 1.0.2
+      snapdragon: 0.8.2
+      to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
+
+  micromatch@4.0.7:
+    dependencies:
+      braces: 3.0.3
+      picomatch: 2.3.1
+
+  mime-db@1.52.0: {}
+
+  mime-types@2.1.35:
+    dependencies:
+      mime-db: 1.52.0
+
+  mime@1.6.0:
+    optional: true
+
+  mimic-fn@2.1.0: {}
+
+  mimic-fn@4.0.0: {}
+
+  minimatch@3.1.2:
+    dependencies:
+      brace-expansion: 1.1.11
+
+  minimatch@9.0.4:
+    dependencies:
+      brace-expansion: 2.0.1
+
+  minimist@1.2.8: {}
+
+  mitt@3.0.1: {}
+
+  mixin-deep@1.3.2:
+    dependencies:
+      for-in: 1.0.2
+      is-extendable: 1.0.1
+
+  mlly@1.7.0:
+    dependencies:
+      acorn: 8.11.3
+      pathe: 1.1.2
+      pkg-types: 1.1.1
+      ufo: 1.5.3
+
+  mrmime@2.0.0: {}
+
+  ms@2.0.0: {}
+
+  ms@2.1.2: {}
+
+  muggle-string@0.4.1: {}
+
+  nanoid@3.3.7: {}
+
+  nanomatch@1.2.13:
+    dependencies:
+      arr-diff: 4.0.0
+      array-unique: 0.3.2
+      define-property: 2.0.2
+      extend-shallow: 3.0.2
+      fragment-cache: 0.2.1
+      is-windows: 1.0.2
+      kind-of: 6.0.3
+      object.pick: 1.3.0
+      regex-not: 1.0.2
+      snapdragon: 0.8.2
+      to-regex: 3.0.2
+    transitivePeerDependencies:
+      - supports-color
+
+  natural-compare@1.4.0: {}
+
+  needle@3.3.1:
+    dependencies:
+      iconv-lite: 0.6.3
+      sax: 1.4.1
+    optional: true
+
+  node-fetch-native@1.6.4: {}
+
+  node-releases@2.0.14: {}
+
+  normalize-path@3.0.0: {}
+
+  normalize-range@0.1.2: {}
+
+  npm-normalize-package-bin@3.0.1: {}
+
+  npm-run-all2@6.2.0:
+    dependencies:
+      ansi-styles: 6.2.1
+      cross-spawn: 7.0.3
+      memorystream: 0.3.1
+      minimatch: 9.0.4
+      pidtree: 0.6.0
+      read-package-json-fast: 3.0.2
+      shell-quote: 1.8.1
+
+  npm-run-path@4.0.1:
+    dependencies:
+      path-key: 3.1.1
+
+  npm-run-path@5.3.0:
+    dependencies:
+      path-key: 4.0.0
+
+  nprogress@0.2.0: {}
+
+  nth-check@2.1.1:
+    dependencies:
+      boolbase: 1.0.0
+
+  object-assign@4.1.1: {}
+
+  object-copy@0.1.0:
+    dependencies:
+      copy-descriptor: 0.1.1
+      define-property: 0.2.5
+      kind-of: 3.2.2
+
+  object-inspect@1.13.1: {}
+
+  object-keys@1.1.1: {}
+
+  object-visit@1.0.1:
+    dependencies:
+      isobject: 3.0.1
+
+  object.assign@4.1.5:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      has-symbols: 1.0.3
+      object-keys: 1.1.1
+
+  object.pick@1.3.0:
+    dependencies:
+      isobject: 3.0.1
+
+  ofetch@1.3.4:
+    dependencies:
+      destr: 2.0.3
+      node-fetch-native: 1.6.4
+      ufo: 1.5.3
+
+  once@1.4.0:
+    dependencies:
+      wrappy: 1.0.2
+
+  onetime@5.1.2:
+    dependencies:
+      mimic-fn: 2.1.0
+
+  onetime@6.0.0:
+    dependencies:
+      mimic-fn: 4.0.0
+
+  open@10.1.0:
+    dependencies:
+      default-browser: 5.2.1
+      define-lazy-prop: 3.0.0
+      is-inside-container: 1.0.0
+      is-wsl: 3.1.0
+
+  optionator@0.9.4:
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.5
+
+  p-limit@3.1.0:
+    dependencies:
+      yocto-queue: 0.1.0
+
+  p-locate@5.0.0:
+    dependencies:
+      p-limit: 3.1.0
+
+  parent-module@1.0.1:
+    dependencies:
+      callsites: 3.1.0
+
+  parse-node-version@1.0.1: {}
+
+  pascalcase@0.1.1: {}
+
+  path-browserify@1.0.1: {}
+
+  path-exists@4.0.0: {}
+
+  path-is-absolute@1.0.1: {}
+
+  path-key@3.1.1: {}
+
+  path-key@4.0.0: {}
+
+  path-parse@1.0.7: {}
+
+  path-type@4.0.0: {}
+
+  pathe@0.2.0: {}
+
+  pathe@1.1.2: {}
+
+  perfect-debounce@1.0.0: {}
+
+  perfect-freehand@1.2.2: {}
+
+  picocolors@1.0.1: {}
+
+  picomatch@2.3.1: {}
+
+  pidtree@0.6.0: {}
+
+  pify@4.0.1:
+    optional: true
+
+  pinia-plugin-persistedstate@3.2.1(pinia@2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5))):
+    dependencies:
+      pinia: 2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5))
+
+  pinia@2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      '@vue/devtools-api': 6.6.3
+      vue: 3.4.27(typescript@5.4.5)
+      vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5))
+    optionalDependencies:
+      typescript: 5.4.5
+
+  pkg-types@1.1.1:
+    dependencies:
+      confbox: 0.1.7
+      mlly: 1.7.0
+      pathe: 1.1.2
+
+  posix-character-classes@0.1.1: {}
+
+  possible-typed-array-names@1.0.0: {}
+
+  postcss-mobile-forever@4.1.4(postcss@5.2.18):
+    dependencies:
+      postcss: 5.2.18
+
+  postcss-prefix-selector@1.16.1(postcss@5.2.18):
+    dependencies:
+      postcss: 5.2.18
+
+  postcss-selector-parser@6.1.0:
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
+  postcss-value-parser@4.2.0: {}
+
+  postcss@5.2.18:
+    dependencies:
+      chalk: 1.1.3
+      js-base64: 2.6.4
+      source-map: 0.5.7
+      supports-color: 3.2.3
+
+  postcss@8.4.38:
+    dependencies:
+      nanoid: 3.3.7
+      picocolors: 1.0.1
+      source-map-js: 1.2.0
+
+  posthtml-parser@0.2.1:
+    dependencies:
+      htmlparser2: 3.10.1
+      isobject: 2.1.0
+
+  posthtml-rename-id@1.0.12:
+    dependencies:
+      escape-string-regexp: 1.0.5
+
+  posthtml-render@1.4.0: {}
+
+  posthtml-svg-mode@1.0.3:
+    dependencies:
+      merge-options: 1.0.1
+      posthtml: 0.9.2
+      posthtml-parser: 0.2.1
+      posthtml-render: 1.4.0
+
+  posthtml@0.9.2:
+    dependencies:
+      posthtml-parser: 0.2.1
+      posthtml-render: 1.4.0
+
+  prelude-ls@1.2.1: {}
+
+  prettier-linter-helpers@1.0.0:
+    dependencies:
+      fast-diff: 1.3.0
+
+  prettier@3.3.0: {}
+
+  proxy-from-env@1.1.0: {}
+
+  prr@1.0.1:
+    optional: true
+
+  punycode@2.3.1: {}
+
+  qs@6.12.1:
+    dependencies:
+      side-channel: 1.0.6
+
+  query-string@4.3.4:
+    dependencies:
+      object-assign: 4.1.1
+      strict-uri-encode: 1.1.0
+
+  queue-microtask@1.2.3: {}
+
+  read-package-json-fast@3.0.2:
+    dependencies:
+      json-parse-even-better-errors: 3.0.2
+      npm-normalize-package-bin: 3.0.1
+
+  readable-stream@3.6.2:
+    dependencies:
+      inherits: 2.0.4
+      string_decoder: 1.3.0
+      util-deprecate: 1.0.2
+
+  readdirp@3.6.0:
+    dependencies:
+      picomatch: 2.3.1
+
+  regex-not@1.0.2:
+    dependencies:
+      extend-shallow: 3.0.2
+      safe-regex: 1.1.0
+
+  regexp.prototype.flags@1.5.2:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-errors: 1.3.0
+      set-function-name: 2.0.2
+
+  repeat-element@1.1.4: {}
+
+  repeat-string@1.6.1: {}
+
+  resolve-from@4.0.0: {}
+
+  resolve-url@0.2.1: {}
+
+  resolve@1.22.8:
+    dependencies:
+      is-core-module: 2.13.1
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+
+  ret@0.1.15: {}
+
+  reusify@1.0.4: {}
+
+  rfdc@1.3.1: {}
+
+  rimraf@3.0.2:
+    dependencies:
+      glob: 7.2.3
+
+  rollup@4.18.0:
+    dependencies:
+      '@types/estree': 1.0.5
+    optionalDependencies:
+      '@rollup/rollup-android-arm-eabi': 4.18.0
+      '@rollup/rollup-android-arm64': 4.18.0
+      '@rollup/rollup-darwin-arm64': 4.18.0
+      '@rollup/rollup-darwin-x64': 4.18.0
+      '@rollup/rollup-linux-arm-gnueabihf': 4.18.0
+      '@rollup/rollup-linux-arm-musleabihf': 4.18.0
+      '@rollup/rollup-linux-arm64-gnu': 4.18.0
+      '@rollup/rollup-linux-arm64-musl': 4.18.0
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0
+      '@rollup/rollup-linux-riscv64-gnu': 4.18.0
+      '@rollup/rollup-linux-s390x-gnu': 4.18.0
+      '@rollup/rollup-linux-x64-gnu': 4.18.0
+      '@rollup/rollup-linux-x64-musl': 4.18.0
+      '@rollup/rollup-win32-arm64-msvc': 4.18.0
+      '@rollup/rollup-win32-ia32-msvc': 4.18.0
+      '@rollup/rollup-win32-x64-msvc': 4.18.0
+      fsevents: 2.3.3
+
+  run-applescript@7.0.0: {}
+
+  run-parallel@1.2.0:
+    dependencies:
+      queue-microtask: 1.2.3
+
+  safe-array-concat@1.1.2:
+    dependencies:
+      call-bind: 1.0.7
+      get-intrinsic: 1.2.4
+      has-symbols: 1.0.3
+      isarray: 2.0.5
+
+  safe-buffer@5.2.1: {}
+
+  safe-regex-test@1.0.3:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-regex: 1.1.4
+
+  safe-regex@1.1.0:
+    dependencies:
+      ret: 0.1.15
+
+  safer-buffer@2.1.2:
+    optional: true
+
+  sax@1.4.1:
+    optional: true
+
+  scule@1.3.0: {}
+
+  semver@5.7.2:
+    optional: true
+
+  semver@6.3.1: {}
+
+  semver@7.6.2: {}
+
+  set-function-length@1.2.2:
+    dependencies:
+      define-data-property: 1.1.4
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      get-intrinsic: 1.2.4
+      gopd: 1.0.1
+      has-property-descriptors: 1.0.2
+
+  set-function-name@2.0.2:
+    dependencies:
+      define-data-property: 1.1.4
+      es-errors: 1.3.0
+      functions-have-names: 1.2.3
+      has-property-descriptors: 1.0.2
+
+  set-value@2.0.1:
+    dependencies:
+      extend-shallow: 2.0.1
+      is-extendable: 0.1.1
+      is-plain-object: 2.0.4
+      split-string: 3.1.0
+
+  shebang-command@2.0.0:
+    dependencies:
+      shebang-regex: 3.0.0
+
+  shebang-regex@3.0.0: {}
+
+  shell-quote@1.8.1: {}
+
+  side-channel@1.0.6:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+      object-inspect: 1.13.1
+
+  signal-exit@3.0.7: {}
+
+  signal-exit@4.1.0: {}
+
+  sirv@2.0.4:
+    dependencies:
+      '@polka/url': 1.0.0-next.25
+      mrmime: 2.0.0
+      totalist: 3.0.1
+
+  slash@3.0.0: {}
+
+  snapdragon-node@2.1.1:
+    dependencies:
+      define-property: 1.0.0
+      isobject: 3.0.1
+      snapdragon-util: 3.0.1
+
+  snapdragon-util@3.0.1:
+    dependencies:
+      kind-of: 3.2.2
+
+  snapdragon@0.8.2:
+    dependencies:
+      base: 0.11.2
+      debug: 2.6.9
+      define-property: 0.2.5
+      extend-shallow: 2.0.1
+      map-cache: 0.2.2
+      source-map: 0.5.7
+      source-map-resolve: 0.5.3
+      use: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
+  source-map-js@1.2.0: {}
+
+  source-map-resolve@0.5.3:
+    dependencies:
+      atob: 2.1.2
+      decode-uri-component: 0.2.2
+      resolve-url: 0.2.1
+      source-map-url: 0.4.1
+      urix: 0.1.0
+
+  source-map-url@0.4.1: {}
+
+  source-map@0.5.7: {}
+
+  source-map@0.6.1: {}
+
+  sourcemap-codec@1.4.8: {}
+
+  speakingurl@14.0.1: {}
+
+  split-string@3.1.0:
+    dependencies:
+      extend-shallow: 3.0.2
+
+  stable@0.1.8: {}
+
+  static-extend@0.1.2:
+    dependencies:
+      define-property: 0.2.5
+      object-copy: 0.1.0
+
+  strict-uri-encode@1.1.0: {}
+
+  string.prototype.trim@1.2.9:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-object-atoms: 1.0.0
+
+  string.prototype.trimend@1.0.8:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+
+  string.prototype.trimstart@1.0.8:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+
+  string_decoder@1.3.0:
+    dependencies:
+      safe-buffer: 5.2.1
+
+  strip-ansi@3.0.1:
+    dependencies:
+      ansi-regex: 2.1.1
+
+  strip-ansi@6.0.1:
+    dependencies:
+      ansi-regex: 5.0.1
+
+  strip-final-newline@2.0.0: {}
+
+  strip-final-newline@3.0.0: {}
+
+  strip-json-comments@3.1.1: {}
+
+  strip-literal@2.1.0:
+    dependencies:
+      js-tokens: 9.0.0
+
+  supports-color@2.0.0: {}
+
+  supports-color@3.2.3:
+    dependencies:
+      has-flag: 1.0.0
+
+  supports-color@5.5.0:
+    dependencies:
+      has-flag: 3.0.0
+
+  supports-color@7.2.0:
+    dependencies:
+      has-flag: 4.0.0
+
+  supports-preserve-symlinks-flag@1.0.0: {}
+
+  svg-baker@1.7.0:
+    dependencies:
+      bluebird: 3.7.2
+      clone: 2.1.2
+      he: 1.2.0
+      image-size: 0.5.5
+      loader-utils: 1.4.2
+      merge-options: 1.0.1
+      micromatch: 3.1.0
+      postcss: 5.2.18
+      postcss-prefix-selector: 1.16.1(postcss@5.2.18)
+      posthtml-rename-id: 1.0.12
+      posthtml-svg-mode: 1.0.3
+      query-string: 4.3.4
+      traverse: 0.6.9
+    transitivePeerDependencies:
+      - supports-color
+
+  svg-tags@1.0.0: {}
+
+  svgo@2.8.0:
+    dependencies:
+      '@trysound/sax': 0.2.0
+      commander: 7.2.0
+      css-select: 4.3.0
+      css-tree: 1.1.3
+      csso: 4.2.0
+      picocolors: 1.0.1
+      stable: 0.1.8
+
+  synckit@0.8.8:
+    dependencies:
+      '@pkgr/core': 0.1.1
+      tslib: 2.6.3
+
+  text-table@0.2.0: {}
+
+  to-fast-properties@2.0.0: {}
+
+  to-object-path@0.3.0:
+    dependencies:
+      kind-of: 3.2.2
+
+  to-regex-range@2.1.1:
+    dependencies:
+      is-number: 3.0.0
+      repeat-string: 1.6.1
+
+  to-regex-range@5.0.1:
+    dependencies:
+      is-number: 7.0.0
+
+  to-regex@3.0.2:
+    dependencies:
+      define-property: 2.0.2
+      extend-shallow: 3.0.2
+      regex-not: 1.0.2
+      safe-regex: 1.1.0
+
+  totalist@3.0.1: {}
+
+  traverse@0.6.9:
+    dependencies:
+      gopd: 1.0.1
+      typedarray.prototype.slice: 1.0.3
+      which-typed-array: 1.1.15
+
+  ts-api-utils@1.3.0(typescript@5.4.5):
+    dependencies:
+      typescript: 5.4.5
+
+  tslib@2.6.3: {}
+
+  type-check@0.4.0:
+    dependencies:
+      prelude-ls: 1.2.1
+
+  type-fest@0.20.2: {}
+
+  typed-array-buffer@1.0.2:
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-typed-array: 1.1.13
+
+  typed-array-byte-length@1.0.1:
+    dependencies:
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+
+  typed-array-byte-offset@1.0.2:
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+
+  typed-array-length@1.0.6:
+    dependencies:
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+      possible-typed-array-names: 1.0.0
+
+  typedarray.prototype.slice@1.0.3:
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      typed-array-buffer: 1.0.2
+      typed-array-byte-offset: 1.0.2
+
+  typescript@5.4.5: {}
+
+  ufo@1.5.3: {}
+
+  unbox-primitive@1.0.2:
+    dependencies:
+      call-bind: 1.0.7
+      has-bigints: 1.0.2
+      has-symbols: 1.0.3
+      which-boxed-primitive: 1.0.2
+
+  unconfig@0.3.13:
+    dependencies:
+      '@antfu/utils': 0.7.8
+      defu: 6.1.4
+      jiti: 1.21.1
+
+  undici-types@5.26.5: {}
+
+  unimport@3.7.2(rollup@4.18.0):
+    dependencies:
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      acorn: 8.11.3
+      escape-string-regexp: 5.0.0
+      estree-walker: 3.0.3
+      fast-glob: 3.3.2
+      local-pkg: 0.5.0
+      magic-string: 0.30.10
+      mlly: 1.7.0
+      pathe: 1.1.2
+      pkg-types: 1.1.1
+      scule: 1.3.0
+      strip-literal: 2.1.0
+      unplugin: 1.10.1
+    transitivePeerDependencies:
+      - rollup
+
+  union-value@1.0.1:
+    dependencies:
+      arr-union: 3.1.0
+      get-value: 2.0.6
+      is-extendable: 0.1.1
+      set-value: 2.0.1
+
+  universalify@2.0.1: {}
+
+  unocss@0.60.4(postcss@5.2.18)(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      '@unocss/astro': 0.60.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      '@unocss/cli': 0.60.4(rollup@4.18.0)
+      '@unocss/core': 0.60.4
+      '@unocss/extractor-arbitrary-variants': 0.60.4
+      '@unocss/postcss': 0.60.4(postcss@5.2.18)
+      '@unocss/preset-attributify': 0.60.4
+      '@unocss/preset-icons': 0.60.4
+      '@unocss/preset-mini': 0.60.4
+      '@unocss/preset-tagify': 0.60.4
+      '@unocss/preset-typography': 0.60.4
+      '@unocss/preset-uno': 0.60.4
+      '@unocss/preset-web-fonts': 0.60.4
+      '@unocss/preset-wind': 0.60.4
+      '@unocss/reset': 0.60.4
+      '@unocss/transformer-attributify-jsx': 0.60.4
+      '@unocss/transformer-attributify-jsx-babel': 0.60.4
+      '@unocss/transformer-compile-class': 0.60.4
+      '@unocss/transformer-directives': 0.60.4
+      '@unocss/transformer-variant-group': 0.60.4
+      '@unocss/vite': 0.60.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+    optionalDependencies:
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - postcss
+      - rollup
+      - supports-color
+
+  unplugin-auto-import@0.17.6(@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5)))(rollup@4.18.0):
+    dependencies:
+      '@antfu/utils': 0.7.8
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      fast-glob: 3.3.2
+      local-pkg: 0.5.0
+      magic-string: 0.30.10
+      minimatch: 9.0.4
+      unimport: 3.7.2(rollup@4.18.0)
+      unplugin: 1.10.1
+    optionalDependencies:
+      '@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.5))
+    transitivePeerDependencies:
+      - rollup
+
+  unplugin-vue-components@0.27.0(@babel/parser@7.24.6)(rollup@4.18.0)(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      '@antfu/utils': 0.7.8
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      chokidar: 3.6.0
+      debug: 4.3.5
+      fast-glob: 3.3.2
+      local-pkg: 0.5.0
+      magic-string: 0.30.10
+      minimatch: 9.0.4
+      resolve: 1.22.8
+      unplugin: 1.10.1
+      vue: 3.4.27(typescript@5.4.5)
+    optionalDependencies:
+      '@babel/parser': 7.24.6
+    transitivePeerDependencies:
+      - rollup
+      - supports-color
+
+  unplugin@1.10.1:
+    dependencies:
+      acorn: 8.11.3
+      chokidar: 3.6.0
+      webpack-sources: 3.2.3
+      webpack-virtual-modules: 0.6.2
+
+  unset-value@1.0.0:
+    dependencies:
+      has-value: 0.3.1
+      isobject: 3.0.1
+
+  update-browserslist-db@1.0.16(browserslist@4.23.0):
+    dependencies:
+      browserslist: 4.23.0
+      escalade: 3.1.2
+      picocolors: 1.0.1
+
+  uri-js@4.4.1:
+    dependencies:
+      punycode: 2.3.1
+
+  urix@0.1.0: {}
+
+  use@3.1.1: {}
+
+  util-deprecate@1.0.2: {}
+
+  v-perfect-signature@1.4.0(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      perfect-freehand: 1.2.2
+      vue: 3.4.27(typescript@5.4.5)
+      vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5))
+
+  vant@4.9.1(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      '@vant/popperjs': 1.3.0
+      '@vant/use': 1.6.0(vue@3.4.27(typescript@5.4.5))
+      '@vue/shared': 3.4.27
+      vue: 3.4.27(typescript@5.4.5)
+
+  vary@1.1.2: {}
+
+  vite-hot-client@0.2.3(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+
+  vite-plugin-compression@0.5.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      chalk: 4.1.2
+      debug: 4.3.5
+      fs-extra: 10.1.0
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  vite-plugin-inspect@0.8.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      '@antfu/utils': 0.7.8
+      '@rollup/pluginutils': 5.1.0(rollup@4.18.0)
+      debug: 4.3.5
+      error-stack-parser-es: 0.1.4
+      fs-extra: 11.2.0
+      open: 10.1.0
+      perfect-debounce: 1.0.0
+      picocolors: 1.0.1
+      sirv: 2.0.4
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - rollup
+      - supports-color
+
+  vite-plugin-svg-icons@2.0.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      '@types/svgo': 2.6.4
+      cors: 2.8.5
+      debug: 4.3.5
+      etag: 1.8.1
+      fs-extra: 10.1.0
+      pathe: 0.2.0
+      svg-baker: 1.7.0
+      svgo: 2.8.0
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  vite-plugin-vue-devtools@7.2.1(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      '@vue/devtools-core': 7.2.1(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))(vue@3.4.27(typescript@5.4.5))
+      '@vue/devtools-kit': 7.2.1(vue@3.4.27(typescript@5.4.5))
+      '@vue/devtools-shared': 7.2.1
+      execa: 8.0.1
+      sirv: 2.0.4
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+      vite-plugin-inspect: 0.8.4(rollup@4.18.0)(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+      vite-plugin-vue-inspector: 5.1.2(vite@5.2.12(@types/node@20.14.1)(less@4.2.0))
+    transitivePeerDependencies:
+      - '@nuxt/kit'
+      - rollup
+      - supports-color
+      - vue
+
+  vite-plugin-vue-inspector@5.1.2(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      '@babel/core': 7.24.6
+      '@babel/plugin-proposal-decorators': 7.24.6(@babel/core@7.24.6)
+      '@babel/plugin-syntax-import-attributes': 7.24.6(@babel/core@7.24.6)
+      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6)
+      '@babel/plugin-transform-typescript': 7.24.6(@babel/core@7.24.6)
+      '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.6)
+      '@vue/compiler-dom': 3.4.27
+      kolorist: 1.8.0
+      magic-string: 0.30.10
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  vite-plugin-vue-setup-extend@0.4.0(vite@5.2.12(@types/node@20.14.1)(less@4.2.0)):
+    dependencies:
+      '@vue/compiler-sfc': 3.4.27
+      magic-string: 0.25.9
+      vite: 5.2.12(@types/node@20.14.1)(less@4.2.0)
+
+  vite@5.2.12(@types/node@20.14.1)(less@4.2.0):
+    dependencies:
+      esbuild: 0.20.2
+      postcss: 8.4.38
+      rollup: 4.18.0
+    optionalDependencies:
+      '@types/node': 20.14.1
+      fsevents: 2.3.3
+      less: 4.2.0
+
+  vue-demi@0.14.8(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      vue: 3.4.27(typescript@5.4.5)
+
+  vue-eslint-parser@9.4.3(eslint@8.57.0):
+    dependencies:
+      debug: 4.3.5
+      eslint: 8.57.0
+      eslint-scope: 7.2.2
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      esquery: 1.5.0
+      lodash: 4.17.21
+      semver: 7.6.2
+    transitivePeerDependencies:
+      - supports-color
+
+  vue-router@4.3.2(vue@3.4.27(typescript@5.4.5)):
+    dependencies:
+      '@vue/devtools-api': 6.6.3
+      vue: 3.4.27(typescript@5.4.5)
+
+  vue-template-compiler@2.7.16:
+    dependencies:
+      de-indent: 1.0.2
+      he: 1.2.0
+
+  vue-tsc@2.0.19(typescript@5.4.5):
+    dependencies:
+      '@volar/typescript': 2.2.5
+      '@vue/language-core': 2.0.19(typescript@5.4.5)
+      semver: 7.6.2
+      typescript: 5.4.5
+
+  vue@3.4.27(typescript@5.4.5):
+    dependencies:
+      '@vue/compiler-dom': 3.4.27
+      '@vue/compiler-sfc': 3.4.27
+      '@vue/runtime-dom': 3.4.27
+      '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.4.5))
+      '@vue/shared': 3.4.27
+    optionalDependencies:
+      typescript: 5.4.5
+
+  webpack-sources@3.2.3: {}
+
+  webpack-virtual-modules@0.6.2: {}
+
+  which-boxed-primitive@1.0.2:
+    dependencies:
+      is-bigint: 1.0.4
+      is-boolean-object: 1.1.2
+      is-number-object: 1.0.7
+      is-string: 1.0.7
+      is-symbol: 1.0.4
+
+  which-typed-array@1.1.15:
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-tostringtag: 1.0.2
+
+  which@2.0.2:
+    dependencies:
+      isexe: 2.0.0
+
+  word-wrap@1.2.5: {}
+
+  wrappy@1.0.2: {}
+
+  xml-name-validator@4.0.0: {}
+
+  yallist@3.1.1: {}
+
+  yocto-queue@0.1.0: {}

+ 17 - 0
postcss.config.js

@@ -0,0 +1,17 @@
+import viewport from 'postcss-mobile-forever'
+import autoprefixer from 'autoprefixer'
+
+export default {
+  plugins: [
+    autoprefixer(),
+    viewport({
+      appSelector: '#app',
+      viewportWidth: 375,
+      maxDisplayWidth: 600,
+      rootContainingBlockSelectorList: [
+        'van-tabbar',
+        'van-popup'
+      ]
+    })
+  ]
+}

BIN=BIN
public/favicon.ico


+ 21 - 0
src/App.vue

@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import { RouterView } from 'vue-router'
+import { useGlobalStore } from '@/stores/modules/global'
+import { useCachedViewStore } from '@/stores/modules/cachedView'
+
+const globalStore = useGlobalStore()
+const cachedViewStore = useCachedViewStore()
+const cachedViews = computed(() => cachedViewStore.cachedViews)
+</script>
+
+<template>
+  <van-config-provider :theme="globalStore.darkMode">
+    <router-view v-slot="{ Component }">
+      <keep-alive :include="cachedViews">
+        <component :is="Component" />
+      </keep-alive>
+    </router-view>
+  </van-config-provider>
+</template>
+
+<style scoped></style>

+ 174 - 0
src/api/index.ts

@@ -0,0 +1,174 @@
+import type {
+  AxiosError,
+  AxiosInstance,
+  AxiosRequestConfig,
+  AxiosResponse,
+  InternalAxiosRequestConfig
+} from 'axios'
+import axios, { HttpStatusCode } from 'axios'
+import qs from 'qs'
+import type { ResultData } from '@/typings/api'
+import { useAuthStore } from '@/stores/modules/auth'
+import { showFailToast } from 'vant'
+
+/**
+ * axios配置
+ */
+const config = {
+  baseURL: import.meta.env.VITE_API_URL,
+  timeout: 8000,
+  paramsSerializer: {
+    serialize(params: Recordable) {
+      for (const key in params) {
+        if (params[key] === '' || params[key] === null) {
+          delete params[key]
+        }
+      }
+      return qs.stringify(params, { allowDots: true })
+    }
+  }
+}
+
+class RequestHttp {
+  service: AxiosInstance
+
+  /**
+   * 请求构造函数
+   * @param config
+   */
+  public constructor(config: AxiosRequestConfig) {
+    // 创建axios实例
+    this.service = axios.create(config)
+    // 请求拦截
+    this.service.interceptors.request.use(
+      (config: InternalAxiosRequestConfig) => {
+        // 请求头携带token
+        const { tokenGet } = useAuthStore()
+        if (tokenGet) {
+          config.headers['Authorization'] = tokenGet
+        }
+        return config
+      },
+      (error: AxiosError) => {
+        // 请求错误处理
+        return Promise.reject(error)
+      }
+    )
+    // 响应拦截
+    this.service.interceptors.response.use(
+      (response: AxiosResponse) => {
+        const { data } = response
+        // 响应拦截处理
+        return data
+      },
+      (error: AxiosError<ResultData<any>>) => {
+        const authStore = useAuthStore()
+        const { response, message } = error
+        const data = response?.data
+        const errMsg = data?.message || message
+        // 响应错误处理
+        if (response?.status === HttpStatusCode.Unauthorized) {
+          if (window.location.pathname.toLocaleLowerCase() !== '/login') {
+            authStore.$reset()
+            window.location.reload()
+          }
+        } else {
+          showFailToast(errMsg || '请求失败')
+        }
+        // 判断客户端是否联网
+        if (!window.navigator.onLine) {
+          showFailToast('网络异常')
+        }
+        return Promise.reject(response?.data || error)
+      }
+    )
+  }
+
+  /**
+   * get请求
+   * @param url 请求地址
+   * @param params 请求参数
+   * @param config 其他配置
+   */
+  get<T>(url: string, params?: object, config = {}): Promise<ResultData<T>> {
+    return this.service.get(url, { params, ...config })
+  }
+
+  /**
+   * post请求
+   * @param url 请求地址
+   * @param data 请求参数
+   * @param config 其他配置
+   */
+  post<T>(url: string, data?: object, config = {}): Promise<ResultData<T>> {
+    return this.service.post(url, data, config)
+  }
+
+  /**
+   * put请求
+   * @param url 请求地址
+   * @param data 请求参数
+   * @param config 其他配置
+   */
+  put<T>(url: string, data?: object, config = {}): Promise<ResultData<T>> {
+    return this.service.put(url, data, config)
+  }
+
+  /**
+   * delete请求
+   * @param url 请求地址
+   * @param data 请求参数
+   * @param config 其他配置
+   */
+  delete<T>(url: string, data?: object, config = {}): Promise<ResultData<T>> {
+    return this.service.delete(url, { data, ...config })
+  }
+
+  /**
+   * patch请求
+   * @param url 请求地址
+   * @param data 请求参数
+   * @param config 其他配置
+   */
+  patch<T>(url: string, data?: object, config = {}): Promise<ResultData<T>> {
+    return this.service.patch(url, data, config)
+  }
+
+  /**
+   * head请求
+   * @param url 请求地址
+   * @param config 其他配置
+   */
+  head<T>(url: string, config = {}): Promise<ResultData<T>> {
+    return this.service.head(url, config)
+  }
+
+  /**
+   * options请求
+   * @param url 请求地址
+   * @param config 其他配置
+   */
+  options<T>(url: string, config = {}): Promise<ResultData<T>> {
+    return this.service.options(url, config)
+  }
+
+  /**
+   * request请求
+   * @param config 请求配置
+   */
+  request<T>(config: AxiosRequestConfig): Promise<ResultData<T>> {
+    return this.service.request(config)
+  }
+
+  /**
+   * 下载文件
+   * @param url 请求地址
+   * @param data 请求参数
+   * @param config 其他配置
+   */
+  download(url: string, data?: object, config = {}): Promise<BlobPart> {
+    return this.service.post(url, data, { ...config, responseType: 'blob' })
+  }
+}
+
+export default new RequestHttp(config)

+ 27 - 0
src/api/modules/file/file.ts

@@ -0,0 +1,27 @@
+import http from '@/api'
+import type { BaseEntity } from '@/typings/api'
+
+export type CategoryEnum = 'image' | 'video' | 'audio' | 'doc' | 'other'
+
+export interface StorageFile extends BaseEntity {
+  name: string
+  realName: string
+  path: string
+  url: string
+  type: string
+  category: CategoryEnum
+  md5: string
+  size: number
+  businessId: string
+  businessExtraId: string
+}
+
+export const upload = (file: File) => {
+  const formData = new FormData()
+  formData.append('file', file)
+  return http.post<StorageFile>('/file/upload', formData)
+}
+
+export const deleteByIds = (ids: string[]) => {
+  return http.delete('/file/delete', ids)
+}

+ 60 - 0
src/api/modules/flow/activity.ts

@@ -0,0 +1,60 @@
+import http from '@/api'
+import { ProcessStatus } from '@/api/modules/flow/instance'
+import { cloneDeep } from 'lodash-es'
+
+export interface FlowActivity {
+  id: string
+  defineId: string
+  multi: 'sequential' | 'joint' | 'single'
+  taskId: string
+  instanceId: string
+  executionId: string
+  activityId: string
+  activityName: string
+  activityType: string
+  assignee: string
+  startTime: string
+  endTime: string
+  duration: number
+  deleteReason?: string
+  status: ProcessStatus | -1
+  records?: FlowActivity[]
+}
+
+export const records = (instanceId: string) => {
+  return http.get<FlowActivity[]>(`/activity/records/${instanceId}`)
+}
+
+export const buildRecords = (data: FlowActivity[]) => {
+  const activities = cloneDeep(data)
+  const length = activities.length
+  for (let i = 0; i < length; i++) {
+    const item = activities[i]
+    const next = activities[i + 1]
+    if (
+      next &&
+      next.multi !== 'sequential' &&
+      item.multi !== 'sequential' &&
+      next.activityId === item.activityId
+    ) {
+      if (!Array.isArray(item.records)) {
+        item.records = []
+      }
+      if (item.activityType === 'userTask') {
+        item.activityType = 'multiUser'
+      }
+      item.records.push(next)
+      activities.splice(i + 1, 1)
+      i--
+    }
+  }
+  activities.forEach((item) => {
+    if (item.multi !== 'sequential') {
+      if (!Array.isArray(item.records)) {
+        item.records = []
+      }
+      item.records.unshift(cloneDeep(item))
+    }
+  })
+  return activities
+}

+ 78 - 0
src/api/modules/flow/define.ts

@@ -0,0 +1,78 @@
+import http from '@/api'
+import type { BaseEntity } from '@/typings/api'
+import type { FormConf } from '@/components/FormParser/type'
+import type { ModelIcon } from '@/api/modules/flow/model'
+import { type FlowGroup, getList as getGroups } from '@/api/modules/flow/group'
+import { ProcessStatus } from '@/api/modules/flow/instance'
+import type { FlowNode, OperationPermissions } from '@/api/modules/flow/flowDesign'
+
+export interface FlowDefine extends BaseEntity {
+  defineId: string
+  key: string
+  name: string
+  version: number
+  groupId: string
+  icon: ModelIcon
+  process: FlowNode
+  form: FormConf
+  deploymentId: string
+  description: string
+  suspend: number
+}
+
+export interface DefineGroup extends FlowGroup {
+  defines: FlowDefine[]
+}
+
+export interface FormInfo {
+  formName: string
+  instanceId?: string
+  taskId?: string
+  flowDefine: FlowDefine
+  status: ProcessStatus
+  startUserId: string
+  startTime: string
+  endTime: string
+  operations: OperationPermissions
+}
+
+export interface StartProcess {
+  defineId: string
+  instanceName: string
+  businessKey: string
+  values: Recordable
+}
+
+export const start = (startProcess: StartProcess) => {
+  return http.post('/define/start', startProcess)
+}
+
+export const getStartForm = (defineId: string) => {
+  return http.get<FormInfo>(`/define/startForm/${defineId}`)
+}
+
+export const getGroupList = async () => {
+  const all = await Promise.all([getGroups(), getList()])
+  if (all[0]) {
+    const groups = all[0]
+    const defines = all[1].success ? all[1].data : []
+    return groups.map((group) => {
+      return {
+        ...group,
+        defines: defines.filter((define) => define.groupId === group.id)
+      }
+    })
+  }
+}
+
+export const getList = (query?: FlowDefine) => {
+  return http.get<FlowDefine[]>('/define', query)
+}
+
+export const getDefine = (defineId: string) => {
+  return http.get<FlowDefine>(`/define/${defineId}`)
+}
+
+export const suspend = (defineId: string) => {
+  return http.put<FlowDefine>(`/define/suspend/${defineId}`)
+}

+ 198 - 0
src/api/modules/flow/flowDesign.ts

@@ -0,0 +1,198 @@
+import type { Options } from '@/components/Render/type'
+
+export type NodeType =
+  | 'start'
+  | 'approval'
+  | 'cc'
+  | 'jump'
+  | 'exclusive'
+  | 'inclusive'
+  | 'concurrent'
+  | 'parallel'
+  | 'timer'
+  | 'notify'
+  | 'condition'
+  | 'end'
+
+export interface InjectField {
+  type: 'string' | 'expression'
+  name: string
+  value: string
+}
+
+export interface FlowNode {
+  id: string
+  pid?: string
+  name: string
+  type: NodeType
+  executionListeners?: NodeListener[]
+  next?: FlowNode
+}
+
+export interface NodeListener {
+  event: string
+  implementationType: 'class' | 'expression' | 'delegateExpression'
+  implementation: string
+}
+
+export interface StartNode extends FlowNode {
+  formProperties: FormProperty[]
+}
+
+export interface AssigneeNode extends FlowNode {
+  // 审批方式
+  assigneeType:
+    | 'user'
+    | 'role'
+    | 'organization'
+    | 'formOrganization'
+    | 'choice'
+    | 'self'
+    | 'leader'
+    | 'orgLeader'
+    | 'formUser'
+    | 'formRole'
+    | 'autoRefuse'
+  // 审批人
+  users: string[]
+  // 审批角色
+  roles: string[]
+  // 审批组织
+  organizations: string[]
+  // 表单内组织
+  formOrganization: string
+  // 表单内人员
+  formUser: string
+  // 表单内角色
+  formRole: string
+  // 主管
+  leader: number
+  // 组织主管
+  orgLeader: number
+  // 自选:true-多选,false-单选
+  choice: boolean
+  // 发起人自己
+  self: boolean
+}
+
+export interface CcNode extends AssigneeNode {
+  formProperties: FormProperty[]
+}
+
+export interface NotifyNode extends AssigneeNode {
+  types: ('site' | 'email' | 'sms' | 'wechat' | 'dingtalk' | 'feishu')[]
+  subject: string
+  content: string
+}
+
+export interface ApprovalNode extends AssigneeNode {
+  // 多人审批方式
+  multi: 'sequential' | 'joint' | 'single'
+  // 审批人为空时处理方式:reject-拒绝,pass-通过,admin-管理员,assign-指定人员
+  nobody: 'refuse' | 'pass' | 'admin' | 'assign'
+  // 审批人与发起人是同一人:self-由提交人自己审批、skip:自动跳过、leader:直属上级审批、orgLeader:部门负责人审批
+  same: 'self' | 'skip' | 'leader' | 'orgLeader'
+  // 多人审批通过比例
+  multiPercent: number
+  // 审批人为空时,指定人员
+  nobodyUsers: string[]
+  // 审批超时
+  timeout: ApprovalTimeout
+  // 表单字段
+  formProperties: FormProperty[]
+  // 操作权限
+  operations: OperationPermissions
+  // 任务监听器
+  taskListeners?: NodeListener[]
+}
+
+export interface TimerNode extends FlowNode {
+  waitType: 'duration' | 'date'
+  unit: 'PT%sS' | 'PT%sM' | 'PT%sH' | 'P%sD' | 'P%sW' | 'P%sM'
+  duration: number
+  timeDate?: string
+}
+
+export interface JumpNode extends FlowNode {
+  targetNode?: string
+}
+
+export interface HttpNode extends FlowNode {
+  url?: string
+  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
+  headers?: Options[]
+  body?: Options[]
+  requestTimeout?: number
+  errorUsers: string[]
+}
+
+export interface ServiceNode extends FlowNode {
+  implementationType: string
+  implementation: string
+  fields: InjectField[]
+}
+
+export interface EndNode extends FlowNode {}
+
+export interface ConditionNode extends FlowNode {
+  def: boolean
+  conditions: any
+}
+
+export interface BranchNode extends FlowNode {
+  branches: FlowNode[]
+}
+
+export interface ExclusiveNode extends BranchNode {
+  branches: ConditionNode[]
+}
+
+export interface InclusiveNode extends BranchNode {
+  branches: ConditionNode[]
+}
+
+export interface ParallelNode extends BranchNode {}
+
+export interface ErrorInfo {
+  id: string
+  name: string
+  message: string
+}
+
+export interface FormProperty {
+  // 字段ID
+  id: string
+  // 字段名称
+  name: string
+  // 只读
+  readonly: boolean
+  // 必填
+  required: boolean
+  // 隐藏
+  hidden: boolean
+}
+
+export interface OperationPermissions {
+  // 同意
+  complete: boolean
+  // 拒绝
+  refuse: boolean
+  // 回退
+  back: boolean
+  // 转交
+  transfer: boolean
+  // 委派
+  delegate: boolean
+  // 加签
+  addMulti: boolean
+  // 减签
+  minusMulti: boolean
+}
+
+export interface ApprovalTimeout {
+  enabled: boolean
+  duration: number
+  unit: 'PT%sS' | 'PT%sM' | 'PT%sH' | 'P%sD' | 'P%sW' | 'P%sM'
+  action: 'pass' | 'refuse' | 'remind'
+  loop: boolean
+}

+ 46 - 0
src/api/modules/flow/group.ts

@@ -0,0 +1,46 @@
+import http from '@/api'
+import type { BaseEntity, ResponseEntity } from '@/typings/api'
+
+export interface FlowGroup extends BaseEntity {
+  name: string
+  sort: number
+}
+
+export interface FlowGroupResponse extends FlowGroup, ResponseEntity {}
+
+export interface FlowGroupQuery {
+  name?: string
+}
+
+export const getList = async (query?: FlowGroupQuery) => {
+  const res = await http.get<FlowGroup[]>('/group', query)
+  if (res.success) {
+    const options = res.data
+    options.push({
+      id: '0',
+      name: '其他',
+      sort: 999
+    })
+    return options
+  }
+}
+
+export const create = (flowGroup: FlowGroup) => {
+  return http.post<FlowGroup>('/group', flowGroup)
+}
+
+export const update = (flowGroup: FlowGroup) => {
+  return http.put<FlowGroup>('/group', flowGroup)
+}
+
+export const createOrUpdate = (flowGroup: FlowGroup) => {
+  return flowGroup.id ? update(flowGroup) : create(flowGroup)
+}
+
+export const deleteByIds = (ids: string[]) => {
+  return http.delete('/group', ids)
+}
+
+export const sort = (newId: string, oldId: string) => {
+  return http.put(`/group/sort/${newId}/${oldId}`)
+}

+ 75 - 0
src/api/modules/flow/instance.ts

@@ -0,0 +1,75 @@
+import http from '@/api'
+import type { BaseEntity, PageQuery, ResultPage } from '@/typings/api'
+import type { FormInfo } from '@/api/modules/flow/define'
+
+export interface FlowInstance extends BaseEntity {
+  name: string
+  definitionId: string
+  version: number
+  startUserId: string
+  startTime: string
+  endTime: string
+  duration: number
+  cancelDays: number
+  status: ProcessStatus
+}
+
+export enum ProcessStatus {
+  RUNNING = 0,
+  COMPLETED = 1,
+  CANCELED = 2,
+  REFUSE = 3,
+  REJECT = 4
+}
+
+export const ProcessStatusDescriptions: { [key in ProcessStatus | -1]: string } = {
+  [ProcessStatus.RUNNING]: '进行中',
+  [ProcessStatus.COMPLETED]: '通过',
+  [ProcessStatus.CANCELED]: '撤回',
+  [ProcessStatus.REFUSE]: '拒绝',
+  [ProcessStatus.REJECT]: '回退',
+  '-1': ''
+}
+
+export interface FlowInstanceQuery extends PageQuery {
+  id: string
+  name: string
+  startUserId?: string
+  modelCode: string
+  definitionId: string
+  status?: number
+  startDates?: string[]
+  endDates?: string[]
+}
+
+export const list = (query: FlowInstanceQuery) => {
+  return http.get<ResultPage<FlowInstance>>('/instance', query)
+}
+
+export const me = (query: FlowInstanceQuery) => {
+  return http.get<ResultPage<FlowInstance>>('/instance/me', query)
+}
+
+export const copy = (query: FlowInstanceQuery) => {
+  return http.get<ResultPage<FlowInstance>>('/instance/copy', query)
+}
+
+export const getInstance = (instanceId: string) => {
+  return http.get<FlowInstance>(`/instance/${instanceId}`)
+}
+
+export const getVariables = (instanceId: string) => {
+  return http.get<Recordable>(`/instance/variables/${instanceId}`)
+}
+
+export const getForm = (instanceId: string) => {
+  return http.get<FormInfo>(`/instance/form/${instanceId}`)
+}
+
+export const cancel = (instanceIds: string[]) => {
+  return http.put('/instance/cancel', instanceIds)
+}
+
+export const getPrintData = (instanceId: string) => {
+  return http.get<string>(`/instance/print/${instanceId}`)
+}

+ 96 - 0
src/api/modules/flow/model.ts

@@ -0,0 +1,96 @@
+import type { BaseEntity, ResponseEntity } from '@/typings/api'
+import type { FormConf } from '@/components/FormParser/type'
+import http from '@/api'
+import { type FlowGroup, getList as getGroups } from './group'
+import type { FlowNode } from './flowDesign'
+
+export interface FlowModel extends BaseEntity {
+  code: string
+  name: string
+  sort: number
+  icon: ModelIcon
+  process: FlowNode
+  form: FormConf
+  version: number
+  groupId: string
+  remark: string
+  admin: string[]
+  enable: boolean
+  settings: ModelSettings
+}
+
+export interface ModelSettings {
+  cancel: {
+    enable: boolean
+    days: number
+  }
+  title: {
+    type: 'default' | 'custom'
+    value?: string
+  }
+  print: {
+    enable: boolean
+    template: string
+  }
+}
+
+export interface ModelIcon {
+  name: string
+  color: string
+  bgColor: string
+}
+
+export interface FlowModelQuery {
+  name?: string
+}
+
+export interface FlowModelResult extends FlowModel, ResponseEntity {}
+
+export interface ModelGroup extends FlowGroup {
+  models: FlowModelResult[]
+}
+
+export const getGroupList = async () => {
+  const all = await Promise.all([getGroups(), getList()])
+  if (all[0]) {
+    const groups = all[0]
+    const models = all[1].success ? all[1].data : []
+    return groups.map((group) => {
+      return {
+        ...group,
+        models: models.filter((model) => model.groupId === group.id)
+      }
+    })
+  }
+}
+
+export const getList = (query?: FlowModelQuery) => {
+  return http.get<FlowModelResult[]>('/model', query)
+}
+
+export const getModel = (modelId: string) => {
+  return http.get<FlowModelResult>(`/model/${modelId}`)
+}
+
+export const create = (flowModel: FlowModel) => {
+  return http.post<FlowModelResult>('/model', flowModel)
+}
+
+export const update = (flowModel: FlowModel) => {
+  return http.put<FlowModelResult>('/model', flowModel)
+}
+
+export const suspend = (modelId: string) => {
+  return http.put<FlowModelResult>(`/model/suspend/${modelId}`)
+}
+export const createOrUpdate = (flowModel: FlowModel) => {
+  return flowModel.id ? update(flowModel) : create(flowModel)
+}
+
+export const deploy = (modelId: string) => {
+  return http.post<FlowModelResult>(`/model/deploy/${modelId}`)
+}
+
+export const deleteByIds = (ids: string[]) => {
+  return http.delete('/model', ids)
+}

+ 137 - 0
src/api/modules/flow/task.ts

@@ -0,0 +1,137 @@
+import http from '@/api'
+import type { FormInfo } from '@/api/modules/flow/define'
+import type { BaseEntity, PageQuery, ResultPage } from '@/typings/api'
+import { ProcessStatus } from '@/api/modules/flow/instance'
+import type { FlowNode } from '@/api/modules/flow/flowDesign'
+
+export interface FlowTask extends BaseEntity {
+  id: string
+  name: string
+  instanceId: string
+  instanceName: string
+  definitionId: string
+  assignee: string
+  startUserId: string
+  startTime: string
+  endTime: string
+  dueDate: string
+  duration: number
+  status: ProcessStatus
+}
+
+/**
+ * 评论
+ */
+export interface FlowComment {
+  // 流程实例id
+  instanceId?: string
+  // 任务id
+  taskId: string
+  // 评论内容
+  content: string
+  // 评论人
+  userId: string
+  // 评论时间
+  time?: string
+  // 附件
+  attachments: Attachment[]
+}
+
+/**
+ * 附件
+ */
+export interface Attachment {
+  // 文件类型
+  type: string
+  // 文件名称
+  name: string
+  // 文件大小
+  size: number
+  // 文件地址
+  url: string
+}
+
+export interface TaskForm {
+  taskId: string
+  values: Recordable
+  comment: FlowComment
+}
+
+export interface RejectTaskForm extends TaskForm {
+  targetNode: string
+}
+
+export interface TransferTaskForm extends TaskForm {
+  assignee: string
+}
+
+export interface TaskQuery extends PageQuery {
+  name: string
+  startUserId: string
+  instanceName: string
+  instanceId: string
+  modelCode: string
+  definitionId: string
+  status?: number
+  startDates?: string[]
+  endDates?: string[]
+}
+
+export const todo = (query: TaskQuery) => {
+  return http.get<ResultPage<FlowTask>>('/task/todo', query)
+}
+
+export const done = (query: TaskQuery) => {
+  return http.get<ResultPage<FlowTask>>('/task/done', query)
+}
+
+export const getForm = (taskId: string) => {
+  return http.get<FormInfo>(`/task/form/${taskId}`)
+}
+
+export const complete = (taskForm: TaskForm) => {
+  return http.post('/task/complete', taskForm)
+}
+
+export const rejectTask = (taskForm: RejectTaskForm) => {
+  return http.post('/task/reject', taskForm)
+}
+
+export const transfer = (taskForm: TransferTaskForm) => {
+  return http.post('/task/transfer', taskForm)
+}
+
+export const addSign = (taskForm: TransferTaskForm) => {
+  return http.post('/task/addSign', taskForm)
+}
+
+export const removeSign = (taskForm: TransferTaskForm) => {
+  return http.post('/task/removeSign', taskForm)
+}
+
+export const refuseTask = (taskForm: TaskForm) => {
+  return http.post('/task/refuse', taskForm)
+}
+
+export const delegate = (taskForm: TransferTaskForm) => {
+  return http.post('/task/delegate', taskForm)
+}
+
+export const comment = (taskForm: TaskForm) => {
+  return http.post('/task/comment', taskForm)
+}
+
+export const getComments = (taskId: string) => {
+  return http.get<FlowComment[]>(`/task/comment/${taskId}`)
+}
+
+export const getParentNodes = (taskId: string) => {
+  return http.get<FlowNode[]>(`/task/parentNodes/${taskId}`)
+}
+
+export const getMultiInstanceUnStartedUsers = (taskId: string) => {
+  return http.get<string[]>(`/task/unStartedUsers/${taskId}`)
+}
+export const getMultiInstanceTaskUnUsers = (taskId: string) => {
+  return http.get<string[]>(`/task/unUsers/${taskId}`)
+}

+ 66 - 0
src/api/modules/oauth/auth.ts

@@ -0,0 +1,66 @@
+import http from '@/api'
+import type { BaseEntity } from '@/typings/api'
+
+export interface UserInfo extends BaseEntity {
+  name: string
+  sex: number
+  username: string
+  avatar: string
+  email: string
+  phone: string
+}
+
+export interface LoginForm {
+  username: string
+  password: string
+  code: string
+  uuid: string
+}
+
+export interface AuthResponse {
+  accessToken: string
+  refreshToken: string
+  expiresIn: number
+  tokenType: string
+  scope: string[]
+}
+
+export interface VerificationCode {
+  img: string
+  uuid: string
+}
+
+/**
+ * 登录
+ * @param loginForm
+ */
+export const login = (loginForm: LoginForm) => {
+  return http.post<AuthResponse>('/auth/login', loginForm)
+}
+
+/**
+ * 退出
+ */
+export const logout = () => {
+  return http.post<null>('/auth/logout')
+}
+/**
+ * 刷新token
+ */
+export const refreshToken = () => {
+  return http.post<AuthResponse>('/auth/refresh')
+}
+
+/**
+ * 获取验证码
+ */
+export const getCodeImg = () => {
+  return http.get<VerificationCode>('/auth/code')
+}
+
+/**
+ * 获取用户信息
+ */
+export const getInfo = () => {
+  return http.get<UserInfo>('/auth/info')
+}

+ 34 - 0
src/api/modules/system/dept.ts

@@ -0,0 +1,34 @@
+import http from '@/api'
+import type { BaseEntity } from '@/typings/api'
+
+export interface Dept extends BaseEntity {
+  pid: string
+  name: string
+  sort: number
+  leader: string
+  children?: Dept[]
+}
+
+export interface DeptQuery {
+  name?: string
+}
+
+export const getById = (id: string) => {
+  return http.get<Dept>(`/dept/${id}`)
+}
+
+export const getOptions = (deptIds: string[]) => {
+  return http.post<Dept[]>('/dept/options', deptIds)
+}
+
+export const search = (params: Recordable) => {
+  return http.get<Dept[]>('/dept/search', params)
+}
+
+export const getChild = (pid: string) => {
+  return http.get<Dept[]>(`/dept/child/${pid}`)
+}
+
+export const getTree = (deptQuery: DeptQuery) => {
+  return http.get<Dept[]>('/dept/tree', deptQuery)
+}

+ 21 - 0
src/api/modules/system/role.ts

@@ -0,0 +1,21 @@
+import http from '@/api'
+import type { BaseEntity, PageQuery, ResultPage } from '@/typings/api'
+
+export interface Role extends BaseEntity {
+  name: string
+  dataScope: number
+  description: string
+  permissions?: string[]
+}
+
+export interface RoleQuery extends PageQuery {
+  name?: string
+}
+
+export const getById = (id: string) => {
+  return http.get<Role>(`/role/${id}`)
+}
+
+export const getList = (params: RoleQuery) => {
+  return http.get<ResultPage<Role>>('/role', params)
+}

+ 44 - 0
src/api/modules/system/user.ts

@@ -0,0 +1,44 @@
+import http from '@/api'
+import type { BaseEntity, PageQuery, ResultPage } from '@/typings/api'
+
+export interface User extends BaseEntity {
+  name: string
+  username: string
+  avatar: string
+  sex: number
+  phone: string
+  email: string
+  enabled: boolean
+  deptId: string
+  leader: string
+  roleIds: string[]
+}
+
+export interface UserQuery extends PageQuery {
+  name?: string
+  username?: string
+  sex?: number
+  phone?: string
+  email?: string
+  enabled?: boolean
+  deptId?: string
+}
+
+export const list = (name?: String) => {
+  return http.get<User[]>('/user/list', { name })
+}
+export const search = (params: Recordable) => {
+  return http.get<User[]>('/user/search', params)
+}
+export const getList = (params: UserQuery) => {
+  return http.get<ResultPage<User>>('/user', params)
+}
+export const getByUsername = (username: string) => {
+  return http.get<User>(`/user/${username}`)
+}
+export const getOptions = (usernames: string[]) => {
+  return http.post<User[]>('/user/options', usernames)
+}
+export const resetPassword = (username: string) => {
+  return http.put(`/user/reset/${username}`)
+}

+ 1 - 0
src/assets/icons/logo.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

BIN=BIN
src/assets/images/login_bg.jpg


+ 40 - 0
src/components/Breadcrumb/BreadcrumbItem.vue

@@ -0,0 +1,40 @@
+<script setup lang="ts"></script>
+
+<template>
+  <span class="van-breadcrumb-item">
+    <span class="van-breadcrumb__inner">
+      <slot></slot>
+    </span>
+    <van-icon name="arrow" size="12" class="separator-icon" />
+  </span>
+</template>
+
+<style scoped lang="less">
+.van-breadcrumb-item {
+  float: left;
+  display: inline-block;
+  align-items: center;
+  .separator-icon {
+    margin: 0 3px;
+    font-weight: 700;
+  }
+  &:not(:last-child) {
+    .van-breadcrumb__inner {
+      color: var(--van-primary-color);
+    }
+  }
+  &:last-child {
+    .van-breadcrumb__inner {
+      color: var(--van-text-color-2);
+    }
+    .separator-icon {
+      display: none;
+    }
+  }
+  .van-breadcrumb__inner {
+    font-weight: 500;
+    text-decoration: none;
+    color: var(--van-text-color);
+  }
+}
+</style>

+ 14 - 0
src/components/Breadcrumb/index.vue

@@ -0,0 +1,14 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="van-breadcrumb">
+    <slot></slot>
+  </div>
+</template>
+
+<style scoped lang="less">
+.van-breadcrumb {
+  font-size: 14px;
+  line-height: 1;
+}
+</style>

+ 121 - 0
src/components/Comment/index.vue

@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import { useUserCacheStore } from '@/stores/modules/userCache'
+
+const props = defineProps<{
+  author: string
+  datetime: string
+}>()
+const userInfo = ref<{
+  avatar: string
+  username: string
+  nickname: string
+}>({
+  avatar: '',
+  username: '',
+  nickname: ''
+})
+const userCacheStore = useUserCacheStore()
+onMounted(() => {
+  userCacheStore.getUser(props.author).then((user) => {
+    if (user) {
+      const { name, username, avatar } = user
+      userInfo.value = {
+        avatar: avatar,
+        username,
+        nickname: name
+      }
+    }
+  })
+})
+</script>
+
+<template>
+  <div class="van-comment">
+    <div class="comment-avatar">
+      <slot name="avatar">
+        <van-image :src="userInfo.avatar" round class="h-6 w-6">
+          <template v-slot:loading>
+            {{ (userInfo.nickname || props.author).charAt(0) }}
+          </template>
+        </van-image>
+      </slot>
+    </div>
+    <div class="comment-inner">
+      <div class="comment-inner__content">
+        <div class="comment-title">
+          <span class="comment-author">
+            {{ userInfo.nickname || props.author }}
+          </span>
+          <span class="comment-datetime">
+            {{ props.datetime }}
+          </span>
+        </div>
+        <div class="comment-content">
+          <slot name="content"></slot>
+        </div>
+        <div class="comment-actions">
+          <slot name="actions"></slot>
+        </div>
+      </div>
+      <div class="comment-inner__comment">
+        <slot></slot>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.van-comment {
+  display: flex;
+
+  .comment-avatar {
+    flex-shrink: 0;
+    margin-right: 12px;
+    cursor: pointer;
+  }
+
+  .comment-inner {
+    flex: 1;
+
+    .comment-inner__content {
+      .comment-title {
+        display: flex;
+        justify-content: space-between;
+
+        .comment-author {
+          margin-right: 8px;
+        }
+      }
+
+      .comment-content {
+        width: fit-content;
+        background-color: var(--van-text-color-3);
+        padding: 5px 10px;
+        margin-top: 5px;
+        border-radius: 5px;
+        position: relative;
+        &::before {
+          content: '';
+          position: absolute;
+          top: 2px;
+          width: 0;
+          height: 0;
+          border: 4px solid transparent;
+          left: -4px;
+          border-left: none;
+          border-right-color: var(--van-text-color-3);
+        }
+      }
+
+      .comment-actions {
+        display: flex;
+        justify-content: flex-end;
+      }
+    }
+
+    .comment-inner__comment {
+      margin-top: 20px;
+    }
+  }
+}
+</style>

+ 211 - 0
src/components/FormParser/index.tsx

@@ -0,0 +1,211 @@
+import Render from '@/components/Render/index'
+import type { PropType, VNode } from 'vue'
+import { renderSlot } from 'vue'
+import { cloneDeep } from 'lodash-es'
+import type { FormConf, FormField } from './type'
+import useForm from './useForm'
+import type { FieldRule, FormInstance } from 'vant'
+
+export default defineComponent({
+  props: {
+    formConf: {
+      type: Object as PropType<FormConf>,
+      required: true
+    },
+    formData: {
+      type: Object as PropType<Recordable>,
+      required: true
+    }
+  },
+  emits: ['submit', 'reset'],
+  setup(props, { slots, emit }) {
+    const formConfCopy: FormConf = reactive(cloneDeep(props.formConf))
+    const formRef = ref<FormInstance>()
+    const { addObserver, delObserver, trigger } = useForm(formConfCopy, props.formData)
+
+    /**
+     * 布局
+     */
+    const layouts: Recordable<(field: FormField) => VNode> = {
+      /**
+       * 表单项
+       * @param field
+       */
+      formItem: (field: FormField): VNode => {
+        const prop = field.id
+        const hidden = field.hidden
+        field.props.rules = buildRule(field)
+        field.props._vModel_ = prop
+        field.props.readonly = field.readonly
+        if (hidden) {
+          return <div></div>
+        }
+        const child = renderChildren(field)
+        return (
+          <Render
+            field={field}
+            key={field.props.key}
+            onAddObserver={addObserver}
+            onDelObserver={delObserver}
+            modelValue={props.formData[field.id]}
+            onUpdate:modelValue={(val) => {
+              if (field.readonly) return
+              setValue(field, val)
+            }}
+          >
+            {child}
+          </Render>
+        )
+      },
+      /**
+       * 容器
+       * @param field
+       */
+      container: (field: FormField): VNode => {
+        const hidden = field.hidden
+        if (hidden) {
+          return <div></div>
+        }
+        const child = renderChildren(field)
+        return (
+          <Render
+            field={field}
+            key={field.props.key}
+            modelValue={field.value}
+            onUpdate:modelValue={(val) => {
+              field.value = val
+            }}
+            onAddObserver={addObserver}
+            onDelObserver={delObserver}
+          >
+            {child}
+          </Render>
+        )
+      }
+    }
+
+    /**
+     * 设置值
+     * @param field
+     * @param val
+     */
+    const setValue = (field: FormField, val: unknown) => {
+      field.value && (field.value = val)
+      if (field.id) {
+        props.formData[field.id] = val
+      }
+      trigger(field.id)
+    }
+    /**
+     * 渲染子组件
+     * @param element
+     */
+    const renderChildren = (element: FormField): VNode[] | undefined => {
+      const children: FormField[] | undefined = element.children
+      if (!Array.isArray(children)) return
+      return renderFormItem(children)
+    }
+    /**
+     * 构建校验
+     * @param field
+     */
+    const buildRule = (field: FormField) => {
+      const { props, rules } = field
+      let ruleList: FieldRule[] = []
+      if (Array.isArray(rules)) {
+        ruleList.push(
+          ...rules.map((rule) => {
+            return {
+              pattern: rule.pattern && new RegExp(rule.pattern),
+              message: `请输入正确的${rule.message}`
+            }
+          })
+        )
+      }
+      if (field.required !== undefined) {
+        const required: FieldRule = {
+          required: field.required || false,
+          message: props.placeholder
+        }
+        if (Array.isArray(field.value)) {
+          required.message = `请至少选择一个${field.label}`
+          required.trigger = 'onChange'
+        }
+        required.message === undefined && (required.message = `${field.label}不能为空`)
+        ruleList.push(required)
+      }
+      return ruleList
+    }
+    /**
+     * 渲染表单
+     */
+    const renderFrom = (): VNode => {
+      return (
+        <van-form
+          label-align={'top'}
+          disabled={formConfCopy.disabled}
+          label-width={`${formConfCopy.labelWidth}px`}
+          ref={formRef}
+          onSubmit={submitForm}
+        >
+          {renderFormItem(formConfCopy.fields)}
+          {renderSlot(slots, 'default', {
+            fields: formConfCopy.fields,
+            formRef: formRef.value,
+            formData: props.formData
+          })}
+        </van-form>
+      )
+    }
+    /**
+     * 渲染表单项
+     */
+    const renderFormItem = (elementList: FormField[]): VNode[] => {
+      return elementList.map((element: FormField) => {
+        const layout = layouts[element.name] || layouts[element.type]
+        if (layout) {
+          return layout(element)
+        }
+        throw new Error(`未找到${element?.type}类型的布局`)
+      })
+    }
+    /**
+     * 提交表单
+     */
+    const submitForm = () => {
+      return new Promise<Recordable>((resolve, reject) => {
+        if (!formRef.value) {
+          reject()
+          return
+        }
+        formRef.value
+          ?.validate()
+          .then(() => {
+            emit('submit', props.formData)
+            resolve(props.formData)
+          })
+          .catch(() => {
+            reject()
+          })
+      })
+    }
+    /**
+     * 重置表单
+     */
+    const resetForm = () => {
+      if (!formRef.value) return
+      Object.keys(props.formData).forEach((key) => {
+        trigger(key)
+      })
+      emit('reset', props.formData)
+    }
+    return {
+      renderFrom,
+      submitForm,
+      resetForm
+    }
+  },
+  render() {
+    return this.renderFrom()
+  }
+})

+ 119 - 0
src/components/FormParser/type.ts

@@ -0,0 +1,119 @@
+import type { Field, Options } from '@/components/Render/type'
+import type { FieldRule } from 'vant'
+
+/**
+ * 表单配置
+ */
+export interface FormConf {
+  labelPosition: 'left' | 'right' | 'top'
+  labelWidth: number
+  gutter: number
+  disabled: boolean
+  fields: FormField[]
+  rules: Rule[]
+  dataSource: DataSource[]
+}
+
+/**
+ * 表单字段
+ */
+export interface FormField extends Field {
+  // id
+  id: string
+  // 类型
+  type: 'formItem' | 'container'
+  // 默认值
+  value?: any
+  // 标题
+  label: string
+  // 只读
+  readonly?: boolean
+  // 必填
+  required?: boolean
+  // 隐藏
+  hidden: boolean
+  // 正则校验
+  rules?: FieldRule[]
+  // 子字段
+  children?: FormField[]
+}
+
+/**
+ * 数据源
+ */
+export interface DataSource {
+  id: string
+  name: string
+  url: string
+  method: 'get' | 'post' | 'put' | 'delete'
+  init: boolean
+  params: Recordable
+  headers: Recordable
+  data: Recordable
+  dataKey: string
+  dataValue: string
+  dataPath: string
+}
+
+export interface Rule {
+  // 条件
+  condition: FilterGroup
+  // 执行
+  actions: Action[]
+}
+
+// 触发事件
+export type TriggerEvent =
+  | 'show' // 显示
+  | 'hide' // 隐藏
+  | 'required' // 必填
+  | 'notRequired' // 非必填
+  | 'enabled' // 启用
+  | 'readonly' // 只读
+  | 'set' // 设置值
+  | 'source' // 触发数据源
+
+export interface Action {
+  field: string
+  trigger: TriggerEvent
+  value: any
+}
+
+export type Callback = (options: Options[]) => void
+
+export type FilterOperator =
+  | 'eq' // 等于
+  | 'ne' // 不等于
+  | 'gt' // 大于
+  | 'ge' // 大于或等于
+  | 'lt' // 小于
+  | 'le' // 小于或等于
+  | 'bt' // 介于
+  | 'nb' // 不介于
+  | 'ul' // 为空
+  | 'nu' // 不为空
+  | 'lk' // 包含
+  | 'nl' // 不包含
+  | 'in' // 在...之中
+  | 'ni' // 不在...之中
+
+/**
+ * 条件
+ */
+export interface FilterCondition {
+  // 筛选字段
+  field?: string
+  // 条件运算符
+  operator: FilterOperator
+  // 筛选值
+  value?: any
+}
+
+/**
+ * 筛选组
+ */
+export interface FilterGroup {
+  operator: 'or' | 'and'
+  conditions: FilterCondition[]
+  groups?: FilterGroup[]
+}

+ 176 - 0
src/components/FormParser/useForm.ts

@@ -0,0 +1,176 @@
+import type { Callback, DataSource, FormConf, FormField } from './type'
+import http from '@/api'
+import type { Options } from '@/components/Render/type'
+import useMatch from './useMatch'
+import { showFailToast } from 'vant'
+
+const useForm = (formConf: FormConf, formData: Recordable) => {
+  const observerList = ref<Callback[]>([])
+  const allFields = computed<FormField[]>(() => {
+    const fields: FormField[] = []
+    const getFields = (fieldList: FormField[]) => {
+      fieldList.forEach((field) => {
+        fields.push(field)
+        if (field.children) {
+          getFields(field.children)
+        }
+      })
+    }
+    getFields(formConf.fields)
+    return fields
+  })
+  const _formData = toRef(formData)
+  const { matchesGroup } = useMatch(formData)
+  provide('formParser', { formData: _formData })
+
+  const addObserver = (callback: Callback) => {
+    observerList.value.push(callback)
+  }
+
+  const delObserver = (callback: Callback) => {
+    observerList.value = observerList.value.filter((item) => item !== callback)
+  }
+
+  const trigger = (prop: string) => {
+    formConf.rules.forEach((rule) => {
+      const { condition, actions } = rule
+      const { conditions } = condition
+      const isProp = conditions.some((rule) => rule.field === prop)
+      if (isProp) {
+        const isMatch = matchesGroup(condition)
+        actions.forEach((action) => {
+          const { field, trigger, value } = action
+          const target = allFields.value.find((f) => f.id === field)
+          if (target) {
+            if (trigger === 'show') {
+              target.hidden = !isMatch
+            } else if (trigger === 'hide') {
+              target.hidden = isMatch
+            } else if (trigger === 'required') {
+              target.required = isMatch
+            } else if (trigger === 'notRequired') {
+              target.required = !isMatch
+            } else if (trigger === 'readonly') {
+              target.readonly = isMatch
+            } else if (trigger === 'enabled') {
+              target.readonly = !isMatch
+            }
+          }
+          if (trigger === 'set') {
+            if (!isMatch) return
+            if (value === 'empty') {
+              formData[field] = Array.isArray(formData[field]) ? [] : null
+            } else if (value.startsWith('{') && value.endsWith('}')) {
+              const key = value.slice(1, -1)
+              formData[field] = formData[key]
+            } else {
+              formData[field] = value
+            }
+          } else if (trigger === 'source') {
+            if (isMatch) {
+              const source = formConf.dataSource.find((item) => item.id === value)
+              if (source) {
+                triggerDataSource(source)
+              }
+            }
+          }
+        })
+      }
+    })
+  }
+
+  /**
+   * 触发数据源
+   * @param source
+   */
+  const triggerDataSource = async (source: DataSource) => {
+    const params: Recordable = {}
+    Object.keys(source.params).forEach((key) => {
+      const value: string = source.params[key]
+      if (/\{[^{}]+}/g.test(value)) {
+        const prop = value.slice(1, -1)
+        params[key] = formData[prop]
+      }
+    })
+    const headers: Recordable = {}
+    Object.keys(source.headers).forEach((key) => {
+      const value: string = source.headers[key]
+      if (/\{[^{}]+}/g.test(value)) {
+        const prop = value.slice(1, -1)
+        headers[key] = formData[prop]
+      }
+    })
+    const data: Recordable = {}
+    Object.keys(source.data).forEach((key) => {
+      const value: string = source.data[key]
+      if (/\{[^{}]+}/g.test(value)) {
+        const prop = value.slice(1, -1)
+        data[key] = formData[prop]
+      }
+    })
+    const res = await http.request<any>({
+      url: source.url,
+      method: source.method,
+      params: params,
+      headers: headers,
+      data: data
+    })
+    if (res.success) {
+      let { data } = res
+      const { dataKey, dataValue, dataPath } = source
+      if (dataPath) {
+        data = dataPath.split('.').reduce((pre, item) => pre[item], data)
+      }
+      if (Array.isArray(data)) {
+        const options: Options[] = data.map((item) => {
+          return {
+            label: item[dataKey],
+            value: item[dataValue]
+          }
+        })
+        observerList.value.forEach((callback) => {
+          callback(options)
+        })
+      }
+    } else {
+      showFailToast(res.message)
+    }
+  }
+
+  const initFormData = (elementList: FormField[]) => {
+    elementList.forEach((field) => {
+      if (field.type === 'formItem') {
+        if (field.value !== undefined) {
+          if (formData[field.id] === undefined) {
+            formData[field.id] = field.value
+          }
+        }
+      }
+      if (field.children) {
+        initFormData(field.children)
+      }
+    })
+  }
+  onMounted(() => {
+    formConf.dataSource.forEach((source) => {
+      if (source.init) {
+        triggerDataSource(source)
+      }
+    })
+  })
+  // 初始化表单数据
+  initFormData(formConf.fields)
+  Object.keys(formData).forEach((key) => {
+    trigger(key)
+  })
+  return {
+    observerList,
+    addObserver,
+    delObserver,
+    initFormData,
+    trigger,
+    triggerDataSource
+  }
+}
+
+export default useForm

+ 99 - 0
src/components/FormParser/useMatch.ts

@@ -0,0 +1,99 @@
+import { isEqual, isNumber } from 'lodash-es'
+import type { FilterCondition, FilterGroup } from './type'
+
+const useMatch = (formData: Recordable) => {
+  /**
+   * 匹配组
+   * @param group
+   */
+  const matchesGroup = (group: FilterGroup): boolean => {
+    const { conditions, groups, operator } = group
+    if (operator === 'or') {
+      const result = conditions.some((item) => matchesCondition(item))
+      if (result) {
+        return true
+      } else if (groups) {
+        return groups.some((item) => matchesGroup(item))
+      } else {
+        return false
+      }
+    } else {
+      const result = conditions.every((item) => matchesCondition(item))
+      if (result) {
+        if (groups) {
+          return groups.every((item) => matchesGroup(item))
+        } else {
+          return true
+        }
+      }
+    }
+    return false
+  }
+
+  /**
+   * 匹配条件
+   * @param condition
+   */
+  const matchesCondition = (condition: FilterCondition): boolean => {
+    const { field, operator, value } = condition
+    if (field) {
+      const val = formData[field]
+      switch (operator) {
+        case 'eq':
+          return isEqual(val, value)
+        case 'ne':
+          return !isEqual(val, value)
+        case 'gt':
+          if (isNumber(val)) {
+            return val > value
+          }
+          return new Date(val).getTime() > new Date(value).getTime()
+        case 'ge':
+          if (isNumber(val)) {
+            return val >= value
+          }
+          return new Date(val).getTime() >= new Date(value).getTime()
+        case 'lt':
+          if (isNumber(val)) {
+            return val < value
+          }
+          return new Date(val).getTime() < new Date(value).getTime()
+        case 'le':
+          if (isNumber(val)) {
+            return val <= value
+          }
+          return new Date(val).getTime() <= new Date(value).getTime()
+        case 'nb':
+          if (isNumber(val)) {
+            return val < value[0] || val > value[1]
+          }
+          return (
+            new Date(val).getTime() < new Date(value[0]).getTime() ||
+            new Date(val).getTime() > new Date(value[1]).getTime()
+          )
+        case 'ul':
+          return val === null || val === ''
+        case 'nu':
+          return val !== null && val !== ''
+        case 'lk':
+          return val.includes(value)
+        case 'nl':
+          return !val.includes(value)
+        case 'in':
+          return value.includes(val)
+        case 'ni':
+          return !value.includes(val)
+        default:
+          return false
+      }
+    }
+    return false
+  }
+
+  return {
+    matchesGroup,
+    matchesCondition
+  }
+}
+
+export default useMatch

+ 42 - 0
src/components/OrgSelector/OrgTag.vue

@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import { type Dept, getById } from '@/api/modules/system/dept'
+
+const $props = withDefaults(
+  defineProps<{
+    id: string
+    type?: 'primary' | 'success' | 'danger' | 'warning'
+    closable?: boolean
+  }>(),
+  {
+    closable: false
+  }
+)
+const org = ref<Dept>()
+onMounted(async () => {
+  if ($props.id) {
+    const res = await getById($props.id)
+    if (res.success) {
+      org.value = res.data
+    }
+  }
+})
+</script>
+
+<template>
+  <van-tag round :closeable="closable">
+    <div class="flex-center gap4px">
+      <van-image class="h-5 w-5" round>
+        <template v-slot:loading>
+          {{ (org?.name || id).charAt(0) }}
+        </template>
+      </van-image>
+      <span>{{ org?.name || id }}</span>
+    </div>
+  </van-tag>
+</template>
+
+<style scoped lang="less">
+.van-tag {
+  padding: 1px 3px 1px 1px;
+}
+</style>

+ 59 - 0
src/components/OrgSelector/index.vue

@@ -0,0 +1,59 @@
+<script setup lang="ts">
+import OrgPicker from '@/components/UserSelector/UserPicker.vue'
+import { useCustomFieldValue } from '@vant/use'
+import OrgTag from './OrgTag.vue'
+
+const props = withDefaults(
+  defineProps<{
+    placeholder?: string
+    multiple?: boolean
+    disabled?: boolean
+  }>(),
+  {
+    multiple: false,
+    disabled: false,
+    placeholder: '请选择组织'
+  }
+)
+const value = defineModel<string | string[] | undefined>({ required: true })
+useCustomFieldValue(() => value.value)
+const orgPickerRef = ref<InstanceType<typeof OrgPicker>>()
+const valueArr = computed<string[]>(() => {
+  if (!value.value) return []
+  return Array.isArray(value.value) ? value.value : [value.value]
+})
+const onClose = (id: string) => {
+  if (!value.value) return
+  if (props.multiple && Array.isArray(value.value)) {
+    value.value.splice(value.value.indexOf(id), 1)
+  } else {
+    value.value = undefined
+  }
+}
+const openOrgPicker = () => {
+  orgPickerRef.value?.openPopup()
+}
+</script>
+
+<template>
+  <div class="flex-items-center flex-wrap gap7px" v-bind="$attrs">
+    <slot>
+      <van-button icon="plus" size="mini" class="org-but" @click="openOrgPicker" />
+    </slot>
+    <OrgTag v-for="item in valueArr" :key="item" :id="item" closable @close="onClose(item)" />
+    <span v-show="!value || value.length === 0" class="placeholder">
+      {{ placeholder }}
+    </span>
+    <OrgPicker ref="orgPickerRef" obj="org" :multiple="multiple" v-bind="$attrs" v-model="value" />
+  </div>
+</template>
+
+<style scoped lang="less">
+.org-but {
+  border-style: dashed;
+}
+.placeholder {
+  color: var(--van-text-color);
+  font-size: var(--van-font-size-md);
+}
+</style>

+ 94 - 0
src/components/Render/components/Calculation.vue

@@ -0,0 +1,94 @@
+<script setup lang="ts">
+import dayjs from 'dayjs'
+const props = withDefaults(
+  defineProps<{
+    expression: (string | Recordable)[]
+    precision?: number
+    _tModel?: string
+    rowIndex?: number
+  }>(),
+  {
+    precision: 2
+  }
+)
+const data = defineModel<number | undefined>({ required: true })
+const { formData } = inject<{
+  formData: Recordable
+}>('formParser', { formData: {} })
+watchEffect(() => {
+  if (formData && props.expression.length) {
+    const getFormVal = (vModel: string) => {
+      try {
+        if (vModel.indexOf('.') > -1) {
+          let [tabelVModel, cmpVModel] = vModel.split('.')
+          const val = getFormDataVal(tabelVModel)
+          if (
+            props._tModel &&
+            props._tModel === tabelVModel &&
+            props.rowIndex != null &&
+            props.rowIndex >= 0
+          ) {
+            return val[props.rowIndex][cmpVModel]
+          }
+          return val.reduce((sum: number, c: Recordable) => (c[cmpVModel] || 0) + sum, 0)
+        }
+        return getFormDataVal(vModel)
+      } catch (e) {
+        return 0
+      }
+    }
+    const temp = props.expression.map((t) => (typeof t === 'object' ? getFormVal(t.vModel) : t))
+    temp.forEach((t, i) => {
+      if (t === '×') {
+        temp[i] = '*'
+      }
+      if (t === '÷') {
+        temp[i] = '/'
+      }
+    })
+    try {
+      const val = eval(temp.join(''))
+      if (val !== undefined) {
+        data.value = Number(val.toFixed(props.precision))
+      }
+    } catch (e) {
+      console.log(e)
+    }
+  }
+})
+const getFormDataVal = (vModel: string) => {
+  if (formData) {
+    const val = formData[vModel]
+    if (Array.isArray(val) && val.length > 0 && typeof val[0] !== 'object') {
+      return val.reduce((acc, currentValue) => {
+        if (typeof currentValue === 'string') {
+          currentValue = /^([01]\d|2[0-3]):([0-5]\d)(:[0-5]\d)?$/.test(currentValue)
+            ? `1970-01-01 ${currentValue}`
+            : currentValue
+          acc = /^([01]\d|2[0-3]):([0-5]\d)(:[0-5]\d)?$/.test(acc) ? `1970-01-01 ${acc}` : acc
+          return (dayjs(currentValue).valueOf() || 0) - (dayjs(acc).valueOf() || 0)
+        }
+        return currentValue - acc
+      })
+    } else if (typeof val === 'string') {
+      const currentValue = /^([01]\d|2[0-3]):([0-5]\d)(:[0-5]\d)?$/.test(val)
+        ? `1970-01-01 ${val}`
+        : val
+      return dayjs(currentValue).valueOf() || 0
+    } else {
+      return formData[vModel] || 0
+    }
+  }
+  return 0
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-stepper v-bind="$attrs" v-model="data" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 17 - 0
src/components/Render/components/Checkbox.vue

@@ -0,0 +1,17 @@
+<script setup lang="ts">
+const value = defineModel<unknown[]>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-checkbox-group v-model="value" v-bind="$attrs">
+        <template v-for="(value, name) in $slots" #[name]="scope">
+          <slot :name="name" v-bind="scope || {}"></slot>
+        </template>
+      </van-checkbox-group>
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 11 - 0
src/components/Render/components/Col.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts"></script>
+
+<template>
+  <van-col v-bind="$attrs">
+    <template v-for="(value, name) in $slots" #[name]="scope">
+      <slot :name="name" v-bind="scope || {}"></slot>
+    </template>
+  </van-col>
+</template>
+
+<style scoped lang="less"></style>

+ 46 - 0
src/components/Render/components/Custom.vue

@@ -0,0 +1,46 @@
+<script setup lang="ts">
+import { mergeProps, type Ref, useAttrs } from 'vue'
+
+const props = defineProps<{
+  path?: string
+  params?: { key: string; value: string }[]
+}>()
+const { formData } = inject<{
+  formData: Ref<Recordable>
+}>('formParser', { formData: ref({}) })
+const modules: Recordable<() => Promise<any>> = import.meta.glob('@/views/**/*.vue')
+let asyncComponent: any = undefined
+watchEffect(() => {
+  const val = modules[`/src/views/${props.path}.vue`]
+  if (val) {
+    asyncComponent = defineAsyncComponent(val)
+  } else {
+    asyncComponent = undefined
+  }
+})
+const customRef = ref()
+const attrs = useAttrs()
+const params = computed(() => {
+  const val =
+    props.params?.reduce((pre, cur) => {
+      if (cur.key) {
+        pre[cur.key] = cur.value
+      }
+      return pre
+    }, {} as Recordable) || {}
+  const obj = JSON.parse(JSON.stringify(val))
+  return mergeProps(obj, attrs)
+})
+</script>
+
+<template>
+  <component
+    v-if="asyncComponent"
+    ref="customRef"
+    :variables="formData"
+    :is="asyncComponent"
+    v-bind="params"
+  />
+</template>
+
+<style scoped lang="less"></style>

+ 93 - 0
src/components/Render/components/Date.vue

@@ -0,0 +1,93 @@
+<script setup lang="ts">
+import type { DatePickerColumnType, TimePickerColumnType } from 'vant'
+
+const props = defineProps<{
+  valueFormat: string
+  placeholder: string
+}>()
+const value = defineModel<string>({ required: true })
+const currentDate = ref<string[]>([])
+const currentTime = ref<string[]>([])
+const dateMaps: Recordable<DatePickerColumnType[]> = {
+  YYYY: ['year'],
+  'YYYY-MM': ['year', 'month'],
+  'YYYY-MM-DD': ['year', 'month', 'day'],
+  'YYYY-MM-DD HH:mm': ['year', 'month', 'day'],
+  'YYYY-MM-DD HH:mm:ss': ['year', 'month', 'day']
+}
+const timeMaps: Recordable<TimePickerColumnType[]> = {
+  'YYYY-MM-DD HH:mm': ['hour', 'minute'],
+  'YYYY-MM-DD HH:mm:ss': ['hour', 'minute', 'second']
+}
+const dateColumnsType = ref<DatePickerColumnType[]>(dateMaps[props.valueFormat])
+const timeColumnsType = ref<TimePickerColumnType[]>(timeMaps[props.valueFormat])
+const showPicker = ref(false)
+const onConfirm = () => {
+  value.value = currentDate.value.join('-')
+  if (currentTime.value.length) {
+    value.value = `${currentDate.value.join('-')} ${currentTime.value.join(':')}`
+  }
+  showPicker.value = false
+}
+const onCancel = () => {
+  showPicker.value = false
+}
+const openPopup = () => {
+  const date = value.value ? new Date(value.value) : new Date()
+  currentDate.value = []
+  currentTime.value = []
+  if (dateColumnsType.value?.includes('year')) {
+    currentDate.value.push(String(date.getFullYear()))
+  }
+  if (dateColumnsType.value?.includes('month')) {
+    currentDate.value.push(String(date.getMonth() + 1))
+  }
+  if (dateColumnsType.value?.includes('day')) {
+    currentDate.value.push(String(date.getDate()))
+  }
+  if (timeColumnsType.value?.includes('hour')) {
+    currentTime.value.push(String(date.getHours()).padStart(2, '0'))
+  }
+  if (timeColumnsType.value?.includes('minute')) {
+    currentTime.value.push(String(date.getMinutes()).padStart(2, '0'))
+  }
+  if (timeColumnsType.value?.includes('second')) {
+    currentTime.value.push(String(date.getSeconds()).padStart(2, '0'))
+  }
+  showPicker.value = true
+}
+</script>
+
+<template>
+  <van-field
+    v-bind="$attrs"
+    v-model="value"
+    :placeholder="placeholder"
+    is-link
+    readonly
+    @click="openPopup"
+  />
+  <van-popup v-model:show="showPicker" v-bind="$attrs" position="bottom">
+    <van-picker-group
+      v-if="timeColumnsType"
+      :title="placeholder"
+      :tabs="['选择日期', '选择时间']"
+      next-step-text="下一步"
+      @confirm="onConfirm"
+      @cancel="onCancel"
+    >
+      <van-date-picker :columns-type="dateColumnsType" v-model="currentDate" v-bind="$attrs" />
+      <van-time-picker :columns-type="timeColumnsType" v-model="currentTime" v-bind="$attrs" />
+    </van-picker-group>
+    <van-date-picker
+      v-else
+      v-model="currentDate"
+      @confirm="onConfirm"
+      @cancel="onCancel"
+      :columns-type="dateColumnsType"
+      v-bind="$attrs"
+    />
+  </van-popup>
+</template>
+
+<style scoped lang="less"></style>

+ 86 - 0
src/components/Render/components/DateRange.vue

@@ -0,0 +1,86 @@
+<script setup lang="ts">
+const props = defineProps<{
+  valueFormat: string
+}>()
+const value = defineModel<string[]>({ required: true })
+let minDate = new Date(2020, 0, 1)
+let maxDate = new Date(2025, 5, 1)
+const startDate = ref<string[]>([])
+const startTime = ref<string[]>([])
+const endDate = ref<string[]>([])
+const endTime = ref<string[]>([])
+const showPicker = ref(false)
+const hasTime = computed(() => {
+  return props.valueFormat.includes('HH:mm') || props.valueFormat.includes('HH:mm:ss')
+})
+const tabs = computed(() => {
+  if (hasTime.value) {
+    return ['开始日期', '开始时间', '结束日期', '结束时间']
+  } else {
+    return ['开始日期', '结束日期']
+  }
+})
+const onConfirm = () => {
+  let start = startDate.value.join('-')
+  let end = endDate.value.join('-')
+  if (hasTime.value) {
+    start = start + ' ' + startTime.value.join(':')
+    end = end + ' ' + endTime.value.join(':')
+  }
+  value.value = [start, end]
+  showPicker.value = false
+}
+const onCancel = () => {
+  showPicker.value = false
+}
+const openPopup = () => {
+  if (value.value?.length) {
+    const sDate = new Date(value.value[0])
+    const eDate = new Date(value.value[1])
+    startDate.value = [
+      String(sDate.getFullYear()),
+      String(sDate.getMonth() + 1).padStart(2, '0'),
+      String(sDate.getDate()).padStart(2, '0')
+    ]
+    startTime.value = [
+      String(sDate.getHours()).padStart(2, '0'),
+      String(sDate.getMinutes()).padStart(2, '0')
+    ]
+    endDate.value = [
+      String(eDate.getFullYear()),
+      String(eDate.getMonth() + 1).padStart(2, '0'),
+      String(eDate.getDate()).padStart(2, '0')
+    ]
+    endTime.value = [
+      String(eDate.getHours()).padStart(2, '0'),
+      String(eDate.getMinutes()).padStart(2, '0')
+    ]
+  }
+  showPicker.value = true
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs" :modelValue="value?.join(' - ')" is-link readonly @click="openPopup" />
+  <van-popup v-model:show="showPicker" v-bind="$attrs" position="bottom">
+    <van-picker-group
+      next-step-text="下一步"
+      @confirm="onConfirm"
+      @cancel="onCancel"
+      :tabs="tabs"
+      v-bind="$attrs"
+    >
+      <van-date-picker
+        v-model="startDate"
+        :min-date="minDate"
+        :max-date="maxDate"
+        v-bind="$attrs"
+      />
+      <van-time-picker v-model="startTime" v-if="hasTime" />
+      <van-date-picker v-model="endDate" :min-date="minDate" :max-date="maxDate" v-bind="$attrs" />
+      <van-time-picker v-model="endTime" v-if="hasTime" />
+    </van-picker-group>
+  </van-popup>
+</template>
+
+<style scoped lang="less"></style>

+ 13 - 0
src/components/Render/components/Divider.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts">
+defineProps<{
+  content: string
+}>()
+</script>
+
+<template>
+  <van-divider v-bind="$attrs">
+    {{ content }}
+  </van-divider>
+</template>
+
+<style scoped lang="less"></style>

+ 155 - 0
src/components/Render/components/DynamicTable.vue

@@ -0,0 +1,155 @@
+<script setup lang="ts">
+import type { FormField } from '@/components/FormParser/type'
+import type { FieldRule } from 'vant'
+
+const data = defineModel<Recordable[]>({ required: true })
+const props = withDefaults(
+  defineProps<{
+    columns: FormField[]
+    _vModel_: string
+    readonly?: boolean
+    showAdd?: boolean
+    showDel?: boolean
+    disabled?: boolean
+    minSize?: number
+    maxSize?: number
+    maxHeight?: number
+  }>(),
+  {
+    readonly: false,
+    showAdd: true,
+    showDel: true,
+    disabled: false,
+    minSize: 1,
+    maxSize: 10,
+    maxHeight: 300
+  }
+)
+const disabled = computed(() => props.disabled)
+onMounted(() => {
+  nextTick(() => {
+    if (props.minSize > 0) {
+      while (data.value.length < props.minSize) {
+        addRow()
+      }
+    }
+  })
+})
+const delRow = (index: number) => {
+  if (props.readonly) {
+    return
+  }
+  data.value.splice(index, 1)
+}
+const addRow = () => {
+  if (props.readonly) {
+    return
+  }
+  const row = props.columns
+    .filter((e) => e.type === 'formItem')
+    .reduce((acc, cur) => {
+      acc[cur.id] = cur.value
+      return acc
+    }, {} as Recordable)
+  data.value.push(row)
+}
+/**
+ * 构建校验
+ * @param field
+ */
+const buildRule = (field: FormField) => {
+  const { props, rules } = field
+  let ruleList: FieldRule[] = []
+  if (Array.isArray(rules)) {
+    ruleList.push(
+      ...rules.map((rule) => {
+        return {
+          pattern: rule.pattern && new RegExp(rule.pattern),
+          message: `请输入正确的${rule.message}`
+        }
+      })
+    )
+  }
+  if (field.required !== undefined) {
+    const required: FieldRule = {
+      required: field.required || false,
+      message: props.placeholder
+    }
+    if (Array.isArray(field.value)) {
+      required.message = `请至少选择一个${field.label}`
+      required.trigger = 'onChange'
+    }
+    required.message === undefined && (required.message = `${field.label}不能为空`)
+    ruleList.push(required)
+  }
+  return ruleList
+}
+</script>
+
+<template>
+  <div v-for="(item, index) in data" :key="index" class="w-full">
+    <div class="row-action">
+      <span> 明细 ({{ index + 1 }}) </span>
+      <button
+        v-if="showDel"
+        type="button"
+        class="icon-delete"
+        @click="delRow(index)"
+        :disabled="data?.length <= minSize || disabled"
+      >
+        <van-icon name="delete" />
+      </button>
+    </div>
+    <Render
+      v-for="col in columns"
+      :key="col.id"
+      :model-value="data[index][col.id]"
+      :disabled="disabled"
+      :rules="buildRule(col)"
+      @update:modelValue="
+        (val) => {
+          if (readonly) return
+          data[index][col.id] = val
+        }
+      "
+      :field="col"
+    />
+  </div>
+  <div class="row-action" v-if="showAdd">
+    <button
+      size="small"
+      class="icon-add"
+      @click="addRow"
+      :disabled="data?.length >= maxSize || disabled"
+    >
+      <van-icon name="plus" />
+      添加明细
+    </button>
+  </div>
+</template>
+
+<style scoped lang="less">
+.row-action {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 10px;
+  height: 30px;
+  background-color: var(--van-active-color);
+  margin: 0 calc(0 - var(--van-padding-md));
+}
+
+.icon-add {
+  width: 100%;
+  text-align: center;
+  color: var(--van-primary-color);
+  font-size: var(--van-font-size-md);
+  background-color: transparent;
+  border: none;
+}
+.icon-delete {
+  font-size: var(--van-font-size-md);
+  background-color: transparent;
+  border: none;
+}
+</style>

+ 65 - 0
src/components/Render/components/FileUpload.vue

@@ -0,0 +1,65 @@
+<script setup lang="ts">
+import { showToast, type UploaderFileListItem } from 'vant'
+import { upload } from '@/api/modules/file/file'
+
+const props = defineProps<{
+  modelValue: string[] | null
+  maxSize: number
+}>()
+const emits = defineEmits(['update:modelValue'])
+const value = computed<UploaderFileListItem[]>({
+  get() {
+    return (
+      props.modelValue?.map((e) => {
+        return {
+          url: e,
+          isImage: false,
+          status: 'done'
+        }
+      }) || []
+    )
+  },
+  set(val) {
+    emits('update:modelValue', val)
+  }
+})
+const onOversize = () => {
+  showToast(`文件大小不能超过 ${props.maxSize / 1024 / 1024}mb`)
+}
+const beforeRead = (
+  file: File | File[]
+): boolean | Promise<File | File[] | undefined> | undefined => {
+  const all = []
+  if (Array.isArray(file)) {
+    const list = file.map((f) => upload(f))
+    all.push(...list)
+  } else {
+    all.push(upload(file))
+  }
+  Promise.all(all).then((res) => {
+    const fileList = res.map((r) => `/api${r.data.url}`)
+    if (Array.isArray(props.modelValue)) {
+      emits('update:modelValue', [...props.modelValue, ...fileList])
+    } else {
+      emits('update:modelValue', fileList)
+    }
+  })
+  return true
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-uploader
+        :model-value="value"
+        :max-size="maxSize"
+        v-bind="$attrs"
+        @oversize="onOversize"
+        :before-read="beforeRead"
+      />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 5 - 0
src/components/Render/components/Iframe.vue

@@ -0,0 +1,5 @@
+<script setup lang="ts"></script>
+
+<template>网页</template>
+
+<style scoped lang="less"></style>

+ 65 - 0
src/components/Render/components/ImageUpload.vue

@@ -0,0 +1,65 @@
+<script setup lang="ts">
+import { showToast, type UploaderFileListItem } from 'vant'
+import { upload } from '@/api/modules/file/file'
+
+const props = defineProps<{
+  modelValue: string[] | null
+  maxSize: number
+}>()
+const emits = defineEmits(['update:modelValue'])
+const value = computed<UploaderFileListItem[]>({
+  get() {
+    return (
+      props.modelValue?.map((e) => {
+        return {
+          url: e,
+          isImage: true,
+          status: 'done'
+        }
+      }) || []
+    )
+  },
+  set(val) {
+    emits('update:modelValue', val)
+  }
+})
+const onOversize = () => {
+  showToast(`文件大小不能超过 ${props.maxSize / 1024 / 1024}mb`)
+}
+const beforeRead = (
+  file: File | File[]
+): boolean | Promise<File | File[] | undefined> | undefined => {
+  const all = []
+  if (Array.isArray(file)) {
+    const list = file.map((f) => upload(f))
+    all.push(...list)
+  } else {
+    all.push(upload(file))
+  }
+  Promise.all(all).then((res) => {
+    const fileList = res.map((r) => `/api${r.data.url}`)
+    if (Array.isArray(props.modelValue)) {
+      emits('update:modelValue', [...props.modelValue, ...fileList])
+    } else {
+      emits('update:modelValue', fileList)
+    }
+  })
+  return true
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-uploader
+        :model-value="value"
+        :max-size="maxSize"
+        v-bind="$attrs"
+        @oversize="onOversize"
+        :before-read="beforeRead"
+      />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 9 - 0
src/components/Render/components/Input.vue

@@ -0,0 +1,9 @@
+<script setup lang="ts">
+const value = defineModel<string>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs" v-model="value" />
+</template>
+
+<style scoped lang="less"></style>

+ 13 - 0
src/components/Render/components/Numner.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts">
+const value = defineModel<number | undefined>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-stepper v-bind="$attrs" v-model="value" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 14 - 0
src/components/Render/components/OrgSelector.vue

@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import OrgSelector from '@/components/OrgSelector/index.vue'
+const value = defineModel<string | string[] | undefined>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs" readonly>
+    <template #input>
+      <OrgSelector v-model="value" v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 5 - 0
src/components/Render/components/ProcessSelector.vue

@@ -0,0 +1,5 @@
+<script setup lang="ts"></script>
+
+<template>流程选择</template>
+
+<style scoped lang="less"></style>

+ 15 - 0
src/components/Render/components/Radio.vue

@@ -0,0 +1,15 @@
+<script setup lang="ts"></script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-radio-group v-bind="$attrs">
+        <template v-for="(value, name) in $slots" #[name]="scope">
+          <slot :name="name" v-bind="scope || {}"></slot>
+        </template>
+      </van-radio-group>
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 17 - 0
src/components/Render/components/Rate.vue

@@ -0,0 +1,17 @@
+<script setup lang="ts">
+defineProps<{
+  count: number
+  allowHalf: boolean
+}>()
+const value = defineModel<number>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-rate v-model="value" :count="count" :allowHalf="allowHalf" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 14 - 0
src/components/Render/components/RoleSelector.vue

@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import RoleSelector from '@/components/RoleSelector/index.vue'
+const value = defineModel<string | string[] | undefined>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs" readonly>
+    <template #input>
+      <RoleSelector v-model="value" v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 11 - 0
src/components/Render/components/Row.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts"></script>
+
+<template>
+  <van-row v-bind="$attrs">
+    <template v-for="(value, name) in $slots" #[name]="scope">
+      <slot :name="name" v-bind="scope || {}"></slot>
+    </template>
+  </van-row>
+</template>
+
+<style scoped lang="less"></style>

+ 95 - 0
src/components/Render/components/Select.vue

@@ -0,0 +1,95 @@
+<script setup lang="ts">
+import type { CheckboxInstance, PickerOption } from 'vant'
+
+const props = defineProps<{
+  title: string
+  columns: PickerOption[]
+  multiple: boolean
+}>()
+const showPicker = ref(false)
+const checkboxRefs = ref<(CheckboxInstance | null)[]>([])
+const value = defineModel<any>({ required: true })
+const checkboxValue = ref<any[]>([])
+const showValue = computed(
+  () =>
+    props.columns
+      .filter((item) =>
+        (Array.isArray(value.value) ? value.value : [value.value]).includes(item.value)
+      )
+      .map((item) => item.text)
+      .join('、') || ''
+)
+const openPopup = () => {
+  checkboxValue.value = Array.isArray(value.value) ? value.value : [value.value]
+  showPicker.value = true
+}
+const onConfirm = ({ selectedValues }: { selectedValues: string[] }) => {
+  if (props.multiple) {
+    value.value = selectedValues
+  } else {
+    value.value = selectedValues.join(',')
+  }
+  showPicker.value = false
+}
+const toggle = (index: number) => {
+  checkboxRefs.value[index]?.toggle()
+}
+</script>
+
+<template>
+  <van-field v-model="showValue" v-bind="$attrs" is-link readonly @click="openPopup" />
+  <van-popup v-model:show="showPicker" round v-bind="$attrs" position="bottom">
+    <div v-if="multiple">
+      <div class="van-picker__toolbar">
+        <button class="van-picker__cancel van-haptics-feedback" @click="showPicker = false">
+          取消
+        </button>
+        <div class="van-picker__title van-ellipsis">{{ title }}</div>
+        <button
+          class="van-picker__confirm van-haptics-feedback"
+          @click="onConfirm({ selectedValues: checkboxValue })"
+        >
+          确认
+        </button>
+      </div>
+      <div class="van-picker__columns picker-checkbox">
+        <van-checkbox-group v-model="checkboxValue" shape="square" v-bind="$attrs">
+          <van-cell-group>
+            <van-cell
+              v-for="(item, index) in columns"
+              clickable
+              :key="item.value"
+              :title="item.text"
+              @click="toggle(index)"
+            >
+              <template #right-icon>
+                <van-checkbox
+                  :name="item.value"
+                  :ref="(el) => (checkboxRefs[index] = el as CheckboxInstance)"
+                  @click.stop
+                />
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </van-checkbox-group>
+      </div>
+    </div>
+    <van-picker
+      v-else
+      :title="title"
+      v-bind="$attrs"
+      :columns="columns"
+      @confirm="onConfirm"
+      @cancel="showPicker = false"
+    />
+  </van-popup>
+</template>
+
+<style scoped lang="less">
+.picker-checkbox {
+  width: 100%;
+  overflow-y: auto;
+  min-height: 264px;
+  max-height: 400px;
+}
+</style>

+ 14 - 0
src/components/Render/components/Signature.vue

@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import Signature from '@/components/Signature/index.vue'
+const value = defineModel<string>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <Signature v-model="value" v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 13 - 0
src/components/Render/components/Slider.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts">
+const value = defineModel<number>({ required: true })
+</script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-slider v-model="value" v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 11 - 0
src/components/Render/components/Stepper.vue

@@ -0,0 +1,11 @@
+<script setup lang="ts"></script>
+
+<template>
+  <van-field v-bind="$attrs">
+    <template #input>
+      <van-stepper v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 18 - 0
src/components/Render/components/Switch.vue

@@ -0,0 +1,18 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue'
+
+const value = defineModel<any>({ required: true })
+defineProps<{
+  style: CSSProperties
+}>()
+</script>
+
+<template>
+  <van-field v-bind="$attrs" :style="style">
+    <template #input>
+      <van-switch v-model="value" v-bind="$attrs" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped lang="less"></style>

+ 15 - 0
src/components/Render/components/Tab.vue

@@ -0,0 +1,15 @@
+<script setup lang="ts">
+defineProps<{
+  label: string
+}>()
+</script>
+
+<template>
+  <van-tab :title="label" v-bind="$attrs">
+    <template v-for="(value, name) in $slots" #[name]="scope">
+      <slot :name="name" v-bind="scope || {}"></slot>
+    </template>
+  </van-tab>
+</template>
+
+<style scoped lang="less"></style>

+ 16 - 0
src/components/Render/components/Tabs.vue

@@ -0,0 +1,16 @@
+<script setup lang="ts">
+defineOptions({
+  inheritAttrs: false
+})
+const active = defineModel<string>({ required: true })
+</script>
+
+<template>
+  <van-tabs v-model:active="active">
+    <template v-for="(value, name) in $slots" #[name]="scope">
+      <slot :name="name" v-bind="scope || {}"></slot>
+    </template>
+  </van-tabs>
+</template>
+
+<style scoped lang="less"></style>

+ 7 - 0
src/components/Render/components/Textarea.vue

@@ -0,0 +1,7 @@
+<script setup lang="ts"></script>
+
+<template>
+  <van-field v-bind="$attrs" />
+</template>
+
+<style scoped lang="less"></style>

+ 61 - 0
src/components/Render/components/Time.vue

@@ -0,0 +1,61 @@
+<script setup lang="ts">
+import type { TimePickerColumnType } from 'vant'
+
+const props = defineProps<{
+  valueFormat: string
+  columnsType: TimePickerColumnType[]
+}>()
+const value = defineModel<string>({ required: true })
+const showPicker = ref(false)
+const currentTime = ref<string[]>([])
+const openPopup = () => {
+  const date = new Date()
+  if (value.value) {
+    const [hour, minute, second] = value.value.split(':')
+    if (hour) {
+      date.setHours(Number(hour))
+    }
+    if (minute) {
+      date.setMinutes(Number(minute))
+    }
+    if (second) {
+      date.setSeconds(Number(second))
+    }
+  }
+  currentTime.value = []
+  if (props.columnsType) {
+    if (props.columnsType.includes('hour')) {
+      currentTime.value.push(String(date.getHours()).padStart(2, '0'))
+    }
+    if (props.columnsType.includes('minute')) {
+      currentTime.value.push(String(date.getMinutes()).padStart(2, '0'))
+    }
+    if (props.columnsType.includes('second')) {
+      currentTime.value.push(String(date.getSeconds()).padStart(2, '0'))
+    }
+  }
+  showPicker.value = true
+}
+const onConfirm = ({ selectedValues }: { selectedValues: string[] }) => {
+  value.value = selectedValues.join(':')
+  showPicker.value = false
+}
+const onCancel = () => {
+  showPicker.value = false
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs" v-model="value" is-link readonly @click="openPopup" />
+  <van-popup v-model:show="showPicker" v-bind="$attrs" position="bottom">
+    <van-time-picker
+      :columns-type="columnsType"
+      v-model="currentTime"
+      @confirm="onConfirm"
+      @cancel="onCancel"
+      v-bind="$attrs"
+    />
+  </van-popup>
+</template>
+
+<style scoped lang="less"></style>

+ 38 - 0
src/components/Render/components/TimeRange.vue

@@ -0,0 +1,38 @@
+<script setup lang="ts">
+const value = defineModel<string[]>({ required: true })
+const startTime = ref<string[]>([])
+const endTime = ref<string[]>([])
+const showPicker = ref(false)
+const onConfirm = () => {
+  value.value = [startTime.value.join(':'), endTime.value.join(':')]
+  showPicker.value = false
+}
+const onCancel = () => {
+  showPicker.value = false
+}
+const openPopup = () => {
+  if (value.value.length) {
+    startTime.value = value.value[0].split(':')
+    endTime.value = value.value[1].split(':')
+  }
+  showPicker.value = true
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs" :modelValue="value.join(' - ')" is-link readonly @click="openPopup" />
+  <van-popup v-model:show="showPicker" v-bind="$attrs" position="bottom">
+    <van-picker-group
+      next-step-text="下一步"
+      @confirm="onConfirm"
+      @cancel="onCancel"
+      :tabs="['开始时间', '结束时间']"
+      v-bind="$attrs"
+    >
+      <van-time-picker v-model="startTime" v-bind="$attrs" />
+      <van-time-picker v-model="endTime" v-bind="$attrs" />
+    </van-picker-group>
+  </van-popup>
+</template>
+
+<style scoped lang="less"></style>

+ 40 - 0
src/components/Render/components/UserSelector.vue

@@ -0,0 +1,40 @@
+<script setup lang="ts">
+import { getOptions } from '@/api/modules/system/user'
+import UserPicker from '@/components/UserSelector/UserPicker.vue'
+import { useCustomFieldValue } from '@vant/use'
+
+type ModelValue = string[] | undefined
+const value = defineModel<ModelValue>({ required: true })
+useCustomFieldValue(() => value.value)
+const userPickerRef = ref<InstanceType<typeof UserPicker>>()
+const showValue = ref('')
+watchEffect(async () => {
+  if (value.value && value.value.length > 0) {
+    const array = Array.isArray(value.value) ? value.value : [value.value]
+    const res = await getOptions(array)
+    if (res.success) {
+      const options = res.data
+      if (options.length > 3) {
+        showValue.value = `${options
+          .map((e) => e.name)
+          .slice(0, 3)
+          .join('、')}...`
+      } else {
+        showValue.value = options.map((e) => e.name).join('、')
+      }
+    }
+  } else {
+    showValue.value = ''
+  }
+})
+const openPopup = () => {
+  userPickerRef.value?.openPopup()
+}
+</script>
+
+<template>
+  <van-field v-bind="$attrs" @click="openPopup" v-model="showValue" readonly is-link />
+  <UserPicker ref="userPickerRef" v-bind="$attrs" v-model="value" />
+</template>
+
+<style scoped lang="less"></style>

+ 40 - 0
src/components/Render/components/index.ts

@@ -0,0 +1,40 @@
+import type { Component } from 'vue'
+
+/**
+ * 定义要渲染的组件(推荐异步加载),如果是全局注册可以不用引入
+ */
+const asyncComponents: Record<string, Component> = {
+  Input: defineAsyncComponent(() => import('./Input.vue')),
+  Textarea: defineAsyncComponent(() => import('./Textarea.vue')),
+  Number: defineAsyncComponent(() => import('./Numner.vue')),
+  Select: defineAsyncComponent(() => import('./Select.vue')),
+  Radio: defineAsyncComponent(() => import('./Radio.vue')),
+  Checkbox: defineAsyncComponent(() => import('./Checkbox.vue')),
+  Date: defineAsyncComponent(() => import('./Date.vue')),
+  DateRange: defineAsyncComponent(() => import('./DateRange.vue')),
+  Time: defineAsyncComponent(() => import('./Time.vue')),
+  TimeRange: defineAsyncComponent(() => import('./TimeRange.vue')),
+  Switch: defineAsyncComponent(() => import('./Switch.vue')),
+  Slider: defineAsyncComponent(() => import('./Slider.vue')),
+  Rate: defineAsyncComponent(() => import('./Rate.vue')),
+  FileUpload: defineAsyncComponent(() => import('./FileUpload.vue')),
+  ImageUpload: defineAsyncComponent(() => import('./ImageUpload.vue')),
+  Signature: defineAsyncComponent(() => import('./Signature.vue')),
+  Divider: defineAsyncComponent(() => import('./Divider.vue')),
+  UserSelector: defineAsyncComponent(() => import('./UserSelector.vue')),
+  RoleSelector: defineAsyncComponent(() => import('./RoleSelector.vue')),
+  OrgSelector: defineAsyncComponent(() => import('./OrgSelector.vue')),
+  Calculation: defineAsyncComponent(() => import('./Calculation.vue')),
+  Row: defineAsyncComponent(() => import('./Row.vue')),
+  // Col: defineAsyncComponent(() => import('./Col.vue')),
+  DynamicTable: defineAsyncComponent(() => import('./DynamicTable.vue')),
+  ProcessSelector: defineAsyncComponent(() => import('./ProcessSelector.vue')),
+  Custom: defineAsyncComponent(() => import('./Custom.vue')),
+  Tabs: defineAsyncComponent(() => import('./Tabs.vue')),
+  Tab: defineAsyncComponent(() => import('./Tab.vue')),
+  Collapse: defineAsyncComponent(() => import('vant/es').then(({ Collapse }) => Collapse)),
+  CollapseItem: defineAsyncComponent(() =>
+    import('vant/es').then(({ CollapseItem }) => CollapseItem)
+  )
+}
+export default asyncComponents

+ 6 - 0
src/components/Render/hooks/CollapseItem.tsx

@@ -0,0 +1,6 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useCollapseItem = function (field: FormField) {
+  // @ts-ignore
+  delete field.label
+}

+ 13 - 0
src/components/Render/hooks/Date.tsx

@@ -0,0 +1,13 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useDate = function (field: FormField) {
+  const { props } = field
+  const { type } = props
+  if (type === 'date') {
+    delete props.type
+  }
+  if (props.placeholder) {
+    props.title = props.placeholder
+  }
+  delete props.style
+}

+ 8 - 0
src/components/Render/hooks/DateRange.tsx

@@ -0,0 +1,8 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useDateRange = function (field: FormField) {
+  const { props } = field
+  props.placeholder = `请选择${field.label}`
+  props.title = props.placeholder
+  delete props.style
+}

+ 28 - 0
src/components/Render/hooks/FileUpload.tsx

@@ -0,0 +1,28 @@
+import type { FormField } from '@/components/FormParser/type'
+import { showToast } from 'vant'
+
+export const useFileUpload = function (field: FormField) {
+  const { props } = field
+  if (props.limit > 1) {
+    props.multiple = true
+    props.maxCount = props.limit
+    delete props.limit
+  }
+  if (props.size > 0) {
+    props.maxSize = props.size * 1024 * 1024
+    delete props.size
+  }
+  props.onOversize = () => {
+    showToast(`文件大小不能超过 ${props.size}mb`)
+  }
+  props.beforeRead = (file: File) => {
+    if (props.accept) {
+      if (props.accept.includes(file.type)) {
+        return true
+      } else {
+        showToast(`文件类型错误,请上传${props.accept}格式文件`)
+        return false
+      }
+    }
+  }
+}

+ 29 - 0
src/components/Render/hooks/ImageUpload.tsx

@@ -0,0 +1,29 @@
+import type { FormField } from '@/components/FormParser/type'
+import { showToast } from 'vant'
+
+export const useImageUpload = function (field: FormField) {
+  const { props } = field
+  props.accept = 'image/*'
+  if (props.limit > 1) {
+    props.multiple = true
+    props.maxCount = props.limit
+    delete props.limit
+  }
+  if (props.size > 0) {
+    props.maxSize = props.size * 1024 * 1024
+    delete props.size
+  }
+  props.onOversize = () => {
+    showToast(`文件大小不能超过 ${props.size}mb`)
+  }
+  props.beforeRead = (file: File) => {
+    if (props.accept) {
+      if (props.accept.includes(file.type)) {
+        return true
+      } else {
+        showToast(`文件类型错误,请上传${props.accept}格式文件`)
+        return false
+      }
+    }
+  }
+}

+ 9 - 0
src/components/Render/hooks/Rate.tsx

@@ -0,0 +1,9 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useRate = function (field: FormField) {
+  const { props } = field
+  if (props.max) {
+    props.count = props.max
+    delete props.max
+  }
+}

+ 18 - 0
src/components/Render/hooks/Select.tsx

@@ -0,0 +1,18 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useSelect = function (field: FormField) {
+  const { props } = field
+  if (props.placeholder) {
+    props.title = props.placeholder
+  }
+  if (Array.isArray(props.options)) {
+    props.columns = props.options.map((opt) => {
+      return {
+        text: opt.label,
+        value: opt.value
+      }
+    })
+    delete props.options
+  }
+  delete props.style
+}

+ 10 - 0
src/components/Render/hooks/Textarea.tsx

@@ -0,0 +1,10 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useTextarea = function (field: FormField) {
+  const { props } = field
+  if (props.autosize) {
+    const { minRows } = props.autosize
+    props.rows = minRows
+    props.autosize = true
+  }
+}

+ 18 - 0
src/components/Render/hooks/Time.tsx

@@ -0,0 +1,18 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useTime = function (field: FormField) {
+  const { props } = field
+  const { valueFormat } = props
+  if (valueFormat) {
+    const maps: Recordable<string[]> = {
+      'HH:mm': ['hour', 'minute'],
+      'HH:mm:ss': ['hour', 'minute', 'second']
+    }
+    props.columnsType = maps[valueFormat]
+    if (props.isRange) {
+      field.name = 'TimeRange'
+      props.placeholder = `请选择${field.label}`
+    }
+  }
+  delete props.style
+}

+ 13 - 0
src/components/Render/hooks/TimeRange.tsx

@@ -0,0 +1,13 @@
+import type { FormField } from '@/components/FormParser/type'
+
+export const useTimeRange = function (field: FormField) {
+  const { props } = field
+  const { valueFormat } = props
+  props.placeholder = `请选择${field.label}`
+  const maps: Recordable<string[]> = {
+    'HH:mm': ['hour', 'minute'],
+    'HH:mm:ss': ['hour', 'minute', 'second']
+  }
+  props.columnsType = maps[valueFormat]
+  delete props.style
+}

+ 10 - 0
src/components/Render/hooks/index.ts

@@ -0,0 +1,10 @@
+const slots = import.meta.glob('./*.tsx', { eager: true })
+const hooks: Record<string, any> = {}
+Object.keys(slots).forEach((key: string) => {
+  const obj: any = slots[key]
+  if (obj) {
+    const name = key.replace('./', '').replace('.tsx', '')
+    hooks[name] = obj
+  }
+})
+export default hooks

+ 107 - 0
src/components/Render/index.tsx

@@ -0,0 +1,107 @@
+import type { Field, Options } from './type'
+import type { PropType } from 'vue'
+import { mergeProps } from 'vue'
+import { cloneDeep } from 'lodash-es'
+import asyncComponents from './components'
+import componentChild from './slots'
+import hooks from './hooks'
+import type { Callback, FormField } from '@/components/FormParser/type'
+
+export default defineComponent({
+  props: {
+    modelValue: {
+      type: [String, Number, Boolean, Array, Object],
+      required: false
+    },
+    field: {
+      type: Object as PropType<FormField>,
+      required: true
+    }
+  },
+  emits: [
+    'update:modelValue',
+    'input',
+    'change',
+    'addObserver',
+    'delObserver',
+    'mounted',
+    'unmount'
+  ],
+  components: {
+    ...asyncComponents
+  },
+  setup(props, { emit }) {
+    const callback: Callback = (options: Options[]) => {
+      props.field.props.options = options
+    }
+    onMounted(() => {
+      emit('mounted')
+      const { dataType, dataSource } = props.field.props
+      if (dataType === 'dynamic' && dataSource) {
+        emit('addObserver', callback)
+      }
+    })
+    onBeforeUnmount(() => {
+      emit('unmount')
+      const { dataType, dataSource } = props.field.props
+      if (dataType === 'dynamic' && dataSource) {
+        emit('delObserver', callback)
+      }
+    })
+    const buildDataObject = (fieldClone: FormField) => {
+      // 赋值属性
+      const { props: nestedProps, ...rest } = fieldClone
+      const dataObject: Recordable = { ...rest, ...nestedProps }
+      /*dataObject.id = fieldClone.name
+      dataObject.name = fieldClone.id*/
+      // 双向绑定
+      if (props.modelValue !== undefined) {
+        dataObject.modelValue = props.modelValue
+        dataObject['onUpdate:modelValue'] = (value: any) => {
+          emit('update:modelValue', value)
+          emit('input', value)
+          emit('change', value)
+        }
+      }
+      // 删除无用属性
+      delete dataObject.options
+      delete dataObject.dataType
+      delete dataObject.dataSource
+      return dataObject
+    }
+    const buildSlots = (fieldClone: Field) => {
+      let slots: Recordable<(...args: any) => void> = {}
+      const childObjs = componentChild[fieldClone.name]
+      if (childObjs) {
+        Object.keys(childObjs).forEach((key) => {
+          const childFunc = childObjs[key]
+          slots[key] = (...args: any) => childFunc(fieldClone, ...args)
+        })
+      }
+      return slots
+    }
+    const useHooks = (fieldClone: Field) => {
+      const childObjs = hooks[fieldClone.name]
+      if (childObjs) {
+        Object.keys(childObjs).forEach((key) => {
+          const mixinFunc = childObjs[key]
+          mixinFunc.call(this, fieldClone)
+        })
+      }
+    }
+    return {
+      buildDataObject,
+      useHooks,
+      buildSlots
+    }
+  },
+  render() {
+    const fieldClone: FormField = cloneDeep(this.field)
+    const slots = this.buildSlots(fieldClone)
+    this.useHooks(fieldClone)
+    const dataObject = this.buildDataObject(fieldClone)
+    const componentName = fieldClone.props.componentName || fieldClone.name
+    const eleComponent = resolveComponent(componentName)
+    return h(eleComponent, mergeProps(dataObject, this.$attrs), { ...this.$slots, ...slots })
+  }
+})

+ 13 - 0
src/components/Render/slots/Checkbox.tsx

@@ -0,0 +1,13 @@
+import type { Field, Options } from '../type'
+
+export default {
+  default: (field: Field) => {
+    return field.props.options?.map((item: Options) => {
+      return (
+        <van-checkbox name={item.value} shape="square" disabled={item.disabled}>
+          {item.label}
+        </van-checkbox>
+      )
+    })
+  }
+}

+ 13 - 0
src/components/Render/slots/Radio.tsx

@@ -0,0 +1,13 @@
+import type { Field, Options } from '../type'
+
+export default {
+  default: (field: Field) => {
+    return field.props.options?.map((item: Options) => {
+      return (
+        <van-radio name={item.value} disabled={item.disabled}>
+          {item.label}
+        </van-radio>
+      )
+    })
+  }
+}

+ 11 - 0
src/components/Render/slots/index.ts

@@ -0,0 +1,11 @@
+const slots = import.meta.glob('./*.tsx', { eager: true })
+const componentChild: Record<string, any> = {}
+Object.keys(slots).forEach((key: string) => {
+  const obj: any = slots[key]
+  if (obj) {
+    const name = key.replace('./', '').replace('.tsx', '')
+    componentChild[name] = obj.default
+  }
+})
+
+export default componentChild

+ 33 - 0
src/components/Render/type.ts

@@ -0,0 +1,33 @@
+import type { CSSProperties } from 'vue'
+
+/**
+ * 字段
+ */
+export interface Field {
+  name: string
+  icon?: string
+  props: Props
+}
+
+/**
+ * 组件属性
+ */
+export interface Props extends Recordable {
+  key?: string | number
+  // 样式
+  style?: CSSProperties
+  // 类名
+  class?: string[]
+  // 选项
+  options?: Options[]
+  // 数据类型
+  dataType?: 'static' | 'dynamic'
+  // 数据源
+  dataSource?: string
+}
+
+export interface Options {
+  value: string | number
+  label: string
+  disabled?: boolean
+}

+ 41 - 0
src/components/RoleSelector/RoleName.vue

@@ -0,0 +1,41 @@
+<script setup lang="ts">
+import { type Role, getById } from '@/api/modules/system/role'
+const props = withDefaults(
+  defineProps<{
+    id: string
+    showLabel?: boolean
+  }>(),
+  {
+    showLabel: true
+  }
+)
+const role = ref<Role>()
+onMounted(async () => {
+  if (!props.id) {
+    throw new Error('id is required')
+  }
+  const res = await getById(props.id)
+  if (res.success) {
+    role.value = res.data
+  }
+})
+</script>
+
+<template>
+  <div class="flex-items-center">
+    <van-image class="h-6 w-6" round fit="cover">
+      <template v-slot:loading>
+        <van-icon name="friends-o" />
+      </template>
+    </van-image>
+    <span class="role-name" v-show="showLabel">
+      {{ role?.name }}
+    </span>
+  </div>
+</template>
+
+<style scoped lang="less">
+.van-image + .role-name {
+  margin-left: 8px;
+}
+</style>

+ 211 - 0
src/components/RoleSelector/RolePicker.vue

@@ -0,0 +1,211 @@
+<script setup lang="ts">
+import { getList, type Role, type RoleQuery } from '@/api/modules/system/role'
+import RoleName from './RoleName.vue'
+
+const props = withDefaults(
+  defineProps<{
+    multiple?: boolean
+    max?: number
+  }>(),
+  {
+    multiple: false,
+    max: 100
+  }
+)
+
+const value = defineModel<string | string[] | undefined>({ required: true })
+const temValue = ref<string[]>([])
+const roleOptions = ref<Role[]>([])
+const total = ref(0)
+const loading = ref(false)
+const finished = ref(false)
+const refreshing = ref(false)
+const showSelected = ref(false)
+const showRight = ref(false)
+const isCheckAll = ref(false)
+const isIndeterminate = computed(() => {
+  isCheckAll.value =
+    roleOptions.value.length > 0 &&
+    roleOptions.value.every((e) => temValue.value?.includes(e.id) || false)
+  if (isCheckAll.value) {
+    return false
+  }
+  return roleOptions.value.some((e) => temValue.value?.includes(e.id) || false)
+})
+const checkboxRefs = ref<any[]>([])
+const queryForm = ref<RoleQuery>({
+  name: undefined,
+  page: 0,
+  limit: 10
+})
+const onBack = () => {
+  showRight.value = false
+}
+const openPopup = () => {
+  if (value.value) {
+    temValue.value = Array.isArray(value.value) ? value.value : [value.value]
+  } else {
+    temValue.value = []
+  }
+  showRight.value = true
+}
+const confirm = () => {
+  showRight.value = false
+  if (props.multiple) {
+    value.value = temValue.value
+  } else {
+    if (temValue.value.length) {
+      value.value = temValue.value?.[0]
+    } else {
+      value.value = undefined
+    }
+  }
+}
+
+const checkAllChange = (val: boolean) => {
+  temValue.value = val ? roleOptions.value.map((e) => e.id) : []
+}
+const toggle = (index: number, role: Role) => {
+  checkboxRefs.value[index].toggle()
+  if (!props.multiple) {
+    temValue.value = temValue.value.filter((e) => e === role.id)
+  }
+}
+const onRefresh = () => {
+  refreshing.value = true
+  finished.value = false
+  loading.value = true
+  onLoad()
+}
+const onLoad = () => {
+  queryForm.value.page++
+  if (refreshing.value) {
+    queryForm.value.page = 1
+    roleOptions.value = []
+    refreshing.value = false
+  }
+  getList(queryForm.value)
+    .then((res) => {
+      if (res.success) {
+        roleOptions.value.push(...res.data.rows)
+        total.value = res.data.total
+      }
+    })
+    .finally(() => {
+      loading.value = false
+      finished.value = roleOptions.value.length >= total.value
+    })
+}
+const onClose = () => {
+  queryForm.value.name = undefined
+}
+defineExpose({
+  openPopup
+})
+</script>
+
+<template>
+  <van-popup
+    v-bind="$attrs"
+    v-model:show="showRight"
+    position="right"
+    teleport="body"
+    @close="onClose"
+    :style="{
+      width: '100%',
+      maxWidth: '600px',
+      height: '100%',
+      background: 'var(--van-background)'
+    }"
+  >
+    <van-nav-bar placeholder clickable fixed left-arrow title="角色选择" @click-left="onBack" />
+    <van-form label-align="left">
+      <van-search
+        v-model="queryForm.name"
+        placeholder="请输入角色关键词"
+        @update:modelValue="onRefresh"
+        @search="onRefresh"
+      />
+    </van-form>
+    <van-cell :border="false" v-show="multiple">
+      <template #title>
+        <van-checkbox
+          v-model="isCheckAll"
+          :indeterminate="isIndeterminate"
+          @change="checkAllChange"
+        >
+          全选
+        </van-checkbox>
+      </template>
+    </van-cell>
+    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+      <van-list
+        v-model:loading="loading"
+        :finished="finished"
+        finished-text="没有更多了"
+        @load="onLoad"
+      >
+        <van-checkbox-group v-model="temValue">
+          <van-cell-group>
+            <van-cell
+              v-for="(item, index) in roleOptions"
+              clickable
+              :key="item.id"
+              :title="item.name"
+              @click="toggle(index, item)"
+            >
+              <template #title>
+                <div class="flex-items-center">
+                  <van-checkbox
+                    :name="item.id"
+                    :ref="(el) => (checkboxRefs[index] = el)"
+                    @click.stop
+                    mr2
+                  />
+                  <van-icon name="friends-o" mr2 />
+                  {{ item.name }}
+                </div>
+              </template>
+            </van-cell>
+          </van-cell-group>
+        </van-checkbox-group>
+      </van-list>
+    </van-pull-refresh>
+
+    <van-action-bar>
+      <div class="flex-between w-full p3">
+        <div v-if="temValue?.length" class="flex-1 color-primary" @click="showSelected = true">
+          已选择:({{ temValue?.length || 0 }})
+          <van-icon name="arrow" />
+        </div>
+        <div v-else>最多选择{{ multiple ? max : 1 }}项</div>
+        <van-button type="primary" size="small" @click="confirm"
+          >确定 ({{ temValue?.length || 0 }}/{{ multiple ? max : 1 }})
+        </van-button>
+      </div>
+    </van-action-bar>
+    <van-action-sheet
+      v-model:show="showSelected"
+      class="min-h-400px"
+      :title="`已选择(${temValue?.length})`"
+    >
+      <van-cell-group>
+        <van-cell v-for="(item, index) in temValue" :key="item">
+          <template #title>
+            <RoleName :id="item" />
+          </template>
+          <template #right-icon>
+            <van-button
+              type="warning"
+              @click="temValue?.splice(index, 1)"
+              icon="delete"
+              size="mini"
+            ></van-button>
+          </template>
+        </van-cell>
+      </van-cell-group>
+    </van-action-sheet>
+  </van-popup>
+</template>
+
+<style scoped lang="less"></style>

+ 42 - 0
src/components/RoleSelector/RoleTag.vue

@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import { getById, type Role } from '@/api/modules/system/role'
+
+const $props = withDefaults(
+  defineProps<{
+    roleId: string
+    type?: 'primary' | 'success' | 'danger' | 'warning'
+    closable?: boolean
+  }>(),
+  {
+    closable: false
+  }
+)
+const role = ref<Role>()
+onMounted(async () => {
+  if ($props.roleId) {
+    const res = await getById($props.roleId)
+    if (res.success) {
+      role.value = res.data
+    }
+  }
+})
+</script>
+
+<template>
+  <van-tag round :closeable="closable">
+    <div class="flex-center gap4px">
+      <van-image class="h-5 w-5" round>
+        <template v-slot:loading>
+          {{ (role?.name || roleId).charAt(0) }}
+        </template>
+      </van-image>
+      <span>{{ role?.name || roleId }}</span>
+    </div>
+  </van-tag>
+</template>
+
+<style scoped lang="less">
+.van-tag {
+  padding: 1px 3px 1px 1px;
+}
+</style>

+ 58 - 0
src/components/RoleSelector/index.vue

@@ -0,0 +1,58 @@
+<script setup lang="ts">
+import RolePicker from './RolePicker.vue'
+import { useCustomFieldValue } from '@vant/use'
+
+const props = withDefaults(
+  defineProps<{
+    placeholder?: string
+    multiple?: boolean
+    disabled?: boolean
+  }>(),
+  {
+    multiple: false,
+    disabled: false,
+    placeholder: '请选择角色'
+  }
+)
+const value = defineModel<string | string[] | undefined>({ required: true })
+useCustomFieldValue(() => value.value)
+const rolePickerRef = ref<InstanceType<typeof RolePicker>>()
+const valueArr = computed<string[]>(() => {
+  if (!value.value) return []
+  return Array.isArray(value.value) ? value.value : [value.value]
+})
+const onClose = (roleId: string) => {
+  if (!value.value) return
+  if (props.multiple && Array.isArray(value.value)) {
+    value.value.splice(value.value.indexOf(roleId), 1)
+  } else {
+    value.value = undefined
+  }
+}
+const openRolePicker = () => {
+  rolePickerRef.value?.openPopup()
+}
+</script>
+
+<template>
+  <div class="flex-items-center flex-wrap gap7px" v-bind="$attrs">
+    <slot>
+      <van-button icon="plus" size="mini" class="role-but" @click="openRolePicker" />
+    </slot>
+    <RoleTag v-for="item in valueArr" :key="item" :roleId="item" closable @close="onClose(item)" />
+    <span v-show="!value || value.length === 0" class="placeholder">
+      {{ placeholder }}
+    </span>
+    <RolePicker ref="rolePickerRef" :multiple="multiple" v-bind="$attrs" v-model="value" />
+  </div>
+</template>
+
+<style scoped lang="less">
+.role-but {
+  border-style: dashed;
+}
+.placeholder {
+  color: var(--van-text-color);
+  font-size: var(--van-font-size-md);
+}
+</style>

+ 199 - 0
src/components/Signature/index.vue

@@ -0,0 +1,199 @@
+<script setup lang="ts">
+import { useVModel } from '@vueuse/core'
+import { VPerfectSignature } from 'v-perfect-signature'
+import type { CSSProperties } from 'vue'
+import { upload } from '@/api/modules/file/file'
+import { useCustomFieldValue } from '@vant/use'
+
+interface SignatureProps {
+  size?: string
+  penColor?: string
+  backgroundColor?: string
+  lineWidth?: number
+  clearable?: boolean
+  disabled?: boolean
+  readonly?: boolean
+  modelValue: string | null
+  style?: CSSProperties
+}
+
+const $props = withDefaults(defineProps<SignatureProps>(), {
+  size: '',
+  lineWidth: 12,
+  disabled: false,
+  readonly: false,
+  clearable: true
+})
+const disabled = computed(() => {
+  return $props.disabled || $props.readonly
+})
+
+const $emit = defineEmits<{
+  (e: 'update:modelValue', modelValue: string): void
+}>()
+const value = useVModel($props, 'modelValue', $emit)
+useCustomFieldValue(() => value.value)
+const signaturePadRef = ref<InstanceType<typeof VPerfectSignature>>()
+const showRight = ref(false)
+const timestamp = ref(0)
+const strokeOptions = {
+  size: $props.lineWidth,
+  thinning: 0.75,
+  smoothing: 0.5,
+  streamline: 0.5
+}
+const handleClick = () => {
+  !disabled.value && (showRight.value = true)
+}
+const handleClear = () => {
+  !disabled.value && (value.value = null)
+}
+/**
+ * dataUrl转file
+ * @param dataUrl
+ * @param filename
+ */
+const dataURLtoFile = (dataUrl: string, filename: string) => {
+  const arr = dataUrl.split(',')
+  const byteString = atob(arr[1])
+  let n = byteString.length
+  const u8arr = new Uint8Array(n)
+  while (n--) {
+    u8arr[n] = byteString.charCodeAt(n)
+  }
+  return new File([u8arr], filename, { type: 'image/png' })
+}
+const handelConfirm = () => {
+  if (signaturePadRef.value?.isEmpty()) {
+    value.value = null
+  } else {
+    const dataUrl = signaturePadRef.value?.toDataURL()
+    if (dataUrl) {
+      const file = dataURLtoFile(dataUrl, 'signature.png')
+      upload(file).then((res) => {
+        if (res.message) {
+          value.value = `/api${res.data.url}`
+        } else {
+          // ElMessage.error(res.message)
+        }
+      })
+    }
+  }
+  showRight.value = false
+}
+const onOpen = () => {
+  timestamp.value = Date.now()
+  nextTick(() => {
+    if (value.value) {
+      signaturePadRef.value?.fromDataURL(value.value)
+    }
+  })
+}
+</script>
+
+<template>
+  <div class="handwritten-name-wrap" :style="style" v-bind="$attrs">
+    <div :class="['img-wrap', { 'is-disabled': disabled }]" @click="handleClick">
+      <template v-if="value">
+        <van-icon
+          name="clear"
+          class="van-icon-clear"
+          v-show="clearable && !disabled"
+          @click.stop="handleClear"
+        />
+        <img :src="value" alt="" />
+      </template>
+      <span v-else> 点击签名 </span>
+    </div>
+  </div>
+  <van-popup
+    v-bind="$attrs"
+    v-model:show="showRight"
+    position="right"
+    @opened="onOpen"
+    :style="{
+      width: '100%',
+      maxWidth: '600px',
+      height: '100%'
+    }"
+  >
+    <div class="flex-col h-full">
+      <van-nav-bar
+        placeholder
+        clickable
+        fixed
+        left-arrow
+        title="签名面板"
+        right-text="确认"
+        @click-right="handelConfirm"
+        @click-left="showRight = false"
+      />
+      <VPerfectSignature
+        class="perfect-signature flex-1"
+        :key="timestamp"
+        :pen-color="penColor"
+        :background-color="backgroundColor"
+        :stroke-options="strokeOptions"
+        ref="signaturePadRef"
+      />
+    </div>
+  </van-popup>
+</template>
+
+<style scoped lang="less">
+.perfect-signature {
+  border: 1px dashed var(--van-border-color);
+  width: 100% !important;
+}
+
+.handwritten-name-wrap {
+  .is-disabled {
+    // background-color: var(--el-disabled-bg-color) !important;
+    border: 1px dashed var(--van-border-color) !important;
+    color: var(--van-text-color) !important;
+
+    &:hover,
+    &:focus {
+      cursor: not-allowed !important;
+    }
+  }
+
+  .img-wrap {
+    height: 70px;
+    width: 100%;
+    max-width: 170px;
+    position: relative;
+    border: 1px dashed var(--van-border-color);
+
+    span {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      font-size: 14px;
+      color: var(--van-text-color-2);
+    }
+
+    img {
+      width: 100%;
+      height: 100%;
+      position: relative;
+      z-index: 1;
+    }
+
+    .van-icon-clear {
+      position: absolute;
+      top: 0;
+      right: 0;
+      z-index: 2;
+      color: var(--van-text-color);
+      font-size: 20px;
+      cursor: pointer;
+
+      &:hover {
+        color: var(--van-primary-color);
+      }
+    }
+  }
+}
+</style>

+ 34 - 0
src/components/SvgIcon/index.vue

@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue'
+
+const props = withDefaults(
+  defineProps<{
+    name: string
+    prefix?: string
+    color?: string
+    size?: number
+  }>(),
+  {
+    prefix: 'icon',
+    size: 16
+  }
+)
+
+const symbolId = computed(() => `#${props.prefix}-${props.name}`)
+const fill = computed(() => (props.color ? props.color : 'currentColor'))
+const getStyle = computed((): CSSProperties => {
+  const s = `${`${props.size}`.replace('px', '')}px`
+  return {
+    width: s,
+    height: s
+  }
+})
+</script>
+
+<template>
+  <svg :style="getStyle" aria-hidden="true">
+    <use :xlink:href="symbolId" :fill="fill" />
+  </svg>
+</template>
+
+<style scoped lang="less"></style>

+ 57 - 0
src/components/Timeline/TimelineItem.vue

@@ -0,0 +1,57 @@
+<script setup lang="ts"></script>
+
+<template>
+  <li class="van-timeline-item">
+    <div class="van-timeline-item__tail" />
+    <div class="van-timeline-item__icon">
+      <slot name="icon"></slot>
+    </div>
+    <div class="van-timeline-item__wrapper">
+      <slot />
+    </div>
+  </li>
+</template>
+
+<style scoped lang="less">
+.van-timeline-item {
+  position: relative;
+  padding-bottom: 20px;
+  &:last-child {
+    .van-timeline-item__tail {
+      display: none;
+    }
+  }
+
+  .van-timeline-item__tail {
+    position: absolute;
+    left: 4px;
+    height: 100%;
+    border-left: 2px solid var(--van-border-color);
+  }
+  .van-timeline-item__icon {
+    border-radius: 50%;
+    border: 1px solid var(--van-border-color);
+    padding: 0 !important;
+    background-color: var(--van-background);
+    color: var(--van-gray-5);
+
+    position: absolute;
+    top: 5.5px;
+    left: 5px;
+    height: auto;
+    width: auto;
+    margin-top: 0;
+    line-height: 0;
+    text-align: center;
+    transform: translate(-50%, -50%);
+  }
+  .van-timeline-item__wrapper {
+    position: relative;
+    // padding-left: 28px;
+    top: -2px;
+    margin: 0 0 0 26px;
+    word-break: break-word;
+    font-size: var(--van-font-size-xs);
+  }
+}
+</style>

+ 13 - 0
src/components/Timeline/index.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts"></script>
+
+<template>
+  <ul class="van-timeline">
+    <slot />
+  </ul>
+</template>
+
+<style scoped lang="less">
+.van-timeline {
+  list-style: none;
+}
+</style>

+ 41 - 0
src/components/UserSelector/OrgName.vue

@@ -0,0 +1,41 @@
+<script setup lang="ts">
+import { type Dept, getById } from '@/api/modules/system/dept'
+const props = withDefaults(
+  defineProps<{
+    id: string
+    showLabel?: boolean
+  }>(),
+  {
+    showLabel: true
+  }
+)
+const dept = ref<Dept>()
+onMounted(async () => {
+  if (!props.id) {
+    throw new Error('id is required')
+  }
+  const res = await getById(props.id)
+  if (res.success) {
+    dept.value = res.data
+  }
+})
+</script>
+
+<template>
+  <div class="flex-items-center">
+    <van-image class="h-6 w-6" round fit="cover">
+      <template v-slot:loading>
+        <van-icon name="cluster" />
+      </template>
+    </van-image>
+    <span class="org-name" v-show="showLabel">
+      {{ dept?.name }}
+    </span>
+  </div>
+</template>
+
+<style scoped lang="less">
+.van-image + .org-name {
+  margin-left: 8px;
+}
+</style>

+ 45 - 0
src/components/UserSelector/UserName.vue

@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import type { User } from '@/api/modules/system/user'
+import { useUserCacheStore } from '@/stores/modules/userCache'
+
+const $props = withDefaults(
+  defineProps<{
+    username: string
+    showAvatar?: boolean
+    showLabel?: boolean
+  }>(),
+  {
+    showAvatar: true,
+    showLabel: true
+  }
+)
+const user = ref<User>()
+const avatar = computed(() => user.value?.avatar)
+const userCacheStore = useUserCacheStore()
+onMounted(async () => {
+  if (!$props.username) {
+    throw new Error('username is required')
+  }
+  const val = await userCacheStore.getUser($props.username)
+  if (val) {
+    user.value = val
+  }
+})
+</script>
+
+<template>
+  <div class="flex-items-center">
+    <van-image class="h-6 w-6" round fit="cover" :src="avatar">
+      {{ (user?.name || username).charAt(0) }}
+    </van-image>
+    <span class="avatar-name" v-show="showLabel">
+      {{ user?.name || username }}
+    </span>
+  </div>
+</template>
+
+<style scoped lang="less">
+.van-image + .avatar-name {
+  margin-left: 8px;
+}
+</style>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio