liushengqiang hai 1 ano
achega
a6618e2dbb
Modificáronse 86 ficheiros con 10970 adicións e 0 borrados
  1. 3 0
      .browserslistrc
  2. 14 0
      .editorconfig
  3. 4 0
      .eslintignore
  4. 19 0
      .eslintrc.js
  5. 18 0
      .gitignore
  6. 9 0
      .postcssrc.js
  7. 9 0
      .prettierrc.js
  8. 21 0
      LICENSE
  9. 124 0
      README.md
  10. 20 0
      babel.config.js
  11. 17 0
      components.d.ts
  12. 58 0
      index.html
  13. 95 0
      package.json
  14. 6 0
      plopfile.js
  15. 5386 0
      pnpm-lock.yaml
  16. BIN=BIN
      public/favicon.ico
  17. 99 0
      public/flexible.js
  18. 11 0
      src/App.tsx
  19. 10 0
      src/component-ui/README.md
  20. 129 0
      src/component-ui/global.less
  21. 218 0
      src/component-ui/index.less
  22. 28 0
      src/component-ui/k-action-sheet/index.module.less
  23. 84 0
      src/component-ui/k-action-sheet/index.tsx
  24. 47 0
      src/component-ui/k-dialog/index.module.less
  25. 97 0
      src/component-ui/k-dialog/index.tsx
  26. BIN=BIN
      src/components/m-empty/images/404.png
  27. BIN=BIN
      src/components/m-empty/images/empty.png
  28. BIN=BIN
      src/components/m-empty/images/network.png
  29. 25 0
      src/components/m-empty/index.module.less
  30. 62 0
      src/components/m-empty/index.tsx
  31. 0 0
      src/components/m-full-refresh/datas/data.json
  32. 21 0
      src/components/m-full-refresh/index.module.less
  33. 77 0
      src/components/m-full-refresh/index.tsx
  34. BIN=BIN
      src/components/m-full-refresh/loading.gif
  35. 1 0
      src/components/m-full-refresh/loading.json
  36. 0 0
      src/components/m-header/index.module.less
  37. 123 0
      src/components/m-header/index.tsx
  38. 35 0
      src/components/m-image-preview/index.module.less
  39. 281 0
      src/components/m-image-preview/index.tsx
  40. 45 0
      src/components/m-img-code/index.module.less
  41. 129 0
      src/components/m-img-code/index.tsx
  42. 112 0
      src/components/m-popup/index.tsx
  43. 47 0
      src/components/m-protocol/index.module.less
  44. 139 0
      src/components/m-protocol/index.tsx
  45. 26 0
      src/components/m-qrcode/index.module.less
  46. 64 0
      src/components/m-qrcode/index.tsx
  47. 73 0
      src/components/m-search/index.module.less
  48. 87 0
      src/components/m-search/index.tsx
  49. 13 0
      src/components/m-sticky/index.module.less
  50. 126 0
      src/components/m-sticky/index.tsx
  51. 67 0
      src/components/m-uploader/index.module.less
  52. 389 0
      src/components/m-uploader/index.tsx
  53. 388 0
      src/components/m-uploader/inside.tsx
  54. 53 0
      src/components/m-video/index.module.less
  55. 217 0
      src/components/m-video/index.tsx
  56. 0 0
      src/helpers/constant.ts
  57. 16 0
      src/helpers/deep-clone.ts
  58. 116 0
      src/helpers/native-message.ts
  59. 112 0
      src/helpers/request.ts
  60. 430 0
      src/helpers/toolsValidate.ts
  61. 134 0
      src/helpers/utils.ts
  62. 42 0
      src/main.ts
  63. 50 0
      src/router/index.ts
  64. 17 0
      src/router/router-root.ts
  65. 24 0
      src/router/routes-common.ts
  66. 5 0
      src/shims-vue.d.ts
  67. 56 0
      src/state.ts
  68. 173 0
      src/styles/index.less
  69. 0 0
      src/views/404/index.module.less
  70. 33 0
      src/views/404/index.tsx
  71. 8 0
      src/views/courseware-play/index.tsx
  72. 32 0
      src/views/layout/auth.module.less
  73. 112 0
      src/views/layout/auth.tsx
  74. BIN=BIN
      src/views/layout/images/bottom_manage_bg.png
  75. BIN=BIN
      src/views/layout/images/bottom_student_bg.png
  76. BIN=BIN
      src/views/layout/images/bottom_teacher_bg.png
  77. BIN=BIN
      src/views/layout/images/top_bg.png
  78. 84 0
      src/views/layout/login.module.less
  79. 206 0
      src/views/layout/login.tsx
  80. 1 0
      src/vite-env.d.ts
  81. 24 0
      templates/component/index.hbs
  82. 61 0
      templates/component/prompt.js
  83. 9 0
      templates/utils.js
  84. 25 0
      tsconfig.json
  85. 10 0
      tsconfig.node.json
  86. 64 0
      vite.config.ts

+ 3 - 0
.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+# http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 4 - 0
.eslintignore

@@ -0,0 +1,4 @@
+public
+dist
+*.d.ts
+*

+ 19 - 0
.eslintrc.js

@@ -0,0 +1,19 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: [
+    'plugin:vue/vue3-essential',
+    'eslint:recommended',
+    '@vue/typescript/recommended',
+    '@vue/prettier'
+  ],
+  parserOptions: {
+    ecmaVersion: 2020,
+    sourceType: 'module'
+  },
+  rules: {
+    '@typescript-eslint/no-explicit-any': ['off']
+  }
+};

+ 18 - 0
.gitignore

@@ -0,0 +1,18 @@
+node_modules
+.DS_Store
+# dist
+dist-ssr
+*.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+tests/**/coverage/
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln

+ 9 - 0
.postcssrc.js

@@ -0,0 +1,9 @@
+module.exports = {
+  plugins: {
+    autoprefixer: {},
+    'postcss-pxtorem': {
+      rootValue: 37.5,
+      propList: ['*'],
+    },
+  }
+}

+ 9 - 0
.prettierrc.js

@@ -0,0 +1,9 @@
+module.exports = {
+  bracketSpacing: true,
+  jsxBracketSameLine: true,
+  singleQuote: true,
+  arrowParens: 'avoid',
+  trailingComma: 'none',
+  // 避免截断标签
+  htmlWhitespaceSensitivity: 'ignore'
+};

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 踏学吾痕
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 124 - 0
README.md

