Browse Source

更新网页

qw 4 months ago
commit
0ad4a57808
72 changed files with 13381 additions and 0 deletions
  1. 1 0
      .env
  2. 76 0
      .eslintrc-auto-import.json
  3. 30 0
      .gitignore
  4. 6 0
      .vscode/extensions.json
  5. 39 0
      README.md
  6. 73 0
      auto-imports.d.ts
  7. 62 0
      components.d.ts
  8. 1 0
      env.d.ts
  9. 13 0
      index.html
  10. 7824 0
      package-lock.json
  11. 51 0
      package.json
  12. 28 0
      project.config.json
  13. 7 0
      project.private.config.json
  14. BIN
      public/favicon.ico
  15. BIN
      public/默认头像.png
  16. 116 0
      src/API/menus.ts
  17. 44 0
      src/API/users.ts
  18. 16 0
      src/App.vue
  19. 86 0
      src/assets/base.css
  20. 1 0
      src/assets/logo.svg
  21. 4 0
      src/assets/main.scss
  22. 41 0
      src/components/HelloWorld.vue
  23. 94 0
      src/components/TheWelcome.vue
  24. 87 0
      src/components/WelcomeItem.vue
  25. 11 0
      src/components/__tests__/HelloWorld.spec.ts
  26. 7 0
      src/components/icons/IconCommunity.vue
  27. 7 0
      src/components/icons/IconDocumentation.vue
  28. 7 0
      src/components/icons/IconEcosystem.vue
  29. 7 0
      src/components/icons/IconSupport.vue
  30. 19 0
      src/components/icons/IconTooling.vue
  31. 130 0
      src/components/layout/AppAside.vue
  32. 122 0
      src/components/layout/AppAsideForTab2.vue
  33. 187 0
      src/components/layout/AppHeader.vue
  34. 105 0
      src/components/layout/AppLayout.vue
  35. 17 0
      src/components/layout/TabsComponent.vue
  36. 3 0
      src/components/layout/isCollapse.ts
  37. 20 0
      src/main.ts
  38. 146 0
      src/router/index.ts
  39. 17 0
      src/shims-vue.d.ts
  40. 12 0
      src/stores/counter.ts
  41. 39 0
      src/stores/mytoken.ts
  42. 48 0
      src/utils/request.ts
  43. 15 0
      src/views/AboutView.vue
  44. 24 0
      src/views/ErrorPage.vue
  45. 9 0
      src/views/HomeView.vue
  46. 219 0
      src/views/ModelSelection.vue
  47. 236 0
      src/views/ModelTrain.vue
  48. 404 0
      src/views/Visualizatio.vue
  49. 403 0
      src/views/Visualization.vue
  50. 209 0
      src/views/login/loginView.vue
  51. 286 0
      src/views/menu/AcidNeutralizationModel.vue
  52. 292 0
      src/views/menu/Calculation.vue
  53. 185 0
      src/views/menu/IntroUpdateModal.vue
  54. 149 0
      src/views/menu/Introduce.vue
  55. 92 0
      src/views/menu/IntroductionUpdate.vue
  56. 17 0
      src/views/menu/Overview.vue
  57. 17 0
      src/views/menu/ResearchFindings.vue
  58. 182 0
      src/views/menu/RichTextEditor.vue
  59. 333 0
      src/views/menu/SoilAcidReductionIterativeEvolution.vue
  60. 335 0
      src/views/menu/SoilAcidificationIterativeEvolution.vue
  61. 18 0
      src/views/menu/SoilPro.vue
  62. 17 0
      src/views/menu/Unit.vue
  63. 8 0
      src/views/menu/mapView.vue
  64. 52 0
      src/views/packaged/PaginationComponent.vue
  65. 77 0
      src/views/thres.vue
  66. 12 0
      tsconfig.app.json
  67. 14 0
      tsconfig.json
  68. 18 0
      tsconfig.node.json
  69. 11 0
      tsconfig.vitest.json
  70. 51 0
      vite.config.ts
  71. 46 0
      vitest.config.ts
  72. 46 0
      vitest.config.ts.timestamp-1740657859395-685793505d838.mjs

+ 1 - 0
.env

@@ -0,0 +1 @@
+VITE_API_URL= 'https://127.0.0.1:5000'

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

@@ -0,0 +1,76 @@
+{
+  "globals": {
+    "Component": true,
+    "ComponentPublicInstance": true,
+    "ComputedRef": true,
+    "DirectiveBinding": true,
+    "EffectScope": true,
+    "ExtractDefaultPropTypes": true,
+    "ExtractPropTypes": true,
+    "ExtractPublicPropTypes": true,
+    "InjectionKey": true,
+    "MaybeRef": true,
+    "MaybeRefOrGetter": 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,
+    "onBeforeUnmount": true,
+    "onBeforeUpdate": true,
+    "onDeactivated": true,
+    "onErrorCaptured": true,
+    "onMounted": true,
+    "onRenderTracked": true,
+    "onRenderTriggered": true,
+    "onScopeDispose": true,
+    "onServerPrefetch": true,
+    "onUnmounted": true,
+    "onUpdated": true,
+    "onWatcherCleanup": 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,
+    "useId": true,
+    "useModel": true,
+    "useSlots": true,
+    "useTemplateRef": true,
+    "watch": true,
+    "watchEffect": true,
+    "watchPostEffect": true,
+    "watchSyncEffect": true,
+    "ElMessage": true,
+    "ElM": true
+  }
+}

+ 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

+ 6 - 0
.vscode/extensions.json

@@ -0,0 +1,6 @@
+{
+  "recommendations": [
+    "Vue.volar",
+    "vitest.explorer"
+  ]
+}

+ 39 - 0
README.md

@@ -0,0 +1,39 @@
+# vue_soil
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
+
+## Type Support for `.vue` Imports in TS
+
+TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vite.dev/config/).
+
+## Project Setup
+
+```sh
+npm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+npm run dev
+```
+
+### Type-Check, Compile and Minify for Production
+
+```sh
+npm run build
+```
+
+### Run Unit Tests with [Vitest](https://vitest.dev/)
+
+```sh
+npm run test:unit
+```

+ 73 - 0
auto-imports.d.ts

@@ -0,0 +1,73 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+// biome-ignore lint: disable
+export {}
+declare global {
+  const EffectScope: typeof import('vue')['EffectScope']
+  const ElM: typeof import('element-plus/es')['ElM']
+  const ElMessage: typeof import('element-plus/es')['ElMessage']
+  const computed: typeof import('vue')['computed']
+  const createApp: typeof import('vue')['createApp']
+  const customRef: typeof import('vue')['customRef']
+  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
+  const defineComponent: typeof import('vue')['defineComponent']
+  const effectScope: typeof import('vue')['effectScope']
+  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
+  const getCurrentScope: typeof import('vue')['getCurrentScope']
+  const h: typeof import('vue')['h']
+  const inject: typeof import('vue')['inject']
+  const isProxy: typeof import('vue')['isProxy']
+  const isReactive: typeof import('vue')['isReactive']
+  const isReadonly: typeof import('vue')['isReadonly']
+  const isRef: typeof import('vue')['isRef']
+  const markRaw: typeof import('vue')['markRaw']
+  const nextTick: typeof import('vue')['nextTick']
+  const onActivated: typeof import('vue')['onActivated']
+  const onBeforeMount: typeof import('vue')['onBeforeMount']
+  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
+  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
+  const onDeactivated: typeof import('vue')['onDeactivated']
+  const onErrorCaptured: typeof import('vue')['onErrorCaptured']
+  const onMounted: typeof import('vue')['onMounted']
+  const onRenderTracked: typeof import('vue')['onRenderTracked']
+  const onRenderTriggered: typeof import('vue')['onRenderTriggered']
+  const onScopeDispose: typeof import('vue')['onScopeDispose']
+  const onServerPrefetch: typeof import('vue')['onServerPrefetch']
+  const onUnmounted: typeof import('vue')['onUnmounted']
+  const onUpdated: typeof import('vue')['onUpdated']
+  const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
+  const provide: typeof import('vue')['provide']
+  const reactive: typeof import('vue')['reactive']
+  const readonly: typeof import('vue')['readonly']
+  const ref: typeof import('vue')['ref']
+  const resolveComponent: typeof import('vue')['resolveComponent']
+  const shallowReactive: typeof import('vue')['shallowReactive']
+  const shallowReadonly: typeof import('vue')['shallowReadonly']
+  const shallowRef: typeof import('vue')['shallowRef']
+  const toRaw: typeof import('vue')['toRaw']
+  const toRef: typeof import('vue')['toRef']
+  const toRefs: typeof import('vue')['toRefs']
+  const toValue: typeof import('vue')['toValue']
+  const triggerRef: typeof import('vue')['triggerRef']
+  const unref: typeof import('vue')['unref']
+  const useAttrs: typeof import('vue')['useAttrs']
+  const useCssModule: typeof import('vue')['useCssModule']
+  const useCssVars: typeof import('vue')['useCssVars']
+  const useId: typeof import('vue')['useId']
+  const useModel: typeof import('vue')['useModel']
+  const useSlots: typeof import('vue')['useSlots']
+  const useTemplateRef: typeof import('vue')['useTemplateRef']
+  const watch: typeof import('vue')['watch']
+  const watchEffect: typeof import('vue')['watchEffect']
+  const watchPostEffect: typeof import('vue')['watchPostEffect']
+  const watchSyncEffect: typeof import('vue')['watchSyncEffect']
+}
+// for type re-export
+declare global {
+  // @ts-ignore
+  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  import('vue')
+}

+ 62 - 0
components.d.ts

@@ -0,0 +1,62 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+  export interface GlobalComponents {
+    AppAside: typeof import('./src/components/layout/AppAside.vue')['default']
+    AppAsideForTab2: typeof import('./src/components/layout/AppAsideForTab2.vue')['default']
+    AppHeader: typeof import('./src/components/layout/AppHeader.vue')['default']
+    AppLayout: typeof import('./src/components/layout/AppLayout.vue')['default']
+    ElAlert: typeof import('element-plus/es')['ElAlert']
+    ElAside: typeof import('element-plus/es')['ElAside']
+    ElAvarar: typeof import('element-plus/es')['ElAvarar']
+    ElAvatar: typeof import('element-plus/es')['ElAvatar']
+    ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
+    ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
+    ElButton: typeof import('element-plus/es')['ElButton']
+    ElCard: typeof import('element-plus/es')['ElCard']
+    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+    ElCol: typeof import('element-plus/es')['ElCol']
+    ElContainer: typeof import('element-plus/es')['ElContainer']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElDropdown: typeof import('element-plus/es')['ElDropdown']
+    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
+    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
+    ElForm: typeof import('element-plus/es')['ElForm']
+    ElFormItem: typeof import('element-plus/es')['ElFormItem']
+    ElHeader: typeof import('element-plus/es')['ElHeader']
+    ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElInput: typeof import('element-plus/es')['ElInput']
+    ElMain: typeof import('element-plus/es')['ElMain']
+    ElMenu: typeof import('element-plus/es')['ElMenu']
+    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+    ElOption: typeof import('element-plus/es')['ElOption']
+    ElPagination: typeof import('element-plus/es')['ElPagination']
+    ElRow: typeof import('element-plus/es')['ElRow']
+    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
+    ElSelect: typeof import('element-plus/es')['ElSelect']
+    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+    ElTable: typeof import('element-plus/es')['ElTable']
+    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTooltip: typeof import('element-plus/es')['ElTooltip']
+    ElUpload: typeof import('element-plus/es')['ElUpload']
+    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
+    IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
+    IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
+    IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
+    IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    TabsComponent: typeof import('./src/components/layout/TabsComponent.vue')['default']
+    TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
+    WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
+  }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
+}

+ 1 - 0
env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="">
+  <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>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

+ 7824 - 0
package-lock.json