@@ -0,0 +1,124 @@
+# vue-vite-h5
+
+This template should help get you started developing mobile applications with Vue3 and Typescript and Vant in Vite.
+
+## Project setup
+
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+
+```
+npm start
+```
+
+### Compiles and minifies for production
+
+```
+npm build
+```
+
+### Lints and fixes files (eslint + prettier)
+
+```
+npm lint
+```
+
+### Generate component(page) templates for development
+
+```
+npm generate
+```
+
+### postMessage API 方法
+
+```
+goBack
+back
+getNavHeight
+getToken
+chooseFile
+login
+joinChatGroup
+openWebView
+callPhone
+shareTripartite
+savePicture
+```
+
+### Customize configuration
+
+See [Configuration Reference](https://vitejs.dev/config/).
+
+## Browser adaptation
+
+### Rem Unit (default)
+
+Vant uses `px` unit by default,You can use tools such as `postcss-pxtorem` to transform `px` unit to `rem` unit.
+
+- [postcss-pxtorem](https://github.com/cuth/postcss-pxtorem)
+- [lib-flexible](https://github.com/amfe/lib-flexible)
+
+#### PostCSS Config
+
+PostCSS config example:
+
+```js
+// .postcssrc.js
+module.exports = {
+  plugins: {
+    'postcss-pxtorem': {
+      rootValue: 37.5,
+      propList: ['*']
+    }
+  }
+};
+```
+
+### Viewport Units
+
+you can use tools such as [postcss--px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) to transform `px` unit to viewport units (vw, vh, vmin, vmax).
+
+#### PostCSS Config
+
+PostCSS config example:
+
+```js
+// .postcssrc.js
+module.exports = {
+  plugins: {
+    'postcss-px-to-viewport': {
+      viewportWidth: 375
+    }
+  }
+};
+```
+
+### Custom rootValue
+
+If the size of the design draft is 750 or other sizes, you can adjust the `rootValue` to:
+
+```js
+// .postcssrc.js
+module.exports = {
+  plugins: {
+    // postcss-pxtorem version >= 5.0.0
+    'postcss-pxtorem': {
+      rootValue({ file }) {
+        return file.indexOf('vant') !== -1 ? 37.5 : 75;
+      },
+      propList: ['*']
+    }
+  }
+};
+```
+
+## Recommended IDE Setup
+
+- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
+
+## Type Support For `.vue` Imports in TS
+
+Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.

+ 20 - 0
babel.config.js

@@ -0,0 +1,20 @@
+module.exports = {
+  presets: [
+    [
+      '@babel/preset-env',
+      {
+        targets: {
+          node: 'current'
+        }
+      }
+    ]
+  ],
+  env: {
+    development: {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
+      plugins: ['dynamic-import-node']
+    }
+  }
+};

+ 17 - 0
components.d.ts

@@ -0,0 +1,17 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+import '@vue/runtime-core'
+
+export {}
+
+declare module '@vue/runtime-core' {
+  export interface GlobalComponents {
+    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    VanButton: typeof import('vant/es')['Button']
+  }
+}

+ 58 - 0
index.html

@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8" />
+  <link rel="icon" href="/favicon.ico" />
+  <meta name="viewport"
+    content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
+  <meta http-equiv="Cache-control" content="no-cache">
+  <meta http-equiv="Cache" content="no-cache">
+  <meta name="apple-mobile-web-app-capable" content="yes" />
+  <!-- 设置苹果工具栏颜色 -->
+  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
+  <!-- 忽略页面中的数字识别为电话,忽略email识别 -->
+  <meta name="format-detection" content="telphone=no, email=no" />
+  <!-- 启用360浏览器的极速模式(webkit) -->
+  <meta name="renderer" content="webkit" />
+  <!-- 避免IE使用兼容模式 -->
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+  <meta name="HandheldFriendly" content="true" />
+  <!-- uc强制竖屏 -->
+  <meta name="screen-orientation" content="portrait" />
+  <!-- QQ强制竖屏 -->
+  <meta name="x5-orientation" content="portrait" />
+  <!-- UC强制全屏 -->
+  <meta name="full-screen" content="yes" />
+  <!-- QQ强制全屏 -->
+  <meta name="x5-fullscreen" content="true" />
+  <!-- UC应用模式 -->
+  <meta name="browsermode" content="application" />
+  <!-- QQ应用模式 -->
+  <meta name="x5-page-mode" content="app" />
+  <!-- 设置在apple上以应用模式启动时,是否全屏 -->
+  <meta name="apple-touch-fullscreen" content="yes" />
+  <!-- windows phone 点击无高光 -->
+  <meta name="msapplication-tap-highlight" content="no" />
+  <meta name="referrer" content="no-referrer" />
+  <title>学生端</title>
+  <script src="/flexible.js" charset="UTF-8"></script>
+</head>
+
+<body>
+  <div id="app"></div>
+  <script type="module" src="/src/main.ts"></script>
+  <script type="text/javascript">
+    // var url =  window.location.origin + '/_AMapService'
+    window._AMapSecurityConfig = {
+      serviceHost: 'https://online.dayaedu.com/_AMapService'
+    }
+
+      // window._AMapSecurityConfig = {
+      //     serviceHost: 'http://192.168.3.120:8001/_AMapService',
+      //     // 例如 :serviceHost:'http://1.1.1.1:80/_AMapService',
+      //   }
+  </script>
+</body>
+
+</html>

+ 95 - 0
package.json

@@ -0,0 +1,95 @@
+{
+  "name": "vue-vite-h5",
+  "version": "0.2.0",
+  "license": "MIT",
+  "author": "LZHD",
+  "description": "Developing with Vue 3 and Typescript in Vite.",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/LZHD/vue-vite-h5"
+  },
+  "bugs": {
+    "url": "https://github.com/LZHD/vue-vite-h5/issues"
+  },
+  "homepage": "https://github.com/LZHD/vue-vite-h5#readme",
+  "scripts": {
+    "dev": "vite",
+    "start": "npm run dev",
+    "build": "vue-tsc --noEmit && vite build",
+    "serve": "vite preview",
+    "lint": "eslint --ext .js,.jsx,.vue,.ts,.tsx src",
+    "generate": "plop",
+    "prepare": "husky install"
+  },
+  "dependencies": {
+    "@amap/amap-jsapi-loader": "^1.0.1",
+    "@vant/use": "^1.5.1",
+    "@vueuse/core": "^10.1.2",
+    "clean-deep": "^3.4.0",
+    "dayjs": "^1.11.7",
+    "echarts": "^5.4.2",
+    "html2canvas": "^1.4.1",
+    "numeral": "^2.0.6",
+    "plyr": "^3.7.8",
+    "qrcode": "^1.5.3",
+    "query-string": "^8.1.0",
+    "swiper": "^9.3.2",
+    "terser": "^5.17.6",
+    "umi-request": "^1.4.0",
+    "vant": "^4.1.2",
+    "vconsole": "^3.15.0",
+    "vue": "^3.2.47",
+    "vue-awesome-swiper": "^5.0.1",
+    "vue-router": "^4.1.6",
+    "vue3-lottie": "^2.7.0"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.21.4",
+    "@babel/preset-env": "^7.21.4",
+    "@types/node": "^16.18.23",
+    "@typescript-eslint/eslint-plugin": "^5.57.1",
+    "@typescript-eslint/parser": "^5.57.1",
+    "@vitejs/plugin-legacy": "^4.0.3",
+    "@vitejs/plugin-vue": "^4.1.0",
+    "@vitejs/plugin-vue-jsx": "^3.0.1",
+    "@vue/babel-plugin-jsx": "^1.1.1",
+    "@vue/compiler-sfc": "^3.2.47",
+    "@vue/eslint-config-prettier": "^7.1.0",
+    "@vue/eslint-config-typescript": "^11.0.2",
+    "autoprefixer": "^10.4.14",
+    "babel-plugin-dynamic-import-node": "^2.3.3",
+    "eslint": "^8.38.0",
+    "eslint-plugin-prettier": "^4.2.1",
+    "eslint-plugin-vue": "^9.10.0",
+    "husky": "^8.0.0",
+    "less": "^4.1.3",
+    "lint-staged": "^13.2.2",
+    "plop": "^3.1.2",
+    "postcss": "^8.4.21",
+    "postcss-pxtorem": "^6.0.0",
+    "prettier": "^2.8.7",
+    "typescript": "^5.0.4",
+    "unplugin-vue-components": "^0.24.1",
+    "vite": "^4.2.1",
+    "vite-plugin-eslint": "^1.8.1",
+    "vue-eslint-parser": "^9.1.1",
+    "vue-tsc": "^1.2.0",
+    "yorkie": "^2.0.0"
+  },
+  "gitHooks": {
+    "pre-commit": "lint-staged"
+  },
+  "lint-staged": {
+    "*.{js,jsx,vue,ts,tsx}": [
+      "eslint --fix"
+    ]
+  },
+  "engines": {
+    "node": ">=14.20.0"
+  },
+  "config": {
+    "commitizen": {
+      "path": "./node_modules/cz-conventional-changelog"
+    }
+  }
+}

+ 6 - 0
plopfile.js

@@ -0,0 +1,6 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const componentGenerator = require('./templates/component/prompt');
+
+module.exports = function (plop) {
+  plop.setGenerator('component', componentGenerator);
+};

+ 5386 - 0
pnpm-lock.yaml

@@ -0,0 +1,5386 @@
+lockfileVersion: '6.0'
+
+dependencies:
+  '@amap/amap-jsapi-loader':
+    specifier: ^1.0.1
+    version: 1.0.1
+  '@vant/use':
+    specifier: ^1.5.1
+    version: 1.5.1(vue@3.2.47)
+  '@vueuse/core':
+    specifier: ^10.1.2
+    version: 10.1.2(vue@3.2.47)
+  clean-deep:
+    specifier: ^3.4.0
+    version: 3.4.0
+  dayjs:
+    specifier: ^1.11.7
+    version: 1.11.7
+  echarts:
+    specifier: ^5.4.2
+    version: 5.4.2
+  html2canvas:
+    specifier: ^1.4.1
+    version: 1.4.1
+  numeral:
+    specifier: ^2.0.6
+    version: 2.0.6
+  plyr:
+    specifier: ^3.7.8
+    version: 3.7.8
+  qrcode:
+    specifier: ^1.5.3
+    version: 1.5.3
+  query-string:
+    specifier: ^8.1.0
+    version: 8.1.0
+  swiper:
+    specifier: ^9.3.2
+    version: 9.3.2
+  terser:
+    specifier: ^5.17.6
+    version: 5.17.6
+  umi-request:
+    specifier: ^1.4.0
+    version: 1.4.0
+  vant:
+    specifier: ^4.1.2
+    version: 4.1.2(vue@3.2.47)
+  vconsole:
+    specifier: ^3.15.0
+    version: 3.15.0
+  vue:
+    specifier: ^3.2.47
+    version: 3.2.47
+  vue-awesome-swiper:
+    specifier: ^5.0.1
+    version: 5.0.1(swiper@9.3.2)(vue@3.2.47)
+  vue-router:
+    specifier: ^4.1.6
+    version: 4.1.6(vue@3.2.47)
+  vue3-lottie:
+    specifier: ^2.7.0
+    version: 2.7.0(vue@3.2.47)
+
+devDependencies:
+  '@babel/core':
+    specifier: ^7.21.4
+    version: 7.21.4
+  '@babel/preset-env':
+    specifier: ^7.21.4
+    version: 7.21.4(@babel/core@7.21.4)
+  '@types/node':
+    specifier: ^16.18.23
+    version: 16.18.23
+  '@typescript-eslint/eslint-plugin':
+    specifier: ^5.57.1
+    version: 5.57.1(@typescript-eslint/parser@5.57.1)(eslint@8.38.0)(typescript@5.0.4)
+  '@typescript-eslint/parser':
+    specifier: ^5.57.1
+    version: 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+  '@vitejs/plugin-legacy':
+    specifier: ^4.0.3
+    version: 4.0.3(terser@5.17.6)(vite@4.2.1)
+  '@vitejs/plugin-vue':
+    specifier: ^4.1.0
+    version: 4.1.0(vite@4.2.1)(vue@3.2.47)
+  '@vitejs/plugin-vue-jsx':
+    specifier: ^3.0.1
+    version: 3.0.1(vite@4.2.1)(vue@3.2.47)
+  '@vue/babel-plugin-jsx':
+    specifier: ^1.1.1
+    version: 1.1.1(@babel/core@7.21.4)
+  '@vue/compiler-sfc':
+    specifier: ^3.2.47
+    version: 3.2.47
+  '@vue/eslint-config-prettier':
+    specifier: ^7.1.0
+    version: 7.1.0(eslint@8.38.0)(prettier@2.8.7)
+  '@vue/eslint-config-typescript':
+    specifier: ^11.0.2
+    version: 11.0.2(eslint-plugin-vue@9.10.0)(eslint@8.38.0)(typescript@5.0.4)
+  autoprefixer:
+    specifier: ^10.4.14
+    version: 10.4.14(postcss@8.4.21)
+  babel-plugin-dynamic-import-node:
+    specifier: ^2.3.3
+    version: 2.3.3
+  eslint:
+    specifier: ^8.38.0
+    version: 8.38.0
+  eslint-plugin-prettier:
+    specifier: ^4.2.1
+    version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.38.0)(prettier@2.8.7)
+  eslint-plugin-vue:
+    specifier: ^9.10.0
+    version: 9.10.0(eslint@8.38.0)
+  husky:
+    specifier: ^8.0.0
+    version: 8.0.0
+  less:
+    specifier: ^4.1.3
+    version: 4.1.3
+  lint-staged:
+    specifier: ^13.2.2
+    version: 13.2.2
+  plop:
+    specifier: ^3.1.2
+    version: 3.1.2
+  postcss:
+    specifier: ^8.4.21
+    version: 8.4.21
+  postcss-pxtorem:
+    specifier: ^6.0.0
+    version: 6.0.0(postcss@8.4.21)
+  prettier:
+    specifier: ^2.8.7
+    version: 2.8.7
+  typescript:
+    specifier: ^5.0.4
+    version: 5.0.4
+  unplugin-vue-components:
+    specifier: ^0.24.1
+    version: 0.24.1(vue@3.2.47)
+  vite:
+    specifier: ^4.2.1
+    version: 4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6)
+  vite-plugin-eslint:
+    specifier: ^1.8.1
+    version: 1.8.1(eslint@8.38.0)(vite@4.2.1)
+  vue-eslint-parser:
+    specifier: ^9.1.1
+    version: 9.1.1(eslint@8.38.0)
+  vue-tsc:
+    specifier: ^1.2.0
+    version: 1.2.0(typescript@5.0.4)
+  yorkie:
+    specifier: ^2.0.0
+    version: 2.0.0
+
+packages:
+
+  /@amap/amap-jsapi-loader@1.0.1:
+    resolution: {integrity: sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==}
+    dev: false
+
+  /@ampproject/remapping@2.2.1:
+    resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.3
+      '@jridgewell/trace-mapping': 0.3.18
+    dev: true
+
+  /@antfu/utils@0.7.2:
+    resolution: {integrity: sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==}
+    dev: true
+
+  /@babel/code-frame@7.21.4:
+    resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/highlight': 7.18.6
+    dev: true
+
+  /@babel/compat-data@7.21.4:
+    resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==}
+    engines: {node: '>=6.9.0'}
+    dev: true
+
+  /@babel/core@7.21.4:
+    resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@ampproject/remapping': 2.2.1
+      '@babel/code-frame': 7.21.4
+      '@babel/generator': 7.21.4
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-module-transforms': 7.21.2
+      '@babel/helpers': 7.21.0
+      '@babel/parser': 7.21.4
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+      convert-source-map: 1.9.0
+      debug: 4.3.4
+      gensync: 1.0.0-beta.2
+      json5: 2.2.3
+      semver: 6.3.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/generator@7.21.4:
+    resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+      '@jridgewell/gen-mapping': 0.3.3
+      '@jridgewell/trace-mapping': 0.3.18
+      jsesc: 2.5.2
+    dev: true
+
+  /@babel/helper-annotate-as-pure@7.18.6:
+    resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9:
+    resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-explode-assignable-expression': 7.18.6
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-compilation-targets@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/compat-data': 7.21.4
+      '@babel/core': 7.21.4
+      '@babel/helper-validator-option': 7.21.0
+      browserslist: 4.21.5
+      lru-cache: 5.1.1
+      semver: 6.3.0
+    dev: true
+
+  /@babel/helper-create-class-features-plugin@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-function-name': 7.21.0
+      '@babel/helper-member-expression-to-functions': 7.21.0
+      '@babel/helper-optimise-call-expression': 7.18.6
+      '@babel/helper-replace-supers': 7.20.7
+      '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+      '@babel/helper-split-export-declaration': 7.18.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helper-create-regexp-features-plugin@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      regexpu-core: 5.3.2
+    dev: true
+
+  /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==}
+    peerDependencies:
+      '@babel/core': ^7.4.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      debug: 4.3.4
+      lodash.debounce: 4.0.8
+      resolve: 1.22.2
+      semver: 6.3.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helper-environment-visitor@7.18.9:
+    resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
+    engines: {node: '>=6.9.0'}
+    dev: true
+
+  /@babel/helper-explode-assignable-expression@7.18.6:
+    resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-function-name@7.21.0:
+    resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/template': 7.20.7
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-hoist-variables@7.18.6:
+    resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-member-expression-to-functions@7.21.0:
+    resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-module-imports@7.21.4:
+    resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-module-transforms@7.21.2:
+    resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-module-imports': 7.21.4
+      '@babel/helper-simple-access': 7.20.2
+      '@babel/helper-split-export-declaration': 7.18.6
+      '@babel/helper-validator-identifier': 7.19.1
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helper-optimise-call-expression@7.18.6:
+    resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-plugin-utils@7.20.2:
+    resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==}
+    engines: {node: '>=6.9.0'}
+    dev: true
+
+  /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-wrap-function': 7.20.5
+      '@babel/types': 7.21.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helper-replace-supers@7.20.7:
+    resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-member-expression-to-functions': 7.21.0
+      '@babel/helper-optimise-call-expression': 7.18.6
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helper-simple-access@7.20.2:
+    resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-skip-transparent-expression-wrappers@7.20.0:
+    resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-split-export-declaration@7.18.6:
+    resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/helper-string-parser@7.19.4:
+    resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
+    engines: {node: '>=6.9.0'}
+
+  /@babel/helper-validator-identifier@7.19.1:
+    resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
+    engines: {node: '>=6.9.0'}
+
+  /@babel/helper-validator-option@7.21.0:
+    resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==}
+    engines: {node: '>=6.9.0'}
+    dev: true
+
+  /@babel/helper-wrap-function@7.20.5:
+    resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-function-name': 7.21.0
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/helpers@7.21.0:
+    resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/highlight@7.18.6:
+    resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-validator-identifier': 7.19.1
+      chalk: 2.4.2
+      js-tokens: 4.0.0
+    dev: true
+
+  /@babel/parser@7.21.4:
+    resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+    dependencies:
+      '@babel/types': 7.21.4
+
+  /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.13.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+      '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.12.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/compat-data': 7.21.4
+      '@babel/core': 7.21.4
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.4)
+    dev: true
+
+  /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.21.4):
+    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-jsx@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-module-imports': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-classes@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-function-name': 7.21.0
+      '@babel/helper-optimise-call-expression': 7.18.6
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-replace-supers': 7.20.7
+      '@babel/helper-split-export-declaration': 7.18.6
+      globals: 11.12.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/template': 7.20.7
+    dev: true
+
+  /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-function-name': 7.21.0
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-literals@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.21.4):
+    resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-module-transforms': 7.21.2
+      '@babel/helper-plugin-utils': 7.20.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-module-transforms': 7.21.2
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-simple-access': 7.20.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.21.4):
+    resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-hoist-variables': 7.18.6
+      '@babel/helper-module-transforms': 7.21.2
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-validator-identifier': 7.19.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-module-transforms': 7.21.2
+      '@babel/helper-plugin-utils': 7.20.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-replace-supers': 7.20.7
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-parameters@7.21.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      regenerator-transform: 0.15.1
+    dev: true
+
+  /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-spread@7.20.7(@babel/core@7.21.4):
+    resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-skip-transparent-expression-wrappers': 7.20.0
+    dev: true
+
+  /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.21.4):
+    resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-typescript@7.21.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-annotate-as-pure': 7.18.6
+      '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.21.4):
+    resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.21.4):
+    resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+    dev: true
+
+  /@babel/preset-env@7.21.4(@babel/core@7.21.4):
+    resolution: {integrity: sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/compat-data': 7.21.4
+      '@babel/core': 7.21.4
+      '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4)
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/helper-validator-option': 7.21.0
+      '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.4)
+      '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.21.4)
+      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.21.4)
+      '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.21.4)
+      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.4)
+      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.4)
+      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.4)
+      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.21.4)
+      '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.4)
+      '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-transform-destructuring': 7.21.3(@babel/core@7.21.4)
+      '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.21.4)
+      '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.21.4)
+      '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.21.4)
+      '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.21.4)
+      '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.21.4)
+      '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.21.4)
+      '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.21.4)
+      '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.21.4)
+      '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.21.4)
+      '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.21.4)
+      '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/preset-modules': 0.1.5(@babel/core@7.21.4)
+      '@babel/types': 7.21.4
+      babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.21.4)
+      babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.21.4)
+      babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.21.4)
+      core-js-compat: 3.30.0
+      semver: 6.3.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/preset-modules@0.1.5(@babel/core@7.21.4):
+    resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-plugin-utils': 7.20.2
+      '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.4)
+      '@babel/types': 7.21.4
+      esutils: 2.0.3
+    dev: true
+
+  /@babel/regjsgen@0.8.0:
+    resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==}
+    dev: true
+
+  /@babel/runtime@7.21.0:
+    resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      regenerator-runtime: 0.13.11
+
+  /@babel/template@7.20.7:
+    resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/code-frame': 7.21.4
+      '@babel/parser': 7.21.4
+      '@babel/types': 7.21.4
+    dev: true
+
+  /@babel/traverse@7.21.4:
+    resolution: {integrity: sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/code-frame': 7.21.4
+      '@babel/generator': 7.21.4
+      '@babel/helper-environment-visitor': 7.18.9
+      '@babel/helper-function-name': 7.21.0
+      '@babel/helper-hoist-variables': 7.18.6
+      '@babel/helper-split-export-declaration': 7.18.6
+      '@babel/parser': 7.21.4
+      '@babel/types': 7.21.4
+      debug: 4.3.4
+      globals: 11.12.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@babel/types@7.21.4:
+    resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-string-parser': 7.19.4
+      '@babel/helper-validator-identifier': 7.19.1
+      to-fast-properties: 2.0.0
+
+  /@esbuild/android-arm64@0.17.15:
+    resolution: {integrity: sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/android-arm@0.17.15:
+    resolution: {integrity: sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/android-x64@0.17.15:
+    resolution: {integrity: sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/darwin-arm64@0.17.15:
+    resolution: {integrity: sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/darwin-x64@0.17.15:
+    resolution: {integrity: sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/freebsd-arm64@0.17.15:
+    resolution: {integrity: sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/freebsd-x64@0.17.15:
+    resolution: {integrity: sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-arm64@0.17.15:
+    resolution: {integrity: sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-arm@0.17.15:
+    resolution: {integrity: sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-ia32@0.17.15:
+    resolution: {integrity: sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-loong64@0.17.15:
+    resolution: {integrity: sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-mips64el@0.17.15:
+    resolution: {integrity: sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-ppc64@0.17.15:
+    resolution: {integrity: sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-riscv64@0.17.15:
+    resolution: {integrity: sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-s390x@0.17.15:
+    resolution: {integrity: sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-x64@0.17.15:
+    resolution: {integrity: sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/netbsd-x64@0.17.15:
+    resolution: {integrity: sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/openbsd-x64@0.17.15:
+    resolution: {integrity: sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/sunos-x64@0.17.15:
+    resolution: {integrity: sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/win32-arm64@0.17.15:
+    resolution: {integrity: sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/win32-ia32@0.17.15:
+    resolution: {integrity: sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/win32-x64@0.17.15:
+    resolution: {integrity: sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@eslint-community/eslint-utils@4.4.0(eslint@8.38.0):
+    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+    dependencies:
+      eslint: 8.38.0
+      eslint-visitor-keys: 3.4.0
+    dev: true
+
+  /@eslint-community/regexpp@4.5.0:
+    resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+    dev: true
+
+  /@eslint/eslintrc@2.0.2:
+    resolution: {integrity: sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.3.4
+      espree: 9.5.1
+      globals: 13.20.0
+      ignore: 5.2.4
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@eslint/js@8.38.0:
+    resolution: {integrity: sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: true
+
+  /@humanwhocodes/config-array@0.11.8:
+    resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
+    engines: {node: '>=10.10.0'}
+    dependencies:
+      '@humanwhocodes/object-schema': 1.2.1
+      debug: 4.3.4
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@humanwhocodes/module-importer@1.0.1:
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+    dev: true
+
+  /@humanwhocodes/object-schema@1.2.1:
+    resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
+    dev: true
+
+  /@jridgewell/gen-mapping@0.3.3:
+    resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      '@jridgewell/set-array': 1.1.2
+      '@jridgewell/sourcemap-codec': 1.4.15
+      '@jridgewell/trace-mapping': 0.3.18
+
+  /@jridgewell/resolve-uri@3.1.0:
+    resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
+    engines: {node: '>=6.0.0'}
+
+  /@jridgewell/set-array@1.1.2:
+    resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
+    engines: {node: '>=6.0.0'}
+
+  /@jridgewell/source-map@0.3.3:
+    resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==}
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.3
+      '@jridgewell/trace-mapping': 0.3.18
+
+  /@jridgewell/sourcemap-codec@1.4.14:
+    resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
+
+  /@jridgewell/sourcemap-codec@1.4.15:
+    resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+
+  /@jridgewell/trace-mapping@0.3.18:
+    resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.0
+      '@jridgewell/sourcemap-codec': 1.4.14
+
+  /@nodelib/fs.scandir@2.1.5:
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+    dev: true
+
+  /@nodelib/fs.stat@2.0.5:
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+    dev: true
+
+  /@nodelib/fs.walk@1.2.8:
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.15.0
+    dev: true
+
+  /@rollup/pluginutils@4.2.1:
+    resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
+    engines: {node: '>= 8.0.0'}
+    dependencies:
+      estree-walker: 2.0.2
+      picomatch: 2.3.1
+    dev: true
+
+  /@rollup/pluginutils@5.0.2:
+    resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+    dependencies:
+      '@types/estree': 1.0.0
+      estree-walker: 2.0.2
+      picomatch: 2.3.1
+    dev: true
+
+  /@types/eslint@8.37.0:
+    resolution: {integrity: sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==}
+    dependencies:
+      '@types/estree': 1.0.0
+      '@types/json-schema': 7.0.11
+    dev: true
+
+  /@types/estree@1.0.0:
+    resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
+    dev: true
+
+  /@types/fined@1.1.3:
+    resolution: {integrity: sha512-CWYnSRnun3CGbt6taXeVo2lCbuaj4mchVJ4UF/BdU5TSuIn3AmS13pGMwCsBUoehGbhZrBrpNJZSZI5EVilXww==}
+    dev: true
+
+  /@types/inquirer@8.2.6:
+    resolution: {integrity: sha512-3uT88kxg8lNzY8ay2ZjP44DKcRaTGztqeIvN2zHvhzIBH/uAPaL75aBtdNRKbA7xXoMbBt5kX0M00VKAnfOYlA==}
+    dependencies:
+      '@types/through': 0.0.30
+      rxjs: 7.8.0
+    dev: true
+
+  /@types/json-schema@7.0.11:
+    resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
+    dev: true
+
+  /@types/liftoff@4.0.0:
+    resolution: {integrity: sha512-Ny/PJkO6nxWAQnaet8q/oWz15lrfwvdvBpuY4treB0CSsBO1CG0fVuNLngR3m3bepQLd+E4c3Y3DlC2okpUvPw==}
+    dependencies:
+      '@types/fined': 1.1.3
+      '@types/node': 16.18.23
+    dev: true
+
+  /@types/node@16.18.23:
+    resolution: {integrity: sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==}
+    dev: true
+
+  /@types/semver@7.3.13:
+    resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
+    dev: true
+
+  /@types/through@0.0.30:
+    resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==}
+    dependencies:
+      '@types/node': 16.18.23
+    dev: true
+
+  /@types/web-bluetooth@0.0.17:
+    resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==}
+    dev: false
+
+  /@typescript-eslint/eslint-plugin@5.57.1(@typescript-eslint/parser@5.57.1)(eslint@8.38.0)(typescript@5.0.4):
+    resolution: {integrity: sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^5.0.0
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@eslint-community/regexpp': 4.5.0
+      '@typescript-eslint/parser': 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+      '@typescript-eslint/scope-manager': 5.57.1
+      '@typescript-eslint/type-utils': 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+      '@typescript-eslint/utils': 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+      debug: 4.3.4
+      eslint: 8.38.0
+      grapheme-splitter: 1.0.4
+      ignore: 5.2.4
+      natural-compare-lite: 1.4.0
+      semver: 7.3.8
+      tsutils: 3.21.0(typescript@5.0.4)
+      typescript: 5.0.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/parser@5.57.1(eslint@8.38.0)(typescript@5.0.4):
+    resolution: {integrity: sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/scope-manager': 5.57.1
+      '@typescript-eslint/types': 5.57.1
+      '@typescript-eslint/typescript-estree': 5.57.1(typescript@5.0.4)
+      debug: 4.3.4
+      eslint: 8.38.0
+      typescript: 5.0.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/scope-manager@5.57.1:
+    resolution: {integrity: sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.57.1
+      '@typescript-eslint/visitor-keys': 5.57.1
+    dev: true
+
+  /@typescript-eslint/type-utils@5.57.1(eslint@8.38.0)(typescript@5.0.4):
+    resolution: {integrity: sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '*'
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/typescript-estree': 5.57.1(typescript@5.0.4)
+      '@typescript-eslint/utils': 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+      debug: 4.3.4
+      eslint: 8.38.0
+      tsutils: 3.21.0(typescript@5.0.4)
+      typescript: 5.0.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/types@5.57.1:
+    resolution: {integrity: sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: true
+
+  /@typescript-eslint/typescript-estree@5.57.1(typescript@5.0.4):
+    resolution: {integrity: sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/types': 5.57.1
+      '@typescript-eslint/visitor-keys': 5.57.1
+      debug: 4.3.4
+      globby: 11.1.0
+      is-glob: 4.0.3
+      semver: 7.3.8
+      tsutils: 3.21.0(typescript@5.0.4)
+      typescript: 5.0.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/utils@5.57.1(eslint@8.38.0)(typescript@5.0.4):
+    resolution: {integrity: sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0)
+      '@types/json-schema': 7.0.11
+      '@types/semver': 7.3.13
+      '@typescript-eslint/scope-manager': 5.57.1
+      '@typescript-eslint/types': 5.57.1
+      '@typescript-eslint/typescript-estree': 5.57.1(typescript@5.0.4)
+      eslint: 8.38.0
+      eslint-scope: 5.1.1
+      semver: 7.3.8
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+    dev: true
+
+  /@typescript-eslint/visitor-keys@5.57.1:
+    resolution: {integrity: sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.57.1
+      eslint-visitor-keys: 3.4.0
+    dev: true
+
+  /@vant/popperjs@1.3.0:
+    resolution: {integrity: sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==}
+    dev: false
+
+  /@vant/use@1.5.1(vue@3.2.47):
+    resolution: {integrity: sha512-Zxd7lDz/LliVYEQi3PR9a8CQa/kGCVzF0u9hqDMaTlgXlbG0wHMFPllrcG0ThR6bfs8xrYVuSFM9pJn6HSoUGQ==}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      vue: 3.2.47
+    dev: false
+
+  /@vitejs/plugin-legacy@4.0.3(terser@5.17.6)(vite@4.2.1):
+    resolution: {integrity: sha512-RqDQOSEmFSNL42vITkNp8HE8Ak1yjGgaav4B6BGcZ8/URK0wikzwSyhNRirHDkp+snflEEk7iPZXTXUYA9exbg==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      terser: ^5.4.0
+      vite: ^4.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/preset-env': 7.21.4(@babel/core@7.21.4)
+      browserslist: 4.21.5
+      core-js: 3.30.2
+      magic-string: 0.30.0
+      regenerator-runtime: 0.13.11
+      systemjs: 6.14.1
+      terser: 5.17.6
+      vite: 4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@vitejs/plugin-vue-jsx@3.0.1(vite@4.2.1)(vue@3.2.47):
+    resolution: {integrity: sha512-+Jb7ggL48FSPS1uhPnJbJwWa9Sr90vQ+d0InW+AhBM22n+cfuYqJZDckBc+W3QSHe1WDvewMZfa4wZOtk5pRgw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^4.0.0
+      vue: ^3.0.0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.21.4)
+      '@vue/babel-plugin-jsx': 1.1.1(@babel/core@7.21.4)
+      vite: 4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6)
+      vue: 3.2.47
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@vitejs/plugin-vue@4.1.0(vite@4.2.1)(vue@3.2.47):
+    resolution: {integrity: sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^4.0.0
+      vue: ^3.2.25
+    dependencies:
+      vite: 4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6)
+      vue: 3.2.47
+    dev: true
+
+  /@volar/language-core@1.3.0-alpha.0:
+    resolution: {integrity: sha512-W3uMzecHPcbwddPu4SJpUcPakRBK/y/BP+U0U6NiPpUX1tONLC4yCawt+QBJqtgJ+sfD6ztf5PyvPL3hQRqfOA==}
+    dependencies:
+      '@volar/source-map': 1.3.0-alpha.0
+    dev: true
+
+  /@volar/source-map@1.3.0-alpha.0:
+    resolution: {integrity: sha512-jSdizxWFvDTvkPYZnO6ew3sBZUnS0abKCbuopkc0JrIlFbznWC/fPH3iPFIMS8/IIkRxq1Jh9VVG60SmtsdaMQ==}
+    dependencies:
+      muggle-string: 0.2.2
+    dev: true
+
+  /@volar/typescript@1.3.0-alpha.0:
+    resolution: {integrity: sha512-5UItyW2cdH2mBLu4RrECRNJRgtvvzKrSCn2y3v/D61QwIDkGx4aeil6x8RFuUL5TFtV6QvVHXnsOHxNgd+sCow==}
+    dependencies:
+      '@volar/language-core': 1.3.0-alpha.0
+    dev: true
+
+  /@volar/vue-language-core@1.2.0:
+    resolution: {integrity: sha512-w7yEiaITh2WzKe6u8ZdeLKCUz43wdmY/OqAmsB/PGDvvhTcVhCJ6f0W/RprZL1IhqH8wALoWiwEh/Wer7ZviMQ==}
+    dependencies:
+      '@volar/language-core': 1.3.0-alpha.0
+      '@volar/source-map': 1.3.0-alpha.0
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-sfc': 3.2.47
+      '@vue/reactivity': 3.2.47
+      '@vue/shared': 3.2.47
+      minimatch: 6.2.0
+      muggle-string: 0.2.2
+      vue-template-compiler: 2.7.14
+    dev: true
+
+  /@volar/vue-typescript@1.2.0:
+    resolution: {integrity: sha512-zjmRi9y3J1EkG+pfuHp8IbHmibihrKK485cfzsHjiuvJMGrpkWvlO5WVEk8oslMxxeGC5XwBFE9AOlvh378EPA==}
+    dependencies:
+      '@volar/typescript': 1.3.0-alpha.0
+      '@volar/vue-language-core': 1.2.0
+    dev: true
+
+  /@vue/babel-helper-vue-transform-on@1.0.2:
+    resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==}
+    dev: true
+
+  /@vue/babel-plugin-jsx@1.1.1(@babel/core@7.21.4):
+    resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
+    dependencies:
+      '@babel/helper-module-imports': 7.21.4
+      '@babel/plugin-syntax-jsx': 7.21.4(@babel/core@7.21.4)
+      '@babel/template': 7.20.7
+      '@babel/traverse': 7.21.4
+      '@babel/types': 7.21.4
+      '@vue/babel-helper-vue-transform-on': 1.0.2
+      camelcase: 6.3.0
+      html-tags: 3.3.1
+      svg-tags: 1.0.0
+    transitivePeerDependencies:
+      - '@babel/core'
+      - supports-color
+    dev: true
+
+  /@vue/compiler-core@3.2.47:
+    resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==}
+    dependencies:
+      '@babel/parser': 7.21.4
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      source-map: 0.6.1
+
+  /@vue/compiler-dom@3.2.47:
+    resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==}
+    dependencies:
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+
+  /@vue/compiler-sfc@3.2.47:
+    resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==}
+    dependencies:
+      '@babel/parser': 7.21.4
+      '@vue/compiler-core': 3.2.47
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/reactivity-transform': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+      postcss: 8.4.21
+      source-map: 0.6.1
+
+  /@vue/compiler-ssr@3.2.47:
+    resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==}
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/shared': 3.2.47
+
+  /@vue/devtools-api@6.5.0:
+    resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==}
+    dev: false
+
+  /@vue/eslint-config-prettier@7.1.0(eslint@8.38.0)(prettier@2.8.7):
+    resolution: {integrity: sha512-Pv/lVr0bAzSIHLd9iz0KnvAr4GKyCEl+h52bc4e5yWuDVtLgFwycF7nrbWTAQAS+FU6q1geVd07lc6EWfJiWKQ==}
+    peerDependencies:
+      eslint: '>= 7.28.0'
+      prettier: '>= 2.0.0'
+    dependencies:
+      eslint: 8.38.0
+      eslint-config-prettier: 8.8.0(eslint@8.38.0)
+      eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.38.0)(prettier@2.8.7)
+      prettier: 2.8.7
+    dev: true
+
+  /@vue/eslint-config-typescript@11.0.2(eslint-plugin-vue@9.10.0)(eslint@8.38.0)(typescript@5.0.4):
+    resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+      eslint-plugin-vue: ^9.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/eslint-plugin': 5.57.1(@typescript-eslint/parser@5.57.1)(eslint@8.38.0)(typescript@5.0.4)
+      '@typescript-eslint/parser': 5.57.1(eslint@8.38.0)(typescript@5.0.4)
+      eslint: 8.38.0
+      eslint-plugin-vue: 9.10.0(eslint@8.38.0)
+      typescript: 5.0.4
+      vue-eslint-parser: 9.1.1(eslint@8.38.0)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@vue/reactivity-transform@3.2.47:
+    resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==}
+    dependencies:
+      '@babel/parser': 7.21.4
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+
+  /@vue/reactivity@3.2.47:
+    resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==}
+    dependencies:
+      '@vue/shared': 3.2.47
+
+  /@vue/runtime-core@3.2.47:
+    resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==}
+    dependencies:
+      '@vue/reactivity': 3.2.47
+      '@vue/shared': 3.2.47
+
+  /@vue/runtime-dom@3.2.47:
+    resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==}
+    dependencies:
+      '@vue/runtime-core': 3.2.47
+      '@vue/shared': 3.2.47
+      csstype: 2.6.21
+
+  /@vue/server-renderer@3.2.47(vue@3.2.47):
+    resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==}
+    peerDependencies:
+      vue: 3.2.47
+    dependencies:
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/shared': 3.2.47
+      vue: 3.2.47
+
+  /@vue/shared@3.2.47:
+    resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==}
+
+  /@vueuse/core@10.1.2(vue@3.2.47):
+    resolution: {integrity: sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==}
+    dependencies:
+      '@types/web-bluetooth': 0.0.17
+      '@vueuse/metadata': 10.1.2
+      '@vueuse/shared': 10.1.2(vue@3.2.47)
+      vue-demi: 0.14.5(vue@3.2.47)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
+  /@vueuse/metadata@10.1.2:
+    resolution: {integrity: sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==}
+    dev: false
+
+  /@vueuse/shared@10.1.2(vue@3.2.47):
+    resolution: {integrity: sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==}
+    dependencies:
+      vue-demi: 0.14.5(vue@3.2.47)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
+  /acorn-jsx@5.3.2(acorn@8.8.2):
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      acorn: 8.8.2
+    dev: true
+
+  /acorn@8.8.2:
+    resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  /aggregate-error@3.1.0:
+    resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+    engines: {node: '>=8'}
+    dependencies:
+      clean-stack: 2.2.0
+      indent-string: 4.0.0
+    dev: true
+
+  /ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+    dev: true
+
+  /ansi-escapes@4.3.2:
+    resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      type-fest: 0.21.3
+    dev: true
+
+  /ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+
+  /ansi-regex@6.0.1:
+    resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /ansi-styles@3.2.1:
+    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+    engines: {node: '>=4'}
+    dependencies:
+      color-convert: 1.9.3
+    dev: true
+
+  /ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+    dependencies:
+      color-convert: 2.0.1
+
+  /ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /anymatch@3.1.3:
+    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+    engines: {node: '>= 8'}
+    dependencies:
+      normalize-path: 3.0.0
+      picomatch: 2.3.1
+    dev: true
+
+  /argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+    dev: true
+
+  /array-each@1.0.1:
+    resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /array-slice@1.1.0:
+    resolution: {integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /astral-regex@2.0.0:
+    resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /autoprefixer@10.4.14(postcss@8.4.21):
+    resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
+    engines: {node: ^10 || ^12 || >=14}
+    hasBin: true
+    peerDependencies:
+      postcss: ^8.1.0
+    dependencies:
+      browserslist: 4.21.5
+      caniuse-lite: 1.0.30001476
+      fraction.js: 4.2.0
+      normalize-range: 0.1.2
+      picocolors: 1.0.0
+      postcss: 8.4.21
+      postcss-value-parser: 4.2.0
+    dev: true
+
+  /babel-plugin-dynamic-import-node@2.3.3:
+    resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==}
+    dependencies:
+      object.assign: 4.1.4
+    dev: true
+
+  /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.21.4):
+    resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/compat-data': 7.21.4
+      '@babel/core': 7.21.4
+      '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.4)
+      semver: 6.3.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.21.4):
+    resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.4)
+      core-js-compat: 3.30.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.21.4):
+    resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    dependencies:
+      '@babel/core': 7.21.4
+      '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.4)
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+    dev: true
+
+  /base64-arraybuffer@1.0.2:
+    resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+    engines: {node: '>= 0.6.0'}
+    dev: false
+
+  /base64-js@1.5.1:
+    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+    dev: true
+
+  /binary-extensions@2.2.0:
+    resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /bl@4.1.0:
+    resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+    dependencies:
+      buffer: 5.7.1
+      inherits: 2.0.4
+      readable-stream: 3.6.2
+    dev: true
+
+  /bl@5.1.0:
+    resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==}
+    dependencies:
+      buffer: 6.0.3
+      inherits: 2.0.4
+      readable-stream: 3.6.2
+    dev: true
+
+  /boolbase@1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+    dev: true
+
+  /brace-expansion@1.1.11:
+    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+    dependencies:
+      balanced-match: 1.0.2
+      concat-map: 0.0.1
+    dev: true
+
+  /brace-expansion@2.0.1:
+    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+    dependencies:
+      balanced-match: 1.0.2
+    dev: true
+
+  /braces@3.0.2:
+    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+    engines: {node: '>=8'}
+    dependencies:
+      fill-range: 7.0.1
+    dev: true
+
+  /browserslist@4.21.5:
+    resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+    dependencies:
+      caniuse-lite: 1.0.30001476
+      electron-to-chromium: 1.4.356
+      node-releases: 2.0.10
+      update-browserslist-db: 1.0.10(browserslist@4.21.5)
+    dev: true
+
+  /buffer-from@1.1.2:
+    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
+  /buffer@5.7.1:
+    resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+    dev: true
+
+  /buffer@6.0.3:
+    resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+    dev: true
+
+  /call-bind@1.0.2:
+    resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+    dependencies:
+      function-bind: 1.1.1
+      get-intrinsic: 1.2.0
+
+  /callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /camel-case@4.1.2:
+    resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
+    dependencies:
+      pascal-case: 3.1.2
+      tslib: 2.5.0
+    dev: true
+
+  /camelcase@5.3.1:
+    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+    engines: {node: '>=6'}
+    dev: false
+
+  /camelcase@6.3.0:
+    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /caniuse-lite@1.0.30001476:
+    resolution: {integrity: sha512-JmpktFppVSvyUN4gsLS0bShY2L9ZUslHLE72vgemBkS43JD2fOvKTKs+GtRwuxrtRGnwJFW0ye7kWRRlLJS9vQ==}
+    dev: true
+
+  /capital-case@1.0.4:
+    resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
+    dependencies:
+      no-case: 3.0.4
+      tslib: 2.5.0
+      upper-case-first: 2.0.2
+    dev: true
+
+  /chalk@2.4.2:
+    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+    engines: {node: '>=4'}
+    dependencies:
+      ansi-styles: 3.2.1
+      escape-string-regexp: 1.0.5
+      supports-color: 5.5.0
+    dev: true
+
+  /chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+    dev: true
+
+  /chalk@5.2.0:
+    resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
+    engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+    dev: true
+
+  /change-case@4.1.2:
+    resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==}
+    dependencies:
+      camel-case: 4.1.2
+      capital-case: 1.0.4
+      constant-case: 3.0.4
+      dot-case: 3.0.4
+      header-case: 2.0.4
+      no-case: 3.0.4
+      param-case: 3.0.4
+      pascal-case: 3.1.2
+      path-case: 3.0.4
+      sentence-case: 3.0.4
+      snake-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /chardet@0.7.0:
+    resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
+    dev: true
+
+  /chokidar@3.5.3:
+    resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+    engines: {node: '>= 8.10.0'}
+    dependencies:
+      anymatch: 3.1.3
+      braces: 3.0.2
+      glob-parent: 5.1.2
+      is-binary-path: 2.1.0
+      is-glob: 4.0.3
+      normalize-path: 3.0.0
+      readdirp: 3.6.0
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /ci-info@1.6.0:
+    resolution: {integrity: sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==}
+    dev: true
+
+  /clean-deep@3.4.0:
+    resolution: {integrity: sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==}
+    engines: {node: '>=4'}
+    dependencies:
+      lodash.isempty: 4.4.0
+      lodash.isplainobject: 4.0.6
+      lodash.transform: 4.6.0
+    dev: false
+
+  /clean-stack@2.2.0:
+    resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /cli-cursor@3.1.0:
+    resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+    engines: {node: '>=8'}
+    dependencies:
+      restore-cursor: 3.1.0
+    dev: true
+
+  /cli-cursor@4.0.0:
+    resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      restore-cursor: 4.0.0
+    dev: true
+
+  /cli-spinners@2.8.0:
+    resolution: {integrity: sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /cli-truncate@2.1.0:
+    resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
+    engines: {node: '>=8'}
+    dependencies:
+      slice-ansi: 3.0.0
+      string-width: 4.2.3
+    dev: true
+
+  /cli-truncate@3.1.0:
+    resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      slice-ansi: 5.0.0
+      string-width: 5.1.2
+    dev: true
+
+  /cli-width@3.0.0:
+    resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
+    engines: {node: '>= 10'}
+    dev: true
+
+  /cliui@6.0.0:
+    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+    dependencies:
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      wrap-ansi: 6.2.0
+    dev: false
+
+  /clone@1.0.4:
+    resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
+    engines: {node: '>=0.8'}
+    dev: true
+
+  /color-convert@1.9.3:
+    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+    dependencies:
+      color-name: 1.1.3
+    dev: true
+
+  /color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+    dependencies:
+      color-name: 1.1.4
+
+  /color-name@1.1.3:
+    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+    dev: true
+
+  /color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+  /colorette@2.0.19:
+    resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
+    dev: true
+
+  /commander@10.0.0:
+    resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==}
+    engines: {node: '>=14'}
+    dev: true
+
+  /commander@2.20.3:
+    resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+
+  /concat-map@0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+    dev: true
+
+  /constant-case@3.0.4:
+    resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
+    dependencies:
+      no-case: 3.0.4
+      tslib: 2.5.0
+      upper-case: 2.0.2
+    dev: true
+
+  /convert-source-map@1.9.0:
+    resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+    dev: true
+
+  /copy-anything@2.0.6:
+    resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
+    dependencies:
+      is-what: 3.14.1
+    dev: true
+
+  /copy-text-to-clipboard@3.1.0:
+    resolution: {integrity: sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==}
+    engines: {node: '>=12'}
+    dev: false
+
+  /core-js-compat@3.30.0:
+    resolution: {integrity: sha512-P5A2h/9mRYZFIAP+5Ab8ns6083IyVpSclU74UNvbGVQ8VM7n3n3/g2yF3AkKQ9NXz2O+ioxLbEWKnDtgsFamhg==}
+    dependencies:
+      browserslist: 4.21.5
+    dev: true
+
+  /core-js@3.30.2:
+    resolution: {integrity: sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==}
+    requiresBuild: true
+
+  /cross-spawn@5.1.0:
+    resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+    dependencies:
+      lru-cache: 4.1.5
+      shebang-command: 1.2.0
+      which: 1.3.1
+    dev: true
+
+  /cross-spawn@7.0.3:
+    resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+    engines: {node: '>= 8'}
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+    dev: true
+
+  /css-line-break@2.1.0:
+    resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+    dependencies:
+      utrie: 1.0.2
+    dev: false
+
+  /cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+    dev: true
+
+  /csstype@2.6.21:
+    resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
+
+  /custom-event-polyfill@1.0.7:
+    resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
+    dev: false
+
+  /dayjs@1.11.7:
+    resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
+    dev: false
+
+  /de-indent@1.0.2:
+    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+    dev: true
+
+  /debug@3.2.7:
+    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.1.2
+    dev: true
+    optional: true
+
+  /debug@4.3.4:
+    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.1.2
+    dev: true
+
+  /decamelize@1.2.0:
+    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
+  /decode-uri-component@0.4.1:
+    resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==}
+    engines: {node: '>=14.16'}
+    dev: false
+
+  /deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+    dev: true
+
+  /defaults@1.0.4:
+    resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
+    dependencies:
+      clone: 1.0.4
+    dev: true
+
+  /define-properties@1.2.0:
+    resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-property-descriptors: 1.0.0
+      object-keys: 1.1.1
+    dev: true
+
+  /del@6.1.1:
+    resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==}
+    engines: {node: '>=10'}
+    dependencies:
+      globby: 11.1.0
+      graceful-fs: 4.2.11
+      is-glob: 4.0.3
+      is-path-cwd: 2.2.0
+      is-path-inside: 3.0.3
+      p-map: 4.0.0
+      rimraf: 3.0.2
+      slash: 3.0.0
+    dev: true
+
+  /detect-file@1.0.0:
+    resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /dijkstrajs@1.0.3:
+    resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
+    dev: false
+
+  /dir-glob@3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+    dependencies:
+      path-type: 4.0.0
+    dev: true
+
+  /doctrine@3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      esutils: 2.0.3
+    dev: true
+
+  /dot-case@3.0.4:
+    resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+    dependencies:
+      no-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /eastasianwidth@0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+    dev: true
+
+  /echarts@5.4.2:
+    resolution: {integrity: sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==}
+    dependencies:
+      tslib: 2.3.0
+      zrender: 5.4.3
+    dev: false
+
+  /electron-to-chromium@1.4.356:
+    resolution: {integrity: sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==}
+    dev: true
+
+  /emoji-regex@8.0.0:
+    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+  /emoji-regex@9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+    dev: true
+
+  /encode-utf8@1.0.3:
+    resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
+    dev: false
+
+  /encoding@0.1.13:
+    resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
+    dependencies:
+      iconv-lite: 0.6.3
+    dev: false
+
+  /errno@0.1.8:
+    resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
+    hasBin: true
+    requiresBuild: true
+    dependencies:
+      prr: 1.0.1
+    dev: true
+    optional: true
+
+  /esbuild@0.17.15:
+    resolution: {integrity: sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    optionalDependencies:
+      '@esbuild/android-arm': 0.17.15
+      '@esbuild/android-arm64': 0.17.15
+      '@esbuild/android-x64': 0.17.15
+      '@esbuild/darwin-arm64': 0.17.15
+      '@esbuild/darwin-x64': 0.17.15
+      '@esbuild/freebsd-arm64': 0.17.15
+      '@esbuild/freebsd-x64': 0.17.15
+      '@esbuild/linux-arm': 0.17.15
+      '@esbuild/linux-arm64': 0.17.15
+      '@esbuild/linux-ia32': 0.17.15
+      '@esbuild/linux-loong64': 0.17.15
+      '@esbuild/linux-mips64el': 0.17.15
+      '@esbuild/linux-ppc64': 0.17.15
+      '@esbuild/linux-riscv64': 0.17.15
+      '@esbuild/linux-s390x': 0.17.15
+      '@esbuild/linux-x64': 0.17.15
+      '@esbuild/netbsd-x64': 0.17.15
+      '@esbuild/openbsd-x64': 0.17.15
+      '@esbuild/sunos-x64': 0.17.15
+      '@esbuild/win32-arm64': 0.17.15
+      '@esbuild/win32-ia32': 0.17.15
+      '@esbuild/win32-x64': 0.17.15
+    dev: true
+
+  /escalade@3.1.1:
+    resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /escape-string-regexp@1.0.5:
+    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+    engines: {node: '>=0.8.0'}
+    dev: true
+
+  /escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /eslint-config-prettier@8.8.0(eslint@8.38.0):
+    resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
+    hasBin: true
+    peerDependencies:
+      eslint: '>=7.0.0'
+    dependencies:
+      eslint: 8.38.0
+    dev: true
+
+  /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.38.0)(prettier@2.8.7):
+    resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
+    engines: {node: '>=12.0.0'}
+    peerDependencies:
+      eslint: '>=7.28.0'
+      eslint-config-prettier: '*'
+      prettier: '>=2.0.0'
+    peerDependenciesMeta:
+      eslint-config-prettier:
+        optional: true
+    dependencies:
+      eslint: 8.38.0
+      eslint-config-prettier: 8.8.0(eslint@8.38.0)
+      prettier: 2.8.7
+      prettier-linter-helpers: 1.0.0
+    dev: true
+
+  /eslint-plugin-vue@9.10.0(eslint@8.38.0):
+    resolution: {integrity: sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0)
+      eslint: 8.38.0
+      natural-compare: 1.4.0
+      nth-check: 2.1.1
+      postcss-selector-parser: 6.0.11
+      semver: 7.3.8
+      vue-eslint-parser: 9.1.1(eslint@8.38.0)
+      xml-name-validator: 4.0.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-scope@5.1.1:
+    resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
+    engines: {node: '>=8.0.0'}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 4.3.0
+    dev: true
+
+  /eslint-scope@7.1.1:
+    resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+    dev: true
+
+  /eslint-visitor-keys@3.4.0:
+    resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: true
+
+  /eslint@8.38.0:
+    resolution: {integrity: sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0)
+      '@eslint-community/regexpp': 4.5.0
+      '@eslint/eslintrc': 2.0.2
+      '@eslint/js': 8.38.0
+      '@humanwhocodes/config-array': 0.11.8
+      '@humanwhocodes/module-importer': 1.0.1
+      '@nodelib/fs.walk': 1.2.8
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.3
+      debug: 4.3.4
+      doctrine: 3.0.0
+      escape-string-regexp: 4.0.0
+      eslint-scope: 7.1.1
+      eslint-visitor-keys: 3.4.0
+      espree: 9.5.1
+      esquery: 1.5.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.20.0
+      grapheme-splitter: 1.0.4
+      ignore: 5.2.4
+      import-fresh: 3.3.0
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      is-path-inside: 3.0.3
+      js-sdsl: 4.4.0
+      js-yaml: 4.1.0
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.1
+      strip-ansi: 6.0.1
+      strip-json-comments: 3.1.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /espree@9.5.1:
+    resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      acorn: 8.8.2
+      acorn-jsx: 5.3.2(acorn@8.8.2)
+      eslint-visitor-keys: 3.4.0
+    dev: true
+
+  /esquery@1.5.0:
+    resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+    engines: {node: '>=0.10'}
+    dependencies:
+      estraverse: 5.3.0
+    dev: true
+
+  /esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+    dependencies:
+      estraverse: 5.3.0
+    dev: true
+
+  /estraverse@4.3.0:
+    resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+    engines: {node: '>=4.0'}
+    dev: true
+
+  /estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+    dev: true
+
+  /estree-walker@2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  /esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /execa@0.8.0:
+    resolution: {integrity: sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==}
+    engines: {node: '>=4'}
+    dependencies:
+      cross-spawn: 5.1.0
+      get-stream: 3.0.0
+      is-stream: 1.1.0
+      npm-run-path: 2.0.2
+      p-finally: 1.0.0
+      signal-exit: 3.0.7
+      strip-eof: 1.0.0
+    dev: true
+
+  /execa@7.1.1:
+    resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==}
+    engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
+    dependencies:
+      cross-spawn: 7.0.3
+      get-stream: 6.0.1
+      human-signals: 4.3.1
+      is-stream: 3.0.0
+      merge-stream: 2.0.0
+      npm-run-path: 5.1.0
+      onetime: 6.0.0
+      signal-exit: 3.0.7
+      strip-final-newline: 3.0.0
+    dev: true
+
+  /expand-tilde@2.0.2:
+    resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      homedir-polyfill: 1.0.3
+    dev: true
+
+  /extend@3.0.2:
+    resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+    dev: true
+
+  /external-editor@3.1.0:
+    resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
+    engines: {node: '>=4'}
+    dependencies:
+      chardet: 0.7.0
+      iconv-lite: 0.4.24
+      tmp: 0.0.33
+    dev: true
+
+  /fast-deep-equal@3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+    dev: true
+
+  /fast-diff@1.2.0:
+    resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
+    dev: true
+
+  /fast-glob@3.2.12:
+    resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
+    engines: {node: '>=8.6.0'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.5
+    dev: true
+
+  /fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+    dev: true
+
+  /fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+    dev: true
+
+  /fastq@1.15.0:
+    resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+    dependencies:
+      reusify: 1.0.4
+    dev: true
+
+  /figures@3.2.0:
+    resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
+    engines: {node: '>=8'}
+    dependencies:
+      escape-string-regexp: 1.0.5
+    dev: true
+
+  /file-entry-cache@6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flat-cache: 3.0.4
+    dev: true
+
+  /fill-range@7.0.1:
+    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      to-regex-range: 5.0.1
+    dev: true
+
+  /filter-obj@5.1.0:
+    resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==}
+    engines: {node: '>=14.16'}
+    dev: false
+
+  /find-up@4.1.0:
+    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+    engines: {node: '>=8'}
+    dependencies:
+      locate-path: 5.0.0
+      path-exists: 4.0.0
+    dev: false
+
+  /find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+    dev: true
+
+  /findup-sync@5.0.0:
+    resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==}
+    engines: {node: '>= 10.13.0'}
+    dependencies:
+      detect-file: 1.0.0
+      is-glob: 4.0.3
+      micromatch: 4.0.5
+      resolve-dir: 1.0.1
+    dev: true
+
+  /fined@2.0.0:
+    resolution: {integrity: sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==}
+    engines: {node: '>= 10.13.0'}
+    dependencies:
+      expand-tilde: 2.0.2
+      is-plain-object: 5.0.0
+      object.defaults: 1.1.0
+      object.pick: 1.3.0
+      parse-filepath: 1.0.2
+    dev: true
+
+  /flagged-respawn@2.0.0:
+    resolution: {integrity: sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==}
+    engines: {node: '>= 10.13.0'}
+    dev: true
+
+  /flat-cache@3.0.4:
+    resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flatted: 3.2.7
+      rimraf: 3.0.2
+    dev: true
+
+  /flatted@3.2.7:
+    resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+    dev: true
+
+  /for-in@1.0.2:
+    resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /for-own@1.0.0:
+    resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      for-in: 1.0.2
+    dev: true
+
+  /fraction.js@4.2.0:
+    resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
+    dev: true
+
+  /fs.realpath@1.0.0:
+    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+    dev: true
+
+  /fsevents@2.3.2:
+    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /function-bind@1.1.1:
+    resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+
+  /gensync@1.0.0-beta.2:
+    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+    engines: {node: '>=6.9.0'}
+    dev: true
+
+  /get-caller-file@2.0.5:
+    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+    engines: {node: 6.* || 8.* || >= 10.*}
+    dev: false
+
+  /get-intrinsic@1.2.0:
+    resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
+    dependencies:
+      function-bind: 1.1.1
+      has: 1.0.3
+      has-symbols: 1.0.3
+
+  /get-stream@3.0.0:
+    resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /get-stream@6.0.1:
+    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /glob-parent@5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+    dependencies:
+      is-glob: 4.0.3
+    dev: true
+
+  /glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      is-glob: 4.0.3
+    dev: true
+
+  /glob@7.2.3:
+    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    dependencies:
+      fs.realpath: 1.0.0
+      inflight: 1.0.6
+      inherits: 2.0.4
+      minimatch: 3.1.2
+      once: 1.4.0
+      path-is-absolute: 1.0.1
+    dev: true
+
+  /global-modules@1.0.0:
+    resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      global-prefix: 1.0.2
+      is-windows: 1.0.2
+      resolve-dir: 1.0.1
+    dev: true
+
+  /global-prefix@1.0.2:
+    resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      expand-tilde: 2.0.2
+      homedir-polyfill: 1.0.3
+      ini: 1.3.8
+      is-windows: 1.0.2
+      which: 1.3.1
+    dev: true
+
+  /globals@11.12.0:
+    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /globals@13.20.0:
+    resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      type-fest: 0.20.2
+    dev: true
+
+  /globby@11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+    dependencies:
+      array-union: 2.1.0
+      dir-glob: 3.0.1
+      fast-glob: 3.2.12
+      ignore: 5.2.4
+      merge2: 1.4.1
+      slash: 3.0.0
+    dev: true
+
+  /globby@13.1.3:
+    resolution: {integrity: sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      dir-glob: 3.0.1
+      fast-glob: 3.2.12
+      ignore: 5.2.4
+      merge2: 1.4.1
+      slash: 4.0.0
+    dev: true
+
+  /graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+    dev: true
+
+  /grapheme-splitter@1.0.4:
+    resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+    dev: true
+
+  /handlebars@4.7.7:
+    resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==}
+    engines: {node: '>=0.4.7'}
+    hasBin: true
+    dependencies:
+      minimist: 1.2.8
+      neo-async: 2.6.2
+      source-map: 0.6.1
+      wordwrap: 1.0.0
+    optionalDependencies:
+      uglify-js: 3.17.4
+    dev: true
+
+  /has-flag@3.0.0:
+    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /has-property-descriptors@1.0.0:
+    resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+    dependencies:
+      get-intrinsic: 1.2.0
+    dev: true
+
+  /has-symbols@1.0.3:
+    resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+    engines: {node: '>= 0.4'}
+
+  /has@1.0.3:
+    resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+    engines: {node: '>= 0.4.0'}
+    dependencies:
+      function-bind: 1.1.1
+
+  /he@1.2.0:
+    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+    hasBin: true
+    dev: true
+
+  /header-case@2.0.4:
+    resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
+    dependencies:
+      capital-case: 1.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /homedir-polyfill@1.0.3:
+    resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      parse-passwd: 1.0.0
+    dev: true
+
+  /html-tags@3.3.1:
+    resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /html2canvas@1.4.1:
+    resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+    engines: {node: '>=8.0.0'}
+    dependencies:
+      css-line-break: 2.1.0
+      text-segmentation: 1.0.3
+    dev: false
+
+  /human-signals@4.3.1:
+    resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
+    engines: {node: '>=14.18.0'}
+    dev: true
+
+  /husky@8.0.0:
+    resolution: {integrity: sha512-4qbE/5dzNDNxFEkX9MNRPKl5+omTXQzdILCUWiqG/lWIAioiM5vln265/l6I2Zx8gpW8l1ukZwGQeCFbBZ6+6w==}
+    engines: {node: '>=14'}
+    hasBin: true
+    dev: true
+
+  /iconv-lite@0.4.24:
+    resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      safer-buffer: 2.1.2
+    dev: true
+
+  /iconv-lite@0.6.3:
+    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      safer-buffer: 2.1.2
+
+  /ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+    dev: true
+
+  /ignore@5.2.4:
+    resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
+    engines: {node: '>= 4'}
+    dev: true
+
+  /image-size@0.5.5:
+    resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /import-fresh@3.3.0:
+    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+    engines: {node: '>=6'}
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
+    dev: true
+
+  /imurmurhash@0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+    dev: true
+
+  /indent-string@4.0.0:
+    resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /inflight@1.0.6:
+    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+    dependencies:
+      once: 1.4.0
+      wrappy: 1.0.2
+    dev: true
+
+  /inherits@2.0.4:
+    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+    dev: true
+
+  /ini@1.3.8:
+    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+    dev: true
+
+  /inquirer@8.2.5:
+    resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==}
+    engines: {node: '>=12.0.0'}
+    dependencies:
+      ansi-escapes: 4.3.2
+      chalk: 4.1.2
+      cli-cursor: 3.1.0
+      cli-width: 3.0.0
+      external-editor: 3.1.0
+      figures: 3.2.0
+      lodash: 4.17.21
+      mute-stream: 0.0.8
+      ora: 5.4.1
+      run-async: 2.4.1
+      rxjs: 7.8.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      through: 2.3.8
+      wrap-ansi: 7.0.0
+    dev: true
+
+  /interpret@2.2.0:
+    resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==}
+    engines: {node: '>= 0.10'}
+    dev: true
+
+  /is-absolute@1.0.0:
+    resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      is-relative: 1.0.0
+      is-windows: 1.0.2
+    dev: true
+
+  /is-binary-path@2.1.0:
+    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+    engines: {node: '>=8'}
+    dependencies:
+      binary-extensions: 2.2.0
+    dev: true
+
+  /is-ci@1.2.1:
+    resolution: {integrity: sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==}
+    hasBin: true
+    dependencies:
+      ci-info: 1.6.0
+    dev: true
+
+  /is-core-module@2.11.0:
+    resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
+    dependencies:
+      has: 1.0.3
+    dev: true
+
+  /is-extglob@2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /is-fullwidth-code-point@3.0.0:
+    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+    engines: {node: '>=8'}
+
+  /is-fullwidth-code-point@4.0.0:
+    resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /is-glob@4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      is-extglob: 2.1.1
+    dev: true
+
+  /is-interactive@1.0.0:
+    resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /is-interactive@2.0.0:
+    resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /is-number@7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+    dev: true
+
+  /is-path-cwd@2.2.0:
+    resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /is-path-inside@3.0.3:
+    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /is-plain-object@5.0.0:
+    resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /is-relative@1.0.0:
+    resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      is-unc-path: 1.0.0
+    dev: true
+
+  /is-stream@1.1.0:
+    resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
+    engines: {node: '>=0.10.0'}
+
+  /is-stream@3.0.0:
+    resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
+  /is-unc-path@1.0.0:
+    resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      unc-path-regex: 0.1.2
+    dev: true
+
+  /is-unicode-supported@0.1.0:
+    resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /is-unicode-supported@1.3.0:
+    resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /is-what@3.14.1:
+    resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
+    dev: true
+
+  /is-windows@1.0.2:
+    resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /isbinaryfile@4.0.10:
+    resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==}
+    engines: {node: '>= 8.0.0'}
+    dev: true
+
+  /isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+    dev: true
+
+  /isobject@3.0.1:
+    resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /isomorphic-fetch@2.2.1:
+    resolution: {integrity: sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==}
+    dependencies:
+      node-fetch: 1.7.3
+      whatwg-fetch: 3.6.2
+    dev: false
+
+  /js-sdsl@4.4.0:
+    resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
+    dev: true
+
+  /js-tokens@4.0.0:
+    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+    dev: true
+
+  /js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+    dependencies:
+      argparse: 2.0.1
+    dev: true
+
+  /jsesc@0.5.0:
+    resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
+    hasBin: true
+    dev: true
+
+  /jsesc@2.5.2:
+    resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+    engines: {node: '>=4'}
+    hasBin: true
+    dev: true
+
+  /json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+    dev: true
+
+  /json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+    dev: true
+
+  /json5@2.2.3:
+    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+    engines: {node: '>=6'}
+    hasBin: true
+    dev: true
+
+  /kind-of@6.0.3:
+    resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /less@4.1.3:
+    resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==}
+    engines: {node: '>=6'}
+    hasBin: true
+    dependencies:
+      copy-anything: 2.0.6
+      parse-node-version: 1.0.1
+      tslib: 2.5.0
+    optionalDependencies:
+      errno: 0.1.8
+      graceful-fs: 4.2.11
+      image-size: 0.5.5
+      make-dir: 2.1.0
+      mime: 1.6.0
+      needle: 3.2.0
+      source-map: 0.6.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+    dev: true
+
+  /liftoff@4.0.0:
+    resolution: {integrity: sha512-rMGwYF8q7g2XhG2ulBmmJgWv25qBsqRbDn5gH0+wnuyeFt7QBJlHJmtg5qEdn4pN6WVAUMgXnIxytMFRX9c1aA==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      extend: 3.0.2
+      findup-sync: 5.0.0
+      fined: 2.0.0
+      flagged-respawn: 2.0.0
+      is-plain-object: 5.0.0
+      object.map: 1.0.1
+      rechoir: 0.8.0
+      resolve: 1.22.2
+    dev: true
+
+  /lilconfig@2.1.0:
+    resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /lint-staged@13.2.2:
+    resolution: {integrity: sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA==}
+    engines: {node: ^14.13.1 || >=16.0.0}
+    hasBin: true
+    dependencies:
+      chalk: 5.2.0
+      cli-truncate: 3.1.0
+      commander: 10.0.0
+      debug: 4.3.4
+      execa: 7.1.1
+      lilconfig: 2.1.0
+      listr2: 5.0.8
+      micromatch: 4.0.5
+      normalize-path: 3.0.0
+      object-inspect: 1.12.3
+      pidtree: 0.6.0
+      string-argv: 0.3.1
+      yaml: 2.2.2
+    transitivePeerDependencies:
+      - enquirer
+      - supports-color
+    dev: true
+
+  /listr2@5.0.8:
+    resolution: {integrity: sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==}
+    engines: {node: ^14.13.1 || >=16.0.0}
+    peerDependencies:
+      enquirer: '>= 2.3.0 < 3'
+    peerDependenciesMeta:
+      enquirer:
+        optional: true
+    dependencies:
+      cli-truncate: 2.1.0
+      colorette: 2.0.19
+      log-update: 4.0.0
+      p-map: 4.0.0
+      rfdc: 1.3.0
+      rxjs: 7.8.0
+      through: 2.3.8
+      wrap-ansi: 7.0.0
+    dev: true
+
+  /loadjs@4.2.0:
+    resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==}
+    dev: false
+
+  /local-pkg@0.4.3:
+    resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
+    engines: {node: '>=14'}
+    dev: true
+
+  /locate-path@5.0.0:
+    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+    engines: {node: '>=8'}
+    dependencies:
+      p-locate: 4.1.0
+    dev: false
+
+  /locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-locate: 5.0.0
+    dev: true
+
+  /lodash-es@4.17.21:
+    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+    dev: false
+
+  /lodash.debounce@4.0.8:
+    resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+    dev: true
+
+  /lodash.get@4.4.2:
+    resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+    dev: true
+
+  /lodash.isempty@4.4.0:
+    resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==}
+    dev: false
+
+  /lodash.isplainobject@4.0.6:
+    resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+    dev: false
+
+  /lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+    dev: true
+
+  /lodash.transform@4.6.0:
+    resolution: {integrity: sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ==}
+    dev: false
+
+  /lodash@4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+    dev: true
+
+  /log-symbols@4.1.0:
+    resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+    engines: {node: '>=10'}
+    dependencies:
+      chalk: 4.1.2
+      is-unicode-supported: 0.1.0
+    dev: true
+
+  /log-symbols@5.1.0:
+    resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==}
+    engines: {node: '>=12'}
+    dependencies:
+      chalk: 5.2.0
+      is-unicode-supported: 1.3.0
+    dev: true
+
+  /log-update@4.0.0:
+    resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-escapes: 4.3.2
+      cli-cursor: 3.1.0
+      slice-ansi: 4.0.0
+      wrap-ansi: 6.2.0
+    dev: true
+
+  /lottie-web@5.11.0:
+    resolution: {integrity: sha512-9vSt0AtdOH98GKDXwD5LPfFg9Pcmxt5+1BllAbudKM5iqPxpJnJUfuGaP45OyudDrESCOBgsjnntVUTygBNlzw==}
+    dev: false
+
+  /lower-case@2.0.2:
+    resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
+    dependencies:
+      tslib: 2.5.0
+    dev: true
+
+  /lru-cache@4.1.5:
+    resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+    dependencies:
+      pseudomap: 1.0.2
+      yallist: 2.1.2
+    dev: true
+
+  /lru-cache@5.1.1:
+    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+    dependencies:
+      yallist: 3.1.1
+    dev: true
+
+  /lru-cache@6.0.0:
+    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+    engines: {node: '>=10'}
+    dependencies:
+      yallist: 4.0.0
+    dev: true
+
+  /magic-string@0.25.9:
+    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+    dependencies:
+      sourcemap-codec: 1.4.8
+
+  /magic-string@0.30.0:
+    resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.4.15
+    dev: true
+
+  /make-dir@2.1.0:
+    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+    engines: {node: '>=6'}
+    requiresBuild: true
+    dependencies:
+      pify: 4.0.1
+      semver: 5.7.1
+    dev: true
+    optional: true
+
+  /make-iterator@1.0.1:
+    resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      kind-of: 6.0.3
+    dev: true
+
+  /map-cache@0.2.2:
+    resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /merge-stream@2.0.0:
+    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+    dev: true
+
+  /merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+    dev: true
+
+  /micromatch@4.0.5:
+    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+    engines: {node: '>=8.6'}
+    dependencies:
+      braces: 3.0.2
+      picomatch: 2.3.1
+    dev: true
+
+  /mime@1.6.0:
+    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+    engines: {node: '>=4'}
+    hasBin: true
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /mimic-fn@2.1.0:
+    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /mimic-fn@4.0.0:
+    resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /minimatch@3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+    dependencies:
+      brace-expansion: 1.1.11
+    dev: true
+
+  /minimatch@6.2.0:
+    resolution: {integrity: sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==}
+    engines: {node: '>=10'}
+    dependencies:
+      brace-expansion: 2.0.1
+    dev: true
+
+  /minimatch@7.4.5:
+    resolution: {integrity: sha512-OzOamaOmNBJZUv2qqY1OSWa+++4YPpOkLgkc0w30Oov5ufKlWWXnFUl0l4dgmSv5Shq/zRVkEOXAe2NaqO4l5Q==}
+    engines: {node: '>=10'}
+    dependencies:
+      brace-expansion: 2.0.1
+    dev: true
+
+  /minimist@1.2.8:
+    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+    dev: true
+
+  /mkdirp@1.0.4:
+    resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dev: true
+
+  /ms@2.1.2:
+    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+    dev: true
+
+  /muggle-string@0.2.2:
+    resolution: {integrity: sha512-YVE1mIJ4VpUMqZObFndk9CJu6DBJR/GB13p3tXuNbwD4XExaI5EOuRl6BHeIDxIqXZVxSfAC+y6U1Z/IxCfKUg==}
+    dev: true
+
+  /mutation-observer@1.0.3:
+    resolution: {integrity: sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==}
+    dev: false
+
+  /mute-stream@0.0.8:
+    resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
+    dev: true
+
+  /nanoid@3.3.6:
+    resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  /natural-compare-lite@1.4.0:
+    resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+    dev: true
+
+  /natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+    dev: true
+
+  /needle@3.2.0:
+    resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==}
+    engines: {node: '>= 4.4.x'}
+    hasBin: true
+    requiresBuild: true
+    dependencies:
+      debug: 3.2.7
+      iconv-lite: 0.6.3
+      sax: 1.2.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+    optional: true
+
+  /neo-async@2.6.2:
+    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+    dev: true
+
+  /no-case@3.0.4:
+    resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+    dependencies:
+      lower-case: 2.0.2
+      tslib: 2.5.0
+    dev: true
+
+  /node-fetch@1.7.3:
+    resolution: {integrity: sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==}
+    dependencies:
+      encoding: 0.1.13
+      is-stream: 1.1.0
+    dev: false
+
+  /node-plop@0.31.1:
+    resolution: {integrity: sha512-qmXJJt3YETFt/e0dtMADVpvck6EvN01Jig086o+J3M6G++mWA7iJ3Pqz4m4kvlynh73Iz2/rcZzxq7xTiF+aIQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      '@types/inquirer': 8.2.6
+      change-case: 4.1.2
+      del: 6.1.1
+      globby: 13.1.3
+      handlebars: 4.7.7
+      inquirer: 8.2.5
+      isbinaryfile: 4.0.10
+      lodash.get: 4.4.2
+      lower-case: 2.0.2
+      mkdirp: 1.0.4
+      resolve: 1.22.2
+      title-case: 3.0.3
+      upper-case: 2.0.2
+    dev: true
+
+  /node-releases@2.0.10:
+    resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
+    dev: true
+
+  /normalize-path@1.0.0:
+    resolution: {integrity: sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /normalize-path@3.0.0:
+    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /normalize-range@0.1.2:
+    resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /npm-run-path@2.0.2:
+    resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
+    engines: {node: '>=4'}
+    dependencies:
+      path-key: 2.0.1
+    dev: true
+
+  /npm-run-path@5.1.0:
+    resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      path-key: 4.0.0
+    dev: true
+
+  /nth-check@2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+    dependencies:
+      boolbase: 1.0.0
+    dev: true
+
+  /numeral@2.0.6:
+    resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==}
+    dev: false
+
+  /object-inspect@1.12.3:
+    resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+
+  /object-keys@1.1.1:
+    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /object.assign@4.1.4:
+    resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.2
+      define-properties: 1.2.0
+      has-symbols: 1.0.3
+      object-keys: 1.1.1
+    dev: true
+
+  /object.defaults@1.1.0:
+    resolution: {integrity: sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      array-each: 1.0.1
+      array-slice: 1.1.0
+      for-own: 1.0.0
+      isobject: 3.0.1
+    dev: true
+
+  /object.map@1.0.1:
+    resolution: {integrity: sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      for-own: 1.0.0
+      make-iterator: 1.0.1
+    dev: true
+
+  /object.pick@1.3.0:
+    resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      isobject: 3.0.1
+    dev: true
+
+  /once@1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+    dependencies:
+      wrappy: 1.0.2
+    dev: true
+
+  /onetime@5.1.2:
+    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+    engines: {node: '>=6'}
+    dependencies:
+      mimic-fn: 2.1.0
+    dev: true
+
+  /onetime@6.0.0:
+    resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      mimic-fn: 4.0.0
+    dev: true
+
+  /optionator@0.9.1:
+    resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.3
+    dev: true
+
+  /ora@5.4.1:
+    resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      bl: 4.1.0
+      chalk: 4.1.2
+      cli-cursor: 3.1.0
+      cli-spinners: 2.8.0
+      is-interactive: 1.0.0
+      is-unicode-supported: 0.1.0
+      log-symbols: 4.1.0
+      strip-ansi: 6.0.1
+      wcwidth: 1.0.1
+    dev: true
+
+  /ora@6.3.0:
+    resolution: {integrity: sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      chalk: 5.2.0
+      cli-cursor: 4.0.0
+      cli-spinners: 2.8.0
+      is-interactive: 2.0.0
+      is-unicode-supported: 1.3.0
+      log-symbols: 5.1.0
+      stdin-discarder: 0.1.0
+      strip-ansi: 7.0.1
+      wcwidth: 1.0.1
+    dev: true
+
+  /os-tmpdir@1.0.2:
+    resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /p-finally@1.0.0:
+    resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /p-limit@2.3.0:
+    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+    engines: {node: '>=6'}
+    dependencies:
+      p-try: 2.2.0
+    dev: false
+
+  /p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      yocto-queue: 0.1.0
+    dev: true
+
+  /p-locate@4.1.0:
+    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+    engines: {node: '>=8'}
+    dependencies:
+      p-limit: 2.3.0
+    dev: false
+
+  /p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-limit: 3.1.0
+    dev: true
+
+  /p-map@4.0.0:
+    resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      aggregate-error: 3.1.0
+    dev: true
+
+  /p-try@2.2.0:
+    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+    engines: {node: '>=6'}
+    dev: false
+
+  /param-case@3.0.4:
+    resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
+    dependencies:
+      dot-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+    dependencies:
+      callsites: 3.1.0
+    dev: true
+
+  /parse-filepath@1.0.2:
+    resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==}
+    engines: {node: '>=0.8'}
+    dependencies:
+      is-absolute: 1.0.0
+      map-cache: 0.2.2
+      path-root: 0.1.1
+    dev: true
+
+  /parse-node-version@1.0.1:
+    resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
+    engines: {node: '>= 0.10'}
+    dev: true
+
+  /parse-passwd@1.0.0:
+    resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /pascal-case@3.1.2:
+    resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
+    dependencies:
+      no-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /path-case@3.0.4:
+    resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==}
+    dependencies:
+      dot-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+
+  /path-is-absolute@1.0.1:
+    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /path-key@2.0.1:
+    resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /path-key@4.0.0:
+    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /path-parse@1.0.7:
+    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+    dev: true
+
+  /path-root-regex@0.1.2:
+    resolution: {integrity: sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /path-root@0.1.1:
+    resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      path-root-regex: 0.1.2
+    dev: true
+
+  /path-type@4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /picocolors@1.0.0:
+    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
+  /picomatch@2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+    dev: true
+
+  /pidtree@0.6.0:
+    resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+    engines: {node: '>=0.10'}
+    hasBin: true
+    dev: true
+
+  /pify@4.0.1:
+    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+    engines: {node: '>=6'}
+    dev: true
+    optional: true
+
+  /plop@3.1.2:
+    resolution: {integrity: sha512-39SOtQ3WlePXSNqKqAh/QlUSHXHO25iCnyCO3Qs/9UzPVmwVledRTDGvPd2csh+JnHVXz4c63F6fBwdqZHgbUg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    hasBin: true
+    dependencies:
+      '@types/liftoff': 4.0.0
+      chalk: 5.2.0
+      interpret: 2.2.0
+      liftoff: 4.0.0
+      minimist: 1.2.8
+      node-plop: 0.31.1
+      ora: 6.3.0
+      v8flags: 4.0.0
+    dev: true
+
+  /plyr@3.7.8:
+    resolution: {integrity: sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA==}
+    dependencies:
+      core-js: 3.30.2
+      custom-event-polyfill: 1.0.7
+      loadjs: 4.2.0
+      rangetouch: 2.0.1
+      url-polyfill: 1.1.12
+    dev: false
+
+  /pngjs@5.0.0:
+    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
+    engines: {node: '>=10.13.0'}
+    dev: false
+
+  /postcss-pxtorem@6.0.0(postcss@8.4.21):
+    resolution: {integrity: sha512-ZRXrD7MLLjLk2RNGV6UA4f5Y7gy+a/j1EqjAfp9NdcNYVjUMvg5HTYduTjSkKBkRkfqbg/iKrjMO70V4g1LZeg==}
+    peerDependencies:
+      postcss: ^8.0.0
+    dependencies:
+      postcss: 8.4.21
+    dev: true
+
+  /postcss-selector-parser@6.0.11:
+    resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==}
+    engines: {node: '>=4'}
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+    dev: true
+
+  /postcss-value-parser@4.2.0:
+    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+    dev: true
+
+  /postcss@8.4.21:
+    resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
+    engines: {node: ^10 || ^12 || >=14}
+    dependencies:
+      nanoid: 3.3.6
+      picocolors: 1.0.0
+      source-map-js: 1.0.2
+
+  /prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+    dev: true
+
+  /prettier-linter-helpers@1.0.0:
+    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      fast-diff: 1.2.0
+    dev: true
+
+  /prettier@2.8.7:
+    resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    dev: true
+
+  /prr@1.0.1:
+    resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
+    dev: true
+    optional: true
+
+  /pseudomap@1.0.2:
+    resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
+    dev: true
+
+  /punycode@2.3.0:
+    resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /qrcode@1.5.3:
+    resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    dependencies:
+      dijkstrajs: 1.0.3
+      encode-utf8: 1.0.3
+      pngjs: 5.0.0
+      yargs: 15.4.1
+    dev: false
+
+  /qs@6.11.1:
+    resolution: {integrity: sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==}
+    engines: {node: '>=0.6'}
+    dependencies:
+      side-channel: 1.0.4
+    dev: false
+
+  /query-string@8.1.0:
+    resolution: {integrity: sha512-BFQeWxJOZxZGix7y+SByG3F36dA0AbTy9o6pSmKFcFz7DAj0re9Frkty3saBn3nHo3D0oZJ/+rx3r8H8r8Jbpw==}
+    engines: {node: '>=14.16'}
+    dependencies:
+      decode-uri-component: 0.4.1
+      filter-obj: 5.1.0
+      split-on-first: 3.0.0
+    dev: false
+
+  /queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+    dev: true
+
+  /rangetouch@2.0.1:
+    resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==}
+    dev: false
+
+  /readable-stream@3.6.2:
+    resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+    engines: {node: '>= 6'}
+    dependencies:
+      inherits: 2.0.4
+      string_decoder: 1.3.0
+      util-deprecate: 1.0.2
+    dev: true
+
+  /readdirp@3.6.0:
+    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+    engines: {node: '>=8.10.0'}
+    dependencies:
+      picomatch: 2.3.1
+    dev: true
+
+  /rechoir@0.8.0:
+    resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==}
+    engines: {node: '>= 10.13.0'}
+    dependencies:
+      resolve: 1.22.2
+    dev: true
+
+  /regenerate-unicode-properties@10.1.0:
+    resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==}
+    engines: {node: '>=4'}
+    dependencies:
+      regenerate: 1.4.2
+    dev: true
+
+  /regenerate@1.4.2:
+    resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
+    dev: true
+
+  /regenerator-runtime@0.13.11:
+    resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+
+  /regenerator-transform@0.15.1:
+    resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==}
+    dependencies:
+      '@babel/runtime': 7.21.0
+    dev: true
+
+  /regexpu-core@5.3.2:
+    resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==}
+    engines: {node: '>=4'}
+    dependencies:
+      '@babel/regjsgen': 0.8.0
+      regenerate: 1.4.2
+      regenerate-unicode-properties: 10.1.0
+      regjsparser: 0.9.1
+      unicode-match-property-ecmascript: 2.0.0
+      unicode-match-property-value-ecmascript: 2.1.0
+    dev: true
+
+  /regjsparser@0.9.1:
+    resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==}
+    hasBin: true
+    dependencies:
+      jsesc: 0.5.0
+    dev: true
+
+  /require-directory@2.1.1:
+    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
+  /require-main-filename@2.0.0:
+    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+    dev: false
+
+  /resolve-dir@1.0.1:
+    resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      expand-tilde: 2.0.2
+      global-modules: 1.0.0
+    dev: true
+
+  /resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /resolve@1.22.2:
+    resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.11.0
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: true
+
+  /restore-cursor@3.1.0:
+    resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+    engines: {node: '>=8'}
+    dependencies:
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+    dev: true
+
+  /restore-cursor@4.0.0:
+    resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+    dev: true
+
+  /reusify@1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+    dev: true
+
+  /rfdc@1.3.0:
+    resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+    dev: true
+
+  /rimraf@3.0.2:
+    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    hasBin: true
+    dependencies:
+      glob: 7.2.3
+    dev: true
+
+  /rollup@2.79.1:
+    resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==}
+    engines: {node: '>=10.0.0'}
+    hasBin: true
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /rollup@3.20.2:
+    resolution: {integrity: sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==}
+    engines: {node: '>=14.18.0', npm: '>=8.0.0'}
+    hasBin: true
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /run-async@2.4.1:
+    resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
+    engines: {node: '>=0.12.0'}
+    dev: true
+
+  /run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+    dependencies:
+      queue-microtask: 1.2.3
+    dev: true
+
+  /rxjs@7.8.0:
+    resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
+    dependencies:
+      tslib: 2.5.0
+    dev: true
+
+  /safe-buffer@5.2.1:
+    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+    dev: true
+
+  /safer-buffer@2.1.2:
+    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+  /sax@1.2.4:
+    resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
+    dev: true
+    optional: true
+
+  /semver@5.7.1:
+    resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
+    hasBin: true
+    dev: true
+    optional: true
+
+  /semver@6.3.0:
+    resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
+    hasBin: true
+    dev: true
+
+  /semver@7.3.8:
+    resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      lru-cache: 6.0.0
+    dev: true
+
+  /sentence-case@3.0.4:
+    resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
+    dependencies:
+      no-case: 3.0.4
+      tslib: 2.5.0
+      upper-case-first: 2.0.2
+    dev: true
+
+  /set-blocking@2.0.0:
+    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+    dev: false
+
+  /shebang-command@1.2.0:
+    resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      shebang-regex: 1.0.0
+    dev: true
+
+  /shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+    dependencies:
+      shebang-regex: 3.0.0
+    dev: true
+
+  /shebang-regex@1.0.0:
+    resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /side-channel@1.0.4:
+    resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+    dependencies:
+      call-bind: 1.0.2
+      get-intrinsic: 1.2.0
+      object-inspect: 1.12.3
+    dev: false
+
+  /signal-exit@3.0.7:
+    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+    dev: true
+
+  /slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /slash@4.0.0:
+    resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /slice-ansi@3.0.0:
+    resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      ansi-styles: 4.3.0
+      astral-regex: 2.0.0
+      is-fullwidth-code-point: 3.0.0
+    dev: true
+
+  /slice-ansi@4.0.0:
+    resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-styles: 4.3.0
+      astral-regex: 2.0.0
+      is-fullwidth-code-point: 3.0.0
+    dev: true
+
+  /slice-ansi@5.0.0:
+    resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-styles: 6.2.1
+      is-fullwidth-code-point: 4.0.0
+    dev: true
+
+  /snake-case@3.0.4:
+    resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
+    dependencies:
+      dot-case: 3.0.4
+      tslib: 2.5.0
+    dev: true
+
+  /source-map-js@1.0.2:
+    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+    engines: {node: '>=0.10.0'}
+
+  /source-map-support@0.5.21:
+    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+    dependencies:
+      buffer-from: 1.1.2
+      source-map: 0.6.1
+
+  /source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  /sourcemap-codec@1.4.8:
+    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+    deprecated: Please use @jridgewell/sourcemap-codec instead
+
+  /split-on-first@3.0.0:
+    resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==}
+    engines: {node: '>=12'}
+    dev: false
+
+  /ssr-window@4.0.2:
+    resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==}
+    dev: false
+
+  /stdin-discarder@0.1.0:
+    resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      bl: 5.1.0
+    dev: true
+
+  /string-argv@0.3.1:
+    resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
+    engines: {node: '>=0.6.19'}
+    dev: true
+
+  /string-width@4.2.3:
+    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+    engines: {node: '>=8'}
+    dependencies:
+      emoji-regex: 8.0.0
+      is-fullwidth-code-point: 3.0.0
+      strip-ansi: 6.0.1
+
+  /string-width@5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+    dependencies:
+      eastasianwidth: 0.2.0
+      emoji-regex: 9.2.2
+      strip-ansi: 7.0.1
+    dev: true
+
+  /string_decoder@1.3.0:
+    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+    dependencies:
+      safe-buffer: 5.2.1
+    dev: true
+
+  /strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+    dependencies:
+      ansi-regex: 5.0.1
+
+  /strip-ansi@7.0.1:
+    resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-regex: 6.0.1
+    dev: true
+
+  /strip-eof@1.0.0:
+    resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /strip-final-newline@3.0.0:
+    resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /strip-indent@2.0.0:
+    resolution: {integrity: sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /supports-color@5.5.0:
+    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+    engines: {node: '>=4'}
+    dependencies:
+      has-flag: 3.0.0
+    dev: true
+
+  /supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+    dependencies:
+      has-flag: 4.0.0
+    dev: true
+
+  /supports-preserve-symlinks-flag@1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /svg-tags@1.0.0:
+    resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
+    dev: true
+
+  /swiper@9.3.2:
+    resolution: {integrity: sha512-Kj9Z4kXRmJR3YT/Wj+XLWj8P6IcRt+WG38uL8M3/Wny7+6sV0TlP9vnE1X+Co9c7VzNooojWGnFa+Wf/9+CUMA==}
+    engines: {node: '>= 4.7.0'}
+    dependencies:
+      ssr-window: 4.0.2
+    dev: false
+
+  /systemjs@6.14.1:
+    resolution: {integrity: sha512-8ftwWd+XnQtZ/aGbatrN4QFNGrKJzmbtixW+ODpci7pyoTajg4sonPP8aFLESAcuVxaC1FyDESt+SpfFCH9rZQ==}
+    dev: true
+
+  /terser@5.17.6:
+    resolution: {integrity: sha512-V8QHcs8YuyLkLHsJO5ucyff1ykrLVsR4dNnS//L5Y3NiSXpbK1J+WMVUs67eI0KTxs9JtHhgEQpXQVHlHI92DQ==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      '@jridgewell/source-map': 0.3.3
+      acorn: 8.8.2
+      commander: 2.20.3
+      source-map-support: 0.5.21
+
+  /text-segmentation@1.0.3:
+    resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+    dependencies:
+      utrie: 1.0.2
+    dev: false
+
+  /text-table@0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+    dev: true
+
+  /through@2.3.8:
+    resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+    dev: true
+
+  /title-case@3.0.3:
+    resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==}
+    dependencies:
+      tslib: 2.5.0
+    dev: true
+
+  /tmp@0.0.33:
+    resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
+    engines: {node: '>=0.6.0'}
+    dependencies:
+      os-tmpdir: 1.0.2
+    dev: true
+
+  /to-fast-properties@2.0.0:
+    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+    engines: {node: '>=4'}
+
+  /to-regex-range@5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+    dependencies:
+      is-number: 7.0.0
+    dev: true
+
+  /tslib@1.14.1:
+    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+    dev: true
+
+  /tslib@2.3.0:
+    resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
+    dev: false
+
+  /tslib@2.5.0:
+    resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
+    dev: true
+
+  /tsutils@3.21.0(typescript@5.0.4):
+    resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+    engines: {node: '>= 6'}
+    peerDependencies:
+      typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+    dependencies:
+      tslib: 1.14.1
+      typescript: 5.0.4
+    dev: true
+
+  /type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+    dev: true
+
+  /type-fest@0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /type-fest@0.21.3:
+    resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /typescript@5.0.4:
+    resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
+    engines: {node: '>=12.20'}
+    hasBin: true
+    dev: true
+
+  /uglify-js@3.17.4:
+    resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
+    engines: {node: '>=0.8.0'}
+    hasBin: true
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /umi-request@1.4.0:
+    resolution: {integrity: sha512-OknwtQZddZHi0Ggi+Vr/olJ7HNMx4AzlywyK0W3NZBT7B0stjeZ9lcztA85dBgdAj3KVk8uPJPZSnGaDjELhrA==}
+    dependencies:
+      isomorphic-fetch: 2.2.1
+      qs: 6.11.1
+    dev: false
+
+  /unc-path-regex@0.1.2:
+    resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /unicode-canonical-property-names-ecmascript@2.0.0:
+    resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /unicode-match-property-ecmascript@2.0.0:
+    resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
+    engines: {node: '>=4'}
+    dependencies:
+      unicode-canonical-property-names-ecmascript: 2.0.0
+      unicode-property-aliases-ecmascript: 2.1.0
+    dev: true
+
+  /unicode-match-property-value-ecmascript@2.1.0:
+    resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /unicode-property-aliases-ecmascript@2.1.0:
+    resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /unplugin-vue-components@0.24.1(vue@3.2.47):
+    resolution: {integrity: sha512-T3A8HkZoIE1Cja95xNqolwza0yD5IVlgZZ1PVAGvVCx8xthmjsv38xWRCtHtwl+rvZyL9uif42SRkDGw9aCfMA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@babel/parser': ^7.15.8
+      '@nuxt/kit': ^3.2.2
+      vue: 2 || 3
+    peerDependenciesMeta:
+      '@babel/parser':
+        optional: true
+      '@nuxt/kit':
+        optional: true
+    dependencies:
+      '@antfu/utils': 0.7.2
+      '@rollup/pluginutils': 5.0.2
+      chokidar: 3.5.3
+      debug: 4.3.4
+      fast-glob: 3.2.12
+      local-pkg: 0.4.3
+      magic-string: 0.30.0
+      minimatch: 7.4.5
+      resolve: 1.22.2
+      unplugin: 1.3.1
+      vue: 3.2.47
+    transitivePeerDependencies:
+      - rollup
+      - supports-color
+    dev: true
+
+  /unplugin@1.3.1:
+    resolution: {integrity: sha512-h4uUTIvFBQRxUKS2Wjys6ivoeofGhxzTe2sRWlooyjHXVttcVfV/JiavNd3d4+jty0SVV0dxGw9AkY9MwiaCEw==}
+    dependencies:
+      acorn: 8.8.2
+      chokidar: 3.5.3
+      webpack-sources: 3.2.3
+      webpack-virtual-modules: 0.5.0
+    dev: true
+
+  /update-browserslist-db@1.0.10(browserslist@4.21.5):
+    resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
+    hasBin: true
+    peerDependencies:
+      browserslist: '>= 4.21.0'
+    dependencies:
+      browserslist: 4.21.5
+      escalade: 3.1.1
+      picocolors: 1.0.0
+    dev: true
+
+  /upper-case-first@2.0.2:
+    resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
+    dependencies:
+      tslib: 2.5.0
+    dev: true
+
+  /upper-case@2.0.2:
+    resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==}
+    dependencies:
+      tslib: 2.5.0
+    dev: true
+
+  /uri-js@4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+    dependencies:
+      punycode: 2.3.0
+    dev: true
+
+  /url-polyfill@1.1.12:
+    resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==}
+    dev: false
+
+  /util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+    dev: true
+
+  /utrie@1.0.2:
+    resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+    dependencies:
+      base64-arraybuffer: 1.0.2
+    dev: false
+
+  /v8flags@4.0.0:
+    resolution: {integrity: sha512-83N0OkTbn6gOjJ2awNuzuK4czeGxwEwBoTqlhBZhnp8o0IJ72mXRQKphj/azwRf3acbDJZYZhbOPEJHd884ELg==}
+    engines: {node: '>= 10.13.0'}
+    dev: true
+
+  /vant@4.1.2(vue@3.2.47):
+    resolution: {integrity: sha512-iRUYBR5zDbs7O0UTxauyW/0XbJoE0g/eHipn0y3QxXeazdmNiaV0kGbBKRJ8vE/7p74zila/O5LzDiYbPDDN7Q==}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      '@vant/popperjs': 1.3.0
+      '@vant/use': 1.5.1(vue@3.2.47)
+      vue: 3.2.47
+    dev: false
+
+  /vconsole@3.15.0:
+    resolution: {integrity: sha512-8hq7wabPcRucSWQyN7/1tthMawP9JPvM95zgtMHpPknMMMCKj+abpoK7P7oKK4B0qw58C24Mdvo9+raUdpHyVQ==}
+    dependencies:
+      '@babel/runtime': 7.21.0
+      copy-text-to-clipboard: 3.1.0
+      core-js: 3.30.2
+      mutation-observer: 1.0.3
+    dev: false
+
+  /vite-plugin-eslint@1.8.1(eslint@8.38.0)(vite@4.2.1):
+    resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
+    peerDependencies:
+      eslint: '>=7'
+      vite: '>=2'
+    dependencies:
+      '@rollup/pluginutils': 4.2.1
+      '@types/eslint': 8.37.0
+      eslint: 8.38.0
+      rollup: 2.79.1
+      vite: 4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6)
+    dev: true
+
+  /vite@4.2.1(@types/node@16.18.23)(less@4.1.3)(terser@5.17.6):
+    resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': '>= 14'
+      less: '*'
+      sass: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      less:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+    dependencies:
+      '@types/node': 16.18.23
+      esbuild: 0.17.15
+      less: 4.1.3
+      postcss: 8.4.21
+      resolve: 1.22.2
+      rollup: 3.20.2
+      terser: 5.17.6
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /vue-awesome-swiper@5.0.1(swiper@9.3.2)(vue@3.2.47):
+    resolution: {integrity: sha512-mWjFJzUqA4lG+DmsmibvMpoiBnl+IH2SSeiiQ3i5M0t1y9FknTxnGT0DsMb2YdJLgjYMEK3sYOWzqgLnZMH8Lg==}
+    peerDependencies:
+      swiper: ^7.0.0  || ^8.0.0
+      vue: 3.x
+    dependencies:
+      swiper: 9.3.2
+      vue: 3.2.47
+    dev: false
+
+  /vue-demi@0.14.5(vue@3.2.47):
+    resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+    dependencies:
+      vue: 3.2.47
+    dev: false
+
+  /vue-eslint-parser@9.1.1(eslint@8.38.0):
+    resolution: {integrity: sha512-C2aI/r85Q6tYcz4dpgvrs4wH/MqVrRAVIdpYedrxnATDHHkb+TroeRcDpKWGZCx/OcECMWfz7tVwQ8e+Opy6rA==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '>=6.0.0'
+    dependencies:
+      debug: 4.3.4
+      eslint: 8.38.0
+      eslint-scope: 7.1.1
+      eslint-visitor-keys: 3.4.0
+      espree: 9.5.1
+      esquery: 1.5.0
+      lodash: 4.17.21
+      semver: 7.3.8
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /vue-router@4.1.6(vue@3.2.47):
+    resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==}
+    peerDependencies:
+      vue: ^3.2.0
+    dependencies:
+      '@vue/devtools-api': 6.5.0
+      vue: 3.2.47
+    dev: false
+
+  /vue-template-compiler@2.7.14:
+    resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==}
+    dependencies:
+      de-indent: 1.0.2
+      he: 1.2.0
+    dev: true
+
+  /vue-tsc@1.2.0(typescript@5.0.4):
+    resolution: {integrity: sha512-rIlzqdrhyPYyLG9zxsVRa+JEseeS9s8F2BbVVVWRRsTZvJO2BbhLEb2HW3MY+DFma0378tnIqs+vfTzbcQtRFw==}
+    hasBin: true
+    peerDependencies:
+      typescript: '*'
+    dependencies:
+      '@volar/vue-language-core': 1.2.0
+      '@volar/vue-typescript': 1.2.0
+      typescript: 5.0.4
+    dev: true
+
+  /vue3-lottie@2.7.0(vue@3.2.47):
+    resolution: {integrity: sha512-6vblrGFQxRP1bqd5Lfg+/g/kDH7OL5dQMxU9xYORSsTC7NfHXOjebhYrIYOlRodtA5/zfWMkG+3+sIR7wjaIXw==}
+    engines: {node: '>=12'}
+    peerDependencies:
+      vue: ^3.2
+    dependencies:
+      lodash-es: 4.17.21
+      lottie-web: 5.11.0
+      vue: 3.2.47
+    dev: false
+
+  /vue@3.2.47:
+    resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==}
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-sfc': 3.2.47
+      '@vue/runtime-dom': 3.2.47
+      '@vue/server-renderer': 3.2.47(vue@3.2.47)
+      '@vue/shared': 3.2.47
+
+  /wcwidth@1.0.1:
+    resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
+    dependencies:
+      defaults: 1.0.4
+    dev: true
+
+  /webpack-sources@3.2.3:
+    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
+    engines: {node: '>=10.13.0'}
+    dev: true
+
+  /webpack-virtual-modules@0.5.0:
+    resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
+    dev: true
+
+  /whatwg-fetch@3.6.2:
+    resolution: {integrity: sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==}
+    dev: false
+
+  /which-module@2.0.1:
+    resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
+    dev: false
+
+  /which@1.3.1:
+    resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+    hasBin: true
+    dependencies:
+      isexe: 2.0.0
+    dev: true
+
+  /which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+    dependencies:
+      isexe: 2.0.0
+    dev: true
+
+  /word-wrap@1.2.3:
+    resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /wordwrap@1.0.0:
+    resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+    dev: true
+
+  /wrap-ansi@6.2.0:
+    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+    engines: {node: '>=8'}
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+
+  /wrap-ansi@7.0.0:
+    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+    dev: true
+
+  /wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+    dev: true
+
+  /xml-name-validator@4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /y18n@4.0.3:
+    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+    dev: false
+
+  /yallist@2.1.2:
+    resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
+    dev: true
+
+  /yallist@3.1.1:
+    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+    dev: true
+
+  /yallist@4.0.0:
+    resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+    dev: true
+
+  /yaml@2.2.2:
+    resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==}
+    engines: {node: '>= 14'}
+    dev: true
+
+  /yargs-parser@18.1.3:
+    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+    engines: {node: '>=6'}
+    dependencies:
+      camelcase: 5.3.1
+      decamelize: 1.2.0
+    dev: false
+
+  /yargs@15.4.1:
+    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+    engines: {node: '>=8'}
+    dependencies:
+      cliui: 6.0.0
+      decamelize: 1.2.0
+      find-up: 4.1.0
+      get-caller-file: 2.0.5
+      require-directory: 2.1.1
+      require-main-filename: 2.0.0
+      set-blocking: 2.0.0
+      string-width: 4.2.3
+      which-module: 2.0.1
+      y18n: 4.0.3
+      yargs-parser: 18.1.3
+    dev: false
+
+  /yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /yorkie@2.0.0:
+    resolution: {integrity: sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==}
+    engines: {node: '>=4'}
+    requiresBuild: true
+    dependencies:
+      execa: 0.8.0
+      is-ci: 1.2.1
+      normalize-path: 1.0.0
+      strip-indent: 2.0.0
+    dev: true
+
+  /zrender@5.4.3:
+    resolution: {integrity: sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==}
+    dependencies:
+      tslib: 2.3.0
+    dev: false

BIN=BIN
public/favicon.ico


+ 99 - 0
public/flexible.js

@@ -0,0 +1,99 @@
+!(function (a, b) {
+  function c() {
+    var b = f.getBoundingClientRect().width;
+    b / i > 420 && (b = 420 * i);
+    var c = b / 10;
+    (f.style.fontSize = c + 'px'), (k.rem = a.rem = c);
+  }
+  var d,
+    e = a.document,
+    f = e.documentElement,
+    g = e.querySelector('meta[name="viewport"]'),
+    h = e.querySelector('meta[name="flexible"]'),
+    i = 0,
+    j = 0,
+    k = b.flexible || (b.flexible = {});
+  if (g) {
+    console.warn('将根据已有的meta标签来设置缩放比例');
+    var l = g.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
+    l && ((j = parseFloat(l[1])), (i = parseInt(1 / j)));
+  } else if (h) {
+    var m = h.getAttribute('content');
+    if (m) {
+      var n = m.match(/initial\-dpr=([\d\.]+)/),
+        o = m.match(/maximum\-dpr=([\d\.]+)/);
+      n && ((i = parseFloat(n[1])), (j = parseFloat((1 / i).toFixed(2)))),
+        o && ((i = parseFloat(o[1])), (j = parseFloat((1 / i).toFixed(2))));
+    }
+  }
+  if (!i && !j) {
+    var p = a.navigator.userAgent,
+      q = (!!p.match(/android/gi), !!p.match(/iphone/gi)),
+      r = q && !!p.match(/OS 9_3/),
+      s = a.devicePixelRatio;
+    (i =
+      q && !r
+        ? s >= 3 && (!i || i >= 3)
+          ? 3
+          : s >= 2 && (!i || i >= 2)
+          ? 2
+          : 1
+        : 1),
+      (j = 1 / i);
+  }
+  if ((f.setAttribute('data-dpr', i), !g))
+    if (
+      ((g = e.createElement('meta')),
+      g.setAttribute('name', 'viewport'),
+      g.setAttribute(
+        'content',
+        'initial-scale=' +
+          j +
+          ', maximum-scale=' +
+          j +
+          ', minimum-scale=' +
+          j +
+          ', user-scalable=no'
+      ),
+      f.firstElementChild)
+    )
+      f.firstElementChild.appendChild(g);
+    else {
+      var t = e.createElement('div');
+      t.appendChild(g), e.write(t.innerHTML);
+    }
+  a.addEventListener(
+    'resize',
+    function () {
+      clearTimeout(d), (d = setTimeout(c, 300));
+    },
+    !1
+  ),
+    a.addEventListener(
+      'pageshow',
+      function (a) {
+        a.persisted && (clearTimeout(d), (d = setTimeout(c, 300)));
+      },
+      !1
+    ),
+    'complete' === e.readyState
+      ? (e.body.style.fontSize = 12 * i + 'px')
+      : e.addEventListener(
+          'DOMContentLoaded',
+          function () {
+            e.body.style.fontSize = 12 * i + 'px';
+          },
+          !1
+        ),
+    c(),
+    (k.dpr = a.dpr = i),
+    (k.refreshRem = c),
+    (k.rem2px = function (a) {
+      var b = parseFloat(a) * this.rem;
+      return 'string' == typeof a && a.match(/rem$/) && (b += 'px'), b;
+    }),
+    (k.px2rem = function (a) {
+      var b = parseFloat(a) / this.rem;
+      return 'string' == typeof a && a.match(/px$/) && (b += 'rem'), b;
+    });
+})(window, window.lib || (window.lib = {}));