@@ -0,0 +1,7824 @@
+{
+  "name": "vue_soil",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "vue_soil",
+      "version": "0.0.0",
+      "dependencies": {
+        "@element-plus/icons-vue": "^2.3.1",
+        "@wangeditor/editor": "^5.1.23",
+        "@wangeditor/editor-for-vue": "^5.1.12",
+        "axios": "^1.7.9",
+        "echarts": "^5.6.0",
+        "echarts-gl": "^2.0.9",
+        "element-plus": "^2.9.3",
+        "leaflet": "^1.9.4",
+        "pinia": "^2.3.0",
+        "sass": "^1.84.0",
+        "vue": "^3.5.13",
+        "vue-echarts": "^7.0.3",
+        "vue-leaflet": "^0.1.0",
+        "vue-router": "^4.5.0"
+      },
+      "devDependencies": {
+        "@iconify-json/ep": "^1.2.2",
+        "@tsconfig/node22": "^22.0.0",
+        "@types/jsdom": "^21.1.7",
+        "@types/leaflet": "^1.9.16",
+        "@types/node": "^22.13.8",
+        "@types/vue": "^2.0.0",
+        "@vitejs/plugin-vue": "^5.2.1",
+        "@vue/test-utils": "^2.4.6",
+        "@vue/tsconfig": "^0.7.0",
+        "jsdom": "^25.0.1",
+        "npm-run-all2": "^7.0.2",
+        "typescript": "~5.6.3",
+        "unplugin-auto-import": "^19.0.0",
+        "unplugin-icons": "^22.0.0",
+        "unplugin-vue-components": "^28.0.0",
+        "vite": "^6.0.5",
+        "vite-plugin-vue-devtools": "^7.6.8",
+        "vitest": "^2.1.9",
+        "vue-tsc": "^2.1.10"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@antfu/install-pkg": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-0.5.0.tgz",
+      "integrity": "sha512-dKnk2xlAyC7rvTkpkHmu+Qy/2Zc3Vm/l8PtNyIOGDBtXPY3kThfU4ORNEp3V7SXw5XSOb+tOJaUYpfquPzL/Tg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "package-manager-detector": "^0.2.5",
+        "tinyexec": "^0.3.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@antfu/utils": {
+      "version": "0.7.10",
+      "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
+      "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@asamuzakjp/css-color": {
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz",
+      "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@csstools/css-calc": "^2.1.1",
+        "@csstools/css-color-parser": "^3.0.7",
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3",
+        "lru-cache": "^10.4.3"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.26.2",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+      "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz",
+      "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz",
+      "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.26.0",
+        "@babel/generator": "^7.26.0",
+        "@babel/helper-compilation-targets": "^7.25.9",
+        "@babel/helper-module-transforms": "^7.26.0",
+        "@babel/helpers": "^7.26.0",
+        "@babel/parser": "^7.26.0",
+        "@babel/template": "^7.25.9",
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.26.0",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz",
+      "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.26.5",
+        "@babel/types": "^7.26.5",
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.25",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
+      "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz",
+      "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.26.5",
+        "@babel/helper-validator-option": "^7.25.9",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz",
+      "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.25.9",
+        "@babel/helper-member-expression-to-functions": "^7.25.9",
+        "@babel/helper-optimise-call-expression": "^7.25.9",
+        "@babel/helper-replace-supers": "^7.25.9",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+        "@babel/traverse": "^7.25.9",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-member-expression-to-functions": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz",
+      "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
+      "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
+      "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9",
+        "@babel/traverse": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz",
+      "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
+      "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz",
+      "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-member-expression-to-functions": "^7.25.9",
+        "@babel/helper-optimise-call-expression": "^7.25.9",
+        "@babel/traverse": "^7.26.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
+      "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+      "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+      "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
+      "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz",
+      "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.25.9",
+        "@babel/types": "^7.26.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz",
+      "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.26.5"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-decorators": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz",
+      "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.25.9",
+        "@babel/helper-plugin-utils": "^7.25.9",
+        "@babel/plugin-syntax-decorators": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-decorators": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz",
+      "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-attributes": {
+      "version": "7.26.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz",
+      "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-jsx": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz",
+      "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-typescript": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz",
+      "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typescript": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz",
+      "integrity": "sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.25.9",
+        "@babel/helper-create-class-features-plugin": "^7.25.9",
+        "@babel/helper-plugin-utils": "^7.26.5",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+        "@babel/plugin-syntax-typescript": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.26.9",
+      "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.9.tgz",
+      "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
+      "license": "MIT",
+      "dependencies": {
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.25.9",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
+      "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.25.9",
+        "@babel/parser": "^7.25.9",
+        "@babel/types": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz",
+      "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.26.2",
+        "@babel/generator": "^7.26.5",
+        "@babel/parser": "^7.26.5",
+        "@babel/template": "^7.25.9",
+        "@babel/types": "^7.26.5",
+        "debug": "^4.3.1",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.26.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz",
+      "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.25.9",
+        "@babel/helper-validator-identifier": "^7.25.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@csstools/color-helpers": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz",
+      "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT-0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@csstools/css-calc": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz",
+      "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-color-parser": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz",
+      "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@csstools/color-helpers": "^5.0.1",
+        "@csstools/css-calc": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-parser-algorithms": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz",
+      "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-tokenizer": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz",
+      "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@ctrl/tinycolor": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
+      "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@element-plus/icons-vue": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
+      "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
+      "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
+      "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
+      "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
+      "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
+      "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
+      "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
+      "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
+      "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
+      "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
+      "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
+      "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
+      "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
+      "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
+      "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
+      "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
+      "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
+      "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
+      "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
+      "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
+      "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
+      "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
+      "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
+      "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
+      "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
+      "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@floating-ui/core": {
+      "version": "1.6.9",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz",
+      "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/utils": "^0.2.9"
+      }
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "1.6.13",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz",
+      "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
+      "license": "MIT",
+      "dependencies": {
+        "@floating-ui/core": "^1.6.0",
+        "@floating-ui/utils": "^0.2.9"
+      }
+    },
+    "node_modules/@floating-ui/utils": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
+      "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
+      "license": "MIT"
+    },
+    "node_modules/@iconify-json/ep": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/@iconify-json/ep/-/ep-1.2.2.tgz",
+      "integrity": "sha512-/IH1GjQKH5uK7lQAOjwPxdjkU98OWUWnHYCdg/EkeebBKEteotaOMeEz5pR1egqMcI7zPFdFBTcGyCHla1ddQw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@iconify/types": "*"
+      }
+    },
+    "node_modules/@iconify/types": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz",
+      "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@iconify/utils": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-2.3.0.tgz",
+      "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/install-pkg": "^1.0.0",
+        "@antfu/utils": "^8.1.0",
+        "@iconify/types": "^2.0.0",
+        "debug": "^4.4.0",
+        "globals": "^15.14.0",
+        "kolorist": "^1.8.0",
+        "local-pkg": "^1.0.0",
+        "mlly": "^1.7.4"
+      }
+    },
+    "node_modules/@iconify/utils/node_modules/@antfu/install-pkg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-1.0.0.tgz",
+      "integrity": "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "package-manager-detector": "^0.2.8",
+        "tinyexec": "^0.3.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@iconify/utils/node_modules/@antfu/utils": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-8.1.0.tgz",
+      "integrity": "sha512-XPR7Jfwp0FFl/dFYPX8ZjpmU4/1mIXTjnZ1ba48BLMyKOV62/tiRjdsFcPs2hsYcSud4tzk7w3a3LjX8Fu3huA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@iconify/utils/node_modules/globals": {
+      "version": "15.14.0",
+      "resolved": "https://registry.npmmirror.com/globals/-/globals-15.14.0.tgz",
+      "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@iconify/utils/node_modules/local-pkg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.0.0.tgz",
+      "integrity": "sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mlly": "^1.7.3",
+        "pkg-types": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+      "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.2.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@one-ini/wasm": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
+      "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.1.tgz",
+      "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "detect-libc": "^1.0.3",
+        "is-glob": "^4.0.3",
+        "micromatch": "^4.0.5",
+        "node-addon-api": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.5.1",
+        "@parcel/watcher-darwin-arm64": "2.5.1",
+        "@parcel/watcher-darwin-x64": "2.5.1",
+        "@parcel/watcher-freebsd-x64": "2.5.1",
+        "@parcel/watcher-linux-arm-glibc": "2.5.1",
+        "@parcel/watcher-linux-arm-musl": "2.5.1",
+        "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+        "@parcel/watcher-linux-arm64-musl": "2.5.1",
+        "@parcel/watcher-linux-x64-glibc": "2.5.1",
+        "@parcel/watcher-linux-x64-musl": "2.5.1",
+        "@parcel/watcher-win32-arm64": "2.5.1",
+        "@parcel/watcher-win32-ia32": "2.5.1",
+        "@parcel/watcher-win32-x64": "2.5.1"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+      "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+      "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+      "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+      "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+      "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-musl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+      "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+      "cpu": [
+        "arm"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+      "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+      "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+      "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+      "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+      "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+      "cpu": [
+        "arm64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+      "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+      "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+      "cpu": [
+        "x64"
+      ],
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@polka/url": {
+      "version": "1.0.0-next.28",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz",
+      "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@popperjs/core": {
+      "name": "@sxzz/popperjs-es",
+      "version": "2.11.7",
+      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
+      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/popperjs"
+      }
+    },
+    "node_modules/@rollup/pluginutils": {
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
+      "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "estree-walker": "^2.0.2",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.31.0.tgz",
+      "integrity": "sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.31.0.tgz",
+      "integrity": "sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.31.0.tgz",
+      "integrity": "sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.31.0.tgz",
+      "integrity": "sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.31.0.tgz",
+      "integrity": "sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.31.0.tgz",
+      "integrity": "sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.31.0.tgz",
+      "integrity": "sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.31.0.tgz",
+      "integrity": "sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.31.0.tgz",
+      "integrity": "sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.31.0.tgz",
+      "integrity": "sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.31.0.tgz",
+      "integrity": "sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.31.0.tgz",
+      "integrity": "sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.31.0.tgz",
+      "integrity": "sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.31.0.tgz",
+      "integrity": "sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.31.0.tgz",
+      "integrity": "sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.31.0.tgz",
+      "integrity": "sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.31.0.tgz",
+      "integrity": "sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.31.0.tgz",
+      "integrity": "sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.31.0.tgz",
+      "integrity": "sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@sec-ant/readable-stream": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+      "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@sindresorhus/merge-streams": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+      "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@transloadit/prettier-bytes": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
+      "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==",
+      "license": "MIT"
+    },
+    "node_modules/@tsconfig/node22": {
+      "version": "22.0.0",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz",
+      "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==",
+      "license": "MIT"
+    },
+    "node_modules/@types/geojson": {
+      "version": "7946.0.16",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+      "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/jsdom": {
+      "version": "21.1.7",
+      "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz",
+      "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*",
+        "@types/tough-cookie": "*",
+        "parse5": "^7.0.0"
+      }
+    },
+    "node_modules/@types/leaflet": {
+      "version": "1.9.16",
+      "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.16.tgz",
+      "integrity": "sha512-wzZoyySUxkgMZ0ihJ7IaUIblG8Rdc8AbbZKLneyn+QjYsj5q1QU7TEKYqwTr10BGSzY5LI7tJk9Ifo+mEjdFRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/geojson": "*"
+      }
+    },
+    "node_modules/@types/lodash": {
+      "version": "4.17.14",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
+      "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==",
+      "license": "MIT"
+    },
+    "node_modules/@types/lodash-es": {
+      "version": "4.17.12",
+      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
+      "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/lodash": "*"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "22.13.8",
+      "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.8.tgz",
+      "integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.20.0"
+      }
+    },
+    "node_modules/@types/tough-cookie": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
+      "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/vue": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/@types/vue/-/vue-2.0.0.tgz",
+      "integrity": "sha512-WDElkBv/o4lVwu6wYHB06AXs4Xo2fwDjJUpvPRc1QQdzkUSiGFjrYuSCy8raxLE5FObgKq8ND7R5gSZTFLK60w==",
+      "deprecated": "This is a stub types definition for vuejs (https://github.com/vuejs/vue). vuejs provides its own type definitions, so you don't need @types/vue installed!",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "vue": "*"
+      }
+    },
+    "node_modules/@types/web-bluetooth": {
+      "version": "0.0.16",
+      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
+      "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
+      "license": "MIT"
+    },
+    "node_modules/@uppy/companion-client": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz",
+      "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
+      "license": "MIT",
+      "dependencies": {
+        "@uppy/utils": "^4.1.2",
+        "namespace-emitter": "^2.0.1"
+      }
+    },
+    "node_modules/@uppy/core": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz",
+      "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@transloadit/prettier-bytes": "0.0.7",
+        "@uppy/store-default": "^2.1.1",
+        "@uppy/utils": "^4.1.3",
+        "lodash.throttle": "^4.1.1",
+        "mime-match": "^1.0.2",
+        "namespace-emitter": "^2.0.1",
+        "nanoid": "^3.1.25",
+        "preact": "^10.5.13"
+      }
+    },
+    "node_modules/@uppy/store-default": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz",
+      "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==",
+      "license": "MIT"
+    },
+    "node_modules/@uppy/utils": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz",
+      "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
+      "license": "MIT",
+      "dependencies": {
+        "lodash.throttle": "^4.1.1"
+      }
+    },
+    "node_modules/@uppy/xhr-upload": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
+      "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@uppy/companion-client": "^2.2.2",
+        "@uppy/utils": "^4.1.2",
+        "nanoid": "^3.1.25"
+      },
+      "peerDependencies": {
+        "@uppy/core": "^2.3.3"
+      }
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz",
+      "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.0.0 || ^6.0.0",
+        "vue": "^3.2.25"
+      }
+    },
+    "node_modules/@vitest/expect": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-2.1.9.tgz",
+      "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/spy": "2.1.9",
+        "@vitest/utils": "2.1.9",
+        "chai": "^5.1.2",
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/pretty-format": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-2.1.9.tgz",
+      "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/runner": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-2.1.9.tgz",
+      "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/utils": "2.1.9",
+        "pathe": "^1.1.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/snapshot": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-2.1.9.tgz",
+      "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "2.1.9",
+        "magic-string": "^0.30.12",
+        "pathe": "^1.1.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/spy": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-2.1.9.tgz",
+      "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyspy": "^3.0.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/utils": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-2.1.9.tgz",
+      "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "2.1.9",
+        "loupe": "^3.1.2",
+        "tinyrainbow": "^1.2.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@volar/language-core": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.11.tgz",
+      "integrity": "sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/source-map": "2.4.11"
+      }
+    },
+    "node_modules/@volar/source-map": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.11.tgz",
+      "integrity": "sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@volar/typescript": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.11.tgz",
+      "integrity": "sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "2.4.11",
+        "path-browserify": "^1.0.1",
+        "vscode-uri": "^3.0.8"
+      }
+    },
+    "node_modules/@vue/babel-helper-vue-transform-on": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz",
+      "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vue/babel-plugin-jsx": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz",
+      "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.24.7",
+        "@babel/helper-plugin-utils": "^7.24.8",
+        "@babel/plugin-syntax-jsx": "^7.24.7",
+        "@babel/template": "^7.25.0",
+        "@babel/traverse": "^7.25.6",
+        "@babel/types": "^7.25.6",
+        "@vue/babel-helper-vue-transform-on": "1.2.5",
+        "@vue/babel-plugin-resolve-type": "1.2.5",
+        "html-tags": "^3.3.1",
+        "svg-tags": "^1.0.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "@babel/core": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/babel-plugin-resolve-type": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz",
+      "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.24.7",
+        "@babel/helper-module-imports": "^7.24.7",
+        "@babel/helper-plugin-utils": "^7.24.8",
+        "@babel/parser": "^7.25.6",
+        "@vue/compiler-sfc": "^3.5.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@vue/compiler-core": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz",
+      "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.25.3",
+        "@vue/shared": "3.5.13",
+        "entities": "^4.5.0",
+        "estree-walker": "^2.0.2",
+        "source-map-js": "^1.2.0"
+      }
+    },
+    "node_modules/@vue/compiler-dom": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz",
+      "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-core": "3.5.13",
+        "@vue/shared": "3.5.13"
+      }
+    },
+    "node_modules/@vue/compiler-sfc": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz",
+      "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.25.3",
+        "@vue/compiler-core": "3.5.13",
+        "@vue/compiler-dom": "3.5.13",
+        "@vue/compiler-ssr": "3.5.13",
+        "@vue/shared": "3.5.13",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.30.11",
+        "postcss": "^8.4.48",
+        "source-map-js": "^1.2.0"
+      }
+    },
+    "node_modules/@vue/compiler-ssr": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz",
+      "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.13",
+        "@vue/shared": "3.5.13"
+      }
+    },
+    "node_modules/@vue/compiler-vue2": {
+      "version": "2.7.16",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+      "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "de-indent": "^1.0.2",
+        "he": "^1.2.0"
+      }
+    },
+    "node_modules/@vue/devtools-api": {
+      "version": "6.6.4",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+      "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+      "license": "MIT"
+    },
+    "node_modules/@vue/devtools-core": {
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.0.tgz",
+      "integrity": "sha512-tSO3pghV5RZGSonZ87S2fOGru3X93epmar5IjZOWjHxH6XSwnK5UbR2aW5puZV+LgLoVYrcNou3krSo5k1F31g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-kit": "^7.7.0",
+        "@vue/devtools-shared": "^7.7.0",
+        "mitt": "^3.0.1",
+        "nanoid": "^5.0.9",
+        "pathe": "^1.1.2",
+        "vite-hot-client": "^0.2.4"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
+    "node_modules/@vue/devtools-core/node_modules/nanoid": {
+      "version": "5.0.9",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
+      "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.js"
+      },
+      "engines": {
+        "node": "^18 || >=20"
+      }
+    },
+    "node_modules/@vue/devtools-kit": {
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.0.tgz",
+      "integrity": "sha512-5cvZ+6SA88zKC8XiuxUfqpdTwVjJbvYnQZY5NReh7qlSGPvVDjjzyEtW+gdzLXNSd8tStgOjAdMCpvDQamUXtA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-shared": "^7.7.0",
+        "birpc": "^0.2.19",
+        "hookable": "^5.5.3",
+        "mitt": "^3.0.1",
+        "perfect-debounce": "^1.0.0",
+        "speakingurl": "^14.0.1",
+        "superjson": "^2.2.1"
+      }
+    },
+    "node_modules/@vue/devtools-shared": {
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.0.tgz",
+      "integrity": "sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "rfdc": "^1.4.1"
+      }
+    },
+    "node_modules/@vue/language-core": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz",
+      "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/language-core": "~2.4.11",
+        "@vue/compiler-dom": "^3.5.0",
+        "@vue/compiler-vue2": "^2.7.16",
+        "@vue/shared": "^3.5.0",
+        "alien-signals": "^0.4.9",
+        "minimatch": "^9.0.3",
+        "muggle-string": "^0.4.1",
+        "path-browserify": "^1.0.1"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vue/language-core/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz",
+      "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/shared": "3.5.13"
+      }
+    },
+    "node_modules/@vue/runtime-core": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz",
+      "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.13",
+        "@vue/shared": "3.5.13"
+      }
+    },
+    "node_modules/@vue/runtime-dom": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz",
+      "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.13",
+        "@vue/runtime-core": "3.5.13",
+        "@vue/shared": "3.5.13",
+        "csstype": "^3.1.3"
+      }
+    },
+    "node_modules/@vue/server-renderer": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz",
+      "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-ssr": "3.5.13",
+        "@vue/shared": "3.5.13"
+      },
+      "peerDependencies": {
+        "vue": "3.5.13"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz",
+      "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
+      "license": "MIT"
+    },
+    "node_modules/@vue/test-utils": {
+      "version": "2.4.6",
+      "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz",
+      "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "js-beautify": "^1.14.9",
+        "vue-component-type-helpers": "^2.0.0"
+      }
+    },
+    "node_modules/@vue/tsconfig": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz",
+      "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "typescript": "5.x",
+        "vue": "^3.4.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        },
+        "vue": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vueuse/core": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
+      "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/web-bluetooth": "^0.0.16",
+        "@vueuse/metadata": "9.13.0",
+        "@vueuse/shared": "9.13.0",
+        "vue-demi": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vueuse/metadata": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
+      "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@vueuse/shared": {
+      "version": "9.13.0",
+      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
+      "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
+      "license": "MIT",
+      "dependencies": {
+        "vue-demi": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/@wangeditor/basic-modules": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
+      "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-url": "^1.2.4"
+      },
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.throttle": "^4.1.1",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/code-highlight": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
+      "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
+      "license": "MIT",
+      "dependencies": {
+        "prismjs": "^1.23.0"
+      },
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/core": {
+      "version": "1.1.19",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz",
+      "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/event-emitter": "^0.3.3",
+        "event-emitter": "^0.3.5",
+        "html-void-elements": "^2.0.0",
+        "i18next": "^20.4.0",
+        "scroll-into-view-if-needed": "^2.2.28",
+        "slate-history": "^0.66.0"
+      },
+      "peerDependencies": {
+        "@uppy/core": "^2.1.1",
+        "@uppy/xhr-upload": "^2.0.3",
+        "dom7": "^3.0.0",
+        "is-hotkey": "^0.2.0",
+        "lodash.camelcase": "^4.3.0",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.debounce": "^4.0.8",
+        "lodash.foreach": "^4.5.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "lodash.toarray": "^4.4.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/editor": {
+      "version": "5.1.23",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz",
+      "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@uppy/core": "^2.1.1",
+        "@uppy/xhr-upload": "^2.0.3",
+        "@wangeditor/basic-modules": "^1.1.7",
+        "@wangeditor/code-highlight": "^1.0.3",
+        "@wangeditor/core": "^1.1.19",
+        "@wangeditor/list-module": "^1.0.5",
+        "@wangeditor/table-module": "^1.1.4",
+        "@wangeditor/upload-image-module": "^1.0.2",
+        "@wangeditor/video-module": "^1.1.4",
+        "dom7": "^3.0.0",
+        "is-hotkey": "^0.2.0",
+        "lodash.camelcase": "^4.3.0",
+        "lodash.clonedeep": "^4.5.0",
+        "lodash.debounce": "^4.0.8",
+        "lodash.foreach": "^4.5.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "lodash.toarray": "^4.4.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/editor-for-vue": {
+      "version": "5.1.12",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
+      "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@wangeditor/editor": ">=5.1.0",
+        "vue": "^3.0.5"
+      }
+    },
+    "node_modules/@wangeditor/list-module": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz",
+      "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/table-module": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz",
+      "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.isequal": "^4.5.0",
+        "lodash.throttle": "^4.1.1",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/upload-image-module": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
+      "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@uppy/core": "^2.0.3",
+        "@uppy/xhr-upload": "^2.0.3",
+        "@wangeditor/basic-modules": "1.x",
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "lodash.foreach": "^4.5.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/@wangeditor/video-module": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz",
+      "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@uppy/core": "^2.1.4",
+        "@uppy/xhr-upload": "^2.0.7",
+        "@wangeditor/core": "1.x",
+        "dom7": "^3.0.0",
+        "nanoid": "^3.2.0",
+        "slate": "^0.72.0",
+        "snabbdom": "^3.1.0"
+      }
+    },
+    "node_modules/abbrev": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
+      "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.14.0",
+      "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz",
+      "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+      "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/alien-signals": {
+      "version": "0.4.14",
+      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz",
+      "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+      "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/anymatch/node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/assertion-error": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz",
+      "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/async-validator": {
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
+      "license": "MIT"
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "1.7.9",
+      "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.9.tgz",
+      "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.6",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/birpc": {
+      "version": "0.2.19",
+      "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz",
+      "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.24.4",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+      "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001688",
+        "electron-to-chromium": "^1.5.73",
+        "node-releases": "^2.0.19",
+        "update-browserslist-db": "^1.1.1"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cac": {
+      "version": "6.7.14",
+      "resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz",
+      "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001695",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
+      "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chai": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmmirror.com/chai/-/chai-5.1.2.tgz",
+      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "assertion-error": "^2.0.1",
+        "check-error": "^2.1.1",
+        "deep-eql": "^5.0.1",
+        "loupe": "^3.1.0",
+        "pathval": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/check-error": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/check-error/-/check-error-2.1.1.tgz",
+      "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 16"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/claygl": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
+      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+      "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/compute-scroll-into-view": {
+      "version": "1.0.20",
+      "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+      "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
+      "license": "MIT"
+    },
+    "node_modules/confbox": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz",
+      "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/config-chain": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+      "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ini": "^1.3.4",
+        "proto-list": "~1.2.1"
+      }
+    },
+    "node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/copy-anything": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
+      "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-what": "^4.1.8"
+      },
+      "engines": {
+        "node": ">=12.13"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mesqueeb"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/cssstyle": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz",
+      "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@asamuzakjp/css-color": "^2.8.2",
+        "rrweb-cssom": "^0.8.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/cssstyle/node_modules/rrweb-cssom": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
+      "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/csstype": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+      "license": "MIT"
+    },
+    "node_modules/d": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/d/-/d-1.0.2.tgz",
+      "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
+      "license": "ISC",
+      "dependencies": {
+        "es5-ext": "^0.10.64",
+        "type": "^2.7.2"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/data-urls": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+      "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-mimetype": "^4.0.0",
+        "whatwg-url": "^14.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/dayjs": {
+      "version": "1.11.13",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+      "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
+      "license": "MIT"
+    },
+    "node_modules/de-indent": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+      "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decimal.js": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+      "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/deep-eql": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmmirror.com/deep-eql/-/deep-eql-5.0.2.tgz",
+      "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/default-browser": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
+      "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bundle-name": "^4.1.0",
+        "default-browser-id": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/default-browser-id": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
+      "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+      "license": "Apache-2.0",
+      "optional": true,
+      "bin": {
+        "detect-libc": "bin/detect-libc.js"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/dom7": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
+      "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
+      "license": "MIT",
+      "dependencies": {
+        "ssr-window": "^3.0.0-alpha.1"
+      }
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/echarts": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
+      "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "2.3.0",
+        "zrender": "5.6.1"
+      }
+    },
+    "node_modules/echarts-gl": {
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
+      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
+      "dependencies": {
+        "claygl": "^1.2.1",
+        "zrender": "^5.1.1"
+      },
+      "peerDependencies": {
+        "echarts": "^5.1.2"
+      }
+    },
+    "node_modules/editorconfig": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
+      "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@one-ini/wasm": "0.1.1",
+        "commander": "^10.0.0",
+        "minimatch": "9.0.1",
+        "semver": "^7.5.3"
+      },
+      "bin": {
+        "editorconfig": "bin/editorconfig"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.83",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz",
+      "integrity": "sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/element-plus": {
+      "version": "2.9.3",
+      "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.3.tgz",
+      "integrity": "sha512-6tSLp5XytDS4TMZ0P3aGZnr7MXTagfNycepNfIDitd9IgwM9y01+Ssu6mglNi8RiXYhek6LBWNOd/cvpIO12+w==",
+      "license": "MIT",
+      "dependencies": {
+        "@ctrl/tinycolor": "^3.4.1",
+        "@element-plus/icons-vue": "^2.3.1",
+        "@floating-ui/dom": "^1.0.1",
+        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
+        "@types/lodash": "^4.14.182",
+        "@types/lodash-es": "^4.17.6",
+        "@vueuse/core": "^9.1.0",
+        "async-validator": "^4.2.5",
+        "dayjs": "^1.11.13",
+        "escape-html": "^1.0.3",
+        "lodash": "^4.17.21",
+        "lodash-es": "^4.17.21",
+        "lodash-unified": "^1.0.2",
+        "memoize-one": "^6.0.0",
+        "normalize-wheel-es": "^1.2.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/error-stack-parser-es": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz",
+      "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+      "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/es5-ext": {
+      "version": "0.10.64",
+      "resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz",
+      "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
+      "hasInstallScript": true,
+      "license": "ISC",
+      "dependencies": {
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.3",
+        "esniff": "^2.0.1",
+        "next-tick": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+      "license": "MIT",
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "node_modules/es6-symbol": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz",
+      "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
+      "license": "ISC",
+      "dependencies": {
+        "d": "^1.0.2",
+        "ext": "^1.7.0"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
+      "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.24.2",
+        "@esbuild/android-arm": "0.24.2",
+        "@esbuild/android-arm64": "0.24.2",
+        "@esbuild/android-x64": "0.24.2",
+        "@esbuild/darwin-arm64": "0.24.2",
+        "@esbuild/darwin-x64": "0.24.2",
+        "@esbuild/freebsd-arm64": "0.24.2",
+        "@esbuild/freebsd-x64": "0.24.2",
+        "@esbuild/linux-arm": "0.24.2",
+        "@esbuild/linux-arm64": "0.24.2",
+        "@esbuild/linux-ia32": "0.24.2",
+        "@esbuild/linux-loong64": "0.24.2",
+        "@esbuild/linux-mips64el": "0.24.2",
+        "@esbuild/linux-ppc64": "0.24.2",
+        "@esbuild/linux-riscv64": "0.24.2",
+        "@esbuild/linux-s390x": "0.24.2",
+        "@esbuild/linux-x64": "0.24.2",
+        "@esbuild/netbsd-arm64": "0.24.2",
+        "@esbuild/netbsd-x64": "0.24.2",
+        "@esbuild/openbsd-arm64": "0.24.2",
+        "@esbuild/openbsd-x64": "0.24.2",
+        "@esbuild/sunos-x64": "0.24.2",
+        "@esbuild/win32-arm64": "0.24.2",
+        "@esbuild/win32-ia32": "0.24.2",
+        "@esbuild/win32-x64": "0.24.2"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "license": "MIT"
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+      "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/esniff": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz",
+      "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+      "license": "ISC",
+      "dependencies": {
+        "d": "^1.0.1",
+        "es5-ext": "^0.10.62",
+        "event-emitter": "^0.3.5",
+        "type": "^2.7.2"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT"
+    },
+    "node_modules/event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+      "license": "MIT",
+      "dependencies": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "node_modules/execa": {
+      "version": "9.5.2",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz",
+      "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@sindresorhus/merge-streams": "^4.0.0",
+        "cross-spawn": "^7.0.3",
+        "figures": "^6.1.0",
+        "get-stream": "^9.0.0",
+        "human-signals": "^8.0.0",
+        "is-plain-obj": "^4.1.0",
+        "is-stream": "^4.0.1",
+        "npm-run-path": "^6.0.0",
+        "pretty-ms": "^9.0.0",
+        "signal-exit": "^4.1.0",
+        "strip-final-newline": "^4.0.0",
+        "yoctocolors": "^2.0.0"
+      },
+      "engines": {
+        "node": "^18.19.0 || >=20.5.0"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/expect-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
+      "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/ext": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
+      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+      "license": "ISC",
+      "dependencies": {
+        "type": "^2.7.2"
+      }
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.19.0.tgz",
+      "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/figures": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+      "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-unicode-supported": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.9",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+      "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+      "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+      "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
+      "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+      "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@sec-ant/readable-stream": "^0.4.1",
+        "is-stream": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/glob": {
+      "version": "10.4.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+      "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "foreground-child": "^3.1.0",
+        "jackspeak": "^3.1.2",
+        "minimatch": "^9.0.4",
+        "minipass": "^7.1.2",
+        "package-json-from-dist": "^1.0.0",
+        "path-scurry": "^1.11.1"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/glob/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "he": "bin/he"
+      }
+    },
+    "node_modules/hookable": {
+      "version": "5.5.3",
+      "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+      "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/html-encoding-sniffer": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+      "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "whatwg-encoding": "^3.1.1"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/html-tags": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+      "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/html-void-elements": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz",
+      "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==",
+      "license": "MIT",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/wooorm"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/human-signals": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
+      "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/i18next": {
+      "version": "20.6.1",
+      "resolved": "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz",
+      "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.12.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/immer": {
+      "version": "9.0.21",
+      "resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/immer"
+      }
+    },
+    "node_modules/immutable": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz",
+      "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
+      "license": "MIT"
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "devOptional": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-hotkey": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz",
+      "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
+      "license": "MIT"
+    },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "devOptional": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+      "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
+      "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-potential-custom-element-name": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+      "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-stream": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+      "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+      "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-url": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz",
+      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+      "license": "MIT"
+    },
+    "node_modules/is-what": {
+      "version": "4.1.16",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
+      "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.13"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mesqueeb"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+      "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-inside-container": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/jackspeak": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+      "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      },
+      "optionalDependencies": {
+        "@pkgjs/parseargs": "^0.11.0"
+      }
+    },
+    "node_modules/js-beautify": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
+      "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "config-chain": "^1.1.13",
+        "editorconfig": "^1.0.4",
+        "glob": "^10.3.3",
+        "js-cookie": "^3.0.5",
+        "nopt": "^7.2.0"
+      },
+      "bin": {
+        "css-beautify": "js/bin/css-beautify.js",
+        "html-beautify": "js/bin/html-beautify.js",
+        "js-beautify": "js/bin/js-beautify.js"
+      },
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/js-cookie": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
+      "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsdom": {
+      "version": "25.0.1",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz",
+      "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cssstyle": "^4.1.0",
+        "data-urls": "^5.0.0",
+        "decimal.js": "^10.4.3",
+        "form-data": "^4.0.0",
+        "html-encoding-sniffer": "^4.0.0",
+        "http-proxy-agent": "^7.0.2",
+        "https-proxy-agent": "^7.0.5",
+        "is-potential-custom-element-name": "^1.0.1",
+        "nwsapi": "^2.2.12",
+        "parse5": "^7.1.2",
+        "rrweb-cssom": "^0.7.1",
+        "saxes": "^6.0.0",
+        "symbol-tree": "^3.2.4",
+        "tough-cookie": "^5.0.0",
+        "w3c-xmlserializer": "^5.0.0",
+        "webidl-conversions": "^7.0.0",
+        "whatwg-encoding": "^3.1.1",
+        "whatwg-mimetype": "^4.0.0",
+        "whatwg-url": "^14.0.0",
+        "ws": "^8.18.0",
+        "xml-name-validator": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "canvas": "^2.11.2"
+      },
+      "peerDependenciesMeta": {
+        "canvas": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz",
+      "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/kolorist": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+      "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/leaflet": {
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
+      "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/local-pkg": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.5.1.tgz",
+      "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mlly": "^1.7.3",
+        "pkg-types": "^1.2.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "license": "MIT"
+    },
+    "node_modules/lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+      "license": "MIT"
+    },
+    "node_modules/lodash-unified": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
+      "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/lodash-es": "*",
+        "lodash": "*",
+        "lodash-es": "*"
+      }
+    },
+    "node_modules/lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.debounce": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.foreach": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+      "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+      "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
+      "license": "MIT"
+    },
+    "node_modules/lodash.throttle": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+      "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+      "license": "MIT"
+    },
+    "node_modules/lodash.toarray": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+      "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==",
+      "license": "MIT"
+    },
+    "node_modules/loupe": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmmirror.com/loupe/-/loupe-3.1.3.tgz",
+      "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.17",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0"
+      }
+    },
+    "node_modules/memoize-one": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+      "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
+      "license": "MIT"
+    },
+    "node_modules/memorystream": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+      "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/micromatch/node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "devOptional": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz",
+      "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
+      "license": "ISC",
+      "dependencies": {
+        "wildcard": "^1.1.0"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
+      "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/mitt": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+      "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mlly": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.7.4.tgz",
+      "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "pathe": "^2.0.1",
+        "pkg-types": "^1.3.0",
+        "ufo": "^1.5.4"
+      }
+    },
+    "node_modules/mlly/node_modules/pathe": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.2.tgz",
+      "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mrmime": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+      "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/muggle-string": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+      "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/namespace-emitter": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
+      "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==",
+      "license": "MIT"
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.8",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/next-tick": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz",
+      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+      "license": "ISC"
+    },
+    "node_modules/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+      "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nopt": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
+      "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "abbrev": "^2.0.0"
+      },
+      "bin": {
+        "nopt": "bin/nopt.js"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-wheel-es": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
+      "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/npm-normalize-package-bin": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
+      "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/npm-run-all2": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.2.tgz",
+      "integrity": "sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "cross-spawn": "^7.0.6",
+        "memorystream": "^0.3.1",
+        "minimatch": "^9.0.0",
+        "pidtree": "^0.6.0",
+        "read-package-json-fast": "^4.0.0",
+        "shell-quote": "^1.7.3",
+        "which": "^5.0.0"
+      },
+      "bin": {
+        "npm-run-all": "bin/npm-run-all/index.js",
+        "npm-run-all2": "bin/npm-run-all/index.js",
+        "run-p": "bin/run-p/index.js",
+        "run-s": "bin/run-s/index.js"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0",
+        "npm": ">= 9"
+      }
+    },
+    "node_modules/npm-run-all2/node_modules/isexe": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+      "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/npm-run-all2/node_modules/which": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
+      "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^3.1.1"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+      "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^4.0.0",
+        "unicorn-magic": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/npm-run-path/node_modules/path-key": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nwsapi": {
+      "version": "2.2.16",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz",
+      "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/open": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz",
+      "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "default-browser": "^5.2.1",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
+        "is-wsl": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0"
+    },
+    "node_modules/package-manager-detector": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-0.2.9.tgz",
+      "integrity": "sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/parse-ms": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+      "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
+      "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^4.5.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/path-browserify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/pathe": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+      "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/pathval": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/pathval/-/pathval-2.0.0.tgz",
+      "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.16"
+      }
+    },
+    "node_modules/perfect-debounce": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+      "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pidtree": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
+      "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "pidtree": "bin/pidtree.js"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/pinia": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.0.tgz",
+      "integrity": "sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-api": "^6.6.3",
+        "vue-demi": "^0.14.10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.4.4",
+        "vue": "^2.7.0 || ^3.5.11"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/pkg-types": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz",
+      "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.1.8",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.1"
+      }
+    },
+    "node_modules/pkg-types/node_modules/pathe": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.2.tgz",
+      "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/postcss": {
+      "version": "8.5.1",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
+      "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.8",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/preact": {
+      "version": "10.26.4",
+      "resolved": "https://registry.npmmirror.com/preact/-/preact-10.26.4.tgz",
+      "integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/preact"
+      }
+    },
+    "node_modules/pretty-ms": {
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
+      "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parse-ms": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/prismjs": {
+      "version": "1.29.0",
+      "resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
+      "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/proto-list": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/read-package-json-fast": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz",
+      "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "json-parse-even-better-errors": "^4.0.0",
+        "npm-normalize-package-bin": "^4.0.0"
+      },
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/readdirp/node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+      "license": "MIT"
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rfdc": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+      "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/rollup": {
+      "version": "4.31.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.31.0.tgz",
+      "integrity": "sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.6"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.31.0",
+        "@rollup/rollup-android-arm64": "4.31.0",
+        "@rollup/rollup-darwin-arm64": "4.31.0",
+        "@rollup/rollup-darwin-x64": "4.31.0",
+        "@rollup/rollup-freebsd-arm64": "4.31.0",
+        "@rollup/rollup-freebsd-x64": "4.31.0",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.31.0",
+        "@rollup/rollup-linux-arm-musleabihf": "4.31.0",
+        "@rollup/rollup-linux-arm64-gnu": "4.31.0",
+        "@rollup/rollup-linux-arm64-musl": "4.31.0",
+        "@rollup/rollup-linux-loongarch64-gnu": "4.31.0",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.31.0",
+        "@rollup/rollup-linux-riscv64-gnu": "4.31.0",
+        "@rollup/rollup-linux-s390x-gnu": "4.31.0",
+        "@rollup/rollup-linux-x64-gnu": "4.31.0",
+        "@rollup/rollup-linux-x64-musl": "4.31.0",
+        "@rollup/rollup-win32-arm64-msvc": "4.31.0",
+        "@rollup/rollup-win32-ia32-msvc": "4.31.0",
+        "@rollup/rollup-win32-x64-msvc": "4.31.0",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/rrweb-cssom": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
+      "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/run-applescript": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
+      "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/sass": {
+      "version": "1.84.0",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.84.0.tgz",
+      "integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==",
+      "license": "MIT",
+      "dependencies": {
+        "chokidar": "^4.0.0",
+        "immutable": "^5.0.2",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher": "^2.4.1"
+      }
+    },
+    "node_modules/sass/node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/sass/node_modules/readdirp": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.1.tgz",
+      "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/saxes": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+      "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "xmlchars": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=v12.22.7"
+      }
+    },
+    "node_modules/scroll-into-view-if-needed": {
+      "version": "2.2.31",
+      "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+      "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+      "license": "MIT",
+      "dependencies": {
+        "compute-scroll-into-view": "^1.0.20"
+      }
+    },
+    "node_modules/scule": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz",
+      "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/semver": {
+      "version": "7.6.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shell-quote": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz",
+      "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/siginfo": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+      "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/sirv": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
+      "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@polka/url": "^1.0.0-next.24",
+        "mrmime": "^2.0.0",
+        "totalist": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/slate": {
+      "version": "0.72.8",
+      "resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
+      "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
+      "license": "MIT",
+      "dependencies": {
+        "immer": "^9.0.6",
+        "is-plain-object": "^5.0.0",
+        "tiny-warning": "^1.0.3"
+      }
+    },
+    "node_modules/slate-history": {
+      "version": "0.66.0",
+      "resolved": "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz",
+      "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
+      "license": "MIT",
+      "dependencies": {
+        "is-plain-object": "^5.0.0"
+      },
+      "peerDependencies": {
+        "slate": ">=0.65.3"
+      }
+    },
+    "node_modules/snabbdom": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz",
+      "integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.17.0"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/speakingurl": {
+      "version": "14.0.1",
+      "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
+      "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ssr-window": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz",
+      "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==",
+      "license": "MIT"
+    },
+    "node_modules/stackback": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+      "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/std-env": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz",
+      "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/string-width-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+      "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/strip-literal": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-2.1.1.tgz",
+      "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "js-tokens": "^9.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/strip-literal/node_modules/js-tokens": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.1.tgz",
+      "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/superjson": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
+      "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "copy-anything": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/svg-tags": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+      "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
+      "dev": true
+    },
+    "node_modules/symbol-tree": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+      "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+      "license": "MIT"
+    },
+    "node_modules/tinybench": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+      "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tinyexec": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+      "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tinypool": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+      "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      }
+    },
+    "node_modules/tinyrainbow": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+      "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tinyspy": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmmirror.com/tinyspy/-/tinyspy-3.0.2.tgz",
+      "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tldts": {
+      "version": "6.1.73",
+      "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.73.tgz",
+      "integrity": "sha512-/h4bVmuEMm57c2uCiAf1Q9mlQk7cA22m+1Bu0K92vUUtTVT9D4mOFWD9r4WQuTULcG9eeZtNKhLl0Il1LdKGog==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tldts-core": "^6.1.73"
+      },
+      "bin": {
+        "tldts": "bin/cli.js"
+      }
+    },
+    "node_modules/tldts-core": {
+      "version": "6.1.73",
+      "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.73.tgz",
+      "integrity": "sha512-k1g5eX87vxu3g//6XMn62y4qjayu4cYby/PF7Ksnh4F4uUK1Z1ze/mJ4a+y5OjdJ+cXRp+YTInZhH+FGdUWy1w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "devOptional": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/totalist": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+      "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tough-cookie": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.0.tgz",
+      "integrity": "sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "tldts": "^6.1.32"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+      "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "punycode": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
+      "license": "0BSD"
+    },
+    "node_modules/type": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmmirror.com/type/-/type-2.7.3.tgz",
+      "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
+      "license": "ISC"
+    },
+    "node_modules/typescript": {
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+      "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
+      "devOptional": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/ufo": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz",
+      "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/undici-types": {
+      "version": "6.20.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+      "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/unicorn-magic": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+      "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/unimport": {
+      "version": "3.14.6",
+      "resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.14.6.tgz",
+      "integrity": "sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@rollup/pluginutils": "^5.1.4",
+        "acorn": "^8.14.0",
+        "escape-string-regexp": "^5.0.0",
+        "estree-walker": "^3.0.3",
+        "fast-glob": "^3.3.3",
+        "local-pkg": "^1.0.0",
+        "magic-string": "^0.30.17",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.1",
+        "picomatch": "^4.0.2",
+        "pkg-types": "^1.3.0",
+        "scule": "^1.3.0",
+        "strip-literal": "^2.1.1",
+        "unplugin": "^1.16.1"
+      }
+    },
+    "node_modules/unimport/node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
+    "node_modules/unimport/node_modules/local-pkg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.0.0.tgz",
+      "integrity": "sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mlly": "^1.7.3",
+        "pkg-types": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/unimport/node_modules/pathe": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.2.tgz",
+      "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/unimport/node_modules/unplugin": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.1.tgz",
+      "integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+      "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/unplugin": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-2.1.2.tgz",
+      "integrity": "sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.14.0",
+        "webpack-virtual-modules": "^0.6.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/unplugin-auto-import": {
+      "version": "19.0.0",
+      "resolved": "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-19.0.0.tgz",
+      "integrity": "sha512-TREXtXqCM6YLy3rE2tjvKZEaCiPlP2e5bmnRKaS8AM2MlNgjV7UP4RPieWIfs4Isv0GoeHmov956PIIvJYdqpQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/utils": "^0.7.10",
+        "@rollup/pluginutils": "^5.1.4",
+        "local-pkg": "^0.5.1",
+        "magic-string": "^0.30.17",
+        "picomatch": "^4.0.2",
+        "unimport": "^3.14.5",
+        "unplugin": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@nuxt/kit": "^3.2.2",
+        "@vueuse/core": "*"
+      },
+      "peerDependenciesMeta": {
+        "@nuxt/kit": {
+          "optional": true
+        },
+        "@vueuse/core": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/unplugin-icons": {
+      "version": "22.0.0",
+      "resolved": "https://registry.npmmirror.com/unplugin-icons/-/unplugin-icons-22.0.0.tgz",
+      "integrity": "sha512-+1jIt2wynxL+GISehNok8MIb9RaCufIZCHJs0HKbxOljJL9m4NtOhva+dZhNtSKtfQ62Hwd/RRbniSVuuD4Xow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/install-pkg": "^0.5.0",
+        "@antfu/utils": "^0.7.10",
+        "@iconify/utils": "^2.2.1",
+        "debug": "^4.4.0",
+        "kolorist": "^1.8.0",
+        "local-pkg": "^0.5.1",
+        "unplugin": "^2.1.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@svgr/core": ">=7.0.0",
+        "@svgx/core": "^1.0.1",
+        "@vue/compiler-sfc": "^3.0.2 || ^2.7.0",
+        "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0",
+        "vue-template-compiler": "^2.6.12",
+        "vue-template-es2015-compiler": "^1.9.0"
+      },
+      "peerDependenciesMeta": {
+        "@svgr/core": {
+          "optional": true
+        },
+        "@svgx/core": {
+          "optional": true
+        },
+        "@vue/compiler-sfc": {
+          "optional": true
+        },
+        "svelte": {
+          "optional": true
+        },
+        "vue-template-compiler": {
+          "optional": true
+        },
+        "vue-template-es2015-compiler": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/unplugin-vue-components": {
+      "version": "28.0.0",
+      "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-28.0.0.tgz",
+      "integrity": "sha512-vYe0wSyqTVhyNFIad1iiGyQGhG++tDOMgohqenMDOAooMJP9vvzCdXTqCVx20A0rCQXFNjgoRbSeDAioLPH36Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/utils": "^0.7.10",
+        "@rollup/pluginutils": "^5.1.4",
+        "chokidar": "^3.6.0",
+        "debug": "^4.4.0",
+        "fast-glob": "^3.3.3",
+        "local-pkg": "^0.5.1",
+        "magic-string": "^0.30.17",
+        "minimatch": "^9.0.5",
+        "mlly": "^1.7.3",
+        "unplugin": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@babel/parser": "^7.15.8",
+        "@nuxt/kit": "^3.2.2",
+        "vue": "2 || 3"
+      },
+      "peerDependenciesMeta": {
+        "@babel/parser": {
+          "optional": true
+        },
+        "@nuxt/kit": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/unplugin-vue-components/node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
+      "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "6.0.7",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
+      "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.24.2",
+        "postcss": "^8.4.49",
+        "rollup": "^4.23.0"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+        "jiti": ">=1.21.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-hot-client": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-0.2.4.tgz",
+      "integrity": "sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0"
+      }
+    },
+    "node_modules/vite-node": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/vite-node/-/vite-node-2.1.9.tgz",
+      "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cac": "^6.7.14",
+        "debug": "^4.3.7",
+        "es-module-lexer": "^1.5.4",
+        "pathe": "^1.1.2",
+        "vite": "^5.0.0"
+      },
+      "bin": {
+        "vite-node": "vite-node.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/android-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/android-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/android-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/darwin-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-loong64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-s390x": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/linux-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/sunos-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/win32-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/win32-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/@esbuild/win32-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vite-node/node_modules/esbuild": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
+      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.21.5",
+        "@esbuild/android-arm": "0.21.5",
+        "@esbuild/android-arm64": "0.21.5",
+        "@esbuild/android-x64": "0.21.5",
+        "@esbuild/darwin-arm64": "0.21.5",
+        "@esbuild/darwin-x64": "0.21.5",
+        "@esbuild/freebsd-arm64": "0.21.5",
+        "@esbuild/freebsd-x64": "0.21.5",
+        "@esbuild/linux-arm": "0.21.5",
+        "@esbuild/linux-arm64": "0.21.5",
+        "@esbuild/linux-ia32": "0.21.5",
+        "@esbuild/linux-loong64": "0.21.5",
+        "@esbuild/linux-mips64el": "0.21.5",
+        "@esbuild/linux-ppc64": "0.21.5",
+        "@esbuild/linux-riscv64": "0.21.5",
+        "@esbuild/linux-s390x": "0.21.5",
+        "@esbuild/linux-x64": "0.21.5",
+        "@esbuild/netbsd-x64": "0.21.5",
+        "@esbuild/openbsd-x64": "0.21.5",
+        "@esbuild/sunos-x64": "0.21.5",
+        "@esbuild/win32-arm64": "0.21.5",
+        "@esbuild/win32-ia32": "0.21.5",
+        "@esbuild/win32-x64": "0.21.5"
+      }
+    },
+    "node_modules/vite-node/node_modules/vite": {
+      "version": "5.4.14",
+      "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.14.tgz",
+      "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.21.3",
+        "postcss": "^8.4.43",
+        "rollup": "^4.20.0"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-plugin-inspect": {
+      "version": "0.8.9",
+      "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz",
+      "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@antfu/utils": "^0.7.10",
+        "@rollup/pluginutils": "^5.1.3",
+        "debug": "^4.3.7",
+        "error-stack-parser-es": "^0.1.5",
+        "fs-extra": "^11.2.0",
+        "open": "^10.1.0",
+        "perfect-debounce": "^1.0.0",
+        "picocolors": "^1.1.1",
+        "sirv": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1"
+      },
+      "peerDependenciesMeta": {
+        "@nuxt/kit": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-plugin-vue-devtools": {
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.7.0.tgz",
+      "integrity": "sha512-1dWiREwIl4JELwXGHXih80hIgjcViMcZGr3j0edo6NQ9kNzAOxMIUgFqc/TO1ary4ZroJUxoB0YDI6jnDf13iQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-core": "^7.7.0",
+        "@vue/devtools-kit": "^7.7.0",
+        "@vue/devtools-shared": "^7.7.0",
+        "execa": "^9.5.1",
+        "sirv": "^3.0.0",
+        "vite-plugin-inspect": "0.8.9",
+        "vite-plugin-vue-inspector": "^5.3.1"
+      },
+      "engines": {
+        "node": ">=v14.21.3"
+      },
+      "peerDependencies": {
+        "vite": "^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-vue-inspector": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.1.tgz",
+      "integrity": "sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "^7.23.0",
+        "@babel/plugin-proposal-decorators": "^7.23.0",
+        "@babel/plugin-syntax-import-attributes": "^7.22.5",
+        "@babel/plugin-syntax-import-meta": "^7.10.4",
+        "@babel/plugin-transform-typescript": "^7.22.15",
+        "@vue/babel-plugin-jsx": "^1.1.5",
+        "@vue/compiler-dom": "^3.3.4",
+        "kolorist": "^1.8.0",
+        "magic-string": "^0.30.4"
+      },
+      "peerDependencies": {
+        "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0"
+      }
+    },
+    "node_modules/vitest": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/vitest/-/vitest-2.1.9.tgz",
+      "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/expect": "2.1.9",
+        "@vitest/mocker": "2.1.9",
+        "@vitest/pretty-format": "^2.1.9",
+        "@vitest/runner": "2.1.9",
+        "@vitest/snapshot": "2.1.9",
+        "@vitest/spy": "2.1.9",
+        "@vitest/utils": "2.1.9",
+        "chai": "^5.1.2",
+        "debug": "^4.3.7",
+        "expect-type": "^1.1.0",
+        "magic-string": "^0.30.12",
+        "pathe": "^1.1.2",
+        "std-env": "^3.8.0",
+        "tinybench": "^2.9.0",
+        "tinyexec": "^0.3.1",
+        "tinypool": "^1.0.1",
+        "tinyrainbow": "^1.2.0",
+        "vite": "^5.0.0",
+        "vite-node": "2.1.9",
+        "why-is-node-running": "^2.3.0"
+      },
+      "bin": {
+        "vitest": "vitest.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "@edge-runtime/vm": "*",
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "@vitest/browser": "2.1.9",
+        "@vitest/ui": "2.1.9",
+        "happy-dom": "*",
+        "jsdom": "*"
+      },
+      "peerDependenciesMeta": {
+        "@edge-runtime/vm": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@vitest/browser": {
+          "optional": true
+        },
+        "@vitest/ui": {
+          "optional": true
+        },
+        "happy-dom": {
+          "optional": true
+        },
+        "jsdom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/aix-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/android-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/android-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/android-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/darwin-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/darwin-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/freebsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-loong64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-mips64el": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-riscv64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-s390x": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/linux-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/netbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/openbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/sunos-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/win32-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/win32-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@esbuild/win32-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/vitest/node_modules/@vitest/mocker": {
+      "version": "2.1.9",
+      "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-2.1.9.tgz",
+      "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/spy": "2.1.9",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.12"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "msw": "^2.4.9",
+        "vite": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "msw": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/esbuild": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
+      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.21.5",
+        "@esbuild/android-arm": "0.21.5",
+        "@esbuild/android-arm64": "0.21.5",
+        "@esbuild/android-x64": "0.21.5",
+        "@esbuild/darwin-arm64": "0.21.5",
+        "@esbuild/darwin-x64": "0.21.5",
+        "@esbuild/freebsd-arm64": "0.21.5",
+        "@esbuild/freebsd-x64": "0.21.5",
+        "@esbuild/linux-arm": "0.21.5",
+        "@esbuild/linux-arm64": "0.21.5",
+        "@esbuild/linux-ia32": "0.21.5",
+        "@esbuild/linux-loong64": "0.21.5",
+        "@esbuild/linux-mips64el": "0.21.5",
+        "@esbuild/linux-ppc64": "0.21.5",
+        "@esbuild/linux-riscv64": "0.21.5",
+        "@esbuild/linux-s390x": "0.21.5",
+        "@esbuild/linux-x64": "0.21.5",
+        "@esbuild/netbsd-x64": "0.21.5",
+        "@esbuild/openbsd-x64": "0.21.5",
+        "@esbuild/sunos-x64": "0.21.5",
+        "@esbuild/win32-arm64": "0.21.5",
+        "@esbuild/win32-ia32": "0.21.5",
+        "@esbuild/win32-x64": "0.21.5"
+      }
+    },
+    "node_modules/vitest/node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
+    "node_modules/vitest/node_modules/vite": {
+      "version": "5.4.14",
+      "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.14.tgz",
+      "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.21.3",
+        "postcss": "^8.4.43",
+        "rollup": "^4.20.0"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vscode-uri": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
+      "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vue": {
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
+      "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.13",
+        "@vue/compiler-sfc": "3.5.13",
+        "@vue/runtime-dom": "3.5.13",
+        "@vue/server-renderer": "3.5.13",
+        "@vue/shared": "3.5.13"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-component-type-helpers": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.0.tgz",
+      "integrity": "sha512-cYrAnv2me7bPDcg9kIcGwjJiSB6Qyi08+jLDo9yuvoFQjzHiPTzML7RnkJB1+3P6KMsX/KbCD4QE3Tv/knEllw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vue-demi": {
+      "version": "0.14.10",
+      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-echarts": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmmirror.com/vue-echarts/-/vue-echarts-7.0.3.tgz",
+      "integrity": "sha512-/jSxNwOsw5+dYAUcwSfkLwKPuzTQ0Cepz1LxCOpj2QcHrrmUa/Ql0eQqMmc1rTPQVrh2JQ29n2dhq75ZcHvRDw==",
+      "license": "MIT",
+      "dependencies": {
+        "vue-demi": "^0.13.11"
+      },
+      "peerDependencies": {
+        "@vue/runtime-core": "^3.0.0",
+        "echarts": "^5.5.1",
+        "vue": "^2.7.0 || ^3.1.1"
+      },
+      "peerDependenciesMeta": {
+        "@vue/runtime-core": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-echarts/node_modules/vue-demi": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
+      "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "vue-demi-fix": "bin/vue-demi-fix.js",
+        "vue-demi-switch": "bin/vue-demi-switch.js"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      },
+      "peerDependencies": {
+        "@vue/composition-api": "^1.0.0-rc.1",
+        "vue": "^3.0.0-0 || ^2.6.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-leaflet": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/vue-leaflet/-/vue-leaflet-0.1.0.tgz",
+      "integrity": "sha512-J2QxmQSbmnpM/Ng+C8vxowXcWp/IEe99r87psHyWYpBz2nbxkQAeYXW7WFcgzV4O7d7Vm4a1GcqKzrU9DeDpBA==",
+      "license": "MIT"
+    },
+    "node_modules/vue-router": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz",
+      "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-api": "^6.6.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "vue": "^3.2.0"
+      }
+    },
+    "node_modules/vue-tsc": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.0.tgz",
+      "integrity": "sha512-gtmM1sUuJ8aSb0KoAFmK9yMxb8TxjewmxqTJ1aKphD5Cbu0rULFY6+UQT51zW7SpUcenfPUuflKyVwyx9Qdnxg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@volar/typescript": "~2.4.11",
+        "@vue/language-core": "2.2.0"
+      },
+      "bin": {
+        "vue-tsc": "bin/vue-tsc.js"
+      },
+      "peerDependencies": {
+        "typescript": ">=5.0.0"
+      }
+    },
+    "node_modules/w3c-xmlserializer": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+      "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "xml-name-validator": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+      "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/webpack-virtual-modules": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+      "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/whatwg-encoding": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "0.6.3"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/whatwg-url": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz",
+      "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "^5.0.0",
+        "webidl-conversions": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/why-is-node-running": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+      "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "siginfo": "^2.0.0",
+        "stackback": "0.0.2"
+      },
+      "bin": {
+        "why-is-node-running": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wildcard": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
+      "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==",
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ws": {
+      "version": "8.18.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xml-name-validator": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+      "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/xmlchars": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+      "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yoctocolors": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz",
+      "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zrender": {
+      "version": "5.6.1",
+      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz",
+      "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "tslib": "2.3.0"
+      }
+    }
+  }
+}