+ 11 - 0
src/App.tsx

@@ -0,0 +1,11 @@
+import { defineComponent } from 'vue';
+export default defineComponent({
+  name: 'App',
+  setup() {
+    return () => (
+      <>
+        <router-view></router-view>
+      </>
+    );
+  }
+});

+ 10 - 0
src/component-ui/README.md

@@ -0,0 +1,10 @@
+### components-ui
+
+1、在 Vant3.x 基础上封装一套独立样式,因环境差异较大数据应统一输入尽量不要请求接口;
+2、注意 Vant 库等必要依赖库的版本差异;
+3、组件采用 less 的方式编写;
+
+### 使用
+
+1、把项目中 index.less 在项目的根目录中使用;
+2、一些基础组件,只会在原生有 UI 组件上变更样式;

+ 129 - 0
src/component-ui/global.less

@@ -0,0 +1,129 @@
+// 注意:为什么要写两个重复的 :root?
+// 由于 vant 中的主题变量也是在 :root 下声明的,所以在有些情况下会由于优先级的问题无法成功覆盖。通过
+// :root:root 可以显式地让你所写内容的优先级更高一些,从而确保主题变量的成功覆盖。
+:root:root {
+  // 01 品牌色
+  --k-primary: #ff8057;
+
+  // 02 背景色
+  --k-bg-1: #fff;
+  --k-bg-2: #f8f8f8;
+  --k-bg-3: #f6f6f6;
+  --k-bg-4: #f2f2f2;
+
+  // 03 辅助色
+  --k-orange: #ffebdd;
+  --k-red: #f44541;
+  --k-blue: #64a9ff;
+  --k-purple: #8f80ff;
+
+  // 04 渐变色
+  --k-gradient-1: linear-gradient(90deg, #ff9c63 0%, #ff7144 100%);
+  --k-gradient-2: linear-gradient(270deg, #ff4f44 0%, #ffafab 100%);
+  --k-gradient-3: linear-gradient(90deg, #8cccff 0%, #459aff 100%);
+  --k-gradient-4: linear-gradient(90deg, #d4a9ff 0%, #8f80ff 100%);
+  --k-gradient-5: linear-gradient(90deg, #a9f0b4 0%, #09c58c 100%);
+
+  // 05 字体颜色
+  --k-font-primary: #f67146;
+  --k-font-danger: #f44541;
+  --k-gray-1: #333333;
+  --k-gray-2: #666666;
+  --k-gray-3: #777777;
+  --k-gray-4: #aaaaaa;
+  --k-gray-5: #cccccc;
+
+  // 06 分割线
+  --k-hairline-dark: #eeeeee;
+  --k-hairline-shallow: #f2f2f2;
+
+  // 07 蒙层
+  --k-overlay-background-dark: rgba(0, 0, 0, 0.7);
+  --k-overlay-background-shallow: rgba(0, 0, 0, 0.5);
+
+  // 圆角
+  --k-radius-sm: 2px;
+  --k-radius-md: 4px;
+  --k-radius-lg: 8px;
+  --k-radius-xl: 10px;
+  --k-radius-max: 999px;
+
+  // 间距
+  --k-padding-base: 4px;
+  --k-padding-xs: 6px;
+  --k-padding-sm: 8px;
+  --k-padding-md: 12px;
+  --k-padding-lg: 16px;
+  --k-padding-xl: 20px;
+  --k-padding-page: 13px; // 页面是基础边距
+  --k-padding-card: 9px; // 卡片的基础边距
+
+  // 描边 投影
+  --k-border-color: var(--k-primary);
+  --k-border-width: 1px;
+  --k-shadow: 0px 2px 12px 0px rgba(100, 101, 102, 0.12);
+
+  // 设置Vant UI组件库中的默认样式;
+  --van-primary: var(--k-primary);
+  --van-primary-color: var(--van-primary);
+  --van-primary-text: var(--k-font-primary);
+  --van-text-color: var(--k-gray-1);
+
+  // 多选框
+  --van-checkbox-border-color: #dcdcdc;
+  --van-checkbox-label-color: var(--k-gray-1);
+  --van-checkbox-disabled-icon-color: #dcdcdc;
+  --van-checkbox-disabled-label-color: var(--k-gray-5);
+  --van-checkbox-disabled-background: #f7f8fa;
+
+  // 单选框
+  --van-radio-border-color: #dcdcdc;
+  --van-radio-disabled-icon-color: #dcdcdc;
+  --van-radio-disabled-background: #f7f8fa;
+
+  // 导航
+  --van-nav-bar-arrow-size: 20px;
+  --van-nav-bar-title-font-size: 18px;
+  --van-nav-bar-title-text-color: var(--k-gray-1);
+  --van-nav-bar-icon-color: var(--k-gray-1);
+
+  // tab 选择卡
+  --van-tab-text-color: var(--k-gray-3);
+  --van-tabs-bottom-bar-width: 40px;
+  --van-tab-active-text-color: var(--k-gray-1);
+
+  // 侧边导航栏(分类选择)
+  --van-sidebar-selected-border-width: 2px;
+  --van-sidebar-selected-border-height: 18px;
+  --van-sidebar-text-color: var(--k-gray-1);
+  --van-sidebar-selected-text-color: var(--k-primary);
+
+  // 宫格
+  --van-grid-item-text-color: var(--k-gray-1);
+  --van-grid-item-text-font-size: 14px;
+
+  // 步骤条
+  --van-step-horizontal-title-font-size: 14px;
+  --van-step-finish-text-color: var(--k-gray-1);
+  --van-step-text-color: #999;
+
+  // 按钮
+  --van-button-normal-font-size: 18px;
+
+  // 通知栏
+  --van-notice-bar-background: #ffe3d2;
+  --van-notice-bar-text-color: var(--k-font-primary);
+
+  // 开关
+  --van-switch-size: 22px;
+  --van-switch-width: calc(2em + 4px);
+  --van-switch-height: calc(1em + 4px);
+  // --van-switch-background: #fff;
+
+  // 折叠面板
+  --van-collapse-item-content-text-color: #999;
+
+  // 头部高度
+  --van-nav-bar-height: 44px;
+  --van-nav-bar-arrow-size: 22px;
+}

+ 218 - 0
src/component-ui/index.less

@@ -0,0 +1,218 @@
+// 公用变量
+@import './global.less';
+// :global {
+// 单元格
+.van-cell-group--inset {
+  margin: 0 var(--k-padding-page);
+  border-radius: var(--k-radius-xl);
+}
+.van-cell {
+  font-size: 15px;
+  padding: 12px 18px;
+  color: var(--k-gray-1);
+}
+
+// 导航 - ✅
+.van-nav-bar__left,
+.van-nav-bar__right {
+  padding: 0 var(--k-padding-md);
+}
+
+// 选项卡 侧边导航栏(分类选择) - ✅
+.van-tabs--card {
+  padding: 0;
+  .van-tabs__nav {
+    background-color: transparent;
+  }
+  .van-tabs__nav--card {
+    border-radius: var(--k-radius-max);
+    border: 0;
+  }
+  .van-tab--card {
+    margin-right: var(--k-padding-md);
+    border-right: 0;
+    color: var(--k-gray-1);
+    background-color: #fff;
+    border-radius: var(--k-radius-max);
+    &.van-tab--active {
+      color: #fff;
+      background-color: var(--k-primary);
+    }
+    &:last-child {
+      margin-right: 0;
+    }
+  }
+  .van-tab--shrink {
+    padding: 0 var(--k-padding-lg);
+  }
+}
+
+// 宫格 - ✅
+// 步骤条 - ✅
+// 按钮 - ✅
+.van-button {
+  font-weight: 500;
+  &:active:before {
+    opacity: 0.2;
+  }
+}
+.van-button--disabled {
+  position: relative;
+  opacity: 1;
+  &:active:before {
+    opacity: 0.6;
+  }
+  &:before {
+    content: ' ';
+    display: block;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 100%;
+    height: 100%;
+    background: #fff;
+    border: inherit;
+    border-color: #fff;
+    border-radius: inherit;
+    transform: translate(-50%, -50%);
+    opacity: 0.6;
+  }
+}
+
+// 搜索框 - 【不处理】
+.van-search__field {
+  padding: 0 var(--van-padding-xs) 0 0;
+}
+
+// 气泡弹出框 - 【不处理】
+// 对话框 - ✅
+// 轻提示 - 【不处理】
+// 通知栏 - ✅
+// 遮罩/基础样式 - ✅
+// 定义了基础变量,如果需要对应的引入; --k-overlay-background-dark, --k-overlay-background-shallow
+
+// 单元格滑动 - 【不处理】
+// 协议 - 【不处理】
+// 缺省图 - 【不处理】
+// 输入框 - ✅
+.van-field__label {
+  color: var(--k-gray-2);
+  font-size: 15px;
+}
+.van-field__control {
+  font-size: 15px;
+}
+.van-field__control::placeholder {
+  color: var(--k-gray-5);
+}
+.van-cell__right-icon {
+  font-size: 13px;
+  font-weight: bold;
+  color: #d8d8d8;
+}
+.van-field__label--top.border {
+  position: relative;
+  padding-bottom: 10px;
+  margin-bottom: 10px;
+  &::after {
+    display: block;
+    position: absolute;
+    box-sizing: border-box;
+    content: ' ';
+    pointer-events: none;
+    right: var(--van-padding-md);
+    bottom: 0;
+    left: var(--van-padding-md);
+    border-bottom: 0.02667rem solid var(--van-cell-border-color);
+    transform: scaleY(0.5);
+  }
+}
+
+// 选择框
+// 上拉选择 - ✅
+// 选择器 - ✅
+.van-picker {
+  --van-picker-toolbar-height: 44px !important;
+  .van-picker__toolbar {
+    position: relative;
+    &::after {
+      position: absolute;
+      box-sizing: border-box;
+      content: ' ';
+      pointer-events: none;
+      right: var(--van-padding-md);
+      bottom: 0;
+      left: var(--van-padding-md);
+      border-bottom: 1px solid var(--van-cell-border-color);
+      transform: scaleY(0.5);
+    }
+  }
+  .van-picker__columns {
+    padding: 0 24px;
+  }
+  .van-picker-column {
+    position: relative;
+    z-index: 1;
+  }
+  .van-picker__frame {
+    z-index: 0;
+    &::after {
+      background: var(--k-bg-4);
+      border-radius: 8px;
+    }
+  }
+  .van-picker__cancel,
+  .van-picker__confirm {
+    font-size: 15px;
+  }
+  .van-picker__cancel {
+    color: var(--k-gray-3);
+  }
+  .van-picker__confirm {
+    color: var(--k-font-primary);
+  }
+  .van-picker-column__item {
+    color: var(--k-gray-1);
+    font-size: 16px;
+  }
+  .van-picker-column__item--selected {
+    font-weight: 600;
+  }
+}
+
+// 日历选择器 - ✅
+
+// 上拉菜单-分享面板 - 【不处理】
+// 下拉菜单/搜索样式框 - 【不处理】
+
+// 文件上传 - 【不处理】
+// 图片展示 - 【不处理】
+// 图片全屏展示 - ✅
+.van-image-preview {
+  .van-image-preview__close-icon,
+  .van-image-preview__index {
+    top: calc(var(--van-padding-md) + env(safe-area-inset-bottom));
+  }
+}
+// 弹出层 - 【不处理】
+// 开关 / 基础样式 / 禁用样式
+
+// 折叠面板 - ✅
+// 标签样式
+
+.van-tag {
+  padding-top: 1px;
+  .van-tag__close {
+    margin-top: -2px;
+  }
+}
+.van-tag--large {
+  padding-top: calc(var(--van-padding-base) + 1px);
+}
+.van-tag--medium {
+  padding-top: 3px;
+}
+// 轮播 - 【不处理】
+// 骨架屏 - 【不处理】
+// 进度条 - 【不处理】
+// }

+ 28 - 0
src/component-ui/k-action-sheet/index.module.less

@@ -0,0 +1,28 @@
+@import '../global.less';
+
+.k-sheet_content {
+  margin: 0 13px;
+  padding-top: 10px;
+  :global {
+    .van-sheet-item {
+      line-height: 52px;
+      font-size: 16px;
+      font-weight: 400;
+      color: var(--k-gray-1);
+      text-align: center;
+      padding: 0 var(--k-padding-md);
+    }
+    .van-sheet-item-active {
+      background: var(--k-bg-4);
+      border-radius: var(--k-radius-lg);
+      font-weight: 600;
+    }
+  }
+}
+.k-action-sheet_bottom__cancel {
+  margin: 0 13px;
+  width: calc(100vw - 26px);
+  line-height: 52px;
+  padding: 0;
+  color: var(--k-gray-4);
+}

+ 84 - 0
src/component-ui/k-action-sheet/index.tsx

@@ -0,0 +1,84 @@
+import { ActionSheet } from 'vant';
+import { defineComponent, PropType, reactive, watch } from 'vue';
+import styles from './index.module.less';
+
+type actionsType = {
+  name: string | number;
+  value?: string | number;
+  selected?: boolean;
+};
+
+export default defineComponent({
+  name: 'k-action-sheet',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    actions: {
+      type: Array as PropType<actionsType[]>,
+      required: true,
+      default: () => []
+    },
+    cancelText: {
+      type: String,
+      default: '取消'
+    },
+    teleport: {
+      type: [String, Element],
+      default: ''
+    }
+  },
+  emits: ['update:show', 'select'],
+  setup(props, { emit }) {
+    const form = reactive({
+      oPopover: props.show
+    });
+
+    const onSelect = (item: any) => {
+      emit('select', item);
+      emit('update:show', false);
+    };
+
+    watch(
+      () => form.oPopover,
+      () => {
+        emit('update:show', form.oPopover);
+      }
+    );
+
+    watch(
+      () => props.show,
+      () => {
+        form.oPopover = props.show;
+      }
+    );
+
+    return () => (
+      <ActionSheet v-model:show={form.oPopover} teleport={props.teleport}>
+        <div class={[styles['k-sheet_content'], 'van-hairline--bottom']}>
+          {props.actions.map((item: any) => (
+            <div
+              class={[
+                'van-sheet-item van-ellipsis',
+                item.selected && 'van-sheet-item-active'
+              ]}
+              onClick={() => onSelect(item)}>
+              {item.name}
+            </div>
+          ))}
+        </div>
+
+        <button
+          type="button"
+          class={[
+            'van-action-sheet__cancel',
+            styles['k-action-sheet_bottom__cancel']
+          ]}
+          onClick={() => emit('update:show', false)}>
+          {props.cancelText}
+        </button>
+      </ActionSheet>
+    );
+  }
+});

+ 47 - 0
src/component-ui/k-dialog/index.module.less

@@ -0,0 +1,47 @@
+@import '../global.less';
+
+.dialogTitle {
+  i {
+    display: inline-block;
+    width: 4px;
+    height: 14px;
+    background: var(--k-primary);
+    border-radius: 2px;
+    margin-right: 6px;
+  }
+
+  padding-left: 25px;
+  text-align: left;
+  font-size: 18px;
+  font-weight: 500;
+  color: var(--k-gary-1);
+  line-height: 25px;
+  padding-bottom: 12px;
+}
+
+.oDialog {
+  // margin-top: env(safe-area-inset-top);
+  :global {
+    .van-dialog__header {
+      padding-top: 20px;
+    }
+    .van-dialog__message {
+      font-size: 16px;
+      color: var(--k-gray-1);
+      font-weight: 400;
+      line-height: 24px;
+    }
+    .van-dialog__cancel,
+    .van-dialog__confirm {
+      font-size: 18px;
+      height: 50px;
+      line-height: 50px;
+    }
+    .van-dialog__cancel {
+      color: var(--k-gray-3);
+    }
+    .van-dialog__confirm {
+      color: var(--k-font-primary);
+    }
+  }
+}

+ 97 - 0
src/component-ui/k-dialog/index.tsx

@@ -0,0 +1,97 @@
+import { Dialog } from 'vant'
+import { defineComponent, PropType, reactive, watch } from 'vue'
+import styles from './index.module.less'
+
+export default defineComponent({
+  name: 'o-dialog',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    message: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    confirmButtonText: {
+      type: String,
+      default: '确认'
+    },
+    allowHtml: {
+      type: Boolean,
+      default: false
+    },
+    cancelButtonText: {
+      type: String,
+      default: '取消'
+    },
+    showConfirmButton: {
+      type: Boolean,
+      default: true
+    },
+    showCancelButton: {
+      type: Boolean,
+      default: false
+    },
+    messageAlign: {
+      type: String as PropType<'left' | 'center' | 'right'>,
+      default: 'center'
+    },
+    dialogMarginTop: {
+      type: String,
+      default: '0px'
+    }
+  },
+  emits: ['cancel', 'confirm', 'update:show'],
+  setup(props, { emit, slots }) {
+    const state = reactive({
+      show: props.show || false
+    })
+
+    // 监听状态
+    watch(
+      () => props.show,
+      () => {
+        state.show = props.show
+      }
+    )
+    return () => (
+      <Dialog
+        class={styles.oDialog}
+        style={{
+          marginTop: props.dialogMarginTop
+        }}
+        v-model:show={state.show}
+        message={props.message}
+        allowHtml={props.allowHtml}
+        messageAlign={props.messageAlign}
+        confirmButtonText={props.confirmButtonText}
+        cancelButtonText={props.cancelButtonText}
+        showConfirmButton={props.showConfirmButton}
+        showCancelButton={props.showCancelButton}
+        onConfirm={() => {
+          emit('update:show', false)
+          emit('confirm')
+        }}
+        onCancel={() => {
+          emit('update:show', false)
+          emit('cancel')
+        }}
+      >
+        {{
+          title: () =>
+            props.title && (
+              <div class={styles.dialogTitle}>
+                <i></i>
+                {props.title}
+              </div>
+            )
+        }}
+      </Dialog>
+    )
+  }
+})

BIN=BIN
src/components/m-empty/images/404.png


BIN=BIN
src/components/m-empty/images/empty.png


BIN=BIN
src/components/m-empty/images/network.png


+ 25 - 0
src/components/m-empty/index.module.less

@@ -0,0 +1,25 @@
+.mEmpty {
+  --van-empty-description-color: var(--k-gray-4);
+  --van-empty-description-font-size: 16px;
+  --van-empty-description-margin-top: 13px;
+
+  :global {
+    .van-empty__image {
+      width: 198px;
+      height: 124px;
+    }
+
+    .van-empty__bottom {
+      width: 100%;
+      text-align: center;
+    }
+  }
+
+  .button {
+    background: transparent;
+    min-width: 76px;
+    font-size: 13px;
+    padding: 0 24px;
+    height: 36px;
+  }
+}

+ 62 - 0
src/components/m-empty/index.tsx

@@ -0,0 +1,62 @@
+import { PropType, defineComponent, onMounted, reactive } from 'vue';
+import styles from './index.module.less';
+import { Button, Empty } from 'vant';
+import iconEmpty from './images/empty.png';
+import iconNetwork from './images/network.png';
+import icon404 from './images/404.png';
+
+export default defineComponent({
+  name: 'm-empty',
+  props: {
+    description: {
+      type: String as PropType<string | undefined>,
+      default: ''
+    },
+    image: {
+      type: String as PropType<'empty' | 'network' | '404'>,
+      default: 'empty'
+    },
+    showButton: {
+      type: Boolean,
+      default: false
+    },
+    buttonText: {
+      type: String,
+      default: '返回'
+    }
+  },
+  emits: ['click'],
+  setup(props, { emit }) {
+    const forms = reactive({
+      image: iconEmpty
+    });
+
+    onMounted(() => {
+      if (props.image === 'network') {
+        forms.image = iconNetwork;
+      } else if (props.image === '404') {
+        forms.image = icon404;
+      }
+    });
+    return () => (
+      <Empty
+        style={{
+          paddingTop: 0
+        }}
+        class={styles.mEmpty}
+        image={forms.image}
+        description={props.description}>
+        {props.showButton && (
+          <Button
+            type="primary"
+            plain
+            round
+            class={styles.button}
+            onClick={() => emit('click')}>
+            {props.buttonText}
+          </Button>
+        )}
+      </Empty>
+    );
+  }
+});

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/components/m-full-refresh/datas/data.json


+ 21 - 0
src/components/m-full-refresh/index.module.less

@@ -0,0 +1,21 @@
+.animateWrap {
+  width: 55px !important;
+  height: 55px !important;
+}
+
+.loading {
+  height: 55px !important;
+  img {
+    height: 30px;
+    width: 120px;
+    margin-top: 20px;
+  }
+}
+
+.pullRefresh {
+  :global {
+    .van-pull-refresh__track {
+      min-height: inherit;
+    }
+  }
+}

+ 77 - 0
src/components/m-full-refresh/index.tsx

@@ -0,0 +1,77 @@
+import { Image, PullRefresh } from 'vant';
+import { defineComponent, reactive, watch } from 'vue';
+import styles from './index.module.less';
+import { Vue3Lottie } from 'vue3-lottie';
+import AstronautJSON from './datas/data.json';
+import 'vue3-lottie/dist/style.css';
+import loading from './loading.gif';
+import loadingJSon from './loading.json';
+export default defineComponent({
+  name: 's-full-refresh',
+  props: {
+    title: String,
+    modelValue: {
+      type: Boolean,
+      default: false
+    }
+  },
+  emits: ['refresh', 'update:modelValue'],
+  setup(props, { emit, slots }) {
+    const state = reactive({
+      fullState: false
+    });
+    watch(
+      () => props.modelValue,
+      (val: boolean) => {
+        state.fullState = val;
+      }
+    );
+    watch(
+      () => state.fullState,
+      (val: boolean) => {
+        emit('update:modelValue', val);
+      }
+    );
+    return () => (
+      <PullRefresh
+        v-model:modelValue={state.fullState}
+        onRefresh={() => emit('refresh')}
+        loadingText=" "
+        class={styles.pullRefresh}>
+        {{
+          loading: () => (
+            <div>
+              {
+                <Image src={loadingJSon.loading} class={styles.loading} />
+                // <Vue3Lottie
+                //   class={styles.animateWrap}
+                //   animationData={AstronautJSON}></Vue3Lottie>
+              }
+            </div>
+          ),
+          pulling: () => (
+            <div>
+              {
+                <Image src={loading} class={styles.loading} />
+                // <Vue3Lottie
+                //   class={styles.animateWrap}
+                //   animationData={AstronautJSON}></Vue3Lottie>
+              }
+            </div>
+          ),
+          loosing: () => (
+            <div>
+              {
+                <Image src={loading} class={styles.loading} />
+                // <Vue3Lottie
+                //   class={styles.animateWrap}
+                //   animationData={AstronautJSON}></Vue3Lottie>
+              }
+            </div>
+          ),
+          default: () => <> {slots.default && slots.default()}</>
+        }}
+      </PullRefresh>
+    );
+  }
+});

BIN=BIN
src/components/m-full-refresh/loading.gif


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
src/components/m-full-refresh/loading.json


+ 0 - 0
src/components/m-header/index.module.less


+ 123 - 0
src/components/m-header/index.tsx

@@ -0,0 +1,123 @@
+import { postMessage } from '@/helpers/native-message';
+import { browser } from '@/helpers/utils';
+import { NavBar } from 'vant';
+import { defineComponent, onMounted, reactive, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import styles from './index.module.less';
+import { state } from '@/state';
+
+export default defineComponent({
+  name: 'm-header',
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    isBack: {
+      type: Boolean,
+      default: true
+    },
+    border: {
+      type: Boolean,
+      default: false
+    },
+    isFixed: {
+      type: Boolean,
+      default: true
+    },
+    styleName: {
+      type: Object,
+      default: () => ({})
+    },
+    background: {
+      type: String,
+      default: 'white'
+    },
+    color: {
+      type: String,
+      default: '#323233'
+    },
+    rightText: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['rightClick'],
+  setup(props, { emit, slots }) {
+    const route = useRoute();
+    const router = useRouter();
+    const forms = reactive({
+      title: '',
+      navBarHeight: state.navBarHeight // 顶部高度
+    });
+
+    const onClickLeft = () => {
+      if (browser().isApp) {
+        postMessage({
+          api: 'goBack'
+        });
+      } else {
+        router.back();
+      }
+    };
+    const onClickRight = () => {
+      emit('rightClick');
+    };
+
+    onMounted(() => {
+      forms.title = props.title || (route.meta.title as string);
+      forms.navBarHeight = state.navBarHeight;
+    });
+
+    watch(
+      () => props.title,
+      () => {
+        forms.title = props.title || (route.meta.title as string);
+      }
+    );
+    return () => (
+      <>
+        {slots.content ? (
+          <div
+            style={{
+              paddingTop: `${forms.navBarHeight}px`,
+              background: props.background
+            }}
+            class={styles.headerSection}>
+            {slots.content(forms.navBarHeight)}
+          </div>
+        ) : (
+          <>
+            <div
+              style={{
+                minHeight: `calc(var(--van-nav-bar-height) + ${forms.navBarHeight}px)`
+              }}
+              class={styles.headerSection}>
+              <NavBar
+                title={forms.title}
+                class={[styles.colHeader]}
+                style={{
+                  background: props.background,
+                  color: props.color,
+                  paddingTop: `${forms.navBarHeight}px`
+                }}
+                left-arrow={props.isBack}
+                rightText={props.rightText}
+                fixed={props.isFixed}
+                zIndex={2000}
+                border={props.border}
+                onClickLeft={onClickLeft}
+                onClickRight={onClickRight}
+                v-slots={{
+                  right: () =>
+                    (slots.right && slots.right()) || props.rightText,
+                  title: () => (slots.title && slots.title()) || forms.title
+                }}></NavBar>
+            </div>
+            {slots.default ? slots.default() : null}
+          </>
+        )}
+      </>
+    );
+  }
+});

+ 35 - 0
src/components/m-image-preview/index.module.less

@@ -0,0 +1,35 @@
+.overlayPreview {
+  --van-overlay-background: rgba(0, 0, 0, 0.9) !important;
+
+}
+
+
+.imagePreview {
+  --van-image-preview-close-icon-size: 32px;
+  --van-image-preview-index-line-height: 32px;
+
+  :global {
+    .van-image-preview__cover {
+      // top: calc(var(--van-padding-md) + constant(safe-area-inset-bottom));
+      // top: calc(var(--van-padding-md) + env(safe-area-inset-bottom));
+      right: var(--van-image-preview-close-icon-margin);
+      left: initial;
+      font-size: 32px;
+    }
+
+    .van-image-preview__index {
+      z-index: var(--van-image-preview-close-icon-z-index);
+    }
+
+    .plyr--fullscreen-fallback {
+      height: 100% !important;
+      width: var(--window-page-width) !important;
+      left: var(--window-page-position-left) !important;
+    }
+
+    .video-back {
+      // left: 20px;
+      // left: calc(var(--window-page-position-left) + 20px) !important;
+    }
+  }
+}

+ 281 - 0
src/components/m-image-preview/index.tsx

@@ -0,0 +1,281 @@
+import {
+  Image,
+  Icon,
+  showLoadingToast,
+  showSuccessToast,
+  showFailToast,
+  Popup,
+  Swipe,
+  SwipeItem
+} from 'vant';
+import {
+  PropType,
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  watch
+} from 'vue';
+import styles from './index.module.less';
+import iconPreviewClose from '@/common/images/icon-preview-close.png';
+import iconPreviewDownload from '@/common/images/icon-preview-download.png';
+import { promisefiyPostMessage } from '@/helpers/native-message';
+import { checkFile } from '@/helpers/toolsValidate';
+import MVideo from '../m-video';
+import { state } from '@/state';
+import { browser } from '@/helpers/utils';
+import deepClone from '@/helpers/deep-clone';
+
+export default defineComponent({
+  name: 'm-image-preview',
+  props: {
+    show: {
+      tyep: Boolean,
+      default: false
+    },
+    images: {
+      type: Array as PropType<string[]>,
+      default: () => []
+    },
+    showIndex: {
+      type: Boolean,
+      default: true
+    },
+    startPosition: {
+      type: Number,
+      default: 0
+    },
+    loop: {
+      type: Boolean,
+      default: false
+    },
+    showDownload: {
+      type: Boolean,
+      default: true
+    },
+    teleport: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['update:show'],
+  setup(props, { emit }) {
+    const forms = reactive({
+      show: false,
+      showButton: true,
+      index: props.startPosition + 1,
+      saveLoading: false,
+      preLoading: false
+    });
+
+    const onSave = async (img: string) => {
+      if (forms.saveLoading) return;
+      forms.saveLoading = true;
+      showLoadingToast({ message: '下载中...', forbidClick: true });
+      try {
+        const res = await promisefiyPostMessage({
+          api: 'saveFile',
+          content: {
+            img,
+            type: checkFile(img, 'image') ? 'image' : 'video'
+          }
+        });
+        if (res?.content?.status === 'success') {
+          showSuccessToast('保存成功');
+        } else {
+          showFailToast('保存失败');
+        }
+      } catch {
+        //
+      }
+      forms.saveLoading = false;
+    };
+
+    const videoRef: any = ref([]);
+    const onPlay = (index: any) => {
+      videoRef.value.forEach((item: any, child: any) => {
+        if (child !== index) {
+          item?.onStop();
+          item?.onExitScreen();
+        }
+      });
+    };
+
+    onMounted(() => {
+      forms.show = props.show;
+      // console.log(window.document.body.clientWidth);
+      document.documentElement.style.setProperty(
+        '--window-page-width',
+        (window.document.body.clientWidth || window.document.body.offsetWidth) +
+          'px'
+      );
+
+      onChnageLeftWidth(forms.index - 1);
+    });
+
+    const onChnageLeftWidth = (index: number) => {
+      document.documentElement.style.setProperty(
+        '--window-page-position-left',
+        (window.document.body.clientWidth || window.document.body.offsetWidth) *
+          index +
+          'px'
+      );
+    };
+
+    watch(
+      () => props.show,
+      () => {
+        forms.show = props.show;
+        forms.index = props.startPosition + 1;
+        forms.preLoading = props.show;
+        onChnageLeftWidth(props.startPosition);
+        // console.log(forms.preLoading, 'show');
+        // nextTick(() => {
+        //   // 判断打开的内容是否为视频,是则自动播放
+        //   const defaultUrl = props.images[props.startPosition];
+        //   console.log(defaultUrl, 'defaultUrl');
+        //   if (checkFile(defaultUrl, 'video') && props.show) {
+        //     console.log(1111, videoRef.value);
+        //     //   videoRef.value[props.startPosition]?.onPlay();
+        //     videoRef.value.forEach((item: any, child: any) => {
+        //       if (child === props.startPosition) {
+        //         console.log(item, 'item');
+        //         item?.onPlay();
+        //       }
+        //     });
+        //   }
+        // });
+      }
+    );
+    watch(
+      () => props.startPosition,
+      () => {
+        forms.index = props.startPosition + 1;
+        onChnageLeftWidth(props.startPosition);
+      }
+    );
+
+    return () => (
+      <Popup
+        teleport={props.teleport}
+        v-model:show={forms.show}
+        overlay-class={styles.overlayPreview}
+        class={['van-image-preview', styles.imagePreview]}>
+        {forms.show ? (
+          <>
+            {forms.showButton && (
+              <>
+                <Icon
+                  name={iconPreviewClose}
+                  class="van-image-preview__close-icon van-image-preview__close-icon--top-left van-haptics-feedback"
+                  style={{
+                    top: state.navBarHeight
+                      ? state.navBarHeight + 'px'
+                      : 'var(--van-padding-md)'
+                  }}
+                  onClick={() => {
+                    onPlay(-1);
+                    emit('update:show', false);
+                  }}
+                />
+                <div
+                  class={'van-image-preview__index'}
+                  style={{
+                    top: state.navBarHeight
+                      ? state.navBarHeight + 'px'
+                      : 'var(--van-padding-md)'
+                  }}>
+                  {forms.index} / {props.images.length}
+                </div>
+                {props.showDownload && browser().isApp ? (
+                  <Icon
+                    name={iconPreviewDownload}
+                    class="van-image-preview__close-icon van-image-preview__close-icon--top-right van-haptics-feedback"
+                    style={{
+                      top: state.navBarHeight
+                        ? state.navBarHeight + 'px'
+                        : 'var(--van-padding-md)'
+                    }}
+                    onClick={() => {
+                      // console.log(
+                      //   forms.index,
+                      //   'index',
+                      //   props.images[forms.index - 1]
+                      // );
+
+                      onSave(props.images[forms.index - 1]);
+                    }}
+                  />
+                ) : (
+                  ''
+                )}
+              </>
+            )}
+            <Swipe
+              autoplay={0}
+              loop={false}
+              class={'van-image-preview__swipe'}
+              showIndicators={false}
+              initialSwipe={props.startPosition}
+              onChange={(index: number) => {
+                forms.index = index + 1;
+                // forms.preLoading = true;
+                onPlay(index);
+                onChnageLeftWidth(index);
+              }}
+              lazyRender>
+              {props.images.map((url: string, index: number) => (
+                <SwipeItem
+                  class={'van-image-preview__swipe-item'}
+                  onClick={() => {
+                    onPlay(-1);
+                    emit('update:show', false);
+                  }}>
+                  {checkFile(url, 'image') ? (
+                    <Image class="van-image-preview__image" src={url} />
+                  ) : (
+                    <div
+                      class="van-image-preview__image"
+                      onClick={(e: MouseEvent) => {
+                        e.stopPropagation();
+                        e.preventDefault();
+                      }}>
+                      <MVideo
+                        ref={(el: any) => {
+                          videoRef.value[index] = el;
+                          // if (forms.index === index + 1 && forms.preLoading) {
+                          //   console.log(el, 'player');
+                          //   el?.onPlay();
+                          //   forms.preLoading = false;
+                          // }
+                        }}
+                        // onReady={player => {
+                        //   if (
+                        //     props.startPosition === index &&
+                        //     forms.preLoading
+                        //   ) {
+                        //     console.log(player, 'player');
+                        //     player?.play();
+                        //     forms.preLoading = false;
+                        //   }
+                        // }}
+                        src={url}
+                        onPlay={() => onPlay(index)}
+                        preLoading={false}
+                        // onEnterfullscreen={() => (forms.showButton = false)}
+                        // onExitfullscreen={() => (forms.showButton = true)}
+                      />
+                    </div>
+                  )}
+                </SwipeItem>
+              ))}
+            </Swipe>
+          </>
+        ) : (
+          ''
+        )}
+      </Popup>
+    );
+  }
+});

+ 45 - 0
src/components/m-img-code/index.module.less

@@ -0,0 +1,45 @@
+.imgCode {
+  padding: 16px;
+
+  .codeTitle {
+    text-align: center;
+    font-size: 16px;
+    color: #4f4f4f;
+    margin: 0;
+    padding-bottom: 16px;
+  }
+
+  .img {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .imgChange {
+    display: block;
+    color: #aaaaaa;
+    font-size: 12px;
+    text-align: center;
+    padding-top: 5px;
+  }
+
+  .field {
+    background: #f4f4f4;
+    padding: 10px 12px !important;
+  }
+}
+
+.imgCodePopup {
+  width: 90%;
+  border-radius: 5px;
+  overflow: initial;
+
+  :global {
+    .van-popup__close-icon {
+      top: -37px !important;
+      right: 0 !important;
+      font-size: 25px;
+      color: #fff;
+    }
+  }
+}

+ 129 - 0
src/components/m-img-code/index.tsx

@@ -0,0 +1,129 @@
+import { defineComponent } from 'vue';
+import {
+  Col,
+  Popup,
+  Row,
+  Image as VanImage,
+  Loading,
+  Field,
+  showToast
+} from 'vant';
+import styles from './index.module.less';
+import request from '@/helpers/request';
+
+export default defineComponent({
+  name: 'o-img-code',
+  props: {
+    value: Boolean,
+    phone: [String, Number],
+    type: {
+      type: String,
+      default: 'LOGIN'
+    }
+  },
+  emits: ['close', 'sendCode'],
+  data() {
+    const origin = window.location.origin;
+    return {
+      isSuffix: '/api-web',
+      showStatus: false,
+      identifyingCode:
+        origin + '/api-web/code/getLoginImage?phone=' + this.phone,
+      code: ''
+    };
+  },
+  mounted() {
+    this.showStatus = this.value;
+  },
+  watch: {
+    value(val: any) {
+      this.showStatus = val;
+    },
+    code(val: any) {
+      if (val.length >= 4) {
+        this.checkVerifyLoginImage();
+      }
+    }
+  },
+  methods: {
+    async updateIdentifyingCode() {
+      // 刷新token
+      const origin = window.location.origin;
+      this.identifyingCode = `${origin}/api-web/code/getLoginImage?phone=${
+        this.phone
+      }&token=${Math.random()}`;
+    },
+    async checkVerifyLoginImage() {
+      try {
+        if ((this as any).code.length < 4) {
+          return;
+        }
+        await request.post(`${this.isSuffix}/code/verifyLoginImage`, {
+          requestType: 'form',
+          hideLoading: true,
+          data: {
+            phone: this.phone,
+            code: this.code
+          }
+        });
+        await request.post(`${this.isSuffix}/code/sendSms`, {
+          requestType: 'form',
+          hideLoading: true,
+          data: {
+            mobile: this.phone
+          }
+        });
+        setTimeout(() => {
+          showToast('验证码已发送');
+        }, 100);
+        this.$emit('close');
+        this.$emit('sendCode');
+      } catch {
+        this.code = '';
+        this.updateIdentifyingCode();
+      }
+    }
+  },
+  render() {
+    return (
+      <Popup
+        show={this.showStatus}
+        class={styles.imgCodePopup}
+        closeOnClickOverlay={false}
+        onClose={() => {
+          this.$emit('close');
+        }}
+        closeable
+        closeIcon="close">
+        <div class={styles.imgCode}>
+          <p class={styles.codeTitle}>输入图形验证码</p>
+          <Row>
+            <Col span="14">
+              <Field
+                placeholder="请输入验证码"
+                v-model={this.code}
+                class={styles.field}
+              />
+            </Col>
+            <Col span="10" class={styles.img}>
+              <VanImage
+                src={this.identifyingCode}
+                onClick={() => this.updateIdentifyingCode()}>
+                {{ loading: () => <Loading type="spinner" size="20" /> }}
+              </VanImage>
+            </Col>
+          </Row>
+          <Row style={{ display: 'flex', justifyContent: 'end' }}>
+            <Col span="10">
+              <span
+                class={styles.imgChange}
+                onClick={() => this.updateIdentifyingCode()}>
+                看不清?换一换
+              </span>
+            </Col>
+          </Row>
+        </div>
+      </Popup>
+    );
+  }
+});

+ 112 - 0
src/components/m-popup/index.tsx

@@ -0,0 +1,112 @@
+import { Popup, PopupPosition } from 'vant';
+import { defineComponent, PropType } from 'vue';
+import qs from 'query-string';
+
+export default defineComponent({
+  name: 'col-popup',
+  props: {
+    height: {
+      type: String,
+      default: '100%'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    teleport: {
+      type: String,
+      default: ''
+    },
+    destroy: {
+      type: Boolean,
+      default: false
+    },
+    modelValue: {
+      type: Boolean,
+      default: false
+    },
+    position: {
+      type: String as PropType<PopupPosition>,
+      default: 'bottom'
+    },
+    zIndex: {
+      type: Number,
+      default: 2018
+    }
+  },
+  emits: ['close', 'update:modelValue'],
+  data() {
+    return {
+      popupShow: false,
+      isDestroy: false
+    };
+  },
+  watch: {
+    modelValue() {
+      this.hashState();
+    }
+  },
+  mounted() {
+    this.destroy && (this.isDestroy = false);
+
+    window.addEventListener('hashchange', this.onHash, false);
+  },
+  unmounted() {
+    window.removeEventListener('hashchange', this.onHash, false);
+  },
+  methods: {
+    onHash() {
+      this.$emit('update:modelValue', false);
+      this.isDestroy = false;
+      this.$emit('close');
+    },
+    onPopupClose(val: boolean) {
+      this.$emit('update:modelValue', val);
+      this.hashState();
+    },
+    hashState() {
+      // 打开弹窗
+      if (this.modelValue) {
+        this.isDestroy = false;
+        const splitUrl = window.location.hash.slice(1).split('?');
+        const query = qs.parse(splitUrl[1]);
+        let times = 0;
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
+        for (const key in query) {
+          times++;
+        }
+        const origin = window.location.href;
+        const url = times > 0 ? '&sPop=' + +new Date() : '?sPop=' + +new Date();
+        history.pushState('', '', `${origin}${url}`);
+      } else {
+        const splitUrl = window.location.hash.slice(1).split('?');
+        const query = qs.parse(splitUrl[1]);
+        if (query.sPop) {
+          window.history.go(-1);
+        }
+      }
+      if (this.$refs.protocolPopup) {
+        (this.$refs.protocolPopup as any).scrollTop = 0;
+      }
+    }
+  },
+  render() {
+    return (
+      <Popup
+        ref="protocolPopup"
+        show={this.modelValue}
+        transitionAppear={true}
+        position={this.position}
+        teleport={this.teleport}
+        style={{ height: this.height, width: this.width }}
+        zIndex={this.zIndex}
+        onClosed={() => {
+          if (this.destroy) {
+            this.isDestroy = true;
+          }
+        }}>
+        {this.$slots.default && !this.isDestroy && this.$slots.default()}
+      </Popup>
+    );
+  }
+});

+ 47 - 0
src/components/m-protocol/index.module.less

@@ -0,0 +1,47 @@
+.mProtocol {
+  // display: flex;
+  // align-items: center;
+  font-size: 12px;
+  padding: 15px 14px;
+  color: var(--k-gray-4);
+
+  .protocolText {
+    color: var(--van-primary);
+    line-height: 15px;
+  }
+
+  .boxStyle {
+    background: transparent !important;
+    width: 15px;
+    height: 15px;
+    font-size: 15px;
+    border: transparent !important;
+  }
+
+  :global {
+    .van-checkbox {
+      display: inline-block;
+      align-items: inherit;
+      overflow: inherit;
+    }
+
+    .van-checkbox__icon {
+      height: 15px;
+      line-height: 15px;
+      display: inline-block;
+      vertical-align: sub;
+    }
+
+    .van-checkbox__label {
+      line-height: 15px;
+      color: var(--k-gray-4);
+    }
+  }
+
+  .protocolContent {
+    font-size: 14px;
+    padding: 12px;
+    color: #333;
+    line-height: 1.4;
+  }
+}

+ 139 - 0
src/components/m-protocol/index.tsx

@@ -0,0 +1,139 @@
+import { Checkbox, Icon, Popup } from 'vant';
+import { defineComponent, PropType } from 'vue';
+import styles from './index.module.less';
+import activeButtonIcon from '@/common/images/icon-check-active.png';
+import inactiveButtonIcon from '@/common/images/icon-check.png';
+import MHeader from '../m-header';
+import request from '@/helpers/request';
+const protocolText: any = {
+  BUY_ORDER: '《管乐团平台服务协议》',
+  REGISTER: '《管乐团平台注册协议》'
+};
+export default defineComponent({
+  name: 'o-protocol',
+  props: {
+    showHeader: {
+      type: Boolean,
+      default: false
+    },
+    modelValue: {
+      type: Boolean,
+      default: false
+    },
+    prototcolType: {
+      type: String as PropType<'BUY_ORDER' | 'REGISTER' | 'WITHDRAW'>,
+      default: 'BUY_ORDER'
+    }
+  },
+  data() {
+    return {
+      exists: true,
+      checked: this.modelValue,
+      popupStatus: false,
+      protocolHTML: '',
+      protocolPopup: null as any
+    };
+  },
+  async mounted() {
+    try {
+      this.checked = this.checked || this.exists;
+      this.$emit('update:modelValue', this.checked || this.exists);
+    } catch {
+      //
+    }
+    this.checked = this.modelValue;
+    window.addEventListener('hashchange', this.onHash, false);
+  },
+  unmounted() {
+    window.removeEventListener('hashchange', this.onHash, false);
+  },
+  watch: {
+    checked(val) {
+      this.$emit('update:modelValue', val);
+    },
+    modelValue() {
+      this.checked = this.modelValue;
+    }
+  },
+  methods: {
+    async getContractDetail() {
+      try {
+        // 判断是否有协议内容
+        if (!this.protocolHTML) {
+          const { data } = await request.get(
+            '/api-student/schoolContractTemplate/queryLatestContractTemplate',
+            {
+              params: {
+                contractType: this.prototcolType
+              }
+            }
+          );
+          this.protocolHTML = data.contractTemplateContent;
+        }
+        this.onPopupClose();
+      } catch {
+        //
+      }
+    },
+    onHash() {
+      this.popupStatus = false;
+    },
+    onPopupClose() {
+      this.popupStatus = !this.popupStatus;
+
+      // 打开弹窗
+      if (this.popupStatus) {
+        const route = this.$route;
+        let times = 0;
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
+        for (const i in route.query) {
+          times += 1;
+        }
+        const origin = window.location.href;
+        const url = times > 0 ? '&pto=' + +new Date() : '?pto=' + +new Date();
+        history.pushState('', '', `${origin}${url}`);
+      } else {
+        window.history.go(-1);
+      }
+      if (this.protocolPopup) {
+        (this.protocolPopup as any).scrollTop = 0;
+      }
+    }
+  },
+  render() {
+    return (
+      <div class={styles.mProtocol}>
+        <Checkbox
+          v-model={this.checked}
+          v-slots={{
+            icon: (props: any) => (
+              <Icon
+                class={styles.boxStyle}
+                name={props.checked ? activeButtonIcon : inactiveButtonIcon}
+              />
+            )
+          }}>
+          我已阅读并同意
+        </Checkbox>
+        <span onClick={this.getContractDetail} class={styles.protocolText}>
+          {protocolText[this.prototcolType]}
+        </span>
+
+        <Popup
+          ref={this.protocolPopup}
+          show={this.popupStatus}
+          position="bottom"
+          style={{ height: '100%' }}>
+          {this.showHeader && <MHeader title="管乐团平台服务协议" />}
+          {this.popupStatus && (
+            <div id="mProtocol">
+              <div
+                class={styles.protocolContent}
+                v-html={this.protocolHTML}></div>
+            </div>
+          )}
+        </Popup>
+      </div>
+    );
+  }
+});

+ 26 - 0
src/components/m-qrcode/index.module.less

@@ -0,0 +1,26 @@
+.qrcode {
+  position: relative;
+
+  .qrcodeCanvas {
+    width: 100% !important;
+    height: 100% !important;
+  }
+
+  .qrcodeLogo {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    margin-left: -20px;
+    margin-top: -20px;
+    width: 40px !important;
+    height: 40px !important;
+    border-radius: 4px;
+
+    &.small {
+      margin-left: -10px;
+      margin-top: -10px;
+      width: 20px !important;
+      height: 20px !important;
+    }
+  }
+}

+ 64 - 0
src/components/m-qrcode/index.tsx

@@ -0,0 +1,64 @@
+import { defineComponent, nextTick, onMounted, ref, watch } from 'vue';
+import logo from '@common/images/smallLogo.png';
+//@ts-ignore
+import QRCode from 'qrcode';
+import styles from './index.module.less';
+
+export default defineComponent({
+  props: {
+    text: {
+      type: String,
+      default: ''
+    },
+    size: {
+      type: String,
+      default: '200px'
+    },
+    logoSize: {
+      type: String,
+      default: 'default'
+    }
+  },
+  setup(props) {
+    const canvas = ref();
+
+    const init = () => {
+      QRCode.toCanvas(
+        canvas.value,
+        props.text,
+        {
+          margin: 1
+        },
+        (error: any) => {
+          if (error) console.log(error);
+          console.log('success');
+        }
+      );
+    };
+    watch(
+      () => props.text,
+      () => {
+        init();
+      }
+    );
+    onMounted(() => {
+      nextTick(() => {
+        init();
+      });
+    });
+    return () => (
+      <div
+        class={styles.qrcode}
+        style={{ width: props.size, height: props.size }}>
+        <canvas ref={canvas} class={styles.qrcodeCanvas}></canvas>
+        <img
+          src={logo}
+          class={[
+            styles.qrcodeLogo,
+            props.logoSize === 'small' && styles.small
+          ]}
+        />
+      </div>
+    );
+  }
+});

+ 73 - 0
src/components/m-search/index.module.less

@@ -0,0 +1,73 @@
+.m-search {
+  --van-cell-background-color: transparent;
+
+  input::placeholder {
+    color: var(--k-gray-4);
+  }
+
+  :global {
+    .van-field__control {
+      -webkit-user-select: text !important;
+      user-select: text !important;
+      font-size: 13px;
+    }
+
+    .van-search__field {
+      background: transparent !important;
+      padding: 0 var(--van-padding-xs) 0 0;
+    }
+
+    .van-field__right-icon {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding-right: 4px;
+    }
+  }
+
+  &.default {
+    :global {
+      .van-search__content {
+        background: #f8f9fc !important;
+      }
+    }
+  }
+
+  &.white {
+    :global {
+      .van-search__content {
+        background: #fff !important;
+      }
+    }
+  }
+
+  &.transparent {
+    :global {
+      .van-search__content {
+        background: rgba(255, 255, 255, 0.16);
+
+        input::placeholder {
+          color: #fff;
+        }
+
+        input {
+          color: #fff;
+        }
+
+        .van-field__clear {
+          color: #fff;
+        }
+      }
+    }
+  }
+
+  .searchBtn {
+    width: 56px;
+    height: 27px;
+    padding: 0;
+    font-size: 14px;
+    font-weight: 500;
+    --van-button-mini-height: 28px;
+    --van-font-size-xs: 14px;
+  }
+}

+ 87 - 0
src/components/m-search/index.tsx

@@ -0,0 +1,87 @@
+import { Button, Icon, Search } from 'vant';
+import { PropType, defineComponent, reactive, watch } from 'vue';
+import styles from './index.module.less';
+import iconSearch from '@/common/images/icon-search.png';
+
+type inputBackground = 'default' | 'white' | 'transparent';
+export default defineComponent({
+  name: 'm-search',
+  props: {
+    modelValue: {
+      type: String,
+      default: ''
+    },
+    shape: {
+      type: String as PropType<'round' | 'square'>,
+      default: 'round'
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    autofocus: {
+      // ios系统不支持
+      type: Boolean,
+      default: false
+    },
+    placeholder: {
+      type: String,
+      default: '请输入搜索关键词'
+    },
+    background: {
+      type: String,
+      default: '#fff'
+    },
+    inputBackground: {
+      type: String as PropType<inputBackground>,
+      default: 'default'
+    }
+  },
+  emits: ['search'],
+  setup(props, { slots, emit }) {
+    const forms = reactive({
+      search: props.modelValue || ''
+    });
+
+    watch(
+      () => props.modelValue,
+      () => {
+        forms.search = props.modelValue;
+      }
+    );
+    return () => (
+      <Search
+        class={[styles['m-search'], styles[props.inputBackground]]}
+        shape={props.shape}
+        background={props.background}
+        placeholder={props.placeholder}
+        disabled={props.disabled}
+        autofocus={props.autofocus}
+        autocomplete="off"
+        v-model={forms.search}
+        clearTrigger="always"
+        onClear={() => {
+          console.log('clear');
+          forms.search = '';
+          emit('search', forms.search);
+        }}
+        onSearch={() => emit('search', forms.search)}>
+        {{
+          left: () => slots.left && slots.left(),
+          'left-icon': () => <Icon name={iconSearch} class={styles.leftIcon} />,
+          'right-icon': () => (
+            <Button
+              disabled={props.disabled}
+              class={styles.searchBtn}
+              round
+              type="primary"
+              size="mini"
+              onClick={() => emit('search', forms.search)}>
+              搜索
+            </Button>
+          )
+        }}
+      </Search>
+    );
+  }
+});

+ 13 - 0
src/components/m-sticky/index.module.less

@@ -0,0 +1,13 @@
+.sticky {
+  position: sticky;
+  top: 0;
+  z-index: 99;
+}
+
+.white {
+  background-color: #fff;
+  > div {
+    padding-top: 15px;
+    box-shadow: 0px 0px 10px 0px rgba(216, 216, 216, 0.5);
+  }
+}

+ 126 - 0
src/components/m-sticky/index.tsx

@@ -0,0 +1,126 @@
+import {
+  PropType,
+  defineComponent,
+  nextTick,
+  onMounted,
+  reactive,
+  ref,
+  watch
+} from 'vue';
+import styles from './index.module.less';
+import { useRect } from '@vant/use';
+
+export default defineComponent({
+  name: 'm-sticky',
+  props: {
+    position: {
+      type: String as PropType<'top' | 'bottom'>,
+      default: 'top'
+    },
+    mode: {
+      type: String as PropType<'fixed' | 'sticky'>,
+      default: 'fixed'
+    },
+    offsetTop: {
+      type: String,
+      default: '0px'
+    },
+    offsetBottom: {
+      default: '0px'
+    },
+    // 变量名
+    varName: {
+      type: String,
+      default: '--header-height'
+    }
+  },
+  emits: ['barHeight'],
+  setup(props, { slots, emit }) {
+    const forms = reactive({
+      divStyle: {} as any,
+      heightV: 0,
+      sectionStyle: {
+        width: '100%',
+        height: 'auto',
+        left: '0'
+      }
+    });
+
+    const __initHeight = (height: any) => {
+      forms.sectionStyle.height = `${height}px`;
+      forms.heightV = height;
+
+      // 设置名称
+      document.documentElement.style.setProperty(props.varName, `${height}px`);
+      emit('barHeight', height);
+    };
+
+    const divRef = ref();
+    const div2Ref = ref();
+    onMounted(() => {
+      if (props.position === 'top') {
+        forms.divStyle.top = props.offsetTop || '0px';
+      } else {
+        forms.divStyle.bottom = props.offsetBottom || '0px';
+      }
+      const resize = new ResizeObserver(() => {
+        const { height } = useRect(div2Ref.value);
+        __initHeight(height);
+      });
+      resize.observe(divRef.value);
+
+      // nextTick(() => {
+      //   // 为了处理刚开始头部高度为0的情况
+      //   if (divRef.value) {
+      //     const { height } = useRect(divRef.value);
+      //     __initHeight(height);
+
+      //     setTimeout(() => {
+      //       const { height } = useRect(divRef.value);
+      //       // 判断获取的高度是否一致,如果一致则不做处理
+      //       if (height === forms.heightV) return;
+      //       __initHeight(height);
+      //     }, 200);
+      //   }
+
+      //   // 为了处理头部第一次获取高度不对的问题
+      //   if (div2Ref.value) {
+      //     setTimeout(() => {
+      //       const { height } = useRect(div2Ref.value);
+      //       if (height !== forms.heightV && props.position === 'top') {
+      //         __initHeight(height);
+      //       }
+      //     }, 1000);
+      //   }
+      // });
+    });
+
+    watch(
+      () => props.offsetTop,
+      () => {
+        forms.divStyle.top = props.offsetTop;
+      }
+    );
+    watch(
+      () => props.offsetBottom,
+      () => {
+        forms.divStyle.bottom = props.offsetBottom;
+      }
+    );
+    return () => (
+      <div
+        style={[forms.sectionStyle]}
+        class={props.mode === 'sticky' && styles.sticky}>
+        <div
+          ref={divRef}
+          class={[
+            'van-sticky',
+            props.mode === 'fixed' ? 'van-sticky--fixed' : ''
+          ]}
+          style={[forms.divStyle, forms.sectionStyle]}>
+          <div ref={div2Ref}>{slots.default && slots.default()}</div>
+        </div>
+      </div>
+    );
+  }
+});

+ 67 - 0
src/components/m-uploader/index.module.less

@@ -0,0 +1,67 @@
+.uploader-section {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  box-sizing: border-box;
+  position: relative;
+
+  --upload-file-size: 74px;
+
+  .img-close {
+    position: absolute;
+    top: 5px;
+    right: 12px;
+    z-index: 99;
+    font-size: 12px;
+    background-color: rgba(0, 0, 0, 0.4);
+    color: #fff;
+    font-weight: bold;
+    width: 16px;
+    height: 16px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 50%;
+  }
+
+  .singleImgClose {
+    right: 5px;
+  }
+
+  .uploader {
+    position: relative;
+
+    &.default {
+      :global {
+        .van-uploader__upload {
+          width: var(--upload-file-size);
+          height: var(--upload-file-size);
+          background-color: #fff;
+        }
+      }
+
+      .previewImg {
+        width: var(--upload-file-size);
+        height: var(--upload-file-size);
+        border-radius: 4px;
+        overflow: hidden;
+      }
+
+      .uploadImg {
+        width: var(--upload-file-size);
+        height: var(--upload-file-size);
+        border-radius: 4px;
+        overflow: hidden;
+      }
+    }
+
+    :global {
+
+      .van-uploader__upload-icon,
+      .van-icon__image {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}

+ 389 - 0
src/components/m-uploader/index.tsx

@@ -0,0 +1,389 @@
+import {
+  closeToast,
+  Icon,
+  Image,
+  showLoadingToast,
+  showToast,
+  Uploader
+} from 'vant';
+import { defineComponent, PropType } from 'vue';
+import styles from './index.module.less';
+import { useCustomFieldValue } from '@vant/use';
+import { postMessage } from '@/helpers/native-message';
+import umiRequest from 'umi-request';
+import iconUploader from '@common/images/icon-upload.png';
+// import iconUploadClose from '@common/images/icon-upload-close.png';
+import iconVideoDefault from '@common/images/icon-video-c.png';
+import request from '@/helpers/request';
+import { getOssUploadUrl } from '@/state';
+
+export default defineComponent({
+  name: 'col-upload',
+  props: {
+    modelValue: {
+      type: Array,
+      default: () => []
+    },
+    deletable: {
+      type: Boolean,
+      default: true
+    },
+    maxCount: {
+      type: Number,
+      default: 1
+    },
+    native: {
+      // 是否原生上传
+      type: Boolean,
+      default: false
+    },
+    uploadSize: {
+      // 上传图片大小
+      type: Number,
+      default: 5
+    },
+    uploadType: {
+      type: String as PropType<'IMAGE' | 'VIDEO'>,
+      default: 'IMAGE'
+    },
+    accept: {
+      type: String,
+      default: 'image/*'
+    },
+    bucket: {
+      type: String,
+      default: 'gyt'
+    },
+    path: {
+      type: String,
+      default: ''
+    },
+    uploadIcon: {
+      type: String,
+      default: iconUploader
+    },
+    size: {
+      type: String,
+      default: 'default'
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    position: {
+      type: String as PropType<'outside' | 'inside'>,
+      default: 'outside'
+    }
+  },
+  emits: ['uploadChange', 'update:modelValue'],
+  methods: {
+    nativeUpload() {
+      if (this.disabled) {
+        return;
+      }
+      const type = this.uploadType === 'VIDEO' ? 'video' : 'img';
+
+      let imgCount = 1;
+      if (this.maxCount > 1) {
+        imgCount = this.maxCount - this.modelValue.length;
+      } else {
+        imgCount = this.maxCount;
+      }
+      postMessage(
+        {
+          api: 'chooseFile',
+          content: {
+            type: type,
+            max: imgCount,
+            bucket: this.bucket,
+            path: this.path
+          }
+        },
+        (res: any) => {
+          console.log(res, 'fileUrl');
+          // 判断是否是多选
+          if (this.maxCount > 1) {
+            const files = res.fileUrl;
+            console.log(files, 'files');
+            this.$emit('update:modelValue', [
+              ...this.modelValue,
+              ...files.split(',')
+            ]);
+            this.$emit('uploadChange', [
+              ...this.modelValue,
+              ...files.split(',')
+            ]);
+          } else {
+            this.$emit('update:modelValue', [res.fileUrl]);
+            this.$emit('uploadChange', [res.fileUrl]);
+          }
+        }
+      );
+    },
+    beforeRead(file: any) {
+      console.log(file, 'beforeRead');
+      const isLt2M = file.size / 1024 / 1024 < this.uploadSize;
+      if (!isLt2M) {
+        showToast(`上传文件大小不能超过 ${this.uploadSize}MB`);
+        return false;
+      }
+      return true;
+    },
+    beforeDelete() {
+      // this.dataModel.splice(detail.index, 1)
+      return true;
+    },
+    async afterRead(file: any) {
+      try {
+        file.status = 'uploading';
+        file.message = '上传中...';
+        await this.uploadFile(file.file);
+      } catch (error) {
+        closeToast();
+      }
+    },
+    onClose(e: any, item: any) {
+      const models = this.modelValue;
+      const index = models.findIndex(model => model == item);
+      if (index > -1) {
+        models.splice(index, 1);
+        this.$emit('update:modelValue', models);
+        this.$emit('uploadChange');
+      }
+
+      e.stopPropagation();
+    },
+    async getFile(file: any) {
+      try {
+        await this.uploadFile(file);
+      } catch {
+        //
+      }
+    },
+    async uploadFile(file: any) {
+      // 上传文件
+      try {
+        // 获取签名
+        const signUrl = '/api-web/getUploadSign';
+        const tempName = file.name || '';
+        const fileName =
+          this.path + '/' + (tempName && tempName.replace(/ /gi, '_'));
+        const key = new Date().getTime() + fileName;
+        console.log(file);
+
+        const res = await request.post(signUrl, {
+          data: {
+            filename: fileName,
+            bucketName: this.bucket,
+            postData: {
+              filename: fileName,
+              acl: 'public-read',
+              key: key,
+              unknowValueField: []
+            }
+          }
+        });
+        showLoadingToast({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        });
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: 'public-read',
+          name: fileName
+        } as any;
+        const formData = new FormData();
+        for (const key in obj) {
+          formData.append(key, obj[key]);
+        }
+        formData.append('file', file, fileName);
+        await umiRequest(getOssUploadUrl(this.bucket), {
+          method: 'POST',
+          data: formData
+        });
+        console.log(getOssUploadUrl(this.bucket) + key);
+        const uploadUrl = getOssUploadUrl(this.bucket) + key;
+        closeToast();
+        // 判断是否是多选
+        if (this.maxCount > 1) {
+          this.$emit('update:modelValue', [...this.modelValue, uploadUrl]);
+          this.$emit('uploadChange', [...this.modelValue, uploadUrl]);
+        } else {
+          this.$emit('update:modelValue', [uploadUrl]);
+          this.$emit('uploadChange', [uploadUrl]);
+        }
+      } catch (error) {
+        console.log(error, 'uploadFile');
+      }
+    }
+  },
+  render() {
+    useCustomFieldValue(() => this.modelValue);
+
+    return (
+      <div class={styles['uploader-section']}>
+        {this.modelValue.length > 0 &&
+          this.maxCount > 1 &&
+          this.modelValue.map((item: any) => (
+            <div class={['van-uploader', styles.uploader, styles[this.size]]}>
+              {/* 删除按钮 */}
+              {this.deletable && !this.disabled && (
+                <Icon
+                  name="cross"
+                  onClick={(e: any) => this.onClose(e, item)}
+                  class={styles['img-close']}
+                />
+              )}
+              <div class={['van-uploader__upload']}>
+                {this.uploadType === 'IMAGE' ? (
+                  <Image
+                    src={item + '@base@tag=imgScale&w=200'}
+                    class={styles.previewImg}
+                    fit="cover"
+                  />
+                ) : (
+                  <video
+                    ref="videoUpload"
+                    style={{ backgroundColor: '#F8F8F8' }}
+                    class={styles.previewImg}
+                    poster={iconVideoDefault}
+                    src={item + '#t=1,4'}
+                  />
+                )}
+              </div>
+            </div>
+          ))}
+
+        {this.native ? (
+          this.maxCount > 1 ? (
+            // 小于长度才显示
+            this.modelValue.length < this.maxCount && (
+              <div
+                class={['van-uploader', styles.uploader, styles[this.size]]}
+                onClick={this.nativeUpload}>
+                <Icon
+                  name={this.uploadIcon}
+                  class={['van-uploader__upload']}
+                  size="32"
+                />
+              </div>
+            )
+          ) : (
+            <div
+              class={['van-uploader', styles.uploader, styles[this.size]]}
+              onClick={this.nativeUpload}>
+              {this.modelValue.length > 0 ? (
+                <div class={['van-uploader__upload']}>
+                  {this.modelValue.map((item: any) => (
+                    <>
+                      {/* 删除按钮 */}
+                      {this.deletable && !this.disabled && (
+                        <Icon
+                          name="cross"
+                          onClick={(e: any) => this.onClose(e, item)}
+                          class={[styles['img-close'], styles.singleImgClose]}
+                        />
+                      )}
+                      {this.uploadType === 'IMAGE' ? (
+                        <Image
+                          fit="cover"
+                          position="center"
+                          class={styles.uploadImg}
+                          src={item + '@base@tag=imgScale&w=200'}
+                        />
+                      ) : (
+                        <video
+                          ref="videoUpload"
+                          class={styles.uploadImg}
+                          style={{ backgroundColor: '#F8F8F8' }}
+                          poster={iconVideoDefault}
+                          src={item + '#t=1,4'}
+                        />
+                      )}
+                    </>
+                  ))}
+                </div>
+              ) : (
+                <Icon
+                  name={this.uploadIcon}
+                  class={['van-uploader__upload']}
+                  size="32"
+                />
+              )}
+            </div>
+          )
+        ) : this.maxCount > 1 ? (
+          // 小于长度才显示
+          this.modelValue.length < this.maxCount && (
+            <Uploader
+              class={['van-uploader', styles.uploader, styles[this.size]]}
+              afterRead={this.afterRead}
+              beforeRead={this.beforeRead}
+              beforeDelete={this.beforeDelete}
+              uploadIcon={this.uploadIcon}
+              maxCount={this.maxCount}
+              disabled={this.disabled}
+              accept={this.accept}
+            />
+          )
+        ) : (
+          <Uploader
+            class={['van-uploader', styles.uploader, styles[this.size]]}
+            afterRead={this.afterRead}
+            beforeRead={this.beforeRead}
+            beforeDelete={this.beforeDelete}
+            uploadIcon={this.uploadIcon}
+            accept={this.accept}
+            disabled={this.disabled}>
+            {this.modelValue.length > 0 ? (
+              <div class={['van-uploader__upload']}>
+                {this.modelValue.map((item: any) => (
+                  <>
+                    {/* 删除按钮 */}
+                    {this.deletable && !this.disabled && (
+                      <Icon
+                        name="cross"
+                        onClick={(e: any) => this.onClose(e, item)}
+                        class={[styles['img-close'], styles.singleImgClose]}
+                      />
+                    )}
+
+                    {this.uploadType === 'IMAGE' ? (
+                      <Image
+                        fit="cover"
+                        position="center"
+                        class={styles.uploadImg}
+                        src={item + '@base@tag=imgScale&w=200'}
+                      />
+                    ) : (
+                      <video
+                        ref="videoUpload"
+                        class={styles.uploadImg}
+                        style={{ backgroundColor: '#F8F8F8' }}
+                        poster={iconVideoDefault}
+                        src={item + '#t=1,4'}
+                      />
+                    )}
+                  </>
+                ))}
+              </div>
+            ) : (
+              <Icon
+                name={this.uploadIcon}
+                class={['van-uploader__upload']}
+                size="32"
+              />
+            )}
+          </Uploader>
+        )}
+
+        {this.$slots.default && this.$slots.default()}
+      </div>
+    );
+  }
+});

+ 388 - 0
src/components/m-uploader/inside.tsx

@@ -0,0 +1,388 @@
+import {
+  closeToast,
+  Icon,
+  Image,
+  showLoadingToast,
+  showToast,
+  Uploader
+} from 'vant';
+import { defineComponent, PropType } from 'vue';
+import styles from './index.module.less';
+import { useCustomFieldValue } from '@vant/use';
+import { postMessage } from '@/helpers/native-message';
+import umiRequest from 'umi-request';
+import iconUploader from '@common/images/icon-upload.png';
+// import iconUploadClose from '@common/images/icon-upload-close.png';
+import iconVideoDefault from '@common/images/icon-video-c.png';
+import request from '@/helpers/request';
+import { getOssUploadUrl } from '@/state';
+
+export default defineComponent({
+  name: 'col-upload',
+  props: {
+    modelValue: {
+      type: Array,
+      default: () => []
+    },
+    deletable: {
+      type: Boolean,
+      default: true
+    },
+    maxCount: {
+      type: Number,
+      default: 1
+    },
+    native: {
+      // 是否原生上传
+      type: Boolean,
+      default: false
+    },
+    uploadSize: {
+      // 上传图片大小
+      type: Number,
+      default: 5
+    },
+    uploadType: {
+      type: String as PropType<'IMAGE' | 'VIDEO'>,
+      default: 'IMAGE'
+    },
+    accept: {
+      type: String,
+      default: 'image/*'
+    },
+    bucket: {
+      type: String,
+      default: 'gyt'
+    },
+    path: {
+      type: String,
+      default: ''
+    },
+    uploadIcon: {
+      type: String,
+      default: iconUploader
+    },
+    size: {
+      type: String,
+      default: 'default'
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    position: {
+      type: String as PropType<'outside' | 'inside'>,
+      default: 'outside'
+    }
+  },
+  emits: ['uploadChange', 'update:modelValue'],
+  methods: {
+    nativeUpload() {
+      if (this.disabled) {
+        return;
+      }
+      const type = this.uploadType === 'VIDEO' ? 'video' : 'img';
+      let imgCount = 1;
+      if (this.maxCount > 1) {
+        imgCount = this.maxCount - this.modelValue.length;
+      } else {
+        imgCount = this.maxCount;
+      }
+      postMessage(
+        {
+          api: 'chooseFile',
+          content: {
+            type: type,
+            max: imgCount,
+            bucket: this.bucket,
+            path: this.path
+          }
+        },
+        (res: any) => {
+          console.log(res, 'fileUrl');
+          // 判断是否是多选
+          if (this.maxCount > 1) {
+            const files = res.fileUrl;
+            console.log(files, 'files');
+            this.$emit('update:modelValue', [
+              ...this.modelValue,
+              ...files.split(',')
+            ]);
+            this.$emit('uploadChange', [
+              ...this.modelValue,
+              ...files.split(',')
+            ]);
+          } else {
+            this.$emit('update:modelValue', [res.fileUrl]);
+            this.$emit('uploadChange', [res.fileUrl]);
+          }
+        }
+      );
+    },
+    beforeRead(file: any) {
+      console.log(file, 'beforeRead');
+      const isLt2M = file.size / 1024 / 1024 < this.uploadSize;
+      if (!isLt2M) {
+        showToast(`上传文件大小不能超过 ${this.uploadSize}MB`);
+        return false;
+      }
+      return true;
+    },
+    beforeDelete() {
+      // this.dataModel.splice(detail.index, 1)
+      return true;
+    },
+    async afterRead(file: any) {
+      try {
+        file.status = 'uploading';
+        file.message = '上传中...';
+        await this.uploadFile(file.file);
+      } catch (error) {
+        closeToast();
+      }
+    },
+    onClose(e: any, item: any) {
+      const models = this.modelValue;
+      const index = models.findIndex(model => model == item);
+      if (index > -1) {
+        models.splice(index, 1);
+        this.$emit('update:modelValue', models);
+        this.$emit('uploadChange');
+      }
+
+      e.stopPropagation();
+    },
+    async getFile(file: any) {
+      try {
+        await this.uploadFile(file);
+      } catch {
+        //
+      }
+    },
+    async uploadFile(file: any) {
+      // 上传文件
+      try {
+        // 获取签名
+        const signUrl = '/api-web/getUploadSign';
+        const tempName = file.name || '';
+        const fileName =
+          this.path + '/' + (tempName && tempName.replace(/ /gi, '_'));
+        const key = new Date().getTime() + fileName;
+        console.log(file);
+
+        const res = await request.post(signUrl, {
+          data: {
+            filename: fileName,
+            bucketName: this.bucket,
+            postData: {
+              filename: fileName,
+              acl: 'public-read',
+              key: key,
+              unknowValueField: []
+            }
+          }
+        });
+        showLoadingToast({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        });
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: 'public-read',
+          name: fileName
+        } as any;
+        const formData = new FormData();
+        for (const key in obj) {
+          formData.append(key, obj[key]);
+        }
+        formData.append('file', file, fileName);
+        await umiRequest(getOssUploadUrl(this.bucket), {
+          method: 'POST',
+          data: formData
+        });
+        console.log(getOssUploadUrl(this.bucket) + key);
+        const uploadUrl = getOssUploadUrl(this.bucket) + key;
+        closeToast();
+        // 判断是否是多选
+        if (this.maxCount > 1) {
+          this.$emit('update:modelValue', [...this.modelValue, uploadUrl]);
+          this.$emit('uploadChange', [...this.modelValue, uploadUrl]);
+        } else {
+          this.$emit('update:modelValue', [uploadUrl]);
+          this.$emit('uploadChange', [uploadUrl]);
+        }
+      } catch (error) {
+        console.log(error, 'uploadFile');
+      }
+    }
+  },
+  render() {
+    useCustomFieldValue(() => this.modelValue);
+
+    return (
+      <>
+        {this.modelValue.length > 0 &&
+          this.maxCount > 1 &&
+          this.modelValue.map((item: any) => (
+            <div class={['van-uploader', styles.uploader, styles[this.size]]}>
+              {/* 删除按钮 */}
+              {this.deletable && !this.disabled && (
+                <Icon
+                  name="cross"
+                  onClick={(e: any) => this.onClose(e, item)}
+                  class={styles['img-close']}
+                />
+              )}
+              <div class={['van-uploader__upload']}>
+                {this.uploadType === 'IMAGE' ? (
+                  <Image
+                    src={item + '@base@tag=imgScale&w=200'}
+                    class={styles.previewImg}
+                    fit="cover"
+                  />
+                ) : (
+                  <video
+                    ref="videoUpload"
+                    style={{ backgroundColor: '#F8F8F8' }}
+                    class={styles.previewImg}
+                    poster={iconVideoDefault}
+                    src={item + '#t=1,4'}
+                  />
+                )}
+              </div>
+            </div>
+          ))}
+
+        {this.native ? (
+          this.maxCount > 1 ? (
+            // 小于长度才显示
+            this.modelValue.length < this.maxCount && (
+              <div
+                class={['van-uploader', styles.uploader, styles[this.size]]}
+                onClick={this.nativeUpload}>
+                <Icon
+                  name={this.uploadIcon}
+                  class={['van-uploader__upload']}
+                  size="32"
+                />
+              </div>
+            )
+          ) : (
+            <div
+              class={['van-uploader', styles.uploader, styles[this.size]]}
+              onClick={this.nativeUpload}>
+              {this.modelValue.length > 0 ? (
+                <div class={['van-uploader__upload']}>
+                  {this.modelValue.map((item: any) => (
+                    <>
+                      {/* 删除按钮 */}
+                      {this.deletable && !this.disabled && (
+                        <Icon
+                          name="cross"
+                          onClick={(e: any) => this.onClose(e, item)}
+                          class={[styles['img-close'], styles.singleImgClose]}
+                        />
+                      )}
+                      {this.uploadType === 'IMAGE' ? (
+                        <Image
+                          fit="cover"
+                          position="center"
+                          class={styles.uploadImg}
+                          src={item + '@base@tag=imgScale&w=200'}
+                        />
+                      ) : (
+                        <video
+                          ref="videoUpload"
+                          class={styles.uploadImg}
+                          poster={iconVideoDefault}
+                          style={{ backgroundColor: '#F8F8F8' }}
+                          src={item + '#t=1,4'}
+                        />
+                      )}
+                    </>
+                  ))}
+                </div>
+              ) : (
+                <Icon
+                  name={this.uploadIcon}
+                  class={['van-uploader__upload']}
+                  size="32"
+                />
+              )}
+            </div>
+          )
+        ) : this.maxCount > 1 ? (
+          // 小于长度才显示
+          this.modelValue.length < this.maxCount && (
+            <Uploader
+              class={['van-uploader', styles.uploader, styles[this.size]]}
+              afterRead={this.afterRead}
+              beforeRead={this.beforeRead}
+              beforeDelete={this.beforeDelete}
+              uploadIcon={this.uploadIcon}
+              maxCount={this.maxCount}
+              disabled={this.disabled}
+              accept={this.accept}
+            />
+          )
+        ) : (
+          <Uploader
+            class={['van-uploader', styles.uploader, styles[this.size]]}
+            afterRead={this.afterRead}
+            beforeRead={this.beforeRead}
+            beforeDelete={this.beforeDelete}
+            uploadIcon={this.uploadIcon}
+            accept={this.accept}
+            disabled={this.disabled}>
+            {this.modelValue.length > 0 ? (
+              <div class={['van-uploader__upload']}>
+                {this.modelValue.map((item: any) => (
+                  <>
+                    {/* 删除按钮 */}
+                    {this.deletable && !this.disabled && (
+                      <Icon
+                        name="cross"
+                        onClick={(e: any) => this.onClose(e, item)}
+                        class={[styles['img-close'], styles.singleImgClose]}
+                      />
+                    )}
+
+                    {this.uploadType === 'IMAGE' ? (
+                      <Image
+                        fit="cover"
+                        position="center"
+                        class={styles.uploadImg}
+                        src={item + '@base@tag=imgScale&w=200'}
+                      />
+                    ) : (
+                      <video
+                        ref="videoUpload"
+                        class={styles.uploadImg}
+                        poster={iconVideoDefault}
+                        style={{ backgroundColor: '#F8F8F8' }}
+                        src={item + '#t=1,4'}
+                      />
+                    )}
+                  </>
+                ))}
+              </div>
+            ) : (
+              <Icon
+                name={this.uploadIcon}
+                class={['van-uploader__upload']}
+                size="32"
+              />
+            )}
+          </Uploader>
+        )}
+
+        {this.$slots.default && this.$slots.default()}
+      </>
+    );
+  }
+});

+ 53 - 0
src/components/m-video/index.module.less

@@ -0,0 +1,53 @@
+.video-container {
+  position: relative;
+  width: 100%;
+  --plyr-color-main: var(--k-primary);
+
+  video {
+    width: 100%;
+    // object-fit: cover;
+  }
+
+  :global {
+    .video-back {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      color: #fff;
+      z-index: 99;
+      font-size: 24px;
+      width: 30px;
+      height: 30px;
+      background-color: rgba(0, 0, 0, 0.5);
+      border-radius: 50%;
+      padding: 4px 5px 4px 3px;
+    }
+
+    .plyr__poster {
+      background-size: cover;
+    }
+
+    .plyr__control--overlaid {
+      border: 1px solid #fff;
+      background-color: rgba(0, 0, 0, 0.2) !important;
+    }
+
+    .plyr--video .plyr__control:hover {
+      background-color: transparent !important;
+    }
+  }
+
+  .video {
+    position: relative;
+  }
+}
+
+.loadingVideo {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  background: rgba(0, 0, 0, 0.9);
+  z-index: 10;
+}

+ 217 - 0
src/components/m-video/index.tsx

@@ -0,0 +1,217 @@
+import { defineComponent, PropType } from 'vue';
+import styles from './index.module.less';
+import Plyr from 'plyr';
+import 'plyr/dist/plyr.css';
+import { Loading } from 'vant';
+import { browser } from '@/helpers/utils';
+export default defineComponent({
+  name: 'm-video',
+  props: {
+    setting: {
+      type: Object,
+      default: () => ({})
+    },
+    controls: Boolean,
+    height: String,
+    src: {
+      type: String,
+      default: ''
+    },
+    poster: {
+      type: String,
+      default: ''
+    },
+    styleValue: {
+      type: Object,
+      default: () => ({})
+    },
+    preload: {
+      type: String as PropType<'auto' | 'metadata' | 'none'>,
+      default: 'auto'
+    },
+    currentTime: {
+      type: Boolean,
+      default: true
+    },
+    playsinline: {
+      type: Boolean,
+      default: true
+    },
+    preLoading: {
+      type: Boolean,
+      default: true
+    }
+    // onPlay: {
+    //   type: Function,
+    //   default: () => {}
+    // }
+  },
+  emits: ['exitfullscreen', 'play', 'ready', 'enterfullscreen'],
+  data() {
+    return {
+      player: null as any,
+      loading: true // 首次进入加载中
+    };
+  },
+  mounted() {
+    this.loading = this.preLoading;
+    this._init();
+  },
+  methods: {
+    _init() {
+      // controls: [
+      //   'play-large' ,  // 中间的大播放按钮
+      //   'restart' ,  // 重新开始播放
+      //   'rewind' ,  // 按寻道时间倒带(默认 10 秒)
+      //   'play' ,  // 播放/暂停播放
+      //   'fast-forward' ,  // 快进查找时间(默认 10 秒)
+      //   'progress' ,  // 播放和缓冲的进度条和滑动条
+      //   'current-time' ,  // 播放的当前时间
+      //   ' duration' ,  // 媒体的完整持续时间
+      //   'mute' ,  // 切换静音
+      //   'volume', // 音量控制
+      //   'captions' ,  // 切换字幕
+      //   'settings' ,  // 设置菜单
+      //   'pip' ,  // 画中画(当前仅 Safari)
+      //   'airplay' ,  // Airplay(当前仅 Safari)
+      //   'download ' ,  // 显示一个下载按钮,其中包含指向当前源或您在选项中指定的自定义 URL 的链接
+      //   'fullscreen' ,  // 切换全屏
+      // ] ;
+      const controls = [
+        'play-large',
+        'play',
+        'progress',
+        'captions',
+        'fullscreen'
+      ];
+      // if (browser().isApp) {
+      //   controls.push('fullscreen');
+      // }
+      if (this.currentTime) {
+        controls.push('current-time');
+      }
+      const params: any = {
+        controls: controls,
+        ...this.setting,
+        invertTime: false
+      };
+
+      if (browser().iPhone) {
+        params.fullscreen = {
+          enabled: true,
+          fallback: 'force',
+          iosNative: true
+        };
+      }
+
+      this.player = new Plyr((this as any).$refs.video, params);
+
+      // fullscreen: {
+      //     enabled: true,
+      //     fallback: 'force',
+      //     iosNative: true
+      //   }
+      this.player.elements.container
+        ? (this.player.elements.container.style.height = this.height || '210px')
+        : null;
+
+      if (this.preload === 'none') {
+        this.loading = false;
+      }
+      this.player.on('loadedmetadata', () => {
+        this.loading = false;
+        this.domPlayVisibility(false);
+      });
+
+      this.player.on('loadeddata', () => {
+        this.$emit('ready', this.player);
+      });
+
+      this.player.on('play', () => {
+        this.$emit('play', this.player);
+      });
+
+      this.player.on('enterfullscreen', () => {
+        // console.log('fullscreen', this.player.elements);
+        // const fragment = document.createDocumentFragment();
+        // const i = document.createElement('i');
+        // i.id = 'fullscreen-back';
+        // i.className = 'van-icon van-icon-arrow-left video-back';
+        // i.addEventListener('click', () => {
+        //   this.player.fullscreen.exit();
+        // });
+        // console.log(document.getElementsByClassName('plyr'), i);
+        // fragment.appendChild(i);
+        // // const parentNode = document.getElementsByClassName('plyr')[0];
+        // // parentNode.insertBefore(fragment, parentNode.firstChild);
+        // this.player.elements.container.appendChild(fragment);
+
+        this.$emit('enterfullscreen');
+      });
+
+      this.player.on('exitfullscreen', () => {
+        console.log('exitfullscreen');
+        // const i = document.getElementById('fullscreen-back');
+        // i && i.remove();
+        this.$emit('exitfullscreen');
+      });
+    },
+    // 操作功能
+    domPlayVisibility(hide = true) {
+      const controls = document.querySelector('.plyr__controls');
+      const controls2 = document.querySelector('.plyr__control--overlaid');
+      if (hide) {
+        controls?.setAttribute('style', 'display:none');
+        controls2?.setAttribute('style', 'display:none');
+      } else {
+        controls?.removeAttribute('style');
+        setTimeout(() => {
+          controls2?.removeAttribute('style');
+        }, 200);
+      }
+    },
+    onStop() {
+      this.player.stop();
+    },
+    onExitScreen() {
+      this.player.fullscreen.active && this.player.fullscreen.exit();
+    },
+    onPlay() {
+      this.player?.play();
+    }
+  },
+  unmounted() {
+    this.player?.destroy();
+  },
+  render() {
+    return (
+      <div class={styles['video-container']}>
+        <video
+          ref="video"
+          class={styles['video']}
+          src={this.src}
+          playsinline={this.playsinline}
+          poster={this.poster}
+          preload={this.preload}
+          style={{ ...this.styleValue }}></video>
+        {/* </div> */}
+        {/* 加载视频使用 */}
+        {this.loading && (
+          <div
+            class={styles.loadingVideo}
+            style={{
+              height: this.height || '210px'
+            }}>
+            <Loading
+              size={36}
+              color="#FF8057"
+              vertical
+              style={{ height: '100%', justifyContent: 'center' }}>
+              加载中...
+            </Loading>
+          </div>
+        )}
+      </div>
+    );
+  }
+});

+ 0 - 0
src/helpers/constant.ts


+ 16 - 0
src/helpers/deep-clone.ts

@@ -0,0 +1,16 @@
+const deepClone = (obj: any) => {
+  if (obj === null) return null;
+  const clone = Object.assign({}, obj);
+  Object.keys(clone).forEach(
+    key =>
+      (clone[key] =
+        typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
+  );
+  if (Array.isArray(obj)) {
+    clone.length = obj.length;
+    return Array.from(clone);
+  }
+  return clone;
+};
+
+export default deepClone;

+ 116 - 0
src/helpers/native-message.ts

@@ -0,0 +1,116 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { browser, getRandomKey } from '@/helpers/utils';
+
+export interface IPostMessage {
+  api: string;
+  content?: any;
+}
+
+/**
+ * 劫持postMessage
+ */
+
+const originalPostMessage = window.postMessage;
+
+window.postMessage = (message: IPostMessage) => {
+  // console.log('通过劫持', message)
+  originalPostMessage(message, '*');
+};
+
+/**
+ *
+ * 目前已支持API
+ *
+ * openWebView
+ *
+ */
+
+type CallBack = (evt?: IPostMessage) => void;
+
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+const loop = () => {};
+
+const calls: { [key: string]: CallBack | CallBack[] } = {};
+
+const browserInfo = browser();
+
+if (browserInfo.isApp) {
+  window.addEventListener('message', evt => {
+    try {
+      console.log('app交互接受:', evt.data);
+      const data = evt.data
+        ? typeof evt.data === 'object'
+          ? evt.data
+          : JSON.parse(evt.data)
+        : {};
+      const uuid = data.content?.uuid || data.uuid;
+      console.log(uuid, data.content, 'uuid');
+      try {
+        if (data.content) {
+          data.content = JSON.parse(data.content);
+        }
+      } catch (error) {
+        //
+      }
+      if (data?.content?.uuid) {
+        // console.log('data', data)
+      }
+      if (!uuid) {
+        const keys = Object.keys(calls).filter(
+          key => key.indexOf(data.api) === 0
+        );
+        // console.log(keys, 'keys')
+        // console.log(data, 'data')
+        for (const key of keys) {
+          const callback = calls[key] || loop;
+          typeof callback === 'function' && callback(data);
+        }
+        return;
+      }
+      const callId = data.content?.uuid || data.uuid || data.api + data.uuid;
+      const callback = calls[callId] || loop;
+      // console.log(data, 'data')
+      typeof callback === 'function' && callback(data);
+    } catch (error) {
+      console.error('通信消息解析错误', error);
+    }
+  });
+}
+
+const instance: any =
+  (window as any).DAYA || (window as any).webkit?.messageHandlers?.DAYA;
+
+export const postMessage = (data: IPostMessage, callback?: CallBack) => {
+  if (browserInfo.isApp) {
+    const uuid = getRandomKey();
+    calls[uuid] = callback || loop;
+    data.content = data.content ? { ...data.content, uuid } : { uuid };
+    console.log('app交互发送:', data);
+    instance.postMessage(JSON.stringify(data));
+  }
+};
+
+export const listenerMessage = (api: string, callback: CallBack) => {
+  if (browserInfo.isApp) {
+    const uuid = api + getRandomKey();
+    calls[uuid] = callback || loop;
+  }
+};
+
+export const removeListenerMessage = (api: string, callback: CallBack) => {
+  if (browserInfo.isApp) {
+    const uuid = api;
+    if (Array.isArray(calls[uuid])) {
+      const indexOf = (calls[uuid] as CallBack[]).indexOf(callback);
+      (calls[uuid] as CallBack[]).splice(indexOf, 1);
+    }
+  }
+};
+
+export const promisefiyPostMessage = (
+  data: IPostMessage
+): Promise<IPostMessage | undefined> => {
+  return new Promise(resolve => {
+    postMessage(data, res => resolve(res));
+  });
+};

+ 112 - 0
src/helpers/request.ts

@@ -0,0 +1,112 @@
+import { extend } from 'umi-request';
+import cleanDeep from 'clean-deep';
+import { browser } from '@/helpers/utils';
+import { setLogout, setLoginError, state } from '@/state';
+import { postMessage } from './native-message';
+import { showLoadingToast, showToast, closeToast } from 'vant';
+
+export interface SearchInitParams {
+  rows?: string | number;
+  page?: string | number;
+}
+
+const request = extend({
+  // requestType: 'form',
+  hideLoading: true, // 默认都不显示加载
+  timeout: 20000,
+  timeoutMessage: '请求超时'
+});
+
+// 是否是初始化接口
+let initRequest = false;
+let toast: ReturnType<typeof setTimeout>;
+
+request.interceptors.request.use(
+  (url, options: any) => {
+    if (!options.hideLoading) {
+      clearTimeout(toast);
+      showLoadingToast({
+        message: '加载中...',
+        forbidClick: true,
+        duration: 0
+      });
+    }
+
+    initRequest = options.initRequest || false;
+    const Authorization = sessionStorage.getItem('Authorization') || '';
+    const authHeaders: any = {};
+    if (
+      Authorization &&
+      ![
+        '/api-auth/userlogin',
+        '/api-auth/smsLogin',
+        '/api-auth/open/sendSms'
+      ].includes(url)
+    ) {
+      authHeaders.Authorization = Authorization;
+    }
+
+    if (state?.user?.data?.schoolId) {
+      authHeaders.coopId = state?.user?.data.schoolId;
+    }
+    return {
+      url,
+      options: {
+        ...options,
+        params: cleanDeep(options.params),
+        data: cleanDeep(options.data),
+        headers: {
+          ...options.headers,
+          ...authHeaders
+        }
+      }
+    };
+  },
+  { global: false }
+);
+
+request.interceptors.response.use(
+  async res => {
+    toast = setTimeout(() => {
+      closeToast();
+    }, 100);
+    if (res.status > 299 || res.status < 200) {
+      clearTimeout(toast);
+      const msg = '服务器错误,状态码' + res.status;
+      showToast(msg);
+      throw new Error(msg);
+    }
+    const data = await res.clone().json();
+    // 999 为特殊code码
+    if (data.code !== 200 && data.errCode !== 0 && data.code !== 999) {
+      let msg = data.msg || data.message || '处理失败,请重试';
+      if (initRequest) {
+        if (data.code === 403 || data.code === 5000) {
+          setLogout();
+        } else {
+          setLoginError();
+        }
+      }
+      if (!(data.code === 403 || data.code === 5000)) {
+        clearTimeout(toast);
+        showToast(msg);
+      }
+      const browserInfo = browser();
+      if (data.code === 5000 || data.code === 403) {
+        msg += ' authentication ' + data.code;
+        if (browserInfo.isApp) {
+          postMessage({
+            api: 'login'
+          });
+        } else {
+          setLogout();
+        }
+      }
+      throw new Error(msg);
+    }
+    return res;
+  },
+  { global: false }
+);
+
+export default request;

+ 430 - 0
src/helpers/toolsValidate.ts

@@ -0,0 +1,430 @@
+/* eslint-disable no-useless-escape */
+/**
+ * 验证百分比(不可以小数)
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyNumberPercentage(val: string): string {
+  // 匹配空格
+  let v = val.replace(/(^\s*)|(\s*$)/g, '');
+  // 只能是数字和小数点,不能是其他输入
+  v = v.replace(/[^\d]/g, '');
+  // 不能以0开始
+  v = v.replace(/^0/g, '');
+  // 数字超过100,赋值成最大值100
+  v = v.replace(/^[1-9]\d\d{1,3}$/, '100');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 验证百分比(可以小数)
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyNumberPercentageFloat(val: string): string {
+  let v = verifyNumberIntegerAndFloat(val);
+  // 数字超过100,赋值成最大值100
+  v = v.replace(/^[1-9]\d\d{1,3}$/, '100');
+  // 超过100之后不给再输入值
+  v = v.replace(/^100\.$/, '100');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 小数或整数(不可以负数)
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyNumberIntegerAndFloat(val: string) {
+  // 匹配空格
+  let v = val.replace(/(^\s*)|(\s*$)/g, '');
+  // 只能是数字和小数点,不能是其他输入
+  v = v.replace(/[^\d.]/g, '');
+  // 以0开始只能输入一个
+  v = v.replace(/^0{2}$/g, '0');
+  // 保证第一位只能是数字,不能是点
+  v = v.replace(/^\./g, '');
+  // 小数只能出现1位
+  v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
+  // 小数点后面保留2位
+  v = v.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 正整数验证
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifiyNumberInteger(val: string) {
+  // 匹配空格
+  let v = val.replace(/(^\s*)|(\s*$)/g, '');
+  // 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12
+  v = v.replace(/[\.]*/g, '');
+  // 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323
+  v = v.replace(/(^0[\d]*)$/g, '0');
+  // 首位是0,只能出现一次
+  v = v.replace(/^0\d$/g, '0');
+  // 只匹配数字
+  v = v.replace(/[^\d]/g, '');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 检测正整数
+ * @param val 当前值字符串
+ * @returns 返回boolean
+ */
+export function checkNumberInteger(val: string) {
+  const rep = /[\.]/;
+  return !!rep.test(val);
+}
+
+/**
+ * 去掉中文及空格
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyCnAndSpace(val: string) {
+  // 匹配中文与空格
+  let v = val.replace(/[\u4e00-\u9fa5\s]+/g, '');
+  // 匹配空格
+  v = v.replace(/(^\s*)|(\s*$)/g, '');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 去掉英文及空格
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyEnAndSpace(val: string) {
+  // 匹配英文与空格
+  let v = val.replace(/[a-zA-Z]+/g, '');
+  // 匹配空格
+  v = v.replace(/(^\s*)|(\s*$)/g, '');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 禁止输入空格
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyAndSpace(val: string) {
+  // 匹配空格
+  const v = val.replace(/(^\s*)|(\s*$)/g, '');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 金额用 `,` 区分开
+ * @param val 当前值字符串
+ * @returns 返回处理后的字符串
+ */
+export function verifyNumberComma(val: string) {
+  // 调用小数或整数(不可以负数)方法
+  let v: any = verifyNumberIntegerAndFloat(val);
+  // 字符串转成数组
+  v = v.toString().split('.');
+  // \B 匹配非单词边界,两边都是单词字符或者两边都是非单词字符
+  v[0] = v[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+  // 数组转字符串
+  v = v.join('.');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 匹配文字变色(搜索时)
+ * @param val 当前值字符串
+ * @param text 要处理的字符串值
+ * @param color 搜索到时字体高亮颜色
+ * @returns 返回处理后的字符串
+ */
+export function verifyTextColor(val: string, text = '', color = 'red') {
+  // 返回内容,添加颜色
+  const v = text.replace(
+    new RegExp(val, 'gi'),
+    `<span style='color: ${color}'>${val}</span>`
+  );
+  // 返回结果
+  return v;
+}
+
+/**
+ * 数字转中文大写
+ * @param val 当前值字符串
+ * @param unit 默认:仟佰拾亿仟佰拾万仟佰拾元角分
+ * @returns 返回处理后的字符串
+ */
+export function verifyNumberCnUppercase(
+  val: any,
+  unit = '仟佰拾亿仟佰拾万仟佰拾元角分',
+  v = ''
+) {
+  // 当前内容字符串添加 2个0,为什么??
+  val += '00';
+  // 返回某个指定的字符串值在字符串中首次出现的位置,没有出现,则该方法返回 -1
+  const lookup = val.indexOf('.');
+  // substring:不包含结束下标内容,substr:包含结束下标内容
+  if (lookup >= 0) val = val.substring(0, lookup) + val.substr(lookup + 1, 2);
+  // 根据内容 val 的长度,截取返回对应大写
+  unit = unit.substr(unit.length - val.length);
+  // 循环截取拼接大写
+  for (let i = 0; i < val.length; i++) {
+    v += '零壹贰叁肆伍陆柒捌玖'.substr(val.substr(i, 1), 1) + unit.substr(i, 1);
+  }
+  // 正则处理
+  v = v
+    .replace(/零角零分$/, '整')
+    .replace(/零[仟佰拾]/g, '零')
+    .replace(/零{2,}/g, '零')
+    .replace(/零([亿|万])/g, '$1')
+    .replace(/零+元/, '元')
+    .replace(/亿零{0,3}万/, '亿')
+    .replace(/^元/, '零元');
+  // 返回结果
+  return v;
+}
+
+/**
+ * 手机号码
+ * @param val 当前值字符串
+ * @returns 返回 true: 手机号码正确
+ */
+export function verifyPhone(val: string) {
+  // false: 手机号码不正确
+  if (
+    !/^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/.test(
+      val
+    )
+  )
+    return false;
+  // true: 手机号码正确
+  else return true;
+}
+
+/**
+ * 国内电话号码
+ * @param val 当前值字符串
+ * @returns 返回 true: 国内电话号码正确
+ */
+export function verifyTelPhone(val: string) {
+  // false: 国内电话号码不正确
+  if (!/\d{3}-\d{8}|\d{4}-\d{7}/.test(val)) return false;
+  // true: 国内电话号码正确
+  else return true;
+}
+
+/**
+ * 登录账号 (字母开头,允许5-16字节,允许字母数字下划线)
+ * @param val 当前值字符串
+ * @returns 返回 true: 登录账号正确
+ */
+export function verifyAccount(val: string) {
+  // false: 登录账号不正确
+  if (!/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/.test(val)) return false;
+  // true: 登录账号正确
+  else return true;
+}
+
+/**
+ * 密码 (以字母开头,长度在6~16之间,只能包含字母、数字和下划线)
+ * @param val 当前值字符串
+ * @returns 返回 true: 密码正确
+ */
+export function verifyPassword(val: string) {
+  // false: 密码不正确
+  if (!/^[a-zA-Z]\w{5,15}$/.test(val)) return false;
+  // true: 密码正确
+  else return true;
+}
+
+/**
+ * 强密码 (字母+数字+特殊字符,长度在6-16之间)
+ * @param val 当前值字符串
+ * @returns 返回 true: 强密码正确
+ */
+export function verifyPasswordPowerful(val: string) {
+  // false: 强密码不正确
+  if (
+    !/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(
+      val
+    )
+  )
+    return false;
+  // true: 强密码正确
+  else return true;
+}
+
+/**
+ * 密码强度
+ * @param val 当前值字符串
+ * @description 弱:纯数字,纯字母,纯特殊字符
+ * @description 中:字母+数字,字母+特殊字符,数字+特殊字符
+ * @description 强:字母+数字+特殊字符
+ * @returns 返回处理后的字符串:弱、中、强
+ */
+export function verifyPasswordStrength(val: string) {
+  let v = '';
+  // 弱:纯数字,纯字母,纯特殊字符
+  if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.*]+){6,16}$/.test(val)) v = '弱';
+  // 中:字母+数字,字母+特殊字符,数字+特殊字符
+  if (
+    /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(
+      val
+    )
+  )
+    v = '中';
+  // 强:字母+数字+特殊字符
+  if (
+    /^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(
+      val
+    )
+  )
+    v = '强';
+  // 返回结果
+  return v;
+}
+
+/**
+ * IP地址
+ * @param val 当前值字符串
+ * @returns 返回 true: IP地址正确
+ */
+export function verifyIPAddress(val: string) {
+  // false: IP地址不正确
+  if (
+    !/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/.test(
+      val
+    )
+  )
+    return false;
+  // true: IP地址正确
+  else return true;
+}
+
+/**
+ * 邮箱
+ * @param val 当前值字符串
+ * @returns 返回 true: 邮箱正确
+ */
+export function verifyEmail(val: string) {
+  // false: 邮箱不正确
+  const reg =
+    /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+  if (!reg.test(val)) return false;
+  // true: 邮箱正确
+  else return true;
+}
+
+/**
+ * 身份证
+ * @param val 当前值字符串
+ * @returns 返回 true: 身份证正确
+ */
+export function verifyIdCard(val: string) {
+  // false: 身份证不正确
+  if (
+    !/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(
+      val
+    )
+  )
+    return false;
+  // true: 身份证正确
+  else return true;
+}
+
+/**
+ * 姓名
+ * @param val 当前值字符串
+ * @returns 返回 true: 姓名正确
+ */
+export function verifyFullName(val: string) {
+  // false: 姓名不正确
+  if (!/^[\u4e00-\u9fa5]{1,6}(·[\u4e00-\u9fa5]{1,6}){0,2}$/.test(val))
+    return false;
+  // true: 姓名正确
+  else return true;
+}
+
+/**
+ * 邮政编码
+ * @param val 当前值字符串
+ * @returns 返回 true: 邮政编码正确
+ */
+export function verifyPostalCode(val: string) {
+  // false: 邮政编码不正确
+  if (!/^[1-9][0-9]{5}$/.test(val)) return false;
+  // true: 邮政编码正确
+  else return true;
+}
+
+/**
+ * url 处理
+ * @param val 当前值字符串
+ * @returns 返回 true: url 正确
+ */
+export function verifyUrl(val: string) {
+  // false: url不正确
+  // !/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
+  //   val
+  // )
+  if (
+    !/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?$/.test(
+      val
+    )
+  )
+    return false;
+  // true: url正确
+  else return true;
+}
+
+/**
+ * 车牌号
+ * @param val 当前值字符串
+ * @returns 返回 true:车牌号正确
+ */
+export function verifyCarNum(val: string) {
+  // false: 车牌号不正确
+  if (
+    !/^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test(
+      val
+    )
+  )
+    return false;
+  // true:车牌号正确
+  else return true;
+}
+
+/**
+ * 检测链接类型
+ * @param fileValue 文件链接
+ * @param type 类型 image | video
+ * @returns 返回 true: 满足对应类型
+ */
+export const checkFile = (fileValue: string, type: string) => {
+  const index = fileValue.indexOf('.'); //(考虑严谨用lastIndexOf(".")得到)得到"."在第几位
+  const fileValueSuffix = fileValue.substring(index); //截断"."之前的,得到后缀
+  if (type == 'video') {
+    if (!/(.*)\.(mp4|rmvb|avi|ts)$/.test(fileValueSuffix)) {
+      //根据后缀,判断是否符合视频格式
+      return false;
+    }
+  }
+  if (type == 'image') {
+    if (!/(.*)\.(gif|jpg|jpeg|png|GIF|JPG|PNG|svg)$/.test(fileValueSuffix)) {
+      //根据后缀,判断是否符合图片格式
+      return false;
+    }
+  }
+  return true;
+};

+ 134 - 0
src/helpers/utils.ts

@@ -0,0 +1,134 @@
+export const browser = () => {
+  const u = navigator.userAgent;
+  return {
+    trident: u.indexOf('Trident') > -1, //IE内核
+    presto: u.indexOf('Presto') > -1, //opera内核
+    webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
+    gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
+    mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
+    ios: !!u.match(/Mac OS X/), //ios终端
+    // ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
+    android: u.indexOf('DAYAAPPA') > -1 || u.indexOf('Adr') > -1, //android终端
+    iPhone: u.indexOf('DAYAAPPI') > -1, //是否为iPhone或者QQHD浏览器
+    isApp:
+      u.indexOf('DAYAAPPI') > -1 ||
+      u.indexOf('DAYAAPPA') > -1 ||
+      u.indexOf('Adr') > -1,
+    iPad: u.indexOf('iPad') > -1, //是否iPad
+    webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部
+    weixin: u.indexOf('MicroMessenger') > -1, //是否微信 (2015-01-22新增)
+    alipay: u.indexOf('AlipayClient') > -1, //是否支付宝
+    huawei: !!u.match(/huawei/i) || !!u.match(/honor/i),
+    xiaomi: !!u.match(/mi\s/i) || !!u.match(/redmi/i) || !!u.match(/mix/i)
+  };
+};
+
+export const getRandomKey = () => {
+  const key = '' + new Date().getTime() + Math.floor(Math.random() * 1000000);
+  return key;
+};
+
+/**
+ * 删除token
+ */
+export const removeAuth = () => {
+  sessionStorage.removeItem('Authorization');
+};
+
+/**
+ * 设置token
+ * @param token
+ * @returns {void}
+ */
+export const setAuth = (token: any) => {
+  sessionStorage.setItem('Authorization', token);
+};
+
+/**
+ * 获取token
+ */
+export const getAuth = () => {
+  sessionStorage.getItem('Authorization');
+};
+
+export function checkPhone(phone: string) {
+  const phoneRule =
+    /^((13[0-9])|(14(0|[5-7]|9))|(15([0-3]|[5-9]))|(16(2|[5-7]))|(17[0-8])|(18[0-9])|(19([0-3]|[5-9])))\d{8}$/;
+  return phoneRule.test(phone);
+}
+
+/**
+ * @description 格式化日期控件显示内容
+ * @param type
+ * @param option
+ * @returns OBJECT
+ */
+export const formatterDatePicker = (type: any, option: any) => {
+  if (type === 'year') {
+    option.text += '年';
+  }
+  if (type === 'month') {
+    option.text += '月';
+  }
+  if (type === 'day') {
+    option.text += '日';
+  }
+  return option;
+};
+
+/**
+ * 数字转成汉字
+ * @params num === 要转换的数字
+ * @return 汉字
+ * */
+export const toChinesNum = (num: any) => {
+  const changeNum = [
+    '零',
+    '一',
+    '二',
+    '三',
+    '四',
+    '五',
+    '六',
+    '七',
+    '八',
+    '九'
+  ];
+  const unit = ['', '十', '百', '千', '万'];
+  num = parseInt(num);
+  const getWan = (temp: any) => {
+    const strArr = temp.toString().split('').reverse();
+    let newNum = '';
+    const newArr: string[] = [];
+    strArr.forEach((item: any, index: any) => {
+      newArr.unshift(
+        item === '0' ? changeNum[item] : changeNum[item] + unit[index]
+      );
+    });
+    const numArr: number[] = [];
+    newArr.forEach((m, n) => {
+      if (m !== '零') numArr.push(n);
+    });
+    if (newArr.length > 1) {
+      newArr.forEach((m, n) => {
+        if (newArr[newArr.length - 1] === '零') {
+          if (n <= numArr[numArr.length - 1]) {
+            newNum += m;
+          }
+        } else {
+          newNum += m;
+        }
+      });
+    } else {
+      newNum = newArr[0];
+    }
+
+    return newNum;
+  };
+  const overWan = Math.floor(num / 10000);
+  let noWan: any = num % 10000;
+  if (noWan.toString().length < 4) {
+    noWan = '0' + noWan;
+  }
+  return overWan ? getWan(overWan) + '万' + getWan(noWan) : getWan(num);
+};

+ 42 - 0
src/main.ts

@@ -0,0 +1,42 @@
+import { createApp } from 'vue';
+
+import App from './App';
+import router from './router/index';
+import dayjs from 'dayjs';
+import 'dayjs/locale/zh-cn';
+import 'vant/lib/index.css';
+import './component-ui/index.less';
+import './styles/index.less';
+import { promisefiyPostMessage, postMessage } from './helpers/native-message';
+import { state } from './state';
+import { setAuth } from './helpers/utils';
+
+// 获取token
+promisefiyPostMessage({ api: 'getToken' }).then((res: any) => {
+  console.log(res, 'res');
+  const content = res.content;
+  if (content?.accessToken) {
+    setAuth(content.tokenType + ' ' + content.accessToken);
+  }
+});
+
+// 导航栏高度
+postMessage({ api: 'getNavHeight' }, (res: any) => {
+  const { content } = res as any;
+  const dpi = content.dpi || 2;
+  if (content.navHeight) {
+    const navHeight = content.navHeight / dpi;
+    console.log(navHeight, 'navHeight');
+    state.navBarHeight = navHeight;
+  }
+});
+
+// import Vconsole from 'vconsole';
+// const vconsole = new Vconsole();
+
+const app = createApp(App);
+
+dayjs.locale('zh-ch');
+
+app.use(router);
+app.mount('#app');

+ 50 - 0
src/router/index.ts

@@ -0,0 +1,50 @@
+import { browser } from '@/helpers/utils';
+import { showDialog } from 'vant';
+import { createRouter, createWebHashHistory, Router } from 'vue-router';
+import { postMessage } from '@/helpers/native-message';
+import routes from './routes-common';
+
+const router: Router = createRouter({
+  history: createWebHashHistory(),
+  routes,
+  scrollBehavior(to) {
+    if (to.hash) {
+      return {
+        el: to.hash,
+        behavior: 'smooth'
+      };
+    }
+  }
+});
+
+router.beforeEach((to, from, next) => {
+  document.title = (to.meta.title || '学校端') as any;
+  next();
+});
+
+let isOpen = false;
+router.onError(error => {
+  if (error instanceof Error) {
+    const isChunkLoadFailed = error.name.indexOf('chunk');
+    const targetPath = router.currentRoute.value.fullPath;
+    console.log(error);
+    if (isChunkLoadFailed && !isOpen) {
+      isOpen = true;
+      showDialog({
+        title: '更新提示',
+        message: 'APP有更新请点击确定刷新页面?',
+        confirmButtonColor: 'var(--van-primary)'
+      }).then(() => {
+        // on close
+        if (browser().isApp) {
+          postMessage({ api: 'back' });
+        } else {
+          location.hash = targetPath;
+          window.location.reload();
+        }
+      });
+    }
+  }
+});
+
+export default router;

+ 17 - 0
src/router/router-root.ts

@@ -0,0 +1,17 @@
+// 不需要登录的路由
+export default [
+  {
+    path: '/courseware-play',
+    component: () => import('@/views/courseware-play/index'),
+    meta: {
+      title: '课件播放'
+    }
+  },
+  {
+    path: '/:pathMatch(.*)*',
+    component: () => import('@/views/404'),
+    meta: {
+      title: '404'
+    }
+  }
+];

+ 24 - 0
src/router/routes-common.ts

@@ -0,0 +1,24 @@
+import Auth from '@/views/layout/auth';
+import rootRouter from './router-root';
+
+type metaType = {
+  isRegister: boolean;
+};
+
+export default [
+  {
+    path: '/',
+    component: Auth,
+    children: [
+      {
+        path: '/login',
+        name: 'login',
+        component: () => import('@/views/layout/login'),
+        meta: {
+          isRegister: false
+        } as metaType
+      }
+    ]
+  },
+  ...rootRouter
+];

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

@@ -0,0 +1,5 @@
+declare module '*.vue' {
+  import { DefineComponent } from 'vue';
+  const component: DefineComponent<{}, {}, any>;
+  export default component;
+}

+ 56 - 0
src/state.ts

@@ -0,0 +1,56 @@
+import { reactive } from 'vue';
+import { browser } from './helpers/utils';
+import { postMessage } from './helpers/native-message';
+
+type status = 'init' | 'login' | 'logout' | 'error';
+
+export const state = reactive({
+  user: {
+    status: 'init' as status,
+    data: {} as any
+  },
+  navBarHeight: 0, // 状态栏高度
+  ossUploadUrl: 'https://ks3-cn-beijing.ksyuncs.com/'
+});
+
+// 预览上传到oss的地址
+export const getOssUploadUrl = (bucket: string) => {
+  const tmpBucket = bucket || 'gym';
+  return `https://${tmpBucket}.ks3-cn-beijing.ksyuncs.com/`;
+};
+
+export const setLoginInit = () => {
+  state.user.status = 'init';
+  state.user.data = null;
+};
+
+export const setLogin = (data: any) => {
+  state.user.status = 'login';
+  state.user.data = data;
+};
+
+export const setLogout = () => {
+  state.user.status = 'logout';
+  state.user.data = null;
+};
+
+export const setLoginError = () => {
+  state.user.status = 'error';
+  state.user.data = null;
+};
+
+// 用于处理跳转地址,如果是在app内,则打开一个新的webview, 否则跳转连接
+export const openDefaultWebView = (url?: string, callBack?: any) => {
+  if (browser().isApp) {
+    postMessage({
+      api: 'openWebView',
+      content: {
+        url,
+        orientation: 1,
+        isHideTitle: false
+      }
+    });
+  } else {
+    callBack && callBack();
+  }
+};

+ 173 - 0
src/styles/index.less

@@ -0,0 +1,173 @@
+:root:root {
+  --k-primary: #01c1b5; // 主题色
+  --k-font-primary: #00b2a7; // 字体色
+  --van-pull-refresh-head-height: 55px;
+
+  --van-skeleton-paragraph-background: #ECEEF3;
+
+  --van-skeleton-avatar-background: #ECEEF3;
+}
+
+// 默认输入框光标颜色
+input,
+textarea {
+  caret-color: var(--k-font-primary) !important;
+}
+
+.van-skeleton {
+  padding: 0;
+}
+
+* {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  box-sizing: border-box;
+}
+
+#app {
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  color: #333;
+  min-height: 100vh;
+}
+
+body {
+  background-color: #f8f9fc;
+  user-select: none;
+}
+
+.van-cell {
+  padding: 12px;
+}
+
+// tab 选项卡样式
+
+.van-picker .van-picker-column__item--selected {
+  color: var(--k-font-primary);
+}
+
+// 下拉框样式重置
+.van-dropdown-menu__bar {
+  box-shadow: none;
+  --van-dropdown-menu-title-font-size: 14px;
+  --van-button-normal-font-size: 16px;
+  --van-dropdown-menu-height: 44px;
+}
+
+.van-dropdown-item {
+  // 在某些浏览器上面会显示一条线
+  margin-top: -1px;
+}
+
+.van-dropdown-item__content {
+  border-radius: 0px 0px 12px 12px;
+
+  .van-dropdown-item__option {
+    margin: 0 13px;
+    height: 44px;
+    border-radius: 8px;
+    width: auto;
+    ;
+
+    &:first-child {
+      margin-top: 12px;
+    }
+
+    &:last-child {
+      margin-bottom: 12px;
+    }
+
+    &:after {
+      border: none;
+    }
+
+    .van-cell__title {
+      white-space: nowrap;
+      width: 100%;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      font-size: 16px;
+      color: var(--k-gray-4);
+      text-align: center;
+    }
+
+    .van-cell__value {
+      display: none;
+    }
+  }
+
+
+
+  .van-dropdown-item__option--active {
+    background: #F6F6F6;
+
+    .van-cell__title {
+      font-weight: 600;
+      color: var(--k-font-primary);
+    }
+  }
+}
+
+// 固定底部按钮样式
+.btnGroupFixed {
+  padding: 0 25px;
+  padding-bottom: calc(20px + constant(safe-area-inset-bottom));
+  padding-bottom: calc(20px + env(safe-area-inset-bottom));
+}
+
+
+.btnGroupPopup {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 18px 13px;
+
+  .van-button {
+    font-weight: 400;
+    width: 48%;
+    font-size: 16px;
+  }
+}
+
+.myClassM2 {
+  .amap-marker-label {
+    background: #FF5A56;
+  }
+}
+
+// 地图样式
+.amap-marker-label {
+  // border: 0;
+  background: #00B2A7;
+  border: 0;
+  color: #fff;
+  line-height: 18px;
+  font-size: 12px;
+  padding: 2px 4px;
+  border-radius: 4px;
+
+}
+
+// 自定义动画基类
+.popup-custom {
+  transition: all 0.25s;
+  background: transparent;
+  overflow: initial;
+}
+
+.popup-custom.van-scale {
+  transform-origin: center -25%;
+}
+
+/* 缩放动画 */
+.van-scale-enter-from,
+.van-scale-leave-to {
+  opacity: 0;
+  transform: scale(0.3);
+}
+
+.van-scale-enter-active,
+.van-scale-leave-active {
+  transition: all 0.25s;
+}

+ 0 - 0
src/views/404/index.module.less


+ 33 - 0
src/views/404/index.tsx

@@ -0,0 +1,33 @@
+import MEmpty from '@/components/m-empty';
+import MHeader from '@/components/m-header';
+import { browser } from '@/helpers/utils';
+import { defineComponent } from 'vue';
+import { useRouter } from 'vue-router';
+
+export default defineComponent({
+  name: 'page-404',
+  setup() {
+    const router = useRouter();
+    return () => (
+      <>
+        <MHeader />
+        <MEmpty
+          style={{
+            'min-height': 'calc(100vh - var(--van-nav-bar-height))',
+            paddingTop: '0 !important'
+          }}
+          showButton
+          description="页面找不到了~"
+          image="404"
+          onClick={() => {
+            if (browser().isApp) {
+              postMessage({ api: 'back' });
+            } else {
+              router.back();
+            }
+          }}
+        />
+      </>
+    );
+  }
+});

+ 8 - 0
src/views/courseware-play/index.tsx

@@ -0,0 +1,8 @@
+import { defineComponent } from "vue";
+
+export default defineComponent({
+    name: 'CoursewarePlay',
+    setup() {
+        return () => <div></div>
+    }
+})

+ 32 - 0
src/views/layout/auth.module.less

@@ -0,0 +1,32 @@
+.error {
+  background-color: #fff;
+  display: flex;
+  // padding-top: 20px;
+  flex-direction: column;
+  min-height: calc(100vh);
+  align-items: center;
+  justify-content: center;
+  .info {
+    display: flex;
+    align-items: center;
+    margin-bottom: 30px;
+
+    span {
+      display: inline-block;
+      margin-left: 10px;
+      color: #58727e;
+      font-size: 18px;
+    }
+  }
+
+  :global {
+    .o-result-container,
+    .van-empty {
+      padding-top: 0;
+    }
+
+    .van-button {
+      width: 50%;
+    }
+  }
+}

+ 112 - 0
src/views/layout/auth.tsx

@@ -0,0 +1,112 @@
+import { defineComponent } from 'vue';
+import styles from './auth.module.less';
+import { state, setLogin, setLogout, setLoginError } from '@/state';
+import { browser, setAuth } from '@/helpers/utils';
+import { postMessage } from '@/helpers/native-message';
+import { RouterView } from 'vue-router';
+import request from '@/helpers/request';
+import MHeader from '@/components/m-header';
+import MEmpty from '@/components/m-empty';
+
+export default defineComponent({
+  name: 'Auth-loayout',
+  data() {
+    return {
+      loading: false as boolean
+    };
+  },
+  computed: {
+    isExternal() {
+      // 该路由在外部连接打开是否需要登录
+      // 只判断是否在学员端打开
+      return this.$route.meta.isExternal || false;
+    },
+    isNeedView() {
+      return (
+        state.user.status === 'login' ||
+        this.$route.path === '/login' ||
+        (this as any).isExternal
+      );
+    }
+  },
+  mounted() {
+    !this.isExternal && this.setAuth();
+  },
+  methods: {
+    async setAuth() {
+      const { query } = this.$route;
+      const token = query.userInfo || query.Authorization;
+
+      if (token) {
+        setAuth(token);
+      }
+      if (this.loading) {
+        return;
+      }
+      if (state.user.status === 'init' || state.user.status === 'error') {
+        this.loading = true;
+        try {
+          const res = await request.get('/api-web/schoolStaff/queryUserInfo', {
+            initRequest: true, // 初始化接口
+            requestType: 'form',
+            hideLoading: true
+          });
+          setLogin(res.data);
+        } catch (e: any) {
+          const message = e.message;
+          if (
+            message.indexOf('5000') === -1 &&
+            message.indexOf('authentication') === -1
+          ) {
+            setLoginError();
+          } else {
+            setLogout();
+          }
+        }
+        this.loading = false;
+      }
+      if (state.user.status === 'logout') {
+        if (browser().isApp) {
+          postMessage({ api: 'login' });
+        } else {
+          try {
+            const route = this.$route;
+            const query = {
+              returnUrl: this.$route.path,
+              ...this.$route.query
+            } as any;
+            if (route.meta.isRegister) {
+              query.isRegister = route.meta.isRegister;
+            }
+            this.$router.replace({
+              path: '/login',
+              query: query
+            });
+          } catch (error) {
+            //
+          }
+        }
+      }
+    }
+  },
+  render() {
+    return (
+      <>
+        {state.user.status === 'error' ? (
+          <div class={styles.error}>
+            <MHeader />
+            <MEmpty
+              image="network"
+              description="加载失败,请稍后重试"
+              buttonText="重新加载"
+              showButton
+              onClick={this.setAuth}
+            />
+          </div>
+        ) : this.isNeedView ? (
+          <RouterView></RouterView>
+        ) : null}
+      </>
+    );
+  }
+});

BIN=BIN
src/views/layout/images/bottom_manage_bg.png


BIN=BIN
src/views/layout/images/bottom_student_bg.png


BIN=BIN
src/views/layout/images/bottom_teacher_bg.png


BIN=BIN
src/views/layout/images/top_bg.png


+ 84 - 0
src/views/layout/login.module.less

@@ -0,0 +1,84 @@
+.login {
+  min-height: 100vh;
+  padding: 0 48px;
+  background: linear-gradient(to bottom, #01c1b5, #1bcbbf);
+
+  .codeText {
+    color: #fff;
+  }
+
+  .logo {
+    display: table;
+    padding-top: 100px;
+    padding-bottom: 90px;
+    width: 160px;
+    height: 45px;
+    margin: 0 auto;
+    img {
+      width: inherit;
+      height: inherit;
+    }
+  }
+  .container {
+    background-color: transparent;
+  }
+
+  .input-group {
+    position: relative;
+    border-radius: 50px;
+    border: 2px solid #fff;
+    margin-bottom: 20px;
+    padding-left: 30px;
+    padding-right: 30px;
+    display: flex;
+    align-items: center;
+    background: transparent;
+    input {
+      flex: 1;
+      font-size: 14px;
+      color: #fff;
+
+      background: transparent;
+      border: none;
+      &::placeholder {
+        color: #fff;
+      }
+    }
+    .code-text {
+      position: absolute;
+      right: 0;
+      flex: 1;
+      display: block;
+      width: 94px;
+      text-align: center;
+
+      font-size: 14px;
+      color: #fff;
+      line-height: 30px;
+      height: 30px;
+    }
+
+    :global {
+      .van-field__button {
+        border-left: 2px solid #fff;
+        margin-left: 12px;
+        margin-right: -18px;
+      }
+    }
+  }
+
+  .login-change {
+    padding-top: 8px;
+    font-size: 14px;
+    color: #fff;
+    float: right;
+    cursor: pointer;
+  }
+
+  :global {
+    .van-button--disabled {
+      opacity: 1;
+      color: rgba(0, 0, 0, 0.25);
+    }
+  }
+}

+ 206 - 0
src/views/layout/login.tsx

@@ -0,0 +1,206 @@
+import { defineComponent } from 'vue';
+import { CellGroup, Field, Button, CountDown, showToast } from 'vant';
+import ImgCode from '@/components/m-img-code';
+import request from '@/helpers/request';
+import { setLogin, state } from '@/state';
+import { checkPhone, removeAuth, setAuth } from '@/helpers/utils';
+import styles from './login.module.less';
+import logo from '@/common/images/logo.png';
+
+type loginType = 'PWD' | 'SMS';
+export default defineComponent({
+  name: 'layout-login',
+  data() {
+    return {
+      loginType: 'SMS' as loginType,
+      username: '',
+      password: '',
+      smsCode: '',
+      countDownStatus: true, // 是否发送验证码
+      countDownTime: 1000 * 120, // 倒计时时间
+      // countDownRef: null as any, // 倒计时实例
+      imgCodeStatus: false
+    };
+  },
+  computed: {
+    codeDisable() {
+      let status = true;
+      if (this.loginType === 'PWD') {
+        this.username && this.password && (status = false);
+      } else {
+        this.username && this.smsCode && (status = false);
+      }
+      return status;
+    }
+  },
+  mounted() {
+    removeAuth();
+    this.directNext();
+  },
+  methods: {
+    directNext() {
+      if (state.user.status === 'login' || state.user.status === 'error') {
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
+        const { returnUrl, isRegister, ...rest } = this.$route.query;
+        this.$router.replace({
+          path: returnUrl as any,
+          query: {
+            ...rest
+          }
+        });
+      }
+    },
+    async onLogin() {
+      try {
+        // let res: any
+        const forms: any = {
+          phone: this.username,
+          clientId: 'EDUCATION',
+          clientSecret: 'EDUCATION'
+        };
+
+        if (this.loginType === 'PWD') {
+          forms.password = this.password;
+          forms.grant_type = 'password';
+          const { data } = await request.post('/api-auth/usernameLogin', {
+            requestType: 'form',
+            data: {
+              ...forms
+            }
+          });
+          setAuth(
+            data.authentication.token_type +
+              ' ' +
+              data.authentication.access_token
+          );
+        } else {
+          forms.smsCode = this.smsCode;
+          const { data } = await request.post('/api-auth/smsLogin', {
+            requestType: 'form',
+            data: {
+              ...forms
+            }
+          });
+          setAuth(
+            data.authentication.token_type +
+              ' ' +
+              data.authentication.access_token
+          );
+        }
+
+        const userCash = await request.get(
+          '/api-web/schoolStaff/queryUserInfo',
+          {
+            initRequest: true // 初始化接口
+          }
+        );
+        setLogin(userCash.data);
+
+        this.directNext();
+      } catch {
+        //
+      }
+    },
+    async onSendCode() {
+      // 发送验证码
+      if (!checkPhone(this.username)) {
+        return showToast('请输入正确的手机号码');
+      }
+      this.imgCodeStatus = true;
+    },
+    onCodeSend() {
+      this.countDownStatus = false;
+      this.$nextTick(() => {
+        (this.$refs.countDownRef as any).start();
+      });
+    },
+    onFinished() {
+      this.countDownStatus = true;
+      (this.$refs.countDownRef as any).reset();
+    },
+    onChange() {
+      if (this.loginType === 'PWD') {
+        this.loginType = 'SMS';
+      } else if (this.loginType === 'SMS') {
+        this.loginType = 'PWD';
+      }
+    }
+  },
+  render() {
+    return (
+      <div class={[styles.login]}>
+        <div class={styles.logo}>
+          <img src={logo} />
+        </div>
+        <CellGroup class={styles.container} border={false}>
+          <Field
+            v-model={this.username}
+            name="手机号"
+            placeholder="请输入您的手机号"
+            type="tel"
+            class={styles['input-group']}
+            maxlength={11}
+          />
+
+          {this.loginType === 'PWD' ? (
+            <Field
+              v-model={this.password}
+              type="password"
+              name="密码"
+              class={styles['input-group']}
+              placeholder="请输入密码"
+            />
+          ) : (
+            <Field
+              v-model={this.smsCode}
+              name="验证码"
+              placeholder="请输入验证码"
+              type="tel"
+              class={styles['input-group']}
+              maxlength={6}
+              v-slots={{
+                button: () =>
+                  this.countDownStatus ? (
+                    <span class={styles.codeText} onClick={this.onSendCode}>
+                      获取验证码
+                    </span>
+                  ) : (
+                    <CountDown
+                      ref="countDownRef"
+                      auto-start={false}
+                      time={this.countDownTime}
+                      onFinish={this.onFinished}
+                      format="ss秒"
+                    />
+                  )
+              }}
+            />
+          )}
+        </CellGroup>
+        <div class={styles.margin34}>
+          <Button
+            round
+            block
+            disabled={this.codeDisable}
+            onClick={this.onLogin}>
+            提交
+          </Button>
+          <span class={styles['login-change']} onClick={this.onChange}>
+            {this.loginType === 'PWD' ? '验证码登录' : '密码登录'}
+          </span>
+        </div>
+
+        {this.imgCodeStatus ? (
+          <ImgCode
+            v-model:value={this.imgCodeStatus}
+            phone={this.username}
+            onClose={() => {
+              this.imgCodeStatus = false;
+            }}
+            onSendCode={this.onCodeSend}
+          />
+        ) : null}
+      </div>
+    );
+  }
+});

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

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

+ 24 - 0
templates/component/index.hbs

@@ -0,0 +1,24 @@
+{{#if template}}
+<template>
+  <h1>{{ name }}</h1>
+</template>
+{{/if}}
+
+{{#if script}}
+<script lang="ts">
+import { defineComponent } from 'vue';
+export default defineComponent({
+  name: '{{ properCase name }}',
+  props: {},
+  setup: () => {
+    console.log('{{ properCase name }}');
+  }
+});
+</script>
+{{/if}}
+
+{{#if style}}
+<style scoped lang="scss">
+
+</style>
+{{/if}}

+ 61 - 0
templates/component/prompt.js

@@ -0,0 +1,61 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const { notEmpty } = require('../utils');
+
+module.exports = {
+  description: 'generate Vue3 component',
+  prompts: [
+    {
+      type: 'input',
+      name: 'name',
+      message: 'component name please',
+      validate: notEmpty('name')
+    },
+    {
+      type: 'checkbox',
+      name: 'blocks',
+      message: 'Blocks:',
+      choices: [
+        {
+          name: '<template>',
+          value: 'template',
+          checked: true
+        },
+        {
+          name: '<script>',
+          value: 'script',
+          checked: true
+        },
+        {
+          name: 'style',
+          value: 'style',
+          checked: true
+        }
+      ],
+      validate(value) {
+        if (
+          value.indexOf('script') === -1 &&
+          value.indexOf('template') === -1
+        ) {
+          return 'Components require at least a script or template tag.';
+        }
+        return true;
+      }
+    }
+  ],
+  actions: data => {
+    const name = '{{properCase name}}';
+    return [
+      {
+        type: 'add',
+        path: `src/components/${name}/${name}.vue`,
+        templateFile: 'templates/component/index.hbs',
+        data: {
+          name: name,
+          template: data.blocks.includes('template'),
+          script: data.blocks.includes('script'),
+          style: data.blocks.includes('style')
+        }
+      }
+    ];
+  }
+};

+ 9 - 0
templates/utils.js

@@ -0,0 +1,9 @@
+exports.notEmpty = name => {
+  return v => {
+    if (!v || v.trim === '') {
+      return `${name} is required`;
+    } else {
+      return true;
+    }
+  };
+};

+ 25 - 0
tsconfig.json

@@ -0,0 +1,25 @@
+{
+  "compilerOptions": {
+    "baseUrl": "./",
+    "target": "esnext",
+    "module": "esnext",
+    "moduleResolution": "node",
+    "strict": true,
+    "skipLibCheck": true,
+    "jsx": "preserve",
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    "esModuleInterop": true,
+    "lib": ["esnext", "dom"],
+    "types": ["vite/client", "node"],
+    "paths": {
+      "@/*": ["src/*"],
+      "@common/*": ["src/common/*"],
+      "@components/*": ["src/components/*"],
+      "@store/*": ["src/store/*"],
+      "@views/*": ["src/views/*"]
+    }
+  },
+  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
+  "exclude": ["node_modules", "dist"]
+}

+ 10 - 0
tsconfig.node.json

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

+ 64 - 0
vite.config.ts

@@ -0,0 +1,64 @@
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+import Components from 'unplugin-vue-components/vite';
+import { VantResolver } from 'unplugin-vue-components/resolvers';
+import viteESLint from 'vite-plugin-eslint';
+import legacy from '@vitejs/plugin-legacy'
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const path = require('path');
+
+function resolve(dir: string) {
+  return path.join(__dirname, dir);
+}
+// https://vitejs.dev/config/
+// https://github.com/vitejs/vite/issues/1930 .env
+const proxyUrl = 'https://test.dayaedu.com/';
+export default defineConfig({
+  base: './',
+  plugins: [
+    legacy({
+			targets: 'last 2 versions and not dead, > 0.3%, Firefox ESR'
+		}),
+    vue(),
+    vueJsx(),
+    viteESLint(),
+    Components({
+      resolvers: [VantResolver()]
+    })
+  ],
+  resolve: {
+    alias: {
+      '@': resolve('./src'),
+      '@common': resolve('./src/common'),
+      '@components': resolve('./src/components'),
+      '@store': resolve('./src/store'),
+      '@views': resolve('./src/views')
+    }
+  },
+  server: {
+    host: '0.0.0.0',
+    port: 9002,
+    strictPort: true,
+    cors: true,
+    https: false,
+    proxy: {
+      '/api-auth': {
+        target: proxyUrl,
+        changeOrigin: true
+      },
+      '/api-web': {
+        target: proxyUrl,
+        changeOrigin: true
+      },
+      '/api-teacher': {
+        target: proxyUrl,
+        changeOrigin: true
+      },
+      '/api-student': {
+        target: proxyUrl,
+        changeOrigin: true
+      }
+    }
+  }
+});

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