+ 51 - 0
package.json

@@ -0,0 +1,51 @@
+{
+  "name": "vue_soil",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "run-p type-check \"build-only {@}\" --",
+    "preview": "vite preview",
+    "test:unit": "vitest",
+    "build-only": "vite build",
+    "type-check": "vue-tsc --build"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^5.1.12",
+    "axios": "^1.7.9",
+    "echarts": "^5.6.0",
+    "echarts-gl": "^2.0.9",
+    "element-plus": "^2.9.3",
+    "leaflet": "^1.9.4",
+    "pinia": "^2.3.0",
+    "sass": "^1.84.0",
+    "vue": "^3.5.13",
+    "vue-echarts": "^7.0.3",
+    "vue-leaflet": "^0.1.0",
+    "vue-router": "^4.5.0"
+  },
+  "devDependencies": {
+    "@iconify-json/ep": "^1.2.2",
+    "@tsconfig/node22": "^22.0.0",
+    "@types/jsdom": "^21.1.7",
+    "@types/leaflet": "^1.9.16",
+    "@types/node": "^22.13.8",
+    "@types/vue": "^2.0.0",
+    "@vitejs/plugin-vue": "^5.2.1",
+    "@vue/test-utils": "^2.4.6",
+    "@vue/tsconfig": "^0.7.0",
+    "jsdom": "^25.0.1",
+    "npm-run-all2": "^7.0.2",
+    "typescript": "~5.6.3",
+    "unplugin-auto-import": "^19.0.0",
+    "unplugin-icons": "^22.0.0",
+    "unplugin-vue-components": "^28.0.0",
+    "vite": "^6.0.5",
+    "vite-plugin-vue-devtools": "^7.6.8",
+    "vitest": "^2.1.9",
+    "vue-tsc": "^2.1.10"
+  }
+}

+ 28 - 0
project.config.json

@@ -0,0 +1,28 @@
+{
+  "appid": "wxc75e060d54a6f54c",
+  "compileType": "miniprogram",
+  "libVersion": "3.7.8",
+  "packOptions": {
+    "ignore": [],
+    "include": []
+  },
+  "setting": {
+    "coverView": true,
+    "es6": true,
+    "postcss": true,
+    "minified": true,
+    "enhance": true,
+    "showShadowRootInWxmlPanel": true,
+    "packNpmRelationList": [],
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    }
+  },
+  "condition": {},
+  "editorSetting": {
+    "tabIndent": "insertSpaces",
+    "tabSize": 2
+  }
+}

+ 7 - 0
project.private.config.json

@@ -0,0 +1,7 @@
+{
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "projectname": "soilgd",
+  "setting": {
+    "compileHotReLoad": true
+  }
+}

BIN
public/favicon.ico


BIN
public/默认头像.png


+ 116 - 0
src/API/menus.ts

@@ -0,0 +1,116 @@
+import request from "@/utils/request";
+
+// 使用导入的 request 函数进行网络请求
+export const table = (params: { table: string }) => {
+  return request({
+    url: "/table",
+    method: "POST",
+    data: params,
+  });
+};
+
+const customRequest = (options: any) => {
+  return request(options)
+    .then(response => response.data)
+    .catch(error => {
+      if (error.response && error.response.status === 409) {
+        console.error('数据重复:', error.response.data);
+        throw new Error('数据重复,请重新添加');
+      } else {
+        console.error(`请求失败: ${error.message || '未知错误'}`);
+        throw new Error(`请求失败: ${error.message || '未知错误'}`);
+      }
+    });
+};
+
+export const updateItem = (data: { table: string, item: any }) => {
+  return customRequest({
+    url: "/update_item",
+    method: "PUT",
+    data: data,
+  });
+};
+
+export const addItem = (data: { table: string, item: any }) => {
+  return customRequest({
+    url: "/add_item",
+    method: "POST",
+    data: data,
+  }).catch(error => {
+    if (error.message.includes("数据重复")) {
+      alert(error.message); 
+    }
+    throw error; 
+  });
+};
+
+export const deleteItemApi = (params: { table: string; condition: any }) => {
+  const conditionString = `${Object.keys(params.condition)[0]}=${params.condition[Object.keys(params.condition)[0]]}`;
+  return customRequest({
+    url: "/delete_item",
+    method: "POST",
+    data: {
+      table: params.table,
+      condition: conditionString,
+    },
+  });
+};
+
+export const downloadTemplate = (table: string, format: string = 'xlsx') => {
+  return customRequest({
+    url: "/download_template",
+    method: "GET",
+    params: { table, format },
+    responseType: 'blob',
+  }).then(response => {
+    const blob = new Blob([response], {
+      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = `${table}_template.${format}`;
+    link.click();
+    window.URL.revokeObjectURL(url);
+  });
+};
+
+export const exportData = (table: string, format: string = 'excel') => {
+  const backendFormat = format.toLowerCase() === 'xlsx' ? 'excel' : format;
+
+  return customRequest({
+    url: "/export_data",
+    method: "GET",
+    params: { table, format: backendFormat },
+    responseType: 'blob',
+  }).then(response => {
+    const blob = new Blob([response], {
+      type: backendFormat === 'excel' 
+        ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 
+        : 'text/csv',
+    });
+    const url = window.URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = `${table}_data.${backendFormat === 'excel' ? 'xlsx' : 'csv'}`;
+    link.click();
+    window.URL.revokeObjectURL(url);
+  }).catch(error => {
+    console.error('导出数据时发生错误:', error);
+    throw error;
+  });
+};
+
+export const importData = (table: string, file: File) => {
+  const formData = new FormData();
+  formData.append('file', file);
+  formData.append('table', table);
+  return customRequest({
+    url: "/import_data",
+    method: "POST",
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data',
+    },
+  });
+};

+ 44 - 0
src/API/users.ts

@@ -0,0 +1,44 @@
+import request from "@/utils/request";
+
+// 定义登录信息的类型
+type LoginInfo = {
+  name: string; // 用户名
+  password: string; // 密码
+};
+
+export const login = (loginInfo: LoginInfo) => {
+  return request({
+    url: "/login",
+    method: "POST",
+    data: {
+      name: loginInfo.name,
+      password: loginInfo.password
+    }
+  });
+};
+
+// 定义 token 接口
+type userInfo = {
+  content: {
+  userid: string
+  name: string
+}
+}
+
+export const logout = () => {
+  return request({
+    method: 'POST',
+    url:'/logout',
+  })
+}
+
+export const register = (registerInfo: { name: any; password: any; }) => {
+  return request({
+    url: "/register",
+    method: "POST",
+    data: {
+      name: registerInfo.name,
+      password: registerInfo.password
+    }
+  });
+};

+ 16 - 0
src/App.vue

@@ -0,0 +1,16 @@
+<script setup lang='ts'>
+import { RouterView } from "vue-router"
+import request from './utils/request';
+request({
+  url: '/table',
+  method: 'get'
+}).then(res => {
+  console.log(res)
+})
+</script>
+
+<template>
+  <RouterView />
+</template>
+
+<style scoped></style>

+ 86 - 0
src/assets/base.css

@@ -0,0 +1,86 @@
+/* color palette from <https://github.com/vuejs/theme> */
+:root {
+  --vt-c-white: #ffffff;
+  --vt-c-white-soft: #f8f8f8;
+  --vt-c-white-mute: #f2f2f2;
+
+  --vt-c-black: #181818;
+  --vt-c-black-soft: #222222;
+  --vt-c-black-mute: #282828;
+
+  --vt-c-indigo: #2c3e50;
+
+  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
+  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
+  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
+  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
+
+  --vt-c-text-light-1: var(--vt-c-indigo);
+  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
+  --vt-c-text-dark-1: var(--vt-c-white);
+  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+}
+
+/* semantic color variables for this project */
+:root {
+  --color-background: var(--vt-c-white);
+  --color-background-soft: var(--vt-c-white-soft);
+  --color-background-mute: var(--vt-c-white-mute);
+
+  --color-border: var(--vt-c-divider-light-2);
+  --color-border-hover: var(--vt-c-divider-light-1);
+
+  --color-heading: var(--vt-c-text-light-1);
+  --color-text: var(--vt-c-text-light-1);
+
+  --section-gap: 160px;
+}
+
+@media (prefers-color-scheme: dark) {
+  :root {
+    --color-background: var(--vt-c-black);
+    --color-background-soft: var(--vt-c-black-soft);
+    --color-background-mute: var(--vt-c-black-mute);
+
+    --color-border: var(--vt-c-divider-dark-2);
+    --color-border-hover: var(--vt-c-divider-dark-1);
+
+    --color-heading: var(--vt-c-text-dark-1);
+    --color-text: var(--vt-c-text-dark-2);
+  }
+}
+
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+  margin: 0;
+  font-weight: normal;
+}
+
+body {
+  min-height: 100vh;
+  color: var(--color-text);
+  background: var(--color-background);
+  transition:
+    color 0.5s,
+    background-color 0.5s;
+  line-height: 1.6;
+  font-family:
+    Inter,
+    -apple-system,
+    BlinkMacSystemFont,
+    'Segoe UI',
+    Roboto,
+    Oxygen,
+    Ubuntu,
+    Cantarell,
+    'Fira Sans',
+    'Droid Sans',
+    'Helvetica Neue',
+    sans-serif;
+  font-size: 15px;
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}

+ 1 - 0
src/assets/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>

+ 4 - 0
src/assets/main.scss

@@ -0,0 +1,4 @@
+* {
+  padding:0;
+  margin:0
+}

+ 41 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,41 @@
+<script setup lang="ts">
+defineProps<{
+  msg: string
+}>()
+</script>
+
+<template>
+  <div class="greetings">
+    <h1 class="green">{{ msg }}</h1>
+    <h3>
+      You’ve successfully created a project with
+      <a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
+      <a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
+    </h3>
+  </div>
+</template>
+
+<style scoped>
+h1 {
+  font-weight: 500;
+  font-size: 2.6rem;
+  position: relative;
+  top: -10px;
+}
+
+h3 {
+  font-size: 1.2rem;
+}
+
+.greetings h1,
+.greetings h3 {
+  text-align: center;
+}
+
+@media (min-width: 1024px) {
+  .greetings h1,
+  .greetings h3 {
+    text-align: left;
+  }
+}
+</style>

+ 94 - 0
src/components/TheWelcome.vue

@@ -0,0 +1,94 @@
+<script setup lang="ts">
+import WelcomeItem from './WelcomeItem.vue'
+import DocumentationIcon from './icons/IconDocumentation.vue'
+import ToolingIcon from './icons/IconTooling.vue'
+import EcosystemIcon from './icons/IconEcosystem.vue'
+import CommunityIcon from './icons/IconCommunity.vue'
+import SupportIcon from './icons/IconSupport.vue'
+
+const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
+</script>
+
+<template>
+  <WelcomeItem>
+    <template #icon>
+      <DocumentationIcon />
+    </template>
+    <template #heading>Documentation</template>
+
+    Vue’s
+    <a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
+    provides you with all information you need to get started.
+  </WelcomeItem>
+
+  <WelcomeItem>
+    <template #icon>
+      <ToolingIcon />
+    </template>
+    <template #heading>Tooling</template>
+
+    This project is served and bundled with
+    <a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
+    recommended IDE setup is
+    <a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
+    +
+    <a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
+    you need to test your components and web pages, check out
+    <a href="https://vitest.dev/" target="_blank" rel="noopener">Vite</a>
+    and
+    <a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
+    /
+    <a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
+
+    <br />
+
+    More instructions are available in
+    <a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
+    >.
+  </WelcomeItem>
+
+  <WelcomeItem>
+    <template #icon>
+      <EcosystemIcon />
+    </template>
+    <template #heading>Ecosystem</template>
+
+    Get official tools and libraries for your project:
+    <a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
+    <a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
+    <a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
+    <a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
+    you need more resources, we suggest paying
+    <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
+    a visit.
+  </WelcomeItem>
+
+  <WelcomeItem>
+    <template #icon>
+      <CommunityIcon />
+    </template>
+    <template #heading>Community</template>
+
+    Got stuck? Ask your question on
+    <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
+    (our official Discord server), or
+    <a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
+      >StackOverflow</a
+    >. You should also follow the official
+    <a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
+    Bluesky account or the
+    <a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
+    X account for latest news in the Vue world.
+  </WelcomeItem>
+
+  <WelcomeItem>
+    <template #icon>
+      <SupportIcon />
+    </template>
+    <template #heading>Support Vue</template>
+
+    As an independent project, Vue relies on community backing for its sustainability. You can help
+    us by
+    <a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
+  </WelcomeItem>
+</template>

+ 87 - 0
src/components/WelcomeItem.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="item">
+    <i>
+      <slot name="icon"></slot>
+    </i>
+    <div class="details">
+      <h3>
+        <slot name="heading"></slot>
+      </h3>
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<style scoped>
+.item {
+  margin-top: 2rem;
+  display: flex;
+  position: relative;
+}
+
+.details {
+  flex: 1;
+  margin-left: 1rem;
+}
+
+i {
+  display: flex;
+  place-items: center;
+  place-content: center;
+  width: 32px;
+  height: 32px;
+
+  color: var(--color-text);
+}
+
+h3 {
+  font-size: 1.2rem;
+  font-weight: 500;
+  margin-bottom: 0.4rem;
+  color: var(--color-heading);
+}
+
+@media (min-width: 1024px) {
+  .item {
+    margin-top: 0;
+    padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
+  }
+
+  i {
+    top: calc(50% - 25px);
+    left: -26px;
+    position: absolute;
+    border: 1px solid var(--color-border);
+    background: var(--color-background);
+    border-radius: 8px;
+    width: 50px;
+    height: 50px;
+  }
+
+  .item:before {
+    content: ' ';
+    border-left: 1px solid var(--color-border);
+    position: absolute;
+    left: 0;
+    bottom: calc(50% + 25px);
+    height: calc(50% - 25px);
+  }
+
+  .item:after {
+    content: ' ';
+    border-left: 1px solid var(--color-border);
+    position: absolute;
+    left: 0;
+    top: calc(50% + 25px);
+    height: calc(50% - 25px);
+  }
+
+  .item:first-of-type:before {
+    display: none;
+  }
+
+  .item:last-of-type:after {
+    display: none;
+  }
+}
+</style>

+ 11 - 0
src/components/__tests__/HelloWorld.spec.ts

@@ -0,0 +1,11 @@
+import { describe, it, expect } from 'vitest'
+
+import { mount } from '@vue/test-utils'
+import HelloWorld from '../HelloWorld.vue'
+
+describe('HelloWorld', () => {
+  it('renders properly', () => {
+    const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
+    expect(wrapper.text()).toContain('Hello Vitest')
+  })
+})

+ 7 - 0
src/components/icons/IconCommunity.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
+    <path
+      d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconDocumentation.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
+    <path
+      d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconEcosystem.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
+    <path
+      d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
+    />
+  </svg>
+</template>

+ 7 - 0
src/components/icons/IconSupport.vue

@@ -0,0 +1,7 @@
+<template>
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
+    <path
+      d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
+    />
+  </svg>
+</template>

+ 19 - 0
src/components/icons/IconTooling.vue

@@ -0,0 +1,19 @@
+<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
+<template>
+  <svg
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+    aria-hidden="true"
+    role="img"
+    class="iconify iconify--mdi"
+    width="24"
+    height="24"
+    preserveAspectRatio="xMidYMid meet"
+    viewBox="0 0 24 24"
+  >
+    <path
+      d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
+      fill="currentColor"
+    ></path>
+  </svg>
+</template>

+ 130 - 0
src/components/layout/AppAside.vue

@@ -0,0 +1,130 @@
+<script setup lang='ts'>
+import { Setting as FolderAdd, DataLine, TrendCharts, Coordinate, DocumentAdd } from '@element-plus/icons-vue';
+import { isCollapse } from "./isCollapse";
+</script>
+
+<template>
+  <el-aside>
+    <el-scrollbar>
+      <el-menu router unique-opened :collapse="isCollapse">
+        <a href="/" class="logo">
+          <img src="@/assets/logo.svg" alt="">
+          <h1>土壤酸化模型</h1>
+        </a>
+        <el-sub-menu index="1">
+          <template #title>
+            <el-icon><DataLine /></el-icon><span>介绍</span>
+          </template>
+          <el-menu-item index="/SoilPro">软件简介</el-menu-item>
+          <el-menu-item index="/Overview">项目简介</el-menu-item>
+          <el-menu-item index="/ResearchFindings">研究成果</el-menu-item>
+          <el-menu-item index="/Unit">团队信息</el-menu-item>
+          <el-menu-item index="/IntroductionUpdate">更新介绍</el-menu-item>
+        </el-sub-menu>
+        <el-sub-menu index="2">
+          <template #title>
+            <el-icon><TrendCharts /></el-icon><span>反酸模型</span>
+          </template>
+          <el-menu-item index="/Calculation">反酸模型计算</el-menu-item>
+          <el-menu-item index="/SoilAcidReductionIterativeEvolution">反酸模型迭代可视化</el-menu-item>
+        </el-sub-menu>
+        <el-sub-menu index="3">
+          <template #title>
+            <el-icon><DocumentAdd /></el-icon><span>降酸模型</span>
+          </template>
+          <el-menu-item index="/AcidNeutralizationModel">降酸模型计算</el-menu-item>
+          <el-menu-item index="/SoilAcidificationIterativeEvolution">降酸模型迭代可视化</el-menu-item>
+        </el-sub-menu>
+        <el-menu-item index="/mapView">
+          <el-icon><Coordinate /></el-icon><span>地图展示</span>
+        </el-menu-item>
+      </el-menu>
+    </el-scrollbar>
+  </el-aside>
+</template>
+
+<style lang="scss" scoped>
+.el-aside {
+  background-color: #e9e9eb;
+  height: 100vh;
+  width: auto;
+
+  .el-scrollbar__wrap {
+    overflow-x: hidden; // 隐藏水平滚动条
+  }
+}
+
+.el-menu {
+  background-color: #e9e9eb;
+  border-right: none;
+  width: 200px;
+  white-space: nowrap;
+
+  // 设置菜单项文字颜色为黑色,点击(选中)时变为绿色
+  .el-menu-item,
+  .el-sub-menu__title {
+    color: black; // 正常状态下的文字颜色
+
+    &:hover {
+      color: #2ecc71; // 鼠标悬停时的文字颜色
+    }
+  }
+
+  // 设置选中菜单项的文字颜色为同等颜色的绿色
+  .el-menu-item.is-active {
+    color: #2ecc71; // 选中状态下的文字颜色
+  }
+
+  &.el-menu--collapse {
+    width: 64px;
+
+    // 完全隐藏子菜单和菜单项中的文字
+    span {
+      display: none;
+    }
+
+    // 当鼠标悬停时显示文字
+    .el-menu-item:hover > span,
+    .el-sub-menu:hover > .el-sub-menu__title > span {
+      display: inline;
+    }
+
+    // 确保图标大小适应折叠状态
+    .el-icon {
+      margin-right: 0;
+    }
+
+    // 隐藏logo中的标题
+    h1 {
+      display: none;
+    }
+  }
+
+  // 确保非折叠状态下菜单项的文字显示正常
+  &:not(.el-menu--collapse) {
+    span {
+      display: inline;
+    }
+  }
+}
+
+.logo {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 60px;
+  text-decoration: none;
+  color: black;
+
+  img {
+    width: 32px;
+    height: 32px;
+    margin-right: 8px; // 增加图片与标题之间的间距
+  }
+
+  h1 {
+    display: inline-block;
+    margin: 0;
+  }
+}
+</style>

+ 122 - 0
src/components/layout/AppAsideForTab2.vue

@@ -0,0 +1,122 @@
+<template>
+  <el-aside>
+    <el-scrollbar style="height: 100vh;">
+      <el-menu
+        router
+        unique-opened
+        :collapse="isCollapse"
+        :collapse-transition="false"
+      >
+        <a href="/" class="logo">
+          <img src="@/assets/logo.svg" alt="" />
+          <h1>土壤酸化模型</h1>
+        </a>
+        <el-sub-menu index="1">
+          <template #title>
+            <el-icon><DataLine /></el-icon><span>参数配置</span>
+          </template>
+          <el-menu-item index="/ModelSelection">模型选择</el-menu-item>
+          <el-menu-item index="/thres">阈值选择</el-menu-item>
+          <el-menu-item index="/ModelTrain">模型训练</el-menu-item>
+        </el-sub-menu>
+        <el-menu-item index="/Visualization">
+          <el-icon><Coordinate /></el-icon><span>反酸数据管理</span>
+        </el-menu-item>
+        <el-menu-item index="/Visualizatio">
+          <el-icon><Coordinate /></el-icon><span>降酸数据管理</span>
+        </el-menu-item>
+      </el-menu>
+    </el-scrollbar>
+  </el-aside>
+</template>
+
+<script setup lang="ts">
+import { DataLine, Coordinate } from '@element-plus/icons-vue';
+import { isCollapse } from "./isCollapse";
+</script>
+
+<style lang="scss" scoped>
+.el-aside {
+  background-color: #e9e9eb;
+  height: 100vh;
+  width: auto;
+
+  .el-scrollbar__wrap {
+    overflow-x: hidden; // 隐藏水平滚动条
+  }
+}
+
+.el-menu {
+  background-color: #e9e9eb;
+  border-right: none;
+  width: 200px;
+  white-space: nowrap;
+
+  // 设置菜单项文字颜色为黑色,点击(选中)时变为绿色
+  .el-menu-item,
+  .el-sub-menu__title {
+    color: black; // 正常状态下的文字颜色
+
+    &:hover {
+      color: #2ecc71; // 鼠标悬停时的文字颜色
+    }
+  }
+
+  // 设置选中菜单项的文字颜色为同等颜色的绿色
+  .el-menu-item.is-active {
+    color: #2ecc71; // 选中状态下的文字颜色
+  }
+
+  &.el-menu--collapse {
+    width: 64px;
+
+    // 完全隐藏子菜单和菜单项中的文字
+    span {
+      display: none;
+    }
+
+    // 当鼠标悬停时显示文字
+    .el-menu-item:hover > span,
+    .el-sub-menu:hover > .el-sub-menu__title > span {
+      display: inline;
+    }
+
+    // 确保图标大小适应折叠状态
+    .el-icon {
+      margin-right: 0;
+    }
+
+    // 隐藏logo中的标题
+    h1 {
+      display: none;
+    }
+  }
+
+  // 确保非折叠状态下菜单项的文字显示正常
+  &:not(.el-menu--collapse) {
+    span {
+      display: inline;
+    }
+  }
+}
+
+.logo {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 60px;
+  text-decoration: none;
+  color: black;
+
+  img {
+    width: 32px;
+    height: 32px;
+    margin-right: 8px; // 增加图片与标题之间的间距
+  }
+
+  h1 {
+    display: inline-block;
+    margin: 0;
+  }
+}
+</style>

+ 187 - 0
src/components/layout/AppHeader.vue

@@ -0,0 +1,187 @@
+<script setup lang="ts">
+import { reactive, computed, inject, type Ref } from 'vue';
+import { Expand, Fold, ArrowDown } from '@element-plus/icons-vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { useTokenStore } from '@/stores/mytoken';
+import { logout } from '@/API/users';  // 确保路径与实际存储位置匹配
+import router from '@/router';
+
+// 获取 tokenStore 实例
+const tokenStore = useTokenStore();
+
+// 从 store 中解构出 userid 和 name 来初始化 userInfo
+const userInfo = reactive({
+  name: tokenStore.token.name,
+  userid: tokenStore.token.userid,
+  loginType: tokenStore.token.loginType || 'password', // 默认为密码登录
+});
+
+// 注入 isCollapse 值
+const isCollapse = inject<Ref<boolean>>('isCollapse');
+if (!isCollapse) {
+  throw new Error('isCollapse was not provided by a parent component.');
+}
+
+const props = defineProps<{
+  currentProject: string;
+}>();
+const emit = defineEmits(['switch-project']);
+
+// 计算属性:决定是否显示管理员控制相关UI
+const showAdminControls = computed(() => userInfo.loginType === 'password');
+
+const toggleSidebar = () => {
+  if (isCollapse !== undefined) { // 防止未定义的 isCollapse 导致运行时错误
+    isCollapse.value = !isCollapse.value;
+  }
+};
+
+const switchProject = (projectName: string) => {
+  emit('switch-project', projectName);
+};
+
+const handleLogout = async () => {
+  await ElMessageBox.confirm("确认退出", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: 'warning'
+  }).then(async () => {
+    try {
+      await logout();
+      ElMessage.success("退出成功");
+      
+      // 使用已经获取的 tokenStore 实例
+      tokenStore.clearToken(); // 假设 clearToken 已经在 store 中定义
+      router.push({name: "login"});
+    } catch (error) {
+      console.error('Logout failed:', error);
+      ElMessage.error("退出失败");
+    }
+  }).catch(() => {
+    ElMessage.info("退出操作已取消");
+  });
+};
+</script>
+
+<template>
+  <el-header>
+    <div class="header-content">
+      <!-- 展开/折叠侧边栏 -->
+      <el-icon @click="toggleSidebar" class="toggle-icon">
+        <component :is="isCollapse ? Expand : Fold" />
+      </el-icon>
+      <!-- 仅在密码登录时显示项目选择按钮组 -->
+      <div v-if="showAdminControls" class="project-buttons">
+        <el-button link @click="switchProject('project1')" :class="{ 'active': currentProject === 'project1' }">
+          用户管理
+        </el-button>
+        <el-button link @click="switchProject('project2')" :class="{ 'active': currentProject === 'project2' }">
+          管理员管理
+        </el-button>
+      </div>
+
+      <!-- 仅在密码登录时显示下拉框 -->
+      <el-dropdown >
+        <span class="el-dropdown-link">
+          <el-avatar 
+            :size="32"
+            :src="'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'"
+          />
+          <el-icon class="el-icon--right">
+            <ArrowDown />
+          </el-icon>
+        </span>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item>{{ userInfo.name }}</el-dropdown-item>
+            <el-dropdown-item divided @click="handleLogout">退出</el-dropdown-item>
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
+    </div>
+
+    <!-- 面包屑导航 -->
+    <el-breadcrumb separator="/" class="breadcrumb">
+      <el-breadcrumb-item v-for="(item, index) in $route.matched.filter(route => route.meta && !route.meta.hiddenBreadcrumb)" :key="index" :to="{ path: item.path }">
+        {{ item.meta.title }}
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+  </el-header>
+</template>
+
+<style scoped>
+/* 样式保持不变 */
+.el-header {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between; /* 确保面包屑有足够空间 */
+  align-items: stretch; /* 让子元素占据整个宽度 */
+  background-color: #f8f9fa; /* 更柔和的背景色 */
+  padding: 10px 20px; /* 增加内边距 */
+  border-bottom: 1px solid #e5e7eb; /* 添加底部边框增加分隔感 */
+  height: auto; /* 根据内容自动调整高度 */
+}
+
+.header-content {
+  display: flex;
+  justify-content: space-between; /* 在侧边栏切换图标、项目选择按钮组和下拉框之间创建空间 */
+  align-items: center;
+  margin-bottom: 10px; /* 给header-content下方添加一些间隔,防止与面包屑重叠 */
+}
+
+/* 下拉框样式 */
+.el-dropdown {
+  margin-left: auto; /* 将下拉框推到最右侧 */
+}
+
+.el-dropdown-link {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+}
+
+.toggle-icon {
+  font-size: 1.5em; /* 增大图标尺寸 */
+  cursor: pointer;
+  color: #6b7280; /* 设置图标颜色 */
+  transition: color 0.2s ease-in-out; /* 添加颜色过渡效果 */
+}
+
+.toggle-icon:hover {
+  color: #2ECC71; /* 鼠标悬停时改变颜色 */
+}
+
+.project-buttons {
+  display: flex;
+  gap: 16px; /* 使用gap代替margin-left简化布局 */
+}
+
+.el-button {
+  font-size: 0.9rem; /* 调整字体大小 */
+  padding: 8px 12px; /* 增加填充 */
+  transition: all 0.2s ease-in-out; /* 添加平滑过渡效果 */
+}
+
+.el-button.active, .el-button:hover {
+  color: #2ECC71; /* 统一激活和悬停状态的颜色 */
+  font-weight: bold;
+  background-color: transparent; /* 确保背景透明 */
+  border-bottom: 2px solid #2ECC71; /* 添加下划线强调 */
+}
+
+.breadcrumb {
+  margin-top: 10px; /* 与上面的内容间隔 */
+  font-size: 0.875rem;
+  white-space: nowrap; /* 防止面包屑换行 */
+  overflow: hidden; /* 超出部分隐藏 */
+  text-overflow: ellipsis; /* 显示省略号 */
+  padding-bottom: 5px; /* 给面包屑下方添加一些内边距,增强视觉分离 */
+}
+
+/* 确保面包屑不会因为内容过多而撑破布局 */
+.el-breadcrumb__inner {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+</style>

+ 105 - 0
src/components/layout/AppLayout.vue

@@ -0,0 +1,105 @@
+<script setup lang='ts'>
+import { ref, provide, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import AppAside from './AppAside.vue'; // 静态导入
+import AppHeader from './AppHeader.vue'; // 静态导入
+import AppAsideForTab2 from './AppAsideForTab2.vue'; // 静态导入
+
+const isCollapse = ref(false);
+provide('isCollapse', isCollapse);
+
+const route = useRoute();
+const router = useRouter();
+
+// 项目配置,包括侧边栏组件和默认路由路径
+const projects = {
+  "project1": {
+    sidebar: AppAside, // 使用静态导入的组件
+    defaultRoute: '/SoilPro' // 默认路由路径
+  },
+  "project2": {
+    sidebar: AppAsideForTab2,
+    defaultRoute: '/Visualizatio'
+  }
+};
+
+type ProjectName = keyof typeof projects;
+const currentProject = ref<ProjectName>(route.path.includes('/project1') ? 'project2' : 'project1');
+
+function switchProject(projectName: ProjectName) {
+  currentProject.value = projectName;
+  router.push({ path: projects[projectName].defaultRoute });
+}
+
+watch(
+  () => route.path,
+  (newPath) => {
+    if (newPath === '/SoilPro') {
+      currentProject.value = 'project1';
+    } else if (newPath.startsWith('/project2')) { // 更精确地匹配project2开头的路径
+      currentProject.value = 'project2';
+    }
+  }
+);
+</script>
+
+<template>
+  <div class="common-layout">
+    <el-container style="height: 100vh;">
+      <el-aside :width="isCollapse ? '64px' : '200px'" style="background-color: #2c3e50; transition: width 0.3s;">
+        <component :is="projects[currentProject].sidebar" />
+      </el-aside>
+      <el-container class="header-and-main">
+        <AppHeader @switch-project="switchProject" :current-project="currentProject" />
+        <el-main style="padding-top: 60px; padding: 20px; background-color: #ecf0f1;">
+          <el-scrollbar>
+            <RouterView />
+          </el-scrollbar>
+        </el-main>
+      </el-container>
+    </el-container>
+  </div>
+</template>
+
+<style scoped>
+.common-layout {
+  display: flex;
+  height: 100%;
+}
+
+.header-and-main {
+  flex-direction: column;
+  width: 100%;
+}
+
+.el-main {
+  padding: 20px;
+  background-color: #ecf0f1;
+  flex-grow: 1;
+}
+
+/* 改善侧边栏宽度变化时的过渡效果 */
+.el-aside {
+  transition: width 0.3s ease-out;
+  overflow-x: hidden; /* 确保侧边栏没有横向滚动条 */
+}
+
+/* 自定义滚动条样式开始 */
+.el-scrollbar__wrap {
+  overflow-x: hidden; /* 隐藏横向滚动条 */
+  overflow-y: auto;   /* 确保垂直方向可以滚动 */
+}
+
+/* 针对WebKit浏览器(如Chrome, Safari)的自定义滚动条 */
+.el-scrollbar__bar.is-horizontal {
+  display: none; /* 隐藏水平滚动条 */
+}
+
+/* 对于非WebKit浏览器,可以添加如下通用样式 */
+.el-scrollbar__view {
+  overflow-x: hidden; /* 确保水平方向不会出现滚动条 */
+  overflow-y: auto;   /* 保证垂直方向可以滚动 */
+}
+
+/* 如果需要支持IE或Edge,可以考虑额外的样式规则 */
+</style>

+ 17 - 0
src/components/layout/TabsComponent.vue

@@ -0,0 +1,17 @@
+<template>
+  <el-tabs v-model="activeTab">
+    <el-tab-pane label="标签一" name="tab1">
+    </el-tab-pane>
+    <el-tab-pane label="标签二" name="tab2">
+    </el-tab-pane>
+  </el-tabs>
+</template>
+
+<script setup lang="ts">
+import { ref, provide } from 'vue';
+
+const activeTab = ref('tab1'); // 默认选中的标签页
+
+// 使用 provide 提供当前激活的标签页给父组件或其他子组件
+provide('activeTab', activeTab);
+</script>

+ 3 - 0
src/components/layout/isCollapse.ts

@@ -0,0 +1,3 @@
+import { ref } from 'vue';
+
+export const isCollapse = ref(false);

+ 20 - 0
src/main.ts

@@ -0,0 +1,20 @@
+import './assets/main.scss'
+
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+import ElementPlus from 'element-plus'
+import zhCn from 'element-plus/es/locale/lang/zh-cn' // 引入中文语言包
+import 'element-plus/dist/index.css'
+import 'leaflet/dist/leaflet.css';
+
+import App from './App.vue'
+import router from './router'
+
+const app = createApp(App)
+
+app.use(createPinia())
+app.use(router)
+app.use(ElementPlus, {
+  locale: zhCn, // 设置Element Plus的语言为中文
+})
+app.mount('#app')

+ 146 - 0
src/router/index.ts

@@ -0,0 +1,146 @@
+import { createRouter, createWebHistory } from 'vue-router';
+import AppLayout from '../components/layout/AppLayout.vue';
+import { useTokenStore } from '@/stores/mytoken'; // 确保正确导入 useTokenStore
+
+// 定义路由配置
+const routes = [
+  {
+    path: '/login',
+    name: 'login',
+    component: () => import('../views/login/loginView.vue'),
+  },
+  {
+    path: '/',
+    name: 'home',
+    component: AppLayout,
+    meta: { requiresAuth: true, title: '模型' },
+    children: [
+      {
+        path: 'SoilPro',
+        name: 'SoilPro',
+        component: () => import('../views/menu/SoilPro.vue'),
+        meta: { title: '软件简介' },
+      },
+      {
+        path: 'Overview',
+        name: 'Overview',
+        component: () => import('../views/menu/Overview.vue'),
+        meta: { title: '项目简介' },
+      },
+      {
+        path: 'ResearchFindings',
+        name: 'ResearchFindings',
+        component: () => import('../views/menu/ResearchFindings.vue'),
+        meta: { title: '研究成果' },
+      },
+      {
+        path: 'Unit',
+        name: 'Unit',
+        component: () => import('../views/menu/Unit.vue'),
+        meta: { title: '团队信息' },
+      },
+      {
+      path: 'IntroductionUpdate',
+        name: 'IntroductionUpdate',
+        component: () => import('../views/menu/IntroductionUpdate.vue'),
+        meta: { title: '更新介绍' },
+      },
+      {
+        path: 'Calculation',
+        name: 'Calculation',
+        component: () => import('../views/menu/Calculation.vue'),
+        meta: { title: '反酸计算' },
+      },
+      {
+        path: 'AcidNeutralizationModel',
+        name: 'AcidNeutralizationModel',
+        component: () => import('../views/menu/AcidNeutralizationModel.vue'),
+        meta: { title: '降酸计算' },
+      },
+      {
+        path: 'SoilAcidificationIterativeEvolution',
+        name: 'SoilAcidificationIterativeEvolution',
+        component: () => import('../views/menu/SoilAcidificationIterativeEvolution.vue'),
+        meta: { title: '降酸模型显示' },
+      },
+      {
+        path: 'SoilAcidReductionIterativeEvolution',
+        name: 'SoilAcidReductionIterativeEvolution',
+        component: () => import('../views/menu/SoilAcidReductionIterativeEvolution.vue'),
+        meta: { title: '反酸模型显示' },
+      },
+      {
+        path: 'mapView',
+        name: 'mapView',
+        component: () => import('../views/menu/mapView.vue'),
+        meta: { title: '地图展示' },
+      },
+      {
+        path: 'Visualizatio',
+        name: 'Visualizatio',
+        component: () => import('../views/Visualizatio.vue'),
+        meta: { title: '降酸数据管理' },
+      },
+      {
+        path: 'Visualization',
+        name: 'Visualization',
+        component: () => import('../views/Visualization.vue'),
+        meta: { title: '反酸数据管理' },
+      },
+      {
+        path: 'ModelSelection',
+        name: 'ModelSelection',
+        component: () => import('../views/ModelSelection.vue'),
+        meta: { title: '模型选择' },
+      },
+      {
+        path: 'thres',
+        name: 'thres',
+        component: () => import('../views/thres.vue'),
+        meta: { title: '阈值选择' },
+      },
+      {
+        path: 'ModelTrain',
+        name: 'ModelTrain',
+        component: () => import('../views/ModelTrain.vue'),
+        meta: { title: '模型训练' },
+      },
+      {
+        path: 'about',
+        name: 'about',
+        component: () => import('../views/AboutView.vue'),
+      },
+      {
+        path: '/:pathMatch(.*)*',
+        name: 'ErrorPage',
+        component: () => import('../views/ErrorPage.vue'),
+      },
+    ],
+  },
+];
+
+// 创建 router 实例
+const router = createRouter({
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes, // 使用路由配置数组
+});
+
+// 导航守卫
+router.beforeEach((to, from, next) => {
+  const tokenStore = useTokenStore(); // 使用正确的函数名称
+  if (to.matched.some(record => record.meta.requiresAuth)) {
+    // 检查是否需要认证
+    if (!tokenStore.token.userid) {
+      // 如果没有有效的 token,则重定向到登录页面
+      next({ name: 'login' });
+    } else {
+      // 如果有有效的 token,则允许访问
+      next();
+    }
+  } else {
+    // 如果页面不需要认证,则直接允许访问
+    next();
+  }
+});
+
+export default router;

+ 17 - 0
src/shims-vue.d.ts

@@ -0,0 +1,17 @@
+declare module '*.png' {
+  const value: string;
+  export default value;
+}
+
+declare module 'vue-leaflet' {
+  export const LMap: any;
+  export const LTileLayer: any;
+  export const LMarker: any;
+  export const LPopup: any;
+}
+
+declare module '*.vue' {
+  import { DefineComponent } from 'vue';
+  const component: DefineComponent<{}, {}, any>;
+  export default component;
+}

+ 12 - 0
src/stores/counter.ts

@@ -0,0 +1,12 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+export const useCounterStore = defineStore('counter', () => {
+  const count = ref(0)
+  const doubleCount = computed(() => count.value * 2)
+  function increment() {
+    count.value++
+  }
+
+  return { count, doubleCount, increment }
+})

+ 39 - 0
src/stores/mytoken.ts

@@ -0,0 +1,39 @@
+import { defineStore } from 'pinia';
+import { ref, computed } from 'vue';
+
+interface Token {
+  access_token: any;
+  userid: string | null;
+  name: string;
+  loginType?: string; // 添加此行
+}
+
+export const useTokenStore = defineStore('mytoken', () => {
+  const tokenJson = ref<string>(window.localStorage.getItem("TokenInfo") || "{}");
+
+  const token = computed<Token>(() => {
+    try {
+      return JSON.parse(tokenJson.value) as Token;
+    } catch (e) {
+      console.error("Failed to parse token JSON", e);
+      return { access_token: null, userid: null, name: '' };
+    }
+  });
+
+  function setToken(newToken: string) {
+    tokenJson.value = newToken;
+    window.localStorage.setItem("TokenInfo", newToken);
+  }
+
+  function saveToken(userInfo: { userId: number | null, name: string, loginType?: string }) {
+    const userIdString = userInfo.userId !== null && userInfo.userId !== undefined ? userInfo.userId.toString() : null;
+    const tokenInfo = JSON.stringify({ userid: userIdString, name: userInfo.name, loginType: userInfo.loginType });
+    setToken(tokenInfo);
+  }
+
+  function clearToken() {
+    setToken("{}"); // 设置为空对象以清除 token
+  }
+
+  return { token, setToken, saveToken, clearToken };
+});

+ 48 - 0
src/utils/request.ts

@@ -0,0 +1,48 @@
+import axios, { type AxiosRequestConfig, type AxiosResponse, isAxiosError } from "axios";
+import router from '@/router'; // 引入Vue Router实例
+import { useTokenStore } from '@/stores/mytoken'; // 引入Pinia store
+
+// 创建 axios 实例
+const request = axios.create({ 
+    baseURL: import.meta.env.VITE_API_URL, // 使用环境变量配置的API URL
+    timeout: 1000,
+    headers: {
+        'Content-Type': 'application/json',
+    },
+});
+
+// 请求拦截器
+request.interceptors.request.use(
+    (config) => {
+        if (!config.headers) {
+            config.headers = {} as any; // 强制转换以避免类型不匹配的问题
+        }
+        console.log('Starting Request', config); // 调试信息
+        return config; // 记得返回配置
+    },
+    (error) => {
+        console.error('Request error:', error);
+        return Promise.reject(error);
+    }
+);
+
+// 响应拦截器(可选)
+request.interceptors.response.use(
+    (response: AxiosResponse) => response,
+    async (error) => {
+        if (isAxiosError(error)) {
+            console.error('Response error:', error.message);
+            if (error.response && error.response.status === 401) {
+                // 如果是401未授权错误,则清除token并重定向到登录页
+                const tokenStore = useTokenStore();
+                tokenStore.clearToken(); // 清除token信息
+                router.push('/login'); // 重定向到登录页面
+            }
+        }
+        return Promise.reject(error);
+    }
+);
+
+console.log('Base URL:', request.defaults.baseURL); // 打印检查
+
+export default request;

+ 15 - 0
src/views/AboutView.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="about">
+    <h1>This is an about page</h1>
+  </div>
+</template>
+
+<style>
+@media (min-width: 1024px) {
+  .about {
+    min-height: 100vh;
+    display: flex;
+    align-items: center;
+  }
+}
+</style>

+ 24 - 0
src/views/ErrorPage.vue

@@ -0,0 +1,24 @@
+<template>
+    <div>
+      <h1>404 - Not Found</h1>
+ 
+      <p>页面不存在,还没有开发出来,请尝试访问其他路径。。。。。。</p>
+ 
+    
+    </div>
+  </template>
+  
+  <script setup lang="ts">
+  import { useRouter } from 'vue-router';
+  const router = useRouter()
+ 
+const toLogin = () => {
+    router.push('/login')
+    }
+ 
+  </script>
+  
+ 
+ 
+  <style scoped>
+  </style>

+ 9 - 0
src/views/HomeView.vue

@@ -0,0 +1,9 @@
+<script setup lang='ts'>
+import { RouterView} from "vue-router"
+</script>
+
+<template>
+  <RouterView/>
+</template>
+
+<style scoped></style>

+ 219 - 0
src/views/ModelSelection.vue

@@ -0,0 +1,219 @@
+<template>
+  <div class="model-container">
+    <!-- 模型选择 -->
+    <el-select v-model="selectedModelType" placeholder="请选择模型类型" style="margin-bottom: 5px;" @change="selectedModelTypeChanged">
+      <el-option
+        v-for="type in modelTypes"
+        :key="type.value"
+        :label="type.label"
+        :value="type.value">
+      </el-option>
+    </el-select>
+
+    <!-- 加载失败提示 -->
+    <el-alert v-if="errorOccurred" title="加载数据失败,请检查网络连接或稍后再试。" type="error" show-icon style="margin-bottom: 5px;"></el-alert>
+
+    <!-- 动态加载的模型板块 -->
+    <el-card class="model-section" v-if="selectedModelType && pagedFilteredModelData.length > 0">
+      <template #header>
+        <div class="card-header">
+          <span>{{ selectedModelType === 'reduce_model' ? '降酸模型(Reduce Model)' : '反酸模型(Reflux Model)' }}</span>
+        </div>
+      </template>
+      <el-table
+        :data="pagedFilteredModelData"
+        v-loading="loading"
+        style="width: 100%"
+        empty-text="暂无相关模型数据"
+      >
+        <!-- 复选框列 -->
+        <el-table-column align="center" width="50">
+          <template #default="scope">
+            <el-checkbox v-model="scope.row.selected" @change="handleSelectionChange(scope.row)"></el-checkbox>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="Model_name" label="模型名称" width="180" />
+        <el-table-column prop="Data_type" label="数据类型" width="100" />
+        <el-table-column prop="Performance_score" label="性能评分" width="120" />
+        <el-table-column prop="Created_at" label="创建时间" width="180" />
+      </el-table>
+    </el-card>
+
+   <!-- 分页控制 -->
+   <div class="demo-pagination-block" v-if="selectedModelType && filteredModelData.length > 0">
+      <el-pagination
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 30, 40]"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="filteredModelData.length"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+
+    <!-- 切换模型按钮,位于表格下方并居中 -->
+    <div v-if="selectedModelType && pagedFilteredModelData.length > 0" style="text-align:center; margin-top:5px;">
+      <el-button type="primary" size="small" @click="switchModel">切换模型</el-button>
+    </div>
+
+    <!-- 当没有选择任何模型类型时显示提示信息 -->
+    <div v-if="!selectedModelType && !loading && !errorOccurred" style="text-align:center; padding-top:5px;">
+      请选择一个模型类型以查看详细信息。
+    </div>
+
+    <!-- 当筛选结果为空时显示提示信息 -->
+    <div v-if="selectedModelType && filteredModelData.length === 0 && !loading && !errorOccurred" style="text-align:center; padding-top:5px;">
+      没有找到与所选模型类型匹配的数据。
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted, computed } from 'vue'
+import axios from 'axios'
+import { ElMessage, ElAlert } from 'element-plus'
+
+interface ModelData {
+  ModelID: number
+  Model_name: string
+  Model_type: string
+  Created_at: string
+  Description: string
+  DatasetID: string
+  ModelFilePath: string
+  Data_type: string
+  Performance_score: number
+  selected?: boolean // 添加一个可选的selected属性来跟踪是否被选中
+}
+
+const loading = ref(true)
+const allModels = ref<ModelData[]>([])
+const selectedModelType = ref<string>('reflux_model')
+const modelTypes = [
+  { value: 'reduce_model', label: '降酸模型(Reduce Model)' },
+  { value: 'reflux_model', label: '反酸模型(Reflux Model)' }
+]
+const multipleSelection = ref<ModelData[]>([])
+const errorOccurred = ref(false)
+
+// 分页相关的变量
+const currentPage = ref(1)
+const pageSize = ref(10)
+
+// 获取所有模型数据
+const fetchAllModels = async () => {
+  try {
+    const requestBody = { table: 'Models' }
+    const response = await axios.post('https://127.0.0.1:5000/table', requestBody)
+    allModels.value = response.data.rows.map(row => ({ ...row, selected: false }))
+  } catch (error) {
+    console.error("Error fetching data:", error.message)
+    ElMessage.error('数据加载失败:' + error.message)
+    errorOccurred.value = true
+  } finally {
+    loading.value = false
+  }
+}
+
+// 根据选择的模型类型计算要展示的数据
+const filteredModelData = computed(() => 
+  selectedModelType.value 
+    ? allModels.value.filter(m => m.Model_name.includes(selectedModelType.value))
+    : []
+)
+
+// 分页后的过滤数据
+const pagedFilteredModelData = computed(() => {
+  const start = (currentPage.value - 1) * pageSize.value
+  const end = start + pageSize.value
+  return filteredModelData.value.slice(start, end)
+})
+
+// 更新选择状态
+const handleSelectionChange = (row: ModelData) => {
+  if (row.selected) {
+    multipleSelection.value.push(row)
+  } else {
+    const index = multipleSelection.value.findIndex(r => r.ModelID === row.ModelID)
+    if (index > -1) {
+      multipleSelection.value.splice(index, 1)
+    }
+  }
+}
+
+// 当模型类型改变时触发的函数
+const selectedModelTypeChanged = () => {}
+
+// 分页事件处理
+const handleSizeChange = (val: number) => {
+  pageSize.value = val
+}
+const handleCurrentChange = (val: number) => {
+  currentPage.value = val
+}
+
+// 切换模型状态
+const switchModel = async () => {
+  if (!multipleSelection.value.length) {
+    ElMessage.warning('请先选择至少一个模型')
+    return
+  }
+
+  try {
+    for (const model of multipleSelection.value) {
+      await axios.post('https://127.0.0.1:5000/switch-model', {
+        model_id: model.ModelID,
+        model_name: model.Model_name
+      })
+      ElMessage.success(`模型 ${model.Model_name} 切换成功`)
+    }
+  } catch (error) {
+    console.error("Failed to switch model:", error.message)
+    ElMessage.error('模型切换失败:' + error.message)
+  }
+}
+
+onMounted(() => {
+  fetchAllModels()
+})
+</script>
+
+<style scoped>
+.model-container {
+  display: grid;
+  gap: 5px; /* 减少元素之间的间隔 */
+  padding: 5px; /* 减少整体容器的内边距 */
+}
+
+.model-section {
+  margin-bottom: 5px; /* 减少卡片底部外边距 */
+}
+
+.card-header {
+  font-size: 16px; /* 略微减小字体大小 */
+  font-weight: bold;
+  color: #28A745;
+}
+
+.el-table {
+  margin-top: -10px; /* 调整表格与上方元素的距离 */
+}
+
+/* 设置表头背景色 */
+::v-deep .el-table th {
+  background-color: #61E054 !important; /* 设置你想要的颜色 */
+  color: #030803; /* 表头文字颜色 */
+}
+
+
+/* 减少表格单元格的内边距 */
+::v-deep .el-table td, ::v-deep .el-table th {
+  padding: 4px 0;
+}
+/* 设置奇数行背景色 */
+::v-deep .el-table__row:nth-child(odd) {
+  background-color: #E4FBE5 !important;
+}
+</style>

+ 236 - 0
src/views/ModelTrain.vue

@@ -0,0 +1,236 @@
+<template>
+  <div class="model-container">
+    <!-- 模型选择 -->
+    <el-select v-model="currentType" placeholder="请选择模型类型" style="margin-bottom: 5px;" @change="onTypeChange">
+      <el-option
+        v-for="(type, index) in types"
+        :key="index"
+        :label="type.display"
+        :value="type.name">
+      </el-option>
+    </el-select>
+
+    <!-- 加载失败提示 -->
+    <el-alert v-if="errorOccurred" title="加载数据失败,请检查网络连接或稍后再试。" type="error" show-icon style="margin-bottom: 5px;"></el-alert>
+
+    <!-- 动态加载的数据板块 -->
+    <el-card class="model-section" v-if="currentType && pagedFilteredRows.length > 0">
+      <template #header>
+        <div class="card-header">
+          <span>{{ currentType === 'reduce' ? '降酸模型(Reduce Model)' : '反酸模型(Reflux Model)' }}</span>
+        </div>
+      </template>
+      <el-table
+        :data="pagedFilteredRows"
+        v-loading="loading"
+        style="width: 100%"
+        empty-text="暂无相关数据"
+      >
+        <!-- 复选框列 -->
+        <el-table-column align="center" width="50">
+          <template #default="scope">
+            <el-checkbox v-model="scope.row.selected" @change="handleSelectionChange(scope.row)"></el-checkbox>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="name" label="数据集名称" width="180" />
+        <el-table-column prop="count" label="数据条数" width="100" />
+        <el-table-column prop="uploadTime" label="更新时间" width="180" />
+      </el-table>
+    </el-card>
+
+    <!-- 分页控制 -->
+    <div class="demo-pagination-block" v-if="currentType && filteredRows.length > 0">
+      <el-pagination
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 30, 40]"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="filteredRows.length"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange" 
+      />
+    </div>
+
+    <!-- 训练模型按钮,位于表格下方并居中 -->
+    <div v-if="currentType && pagedFilteredRows.length > 0" style="text-align:center; margin-top:5px;">
+      <el-button type="primary" size="small" @click="trainModel" :disabled="selectedRows.length === 0">训练模型</el-button>
+    </div>
+
+    <!-- 当没有选择任何模型类型时显示提示信息 -->
+    <div v-if="!currentType && !loading && !errorOccurred" style="text-align:center; padding-top:5px;">
+      请选择一个模型类型以查看详细信息。
+    </div>
+
+    <!-- 当筛选结果为空时显示提示信息 -->
+    <div v-if="currentType && filteredRows.length === 0 && !loading && !errorOccurred" style="text-align:center; padding-top:5px;">
+      没有找到与所选模型类型匹配的数据。
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted, computed } from 'vue';
+import axios from 'axios';
+import { ElMessageBox } from 'element-plus'; // 引入 Element Plus 的 MessageBox 组件
+
+const loading = ref(true);
+const rows = ref([]);
+const errorOccurred = ref(false);
+const selectedRows = ref([]); // 新增:用于存储被选中的行
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+const types = [{ name: 'reduce', display: '降酸模型' }, { name: 'reflux', display: '反酸模型' }];
+const currentType = ref('reflux'); // 默认设置为反酸模型
+
+// 数据过滤后的结果
+const filteredRows = computed(() => 
+  currentType.value 
+    ? rows.value.filter(row => row.type === currentType.value)
+    : []
+);
+
+// 分页后的过滤数据
+const pagedFilteredRows = computed(() => {
+  const start = (currentPage.value - 1) * pageSize.value;
+  const end = start + pageSize.value;
+  return filteredRows.value.slice(start, end);
+});
+
+// 定义 fetchData 方法
+const fetchData = async () => {
+  try {
+    const response = await axios.post('https://127.0.0.1:5000/table', { table: 'Datasets' });
+    return response.data.rows;
+  } catch (error) {
+    console.error("Error fetching data:", error.message);
+    throw error;
+  }
+};
+
+// 定义 LoadData 方法
+const LoadData = async () => {
+  try {
+    rows.value = (await fetchData()).map(row => ({
+      id: row.Dataset_ID,
+      name: row.Dataset_name,
+      description: row.Dataset_description,
+      type: row.Dataset_type,
+      count: row.Row_count,
+      status: row.Status,
+      uploadTime: row.Uploaded_at,
+      selected: false
+    }));
+  } catch (error) {
+    errorOccurred.value = true;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 定义 onTypeChange 方法
+const onTypeChange = (newType: string) => {
+  currentType.value = newType;
+  // 如果需要根据新的类型重新加载数据,请在这里调用相关方法
+  // 例如 LoadData();
+};
+
+const handleSelectionChange = (row) => {
+  if (row.selected) {
+    selectedRows.value.push(row);
+  } else {
+    const index = selectedRows.value.findIndex(r => r.id === row.id);
+    if (index > -1) {
+      selectedRows.value.splice(index, 1);
+    }
+  }
+};
+
+const showMessageDialog = (message, type) => {
+  ElMessageBox({
+    title: '提示',
+    message: message,
+    type: type,
+    confirmButtonText: '确定',
+    showClose: false,
+  });
+};
+
+const trainModel = async () => {
+  if (!selectedRows.value.length) {
+    showMessageDialog('请先选择一行或多行数据', 'warning');
+    return;
+  }
+
+  const firstSelectedRow = selectedRows.value[0];
+  const trainData = {
+    model_type: "RandomForest",
+    model_name: "ForestModel1",
+    model_description: "A random forest model trained on current data.",
+    data_type: firstSelectedRow.type,
+    dataset_id: firstSelectedRow.id
+  };
+
+  try {
+    await axios.post('https://127.0.0.1:5000/train-and-save-model', trainData);
+    showMessageDialog('模型训练完成', 'success');
+    selectedRows.value.forEach(row => row.selected = false);
+    selectedRows.value = [];
+  } catch (error) {
+    console.error('模型训练失败:', error);
+    showMessageDialog('模型训练失败', 'error');
+  }
+};
+
+// 定义 handleCurrentChange 方法
+const handleCurrentChange = (newPage: number) => {
+  currentPage.value = newPage;
+};
+
+// 定义 handleSizeChange 方法
+const handleSizeChange = (newSize: number) => {
+  pageSize.value = newSize;
+};
+
+onMounted(() => {
+  LoadData();
+});
+</script>
+
+<style scoped>
+.model-container {
+  display: grid;
+  gap: 5px; /* 减少元素之间的间隔 */
+  padding: 5px; /* 减少整体容器的内边距 */
+}
+
+.model-section {
+  margin-bottom: 5px; /* 减少卡片底部外边距 */
+}
+
+.card-header {
+  font-size: 16px; /* 略微减小字体大小 */
+  font-weight: bold;
+  color: #28A745;
+}
+
+.el-table {
+  margin-top: -10px; /* 调整表格与上方元素的距离 */
+}
+
+/* 设置表头背景色 */
+::v-deep .el-table th {
+  background-color: #61E054 !important; /* 设置你想要的颜色 */
+  color: #030803; /* 表头文字颜色 */
+}
+
+/* 减少表格单元格的内边距 */
+::v-deep .el-table td, ::v-deep .el-table th {
+  padding: 4px 0;
+}
+/* 设置奇数行背景色 */
+::v-deep .el-table__row:nth-child(odd) {
+  background-color: #E4FBE5 !important;
+}
+</style>

+ 404 - 0
src/views/Visualizatio.vue

@@ -0,0 +1,404 @@
+<template>
+  <div>
+    <!-- 操作按钮区 -->
+    <el-row :gutter="10" style="margin-bottom: 20px;">
+      <el-col :span="4">
+        <el-button :icon="Plus" type="primary" @click="openDialog('add')" style="background-color: #3EC01E; border-color: #67C23A; color: white;">新增记录</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-button :icon="Download" type="primary" @click="downloadTemplateAction" style="background-color: #3EC01E; border-color: #67C23A; color: white;">下载模板</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-button :icon="Download" type="primary" @click="exportDataAction" style="background-color: #3EC01E; border-color: #67C23A; color: white;">导出数据</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-upload :before-upload="importDataAction" accept=".xlsx, .csv">
+          <el-button :icon="Upload" type="primary" style="background-color: #3EC01E; border-color: #67C23A; color: white;">导入数据</el-button>
+        </el-upload>
+      </el-col>
+    </el-row>
+
+    <!-- 数据表格 -->
+    <el-table :data="pagedTableDataWithIndex" style="width: 100%" @row-click="handleRowClick" highlight-current-row class="custom-table"
+              v-loading="loading">
+      <el-table-column key="displayIndex" prop="displayIndex" label="序号" width="80"></el-table-column>
+      <el-table-column v-for="col in columns.filter(col => col.key !== 'id')" :key="col.key" :prop="col.dataKey" :label="col.title" :width="col.width"
+                       :formatter="formatNumber">
+      </el-table-column>
+      <el-table-column label="操作" width="120">
+        <template #default="scope">
+          <el-tooltip class="item" effect="dark" content="编辑" placement="top">
+            <el-button circle :icon="EditPen" @click.stop="openDialog('edit', scope.row)" style="font-size: 16px; color: #409EFF;"></el-button>
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" content="删除" placement="top">
+            <el-button circle :icon="DeleteFilled" @click.stop="deleteItem(scope.row)" style="font-size: 16px; color: red;"></el-button>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页控制 -->
+    <PaginationComponent 
+      :total="tableData.length" 
+      :currentPage="currentPage4" 
+      :pageSize="pageSize4" 
+      @update:currentPage="currentPage4 = $event" 
+      @update:pageSize="pageSize4 = $event" 
+      @size-change="handleSizeChange" 
+      @current-change="handleCurrentChange"
+    />
+
+    <!-- 新增/编辑对话框 -->
+    <el-dialog :title="dialogTitle" v-model="dialogVisible">
+      <el-form :model="formData">
+        <el-form-item v-for="col in editableColumns" :key="col.key" :label="col.title">
+          <el-input v-model="formData[col.dataKey]" :type="col.inputType || 'text'"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">{{ dialogSubmitButtonText }}</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, computed, onMounted } from 'vue'
+import { DeleteFilled, Download, Upload, Plus, EditPen } from '@element-plus/icons-vue';
+import { ElMessage } from 'element-plus'
+import { table, updateItem, addItem, deleteItemApi, downloadTemplate, exportData, importData } from '@/API/menus'
+import PaginationComponent from './packaged/PaginationComponent.vue'
+
+interface Column {
+ key: string;
+ dataKey: string;
+ title: string;
+ width: number;
+ inputType?: string;
+}
+
+const columns: Column[] = [
+ { key: 'id', dataKey: 'id', title: 'ID', width: 80 },
+ { key: 'OM', dataKey: 'OM', title: '有机质含量', width: 150 },
+ { key: 'CL', dataKey: 'CL', title: '土壤粘粒', width: 150 },
+ { key: 'CEC', dataKey: 'CEC', title: '阳离子交换量', width: 150 },
+ { key: 'H_plus', dataKey: 'H_plus', title: '交换性氢', width: 150, inputType: 'number' },
+ { key: 'N', dataKey: 'N', title: '水解氮', width: 150 },
+ { key: 'Al3_plus', dataKey: 'Al3_plus', title: '交换性铝', width: 150 },
+ { key: 'Delta_pH', dataKey: 'Delta_pH', title: 'ΔpH', width: 150 },
+]
+
+const editableColumns = columns.filter(col => col.key !== 'id')
+
+const tableData = ref<any[]>([])
+const selectedRow = ref<any | null>(null)
+const dialogVisible = ref(false)
+const formData = reactive<any>({})
+const dialogMode = ref<'add' | 'edit'>('add') // 新增还是编辑模式
+
+const currentPage4 = ref(1)
+const pageSize4 = ref(10)
+
+const pagedTableDataWithIndex = computed(() => {
+ return pagedTableData.value.map((item, index) => ({
+   ...item,
+   displayIndex: (currentPage4.value - 1) * pageSize4.value + index + 1
+ }));
+})
+
+const pagedTableData = computed(() => {
+ const start = (currentPage4.value - 1) * pageSize4.value
+ const end = start + pageSize4.value
+ return tableData.value.slice(start, end)
+})
+
+const loading = ref(false);
+
+const currentTableName = "current_reflux";
+
+const fetchTable = async () => {
+  console.log('正在获取表格数据...');
+  try {
+    loading.value = true;
+    const response = await table({ table: currentTableName });
+    console.log("获取到的数据:", response);
+    tableData.value = response.data.rows;
+  } catch (error) {
+    console.error('获取数据时出错:', error);
+    ElMessage.error('获取数据失败,请检查网络连接或服务器状态');
+  } finally {
+    loading.value = false;
+  }
+};
+
+onMounted(() => {
+ fetchTable()
+})
+
+const handleRowClick = (row: any) => {
+ selectedRow.value = row
+ Object.assign(formData, row)
+}
+
+const openDialog = (mode: 'add' | 'edit', row?: any) => {
+ console.log(`${mode === 'add' ? '打开新增记录' : '打开编辑记录'}对话框`);
+ if (mode === 'add') {
+   selectedRow.value = null;
+   editableColumns.forEach(col => {
+     formData[col.dataKey] = '';
+   });
+ } else if (row) {
+   console.log('编辑记录:', row);
+   selectedRow.value = row;
+   Object.assign(formData, row);
+ }
+ dialogMode.value = mode;
+ dialogVisible.value = true;
+}
+
+function prepareFormData(formData: { [x: string]: any; }, excludeKeys = ['displayIndex']): { [x: string]: any; } {
+  const result: { [x: string]: any; } = {};
+
+  for (const key in formData) {
+    if (!excludeKeys.includes(key)) {
+      let value = formData[key];
+      
+      // 如果是 'displayIndex-' 格式的键,则提取原始 id
+      if (typeof value === 'string' && value.startsWith('displayIndex-')) {
+        value = value.replace('displayIndex-', '');
+      }
+
+      result[key] = value;
+    }
+  }
+
+  return result;
+}
+
+const submitForm = async () => {
+  console.log('开始提交表单...');
+  try {
+    console.log('验证表单数据...');
+    const isValid = validateFormData(formData);
+    if (!isValid) {
+      console.error('表单验证失败,请检查输入的数据');
+      alert('请检查输入的数据');
+      return;
+    }
+
+    // 准备要提交的数据
+    console.log('准备提交的数据:', formData);
+    const dataToSubmit = prepareFormData(formData);
+
+    console.log('已准备的数据:', dataToSubmit);
+
+    // 检查是否存在 id 字段
+    if (!dataToSubmit.id && dialogMode.value !== 'add') {
+      console.error('无法找到记录ID,请联系管理员');
+      alert('无法找到记录ID,请联系管理员');
+      return;
+    }
+
+    let response;
+    if (dialogMode.value === 'add') {
+      console.log('正在添加新记录...');
+      response = await addItem({ table: currentTableName, item: dataToSubmit });
+    } else {
+      console.log('正在更新现有记录...');
+      response = await updateItem({ table: currentTableName, item: dataToSubmit });
+    }
+
+    console.log(dialogMode.value === 'add' ? '添加响应:' : '更新响应:', response);
+
+    dialogVisible.value = false;
+    fetchTable();
+    alert(dialogMode.value === 'add' ? '添加成功' : '修改成功');
+  } catch (error) {
+    console.error('提交表单时发生错误:', error);
+    let errorMessage = '未知错误';
+    if (error.response && error.response.data && error.response.data.message) {
+      errorMessage = error.response.data.message;
+    }
+    console.error(`提交失败原因: ${errorMessage}`);
+    alert(`提交失败: ${errorMessage}`);
+  }
+};
+
+// 示例 validateFormData 函数,需根据实际需求调整
+function validateFormData(data) {
+  for (let key in data) {
+    if (data[key] === '' || data[key] === undefined) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const deleteItem = async (row: any) => {
+ console.log('准备删除记录:', row);
+ if (!row) {
+   ElMessage.warning('请先选择一行记录')
+   return
+ }
+ try {
+   const condition = { id: row.id };
+   console.log('删除记录条件:', condition);
+   await deleteItemApi({ table: 'current_reflux', condition });
+   const index = tableData.value.findIndex(item => item.id === row.id);
+   if (index > -1) {
+     tableData.value.splice(index, 1);
+   }
+   fetchTable()
+   console.log('记录删除成功');
+ } catch (error) {
+   console.error('删除记录时发生错误:', error);
+ }
+}
+
+const downloadTemplateAction = async () => {
+ try {
+   console.log('正在下载模板...');
+   await downloadTemplate('current_reflux');
+ } catch (error) {
+   console.error('下载模板时发生错误:', error);
+ }
+}
+
+const exportDataAction = async () => {
+ try {
+   console.log('正在导出数据...');
+   await exportData('current_reflux');
+ } catch (error) {
+   console.error('导出数据时发生错误:', error);
+ }
+}
+
+const importDataAction = async (file: File) => {
+ try {
+   console.log('正在导入数据...');
+   const response = await importData('current_reflux', file);
+   if(response && response.data){
+     const { total_data, new_data, duplicate_data, message } = response.data;
+     ElMessage({
+       message: `导入结果: ${message} 新增总数:${total_data}, 成功新增:${new_data}, 数据重复:${duplicate_data}`,
+       type: 'success',
+     });
+     fetchTable(); // 刷新表格数据
+   }
+ } catch (error) {
+   console.error('数据导入时发生错误:', error);
+   let errorMessage = '数据导入失败';
+   if (error.response && error.response.data && error.response.data.message) {
+     errorMessage += `: ${error.response.data.message}`;
+   }
+   ElMessage.error(errorMessage);
+ }
+};
+
+const handleFileChange = (event: Event) => {
+ const target = event.target as HTMLInputElement;
+ if (target.files && target.files.length > 0) {
+   importDataAction(target.files[0]);
+ }
+};
+
+const handleSizeChange = (val: number) => {}
+
+const handleCurrentChange = (val: number) => {}
+
+const formatNumber = (row: any, column: any, cellValue: any) => {
+ if (typeof cellValue === 'number') {
+   return cellValue.toFixed(3)
+ }
+ return cellValue
+}
+
+const dialogTitle = computed(() => {
+  return dialogMode.value === 'add' ? '新增记录' : '编辑记录';
+});
+
+const dialogSubmitButtonText = computed(() => {
+  return dialogMode.value === 'add' ? '添加' : '保存';
+});
+</script>
+
+<style scoped>
+/* 应用容器的内边距 */
+.app-container {
+  padding: 20px;
+}
+
+/* 操作按钮区的底部外边距 */
+.el-row {
+  margin-bottom: 10px !important; /* 调整为更小的值 */
+}
+
+/* 按钮的统一风格 */
+.el-button {
+  margin-right: 10px; /* 增加按钮间的间距 */
+}
+
+/* 数据表格的宽度和高亮当前行 */
+.custom-table {
+  width: 100%;
+}
+
+/* 设置表头背景色 */
+::v-deep .el-table th {
+  background-color: #61E054 !important; /* 保持原有颜色 */
+  color: #030803; /* 保持原有颜色 */
+}
+
+/* 设置奇数行背景色 */
+::v-deep .el-table__row:nth-child(odd) {
+  background-color: #E4FBE5 !important; /* 保持原有颜色 */
+}
+
+/* 设置偶数行背景色 */
+::v-deep .el-table__row:nth-child(even) {
+  background-color: #FFFFFF !important; /* 新增:设置偶数行为白色 */
+}
+
+/* 减少表格单元格的内边距 */
+::v-deep .el-table td, ::v-deep .el-table th.is-leaf {
+  padding: 8px 0; /* 减少内边距 */
+}
+
+/* 对话框中的表单标签宽度 */
+.el-form-item__label {
+  width: 120px; /* 设置标签宽度 */
+}
+
+.el-form-item__content {
+  margin-left: 120px; /* 根据标签宽度调整内容区域 */
+}
+
+/* 分页组件样式 */
+.pagination-container {
+  margin-top: 20px; /* 增加分页组件与表格之间的距离 */
+  text-align: center; /* 分页组件居中 */
+}
+
+/* 操作列图标样式 */
+.el-table-column--action .el-button {
+  margin-right: 5px;
+  font-size: 14px;
+}
+
+.el-table-column--action .el-button:last-child {
+  margin-right: 0;
+}
+
+.el-table-column--action .el-button.el-button--primary {
+  background-color: transparent;
+  border-color: transparent;
+  color: #409EFF;
+}
+
+.el-table-column--action .el-button.el-button--danger {
+  background-color: transparent;
+  border-color: transparent;
+  color: red;
+}
+</style>

+ 403 - 0
src/views/Visualization.vue

@@ -0,0 +1,403 @@
+<template>
+  <div>
+    <!-- 操作按钮区 -->
+    <el-row :gutter="10" style="margin-bottom: 20px;">
+      <el-col :span="4">
+        <el-button :icon="Plus" type="primary" @click="openDialog('add')" style="background-color: #3EC01E; border-color: #67C23A; color: white;">新增记录</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-button :icon="Download" type="primary" @click="downloadTemplateAction" style="background-color: #3EC01E; border-color: #67C23A; color: white;">下载模板</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-button :icon="Download" type="primary" @click="exportDataAction" style="background-color: #3EC01E; border-color: #67C23A; color: white;">导出数据</el-button>
+      </el-col>
+      <el-col :span="4">
+        <el-upload :before-upload="importDataAction" accept=".xlsx, .csv">
+          <el-button :icon="Upload" type="primary" style="background-color: #3EC01E; border-color: #67C23A; color: white;">导入数据</el-button>
+        </el-upload>
+      </el-col>
+    </el-row>
+
+    <!-- 数据表格 -->
+    <el-table :data="pagedTableDataWithIndex" style="width: 100%" @row-click="handleRowClick" highlight-current-row class="custom-table"
+              v-loading="loading">
+      <el-table-column key="displayIndex" prop="displayIndex" label="序号" width="80"></el-table-column>
+      <el-table-column v-for="col in columns.filter(col => col.key !== 'id')" :key="col.key" :prop="col.dataKey" :label="col.title" :width="col.width"
+                       :formatter="formatNumber">
+      </el-table-column>
+      <el-table-column label="操作" width="120">
+        <template #default="scope">
+          <el-tooltip class="item" effect="dark" content="编辑" placement="top">
+            <el-button circle :icon="EditPen" @click.stop="openDialog('edit', scope.row)" style="font-size: 16px; color: #409EFF;"></el-button>
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" content="删除" placement="top">
+            <el-button circle :icon="DeleteFilled" @click.stop="deleteItem(scope.row)" style="font-size: 16px; color: red;"></el-button>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页控制 -->
+    <PaginationComponent 
+      :total="tableData.length" 
+      :currentPage="currentPage4" 
+      :pageSize="pageSize4" 
+      @update:currentPage="currentPage4 = $event" 
+      @update:pageSize="pageSize4 = $event" 
+      @size-change="handleSizeChange" 
+      @current-change="handleCurrentChange"
+    />
+
+    <!-- 新增/编辑对话框 -->
+    <el-dialog :title="dialogTitle" v-model="dialogVisible">
+      <el-form :model="formData">
+        <el-form-item v-for="col in editableColumns" :key="col.key" :label="col.title">
+          <el-input v-model="formData[col.dataKey]" :type="col.inputType || 'text'"></el-input>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">{{ dialogSubmitButtonText }}</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, computed, onMounted } from 'vue'
+import { DeleteFilled, Download, Upload, Plus, EditPen } from '@element-plus/icons-vue';
+import { ElMessage } from 'element-plus'
+import { table, updateItem, addItem, deleteItemApi, downloadTemplate, exportData, importData } from '@/API/menus'
+import PaginationComponent from './packaged/PaginationComponent.vue'
+
+interface Column {
+ key: string;
+ dataKey: string;
+ title: string;
+ width: number;
+ inputType?: string;
+}
+
+const columns: Column[] = [
+  { key: 'id', dataKey: 'id', title: '序号', width: 80 },
+  { key: 'Q_over_b', dataKey: 'Q_over_b', title: 'Q/ΔpH', width: 150 },
+  { key: 'pH', dataKey: 'pH', title: '初始pH', width: 150 },
+  { key: 'OM', dataKey: 'OM', title: '有机质含量', width: 150 },
+  { key: 'CL', dataKey: 'CL', title: '土壤粘粒', width: 150 },
+  { key: 'H', dataKey: 'H', title: '交换性氢', width: 150 },
+  { key: 'Al', dataKey: 'Al', title: '交换性铝', width: 150 },
+]
+
+const editableColumns = columns.filter(col => col.key !== 'id')
+
+const tableData = ref<any[]>([])
+const selectedRow = ref<any | null>(null)
+const dialogVisible = ref(false)
+const formData = reactive<any>({})
+const dialogMode = ref<'add' | 'edit'>('add') // 新增还是编辑模式
+
+const currentPage4 = ref(1)
+const pageSize4 = ref(10)
+
+const pagedTableDataWithIndex = computed(() => {
+ return pagedTableData.value.map((item, index) => ({
+   ...item,
+   displayIndex: (currentPage4.value - 1) * pageSize4.value + index + 1
+ }));
+})
+
+const pagedTableData = computed(() => {
+ const start = (currentPage4.value - 1) * pageSize4.value
+ const end = start + pageSize4.value
+ return tableData.value.slice(start, end)
+})
+
+const loading = ref(false);
+
+const currentTableName = "current_reduce";
+
+const fetchTable = async () => {
+  console.log('正在获取表格数据...');
+  try {
+    loading.value = true;
+    const response = await table({ table: currentTableName });
+    console.log("获取到的数据:", response);
+    tableData.value = response.data.rows;
+  } catch (error) {
+    console.error('获取数据时出错:', error);
+    ElMessage.error('获取数据失败,请检查网络连接或服务器状态');
+  } finally {
+    loading.value = false;
+  }
+};
+
+onMounted(() => {
+ fetchTable()
+})
+
+const handleRowClick = (row: any) => {
+ selectedRow.value = row
+ Object.assign(formData, row)
+}
+
+const openDialog = (mode: 'add' | 'edit', row?: any) => {
+ console.log(`${mode === 'add' ? '打开新增记录' : '打开编辑记录'}对话框`);
+ if (mode === 'add') {
+   selectedRow.value = null;
+   editableColumns.forEach(col => {
+     formData[col.dataKey] = '';
+   });
+ } else if (row) {
+   console.log('编辑记录:', row);
+   selectedRow.value = row;
+   Object.assign(formData, row);
+ }
+ dialogMode.value = mode;
+ dialogVisible.value = true;
+}
+
+function prepareFormData(formData: { [x: string]: any; }, excludeKeys = ['displayIndex']): { [x: string]: any; } {
+  const result: { [x: string]: any; } = {};
+
+  for (const key in formData) {
+    if (!excludeKeys.includes(key)) {
+      let value = formData[key];
+      
+      // 如果是 'displayIndex-' 格式的键,则提取原始 id
+      if (typeof value === 'string' && value.startsWith('displayIndex-')) {
+        value = value.replace('displayIndex-', '');
+      }
+
+      result[key] = value;
+    }
+  }
+
+  return result;
+}
+
+const submitForm = async () => {
+  console.log('开始提交表单...');
+  try {
+    console.log('验证表单数据...');
+    const isValid = validateFormData(formData);
+    if (!isValid) {
+      console.error('表单验证失败,请检查输入的数据');
+      alert('请检查输入的数据');
+      return;
+    }
+
+    // 准备要提交的数据
+    console.log('准备提交的数据:', formData);
+    const dataToSubmit = prepareFormData(formData);
+
+    console.log('已准备的数据:', dataToSubmit);
+
+    // 检查是否存在 id 字段
+    if (!dataToSubmit.id && dialogMode.value !== 'add') {
+      console.error('无法找到记录ID,请联系管理员');
+      alert('无法找到记录ID,请联系管理员');
+      return;
+    }
+
+    let response;
+    if (dialogMode.value === 'add') {
+      console.log('正在添加新记录...');
+      response = await addItem({ table: currentTableName, item: dataToSubmit });
+    } else {
+      console.log('正在更新现有记录...');
+      response = await updateItem({ table: currentTableName, item: dataToSubmit });
+    }
+
+    console.log(dialogMode.value === 'add' ? '添加响应:' : '更新响应:', response);
+
+    dialogVisible.value = false;
+    fetchTable();
+    alert(dialogMode.value === 'add' ? '添加成功' : '修改成功');
+  } catch (error) {
+    console.error('提交表单时发生错误:', error);
+    let errorMessage = '未知错误';
+    if (error.response && error.response.data && error.response.data.message) {
+      errorMessage = error.response.data.message;
+    }
+    console.error(`提交失败原因: ${errorMessage}`);
+    alert(`提交失败: ${errorMessage}`);
+  }
+};
+
+// 示例 validateFormData 函数,需根据实际需求调整
+function validateFormData(data) {
+  for (let key in data) {
+    if (data[key] === '' || data[key] === undefined) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const deleteItem = async (row: any) => {
+ console.log('准备删除记录:', row);
+ if (!row) {
+   ElMessage.warning('请先选择一行记录')
+   return
+ }
+ try {
+   const condition = { id: row.id };
+   console.log('删除记录条件:', condition);
+   await deleteItemApi({ table: 'current_reduce', condition });
+   const index = tableData.value.findIndex(item => item.id === row.id);
+   if (index > -1) {
+     tableData.value.splice(index, 1);
+   }
+   fetchTable()
+   console.log('记录删除成功');
+ } catch (error) {
+   console.error('删除记录时发生错误:', error);
+ }
+}
+
+const downloadTemplateAction = async () => {
+ try {
+   console.log('正在下载模板...');
+   await downloadTemplate('current_reduce');
+ } catch (error) {
+   console.error('下载模板时发生错误:', error);
+ }
+}
+
+const exportDataAction = async () => {
+ try {
+   console.log('正在导出数据...');
+   await exportData('current_reduce');
+ } catch (error) {
+   console.error('导出数据时发生错误:', error);
+ }
+}
+
+const importDataAction = async (file: File) => {
+ try {
+   console.log('正在导入数据...');
+   const response = await importData('current_reduce', file);
+   if(response && response.data){
+     const { total_data, new_data, duplicate_data, message } = response.data;
+     ElMessage({
+       message: `导入结果: ${message} 新增总数:${total_data}, 成功新增:${new_data}, 数据重复:${duplicate_data}`,
+       type: 'success',
+     });
+     fetchTable(); // 刷新表格数据
+   }
+ } catch (error) {
+   console.error('数据导入时发生错误:', error);
+   let errorMessage = '数据导入失败';
+   if (error.response && error.response.data && error.response.data.message) {
+     errorMessage += `: ${error.response.data.message}`;
+   }
+   ElMessage.error(errorMessage);
+ }
+};
+
+const handleFileChange = (event: Event) => {
+ const target = event.target as HTMLInputElement;
+ if (target.files && target.files.length > 0) {
+   importDataAction(target.files[0]);
+ }
+};
+
+const handleSizeChange = (val: number) => {}
+
+const handleCurrentChange = (val: number) => {}
+
+const formatNumber = (row: any, column: any, cellValue: any) => {
+ if (typeof cellValue === 'number') {
+   return cellValue.toFixed(3)
+ }
+ return cellValue
+}
+
+const dialogTitle = computed(() => {
+  return dialogMode.value === 'add' ? '新增记录' : '编辑记录';
+});
+
+const dialogSubmitButtonText = computed(() => {
+  return dialogMode.value === 'add' ? '添加' : '保存';
+});
+</script>
+
+<style scoped>
+/* 应用容器的内边距 */
+.app-container {
+  padding: 20px;
+}
+
+/* 操作按钮区的底部外边距 */
+.el-row {
+  margin-bottom: 10px !important; /* 调整为更小的值 */
+}
+
+/* 按钮的统一风格 */
+.el-button {
+  margin-right: 10px; /* 增加按钮间的间距 */
+}
+
+/* 数据表格的宽度和高亮当前行 */
+.custom-table {
+  width: 100%;
+}
+
+/* 设置表头背景色 */
+::v-deep .el-table th {
+  background-color: #61E054 !important; /* 保持原有颜色 */
+  color: #030803; /* 保持原有颜色 */
+}
+
+/* 设置奇数行背景色 */
+::v-deep .el-table__row:nth-child(odd) {
+  background-color: #E4FBE5 !important; /* 保持原有颜色 */
+}
+
+/* 设置偶数行背景色 */
+::v-deep .el-table__row:nth-child(even) {
+  background-color: #FFFFFF !important; /* 新增:设置偶数行为白色 */
+}
+
+/* 减少表格单元格的内边距 */
+::v-deep .el-table td, ::v-deep .el-table th.is-leaf {
+  padding: 8px 0; /* 减少内边距 */
+}
+
+/* 对话框中的表单标签宽度 */
+.el-form-item__label {
+  width: 120px; /* 设置标签宽度 */
+}
+
+.el-form-item__content {
+  margin-left: 120px; /* 根据标签宽度调整内容区域 */
+}
+
+/* 分页组件样式 */
+.pagination-container {
+  margin-top: 20px; /* 增加分页组件与表格之间的距离 */
+  text-align: center; /* 分页组件居中 */
+}
+
+/* 操作列图标样式 */
+.el-table-column--action .el-button {
+  margin-right: 5px;
+  font-size: 14px;
+}
+
+.el-table-column--action .el-button:last-child {
+  margin-right: 0;
+}
+
+.el-table-column--action .el-button.el-button--primary {
+  background-color: transparent;
+  border-color: transparent;
+  color: #409EFF;
+}
+
+.el-table-column--action .el-button.el-button--danger {
+  background-color: transparent;
+  border-color: transparent;
+  color: red;
+}
+</style>

+ 209 - 0
src/views/login/loginView.vue

@@ -0,0 +1,209 @@
+<template>
+  <div class="auth">
+    <!-- 登录表单 -->
+    <el-form v-if="isLogin" ref="formRef" :model="form" :rules="rules" label-width="100px">
+      <h2>登录</h2>
+      <el-form-item prop="name" label="账号">
+        <el-input v-model="form.name"></el-input>
+      </el-form-item>
+      <el-form-item prop="password" label="密码">
+        <el-input type="password" v-model="form.password"></el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="onSubmit" :loading="loading">密码登录</el-button>
+        <el-button @click="toggleForm">注册新账户</el-button>
+        <el-button @click="mockUserLogin">普通用户登录</el-button> <!-- 普通用户登录按钮 -->
+      </el-form-item>
+    </el-form>
+
+    <!-- 注册表单 -->
+    <el-form v-else ref="registerFormRef" :model="registerForm" :rules="registerRules" label-width="100px">
+      <h2>注册</h2>
+      <el-form-item prop="name" label="账号">
+        <el-input v-model="registerForm.name"></el-input>
+      </el-form-item>
+      <el-form-item prop="password" label="密码">
+        <el-input type="password" v-model="registerForm.password"></el-input>
+      </el-form-item>
+      <el-form-item prop="confirmPassword" label="确认密码">
+        <el-input type="password" v-model="registerForm.confirmPassword"></el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="onRegister" :loading="loading">注册</el-button>
+        <el-button @click="toggleForm">返回登录</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { reactive, ref, computed } from 'vue';
+import { ElMessage, ElForm } from "element-plus";
+import axios from 'axios';
+import { login, register } from "@/API/users"; // 假设已封装好的接口
+import { useRouter, useRoute } from "vue-router";
+import { useTokenStore } from "@/stores/mytoken";
+
+const store = useTokenStore();
+const router = useRouter();
+const route = useRoute();
+
+const isLogin = ref(true); // 控制显示登录或注册表单
+
+const form = reactive({
+  name: "",
+  password: ""
+});
+
+const registerForm = reactive({
+  name: "",
+  password: "",
+  confirmPassword: ""
+});
+const formRef = ref<InstanceType<typeof ElForm> | null>(null);
+const registerFormRef = ref<InstanceType<typeof ElForm> | null>(null);
+const loading = ref(false);
+
+// 切换登录/注册表单
+const toggleForm = () => {
+  isLogin.value = !isLogin.value;
+};
+
+// 密码登录提交
+const onSubmit = async () => {
+  if (!formRef.value) return;
+  formRef.value.validate(async (valid: boolean) => {
+    if (!valid) return;
+    loading.value = true;
+    try {
+      const res = await login({ name: form.name, password: form.password });
+      if (res.data.success) {
+        console.log('密码登录成功返回的信息:', res.data);
+        const userInfo = { userId: parseInt(res.data.userId), name: res.data.name, loginType: 'password' }; 
+        store.saveToken(userInfo);
+        console.log('保存的Token信息:', store.token);
+        ElMessage.success("密码登录成功");
+        const redirectPath = typeof route.query.redirect === 'string' ? route.query.redirect : '/';
+        router.push(redirectPath);
+      } else {
+        ElMessage.error(res.data.message || "登录失败");
+      }
+    } catch (error) {
+      if (axios.isAxiosError(error)) {
+        console.error(`HTTP Error: ${error.message}, status code: ${error.response?.status}`);
+        ElMessage.error(`HTTP Error: ${error.response?.statusText}`);
+      } else {
+        console.error(error);
+        ElMessage.error("登录失败");
+      }
+    } finally {
+      loading.value = false;
+    }
+  });
+};
+
+// 模拟普通用户登录
+const mockUserLogin = () => {
+  const mockUserInfo = { userId: 1, name: '普通用户', loginType: 'mock' }; // 添加loginType字段以示区别
+  store.saveToken(mockUserInfo);
+  ElMessage.success("普通用户登录成功");
+  const redirectPath = typeof route.query.redirect === 'string' ? route.query.redirect : '/';
+  router.push(redirectPath);
+};
+
+// 注册提交
+const onRegister = async () => {
+  if (!registerFormRef.value) return;
+  registerFormRef.value.validate(async (valid: boolean) => {
+    if (!valid) return;
+
+    if (registerForm.password !== registerForm.confirmPassword) {
+      ElMessage.error("两次输入的密码不一致");
+      return;
+    }
+
+    try {
+      const res = await register({ name: registerForm.name, password: registerForm.password });
+        if (res.data.success) {
+        ElMessage.success("注册成功,请登录");
+        toggleForm(); // 切换回登录表单
+      } else {
+        ElMessage.error(res.data.message || "注册失败");
+      }
+    } catch (error) {
+      if (axios.isAxiosError(error)) {
+        console.error(`HTTP Error: ${error.message}, status code: ${error.response?.status}`);
+        ElMessage.error(`HTTP Error: ${error.response?.statusText}`);
+      } else {
+        console.error(error);
+        ElMessage.error("注册失败");
+      }
+    } finally {
+      loading.value = false;
+    }
+  });
+};
+
+// 验证规则
+const rules = reactive({
+  name: [
+    { required: true, message: "请输入账号", trigger: "blur" }
+  ],
+  password: [
+    { required: true, message: "请输入密码", trigger: "blur" },
+    { min: 3, max: 16, message: "密码长度应在 3 到 16 个字符之间", trigger: "blur" }
+  ]
+});
+
+const registerRules = reactive({
+  name: [
+    { required: true, message: "请输入账号", trigger: "blur" }
+  ],
+  password: [
+    { required: true, message: "请输入密码", trigger: "blur" },
+    { min: 3, max: 16, message: "密码长度应在 3 到 16 个字符之间", trigger: "blur" }
+  ],
+  confirmPassword: [
+    { required: true, message: "请确认密码", trigger: "blur" },
+    { validator: (rule, value, callback) => {
+      if (value !== registerForm.password) {
+        callback(new Error("两次输入的密码不一致"));
+      } else {
+        callback();
+      }
+    }, trigger: "blur" }
+  ]
+});
+</script>
+
+<style scoped>
+.auth {
+  background-color: #e9e9e9;
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+/* 使用深度选择器 */
+::v-deep .el-form {
+  width: 300px;
+  padding: 30px;
+  background-color: #fff;
+  border-radius: 10px;
+}
+
+::v-deep .el-form h2 {
+  text-align: center;
+  margin-bottom: 20px;
+}
+
+::v-deep .el-form .el-form-item {
+  margin-bottom: 30px;
+}
+
+::v-deep .el-form .el-button {
+  width: 100%;
+  margin: 10px 0;
+}
+</style>

+ 286 - 0
src/views/menu/AcidNeutralizationModel.vue

@@ -0,0 +1,286 @@
+<template>
+  <el-card class="box-card">
+    <template #header>
+      <div class="card-header">
+        <span>降酸模型</span>
+      </div>
+    </template>
+
+    <el-form :model="form" ref="predictForm" label-width="240px" label-position="left">
+      <el-form-item label="土壤初始 pH" prop="init_pH" :error="errorMessages.init_pH" required>
+        <el-input v-model="form.init_pH" size="large" placeholder="请输入土壤初始 3~6 pH"
+                  ref="inputRefs.init_pH"
+                  @input="handleInput('init_pH', $event, 3, 6)">
+        </el-input>
+      </el-form-item>
+
+      <el-form-item label="土壤目标 pH" prop="target_pH" :error="errorMessages.target_pH" required>
+        <el-input v-model="form.target_pH" size="large" placeholder="请输入土壤目标 5~7 pH"
+                  ref="inputRefs.target_pH"
+                  @input="handleInput('target_pH', $event, 5, 7)">
+        </el-input>
+      </el-form-item>
+
+      <el-form-item label="土壤有机质(g/kg)" prop="OM" :error="errorMessages.OM" required>
+        <el-input v-model="form.OM" size="large" placeholder="请输入土壤有机质 10~30 (g/kg)"
+                  ref="inputRefs.OM"
+                  @input="handleInput('OM', $event, 10, 30)">
+        </el-input>
+      </el-form-item>
+
+      <el-form-item label="土壤粘粒(g/kg)" prop="CL" :error="errorMessages.CL" required>
+        <el-input v-model="form.CL" size="large" placeholder="请输入土壤粘粒 50~600 (g/kg)"
+                  ref="inputRefs.CL"
+                  @input="handleInput('CL', $event, 50, 600)">
+        </el-input>
+      </el-form-item>
+
+      <el-form-item label="交换性氢(cmol/kg)" prop="H" :error="errorMessages.H" required>
+        <el-input v-model="form.H" size="large" placeholder="请输入交换性氢 0~4 (cmol/kg)"
+                  ref="inputRefs.H"
+                  @input="handleInput('H', $event, 0, 4)">
+        </el-input>
+      </el-form-item>
+
+      <el-form-item label="交换性铝(cmol/kg)" prop="Al" :error="errorMessages.Al" required>
+        <el-input v-model="form.Al" size="large" placeholder="请输入交换性铝 0~4 (cmol/kg)"
+                  ref="inputRefs.Al"
+                  @input="handleInput('Al', $event, 0, 4)">
+        </el-input>
+      </el-form-item>
+
+      <el-button type="primary" @click="onSubmit" class="onSubmit">计算</el-button>
+
+      <el-dialog v-model="dialogVisible" @close="onDialogClose" :close-on-click-modal="false" width="500px"
+                 align-center class="dialog-class" title="计算结果">
+        <span class="dialog-class">每亩地土壤表层(20cm)撒 {{ result }}吨生石灰</span><br>
+        <span class="dialog-class">{{ result }}吨</span>
+        <template #footer>
+          <el-button @click="dialogVisible = false">关闭</el-button>
+        </template>
+      </el-dialog>
+    </el-form>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref, nextTick } from "vue";
+import { ElMessage } from 'element-plus';
+import axios from 'axios';
+import { useRouter } from 'vue-router';
+import request from '../../utils/request';
+
+const form = reactive({
+  init_pH: null,
+  target_pH: null,
+  OM: null,
+  CL: null,
+  H: null,
+  Al: null,
+});
+
+const router = useRouter();
+const result = ref(null);
+const dialogVisible = ref(false);
+const predictForm = ref(null);
+const errorMessages = reactive({
+  init_pH: '',
+  target_pH: '',
+  OM: '',
+  CL: '',
+  H: '',
+  Al: '',
+});
+
+// 使用 ref 来存储输入框元素
+const inputRefs = reactive({
+  init_pH: ref<HTMLInputElement | null>(null),
+  target_pH: ref<HTMLInputElement | null>(null),
+  OM: ref<HTMLInputElement | null>(null),
+  CL: ref<HTMLInputElement | null>(null),
+  H: ref<HTMLInputElement | null>(null),
+  Al: ref<HTMLInputElement | null>(null),
+});
+
+// 限制输入为数字并校验范围
+const handleInput = (field: string, event: Event, min: number, max: number) => {
+  try {
+    const input = inputRefs[field].value;
+    if (!input) {
+      console.error('未找到输入框元素');
+      return;
+    }
+    // 过滤非数字和小数点字符
+    const filteredValue = input.value.replace(/[^0-9.]/g, '');
+    input.value = filteredValue;
+    form[field] = filteredValue;
+
+    if (filteredValue === '') {
+      errorMessages[field] = '';
+      return;
+    }
+
+    const numValue = parseFloat(filteredValue);
+    if (isNaN(numValue) || numValue < min || numValue > max) {
+      errorMessages[field] = `输入值应在 ${min} 到 ${max} 之间且为有效数字`;
+    } else {
+      errorMessages[field] = '';
+    }
+  } catch (error) {
+    console.error(`处理输入时出错:`, error);
+    errorMessages[field] = '输入处理出错,请检查输入';
+  }
+};
+
+const validateInput = (field: string, value: string | number, min: number, max: number) => {
+  const numValue = parseFloat(value as string);
+  if (isNaN(numValue)) {
+    return false;
+  }
+  return numValue >= min && numValue <= max;
+};
+
+// 计算方法
+const onSubmit = async () => {
+  const inputConfigs = [
+    { field: 'init_pH', min: 3, max: 6 },
+    { field: 'target_pH', min: 5, max: 7 },
+    { field: 'OM', min: 10, max: 30 },
+    { field: 'CL', min: 50, max: 600 },
+    { field: 'H', min: 0, max: 4 },
+    { field: 'Al', min: 0, max: 4 },
+  ];
+
+  let isValid = true;
+  inputConfigs.forEach((config) => {
+    const { field, min, max } = config;
+    const value = form[field];
+    if (!validateInput(field, value, min, max)) {
+      isValid = false;
+      errorMessages[field] = `输入值应在 ${min} 到 ${max} 之间且为有效数字`;
+    } else {
+      errorMessages[field] = '';
+    }
+  });
+
+  if (!isValid) {
+    ElMessage.error('输入值不符合要求,请检查输入');
+    return;
+  }
+
+  console.log('开始计算...');
+  const data = {
+    model_id: 6,
+    parameters: {
+      init_pH: form.init_pH,
+      target_pH: form.target_pH,
+      OM: form.OM,
+      CL: form.CL,
+      H: form.H,
+      Al: form.Al,
+    }
+  };
+  console.log('提交的数据:', data);
+  try {
+    const response = await request.post('/predict', data, {
+      headers: {
+        'Content-Type': 'application/json'
+      }
+    });
+    console.log('预测结果:', response.data);
+    if (response.data && typeof response.data.result === 'number') {
+      result.value = parseFloat(response.data.result.toFixed(2));
+    } else {
+      console.error('未获取到有效的预测结果');
+      ElMessage.error('未获取到有效的预测结果');
+    }
+    dialogVisible.value = true;
+  } catch (error) {
+    console.error('请求失败:', error);
+    if (error.response) {
+      ElMessage.error(`请求失败,状态码: ${error.response.status}`);
+    } else if (error.request) {
+      ElMessage.error('请求发送成功,但没有收到响应');
+    } else {
+      ElMessage.error('请求过程中发生错误: ' + error.message);
+    }
+  }
+};
+
+// 监听弹窗关闭事件,关闭后初始化值
+const onDialogClose = () => {
+  dialogVisible.value = false;
+  form.init_pH = null;
+  form.target_pH = null;
+  form.OM = null;
+  form.CL = null;
+  form.H = null;
+  form.Al = null;
+  Object.keys(errorMessages).forEach(key => errorMessages[key] = '');
+  nextTick(() => {
+    if (predictForm.value) {
+      predictForm.value.resetFields();
+    }
+  });
+};
+</script>
+
+<style scoped>
+.box-card {
+  max-width: 850px;
+  margin: 0 auto;
+  padding: 20px;
+  background-color: #f0f5ff;
+  border-radius: 10px;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.card-header {
+  font-size: 25px;
+  text-align: center;
+  color: #333;
+  margin-bottom: 30px;
+}
+
+.el-form-item {
+  margin-bottom: 20px;
+}
+
+:deep(.el-form-item__label) {
+  font-size: 18px;
+  color: #666;
+}
+
+.el-input {
+  width: 80%;
+}
+
+.onSubmit {
+  display: block;
+  margin: 0 auto;
+  background-color: #007BFF;
+  color: white;
+  padding: 10px 20px;
+  border-radius: 5px;
+  font-size: 16px;
+  transition: background-color 0.3s ease;
+}
+
+.onSubmit:hover {
+  background-color: #0056b3;
+}
+
+.dialog-class {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%; /* 确保容器占满对话框内容区域 */
+  font-size: 22px;
+}
+
+@media (max-width: 576px) {
+  .el-form {
+    --el-form-label-width: 100px;
+  }
+}
+</style>

+ 292 - 0
src/views/menu/Calculation.vue

@@ -0,0 +1,292 @@
+<template>
+  <el-card class="box-card">
+    <template #header>
+      <div class="card-header">
+        <span>反酸模型</span>
+      </div>
+    </template>
+    <el-form :model="form" ref="predictForm" label-width="240px" label-position="left">
+      <el-form-item label="土壤有机质(g/kg)" prop="OM" :error="errorMessages.OM" required>
+          <el-input v-model="form.OM" size="large" placeholder="请输入土壤有机质0~30(g/kg)"
+                    ref="inputRefs.OM"
+                    @input="handleInput('OM', $event, 0, 30)">
+          </el-input>
+      </el-form-item>
+
+      <el-form-item label="土壤粘粒(g/kg)" prop="CL" :error="errorMessages.CL" required>
+          <el-input v-model="form.CL" size="large" placeholder="请输入土壤粘粒50~400(g/kg)"
+                    ref="inputRefs.CL"
+                    @input="handleInput('CL', $event, 50, 400)">
+          </el-input>
+      </el-form-item>
+
+      <el-form-item label="阳离子交换量(cmol/kg)" prop="CEC" :error="errorMessages.CEC" required>
+          <el-input v-model="form.CEC" size="large" placeholder="请输入阳离子交换量0~15(cmol/kg)"
+                    ref="inputRefs.CEC"
+                    @input="handleInput('CEC', $event, 0, 15)">
+          </el-input>
+      </el-form-item>
+
+      <el-form-item label="交换性氢(cmol/kg)" prop="H_plus" :error="errorMessages.H_plus" required>
+          <el-input v-model="form.H_plus" size="large" placeholder="请输入交换性氢0~1(cmol/kg)"
+                    ref="inputRefs.H_plus"
+                    @input="handleInput('H_plus', $event, 0, 1)">
+          </el-input>
+      </el-form-item>
+
+      <el-form-item label="水解氮(g/kg)" prop="N" :error="errorMessages.N" required>
+          <el-input v-model="form.N" size="large" placeholder="请输入水解氮0~0.2(g/kg)"
+                    ref="inputRefs.N"
+                    @input="handleInput('N', $event, 0, 0.2)">
+          </el-input>
+      </el-form-item>
+
+      <el-form-item label="交换性铝(cmol/kg)" prop="Al3_plus" :error="errorMessages.Al3_plus" required>
+          <el-input v-model="form.Al3_plus" size="large" placeholder="请输入交换性铝0~6(cmol/kg)"
+                    ref="inputRefs.Al3_plus"
+                    @input="handleInput('Al3_plus', $event, 0, 6)">
+          </el-input>
+      </el-form-item>
+
+      <el-button type="primary" @click="onSubmit" class="onSubmit">计算</el-button>
+
+      <el-dialog v-model="dialogVisible" @close="onDialogClose" :close-on-click-modal="false" width="500px"
+                 align-center title="计算结果">
+        <span class="dialog-class">pH值: {{ result }}</span>
+        <template #footer>
+          <el-button @click="dialogVisible = false">关闭</el-button>
+        </template>
+      </el-dialog>
+    </el-form>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref ,nextTick} from "vue";
+import { ElMessage } from 'element-plus';
+import axios from 'axios';
+import { useRouter } from 'vue-router';
+import request from '../../utils/request';
+
+const form = reactive({
+  OM: null,
+  CL: null,
+  CEC: null,
+  H_plus: null,
+  N: null,
+  Al3_plus: null,
+  delta_ph: null,
+});
+const router = useRouter();
+const result = ref(null);
+const dialogVisible = ref(false);
+const predictForm = ref(null);
+const errorMessages = reactive({
+  OM: '',
+  CL: '',
+  CEC: '',
+  H_plus: '',
+  N: '',
+  Al3_plus: '',
+});
+
+// 使用 ref 来存储输入框元素
+const inputRefs = reactive({
+  OM: ref<HTMLInputElement | null>(null),
+  CL: ref<HTMLInputElement | null>(null),
+  CEC: ref<HTMLInputElement | null>(null),
+  H_plus: ref<HTMLInputElement | null>(null),
+  N: ref<HTMLInputElement | null>(null),
+  Al3_plus: ref<HTMLInputElement | null>(null),
+});
+
+// 限制输入为数字并校验范围
+const handleInput = (field: string, event: Event, min: number, max: number) => {
+  try {
+    const input = inputRefs[field].value;
+    if (!input) {
+      console.error('未找到输入框元素');
+      return;
+    }
+    // 过滤非数字和小数点字符
+    const filteredValue = input.value.replace(/[^0-9.]/g, '');
+    input.value = filteredValue;
+    form[field] = filteredValue;
+
+    if (filteredValue === '') {
+      errorMessages[field] = '';
+      return;
+    }
+
+    const numValue = parseFloat(filteredValue);
+    if (isNaN(numValue) || numValue < min || numValue > max) {
+      errorMessages[field] = `输入值应在 ${min} 到 ${max} 之间且为有效数字`;
+    } else {
+      errorMessages[field] = '';
+    }
+  } catch (error) {
+    console.error(`处理输入时出错:`, error);
+    errorMessages[field] = '输入处理出错,请检查输入';
+  }
+};
+
+const validateInput = (field: string, value: string, min: number, max: number) => {
+  const numValue = parseFloat(value);
+  if (isNaN(numValue)) {
+    return false;
+  }
+  return numValue >= min && numValue <= max;
+};
+
+// 计算方法
+const onSubmit = async () => {
+  const inputConfigs = [
+    { field: 'OM', min: 0, max: 30 },
+    { field: 'CL', min: 50, max: 400 },
+    { field: 'CEC', min: 0, max: 15 },
+    { field: 'H_plus', min: 0, max: 1 },
+    { field: 'N', min: 0, max: 0.2 },
+    { field: 'Al3_plus', min: 0, max: 6 },
+  ];
+
+  let isValid = true;
+  inputConfigs.forEach((config) => {
+    const { field, min, max } = config;
+    const value = form[field];
+    if (!validateInput(field, value, min, max)) {
+      isValid = false;
+      errorMessages[field] = `输入值应在 ${min} 到 ${max} 之间且为有效数字`;
+    } else {
+      errorMessages[field] = '';
+    }
+  });
+
+  if (!isValid) {
+    ElMessage.error('输入值不符合要求,请检查输入');
+    return;
+  }
+
+  console.log('开始计算...');
+  const data = {
+    model_id: 9,
+    parameters: {
+      organic_matter: form.OM,
+      chloride: form.CL,
+      cec: form.CEC,
+      h_concentration: form.H_plus,
+      n: form.N,
+      al_concentration: form.Al3_plus,
+    }
+  };
+
+  try {
+    const response = await request.post('/predict', data, {
+      headers: {
+        'Content-Type': 'application/json'
+      }
+    });
+    console.log('预测结果:', response.data);
+    if (response.data && response.data.result && response.data.result.length > 0) {
+      result.value = parseFloat(response.data.result[0].toFixed(2));
+    } else {
+      console.error('未获取到有效的预测结果');
+      ElMessage.error('未获取到有效的预测结果');
+    }
+    dialogVisible.value = true;
+  } catch (error) {
+    console.error('请求失败:', error);
+    if (error.response) {
+      ElMessage.error(`请求失败,状态码: ${error.response.status}`);
+    } else if (error.request) {
+      ElMessage.error('请求发送成功,但没有收到响应');
+    } else {
+      ElMessage.error('请求过程中发生错误: ' + error.message);
+    }
+  }
+};
+
+// 监听弹窗关闭事件,关闭后初始化值
+const onDialogClose = () => {
+  dialogVisible.value = false;
+  form.OM = null;
+  form.CL = null;
+  form.CEC = null;
+  form.H_plus = null;
+  form.N = null;
+  form.Al3_plus = null;
+  form.delta_ph = null;
+  Object.keys(errorMessages).forEach(key => errorMessages[key] = '');
+  nextTick(() => {
+    if (predictForm.value) {
+      predictForm.value.resetFields();
+    }
+  });
+};
+</script>
+
+<style scoped>
+.box-card {
+  max-width: 850px;
+  margin: 0 auto;
+  padding: 20px;
+  background-color: #f0f5ff;
+  border-radius: 10px;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.card-header {
+  text-align: center;
+  color: #333;
+  margin-bottom: 30px;
+  font-size: 25px;
+}
+
+.el-form-item {
+  margin-bottom: 20px;
+}
+
+:deep(.el-form-item__label) {
+  font-size: 18px;
+  color: #666;
+}
+
+.el-input {
+  width: 80%;
+}
+
+.onSubmit {
+  display: block;
+  margin: 0 auto;
+  background-color: #007BFF;
+  color: white;
+  padding: 10px 20px;
+  border-radius: 5px;
+  font-size: 16px;
+  transition: background-color 0.3s ease;
+}
+
+.onSubmit:hover {
+  background-color: #0056b3;
+}
+
+.dialog-class {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%; /* 确保容器占满对话框内容区域 */
+  font-size: 20px;
+}
+
+@media (max-width: 576px) {
+  .el-form {
+    --el-form-label-width: 100px;
+  }
+}
+
+/* 自定义 tooltip 样式 */
+:deep(.el-tooltip__popper.is-light) {
+  background-color: white;
+  border-color: #dcdfe6;
+  color: #606266;
+}
+</style>

+ 185 - 0
src/views/menu/IntroUpdateModal.vue

@@ -0,0 +1,185 @@
+<template>
+  <!-- 只有当数据加载完成且 isVisible 为 true 时才显示页面 -->
+  <div class="introduce-update-container" v-if="isVisible && !isLoading">
+    <div class="input-group">
+      <label for="title-input">标题:</label>
+      <input id="title-input" v-model="updatedIntro.title" type="text" placeholder="请输入修改后标题">
+    </div>
+    <div class="input-group">
+      <label>内容:</label>
+      <!-- 使用富文本框组件 -->
+      <RichTextEditor v-model="updatedIntro.intro" />
+    </div>
+    <div class="button-container">
+      <button @click="updateIntro" :disabled="isUpdating" class="submit-button">提交更新</button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, watch } from 'vue';
+import axios from 'axios';
+import RichTextEditor from './RichTextEditor.vue';
+import { ElMessage } from 'element-plus';
+
+// 定义 targetId 和 isVisible 为 prop
+const props = defineProps({
+  targetId: {
+    type: Number,
+    required: true
+  },
+  isVisible: {
+    type: Boolean,
+    default: false
+  }
+});
+
+const emits = defineEmits(['updateSuccess']);
+
+// 存储更新用的介绍数据
+const updatedIntro = ref({
+  title: '',
+  intro: ''
+});
+// 更新状态
+const isUpdating = ref(false);
+// 加载状态
+const isLoading = ref(true);
+
+// 从后端获取介绍数据
+const fetchData = async () => {
+  try {
+    isLoading.value = true;
+    const response = await axios.get(`http://127.0.0.1:5000/software-intro/${props.targetId}`);
+    const { title, intro } = response.data;
+    let processedIntro = intro;
+    // 处理多余的换行符
+    processedIntro = processedIntro.replace(/(\r\n)+/g, '\r\n').trim();
+    // 把换行符转换为 <br> 标签,适配富文本编辑器
+    processedIntro = processedIntro.replace(/\r\n/g, '<br>');
+    updatedIntro.value.title = title;
+    updatedIntro.value.intro = processedIntro;
+  } catch (err: any) {
+    console.error('请求数据时发生错误:', err.message);
+  } finally {
+    // 数据加载完成,将加载状态设为 false
+    isLoading.value = false;
+  }
+};
+
+onMounted(() => {
+  console.log('子组件挂载时接收到的 targetId:', props.targetId);
+  if (props.isVisible) {
+    // 发起数据请求
+    fetchData();
+  }
+});
+
+// 监听 targetId 变化,当 targetId 改变时重新获取数据
+watch(() => props.targetId, (newTargetId, oldTargetId) => {
+  console.log(`targetId 从 ${oldTargetId} 变为 ${newTargetId}`);
+  if (props.isVisible) {
+    fetchData();
+  }
+});
+
+// 更新介绍信息
+const updateIntro = async () => {
+  isUpdating.value = true;
+  try {
+    // 处理富文本内容,将 <br> 标签替换回 \r\n
+    let processedIntro = updatedIntro.value.intro;
+    processedIntro = processedIntro.replace(/<br>/gi, '\r\n');
+    // 处理富文本内容,去除 <p> 和 <br> 标签
+    processedIntro = processedIntro.replace(/<p>/g, '').replace(/<\/p>/g, '\r\n');
+    // 去除多余的换行符
+    processedIntro = processedIntro.replace(/(\r\n)+/g, '\r\n').trim();
+
+    const dataToSend = {
+      title: updatedIntro.value.title,
+      intro: processedIntro
+    };
+    // 发送 PUT 请求更新数据
+    const response = await axios.put(`http://127.0.0.1:5000/software-intro/${props.targetId}`, dataToSend, {
+      headers: {
+        'Content-Type': 'application/json'
+      }
+    });
+    console.log('介绍更新成功!');
+    ElMessage.success('更新成功!');
+    emits('updateSuccess');
+  } catch (err: any) {
+    if (err.response) {
+      console.error(`服务器错误: ${err.response.status} - ${err.response.data.message}`);
+    } else if (err.request) {
+      console.error('网络连接错误,请检查网络设置。');
+    } else {
+      console.error('请求设置错误: ' + err.message);
+    }
+  } finally {
+    isUpdating.value = false;
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.introduce-update-container {
+  margin-top: 20px;
+  padding: 20px;
+  border: 1px solid #ccc;
+  border-radius: 5px;
+  width: 90%;
+  margin-left: auto;
+  margin-right: auto;
+  /* 让容器高度自适应内容 */
+  height: auto;
+  overflow: auto;
+}
+
+.input-group {
+  margin-bottom: 20px;
+  display: flex;
+  align-items: start; /* 让标签和输入框顶部对齐 */
+}
+
+.input-group label {
+  min-width: 80px; /* 固定标签宽度 */
+  margin-right: 10px;
+  text-align: left; /* 文字左对齐 */
+}
+
+.input-group input,
+.input-group .rich-text-editor { 
+  flex: 1;
+  padding: 10px;
+  border: 1px solid #ccc;
+  border-radius: 3px;
+  /* 让输入框和富文本编辑器高度自适应内容 */
+  height: auto;
+  min-height: auto;
+}
+
+.button-container {
+  text-align: right;
+  margin-top: 10px; /* 增加按钮与输入框的间距 */
+}
+
+.submit-button {
+  padding: 10px 20px;
+  background-color: #007BFF;
+  color: white;
+  border: none;
+  border-radius: 3px;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+
+  &:hover {
+    background-color: #0056b3;
+  }
+
+  &:disabled {
+    background-color: #ccc;
+    cursor: not-allowed;
+  }
+}
+</style>

+ 149 - 0
src/views/menu/Introduce.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="software-intro-container">
+    <!-- 加载状态 -->
+    <div v-if="isLoading" class="loading-message">加载中...</div>
+    <!-- 错误信息 -->
+    <div v-else-if="error" class="error-message">{{ error }}</div>
+    <!-- 正常展示内容 -->
+    <div v-else class="content-wrapper">
+      <h1 class="title">{{ softwareIntro.title }}</h1>
+      <div v-for="(paragraph, index) in softwareIntro.introParagraphs" :key="index" class="paragraph">
+        <p v-html="paragraph"></p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, defineProps } from 'vue';
+import axios from 'axios';
+
+// 定义 targetId 为 prop
+const props = defineProps({
+  targetId: {
+    type: Number,
+    default: 1
+  }
+});
+
+// 存储介绍内容
+const softwareIntro = ref({
+  title: '',
+  introParagraphs: []
+});
+// 加载状态
+const isLoading = ref(true);
+// 错误信息
+const error = ref('');
+
+// 判断是否为标题段落
+const isTitle = (paragraph: string) => {
+  return /^[^\s].*[::]$/.test(paragraph);
+};
+
+const imageBaseUrl = ref(import.meta.env.VITE_IMAGE_BASE_URL);
+// 处理段落,将图片路径转换为 <img> 标签
+const processParagraph = (paragraph: string) => {
+  // 假设图片路径是相对路径
+  const imgRegex = /([^\s]+(\.jpg|\.jpeg|\.png|\.gif))/g;
+  return paragraph.replace(imgRegex, `<img src="${imageBaseUrl.value}$1" alt="图片" class="intro-image">`);
+};
+
+onMounted(async () => {
+  try {
+    // 从后端获取介绍数据
+    const response = await axios.get(`http://127.0.0.1:5000/software-intro/${props.targetId}`);
+    const { title, intro } = response.data;
+    // 保留 \r\n 换行符
+    const processedIntro = intro.replace(/<p>/g, '').replace(/<\/p>/g, '\r\n').replace(/<br>/g, '');
+    softwareIntro.value.introParagraphs = processedIntro.split('\r\n').filter(paragraph => paragraph.trim()!== '');
+    softwareIntro.value.title = title;
+  } catch (err: any) {
+    error.value = err.message || '请求数据时发生错误';
+  } finally {
+    isLoading.value = false;
+  }
+});
+</script>
+
+<style scoped lang="scss">
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+body {
+  background-color: white;
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* 更美观的字体 */
+  padding: 0;
+}
+
+.software-intro-container {
+  width: 95%;
+  margin: 0 auto; 
+  padding: 20px;
+  background-color: #fff; 
+  border-radius: 8px; /* 圆角 */
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
+  height: 80vh; /* 设置容器高度为视口高度的 80% */
+  overflow-y: auto; /* 当内容超出容器高度时,显示垂直滚动条 */
+  scrollbar-width: none; /* Firefox */
+  -ms-overflow-style: none; /* Internet Explorer 10+ */
+}
+
+.loading-message {
+  text-align: center;
+  font-size: 18px;
+  color: #999;
+  padding: 20px;
+}
+
+.error-message {
+  text-align: center;
+  font-size: 18px;
+  color: #ff0000; /* 红色错误信息 */
+  padding: 20px;
+}
+
+.title {
+  font-size: 36px;
+  text-align: center;
+  margin-bottom: 20px;
+  color: #333; /* 深灰色标题 */
+}
+
+.paragraph {
+  margin-bottom: 20px;
+}
+
+p {
+  font-size: 16px;
+  line-height: 1.8; /* 增大行高 */
+  color: #666; /* 灰色文字 */
+}
+
+.intro-image {
+  max-width: 100%;
+  height: auto;
+  border-radius: 4px; /* 图片圆角 */
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 图片阴影 */
+  margin-bottom: 10px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .software-intro-container {
+    padding: 15px;
+    height: 90vh; /* 在小屏幕上,调整容器高度为视口高度的 90% */
+  }
+
+  .title {
+    font-size: 28px;
+  }
+
+  p {
+    font-size: 14px;
+  }
+}
+</style>

+ 92 - 0
src/views/menu/IntroductionUpdate.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="parent-container">
+    <div class="button-group">
+      <el-button
+        v-for="(button, index) in buttons"
+        :key="index"
+        type="primary"
+        :class="{ 'is-active': currentTargetId === parseInt(button.targetId) }"
+        @click="showComponent(parseInt(button.targetId))"
+      >
+        {{ button.label }}
+      </el-button>
+    </div>
+    <IntroUpdateModal
+      :targetId="currentTargetId"
+      :isVisible="!!currentTargetId"
+      @updateSuccess="handleUpdateSuccess"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue';
+import IntroUpdateModal from './IntroUpdateModal.vue';
+
+const buttons = [
+  { label: '软件简介更新', targetId: '1' },
+  { label: '项目简介更新', targetId: '2' },
+  { label: '研究成果更新', targetId: '3' },
+  { label: '团队信息更新', targetId: '4' }
+];
+
+const currentTargetId = ref<number | null>(null);
+
+const showComponent = (id: number) => {
+  currentTargetId.value = id;
+};
+
+const handleUpdateSuccess = () => {
+  console.log('子组件更新成功事件已接收');
+};
+
+// 页面加载时默认选中第一个按钮
+onMounted(() => {
+  showComponent(parseInt(buttons[0].targetId));
+});
+</script>
+
+<style scoped>
+.parent-container {
+  padding: 10px;
+  width: 80%;
+  max-width: 1200px;
+  margin: 0 auto;
+  background: #f0f8ff;
+  border-radius: 15px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+}
+
+.button-group {
+  margin-bottom: 15px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 15px;
+}
+
+.el-button {
+  padding: 8px 15px;
+  border-radius: 8px;
+  font-size: 16px;
+  font-weight: 500;
+  background-color: #e0f2ff; /* 正常状态背景色 */
+  color: #007bff; /* 正常状态文字颜色 */
+  border: none;
+  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+  transition: all 0.3s ease;
+}
+
+.el-button:hover {
+  background-color: #b3d9ff; /* 悬停状态背景色 */
+  color: #0056b3; /* 悬停状态文字颜色 */
+  transform: translateY(-2px);
+  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
+}
+
+.is-active {
+  background-color: #007bff; /* 选中状态背景色 */
+  color: white; /* 选中状态文字颜色 */
+  transform: scale(1.05);
+  box-shadow: 0 4px 15px rgba(0, 123, 255, 0.2);
+}
+</style>

+ 17 - 0
src/views/menu/Overview.vue

@@ -0,0 +1,17 @@
+<!--项目简介-->
+<template>
+  <div class="parent-container">
+    <Introduce :targetId="2" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import Introduce from './Introduce.vue'
+</script>
+
+<style scoped>
+.parent-container {
+  padding: 20px;
+  background-color: #f0f8ff; 
+}
+</style>

+ 17 - 0
src/views/menu/ResearchFindings.vue

@@ -0,0 +1,17 @@
+<!--项目成果-->
+<template>
+  <div class="parent-container">
+    <Introduce :targetId="3" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import Introduce from './Introduce.vue'
+</script>
+
+<style scoped>
+.parent-container {
+  padding: 20px;
+  background-color: #f0f8ff; 
+}
+</style>

+ 182 - 0
src/views/menu/RichTextEditor.vue

@@ -0,0 +1,182 @@
+<template>
+  <div class="rich-text-editor-container">
+    <Toolbar
+      class="rich-text-toolbar"
+      :editor="editorRef"
+      :defaultConfig="toolbarConfig"
+      mode="default"
+    />
+    <Editor
+      class="rich-text-editor"
+      :style="{ height: '300px', overflowY: 'hidden' }"
+      v-model="localValue"
+      :defaultConfig="editorConfig"
+      mode="default"
+      @onCreated="handleCreated"
+      @customPaste="customPaste"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, defineProps, defineEmits, watch } from 'vue';
+import '@wangeditor/editor/dist/css/style.css';
+import { onBeforeUnmount, shallowRef } from 'vue';
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+import axios from 'axios';
+
+const props = defineProps({
+  modelValue: String
+});
+
+const emits = defineEmits(['update:modelValue']);
+
+const localValue = ref(props.modelValue);
+
+const editorRef = shallowRef();
+
+const toolbarConfig = ref();
+const editorConfig = ref({ placeholder: '请输入内容...', MENU_CONF: {} });
+
+// 自定义图片上传
+editorConfig.value.MENU_CONF['uploadImage'] = {
+  async customUpload(file, insertFn) {
+    try {
+      const formData = new FormData();
+      formData.append('image', file);
+      const response = await axios.post('http://127.0.0.1:5000/upload-image', formData, {
+        headers: {
+          'Content-Type': 'multipart/form-data'
+        }
+      });
+      const imageUrl = response.data.imageUrl;
+      insertFn(imageUrl, 'img');
+    } catch (error) {
+      console.error('图片上传失败:', error);
+    }
+  },
+};
+
+// 自定义视频上传
+editorConfig.value.MENU_CONF['uploadVideo'] = {
+  async customUpload(file, insertFn) {
+    console.log('上传视频', file);
+  },
+};
+
+const handleCreated = (editor) => {
+  editorRef.value = editor;
+  console.log(editorConfig.value.MENU_CONF, 'editorConfig.value');
+};
+
+const customPaste = (editor, event, callback) => {
+  const text = event.clipboardData.getData('text/plain');
+  if (text) {
+    editor.insertText(text);
+    event.preventDefault();
+    callback(false);
+  }
+};
+
+onBeforeUnmount(() => {
+  const editor = editorRef.value;
+  if (editor) {
+    editor.destroy();
+  }
+});
+
+const updateValue = () => {
+  emits('update:modelValue', localValue.value);
+};
+
+// 监听 localValue 变化,更新父组件的值
+watch(localValue, (newValue, oldValue) => {
+  if (newValue!== props.modelValue) {
+    updateValue();
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.rich-text-editor-container {
+  width: 90%;
+  border: 1px solid #e0e0e0;
+  border-radius: 8px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  margin: 0 auto;
+
+  /* 让容器在小屏幕下也能自适应 */
+  @media (max-width: 768px) {
+    width: 100%;
+  }
+}
+
+.rich-text-toolbar {
+  background-color: #f8f9fa;
+  border-bottom: 1px solid #e0e0e0;
+  padding: 5px 8px;
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+
+  /* 工具栏按钮样式 */
+  .w-e-menu {
+    margin-right: 5px;
+    margin-bottom: 4px;
+
+    button {
+      color: #333;
+      border: none;
+      background: transparent;
+      cursor: pointer;
+      padding: 4px 6px;
+      border-radius: 4px;
+      transition: background-color 0.3s ease;
+
+      &:hover {
+        background-color: #e9ecef;
+      }
+
+      &:active {
+        background-color: #dce0e4;
+      }
+    }
+
+    /* 下拉菜单样式 */
+    .w-e-select {
+      color: #333;
+      border: 1px solid #e0e0e0;
+      background-color: white;
+      border-radius: 4px;
+      padding: 3px 6px;
+      cursor: pointer;
+      transition: border-color 0.3s ease;
+
+      &:hover {
+        border-color: #999;
+      }
+    }
+  }
+}
+
+.rich-text-editor {
+  padding: 12px;
+  font-size: 16px;
+  line-height: 1.6;
+  color: #333;
+  /* 编辑区域滚动条样式 */
+  &::-webkit-scrollbar {
+    width: 8px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #ccc;
+    border-radius: 4px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background-color: #f1f1f1;
+  }
+}
+</style>

+ 333 - 0
src/views/menu/SoilAcidReductionIterativeEvolution.vue

@@ -0,0 +1,333 @@
+<template>
+  <div class="container">
+    <div class="chart-container">
+      <VueEcharts :option="ecLineOption" ref="ecLineOptionRef" />
+    </div>
+    <p class="sub-title">初代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecInitScatterOption" ref="ecInitScatterOptionRef" />
+    </div>
+    <p class="sub-title">中间代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecMidScatterOption" ref="ecMidScatterOptionRef" />
+    </div>
+    <p class="sub-title">最终代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecFinalScatterOption" ref="ecFinalScatterOptionRef" />
+    </div>
+  </div>
+</template>
+
+<script setup lang='ts' name=''>
+import {ref} from 'vue'
+import VueEcharts from 'vue-echarts';
+import 'echarts';
+
+const ecLineOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecInitScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecMidScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecFinalScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+
+// 计算数据范围的函数
+const calculateDataRange = (data) => {
+  const xValues = data.map(item => item[0]);
+  const yValues = data.map(item => item[1]);
+  return {
+    xMin: Math.min(...xValues),
+    xMax: Math.max(...xValues),
+    yMin: Math.min(...yValues),
+    yMax: Math.max(...yValues)
+  };
+};
+
+// 反酸模型  初代  散点图
+const getInitScatterOption=()=>{
+
+  const scatterData = [[0.12931, 0.10315928999999999], [0.066298, 0.10226514000000003], [0.057692, 0.10226514000000003], [0.072464, 0.10339078000000003], [0.146414, 0.10000317000000003], [0.087263, 0.09199080000000004], [0.096983, 0.09947644], [0.070505, 0.10142657000000004], [0.052497, 0.09956722000000007], [0.166515, 0.10179712], [0.063291, 0.10339078000000003]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '4%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+// 反酸模型  中间代  散点图
+const getMidScatterOption=()=>{
+  const scatterData = [[0.12931, 0.09595878000000002], [0.066298, 0.10344700000000003], [0.057692, 0.10344700000000003], [0.072464, 0.09011803], [0.146414, 0.0853504500000001], [0.087263, 0.07407179000000012], [0.096983, 0.10581049999999995], [0.070505, 0.09876380000000004], [0.052497, 0.08568465000000008], [0.166515, 0.13348440999999997], [0.063291, 0.09011803]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '4%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+// 反酸模型  最终代  散点图
+const getFinalScatterOption=() => {
+
+  const scatterData = [[0.12931, 0.1144982841836412], [0.066298, 0.07733075000000009],
+    [0.057692, 0.07784833000000009], [0.072464, 0.09429906104591025],
+    [0.146414, 0.11774272000000004], [0.087263, 0.07587641627546172],
+    [0.096983, 0.12344755999999983], [0.070505, 0.06424743000000006],
+    [0.052497, 0.07665224568865422], [0.166515, 0.15591779999999988],
+    [0.063291, 0.09275175104591024]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '4%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+
+//获取折线图配置
+const getLineOption=()=>{
+  return{
+    tooltip:{
+      trigger:'axis'
+    },
+    legend:{
+      data:['Random Forest', 'XGBoost', 'Gradient Boosting']  // 模型名称
+    },
+    grid: {
+      left: '3%',
+      right: '17%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: '模型迭代',
+      type: 'category',
+      boundaryGap: false,
+      data: ['1代','2代','3代','4代','5代','6代','7代','8代','9代']  // train_sizes按10%递增
+    },
+    yAxis: {
+      name: 'Score (R^2)',
+      type: 'value'
+    },
+    series: [
+      {
+        name: 'Random Forest',
+        type: 'line',
+        data: [-0.07014332070467688, 0.16174446067644666, 0.45539363923645115, 0.42496898634299696, 0.4538427686692541, 0.418902219699232, 0.3944331740214546, 0.5036773554206873, 0.6231911298905934, 0.7017514238881619]
+      },
+      {
+        name: 'XGBoost',
+        type: 'line',
+        data: [-0.5854699949971149, 0.12632204933742897, 0.5552415957727412, 0.36024885147666674, 0.3983302490476677, 0.11693728875627551, 0.41317321044147026, 0.7833174829404705, 0.6626050730438451, 0.8168196535959388]
+      },
+      {
+        name: 'Gradient Boosting',
+        type: 'line',
+        data: [-0.2099996080229254, 0.2604127444757308, 0.5544068626708099, 0.37487088504748367, 0.32309657868722486, 0.24740671740183884, 0.4949107161199925, 0.694806526591159, 0.6719430144475025, 0.7889677514137288]
+      }
+    ]
+  }
+}
+
+const ecLineOption=ref(getLineOption());
+const ecInitScatterOption = ref(getInitScatterOption());
+const ecMidScatterOption = ref(getMidScatterOption());
+const ecFinalScatterOption = ref(getFinalScatterOption());
+
+
+</script>
+
+
+<style scoped>
+.container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  gap: 20px;
+}
+
+.sub-title {
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.chart-container {
+  width: 75%;
+  height: 450px;
+  margin-bottom: 20px;
+}
+
+.VueEcharts {
+  width: 100%;
+  height: 100%;
+  margin: 0 10px;
+}
+</style>

+ 335 - 0
src/views/menu/SoilAcidificationIterativeEvolution.vue

@@ -0,0 +1,335 @@
+<template>
+  <div class="container">
+    <div class="chart-container">
+      <VueEcharts :option="ecLineOption" ref="ecLineOptionRef" />
+    </div>
+    <p class="sub-title">初代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecInitScatterOption" ref="ecInitScatterOptionRef" />
+    </div>
+    <p class="sub-title">中间代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecMidScatterOption" ref="ecMidScatterOptionRef" />
+    </div>
+    <p class="sub-title">最终代散点图</p>
+    <div class="chart-container">
+      <VueEcharts :option="ecFinalScatterOption" ref="ecFinalScatterOptionRef" />
+    </div>
+  </div>
+</template>
+
+<script setup lang='ts' name=''>
+import {ref} from 'vue'
+import VueEcharts from 'vue-echarts';
+import 'echarts';
+
+const ecLineOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecInitScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecMidScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+const ecFinalScatterOptionRef = ref<InstanceType<typeof VueEcharts> | null>(null);
+
+// 计算数据范围的函数
+const calculateDataRange = (data) => {
+  const xValues = data.map(item => item[0]);
+  const yValues = data.map(item => item[1]);
+  return {
+    xMin: Math.min(...xValues),
+    xMax: Math.max(...xValues),
+    yMin: Math.min(...yValues),
+    yMax: Math.max(...yValues)
+  };
+};
+
+// 反酸模型  初代  散点图
+const getInitScatterOption=()=>{
+
+  const scatterData = [[-0.003333333333333854, -0.4181333333333324], [-0.1733333333333329, -0.26733333333333265], [-0.6233333333333331, -0.3718666666666661], [-0.7088888888888892, -0.3854666666666661], [-0.3366666666666669, -0.3998666666666657], [-0.8888888888888887, -0.36439999999999934], [-0.5633333333333326, -0.6207999999999997], [-0.7333333333333325, -0.36026666666666607], [-0.3366666666666663, -0.29213333333333275], [-1.176666666666666, -0.6095999999999993], [-0.7122222222222225, -0.3807999999999989], [-0.7699999999999996, -0.3718666666666661]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '3%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+// 反酸模型  中间代  散点图
+const getMidScatterOption=()=>{
+  const scatterData = [[-0.003333333333333854, -0.5483999999999993], [-0.1733333333333329, -0.2093333333333331], [-0.6233333333333331, -0.5090000000000002], [-0.7088888888888892, -0.4281333333333331], [-0.3366666666666669, -0.4691333333333336], [-0.8888888888888887, -0.49643333333333267], [-0.5633333333333326, -0.7191999999999996], [-0.7333333333333325, -0.5024666666666666], [-0.3366666666666663, -0.37796666666666623], [-1.176666666666666, -0.6415666666666656], [-0.7122222222222225, -0.43299999999999966], [-0.7699999999999996, -0.499966666666667]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '3%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+// 反酸模型  最终代  散点图
+const getFinalScatterOption=() => {
+
+  const scatterData = [[-0.003333333333333854, -0.45726666666666654], [-0.1733333333333329, -0.1726333333333331],
+    [-0.6233333333333331, -0.5226666666666667], [-0.7088888888888892, -0.4791888888888889],
+    [-0.3366666666666669, -0.3630666666666673], [-0.8888888888888887, -0.48272222222222183],
+    [-0.5633333333333326, -0.7492444444444444], [-0.7333333333333325, -0.5572666666666672],
+    [-0.3366666666666663, -0.29379999999999984], [-1.176666666666666, -0.8544111111111106],
+    [-0.7122222222222225, -0.4959777777777775], [-0.7699999999999996, -0.6149666666666669]];
+
+  const range = calculateDataRange(scatterData);
+  const padding = 0.1;
+  const xMin = range.xMin - Math.abs(range.xMin * padding);
+  const xMax = range.xMax + Math.abs(range.xMax * padding);
+  const yMin = range.yMin - Math.abs(range.yMin * padding);
+  const yMax = range.yMax + Math.abs(range.yMax * padding);
+  const min = Math.min(xMin, yMin)
+  const max = Math.max(xMax, yMax)
+
+  return {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'cross'
+      }
+    },
+    legend: {
+      data: ['True vs Predicted']
+    },
+    grid: {
+      left: '3%',
+      right: '22%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: 'True Values',
+      type: 'value',
+      min: min,
+      max: max
+    },
+    yAxis: {
+      name: 'Predicted Values',
+      type: 'value',
+      min: parseFloat(min.toFixed(2)),
+      max: parseFloat(max.toFixed(2))
+    },
+    series: [
+      {
+        name: 'True vs Predicted',
+        type: 'scatter',
+        data: scatterData,
+        symbolSize: 10,
+        itemStyle: {
+          color: '#1f77b4',
+          opacity: 0.7
+        }
+      },
+      {
+        name: 'Trendline',
+        type: 'line',
+        data: [
+          [min, min],
+          [max, max]
+        ],
+        lineStyle: {
+          type: 'dashed',
+          color: '#ff7f0e',
+          width: 2
+        }
+      }
+    ]
+  };
+}
+
+//获取折线图配置
+const getLineOption=()=>{
+  return{
+    tooltip:{
+      trigger:'axis'
+    },
+    legend:{
+      data:['Random Forest', 'XGBoost', 'Gradient Boosting']  // 模型名称
+    },
+    grid: {
+      left: '3%',
+      right: '17%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      name: '模型迭代',
+      type: 'category',
+      boundaryGap: false,
+      data: ['1代','2代','3代','4代','5代','6代','7代','8代','9代']  // train_sizes按10%递增
+    },
+    yAxis: {
+      name: 'Score (R^2)',
+      type: 'value'
+    },
+    series: [
+      {
+        name: 'Random Forest',
+        type: 'line',
+        data: [-0.17101591951095463, -0.556719360354051, -0.04083550751401055, -0.20858221504075436, 0.07297292282221035, 0.19857845644421734, 0.28407131176770184, 0.27979356883596496, 0.36904808817286416, 0.4183018571701477]  // 使用您的实际R2分数数据
+      },
+      {
+        name: 'XGBoost',
+        type: 'line',
+        data: [-1.1811781145886937, -1.5645641005612534, -0.12619079632263497, 0.03324096120721032, 0.06969290639267578, 0.12375262461601955, 0.5331670468884062, 0.49454793164801647, 0.31904329339597803, 0.2712670704381914]
+      },
+      {
+        name: 'Gradient Boosting',
+        type: 'line',
+        data: [-0.8583039298789095, -1.073316171952042, 0.09659300885027666, 0.06097833957434784, 0.191975498544109, 0.3718334600546489, 0.3948098332187753, 0.4398778520728397, 0.452609022210963, 0.41484634172723023]
+      }
+    ]
+  }
+}
+
+const ecLineOption=ref(getLineOption());
+const ecInitScatterOption = ref(getInitScatterOption());
+const ecMidScatterOption = ref(getMidScatterOption());
+const ecFinalScatterOption = ref(getFinalScatterOption());
+
+
+</script>
+
+
+<style scoped>
+.container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  gap: 20px;
+}
+
+.sub-title {
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.chart-container {
+  width: 75%;
+  height: 450px;
+  margin-bottom: 20px;
+}
+
+.VueEcharts {
+  width: 100%;
+  height: 100%;
+  margin: 0 10px;
+}
+</style>

+ 18 - 0
src/views/menu/SoilPro.vue

@@ -0,0 +1,18 @@
+<!-- 引入组件的父组件 -->
+<template>
+  <div class="parent-container">
+    <Introduce :targetId="1" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import Introduce from './Introduce.vue';
+</script>
+
+<style scoped lang="scss">
+.parent-container {
+  padding: 20px;
+  background-color: #f0f8ff; 
+}
+</style>
+

+ 17 - 0
src/views/menu/Unit.vue

@@ -0,0 +1,17 @@
+<!--团体信息-->
+<template>
+  <div class="parent-container">
+    <Introduce :targetId="4" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import Introduce from './Introduce.vue'
+</script>
+
+<style scoped>
+.parent-container {
+  padding: 20px;
+  background-color: #f0f8ff; 
+}
+</style>

+ 8 - 0
src/views/menu/mapView.vue

@@ -0,0 +1,8 @@
+<script setup lang='ts' name=''>
+</script>
+
+<template>
+  <div class="">地图</div>
+</template>
+
+<style scoped></style>

+ 52 - 0
src/views/packaged/PaginationComponent.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="demo-pagination-block" style="text-align: center; margin-top: 20px;">
+    <el-pagination
+      v-model:current-page="currentPage"
+      v-model:page-size="pageSize"
+      :page-sizes="[10, 20, 30, 40]"
+      layout="total, sizes, prev, pager, next, jumper"
+      :total="total"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, watch, onMounted } from 'vue'
+import { useAttrs } from '@vue/runtime-core'
+
+const props = defineProps<{
+  total: number;
+  currentPage?: number;
+  pageSize?: number;
+}>()
+
+const emit = defineEmits<{
+  (e: 'update:currentPage', value: number): void;
+  (e: 'update:pageSize', value: number): void;
+  (e: 'size-change', value: number): void;
+  (e: 'current-change', value: number): void;
+}>()
+
+let currentPage = ref(props.currentPage || 1)
+let pageSize = ref(props.pageSize || 10)
+
+watch(() => props.currentPage, (newVal) => {
+  if (newVal !== currentPage.value) currentPage.value = newVal
+})
+
+watch(() => props.pageSize, (newVal) => {
+  if (newVal !== pageSize.value) pageSize.value = newVal
+})
+
+watch(currentPage, (newVal) => {
+  emit('update:currentPage', newVal)
+  emit('current-change', newVal)
+})
+
+watch(pageSize, (newVal) => {
+  emit('update:pageSize', newVal)
+  emit('size-change', newVal)
+})
+</script>

+ 77 - 0
src/views/thres.vue

@@ -0,0 +1,77 @@
+<template>
+  <div>
+    <!-- 显示当前阈值 -->
+    <p>当前阈值: {{ currentThreshold }}</p>
+    
+    <!-- 显示默认阈值 -->
+    <p>默认阈值: {{ defaultThreshold }}</p>
+
+    <!-- 输入框和按钮用于设置新阈值 -->
+    <el-input v-model="newThreshold" placeholder="请输入新阈值"></el-input>
+    <el-button type="primary" @click="updateThreshold">更新阈值</el-button>
+  </div>
+</template>
+
+<script>
+import axios from 'axios';
+
+export default {
+  data() {
+    return {
+      currentThreshold: null,
+      defaultThreshold: null,
+      newThreshold: '' // 新增阈值输入框的绑定值
+    };
+  },
+  methods: {
+    // 获取阈值信息
+    fetchThresholds() {
+      axios.get('https://127.0.0.1:5000/get-threshold')
+        .then(response => {
+          this.currentThreshold = response.data.current_threshold;
+          this.defaultThreshold = response.data.default_threshold;
+        })
+        .catch(error => {
+          console.error("获取阈值失败:", error);
+        });
+    },
+    // 更新阈值
+    updateThreshold() {
+      const thresholdValue = parseFloat(this.newThreshold); // 将输入转换为浮点数
+      if (isNaN(thresholdValue) || thresholdValue <= 0) {
+        this.$message.error('请输入有效的正数');
+        return;
+      }
+      
+      axios.post('https://127.0.0.1:5000/update-threshold', { threshold: thresholdValue })
+        .then(response => {
+          if (response.data.success) {
+            this.currentThreshold = thresholdValue; // 更新当前阈值显示
+            this.$message.success(response.data.message);
+          } else {
+            this.$message.error(response.data.error);
+          }
+        })
+        .catch(error => {
+          console.error("更新阈值失败:", error);
+          this.$message.error('更新阈值时发生错误');
+        });
+    }
+  },
+  mounted() {
+    // 页面加载时获取阈值
+    this.fetchThresholds();
+  }
+}
+</script>
+
+<style scoped>
+/* 添加一些样式让页面看起来更好 */
+.el-input {
+  margin-top: 10px;
+}
+
+.el-button {
+  margin-top: 10px;
+}
+</style>

+ 12 - 0
tsconfig.app.json

@@ -0,0 +1,12 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.dom.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+  "exclude": ["src/**/__tests__/*"],
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  }
+}

+ 14 - 0
tsconfig.json

@@ -0,0 +1,14 @@
+{
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.node.json"
+    },
+    {
+      "path": "./tsconfig.app.json"
+    },
+    {
+      "path": "./tsconfig.vitest.json"
+    }
+  ]
+}

+ 18 - 0
tsconfig.node.json

@@ -0,0 +1,18 @@
+{
+  "extends": "@tsconfig/node22/tsconfig.json",
+  "include": [
+    "vite.config.*",
+    "vitest.config.*",
+    "cypress.config.*",
+    "nightwatch.conf.*",
+    "playwright.config.*"
+  ],
+  "compilerOptions": {
+    "noEmit": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+
+    "module": "ESNext",
+    "moduleResolution": "Bundler",
+    "types": ["node"]
+  }
+}

+ 11 - 0
tsconfig.vitest.json

@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.app.json",
+  "include": ["src/**/__tests__/*", "env.d.ts"],
+  "exclude": [],
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
+
+    "lib": [],
+    "types": ["node", "jsdom"]
+  }
+}

+ 51 - 0
vite.config.ts

@@ -0,0 +1,51 @@
+import { fileURLToPath, URL } from 'node:url'
+
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import vueDevTools from 'vite-plugin-vue-devtools'
+
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+
+import Icons from 'unplugin-icons/vite'
+import IconsResolver from 'unplugin-icons/resolver'
+
+// https://vite.dev/config/
+export default defineConfig({
+  plugins: [
+    {
+      "compilerOptions": {
+        "types": ["node"]
+      }
+    },
+    vue(),
+    vueDevTools(),
+    AutoImport({
+      imports: ['vue'],
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          prefix: 'Icon',
+        }),
+      ],
+      eslintrc: { enabled: true },
+    }),
+    Components({
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          enabledCollections: ['ep'],
+        }),
+      ],
+    }),
+    Icons({
+      autoInstall: true,
+    }),
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    },
+  },
+})

+ 46 - 0
vitest.config.ts

@@ -0,0 +1,46 @@
+import { fileURLToPath, URL } from 'node:url'
+
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import vueDevTools from 'vite-plugin-vue-devtools'
+
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+
+import Icons from 'unplugin-icons/vite'
+import IconsResolver from 'unplugin-icons/resolver'
+
+// https://vite.dev/config/
+export default defineConfig({
+  plugins: [
+    vue(),
+    vueDevTools(),
+    AutoImport({
+      imports: ['vue'],
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          prefix: 'Icon',
+        }),
+      ],
+      eslintrc: { enabled: true },
+    }),
+    Components({
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          enabledCollections: ['ep'],
+        }),
+      ],
+    }),
+    Icons({
+      autoInstall: true,
+    }),
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    },
+  },
+})

File diff suppressed because it is too large
+ 46 - 0
vitest.config.ts.timestamp-1740657859395-685793505d838.mjs


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