Browse Source

Merge branch 'master' of https://git.zyuas.com/DJI/shangyun

S0025136190 1 year ago
parent
commit
dc008b61df
79 changed files with 3757 additions and 19394 deletions
  1. 0 1
      Web/.eslintignore
  2. 0 22
      Web/.eslintrc.js
  3. 1 1
      Web/.gitignore
  4. 0 5
      Web/.gitignore copy
  5. 0 1
      Web/.npmrc
  6. 0 21
      Web/LICENSE
  7. 9 19
      Web/README.md
  8. 0 2
      Web/env/.env
  9. 0 2
      Web/env/.env.production
  10. 0 2
      Web/env/.env.stag
  11. 14 11
      Web/index.html
  12. 1786 13349
      Web/package-lock.json
  13. 18 101
      Web/package.json
  14. 21 13
      Web/src/App.vue
  15. 0 13
      Web/src/antd.ts
  16. 28 0
      Web/src/api/custom/index.ts
  17. 10 15
      Web/src/api/http/config.ts
  18. 3 6
      Web/src/api/http/request.ts
  19. 0 0
      Web/src/assets/public/favicon.ico
  20. 1 2
      Web/src/components/MediaPanel.vue
  21. 69 0
      Web/src/components/common/nav.vue
  22. 26 24
      Web/src/components/common/sidebar.vue
  23. 20 49
      Web/src/components/common/topbar.vue
  24. 36 0
      Web/src/components/devices/changeRecord/components/Drawer.vue
  25. 169 0
      Web/src/components/devices/changeRecord/index.vue
  26. 37 61
      Web/src/components/devices/device-hms/DeviceHmsDrawer.vue
  27. 43 52
      Web/src/components/devices/device-log/DeviceLogUploadRecordDrawer.vue
  28. 0 1
      Web/src/components/devices/device-log/use-device-log-upload-progress-event.ts
  29. 0 1
      Web/src/components/devices/device-upgrade/use-device-upgrade-event.ts
  30. 421 0
      Web/src/components/devices/deviceList/index.vue
  31. 11 0
      Web/src/components/devices/feedbackRecord/index.vue
  32. 9 10
      Web/src/components/g-map/DroneControlInfoPanel.vue
  33. 165 193
      Web/src/components/g-map/DroneControlPanel.vue
  34. 0 1
      Web/src/components/g-map/use-drone-control-ws-event.ts
  35. 93 85
      Web/src/components/task/CreatePlan.vue
  36. 34 48
      Web/src/components/task/TaskPanel.vue
  37. 2 3
      Web/src/components/task/use-task-ws-event.ts
  38. 0 9
      Web/src/env.d.ts
  39. 1 1
      Web/src/hooks/use-connect-websocket.ts
  40. 2 2
      Web/src/hooks/use-map-tool.ts
  41. 8 8
      Web/src/hooks/use-mouse-tool.ts
  42. 7 7
      Web/src/main.ts
  43. 67 51
      Web/src/pages/page-pilot/pilot-home.vue
  44. 22 36
      Web/src/pages/page-pilot/pilot-index.vue
  45. 54 71
      Web/src/pages/page-pilot/pilot-liveshare.vue
  46. 38 64
      Web/src/pages/page-pilot/pilot-media.vue
  47. 23 12
      Web/src/pages/page-web/home.vue
  48. 19 39
      Web/src/pages/page-web/index.vue
  49. 24 432
      Web/src/pages/page-web/projects/devices.vue
  50. 14 9
      Web/src/pages/page-web/projects/dock.vue
  51. 42 81
      Web/src/pages/page-web/projects/layer.vue
  52. 0 10
      Web/src/pages/page-web/projects/media.vue
  53. 11 0
      Web/src/pages/page-web/projects/media/index.vue
  54. 36 30
      Web/src/pages/page-web/projects/members.vue
  55. 11 0
      Web/src/pages/page-web/projects/replay/index.vue
  56. 5 5
      Web/src/pages/page-web/projects/task.vue
  57. 11 0
      Web/src/pages/page-web/projects/trajectory/index.vue
  58. 159 84
      Web/src/pages/page-web/projects/tsa.vue
  59. 1 2
      Web/src/pages/page-web/projects/wayline.vue
  60. 28 15
      Web/src/pages/page-web/projects/workspace.vue
  61. 7 5
      Web/src/root.ts
  62. 15 45
      Web/src/router/index.ts
  63. 29 29
      Web/src/store/index.ts
  64. 11 15
      Web/src/styles/common.scss
  65. 2 2
      Web/src/types/device-cmd.ts
  66. 8 5
      Web/src/types/enums.ts
  67. 4 4
      Web/src/types/flight-area.ts
  68. 0 0
      Web/src/typings/shims-mqtt.d.ts
  69. 0 0
      Web/src/typings/shims-vue.d.ts
  70. 0 0
      Web/src/typings/vite-env.d.ts
  71. 0 13
      Web/src/use-common-components.ts
  72. 4 9
      Web/src/utils/bytes.ts
  73. 1 1
      Web/src/utils/color.ts
  74. 2 2
      Web/src/utils/error-code/index.ts
  75. 9 9
      Web/src/utils/logger.ts
  76. 4 4
      Web/src/utils/time.ts
  77. 5 3
      Web/tsconfig.json
  78. 47 52
      Web/vite.config.ts
  79. 0 4114
      Web/yarn.lock

+ 0 - 1
Web/.eslintignore

@@ -1 +0,0 @@
-/src/vendors/**

+ 0 - 22
Web/.eslintrc.js

@@ -1,22 +0,0 @@
-module.exports = {
-  env: {
-    browser: true,
-    commonjs: true,
-    es2021: true,
-    node: true
-  },
-  extends: ['standard', 'plugin:vue/vue3-essential'],
-  parserOptions: {
-    ecmaVersion: 12,
-    parser: '@typescript-eslint/parser'
-  },
-  plugins: ['vue', '@typescript-eslint'],
-  rules: {
-    'comma-dangle': 'off',
-    'import/no-absolute-path': 'off',
-    'no-unused-vars': 'off',
-    camelcase: 'off',
-    'no-redeclare': 'off',
-    'vue/no-unused-components': 'off'
-  }
-}

+ 1 - 1
Web/.gitignore

@@ -22,4 +22,4 @@ yarn-error.log*
 .history
 /coverage
 /backup
-node_modules
+node_modules

+ 0 - 5
Web/.gitignore copy

@@ -1,5 +0,0 @@
-node_modules
-.DS_Store
-dist
-dist-ssr
-*.local

+ 0 - 1
Web/.npmrc

@@ -1 +0,0 @@
-registry=https://registry.npmmirror.com/

+ 0 - 21
Web/LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2022 DJI-SDK
-
-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.

+ 9 - 19
Web/README.md

@@ -1,21 +1,11 @@
-# DJI Cloud API
+##  基础运行环境
+01. `node 18.15.0`
+02. `npm 9.5.0`
 
-## What is the DJI Cloud API?
+##  本地启动项目
+01. `npm ci`
+02. `npm run start`
 
-The launch of the Cloud API mainly solves the problem of developers reinventing the wheel. For developers who do not need in-depth customization of APP, they can directly use DJI Pilot2 to communicate with the third cloud platform, and developers can focus on the development and implementation of cloud service interfaces.
-
-## Docker
-
-If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker.zip)
-
-## Usage
-
-For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/doc/cloud-api-tutorial/cn/).
-
-## Latest Release
-
-Cloud API 1.10.0 was released on 7 April 2024. For more information, please visit the [Release Note](https://developer.dji.com/doc/cloud-api-tutorial/cn/).
-
-## License
-
-Cloud API is MIT-licensed. Please refer to the LICENSE file for more information.
+##  服务构建项目
+01. `npm ci`
+02. `npm run build`

+ 0 - 2
Web/env/.env

@@ -1,2 +0,0 @@
-VITE_APP_ENVIRONMENT=DEV
-VITE_APP_APIGATEWAY_BACKEND_HOST=''

+ 0 - 2
Web/env/.env.production

@@ -1,2 +0,0 @@
-VITE_APP_ENVIRONMENT=production
-VITE_APP_APIGATEWAY_BACKEND_HOST=''

+ 0 - 2
Web/env/.env.stag

@@ -1,2 +0,0 @@
-VITE_APP_ENVIRONMENT=STAG
-VITE_APP_APIGATEWAY_BACKEND_HOST=''

+ 14 - 11
Web/index.html

@@ -1,13 +1,16 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>demo-web</title>
-  </head>
-  <body>
-    <div id="demo-app"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
-</html>
+
+<head>
+  <meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <link rel="icon" href="/src/assets/public/favicon.ico" />
+  <title>上云无人机管理平台</title>
+</head>
+
+<body>
+  <div id="root"></div>
+  <script type="module" src="/src/main.ts"></script>
+</body>
+
+</html>

File diff suppressed because it is too large
+ 1786 - 13349
Web/package-lock.json


+ 18 - 101
Web/package.json

@@ -1,117 +1,34 @@
 {
-  "name": "demo-web",
-  "version": "0.0.1",
+  "name": "uav-manage-web",
+  "version": "1.0.0",
+  "description": "上云无人机管理平台",
+  "type": "module",
+  "license": "ISC",
   "scripts": {
-    "serve": "vite",
-    "build:test": "vite build --mode stag",
-    "build": "vite build",
-    "preview": "vite preview",
-    "lint": "eslint --fix"
+    "start": "vite",
+    "build": "vite build"
   },
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
-    "@ant-design/icons-vue": "^6.0.1",
-    "@vitejs/plugin-legacy": "^1.6.2",
     "agora-rtc-sdk-ng": "^4.12.1",
     "ant-design-vue": "^2.2.8",
     "axios": "^0.21.1",
     "eventemitter3": "^5.0.0",
     "mitt": "^3.0.0",
+    "moment": "^2.30.0",
     "mqtt": "^4.3.7",
-    "query-string": "^7.0.1",
     "reconnecting-websocket": "^4.4.0",
-    "vconsole": "^3.8.1",
-    "vite-plugin-components": "^0.13.3",
-    "vite-plugin-importer": "^0.2.5",
-    "vite-plugin-optimize-persist": "^0.1.2",
-    "vite-plugin-package-config": "^0.1.1",
-    "vue": "^3.2.26",
-    "vue-cookies": "^1.7.4",
-    "vue-i18n": "^9.1.6",
-    "vue-router": "4",
-    "vuex": "^4.0.2"
+    "vconsole": "^3.15.0",
+    "vue": "3.2.26",
+    "vue-router": "^4.3.0",
+    "vuex": "^4.1.0"
   },
   "devDependencies": {
-    "@types/node": "^16.3.2",
-    "@types/urlencode": "^1.1.2",
-    "@typescript-eslint/eslint-plugin": "^5.8.1",
-    "@typescript-eslint/parser": "^5.8.1",
-    "@vitejs/plugin-vue": "^1.2.4",
-    "@vue/compiler-sfc": "^3.0.5",
-    "eslint": "^7.30.0",
-    "eslint-config-standard": "^16.0.3",
-    "eslint-plugin-import": "^2.23.4",
-    "eslint-plugin-node": "^11.1.0",
-    "eslint-plugin-promise": "^5.1.0",
-    "eslint-plugin-vue": "^7.13.0",
-    "rollup-plugin-external-globals": "^0.6.1",
+    "@types/node": "^18.15.0",
+    "@vitejs/plugin-vue": "^5.0.0",
     "sass": "^1.35.1",
-    "typescript": "^4.5.4",
-    "vite": "^2.4.0",
-    "vite-plugin-eslint": "^1.3.0",
-    "vite-plugin-style-import": "^1.0.1",
-    "vite-plugin-svg-icons": "^1.0.5",
-    "vite-plugin-vconsole": "^1.1.0",
-    "vue-tsc": "^0.0.24"
-  },
-  "license": "ISC",
-  "vite": {
-    "optimizeDeps": {
-      "include": [
-        "@amap/amap-jsapi-loader",
-        "@ant-design/icons-vue",
-        "@vue/reactivity",
-        "agora-rtc-sdk-ng",
-        "ant-design-vue",
-        "ant-design-vue/es",
-        "ant-design-vue/es/avatar/style/css",
-        "ant-design-vue/es/breadcrumb/style/css",
-        "ant-design-vue/es/button/style/css",
-        "ant-design-vue/es/checkbox/style/css",
-        "ant-design-vue/es/col/style/css",
-        "ant-design-vue/es/collapse/style/css",
-        "ant-design-vue/es/date-picker/style/css",
-        "ant-design-vue/es/divider/style/css",
-        "ant-design-vue/es/drawer/style/css",
-        "ant-design-vue/es/dropdown/style/css",
-        "ant-design-vue/es/empty/style/css",
-        "ant-design-vue/es/form/style/css",
-        "ant-design-vue/es/image/style/css",
-        "ant-design-vue/es/input-number/style/css",
-        "ant-design-vue/es/input/style/css",
-        "ant-design-vue/es/layout/style/css",
-        "ant-design-vue/es/menu/style/css",
-        "ant-design-vue/es/message/style/css",
-        "ant-design-vue/es/modal/style/css",
-        "ant-design-vue/es/pagination/style/css",
-        "ant-design-vue/es/popconfirm/style/css",
-        "ant-design-vue/es/popover/style/css",
-        "ant-design-vue/es/progress/style/css",
-        "ant-design-vue/es/radio/style/css",
-        "ant-design-vue/es/row/style/css",
-        "ant-design-vue/es/select/style/css",
-        "ant-design-vue/es/space/style/css",
-        "ant-design-vue/es/spin/style/css",
-        "ant-design-vue/es/switch/style/css",
-        "ant-design-vue/es/table/style/css",
-        "ant-design-vue/es/tag/style/css",
-        "ant-design-vue/es/time-picker/style/css",
-        "ant-design-vue/es/tooltip/style/css",
-        "ant-design-vue/es/tree/style/css",
-        "ant-design-vue/es/upload/style/css",
-        "axios",
-        "eventemitter3",
-        "lodash",
-        "mitt",
-        "moment",
-        "mqtt",
-        "mqtt/dist/mqtt.min",
-        "reconnecting-websocket",
-        "vconsole",
-        "vue",
-        "vue-router",
-        "vuex"
-      ]
-    }
+    "typescript": "^5.5.0",
+    "vite": "5.3.0",
+    "vite-plugin-vconsole": "^2.1.0"
   }
-}
+}

+ 21 - 13
Web/src/App.vue

@@ -1,29 +1,37 @@
 <template>
-  <div class="demo-app">
-    <router-view />
-    <!-- <div class="map-wrapper">
-      <GMap/>
-    </div> -->
-  </div>
+  <a-config-provider :locale="locale">
+    <div class="app">
+      <router-view />
+      <!-- <div class="map-wrapper">
+        <GMap />
+      </div> -->
+    </div>
+  </a-config-provider>
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, ref } from 'vue'
+import { defineComponent } from 'vue'
 import { useMyStore } from './store'
 import GMap from '/@/components/GMap.vue'
+import zhCN from 'ant-design-vue/es/locale/zh_CN';
+import 'moment/dist/locale/zh-cn';
 
 export default defineComponent({
   name: 'App',
   components: { GMap },
 
-  setup () {
-    const store = useMyStore()
-    return {}
+  setup() {
+    const store = useMyStore();
+
+    return {
+      locale: zhCN,
+    }
   }
 })
 </script>
+
 <style lang="scss" scoped>
-.demo-app {
+.app {
   width: 100%;
   height: 100%;
 
@@ -35,8 +43,8 @@ export default defineComponent({
 </style>
 
 <style lang="scss">
-#demo-app {
+#root {
   width: 100%;
   height: 100%
 }
-</style>
+</style>

+ 0 - 13
Web/src/antd.ts

@@ -1,13 +0,0 @@
-// import Icon from '@ant-design/icons-vue'
-import * as antDesign from 'ant-design-vue'
-import 'ant-design-vue/dist/antd.css'
-import { App } from 'vue'
-import svgIcon from '/@/components/svgIcon.vue'
-
-export const antComponents = {
-  install (app: App): void {
-    app.use(antDesign)
-    // app.component('Icon', Icon)
-    app.component('svg-icon', svgIcon)
-  }
-}

+ 28 - 0
Web/src/api/custom/index.ts

@@ -0,0 +1,28 @@
+import request from '/@/api/http/request';
+
+// Api参数类型
+export type FetchFeedbackRecordListApiParams = {
+    page: number,
+    page_size: number,
+};
+
+// Api函数类型
+export type FetchFeedbackRecordListApi = (data: FetchFeedbackRecordListApiParams) => Promise<any>;
+export type FetchChangeRecordListApi = () => Promise<any>;
+
+// 获取反馈记录列表
+const fetchFeedbackRecordListApi: FetchFeedbackRecordListApi = async (data) => {
+    const res = await request.get('/manage/api/v1/devices', { params: data });
+    return res.data;
+};
+
+// 获取变化记录列表
+const fetchChangeRecordListApi: FetchChangeRecordListApi = async () => {
+    const res = await request.get('/manage/api/v1/workspaces/current');
+    return res.data;
+};
+
+export const apis = {
+    fetchFeedbackRecordList: fetchFeedbackRecordListApi,
+    fetchChangeRecordList: fetchChangeRecordListApi,
+};

+ 10 - 15
Web/src/api/http/config.ts

@@ -1,14 +1,12 @@
 export const CURRENT_CONFIG = {
-
-  // license
-  appId: 'Please enter the app id.', // You need to go to the development website to apply.
-  appKey: 'Please enter the app key.', // You need to go to the development website to apply.
-  appLicense: 'Please enter the app license.', // You need to go to the development website to apply.
-
-  // http
-  baseURL: 'Please enter the backend access address prefix.', // This url must end with "/". Example: 'http://192.168.1.1:6789/'
-  websocketURL: 'Please enter the WebSocket access address.', // Example: 'ws://192.168.1.1:6789/api/v1/ws'
-
+  // 验证配置
+  appId: '146815',
+  appKey: '7c9e9108f2ddcbab32d2b508f452151',
+  appLicense: 'ZK7Dzih4Qc9JCZhDiyDsWJwTW+1rhnnzT1SqDxbdSPVV24bbDC4r1KNjXo7tIPBnPne7ipnXeefP0lJ0OHvxMpkKiag5lFCIndKSvYYdQkyScT3dahCXjmYsd0YyWyHj4tvXoR2DRVq1PdBHLB1iUo2FGLCIZ8QHbGyqglyGdHY=',
+  // 网络请求
+  baseURL: '/api',
+  apiURL: 'http://192.168.3.42:6789',
+  websocketURL: 'ws://192.168.3.42:6789/api/v1/ws',
   // livestreaming
   // RTMP  Note: This IP is the address of the streaming server. If you want to see livestream on web page, you need to convert the RTMP stream to WebRTC stream.
   rtmpURL: 'Please enter the rtmp access address.', // Example: 'rtmp://192.168.1.1/live/'
@@ -28,9 +26,6 @@ export const CURRENT_CONFIG = {
   agoraAPPID: 'Please enter the agora app id.',
   agoraToken: 'Please enter the agora temporary token.',
   agoraChannel: 'Please enter the agora channel.',
-
-  // map
-  // You can apply on the AMap website.
-  amapKey: 'Please enter the amap key.',
-
+  // 高德地图
+  amapKey: '9ccf8815eb701c6aab8cd63e739df0fa',
 }

+ 3 - 6
Web/src/api/http/request.ts

@@ -1,5 +1,4 @@
 import axios from 'axios'
-import { uuidv4 } from '/@/utils/uuid'
 import { CURRENT_CONFIG } from './config'
 import { message } from 'ant-design-vue'
 import router from '/@/router'
@@ -7,22 +6,20 @@ import { ELocalStorageKey, ERouterName, EUserType } from '/@/types/enums'
 export * from './type'
 
 const REQUEST_ID = 'X-Request-Id'
-function getAuthToken () {
+
+function getAuthToken() {
   return localStorage.getItem(ELocalStorageKey.Token)
 }
 
 const instance = axios.create({
-  // withCredentials: true,
   headers: {
     'Content-Type': 'application/json',
   },
-  // timeout: 12000,
 })
 
 instance.interceptors.request.use(
   config => {
     config.headers[ELocalStorageKey.Token] = getAuthToken()
-    // config.headers[REQUEST_ID] = uuidv4()
     config.baseURL = CURRENT_CONFIG.baseURL
     return config
   },
@@ -55,7 +52,7 @@ instance.interceptors.response.use(
     }
     // @See: https://github.com/axios/axios/issues/383
     if (!err.response || !err.response.status) {
-      message.error('The network is abnormal, please check the backend service and try again')
+      message.error('服务异常')
       return
     }
     if (err.response?.status !== 200) {

+ 0 - 0
Web/public/favicon.ico → Web/src/assets/public/favicon.ico


+ 1 - 2
Web/src/components/MediaPanel.vue

@@ -24,9 +24,8 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from '@vue/reactivity'
 import { TableState } from 'ant-design-vue/lib/table/interface'
-import { onMounted, reactive } from 'vue'
+import { onMounted, reactive,ref} from 'vue'
 import { IPage } from '../api/http/type'
 import { ELocalStorageKey } from '../types/enums'
 import { downloadFile } from '../utils/common'

+ 69 - 0
Web/src/components/common/nav.vue

@@ -0,0 +1,69 @@
+<template>
+  <a-layout-sider collapsible>
+    <a-menu theme="dark" mode="inline" v-model:selectedKeys="state.selectedKeys" @select="handleSelect">
+      <a-menu-item :key="'/' + ERouterName.DEVICES">
+        <HddOutlined />
+        <span>
+          设备管理
+        </span>
+      </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.TASK">
+        <ContainerOutlined />
+        <span>
+          远程计划任务
+        </span>
+      </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.MEDIA">
+        <PictureOutlined />
+        <span>
+          照片管理
+        </span>
+      </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.REPLAY">
+        <VideoCameraOutlined />
+        <span>
+          视频回放
+        </span>
+      </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.TRAJECTORY">
+        <GatewayOutlined />
+        <span>
+          轨迹回放
+        </span>
+      </a-menu-item>
+      <a-menu-item :key="'/' + ERouterName.MEMBERS">
+        <TeamOutlined />
+        <span>
+          成员管理
+        </span>
+      </a-menu-item>
+    </a-menu>
+  </a-layout-sider>
+</template>
+<script lang="ts" setup>
+import { reactive, watchEffect } from 'vue';
+import { GatewayOutlined, ContainerOutlined, HddOutlined, PictureOutlined, VideoCameraOutlined, TeamOutlined } from '@ant-design/icons-vue';
+import { ERouterName } from '/@/types/enums';
+import router from '/@/router';
+
+interface State {
+  selectedKeys: string[],
+}
+
+const state: State = reactive({
+  selectedKeys: [],
+})
+
+watchEffect(() => {
+  const path = router.currentRoute.value.fullPath;
+  const firstKey = path.split('/')[1];
+  state.selectedKeys = ['/' + firstKey];
+});
+
+// 选择菜单
+const handleSelect = (item: any) => {
+  router.push({ path: item.key })
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 26 - 24
Web/src/components/common/sidebar.vue

@@ -1,23 +1,20 @@
 <template>
   <div class="demo-project-sidebar-wrapper flex-justify-between">
     <div>
-    <router-link
-      v-for="item in options"
-      :key="item.key"
-      :to="item.path"
-      :class="{
+      <router-link v-for="item in options" :key="item.key" :to="item.path" :class="{
         'menu-item': true,
         selected: selectedRoute(item),
-      }"
-    >
-      <a-tooltip :title="item.label" placement="right">
-        <Icon class="fz20" style="width: 50px;" :icon="item.icon"/>
-      </a-tooltip>
-    </router-link>
+      }">
+        <a-tooltip :title="item.label" placement="right">
+          <Icon class="fz20" style="width: 50px;" :icon="item.icon" />
+        </a-tooltip>
+      </router-link>
     </div>
     <div class="mb20 flex-display flex-column flex-align-center flex-justify-between">
       <a-tooltip title="Back to home" placement="right">
-        <a @click="goHome"> <Icon icon="ImportOutlined" style="font-size: 22px; color: white"/></a>
+        <a @click="goHome">
+          <Icon icon="ImportOutlined" style="font-size: 22px; color: white" />
+        </a>
       </a-tooltip>
     </div>
   </div>
@@ -25,23 +22,23 @@
 
 <script lang="ts">
 import { createVNode, defineComponent } from 'vue'
-import { getRoot } from '/@/root'
 import * as icons from '@ant-design/icons-vue'
+import { getRoot } from '/@/root'
 import { ERouterName } from '/@/types'
 
 interface IOptions {
   key: number
   label: string
   path:
-    | string
-    | {
-        path: string
-        query?: any
-      }
+  | string
+  | {
+    path: string
+    query?: any
+  }
   icon: string
 }
 
-const Icon = (props: {icon: string}) => {
+const Icon = (props: { icon: string }) => {
   return createVNode((icons as any)[props.icon])
 }
 
@@ -50,7 +47,7 @@ export default defineComponent({
     Icon,
   },
   name: 'Sidebar',
-  setup () {
+  setup() {
     const root = getRoot()
     const options = [
       { key: 0, label: 'Tsa', path: '/' + ERouterName.TSA, icon: 'TeamOutlined' },
@@ -62,13 +59,13 @@ export default defineComponent({
       { key: 6, label: 'Flight Area', path: '/' + ERouterName.FLIGHT_AREA, icon: 'GroupOutlined' },
     ]
 
-    function selectedRoute (item: IOptions) {
+    function selectedRoute(item: IOptions) {
       const path = typeof item.path === 'string' ? item.path : item.path.path
       return root.$route.path?.indexOf(path) === 0
     }
 
-    function goHome () {
-      root.$router.push('/' + ERouterName.MEMBERS)
+    function goHome() {
+      root.$router.push('/' + ERouterName.DEVICES)
     }
 
     return {
@@ -90,6 +87,7 @@ export default defineComponent({
   color: $text-white-basic;
   // flex: 1;
   overflow: hidden;
+
   .menu-item {
     width: 100%;
     padding: 16px 0px;
@@ -98,15 +96,18 @@ export default defineComponent({
     align-items: center;
     color: $text-white-basic;
     cursor: pointer;
+
     &.selected {
       background-color: #101010;
       color: $primary;
     }
+
     &.disabled {
       pointer-events: none;
       opacity: 0.45;
     }
   }
+
   .filling {
     flex: 1;
   }
@@ -118,7 +119,8 @@ export default defineComponent({
   }
 
 }
+
 .ant-tooltip-open {
   border: 0;
 }
-</style>
+</style>

+ 20 - 49
Web/src/components/common/topbar.vue

@@ -1,33 +1,26 @@
 <template>
-  <div class="width-100 flex-row flex-justify-between flex-align-center" style="height: 60px;">
-    <div class="height-100">
-      <a-avatar :size="40" shape="square" :src="cloudapi" />
-      <span class="ml10 fontBold">{{ workspaceName }}</span>
+  <div class="width-100 flex-row flex-justify-between flex-align-center"
+    style="height: 60px;border-bottom: 1px solid #F0F2F5;">
+    <div>
+      <a-button type="primary" @click="onClickToWorkspace">
+        项目工作空间
+      </a-button>
     </div>
-
-    <a-space class="fz16 height-100" size="large">
-        <router-link
-        v-for="item in options"
-        :key="item.key"
-        :to="item.path"
-        :class="{
-            'menu-item': true,
-        }">
-          <span @click="selectedRoute(item.path)" :style="selected === item.path ? 'color: #2d8cf0;' : 'color: white'">{{ item.label }}</span>
-        </router-link>
-    </a-space>
-
-    <div class="height-100 fz16 flex-row flex-justify-between flex-align-center">
+    <div style="cursor: pointer;" class="height-100 fz16 flex-row flex-justify-between flex-align-center">
       <a-dropdown>
         <div class="height-100">
-          <span class="fz20 mt20" style="border: 2px solid white; border-radius: 50%; display: inline-flex;"><UserOutlined /></span>
+          <span class="fz20 mt20" style="border: 2px solid white; border-radius: 50%; display: inline-flex;">
+            <UserOutlined />
+          </span>
           <span class="ml10 mr10" style="float: right;">{{ username }}</span>
         </div>
         <template #overlay>
-          <a-menu theme="dark" class="flex-column flex-justify-between flex-align-center">
+          <a-menu class="flex-column flex-justify-between flex-align-center">
             <a-menu-item>
-              <span class="mr10" style="font-size: 16px;"><ExportOutlined /></span>
-              <span @click="logout">Log Out</span>
+              <span class="mr10" style="font-size: 16px;">
+                <PoweroffOutlined />
+              </span>
+              <span @click="logout">退出登录</span>
             </a-menu-item>
           </a-menu>
         </template>
@@ -37,37 +30,16 @@
 </template>
 
 <script lang="ts" setup>
-import { message } from 'ant-design-vue'
-import { defineComponent, onMounted, ref } from 'vue'
+import { onMounted, ref } from 'vue'
 import { getRoot } from '/@/root'
 import { getPlatformInfo } from '/@/api/manage'
 import { ELocalStorageKey, ERouterName } from '/@/types'
-import { UserOutlined, ExportOutlined } from '@ant-design/icons-vue'
-import cloudapi from '/@/assets/icons/cloudapi.png'
+import { UserOutlined, PoweroffOutlined } from '@ant-design/icons-vue'
 
 const root = getRoot()
 
-interface IOptions {
-  key: number
-  label: string
-  path:
-    | string
-    | {
-        path: string
-        query?: any
-      }
-  icon: string
-}
 const username = ref(localStorage.getItem(ELocalStorageKey.Username))
 const workspaceName = ref('')
-const options = [
-  { key: 0, label: ERouterName.WORKSPACE.charAt(0).toUpperCase() + ERouterName.WORKSPACE.substr(1), path: '/' + ERouterName.WORKSPACE },
-  { key: 1, label: ERouterName.MEMBERS.charAt(0).toUpperCase() + ERouterName.MEMBERS.substr(1), path: '/' + ERouterName.MEMBERS },
-  { key: 2, label: ERouterName.DEVICES.charAt(0).toUpperCase() + ERouterName.DEVICES.substr(1), path: '/' + ERouterName.DEVICES },
-  { key: 3, label: ERouterName.FIRMWARES.charAt(0).toUpperCase() + ERouterName.FIRMWARES.substr(1), path: '/' + ERouterName.FIRMWARES },
-]
-
-const selected = ref<string>(root.$route.path)
 
 onMounted(() => {
   getPlatformInfo().then(res => {
@@ -75,8 +47,8 @@ onMounted(() => {
   })
 })
 
-function selectedRoute (path: string) {
-  selected.value = path
+const onClickToWorkspace = () => {
+  root.$router.push(ERouterName.WORKSPACE)
 }
 
 const logout = () => {
@@ -92,5 +64,4 @@ const logout = () => {
   font-weight: 500;
   font-size: 18px;
 }
-
-</style>
+</style>

+ 36 - 0
Web/src/components/devices/changeRecord/components/Drawer.vue

@@ -0,0 +1,36 @@
+<template>
+    <a-drawer :width="800" title="详情" placement="right" v-model:visible="visible" @close="onClose">
+        详情
+    </a-drawer>
+</template>
+
+<script lang="ts" setup>
+import { reactive, onMounted } from 'vue'
+import { apis } from '/@/api/custom/index'
+
+interface Props {
+    id: string,
+    visible: boolean,
+    onClose: () => void,
+};
+
+const props = withDefaults(defineProps<Props>(), {
+
+});
+
+interface State {
+    listLoading: boolean,
+    list: any[],
+};
+
+const state: State = reactive({
+    listLoading: false,
+    list: [],
+});
+
+onMounted(async () => {
+
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 169 - 0
Web/src/components/devices/changeRecord/index.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="changeRecord">
+    <div class="changeRecord-table">
+      <a-table :scroll="{ x: 'max-content', y: 600 }" rowKey="id" :loading="state.listLoading" :columns="columns"
+        :dataSource="state.list" :pagination="paginationConfig">
+        <!-- 操作 -->
+        <template #operation="{ record }">
+          <div class="editable-row-operations">
+            <div class="flex-align-center flex-row" style="color: #2d8cf0">
+              <a-tooltip title="详情">
+                <FileSearchOutlined style="margin-right: 10px;" @click="onClickEdit(record.id)" />
+              </a-tooltip>
+              <a-tooltip title="删除">
+                <DeleteOutlined @click="onClickDelete(record.id)" />
+              </a-tooltip>
+            </div>
+          </div>
+        </template>
+      </a-table>
+    </div>
+    <Drawer :id="state.currentId" :visible="state.drawerVisible" :onClose="drawerOnClickClose" />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { reactive, onMounted } from 'vue';
+import { Modal } from 'ant-design-vue';
+import { DeleteOutlined, FileSearchOutlined } from '@ant-design/icons-vue';
+import Drawer from './components/Drawer.vue';
+import { apis } from '/@/api/custom/index';
+
+interface State {
+  listLoading: boolean,
+  list: any[],
+  currentId: string,
+  drawerVisible: boolean,
+};
+
+const state: State = reactive({
+  listLoading: false,
+  list: [],
+  currentId: '',
+  drawerVisible: false,
+});
+
+const paginationConfig = reactive({
+  pageSizeOptions: ['20', '50', '100'],
+  showQuickJumper: true,
+  showSizeChanger: true,
+  pageSize: 50,
+  current: 1,
+  total: 0
+})
+
+onMounted(async () => {
+  state.listLoading = true;
+  try {
+    const res = await apis.fetchChangeRecordList();
+    console.log(res, 'list');
+    const list = [
+      {
+        id: '1',
+        time: '2021-01-01',
+        name: '1',
+        deviceType: 'aa',
+        sn: '123',
+        deviceName: '1',
+        firmware_version: '1',
+        description: '1',
+        status: '1',
+      },
+      {
+        id: '2',
+        time: '2021-01-01',
+        name: '1',
+        deviceType: 'aa',
+        sn: '123',
+        deviceName: '1',
+        firmware_version: '1',
+        description: '1',
+        status: '1',
+      },
+    ]
+    state.list = list;
+  } catch (e) {
+    console.error(e);
+  } finally {
+    state.listLoading = false;
+  }
+})
+
+const columns = [
+  {
+    title: '反馈时间',
+    dataIndex: 'time',
+    sorter: (a: any, b: any) => a.time - b.time,
+  },
+  {
+    title: '反馈人',
+    dataIndex: 'name',
+  },
+  {
+    title: '设备型号',
+    dataIndex: 'deviceType',
+    sorter: (a: any, b: any) => a.deviceType - b.deviceType,
+  },
+  {
+    title: '设备SN',
+    dataIndex: 'sn',
+  },
+  {
+    title: '设备名称',
+    dataIndex: 'deviceName',
+    sorter: (a: any, b: any) => a.deviceName - b.deviceName,
+  },
+  {
+    title: '固件版本',
+    dataIndex: 'firmware_version',
+  },
+  {
+    title: '设备异常描述',
+    dataIndex: 'description',
+  },
+  {
+    title: '上传状态',
+    dataIndex: 'status',
+    sorter: (a: any, b: any) => a.time - b.time,
+  },
+  {
+    title: '操作',
+    dataIndex: 'operation',
+    fixed: 'right',
+    width: 100,
+    className: 'titleStyle',
+    slots: { customRender: 'operation' }
+  },
+]
+
+// 点击编辑
+const onClickEdit = (id: string) => {
+  state.currentId = id;
+  state.drawerVisible = true;
+}
+
+const drawerOnClickClose = () => {
+  state.drawerVisible = false;
+}
+
+// 点击删除
+const onClickDelete = (id: number) => {
+  Modal.confirm({
+    title: '提示',
+    content: '确定删除吗?',
+    onOk: async () => {
+
+    },
+  });
+}
+</script>
+
+<style lang="scss" scoped>
+.changeRecord {
+  &-table {
+    background-color: white;
+    margin: 20px;
+    padding: 0 20px;
+  }
+}
+</style>

+ 37 - 61
Web/src/components/devices/device-hms/DeviceHmsDrawer.vue

@@ -1,78 +1,54 @@
 <template>
-  <a-drawer
-    title="Hms Info"
-    placement="right"
-    v-model:visible="sVisible"
-    @update:visible="onVisibleChange"
-    :destroyOnClose="true"
-    :width="800">
+  <a-drawer title="设备告警信息" placement="right" v-model:visible="sVisible" @update:visible="onVisibleChange"
+    :destroyOnClose="true" :width="800">
     <div class="flex-row flex-align-center">
       <div style="width: 240px;">
-        <a-range-picker
-          v-model:value="time"
-          format="YYYY-MM-DD"
-          :placeholder="['Start Time', 'End Time']"
-          @change="onTimeChange"/>
+        <a-range-picker v-model:value="time" format="YYYY-MM-DD" @change="onTimeChange" />
       </div>
       <div class="ml5">
-        <a-select
-          style="width: 150px"
-          v-model:value="param.level"
-          @select="onLevelSelect">
-          <a-select-option
-            v-for="item in levels"
-            :key="item.label"
-            :value="item.value"
-          >
+        <a-select style="width: 150px" v-model:value="param.level" @select="onLevelSelect">
+          <a-select-option v-for="item in levels" :key="item.label" :value="item.value">
             {{ item.label }}
           </a-select-option>
         </a-select>
       </div>
       <div class="ml5">
-        <a-select
-          v-model:value="param.domain"
-          :disabled="!param.children_sn || !param.device_sn"
-          style="width: 150px"
+        <a-select v-model:value="param.domain" :disabled="!param.children_sn || !param.device_sn" style="width: 150px"
           @select="onDeviceTypeSelect">
-          <a-select-option
-            v-for="item in deviceTypes"
-            :key="item.label"
-            :value="item.value"
-          >
+          <a-select-option v-for="item in deviceTypes" :key="item.label" :value="item.value">
             {{ item.label }}
           </a-select-option>
         </a-select>
       </div>
       <div class="ml5">
-        <a-input-search
-          v-model:value="param.message"
-          placeholder="input search message"
-          style="width: 200px"
-          @search="getHms"/>
+        <a-input-search v-model:value="param.message" placeholder="搜索告警信息" style="width: 200px" @search="getHms" />
       </div>
     </div>
     <div>
-      <a-table :columns="hmsColumns"  :scroll="{ x: '100%', y: 600 }" :data-source="hmsData.data" :pagination="hmsPaginationProp" @change="refreshHmsData" row-key="hms_id"
-        :rowClassName="rowClassName" :loading="loading">
+      <a-table :columns="hmsColumns" :scroll="{ x: '100%', y: 600 }" :data-source="hmsData.data"
+        :pagination="hmsPaginationProp" @change="refreshHmsData" row-key="hms_id" :rowClassName="rowClassName"
+        :loading="loading">
         <template #time="{ record }">
           <div>{{ record.create_time }}</div>
           <div :style="record.update_time ? '' : record.level === EHmsLevel.CAUTION ? 'color: orange;' :
-            record.level === EHmsLevel.WARN ? 'color: red;' : 'color: #28d445;'">{{ record.update_time ?? 'It is happening...' }}</div>
+            record.level === EHmsLevel.WARN ? 'color: red;' : 'color: #28d445;'">
+            {{ record.update_time ?? 'It is happening...' }}</div>
         </template>
         <template #level="{ text }">
           <div class="flex-row flex-align-center">
-            <div :class="text === EHmsLevel.CAUTION ? 'caution' : text === EHmsLevel.WARN ? 'warn' : 'notice'" style="width: 10px; height: 10px; border-radius: 50%;"></div>
+            <div :class="text === EHmsLevel.CAUTION ? 'caution' : text === EHmsLevel.WARN ? 'warn' : 'notice'"
+              style="width: 10px; height: 10px; border-radius: 50%;"></div>
             <div style="margin-left: 3px;">{{ EHmsLevel[text] }}</div>
           </div>
         </template>
         <template v-for="col in ['code', 'message']" #[col]="{ text }" :key="col">
           <a-tooltip :title="text">
-              <div >{{ text }}</div>
+            <div>{{ text }}</div>
           </a-tooltip>
         </template>
-        <template #domain="{text}">
+        <template #domain="{ text }">
           <a-tooltip :title="EDeviceTypeName[text]">
-              <div >{{ EDeviceTypeName[text] }}</div>
+            <div>{{ EDeviceTypeName[text] }}</div>
           </a-tooltip>
         </template>
       </a-table>
@@ -84,7 +60,7 @@
 <script lang="ts" setup>
 import { watchEffect, reactive, ref, defineProps, defineEmits, watch } from 'vue'
 import { getDeviceHms, HmsQueryBody } from '/@/api/manage'
-import moment, { Moment } from 'moment'
+import moment from 'moment'
 import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface'
 import { Device, DeviceHms } from '/@/types/device'
 import { IPage } from '/@/api/http/type'
@@ -108,11 +84,11 @@ watch(props, () => {
   }
 })
 
-function onVisibleChange (sVisible: boolean) {
+function onVisibleChange(sVisible: boolean) {
   setVisible(sVisible)
 }
 
-function setVisible (v: boolean, e?: Event) {
+function setVisible(v: boolean, e?: Event) {
   sVisible.value = v
   emit('update:visible', v, e)
 }
@@ -120,12 +96,12 @@ function setVisible (v: boolean, e?: Event) {
 const loading = ref(false)
 
 const hmsColumns: ColumnProps[] = [
-  { title: 'Alarm Begin | End Time', dataIndex: 'create_time', width: '25%', className: 'titleStyle', slots: { customRender: 'time' } },
-  { title: 'Level', dataIndex: 'level', width: '120px', className: 'titleStyle', slots: { customRender: 'level' } },
-  { title: 'Device', dataIndex: 'domain', width: '12%', className: 'titleStyle', slots: { customRender: 'domain' } },
-  { title: 'Error Code', dataIndex: 'key', width: '20%', className: 'titleStyle', ellipsis: true, slots: { customRender: 'code' } },
-  { title: 'Hms Message', dataIndex: 'message_en', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
-  { title: 'Hms Message', dataIndex: 'message_zh', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
+  { title: '告警开始|结束时间', dataIndex: 'create_time', width: '25%', className: 'titleStyle', slots: { customRender: 'time' } },
+  { title: '告警等级', dataIndex: 'level', width: '120px', className: 'titleStyle', slots: { customRender: 'level' } },
+  { title: '设备', dataIndex: 'domain', width: '12%', className: 'titleStyle', slots: { customRender: 'domain' } },
+  { title: '错误码', dataIndex: 'key', width: '20%', className: 'titleStyle', ellipsis: true, slots: { customRender: 'code' } },
+  { title: '告警内容', dataIndex: 'message_en', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
+  { title: '解决方案', dataIndex: 'message_zh', className: 'titleStyle', ellipsis: true, slots: { customRender: 'message' } },
 ]
 
 interface DeviceHmsData {
@@ -148,14 +124,14 @@ const hmsPaginationProp = reactive({
 })
 
 // 获取分页信息
-function getPaginationBody () {
+function getPaginationBody() {
   return {
     page: hmsPaginationProp.current,
     page_size: hmsPaginationProp.pageSize
   } as IPage
 }
 
-function showHms () {
+function showHms() {
   const dock = props.device
   if (!dock) return
   if (dock.domain === EDeviceTypeName.Dock) {
@@ -167,7 +143,7 @@ function showHms () {
   }
 }
 
-function refreshHmsData (page: Pagination) {
+function refreshHmsData(page: Pagination) {
   hmsPaginationProp.current = page?.current!
   hmsPaginationProp.pageSize = page?.pageSize!
   getHms()
@@ -187,7 +163,7 @@ const param = reactive<HmsQueryBody>({
 
 const levels = [
   {
-    label: 'All',
+    label: '全部告警等级',
     value: ''
   }, {
     label: EHmsLevel[0],
@@ -203,7 +179,7 @@ const levels = [
 
 const deviceTypes = [
   {
-    label: 'All',
+    label: '全部设备',
     value: -1
   }, {
     label: EDeviceTypeName[EDeviceTypeName.Aircraft],
@@ -227,7 +203,7 @@ const rowClassName = (record: any, index: number) => {
 
 const time = ref([moment(param.begin_time), moment(param.end_time)])
 
-function getHms () {
+function getHms() {
   loading.value = true
   getDeviceHms(param, workspaceId, getPaginationBody())
     .then(res => {
@@ -243,20 +219,20 @@ function getHms () {
     })
 }
 
-function getDeviceHmsBySn (sn: string, childSn: string) {
+function getDeviceHmsBySn(sn: string, childSn: string) {
   param.device_sn = sn
   param.children_sn = childSn
   param.sns = [param.device_sn, param.children_sn]
   getHms()
 }
 
-function onTimeChange (newTime: [Moment, Moment]) {
+function onTimeChange(newTime: any[]) {
   param.begin_time = newTime[0].valueOf()
   param.end_time = newTime[1].valueOf()
   getHms()
 }
 
-function onDeviceTypeSelect (val: number) {
+function onDeviceTypeSelect(val: number) {
   param.sns = [param.device_sn, param.children_sn]
   if (val === EDeviceTypeName.Dock) {
     param.sns = [param.device_sn, '']
@@ -267,7 +243,7 @@ function onDeviceTypeSelect (val: number) {
   getHms()
 }
 
-function onLevelSelect (val: number) {
+function onLevelSelect(val: number) {
   param.level = val
   getHms()
 }

+ 43 - 52
Web/src/components/devices/device-log/DeviceLogUploadRecordDrawer.vue

@@ -1,9 +1,5 @@
 <template>
-  <a-drawer
-    title="设备日志上传记录"
-    placement="right"
-    v-model:visible="sVisible"
-    @update:visible="onVisibleChange"
+  <a-drawer title="设备日志上传记录" placement="right" v-model:visible="sVisible" @update:visible="onVisibleChange"
     :width="800">
     <!-- 设备日志上传记录 -->
     <div class="device-log-upload-record-wrap">
@@ -11,32 +7,32 @@
         <a-button type="primary" @click="onUploadDeviceLog">上传日志</a-button>
       </div>
       <div class="device-log-upload-list">
-        <a-table :columns="deviceLogUploadListColumns"
-                  :scroll="{ x: '100%', y: 600 }"
-                  :data-source="deviceUploadLogState.uploadLogList"
-                  :loading="deviceUploadLogState.loading"
-                  :pagination="deviceUploadLogState.paginationProp"
-                  @change="onDeviceUploadLogTableChange"
-                  rowKey="logs_id">
-         <!-- 设备类型 -->
+        <a-table :columns="deviceLogUploadListColumns" :scroll="{ x: '100%', y: 600 }"
+          :data-source="deviceUploadLogState.uploadLogList" :loading="deviceUploadLogState.loading"
+          :pagination="deviceUploadLogState.paginationProp" @change="onDeviceUploadLogTableChange" rowKey="logs_id">
+          <!-- 设备类型 -->
           <template #device_type="{ record }">
             <div>
-              <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{ DEVICE_NAME[getDeviceInfo(record).parents[0].device_model.device_model_key]}}</div>
-              <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{ DEVICE_NAME[getDeviceInfo(record).hosts[0].device_model.device_model_key]}}</div>
+              <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{
+                DEVICE_NAME[getDeviceInfo(record).parents[0].device_model.device_model_key] }}</div>
+              <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{
+                DEVICE_NAME[getDeviceInfo(record).hosts[0].device_model.device_model_key] }}</div>
             </div>
           </template>
           <!-- 设备sn -->
           <template #device_sn="{ record }">
             <div>
-              <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{ getDeviceInfo(record).parents[0].sn }}</div>
-              <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{ getDeviceInfo(record).hosts[0].sn }}</div>
+              <div v-if="getDeviceInfo(record).parents && getDeviceInfo(record).parents.length > 0">{{
+                getDeviceInfo(record).parents[0].sn }}</div>
+              <div v-if="getDeviceInfo(record).hosts && getDeviceInfo(record).hosts.length > 0">{{
+                getDeviceInfo(record).hosts[0].sn }}</div>
             </div>
           </template>
           <!-- 上传状态 -->
           <template #status="{ record }">
             <div>
               <div>
-                <span class="circle-icon" :style="{backgroundColor: getDeviceLogUploadStatus(record).color}"></span>
+                <span class="circle-icon" :style="{ backgroundColor: getDeviceLogUploadStatus(record).color }"></span>
                 {{ getDeviceLogUploadStatus(record).text }}
               </div>
               <div v-if="record.status === DeviceLogUploadStatusEnum.Uploading">
@@ -48,16 +44,16 @@
           <template #action="{ record }">
             <div class="row-action">
               <a-tooltip title="查看详情">
-                  <FileTextOutlined  @click="showDeviceLogDetail(record)"/>
+                <FileTextOutlined @click="showDeviceLogDetail(record)" />
               </a-tooltip>
               <span v-if="record.status === DeviceLogUploadStatusEnum.Uploading">
                 <a-tooltip title="取消">
-                  <StopOutlined @click="onCancelUploadDeviceLog(record)"/>
+                  <StopOutlined @click="onCancelUploadDeviceLog(record)" />
                 </a-tooltip>
               </span>
               <span v-else>
                 <a-tooltip title="删除">
-                  <DeleteOutlined @click="onDeleteUploadDeviceLog(record)"/>
+                  <DeleteOutlined @click="onDeleteUploadDeviceLog(record)" />
                 </a-tooltip>
               </span>
             </div>
@@ -67,17 +63,12 @@
     </div>
   </a-drawer>
   <!-- 设备日志上传弹框 -->
-  <DeviceLogUploadModal
-     v-model:visible="deviceLogUploadModalVisible"
-     :device="props.device"
-     @upload-log-ok="onUploadLogOk"
-  ></DeviceLogUploadModal>
+  <DeviceLogUploadModal v-model:visible="deviceLogUploadModalVisible" :device="props.device"
+    @upload-log-ok="onUploadLogOk"></DeviceLogUploadModal>
 
   <!-- 设备日志上传详情弹框 -->
-  <DeviceLogDetailModal
-     v-model:visible="deviceLogDetailModalVisible"
-     :deviceLog="currentDeviceLog"
-  ></DeviceLogDetailModal>
+  <DeviceLogDetailModal v-model:visible="deviceLogDetailModalVisible" :deviceLog="currentDeviceLog">
+  </DeviceLogDetailModal>
 </template>
 
 <script lang="ts" setup>
@@ -109,11 +100,11 @@ watchEffect(() => {
   }
 })
 
-function onVisibleChange (sVisible: boolean) {
+function onVisibleChange(sVisible: boolean) {
   setVisible(sVisible)
 }
 
-function setVisible (v: boolean, e?: Event) {
+function setVisible(v: boolean, e?: Event) {
   sVisible.value = v
   emit('update:visible', v, e)
 }
@@ -141,7 +132,7 @@ const deviceUploadLogState = reactive({
 })
 
 // 获取上传的设备日志
-async function getDeviceUploadLogInfo () {
+async function getDeviceUploadLogInfo() {
   deviceUploadLogState.loading = true
   try {
     const { code, data } = await getDeviceUploadLogList({
@@ -163,13 +154,13 @@ async function getDeviceUploadLogInfo () {
 type Pagination = TableState['pagination']
 
 // 获取设备信息
-function getDeviceInfo (deviceLogItem: GetDeviceUploadLogListRsp) {
+function getDeviceInfo(deviceLogItem: GetDeviceUploadLogListRsp) {
   const { device_topo: deviceTopo } = deviceLogItem
   return deviceTopo
 }
 
 // 获取上传状态
-function getDeviceLogUploadStatus (deviceLogItem: GetDeviceUploadLogListRsp) {
+function getDeviceLogUploadStatus(deviceLogItem: GetDeviceUploadLogListRsp) {
   const statusObj = {
     color: '',
     text: ''
@@ -181,7 +172,7 @@ function getDeviceLogUploadStatus (deviceLogItem: GetDeviceUploadLogListRsp) {
 }
 
 // 获取上传进度
-function getLogProgress (deviceLogItem: GetDeviceUploadLogListRsp) {
+function getLogProgress(deviceLogItem: GetDeviceUploadLogListRsp) {
   let percent = 0
   const { logs_progress } = deviceLogItem
   if (logs_progress && logs_progress.length > 0) {
@@ -194,7 +185,7 @@ function getLogProgress (deviceLogItem: GetDeviceUploadLogListRsp) {
 }
 
 // 设备日志上传进度更新
-function onDeviceLogUploadWs (data: DeviceLogUploadInfo) {
+function onDeviceLogUploadWs(data: DeviceLogUploadInfo) {
   const { sn, output } = data
   if (output) {
     const { files, status, logs_id: logId } = output || {}
@@ -219,7 +210,7 @@ function onDeviceLogUploadWs (data: DeviceLogUploadInfo) {
 useDeviceLogUploadProgressEvent(onDeviceLogUploadWs)
 
 // 搜索
-async function onDeviceUploadLogTableChange (page: Pagination) {
+async function onDeviceUploadLogTableChange(page: Pagination) {
   deviceUploadLogState.paginationProp.current = page?.current || 1
   deviceUploadLogState.paginationProp.pageSize = page?.pageSize || 20
   await getDeviceUploadLogInfo()
@@ -229,25 +220,25 @@ async function onDeviceUploadLogTableChange (page: Pagination) {
 const deviceLogDetailModalVisible = ref(false)
 const currentDeviceLog = ref({} as GetDeviceUploadLogListRsp)
 
-function showDeviceLogDetail (deviceLogItem: GetDeviceUploadLogListRsp) {
+function showDeviceLogDetail(deviceLogItem: GetDeviceUploadLogListRsp) {
   if (!deviceLogItem) return
   currentDeviceLog.value = deviceLogItem
   deviceLogDetailModalVisible.value = true
 }
 
 // 取消上传设备日志
-async function onCancelUploadDeviceLog (deviceLogItem: GetDeviceUploadLogListRsp) {
+async function onCancelUploadDeviceLog(deviceLogItem: GetDeviceUploadLogListRsp) {
   Modal.confirm({
     title: '取消日志上传',
     content: '您确认取消设备日志上传吗?',
     okType: 'danger',
-    onOk () {
+    onOk() {
       cancelDeviceLogUploadOk()
     },
   })
 }
 
-async function cancelDeviceLogUploadOk () {
+async function cancelDeviceLogUploadOk() {
   const { code } = await cancelDeviceLogUpload({
     device_sn: props.device?.device_sn || '',
     module_list: [DOMAIN.DOCK, DOMAIN.DRONE],
@@ -259,18 +250,18 @@ async function cancelDeviceLogUploadOk () {
 }
 
 // 删除上传的设备日志
-function onDeleteUploadDeviceLog (deviceLogItem: GetDeviceUploadLogListRsp) {
+function onDeleteUploadDeviceLog(deviceLogItem: GetDeviceUploadLogListRsp) {
   Modal.confirm({
     title: '删除上传日志',
     content: '您确认删除该条已上传设备日志吗?',
     okType: 'danger',
-    onOk () {
+    onOk() {
       deleteUploadDeviceLogOk(deviceLogItem)
     },
   })
 }
 
-async function deleteUploadDeviceLogOk (deviceLogItem: GetDeviceUploadLogListRsp) {
+async function deleteUploadDeviceLogOk(deviceLogItem: GetDeviceUploadLogListRsp) {
   const { code } = await deleteDeviceLogUpload({
     device_sn: props.device?.device_sn || '',
     logs_id: deviceLogItem.logs_id
@@ -283,25 +274,25 @@ async function deleteUploadDeviceLogOk (deviceLogItem: GetDeviceUploadLogListRsp
 // 上传日志
 const deviceLogUploadModalVisible = ref(false)
 
-function onUploadDeviceLog () {
+function onUploadDeviceLog() {
   deviceLogUploadModalVisible.value = true
 }
 
-function onUploadLogOk () {
+function onUploadLogOk() {
   // 刷新列表
   getDeviceUploadLogInfo()
 }
 </script>
 
 <style lang="scss" scoped>
-.device-log-upload-record-wrap{
-  .page-action-row{
+.device-log-upload-record-wrap {
+  .page-action-row {
     display: flex;
     justify-content: space-between;
     width: 100%;
   }
 
-  .device-log-upload-list{
+  .device-log-upload-list {
     padding: 20px 0 10px;
   }
 
@@ -315,10 +306,10 @@ function onUploadLogOk () {
     flex-shrink: 0;
   }
 
-  .row-action{
+  .row-action {
     color: #2d8cf0;
 
-    & > span{
+    &>span {
       margin-right: 10px;
     }
   }

+ 0 - 1
Web/src/components/devices/device-log/use-device-log-upload-progress-event.ts

@@ -5,7 +5,6 @@ import { DeviceLogUploadInfo } from '/@/types/device-log'
 export function useDeviceLogUploadProgressEvent (onDeviceLogUploadWs: (data: DeviceLogUploadInfo) => void): void {
   function handleDeviceLogUploadProgress (payload: any) {
     onDeviceLogUploadWs(payload.data)
-    // eslint-disable-next-line no-unused-expressions
     // console.log('payload', payload.data)
   }
 

+ 0 - 1
Web/src/components/devices/device-upgrade/use-device-upgrade-event.ts

@@ -5,7 +5,6 @@ import { DeviceCmdExecuteInfo, DeviceCmdExecuteStatus } from '/@/types/device-cm
 export function useDeviceUpgradeEvent (onDeviceUpgradeWs: (payload: DeviceCmdExecuteInfo) => void): void {
   function handleDeviceUpgrade (payload: any) {
     onDeviceUpgradeWs(payload.data)
-    // eslint-disable-next-line no-unused-expressions
     // console.log('payload', payload.data)
   }
 

+ 421 - 0
Web/src/components/devices/deviceList/index.vue

@@ -0,0 +1,421 @@
+<template>
+  <div class="device-table-wrap table flex-display flex-column">
+    <a-table :columns="columns" :data-source="data.device" :pagination="paginationProp" @change="refreshData"
+      row-key="device_sn" :expandedRowKeys="expandRows" :row-selection="rowSelection" :rowClassName="rowClassName"
+      :scroll="{ x: 'max-content', y: 600 }" :expandIcon="expandIcon" :loading="loading">
+      <template v-for="col in ['nickname']" #[col]="{ text, record }" :key="col">
+        <div>
+          <a-input v-if="editableData[record.device_sn]" v-model:value="editableData[record.device_sn][col]"
+            style="margin: -5px 0" />
+          <template v-else>
+            <a-tooltip :title="text">
+              {{ text }}
+            </a-tooltip>
+          </template>
+        </div>
+      </template>
+      <template v-for="col in ['sn', 'workspace']" #[col]="{ text }" :key="col">
+        <a-tooltip :title="text">
+          <span>{{ text }}</span>
+        </a-tooltip>
+      </template>
+      <!-- 固件版本 -->
+      <template #firmware_version="{ record }">
+        <span v-if="judgeCurrentType(EDeviceTypeName.Dock)">
+          <DeviceFirmwareUpgrade :device="record" class="table-flex-col" @device-upgrade="onDeviceUpgrade" />
+        </span>
+        <span v-else>
+          {{ record.firmware_version }}
+        </span>
+      </template>
+      <!-- 固件升级 -->
+      <template #firmware_status="{ text }">
+        <div v-if="text === -1">
+          不支持
+        </div>
+        <div v-else>
+          {{ DeviceFirmwareStatus[text] }}
+        </div>
+      </template>
+      <!-- 状态 -->
+      <template #status="{ text }">
+        <span v-if="text" class="flex-row flex-align-center">
+          <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: green;" />
+          <span>在线</span>
+        </span>
+        <span class="flex-row flex-align-center" v-else>
+          <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: red;" />
+          <span>离线</span>
+        </span>
+      </template>
+      <!-- 操作 -->
+      <template #action="{ record }">
+        <div class="editable-row-operations">
+          <!-- 编辑态操作 -->
+          <div v-if="editableData[record.device_sn]">
+            <a-tooltip title="确定">
+              <span @click="save(record)" style="color: #28d445;">
+                <CheckOutlined />
+              </span>
+            </a-tooltip>
+            <a-tooltip title="取消">
+              <span @click="() => delete editableData[record.device_sn]" style="color: #e70102;">
+                <CloseOutlined />
+              </span>
+            </a-tooltip>
+          </div>
+          <!-- 非编辑态操作 -->
+          <div v-else class="flex-align-center flex-row" style="color: #2d8cf0">
+            <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="设备日志">
+              <CloudServerOutlined @click="showDeviceLogUploadRecord(record)" />
+            </a-tooltip>
+            <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="告警信息">
+              <FileSearchOutlined @click="showHms(record)" />
+            </a-tooltip>
+            <a-tooltip title="编辑">
+              <EditOutlined @click="edit(record)" />
+            </a-tooltip>
+            <a-tooltip title="删除">
+              <DeleteOutlined @click="() => { deleteTip = true, deleteSn = record.device_sn }" />
+            </a-tooltip>
+          </div>
+        </div>
+      </template>
+    </a-table>
+    <a-modal v-model:visible="deleteTip" width="450px" :closable="false" centered :okButtonProps="{ danger: true }"
+      @ok="unbind">
+      <p class="pt10 pl20" style="height: 50px;">从工作区中删除设备吗?</p>
+      <template #title>
+        <div class="flex-row flex-justify-center">
+          <span>删除设备</span>
+        </div>
+      </template>
+    </a-modal>
+    <!-- 设备升级 -->
+    <DeviceFirmwareUpgradeModal title="设备升级" v-model:visible="deviceFirmwareUpgradeModalVisible"
+      :device="selectedDevice" @ok="onUpgradeDeviceOk"></DeviceFirmwareUpgradeModal>
+    <!-- 设备日志上传记录 -->
+    <DeviceLogUploadRecordDrawer v-model:visible="deviceLogUploadRecordVisible" :device="currentDevice">
+    </DeviceLogUploadRecordDrawer>
+    <!-- hms 信息 -->
+    <DeviceHmsDrawer v-model:visible="hmsVisible" :device="currentDevice">
+    </DeviceHmsDrawer>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { h, onMounted, reactive, ref, UnwrapRef } from 'vue'
+import { notification } from 'ant-design-vue'
+import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface'
+import { getBindingDevices, unbindDevice, updateDevice } from '/@/api/manage'
+import { EditOutlined, CheckOutlined, CloseOutlined, DeleteOutlined, FileSearchOutlined, CloudServerOutlined } from '@ant-design/icons-vue'
+import { Device, DeviceFirmwareStatus, DeviceFirmwareStatusEnum } from '/@/types/device'
+import DeviceFirmwareUpgrade from '/@/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue'
+import DeviceFirmwareUpgradeModal from '/@/components/devices/device-upgrade/DeviceFirmwareUpgradeModal.vue'
+import { useDeviceFirmwareUpgrade } from '/@/components/devices/device-upgrade/use-device-upgrade'
+import { useDeviceUpgradeEvent } from '/@/components/devices/device-upgrade/use-device-upgrade-event'
+import { DeviceCmdExecuteInfo, DeviceCmdExecuteStatus } from '/@/types/device-cmd'
+import DeviceLogUploadRecordDrawer from '/@/components/devices/device-log/DeviceLogUploadRecordDrawer.vue'
+import DeviceHmsDrawer from '/@/components/devices/device-hms/DeviceHmsDrawer.vue'
+import { IPage } from '/@/api/http/type'
+import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
+
+interface DeviceData {
+  device: Device[]
+}
+
+const loading = ref(true)
+const deleteTip = ref<boolean>(false)
+const deleteSn = ref<string>()
+
+const columns: ColumnProps[] = [
+  {
+    title: '设备型号', dataIndex: 'device_name', width: 150,
+    sorter: (a: Device, b: Device) => a.nickname.localeCompare(b.nickname),
+    className: 'titleStyle'
+  },
+  { title: '设备SN', dataIndex: 'device_sn', width: 100, className: 'titleStyle', ellipsis: true, slots: { customRender: 'sn' } },
+  {
+    title: '设备名称',
+    dataIndex: 'nickname',
+    width: 150,
+    sorter: (a: Device, b: Device) => a.nickname.localeCompare(b.nickname),
+    className: 'titleStyle',
+    ellipsis: true,
+    slots: { customRender: 'nickname' }
+  },
+  { title: '固件版本', dataIndex: 'firmware_version', width: 150, className: 'titleStyle', slots: { customRender: 'firmware_version' } },
+  { title: '固件升级', dataIndex: 'firmware_status', width: 150, className: 'titleStyle', slots: { customRender: 'firmware_status' } },
+  { title: '当前状态', dataIndex: 'status', width: 100, className: 'titleStyle', slots: { customRender: 'status' } },
+  { title: '加入项目时间', dataIndex: 'bound_time', width: 150, sorter: (a: Device, b: Device) => a.bound_time.localeCompare(b.bound_time), className: 'titleStyle' },
+  { title: '最后在线时间', dataIndex: 'login_time', width: 150, sorter: (a: Device, b: Device) => a.login_time.localeCompare(b.login_time), className: 'titleStyle' },
+  {
+    title: '操作',
+    dataIndex: 'actions',
+    fixed: 'right',
+    width: 150,
+    className: 'titleStyle',
+    slots: { customRender: 'action' }
+  },
+]
+
+const expandIcon = (props: any) => {
+  if (judgeCurrentType(EDeviceTypeName.Dock) && !props.expanded) {
+    return h('div',
+      {
+        style: 'border-left: 2px solid rgb(200,200,200); border-bottom: 2px solid rgb(200,200,200); height: 16px; width: 16px; float: left;',
+        class: 'mt-5 ml0',
+      })
+  }
+}
+
+const rowClassName = (record: any, index: number) => {
+  const className = []
+  if ((index & 1) === 0) {
+    className.push('table-striped')
+  }
+  if (record.domain !== EDeviceTypeName.Dock) {
+    className.push('child-row')
+  }
+  return className.toString().replaceAll(',', ' ')
+}
+
+const expandRows = ref<string[]>([])
+const data = reactive<DeviceData>({
+  device: []
+})
+
+const paginationProp = reactive({
+  pageSizeOptions: ['20', '50', '100'],
+  showQuickJumper: true,
+  showSizeChanger: true,
+  pageSize: 50,
+  current: 1,
+  total: 0
+})
+
+// 获取分页信息
+function getPaginationBody() {
+  return {
+    page: paginationProp.current,
+    page_size: paginationProp.pageSize
+  } as IPage
+}
+
+const rowSelection = {
+  onChange: (selectedRowKeys: (string | number)[], selectedRows: []) => {
+    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
+  },
+  onSelect: (record: any, selected: boolean, selectedRows: []) => {
+    console.log(record, selected, selectedRows)
+  },
+  onSelectAll: (selected: boolean, selectedRows: [], changeRows: []) => {
+    console.log(selected, selectedRows, changeRows)
+  },
+  getCheckboxProps: (record: any) => ({
+    disabled: judgeCurrentType(EDeviceTypeName.Dock) && record.domain !== EDeviceTypeName.Dock,
+    style: judgeCurrentType(EDeviceTypeName.Dock) && record.domain !== EDeviceTypeName.Dock ? 'display: none' : ''
+  }),
+}
+
+type Pagination = TableState['pagination']
+
+const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || ''
+const editableData: UnwrapRef<Record<string, Device>> = reactive({})
+
+const current = ref([EDeviceTypeName.Dock])
+
+function judgeCurrentType(type: EDeviceTypeName): boolean {
+  return current.value.indexOf(type) !== -1
+}
+
+// 设备升级
+const {
+  deviceFirmwareUpgradeModalVisible,
+  selectedDevice,
+  onDeviceUpgrade,
+  onUpgradeDeviceOk
+} = useDeviceFirmwareUpgrade(workspaceId)
+
+function onDeviceUpgradeWs(payload: DeviceCmdExecuteInfo) {
+  updateDevicesByWs(data.device, payload)
+}
+
+function updateDevicesByWs(devices: Device[], payload: DeviceCmdExecuteInfo) {
+  if (!devices || devices.length <= 0) {
+    return
+  }
+  for (let i = 0; i < devices.length; i++) {
+    if (devices[i].device_sn === payload.sn) {
+      if (!payload.output) return
+      const { status, progress, ext } = payload.output
+      if (status === DeviceCmdExecuteStatus.Sent || status === DeviceCmdExecuteStatus.InProgress) { // 升级中
+        const rate = ext?.rate ? (ext.rate / 1024).toFixed(2) + 'kb/s' : ''
+        devices[i].firmware_status = DeviceFirmwareStatusEnum.DuringUpgrade
+        devices[i].firmware_progress = (progress?.percent || 0) + '% ' + rate
+      } else { // 终态:成功,失败,超时
+        if (status === DeviceCmdExecuteStatus.Failed || status === DeviceCmdExecuteStatus.Timeout) {
+          notification.error({
+            message: `(${payload.sn}) Upgrade failed`,
+            description: `Error Code: ${payload.result}`,
+            duration: null
+          })
+        }
+        // 拉取列表
+        getDevices(current.value[0], true)
+      }
+      return
+    }
+    if (devices[i].children) {
+      updateDevicesByWs(devices[i].children || [], payload)
+    }
+  }
+}
+
+useDeviceUpgradeEvent(onDeviceUpgradeWs)
+
+// 获取设备列表信息
+function getDevices(domain: number, closeLoading?: boolean) {
+  if (!closeLoading) {
+    loading.value = true
+  }
+  getBindingDevices(workspaceId, getPaginationBody(), domain).then(res => {
+    if (res.code !== 0) {
+      return
+    }
+    const resData: Device[] = res.data.list
+    expandRows.value = []
+    resData.forEach((val: any) => {
+      if (val.children) {
+        val.children = [val.children]
+      }
+      if (judgeCurrentType(EDeviceTypeName.Dock)) {
+        expandRows.value.push(val.device_sn)
+      }
+    })
+    data.device = resData
+    paginationProp.total = res.data.pagination.total
+    paginationProp.current = res.data.pagination.page
+    paginationProp.pageSize = res.data.pagination.page_size
+    loading.value = false
+  })
+}
+
+function refreshData(page: Pagination) {
+  paginationProp.current = page?.current!
+  paginationProp.pageSize = page?.pageSize!
+  getDevices(current.value[0])
+}
+
+// 编辑
+function edit(record: Device) {
+  editableData[record.device_sn] = record
+}
+
+// 保存
+function save(record: Device) {
+  delete editableData[record.device_sn]
+  updateDevice({ nickname: record.nickname }, workspaceId, record.device_sn)
+}
+
+// 解绑
+function unbind() {
+  deleteTip.value = false
+  unbindDevice(deleteSn.value?.toString()!).then(res => {
+    if (res.code !== 0) {
+      return
+    }
+    getDevices(current.value[0])
+  })
+}
+
+const currentDevice = ref({} as Device)
+// 设备日志
+const deviceLogUploadRecordVisible = ref(false)
+function showDeviceLogUploadRecord(dock: Device) {
+  deviceLogUploadRecordVisible.value = true
+  currentDevice.value = dock
+}
+
+// 健康状态
+const hmsVisible = ref<boolean>(false)
+
+function showHms(dock: Device) {
+  hmsVisible.value = true
+  currentDevice.value = dock
+}
+
+onMounted(() => {
+  getDevices(current.value[0])
+})
+</script>
+
+<style lang="scss" scoped>
+.device-table-wrap {
+  .editable-row-operations {
+    div>span {
+      margin-right: 10px;
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.table {
+  background-color: white;
+  margin: 20px;
+  padding: 0 20px;
+}
+
+.table-striped {
+  background-color: #f7f9fa;
+}
+
+.ant-table {
+  border-top: 1px solid rgb(0, 0, 0, 0.06);
+  border-bottom: 1px solid rgb(0, 0, 0, 0.06);
+}
+
+.ant-table-tbody tr td {
+  border: 0;
+}
+
+.ant-table td {
+  white-space: nowrap;
+}
+
+.ant-table-thead tr th {
+  background: white !important;
+  border: 0;
+}
+
+th.ant-table-selection-column {
+  background-color: white !important;
+}
+
+.ant-table-header {
+  background-color: white !important;
+}
+
+.child-row {
+  height: 70px;
+}
+
+.notice {
+  background: $success;
+  overflow: hidden;
+  cursor: pointer;
+}
+
+.caution {
+  background: orange;
+  cursor: pointer;
+  overflow: hidden;
+}
+
+.warn {
+  background: red;
+  cursor: pointer;
+  overflow: hidden;
+}
+</style>

+ 11 - 0
Web/src/components/devices/feedbackRecord/index.vue

@@ -0,0 +1,11 @@
+<template>
+  <div>
+    参考设备变化记录代码
+  </div>
+</template>
+
+<script lang="ts" setup>
+
+</script>
+
+<style lang="scss" scoped></style>

+ 9 - 10
Web/src/components/g-map/DroneControlInfoPanel.vue

@@ -1,14 +1,14 @@
 <template>
-<div class="drone-control-info-wrap">
-  <a-textarea v-model:value="info" placeholder="drc info" :rows="5" disabled/>
-</div>
+  <div class="drone-control-info-wrap">
+    <a-textarea v-model:value="info" placeholder="drc info" :rows="5" disabled />
+  </div>
 </template>
 
 <script lang="ts" setup>
 import { ref, defineProps, watch } from 'vue'
 
 const props = defineProps<{
-    message?: string,
+  message?: string,
 }>()
 
 const info = ref('')
@@ -23,12 +23,11 @@ watch(() => props.message, message => {
 
 <style lang="scss" scoped>
 .drone-control-info-wrap {
-  &::v-deep{
-    textarea.ant-input {
-      background-color: #000;
-      color: #fff;
-      white-space: pre-wrap;
-    }
+
+  :deep(.ant-input) {
+    background-color: #000;
+    color: #fff;
+    white-space: pre-wrap;
   }
 }
 </style>

+ 165 - 193
Web/src/components/g-map/DroneControlPanel.vue

@@ -4,145 +4,141 @@
     <div class="drone-control-box">
       <div class="box">
         <div class="row">
-          <div class="drone-control"><Button :ghost="!flightController" size="small"  @click="onClickFightControl">{{ flightController ? 'Exit Remote Control' : 'Enter Remote Control'}}</Button></div>
+          <div class="drone-control"><Button :ghost="!flightController" size="small" @click="onClickFightControl">{{
+            flightController ? 'Exit Remote Control' : 'Enter Remote Control' }}</Button></div>
         </div>
         <div class="row">
           <div class="drone-control-direction">
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_Q)" @onmouseup="onMouseUp">
-              <template #icon><UndoOutlined /></template><span class="word">Q</span>
+              <template #icon>
+                <UndoOutlined />
+              </template><span class="word">Q</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_W)" @onmouseup="onMouseUp">
-              <template #icon><UpOutlined/></template><span class="word">W</span>
+              <template #icon>
+                <UpOutlined />
+              </template><span class="word">W</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_E)" @onmouseup="onMouseUp">
-              <template #icon><RedoOutlined /></template><span class="word">E</span>
+              <template #icon>
+                <RedoOutlined />
+              </template><span class="word">E</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.ARROW_UP)" @onmouseup="onMouseUp">
-              <template #icon><ArrowUpOutlined /></template>
+              <template #icon>
+                <ArrowUpOutlined />
+              </template>
             </Button>
             <br />
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_A)" @onmouseup="onMouseUp">
-              <template #icon><LeftOutlined/></template><span class="word">A</span>
+              <template #icon>
+                <LeftOutlined />
+              </template><span class="word">A</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_S)" @onmouseup="onMouseUp">
-              <template #icon><DownOutlined/></template><span class="word">S</span>
+              <template #icon>
+                <DownOutlined />
+              </template><span class="word">S</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.KEY_D)" @onmouseup="onMouseUp">
-              <template #icon><RightOutlined/></template><span class="word">D</span>
+              <template #icon>
+                <RightOutlined />
+              </template><span class="word">D</span>
             </Button>
             <Button size="small" ghost @mousedown="onMouseDown(KeyCode.ARROW_DOWN)" @onmouseup="onMouseUp">
-              <template #icon><ArrowDownOutlined /></template>
+              <template #icon>
+                <ArrowDownOutlined />
+              </template>
             </Button>
           </div>
-          <Button type="primary" size="small" danger ghost @click="handleEmergencyStop" >
-            <template #icon><PauseCircleOutlined/></template><span>Break</span>
+          <Button type="primary" size="small" danger ghost @click="handleEmergencyStop">
+            <template #icon>
+              <PauseCircleOutlined />
+            </template><span>Break</span>
           </Button>
         </div>
         <div class="row">
-          <DroneControlPopover
-            :visible="flyToPointPopoverData.visible"
-            :loading="flyToPointPopoverData.loading"
-            @confirm="($event) => onFlyToConfirm(true)"
-            @cancel="($event) =>onFlyToConfirm(false)"
-          >
+          <DroneControlPopover :visible="flyToPointPopoverData.visible" :loading="flyToPointPopoverData.loading"
+            @confirm="($event) => onFlyToConfirm(true)" @cancel="($event) => onFlyToConfirm(false)">
             <template #formContent>
               <div class="form-content">
                 <div>
                   <span class="form-label">latitude:</span>
-                  <a-input-number v-model:value="flyToPointPopoverData.latitude"/>
+                  <a-input-number v-model:value="flyToPointPopoverData.latitude" />
                 </div>
                 <div>
                   <span class="form-label">longitude:</span>
-                  <a-input-number v-model:value="flyToPointPopoverData.longitude"/>
+                  <a-input-number v-model:value="flyToPointPopoverData.longitude" />
                 </div>
                 <div>
                   <span class="form-label">height(m):</span>
-                  <a-input-number v-model:value="flyToPointPopoverData.height"/>
+                  <a-input-number v-model:value="flyToPointPopoverData.height" />
                 </div>
               </div>
             </template>
-            <Button size="small" ghost @click="onShowFlyToPopover" >
+            <Button size="small" ghost @click="onShowFlyToPopover">
               <span>Fly to</span>
             </Button>
           </DroneControlPopover>
-          <Button size="small" ghost @click="onStopFlyToPoint" >
+          <Button size="small" ghost @click="onStopFlyToPoint">
             <span>Stop Fly to</span>
           </Button>
-          <DroneControlPopover
-            :visible="takeoffToPointPopoverData.visible"
-            :loading="takeoffToPointPopoverData.loading"
-            @confirm="($event) => onTakeoffToPointConfirm(true)"
-            @cancel="($event) =>onTakeoffToPointConfirm(false)"
-          >
+          <DroneControlPopover :visible="takeoffToPointPopoverData.visible" :loading="takeoffToPointPopoverData.loading"
+            @confirm="($event) => onTakeoffToPointConfirm(true)" @cancel="($event) => onTakeoffToPointConfirm(false)">
             <template #formContent>
               <div class="form-content">
                 <div>
                   <span class="form-label">latitude:</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.latitude"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.latitude" />
                 </div>
                 <div>
                   <span class="form-label">longitude:</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.longitude"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.longitude" />
                 </div>
                 <div>
                   <span class="form-label">height(m):</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.height"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.height" />
                 </div>
                 <div>
                   <span class="form-label">Safe Takeoff Altitude(m):</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.securityTakeoffHeight"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.securityTakeoffHeight" />
                 </div>
                 <div>
                   <span class="form-label">Return-to-Home Altitude(m):</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.rthAltitude"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.rthAltitude" />
                 </div>
                 <div>
                   <span class="form-label">Lost Action:</span>
-                  <a-select
-                    v-model:value="takeoffToPointPopoverData.rcLostAction"
-                    style="width: 120px"
-                    :options="LostControlActionInCommandFLightOptions"
-                  ></a-select>
+                  <a-select v-model:value="takeoffToPointPopoverData.rcLostAction" style="width: 120px"
+                    :options="LostControlActionInCommandFLightOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">Wayline Lost Action:</span>
-                  <a-select
-                    v-model:value="takeoffToPointPopoverData.exitWaylineWhenRcLost"
-                    style="width: 120px"
-                    :options="WaylineLostControlActionInCommandFlightOptions"
-                  ></a-select>
+                  <a-select v-model:value="takeoffToPointPopoverData.exitWaylineWhenRcLost" style="width: 120px"
+                    :options="WaylineLostControlActionInCommandFlightOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">Return-to-Home Mode:</span>
-                  <a-select
-                    v-model:value="takeoffToPointPopoverData.rthMode"
-                    style="width: 120px"
-                    :options="RthModeInCommandFlightOptions"
-                  ></a-select>
+                  <a-select v-model:value="takeoffToPointPopoverData.rthMode" style="width: 120px"
+                    :options="RthModeInCommandFlightOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">Commander Mode Lost Action:</span>
-                  <a-select
-                    v-model:value="takeoffToPointPopoverData.commanderModeLostAction"
-                    style="width: 120px"
-                    :options="CommanderModeLostActionInCommandFlightOptions"
-                  ></a-select>
+                  <a-select v-model:value="takeoffToPointPopoverData.commanderModeLostAction" style="width: 120px"
+                    :options="CommanderModeLostActionInCommandFlightOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">Commander Flight Mode:</span>
-                  <a-select
-                    v-model:value="takeoffToPointPopoverData.commanderFlightMode"
-                    style="width: 120px"
-                    :options="CommanderFlightModeInCommandFlightOptions"
-                  ></a-select>
+                  <a-select v-model:value="takeoffToPointPopoverData.commanderFlightMode" style="width: 120px"
+                    :options="CommanderFlightModeInCommandFlightOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">Commander Flight Height(m):</span>
-                  <a-input-number v-model:value="takeoffToPointPopoverData.commanderFlightHeight"/>
+                  <a-input-number v-model:value="takeoffToPointPopoverData.commanderFlightHeight" />
                 </div>
               </div>
             </template>
-            <Button size="small" ghost @click="onShowTakeoffToPointPopover" >
+            <Button size="small" ghost @click="onShowTakeoffToPointPopover">
               <span>Take off</span>
             </Button>
             <div v-for="(cmdItem) in cmdList" :key="cmdItem.cmdKey" class="control-cmd-item">
@@ -151,115 +147,95 @@
               </Button>
             </div>
             <div>
-              <Button size="small" ghost @click="openLivestreamAgora" >
+              <Button size="small" ghost @click="openLivestreamAgora">
                 <span>Agora Live</span>
               </Button>
-              <Button size="small" ghost @click="openLivestreamOthers" >
+              <Button size="small" ghost @click="openLivestreamOthers">
                 <span>RTMP/GB28181 Live</span>
               </Button>
             </div>
           </DroneControlPopover>
         </div>
-    </div>
-    <div class="box">
-      <div class="row">
-        <Select v-model:value="payloadSelectInfo.value" style="width: 110px; marginRight: 5px" :options="payloadSelectInfo.options" @change="handlePayloadChange"/>
-        <div class="drone-control">
-          <Button type="primary" size="small" @click="onAuthPayload">Payload Control</Button>
-        </div>
       </div>
-      <div class="row">
-        <DroneControlPopover
-          :visible="gimbalResetPopoverData.visible"
-          :loading="gimbalResetPopoverData.loading"
-          @confirm="($event) => onGimbalResetConfirm(true)"
-          @cancel="($event) =>onGimbalResetConfirm(false)"
-        >
-          <template #formContent>
-            <div class="form-content">
-              <div>
-                <span class="form-label">reset mode:</span>
-                <a-select
-                  v-model:value="gimbalResetPopoverData.resetMode"
-                  style="width: 180px"
-                  :options="GimbalResetModeOptions"
-                ></a-select>
+      <div class="box">
+        <div class="row">
+          <Select v-model:value="payloadSelectInfo.value" style="width: 110px; marginRight: 5px"
+            :options="payloadSelectInfo.options" @change="handlePayloadChange" />
+          <div class="drone-control">
+            <Button type="primary" size="small" @click="onAuthPayload">Payload Control</Button>
+          </div>
+        </div>
+        <div class="row">
+          <DroneControlPopover :visible="gimbalResetPopoverData.visible" :loading="gimbalResetPopoverData.loading"
+            @confirm="($event) => onGimbalResetConfirm(true)" @cancel="($event) => onGimbalResetConfirm(false)">
+            <template #formContent>
+              <div class="form-content">
+                <div>
+                  <span class="form-label">reset mode:</span>
+                  <a-select v-model:value="gimbalResetPopoverData.resetMode" style="width: 180px"
+                    :options="GimbalResetModeOptions"></a-select>
+                </div>
               </div>
-            </div>
-          </template>
-          <Button size="small" ghost @click="onShowGimbalResetPopover">
-            <span>Gimbal Reset</span>
+            </template>
+            <Button size="small" ghost @click="onShowGimbalResetPopover">
+              <span>Gimbal Reset</span>
+            </Button>
+          </DroneControlPopover>
+          <Button size="small" ghost @click="onSwitchCameraMode">
+            <span>Camera Mode Switch</span>
           </Button>
-        </DroneControlPopover>
-        <Button size="small" ghost @click="onSwitchCameraMode">
-          <span>Camera Mode Switch</span>
-        </Button>
-      </div>
-      <div class="row">
-        <Button size="small" ghost @click="onStartCameraRecording">
-          <span>Start Recording</span>
-        </Button>
-        <Button size="small" ghost @click="onStopCameraRecording">
-          <span>Stop Recording</span>
-        </Button>
-      </div>
-      <div class="row">
-        <Button size="small" ghost  @click="onTakeCameraPhoto">
-          <span>Take Photo</span>
-        </Button>
-        <DroneControlPopover
-          :visible="zoomFactorPopoverData.visible"
-          :loading="zoomFactorPopoverData.loading"
-          @confirm="($event) => onZoomFactorConfirm(true)"
-          @cancel="($event) =>onZoomFactorConfirm(false)"
-        >
-          <template #formContent>
-            <div class="form-content">
-              <div>
-                <span class="form-label">camera type:</span>
-                <a-select
-                  v-model:value="zoomFactorPopoverData.cameraType"
-                  style="width: 120px"
-                  :options="ZoomCameraTypeOptions"
-                ></a-select>
-              </div>
-              <div>
-                <span class="form-label">zoom factor:</span>
-                <a-input-number v-model:value="zoomFactorPopoverData.zoomFactor" :min="2" :max="200" />
-              </div>
-            </div>
-          </template>
-          <Button size="small" ghost @click="($event) => onShowZoomFactorPopover()">
-            <span class="word" @click=";">Zoom</span>
+        </div>
+        <div class="row">
+          <Button size="small" ghost @click="onStartCameraRecording">
+            <span>Start Recording</span>
           </Button>
-        </DroneControlPopover>
-        <DroneControlPopover
-            :visible="cameraAimPopoverData.visible"
-            :loading="cameraAimPopoverData.loading"
-            @confirm="($event) => onCameraAimConfirm(true)"
-            @cancel="($event) =>onCameraAimConfirm(false)"
-          >
+          <Button size="small" ghost @click="onStopCameraRecording">
+            <span>Stop Recording</span>
+          </Button>
+        </div>
+        <div class="row">
+          <Button size="small" ghost @click="onTakeCameraPhoto">
+            <span>Take Photo</span>
+          </Button>
+          <DroneControlPopover :visible="zoomFactorPopoverData.visible" :loading="zoomFactorPopoverData.loading"
+            @confirm="($event) => onZoomFactorConfirm(true)" @cancel="($event) => onZoomFactorConfirm(false)">
             <template #formContent>
               <div class="form-content">
                 <div>
                   <span class="form-label">camera type:</span>
-                  <a-select
-                    v-model:value="cameraAimPopoverData.cameraType"
-                    style="width: 120px"
-                    :options="CameraTypeOptions"
-                  ></a-select>
+                  <a-select v-model:value="zoomFactorPopoverData.cameraType" style="width: 120px"
+                    :options="ZoomCameraTypeOptions"></a-select>
+                </div>
+                <div>
+                  <span class="form-label">zoom factor:</span>
+                  <a-input-number v-model:value="zoomFactorPopoverData.zoomFactor" :min="2" :max="200" />
+                </div>
+              </div>
+            </template>
+            <Button size="small" ghost @click="($event) => onShowZoomFactorPopover()">
+              <span class="word" @click=";">Zoom</span>
+            </Button>
+          </DroneControlPopover>
+          <DroneControlPopover :visible="cameraAimPopoverData.visible" :loading="cameraAimPopoverData.loading"
+            @confirm="($event) => onCameraAimConfirm(true)" @cancel="($event) => onCameraAimConfirm(false)">
+            <template #formContent>
+              <div class="form-content">
+                <div>
+                  <span class="form-label">camera type:</span>
+                  <a-select v-model:value="cameraAimPopoverData.cameraType" style="width: 120px"
+                    :options="CameraTypeOptions"></a-select>
                 </div>
                 <div>
                   <span class="form-label">locked:</span>
-                  <a-switch v-model:checked="cameraAimPopoverData.locked"/>
+                  <a-switch v-model:checked="cameraAimPopoverData.locked" />
                 </div>
                 <div>
                   <span class="form-label">x:</span>
-                  <a-input-number v-model:value="cameraAimPopoverData.x" :min="0" :max="1"/>
+                  <a-input-number v-model:value="cameraAimPopoverData.x" :min="0" :max="1" />
                 </div>
                 <div>
                   <span class="form-label">y:</span>
-                  <a-input-number v-model:value="cameraAimPopoverData.y" :min="0" :max="1"/>
+                  <a-input-number v-model:value="cameraAimPopoverData.y" :min="0" :max="1" />
                 </div>
               </div>
             </template>
@@ -267,9 +243,9 @@
               <span class="word" @click=";">AIM</span>
             </Button>
           </DroneControlPopover>
+        </div>
       </div>
     </div>
-    </div>
     <!-- 信息提示 -->
     <DroneControlInfoPanel :message="drcInfo"></DroneControlInfoPanel>
   </div>
@@ -320,7 +296,7 @@ const {
   sendDockControlCmd
 } = useDockControl()
 
-async function sendControlCmd (cmdItem: DeviceCmdItem, index: number) {
+async function sendControlCmd(cmdItem: DeviceCmdItem, index: number) {
   cmdItem.loading = true
   const result = await sendDockControlCmd({
     sn: props.sn,
@@ -350,7 +326,7 @@ const flyToPointPopoverData = reactive({
   maxSpeed: MAX_SPEED,
 })
 
-function onShowFlyToPopover () {
+function onShowFlyToPopover() {
   flyToPointPopoverData.visible = !flyToPointPopoverData.visible
   flyToPointPopoverData.loading = false
   flyToPointPopoverData.latitude = null
@@ -358,7 +334,7 @@ function onShowFlyToPopover () {
   flyToPointPopoverData.height = null
 }
 
-async function onFlyToConfirm (confirm: boolean) {
+async function onFlyToConfirm(confirm: boolean) {
   if (confirm) {
     if (!flyToPointPopoverData.height || !flyToPointPopoverData.latitude || !flyToPointPopoverData.longitude) {
       message.error('Input error')
@@ -381,7 +357,7 @@ async function onFlyToConfirm (confirm: boolean) {
   flyToPointPopoverData.visible = false
 }
 
-async function onStopFlyToPoint () {
+async function onStopFlyToPoint() {
   await stopFlyToPoint(props.sn)
 }
 
@@ -402,7 +378,7 @@ const takeoffToPointPopoverData = reactive({
   commanderFlightHeight: null as null | number,
 })
 
-function onShowTakeoffToPointPopover () {
+function onShowTakeoffToPointPopover() {
   takeoffToPointPopoverData.visible = !takeoffToPointPopoverData.visible
   takeoffToPointPopoverData.loading = false
   takeoffToPointPopoverData.latitude = null
@@ -417,14 +393,14 @@ function onShowTakeoffToPointPopover () {
   takeoffToPointPopoverData.commanderFlightHeight = null
 }
 
-async function onTakeoffToPointConfirm (confirm: boolean) {
+async function onTakeoffToPointConfirm(confirm: boolean) {
   if (confirm) {
     if (!takeoffToPointPopoverData.height ||
-        !takeoffToPointPopoverData.latitude ||
-        !takeoffToPointPopoverData.longitude ||
-        !takeoffToPointPopoverData.securityTakeoffHeight ||
-        !takeoffToPointPopoverData.rthAltitude ||
-        !takeoffToPointPopoverData.commanderFlightHeight) {
+      !takeoffToPointPopoverData.latitude ||
+      !takeoffToPointPopoverData.longitude ||
+      !takeoffToPointPopoverData.securityTakeoffHeight ||
+      !takeoffToPointPopoverData.rthAltitude ||
+      !takeoffToPointPopoverData.commanderFlightHeight) {
       message.error('Input error')
       return
     }
@@ -463,7 +439,7 @@ useMqtt(deviceTopicInfo)
 // })
 const flightController = ref(false)
 
-async function onClickFightControl () {
+async function onClickFightControl() {
   if (flightController.value) {
     exitFlightCOntrol()
     return
@@ -472,7 +448,7 @@ async function onClickFightControl () {
 }
 
 // 进入飞行控制
-async function enterFlightControl () {
+async function enterFlightControl() {
   try {
     const { code, data } = await postDrcEnter({
       client_id: clientId.value,
@@ -497,7 +473,7 @@ async function enterFlightControl () {
 }
 
 // 退出飞行控制
-async function exitFlightCOntrol () {
+async function exitFlightCOntrol() {
   try {
     const { code } = await postDrcExit({
       client_id: clientId.value,
@@ -522,11 +498,11 @@ const {
   resetControlState,
 } = useManualControl(deviceTopicInfo, flightController)
 
-function onMouseDown (type: KeyCode) {
+function onMouseDown(type: KeyCode) {
   handleKeyup(type)
 }
 
-function onMouseUp () {
+function onMouseUp() {
   resetControlState()
 }
 
@@ -611,7 +587,7 @@ const {
   cameraAim,
 } = usePayloadControl()
 
-async function onAuthPayload () {
+async function onAuthPayload() {
   const result = await authPayload(props.sn, payloadSelectInfo.payloadIndex)
   if (result) {
     payloadControlSource.value = ControlSource.A
@@ -624,13 +600,13 @@ const gimbalResetPopoverData = reactive({
   resetMode: null as null | GimbalResetMode,
 })
 
-function onShowGimbalResetPopover () {
+function onShowGimbalResetPopover() {
   gimbalResetPopoverData.visible = !gimbalResetPopoverData.visible
   gimbalResetPopoverData.loading = false
   gimbalResetPopoverData.resetMode = null
 }
 
-async function onGimbalResetConfirm (confirm: boolean) {
+async function onGimbalResetConfirm(confirm: boolean) {
   if (confirm) {
     if (gimbalResetPopoverData.resetMode === null) {
       message.error('Please select reset mode')
@@ -648,7 +624,7 @@ async function onGimbalResetConfirm (confirm: boolean) {
   gimbalResetPopoverData.visible = false
 }
 
-async function onSwitchCameraMode () {
+async function onSwitchCameraMode() {
   if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
     return
   }
@@ -659,21 +635,21 @@ async function onSwitchCameraMode () {
   })
 }
 
-async function onTakeCameraPhoto () {
+async function onTakeCameraPhoto() {
   if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
     return
   }
   await takeCameraPhoto(props.sn, payloadSelectInfo.payloadIndex)
 }
 
-async function onStartCameraRecording () {
+async function onStartCameraRecording() {
   if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
     return
   }
   await startCameraRecording(props.sn, payloadSelectInfo.payloadIndex)
 }
 
-async function onStopCameraRecording () {
+async function onStopCameraRecording() {
   if (!checkPayloadAuth(payloadSelectInfo.controlSource)) {
     return
   }
@@ -687,14 +663,14 @@ const zoomFactorPopoverData = reactive({
   zoomFactor: null as null | number,
 })
 
-function onShowZoomFactorPopover () {
+function onShowZoomFactorPopover() {
   zoomFactorPopoverData.visible = !zoomFactorPopoverData.visible
   zoomFactorPopoverData.loading = false
   zoomFactorPopoverData.cameraType = null
   zoomFactorPopoverData.zoomFactor = null
 }
 
-async function onZoomFactorConfirm (confirm: boolean) {
+async function onZoomFactorConfirm(confirm: boolean) {
   if (confirm) {
     if (!zoomFactorPopoverData.zoomFactor || zoomFactorPopoverData.cameraType === null) {
       message.error('Please input Zoom Factor')
@@ -722,7 +698,7 @@ const cameraAimPopoverData = reactive({
   y: null as null | number,
 })
 
-function onShowCameraAimPopover () {
+function onShowCameraAimPopover() {
   cameraAimPopoverData.visible = !cameraAimPopoverData.visible
   cameraAimPopoverData.loading = false
   cameraAimPopoverData.cameraType = null
@@ -731,15 +707,15 @@ function onShowCameraAimPopover () {
   cameraAimPopoverData.y = null
 }
 
-function openLivestreamOthers () {
+function openLivestreamOthers() {
   store.commit('SET_LIVESTREAM_OTHERS_VISIBLE', true)
 }
 
-function openLivestreamAgora () {
+function openLivestreamAgora() {
   store.commit('SET_LIVESTREAM_AGORA_VISIBLE', true)
 }
 
-async function onCameraAimConfirm (confirm: boolean) {
+async function onCameraAimConfirm(confirm: boolean) {
   if (confirm) {
     if (cameraAimPopoverData.cameraType === null || cameraAimPopoverData.x === null || cameraAimPopoverData.y === null) {
       message.error('Input error')
@@ -772,10 +748,10 @@ watch(() => errorInfo, (errorInfo) => {
 </script>
 
 <style lang='scss' scoped>
-.drone-control-wrapper{
+.drone-control-wrapper {
   // border-bottom: 1px solid #515151;
 
-  .drone-control-header{
+  .drone-control-header {
     font-size: 14px;
     font-weight: 600;
     padding: 10px 10px 0px;
@@ -784,47 +760,43 @@ watch(() => errorInfo, (errorInfo) => {
   .drone-control-box {
     display: flex;
     flex-wrap: 1;
+
     .box {
       width: 50%;
       padding: 5px;
-      border: 0.5px solid rgba(255,255,255,0.3);
+      border: 0.5px solid rgba(255, 255, 255, 0.3);
 
       .row {
         display: flex;
         flex-wrap: wrap;
         padding: 2px;
 
-        + .row{
+        +.row {
           margin-bottom: 6px;
         }
 
-        &::v-deep{
-          .ant-btn{
-            font-size: 12px;
-            padding: 0px 4px;
-            margin-right: 5px;
-          }
+        :deep(.ant-btn) {
+          font-size: 12px;
+          padding: 0px 4px;
+          margin-right: 5px;
         }
       }
 
-      .drone-control{
-         &::v-deep{
+      .drone-control {
+        :deep(.ant-select-single:not(.ant-select-customize-input) .ant-select-selector) {
+          padding: 0 2px;
 
-          .ant-select-single:not(.ant-select-customize-input) .ant-select-selector{
-           padding: 0 2px;
-          }
         }
       }
 
-      .drone-control-direction{
+      .drone-control-direction {
         margin-right: 10px;
 
         .ant-btn {
-          // padding: 0px 1px;
           margin-right: 0;
         }
 
-        .word{
+        .word {
           width: 12px;
           margin-left: 2px;
           font-size: 12px;

+ 0 - 1
Web/src/components/g-map/use-drone-control-ws-event.ts

@@ -76,7 +76,6 @@ export function useDroneControlWsEvent (sn: string, payloadSn: string, funcs?: U
         break
       }
     }
-    // eslint-disable-next-line no-unused-expressions
     // console.log('payload.biz_code', payload.data)
   }
 

+ 93 - 85
Web/src/components/task/CreatePlan.vue

@@ -4,34 +4,41 @@
       Create Plan
     </div>
     <div class="content">
-      <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody" labelAlign="left">
-        <a-form-item label="Plan Name" name="name" :labelCol="{span: 23}">
-          <a-input style="background: black;"  placeholder="Please enter plan name" v-model:value="planBody.name"/>
+      <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody"
+        labelAlign="left">
+        <a-form-item label="Plan Name" name="name" :labelCol="{ span: 23 }">
+          <a-input style="background: black;" placeholder="Please enter plan name" v-model:value="planBody.name" />
         </a-form-item>
         <!-- 航线 -->
-        <a-form-item label="Flight Route" :wrapperCol="{offset: 7}" name="file_id">
-          <router-link
-            :to="{name: 'select-plan'}"
-            @click="selectRoute"
-          >
-          Select Route
+        <a-form-item label="Flight Route" :wrapperCol="{ offset: 7 }" name="file_id">
+          <router-link :to="{ name: 'select-plan' }" @click="selectRoute">
+            Select Route
           </router-link>
         </a-form-item>
         <a-form-item v-if="planBody.file_id" style="margin-top: -15px;">
           <div class="wayline-panel" style="padding-top: 5px;">
             <div class="title">
               <a-tooltip :title="wayline.name">
-                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ wayline.name }}</div>
+                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
+                  {{ wayline.name }}</div>
               </a-tooltip>
-              <div class="ml10"><UserOutlined /></div>
+              <div class="ml10">
+                <UserOutlined />
+              </div>
               <a-tooltip :title="wayline.user_name">
-                <div class="ml5 pr10" style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ wayline.user_name }}</div>
+                <div class="ml5 pr10"
+                  style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{
+                    wayline.user_name }}</div>
               </a-tooltip>
             </div>
             <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
-              <span><RocketOutlined /></span>
+              <span>
+                <RocketOutlined />
+              </span>
               <span class="ml5">{{ DEVICE_NAME[wayline.drone_model_key] }}</span>
-              <span class="ml10"><CameraFilled style="border-top: 1px solid; padding-top: -3px;" /></span>
+              <span class="ml10">
+                <CameraFilled style="border-top: 1px solid; padding-top: -3px;" />
+              </span>
               <span class="ml5" v-for="payload in wayline.payload_model_keys" :key="payload.id">
                 {{ DEVICE_NAME[payload] }}
               </span>
@@ -42,21 +49,21 @@
           </div>
         </a-form-item>
         <!-- 设备 -->
-        <a-form-item label="Device" :wrapperCol="{offset: 10}" v-model:value="planBody.dock_sn" name="dock_sn">
-          <router-link
-            :to="{name: 'select-plan'}"
-            @click="selectDevice"
-          >Select Device</router-link>
+        <a-form-item label="Device" :wrapperCol="{ offset: 10 }" v-model:value="planBody.dock_sn" name="dock_sn">
+          <router-link :to="{ name: 'select-plan' }" @click="selectDevice">Select Device</router-link>
         </a-form-item>
         <a-form-item v-if="planBody.dock_sn" style="margin-top: -15px;">
           <div class="panel" style="padding-top: 5px;">
             <div class="title">
               <a-tooltip :title="dock.nickname">
-                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ dock.nickname }}</div>
+                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
+                  {{ dock.nickname }}</div>
               </a-tooltip>
             </div>
             <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
-              <span><RocketOutlined /></span>
+              <span>
+                <RocketOutlined />
+              </span>
               <span class="ml5">{{ dock.children?.nickname ?? 'No drone' }}</span>
             </div>
           </div>
@@ -65,68 +72,59 @@
         <a-form-item label="Plan Timer" class="plan-timer-form-item">
           <div style="white-space: nowrap;">
             <a-radio-group v-model:value="planBody.task_type" button-style="solid">
-              <a-radio-button v-for="type in TaskTypeOptions" :value="type.value" :key="type.value">{{ type.label }}</a-radio-button>
+              <a-radio-button v-for="type in TaskTypeOptions" :value="type.value" :key="type.value">
+                {{ type.label }}
+              </a-radio-button>
             </a-radio-group>
           </div>
         </a-form-item>
-        <!-- execute date -->
-        <a-form-item label="Date" v-if="planBody.task_type === TaskType.Timed || planBody.task_type === TaskType.Condition" name="select_execute_date" :labelCol="{span: 23}">
-          <a-range-picker
-            v-model:value="planBody.select_execute_date"
-            :disabledDate="(current: Moment) => current < moment().subtract(1, 'days')"
-            format="YYYY-MM-DD"
-            :placeholder="['Start Time', 'End Time']"
-            style="width: 100%;"
-          />
+        <a-form-item label="Date"
+          v-if="planBody.task_type === TaskType.Timed || planBody.task_type === TaskType.Condition"
+          name="select_execute_date" :labelCol="{ span: 23 }">
+          <a-range-picker v-model:value="planBody.select_execute_date"
+            :disabledDate="(current: any) => current < moment().subtract(1, 'days')" format="YYYY-MM-DD"
+            :placeholder="['Start Time', 'End Time']" style="width: 100%;" />
         </a-form-item>
-        <!-- execute time -->
-        <a-form-item label="Time" v-if="planBody.task_type === TaskType.Timed || planBody.task_type === TaskType.Condition"
-          name="select_execute_time" ref="select_execute_time" :labelCol="{span: 23}" :autoLink="false">
-          <div class="mb10 flex-row flex-align-center flex-justify-around" v-for="n in planBody.select_time_number" :key="n">
-            <a-time-picker
-              v-model:value="planBody.select_time[n - 1][0]"
-              format="HH:mm:ss"
-              show-time
-              placeholder="Start Time"
-              :style="planBody.task_type === TaskType.Condition ? 'width: 40%' : 'width: 82%'"
-              @change="() => $refs.select_execute_time.onFieldChange()"
-            />
+        <a-form-item label="Time"
+          v-if="planBody.task_type === TaskType.Timed || planBody.task_type === TaskType.Condition"
+          name="select_execute_time" ref="select_execute_time" :labelCol="{ span: 23 }" :autoLink="false">
+          <div class="mb10 flex-row flex-align-center flex-justify-around" v-for="n in planBody.select_time_number"
+            :key="n">
+            <a-time-picker v-model:value="planBody.select_time[n - 1][0]" format="HH:mm:ss" show-time
+              placeholder="Start Time" :style="planBody.task_type === TaskType.Condition ? 'width: 40%' : 'width: 82%'"
+              @change="() => $refs.select_execute_time.onFieldChange()" />
             <template v-if="planBody.task_type === TaskType.Condition">
               <div><span style="color: white;">-</span></div>
-              <a-time-picker
-                v-model:value="planBody.select_time[n - 1][1]"
-                format="HH:mm:ss"
-                show-time
-                placeholder="End Time"
-                style="width: 40%;"
-              />
+              <a-time-picker v-model:value="planBody.select_time[n - 1][1]" format="HH:mm:ss" show-time
+                placeholder="End Time" style="width: 40%;" />
             </template>
             <div class="ml5" style="font-size:18px">
-              <PlusCircleOutlined class="mr5" style="color: #1890ff" @click="addTime"/>
-              <MinusCircleOutlined :style="planBody.select_time_number === 1 ? 'color: gray' : 'color: red;'" @click="removeTime"/>
+              <PlusCircleOutlined class="mr5" style="color: #1890ff" @click="addTime" />
+              <MinusCircleOutlined :style="planBody.select_time_number === 1 ? 'color: gray' : 'color: red;'"
+                @click="removeTime" />
             </div>
           </div>
         </a-form-item>
         <template v-if="planBody.task_type === TaskType.Condition">
           <!-- battery capacity -->
-          <a-form-item label="Start task when battery level reaches" :labelCol="{span: 23}" name="min_battery_capacity">
+          <a-form-item label="Start task when battery level reaches" :labelCol="{ span: 23 }"
+            name="min_battery_capacity">
             <a-input-number class="width-100" v-model:value="planBody.min_battery_capacity" :min="50" :max="100"
-            :formatter="(value: number) => `${value}%`" :parser="(value: string) => value.replace('%', '')">
+              :formatter="(value: number) => `${value}%`" :parser="(value: string) => value.replace('%', '')">
             </a-input-number>
           </a-form-item>
           <!-- storage capacity -->
-          <a-form-item label="Start task when storage level reaches (MB)" :labelCol="{span: 23}" name="storage_capacity">
+          <a-form-item label="Start task when storage level reaches (MB)" :labelCol="{ span: 23 }"
+            name="storage_capacity">
             <a-input-number v-model:value="planBody.min_storage_capacity" class="width-100">
             </a-input-number>
           </a-form-item>
         </template>
-        <!-- RTH Altitude Relative to Dock -->
-        <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 23}" name="rth_altitude">
+        <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{ span: 23 }" name="rth_altitude">
           <a-input-number v-model:value="planBody.rth_altitude" :min="20" :max="1500" class="width-100" required>
           </a-input-number>
         </a-form-item>
-        <!-- Lost Action -->
-        <a-form-item label="Lost Action" :labelCol="{span: 23}" name="out_of_control_action">
+        <a-form-item label="Lost Action" :labelCol="{ span: 23 }" name="out_of_control_action">
           <div style="white-space: nowrap;">
             <a-radio-group v-model:value="planBody.out_of_control_action" button-style="solid">
               <a-radio-button v-for="action in OutOfControlActionOptions" :value="action.value" :key="action.value">
@@ -146,19 +144,21 @@
       </a-form>
     </div>
   </div>
-  <div v-if="drawerVisible" style="position: absolute; left: 335px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;">
+  <div v-if="drawerVisible"
+    style="position: absolute; left: 335px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;">
     <div>
-      <router-view :name="routeName"/>
+      <router-view :name="routeName" />
     </div>
     <div style="position: absolute; top: 15px; right: 10px;">
-      <a style="color: white;" @click="closePanel"><CloseOutlined /></a>
+      <a style="color: white;" @click="closePanel">
+        <CloseOutlined />
+      </a>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { computed, onMounted, onUnmounted, reactive, ref, toRaw, UnwrapRef } from 'vue'
-import { CloseOutlined, RocketOutlined, CameraFilled, UserOutlined, PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue'
+import { computed, reactive, ref } from 'vue'
 import { ELocalStorageKey, ERouterName } from '/@/types'
 import { useMyStore } from '/@/store'
 import { WaylineType, WaylineFile } from '/@/types/wayline'
@@ -166,7 +166,7 @@ import { Device, DEVICE_NAME } from '/@/types/device'
 import { createPlan, CreatePlan } from '/@/api/wayline'
 import { getRoot } from '/@/root'
 import { TaskType, OutOfControlActionOptions, OutOfControlAction, TaskTypeOptions } from '/@/types/task'
-import moment, { Moment } from 'moment'
+import moment from 'moment';
 import { RuleObject } from 'ant-design-vue/es/form/interface'
 
 const root = getRoot()
@@ -190,9 +190,9 @@ const planBody = reactive({
   file_id: computed(() => store.state?.waylineInfo.id),
   dock_sn: computed(() => store.state?.dockInfo.device_sn),
   task_type: TaskType.Immediate,
-  select_execute_date: [moment(), moment()] as Moment[],
+  select_execute_date: [moment(), moment()] as any,
   select_time_number: 1,
-  select_time: [[]] as Moment[][],
+  select_time: [[]] as any[],
   rth_altitude: '',
   out_of_control_action: OutOfControlAction.ReturnToHome,
   min_battery_capacity: 90 as number,
@@ -209,7 +209,7 @@ const rules = {
   file_id: [{ required: true, message: 'Select Route' }],
   dock_sn: [{ required: true, message: 'Select Device' }],
   select_execute_time: [{
-    validator: async (rule: RuleObject, value: Moment[]) => {
+    validator: async (rule: RuleObject, value: any[]) => {
       validEndTime()
       validStartTime()
       if (planBody.select_time.length < planBody.select_time_number) {
@@ -240,14 +240,14 @@ const rules = {
   out_of_control_action: [{ required: true, message: 'Select Lost Action' }],
 }
 
-function validStartTime (): Error | void {
+function validStartTime(): Error | void {
   for (let i = 0; i < planBody.select_time.length; i++) {
     if (!planBody.select_time[i][0]) {
       throw new Error('Select start time')
     }
   }
 }
-function validEndTime (): Error | void {
+function validEndTime(): Error | void {
   if (TaskType.Condition !== planBody.task_type) return
   for (let i = 0; i < planBody.select_time.length; i++) {
     if (!planBody.select_time[i][1]) {
@@ -258,7 +258,7 @@ function validEndTime (): Error | void {
     }
   }
 }
-function validOverlapped (): Error | void {
+function validOverlapped(): Error | void {
   if (TaskType.Condition !== planBody.task_type) return
   const arr = planBody.select_time.slice()
   arr.sort((a, b) => a[0].unix() - b[0].unix())
@@ -269,7 +269,7 @@ function validOverlapped (): Error | void {
   })
 }
 
-function onSubmit () {
+function onSubmit() {
   console.info(dock, '12131231')
   valueRef.value.validate().then(() => {
     disabled.value = true
@@ -306,32 +306,32 @@ function onSubmit () {
   })
 }
 
-function closePlan () {
+function closePlan() {
   root.$router.push('/' + ERouterName.TASK)
 }
 
-function closePanel () {
+function closePanel() {
   drawerVisible.value = false
   routeName.value = ''
 }
 
-function selectRoute () {
+function selectRoute() {
   drawerVisible.value = true
   routeName.value = 'WaylinePanel'
 }
 
-function selectDevice () {
+function selectDevice() {
   drawerVisible.value = true
   routeName.value = 'DockPanel'
 }
 
-function addTime () {
+function addTime() {
   valueRef.value.validateFields(['select_execute_time']).then(() => {
     planBody.select_time_number++
     planBody.select_time.push([])
   })
 }
-function removeTime () {
+function removeTime() {
   if (planBody.select_time_number === 1) return
   planBody.select_time_number--
   planBody.select_time.splice(planBody.select_time_number)
@@ -370,8 +370,13 @@ function removeTime () {
       margin: 10px;
     }
 
-    form label, input, .ant-input, .ant-calendar-range-picker-separator,
-    .ant-input:hover, .ant-time-picker .anticon, .ant-calendar-picker .anticon {
+    form label,
+    input,
+    .ant-input,
+    .ant-calendar-range-picker-separator,
+    .ant-input:hover,
+    .ant-time-picker .anticon,
+    .ant-calendar-picker .anticon {
       background-color: #232323;
       color: #fff;
     }
@@ -382,12 +387,13 @@ function removeTime () {
 
     .plan-timer-form-item {
 
-      .ant-radio-button-wrapper{
+      .ant-radio-button-wrapper {
         background-color: #232323;
         color: #fff;
         width: 33%;
         text-align: center;
-        &.ant-radio-button-wrapper-checked{
+
+        &.ant-radio-button-wrapper-checked {
           background-color: #1890ff;
         }
       }
@@ -396,11 +402,11 @@ function removeTime () {
 
   .footer {
     display: flex;
-    padding:10px 0;
+    padding: 10px 0;
 
     button {
       width: 45%;
-      color: #fff ;
+      color: #fff;
       border: 0;
     }
   }
@@ -416,6 +422,7 @@ function removeTime () {
   font-size: 13px;
   border-radius: 2px;
   cursor: pointer;
+
   .title {
     display: flex;
     color: white;
@@ -437,6 +444,7 @@ function removeTime () {
   font-size: 13px;
   border-radius: 2px;
   cursor: pointer;
+
   .title {
     display: flex;
     color: white;
@@ -447,4 +455,4 @@ function removeTime () {
     margin: 0px 10px 0 10px;
   }
 }
-</style>
+</style>

+ 34 - 48
Web/src/components/task/TaskPanel.vue

@@ -20,13 +20,13 @@
       <template #status="{ record }">
         <div>
           <div class="flex-display flex-align-center">
-            <span class="circle-icon" :style="{backgroundColor: formatTaskStatus(record).color}"></span>
+            <span class="circle-icon" :style="{ backgroundColor: formatTaskStatus(record).color }"></span>
             {{ formatTaskStatus(record).text }}
-            <a-tooltip v-if="!!record.code" placement="bottom" arrow-point-at-center >
+            <a-tooltip v-if="!!record.code" placement="bottom" arrow-point-at-center>
               <template #title>
-              <div>{{ getCodeMessage(record.code) }}</div>
+                <div>{{ getCodeMessage(record.code) }}</div>
               </template>
-              <exclamation-circle-outlined class="ml5" :style="{color: commonColor.WARN, fontSize: '16px' }"/>
+              <exclamation-circle-outlined class="ml5" :style="{ color: commonColor.WARN, fontSize: '16px' }" />
             </a-tooltip>
           </div>
           <div v-if="record.status === TaskStatus.Carrying">
@@ -42,20 +42,22 @@
       <template #lostAction="{ record }">
         <div>{{ formatLostAction(record) }}</div>
       </template>
-     <!-- 媒体上传状态 -->
+      <!-- 媒体上传状态 -->
       <template #media_upload="{ record }">
         <div>
           <div class="flex-display flex-align-center">
-            <span class="circle-icon" :style="{backgroundColor: formatMediaTaskStatus(record).color}"></span>
+            <span class="circle-icon" :style="{ backgroundColor: formatMediaTaskStatus(record).color }"></span>
             {{ formatMediaTaskStatus(record).text }}
           </div>
           <div class="pl15">
             {{ formatMediaTaskStatus(record).number }}
-            <a-tooltip v-if="formatMediaTaskStatus(record).status === MediaStatus.ToUpload" placement="bottom" arrow-point-at-center >
+            <a-tooltip v-if="formatMediaTaskStatus(record).status === MediaStatus.ToUpload" placement="bottom"
+              arrow-point-at-center>
               <template #title>
-              <div>Upload now</div>
+                <div>Upload now</div>
               </template>
-              <UploadOutlined class="ml5" :style="{color: commonColor.BLUE, fontSize: '16px' }"  @click="onUploadMediaFileNow(record.job_id)"/>
+              <UploadOutlined class="ml5" :style="{ color: commonColor.BLUE, fontSize: '16px' }"
+                @click="onUploadMediaFileNow(record.job_id)" />
             </a-tooltip>
           </div>
         </div>
@@ -63,31 +65,16 @@
       <!-- 操作 -->
       <template #action="{ record }">
         <div class="action-area">
-          <a-popconfirm
-            v-if="record.status === TaskStatus.Wait"
-            title="Are you sure you want to delete flight task?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="onDeleteTask(record.job_id)"
-          >
+          <a-popconfirm v-if="record.status === TaskStatus.Wait" title="Are you sure you want to delete flight task?"
+            ok-text="Yes" cancel-text="No" @confirm="onDeleteTask(record.job_id)">
             <a-button type="primary" size="small">Delete</a-button>
           </a-popconfirm>
-          <a-popconfirm
-            v-if="record.status === TaskStatus.Carrying"
-            title="Are you sure you want to suspend?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="onSuspendTask(record.job_id)"
-          >
+          <a-popconfirm v-if="record.status === TaskStatus.Carrying" title="Are you sure you want to suspend?"
+            ok-text="Yes" cancel-text="No" @confirm="onSuspendTask(record.job_id)">
             <a-button type="primary" size="small">Suspend</a-button>
           </a-popconfirm>
-          <a-popconfirm
-            v-if="record.status === TaskStatus.Paused"
-            title="Are you sure you want to resume?"
-            ok-text="Yes"
-            cancel-text="No"
-            @confirm="onResumeTask(record.job_id)"
-          >
+          <a-popconfirm v-if="record.status === TaskStatus.Paused" title="Are you sure you want to resume?"
+            ok-text="Yes" cancel-text="No" @confirm="onResumeTask(record.job_id)">
             <a-button type="primary" size="small">Resume</a-button>
           </a-popconfirm>
         </div>
@@ -97,10 +84,9 @@
 </template>
 
 <script setup lang="ts">
-import { reactive, ref } from '@vue/reactivity'
 import { message } from 'ant-design-vue'
 import { TableState } from 'ant-design-vue/lib/table/interface'
-import { onMounted } from 'vue'
+import { onMounted, reactive} from 'vue'
 import { IPage } from '/@/api/http/type'
 import { deleteTask, updateTaskStatus, UpdateTaskStatus, getWaylineJobs, Task, uploadMediaFileNow } from '/@/api/wayline'
 import { useMyStore } from '/@/store'
@@ -201,7 +187,7 @@ const plansData = reactive({
 const { formatTaskType, formatTaskTime, formatLostAction, formatTaskStatus, formatMediaTaskStatus } = useFormatTask()
 
 // 设备任务执行进度更新
-function onTaskProgressWs (data: TaskProgressInfo) {
+function onTaskProgressWs(data: TaskProgressInfo) {
   const { bid, output } = data
   if (output) {
     const { status, progress } = output || {}
@@ -220,7 +206,7 @@ function onTaskProgressWs (data: TaskProgressInfo) {
 }
 
 // 媒体上传进度更新
-function onTaskMediaProgressWs (data: MediaStatusProgressInfo) {
+function onTaskMediaProgressWs(data: MediaStatusProgressInfo) {
   const { media_count: mediaCount, uploaded_count: uploadedCount, job_id: jobId } = data
   if (isNaN(mediaCount) || isNaN(uploadedCount) || !jobId) {
     return
@@ -236,7 +222,7 @@ function onTaskMediaProgressWs (data: MediaStatusProgressInfo) {
   taskItem.uploaded_count = uploadedCount
 }
 
-function onoTaskMediaHighestPriorityWS (data: TaskMediaHighestPriorityProgressInfo) {
+function onoTaskMediaHighestPriorityWS(data: TaskMediaHighestPriorityProgressInfo) {
   const { pre_job_id: preJobId, job_id: jobId } = data
   const preTaskItem = plansData.data.find(task => task.job_id === preJobId)
   const taskItem = plansData.data.find(task => task.job_id === jobId)
@@ -248,7 +234,7 @@ function onoTaskMediaHighestPriorityWS (data: TaskMediaHighestPriorityProgressIn
   }
 }
 
-function getCodeMessage (code: number) {
+function getCodeMessage(code: number) {
   return getErrorMessage(code) + `(code: ${code})`
 }
 
@@ -262,7 +248,7 @@ onMounted(() => {
   getPlans()
 })
 
-function getPlans () {
+function getPlans() {
   getWaylineJobs(workspaceId, body).then(res => {
     if (res.code !== 0) {
       return
@@ -273,14 +259,14 @@ function getPlans () {
   })
 }
 
-function refreshData (page: Pagination) {
+function refreshData(page: Pagination) {
   body.page = page?.current!
   body.page_size = page?.pageSize!
   getPlans()
 }
 
 // 删除任务
-async function onDeleteTask (jobId: string) {
+async function onDeleteTask(jobId: string) {
   const { code } = await deleteTask(workspaceId, {
     job_id: jobId
   })
@@ -291,7 +277,7 @@ async function onDeleteTask (jobId: string) {
 }
 
 // 挂起任务
-async function onSuspendTask (jobId: string) {
+async function onSuspendTask(jobId: string) {
   const { code } = await updateTaskStatus(workspaceId, {
     job_id: jobId,
     status: UpdateTaskStatus.Suspend
@@ -303,7 +289,7 @@ async function onSuspendTask (jobId: string) {
 }
 
 // 解除挂起任务
-async function onResumeTask (jobId: string) {
+async function onResumeTask(jobId: string) {
   const { code } = await updateTaskStatus(workspaceId, {
     job_id: jobId,
     status: UpdateTaskStatus.Resume
@@ -315,7 +301,7 @@ async function onResumeTask (jobId: string) {
 }
 
 // 立即上传媒体
-async function onUploadMediaFileNow (jobId: string) {
+async function onUploadMediaFileNow(jobId: string) {
   const { code } = await uploadMediaFileNow(workspaceId, jobId)
   if (code === 0) {
     message.success('Upload Media File successfully')
@@ -328,17 +314,16 @@ async function onUploadMediaFileNow (jobId: string) {
 .plan-panel-wrapper {
   width: 100%;
   padding: 16px;
+
   .plan-table {
     background: #fff;
     margin-top: 10px;
   }
-  .action-area {
 
-    &::v-deep {
-      .ant-btn {
-        margin-right: 10px;
-        margin-bottom: 10px;
-      }
+  .action-area {
+    :deep(.ant-btn) {
+      margin-right: 10px;
+      margin-bottom: 10px;
     }
   }
 
@@ -352,6 +337,7 @@ async function onUploadMediaFileNow (jobId: string) {
     flex-shrink: 0;
   }
 }
+
 .header {
   width: 100%;
   height: 60px;

+ 2 - 3
Web/src/components/task/use-task-ws-event.ts

@@ -9,8 +9,8 @@ export interface UseTaskWsEventParams {
   onoTaskMediaHighestPriorityWS: (data: TaskMediaHighestPriorityProgressInfo) => void
 }
 
-export function useTaskWsEvent (funcs: UseTaskWsEventParams): void {
-  function handleTaskWsEvent (payload: any) {
+export function useTaskWsEvent(funcs: UseTaskWsEventParams): void {
+  function handleTaskWsEvent(payload: any) {
     if (!payload) {
       return
     }
@@ -29,7 +29,6 @@ export function useTaskWsEvent (funcs: UseTaskWsEventParams): void {
         break
       }
     }
-    // eslint-disable-next-line no-unused-expressions
     // console.log('payload', payload.data)
   }
 

+ 0 - 9
Web/src/env.d.ts

@@ -1,9 +0,0 @@
-// Environment variable definition
-// https://cn.vitejs.dev/guide/env-and-mode.html#env-files
-
-interface ImportMetaEnv {
-  VITE_APP_ENVIRONMENT: 'DEV' | 'STAG' | 'UAT' | 'PROD',
-  // api gateway
-  VITE_APP_APIGATEWAY_BACKEND_HOST: string
-  // More environment variables...
-}

+ 1 - 1
Web/src/hooks/use-connect-websocket.ts

@@ -7,7 +7,7 @@ import { getWebsocketUrl } from '/@/websocket/util/config'
  * 接收一个message函数
  * @param messageHandler
  */
-export function useConnectWebSocket (messageHandler: MessageHandler) {
+export function useConnectWebSocket(messageHandler: MessageHandler) {
   const webSocket = new ConnectWebSocket(getWebsocketUrl())
 
   onMounted(() => {

+ 2 - 2
Web/src/hooks/use-map-tool.ts

@@ -1,12 +1,12 @@
 import { GeojsonCoordinate } from '../utils/genjson'
 import { getRoot } from '/@/root'
 
-export function useMapTool () {
+export function useMapTool() {
   const root = getRoot()
   const map = root.$map
   const AMap = root.$aMap
 
-  function panTo (coordinate: GeojsonCoordinate) {
+  function panTo(coordinate: GeojsonCoordinate) {
     map.panTo(coordinate, 100)
     map.setZoom(18, false, 100)
   }

+ 8 - 8
Web/src/hooks/use-mouse-tool.ts

@@ -6,7 +6,7 @@ import { MapDoodleEnum } from '/@/types/map-enum'
 import { EFlightAreaType } from '../types/flight-area'
 import { message } from 'ant-design-vue'
 
-export function useMouseTool () {
+export function useMouseTool() {
   const root = getRoot()
 
   const state = reactive({
@@ -19,7 +19,7 @@ export function useMouseTool () {
     [EFlightAreaType.DFENCE]: '#19be6b',
     [EFlightAreaType.NFZ]: '#ff0000',
   }
-  function drawPin (type:MapDoodleType, getDrawCallback:Function) {
+  function drawPin(type: MapDoodleType, getDrawCallback: Function) {
     root?.$mouseTool.marker({
       title: type + state.pinNum,
       icon: pin2d8cf0,
@@ -28,7 +28,7 @@ export function useMouseTool () {
     root?.$mouseTool.on('draw', getDrawCallback)
   }
 
-  function drawPolyline (type:MapDoodleType, getDrawCallback:Function) {
+  function drawPolyline(type: MapDoodleType, getDrawCallback: Function) {
     root?.$mouseTool.polyline({
       strokeColor: '#2d8cf0',
       strokeOpacity: 1,
@@ -39,7 +39,7 @@ export function useMouseTool () {
     root?.$mouseTool.on('draw', getDrawCallback)
   }
 
-  function drawPolygon (type:MapDoodleType, getDrawCallback:Function) {
+  function drawPolygon(type: MapDoodleType, getDrawCallback: Function) {
     root?.$mouseTool.polygon({
       strokeColor: '#2d8cf0',
       strokeOpacity: 1,
@@ -51,12 +51,12 @@ export function useMouseTool () {
     root?.$mouseTool.on('draw', getDrawCallback)
   }
 
-  function drawOff (type:MapDoodleType) {
+  function drawOff(type: MapDoodleType) {
     root?.$mouseTool.close()
     root?.$mouseTool.off('draw')
   }
 
-  function drawFlightAreaPolygon (type: EFlightAreaType, getDrawFlightAreaCallback: Function) {
+  function drawFlightAreaPolygon(type: EFlightAreaType, getDrawFlightAreaCallback: Function) {
     root?.$mouseTool.polygon({
       strokeColor: flightAreaColorMap[type],
       strokeOpacity: 1,
@@ -73,7 +73,7 @@ export function useMouseTool () {
     root?.$mouseTool.on('draw', getDrawFlightAreaCallback)
   }
 
-  function drawFlightAreaCircle (type: EFlightAreaType, getDrawFlightAreaCallback: Function) {
+  function drawFlightAreaCircle(type: EFlightAreaType, getDrawFlightAreaCallback: Function) {
     root?.$mouseTool.circle({
       strokeColor: flightAreaColorMap[type],
       strokeOpacity: 1,
@@ -90,7 +90,7 @@ export function useMouseTool () {
     root?.$mouseTool.on('draw', getDrawFlightAreaCallback)
   }
 
-  function mouseTool (type: MapDoodleType, getDrawCallback: Function, flightAreaType?: EFlightAreaType) {
+  function mouseTool(type: MapDoodleType, getDrawCallback: Function, flightAreaType?: EFlightAreaType) {
     state.currentType = type
     if (flightAreaType) {
       switch (type) {

+ 7 - 7
Web/src/main.ts

@@ -1,18 +1,18 @@
 import App from './App.vue'
 import router from './router'
-import { antComponents } from './antd'
-import { CommonComponents } from './use-common-components'
-import 'virtual:svg-icons-register'
 import store, { storeKey } from './store'
 import { createInstance } from '/@/root'
 import { useDirectives } from './directives'
-
+import Antd from 'ant-design-vue';
+import svgIcon from '/@/components/svgIcon.vue'
+import 'ant-design-vue/dist/antd.css'
 import '/@/styles/index.scss'
+
 const app = createInstance(App)
 
 app.use(store, storeKey)
 app.use(router)
-app.use(CommonComponents)
-app.use(antComponents)
+app.use(Antd)
+app.component('svg-icon', svgIcon)
 app.use(useDirectives)
-app.mount('#demo-app')
+app.mount('#root')

+ 67 - 51
Web/src/pages/page-pilot/pilot-home.vue

@@ -7,110 +7,122 @@
             <a-avatar :size="60" :src="cloudapi">
             </a-avatar>
           </a-layout-sider>
-          <a-layout-content style="margin-left: 1vw;" @click="showStatus">
+          <a-layout-content style="margin-left: 1vw;">
             <div style="height: 50%;">
-              <span style="font-size: 16px; font-weight: bolder">{{ workspaceName }}</span>
-              <RightOutlined style="float: right; margin-top: 5px; color: #8894a0" />
+              <a-dropdown :trigger="['click']">
+                <span style="font-size: 16px; font-weight: bolder">{{ workspaceName }}</span>
+                <template #overlay>
+                  <a-menu>
+                    <a-menu-item key="1">
+                      项目编号0001
+                    </a-menu-item>
+                    <a-menu-item key="2">
+                      项目编号0002
+                    </a-menu-item>
+                    <a-menu-item key="3">
+                      项目编号0003
+                    </a-menu-item>
+                  </a-menu>
+                </template>
+              </a-dropdown>
+              <RightOutlined style="float: right; margin-top: 5px; color: #8894a0" @click="showStatus" />
             </div>
             <div style="height: 50%;">
               <CloudSyncOutlined v-if="thingState === EStatusValue.CONNECTED" style="color: #75c5f6" />
-              <SyncOutlined spin v-else/>
+              <SyncOutlined spin v-else />
               <span style="color: #737373; margin-left: 3px;">{{ thingState }}</span>
             </div>
-            <a-drawer  placement="right" v-model:visible="drawerVisible" width="340px">
+            <a-drawer placement="right" v-model:visible="drawerVisible" width="340px">
               <div class="mb10 flex-row flex-justify-center flex-align-center">
-                <p class="fz14" style="font-weight: 100;">Module State</p>
+                <p class="fz14" style="font-weight: 100;">
+                  模块状态
+                </p>
               </div>
-              <div class= "width-100 mb10 flex-align-start" v-for="m in modules" :key="m.name" style="height: 30px;">
-
-                <div class="ml5" style="float: left; color: #000000;">{{m.name}}:</div>
+              <div class="width-100 mb10 flex-align-start" v-for="m in modules" :key="m.name" style="height: 30px;">
+                <div class="ml5" style="float: left; color: #000000;">{{ m.name }}:</div>
                 <div class="ml10" style="float: right; margin-bottom: 8px;">
-                  <span :key="m.state" :class="m.state.value === EStatusValue.CONNECTED ? 'green' : 'red'">{{ m.state.value }}&nbsp;</span>
-                  <a-button-group >
-                  <a-button class="ml5" type="primary" size="small" @click.stop="moduleInstall(m)">install</a-button>
-                  <a-button class="ml5 mr5" type="danger" size="small" @click.stop="moduleUninstall(m)">uninstall</a-button>
+                  <span :key="m.state" :class="m.state.value === EStatusValue.CONNECTED ? 'green' : 'red'">{{
+                    m.state.value }}&nbsp;</span>
+                  <a-button-group>
+                    <a-button class="ml5" type="primary" size="small" @click.stop="moduleInstall(m)">安装</a-button>
+                    <a-button class="ml5 mr5" type="danger" size="small" @click.stop="moduleUninstall(m)">卸载</a-button>
                   </a-button-group>
                 </div>
                 <a-divider />
-
               </div>
             </a-drawer>
           </a-layout-content>
-
         </a-layout>
-        <a-divider  style="height: 2px; background-color: #f5f5f5; margin-top: 3vh;" />
-
+        <a-divider style="height: 2px; background-color: #f5f5f5; margin-top: 3vh;" />
         <a-button id="exitBtn" class="fz18" @click="confirmAgain"
-        style="width: 10vw; height: 10vh; position: fixed; bottom: 13vh; left: 15vw; background-color: #e6e6e6; color: red; border: 0;"
-        type="primary">Exit
+          style="width: 10vw; height: 10vh; position: fixed; bottom: 13vh; left: 15vw; background-color: #e6e6e6; color: red; border: 0;"
+          type="primary">
+          退出
         </a-button>
         <a-modal v-model:visible="exitVisible" width="300px" :closable="false">
           <template #footer>
-            <a-button type="text" style="width: 48%; float: left;" @click="onBack">Cancel</a-button>
-            <a-button type="text" style="width: 48%;" @click="onExit">Exit</a-button>
+            <a-button type="text" style="width: 48%; float: left;" @click="onBack">取消</a-button>
+            <a-button type="text" style="width: 48%;" @click="onExit">确定</a-button>
           </template>
-          <p>Data will not be synchronized between DJI Pilot and this server after exiting.</p>
+          <p>退出后,大疆无人机与该服务器之间的数据将不会同步</p>
         </a-modal>
       </div>
     </a-layout-sider>
     <a-layout-content class="right flex-column">
       <div class="mb5">
-        <span class="ml5" style="color: #939393;">Serial Number</span>
+        <span class="ml5" style="color: #939393;">序列号</span>
       </div>
       <div class="fz16" style="background-color: white; border-radius: 4px;">
         <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle">
           <a-col :span="1"></a-col>
-            <a-col :span="9">
-            Remote Control Sn
-            </a-col>
+          <a-col :span="9">
+            遥控器SN
+          </a-col>
           <a-col :span="13" class="flex-align-end flex-column">
             <span style="color: #737373">{{ device.data.gateway_sn }}</span>
           </a-col>
         </a-row>
-        <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" v-if="device.data.online_status && device.data.sn">
+        <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle"
+          v-if="device.data.online_status && device.data.sn">
           <a-col :span="1"></a-col>
           <a-col :span="9">Aircraft Sn</a-col>
-          <a-col :span="13" class="flex-align-end flex-column" >
+          <a-col :span="13" class="flex-align-end flex-column">
             <span style="color: #737373">{{ device.data.sn }}</span>
           </a-col>
         </a-row>
       </div>
       <div class="mt5 mb5">
-        <span class="ml5" style="color: #939393;">Settings</span>
+        <span class="ml5" style="color: #939393;">设置</span>
       </div>
       <div class="fz16" style="background-color: white; border-radius: 4px;">
-        <a-row v-if="device.data.online_status && device.data.sn" style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice">
+        <a-row v-if="device.data.online_status && device.data.sn"
+          style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice">
           <a-col :span="1"></a-col>
           <a-col :span="11">
-            Device Binding
+            设备绑定
           </a-col>
           <a-col :span="10" style="text-align: right">
             <span v-if="device.data.bound_status" style="color: #737373">Aircraft bound</span>
             <span v-else style="color: #737373">Aircraft not bound</span>
           </a-col>
-          <a-col :span="2" class="flex-align-center flex-column" >
+          <a-col :span="2" class="flex-align-center flex-column">
             <RightOutlined style="color: #8894a0; font-size: 20px;" />
           </a-col>
         </a-row>
         <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="onMediaSetting">
           <a-col :span="1"></a-col>
           <a-col :span="21">
-            Media File Upload
+            上传媒体
           </a-col>
-          <a-col :span="2" class="flex-align-center flex-column" >
+          <a-col :span="2" class="flex-align-center flex-column">
             <RightOutlined style="color: #8894a0; font-size: 20px;" />
           </a-col>
         </a-row>
         <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="onLiveshareSetting">
           <a-col :span="1"></a-col>
-          <a-col :span="21">Livestream Manually</a-col>
-          <a-col :span="2" class="flex-align-center flex-column">
-            <RightOutlined style="color: #8894a0; font-size: 20px;" />
+          <a-col :span="21">
+            手动直播
           </a-col>
-        </a-row>
-        <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="onOpen3rdApp">
-          <a-col :span="1"></a-col>
-          <a-col :span="21">Open 3rd Party APP</a-col>
           <a-col :span="2" class="flex-align-center flex-column">
             <RightOutlined style="color: #8894a0; font-size: 20px;" />
           </a-col>
@@ -120,15 +132,14 @@
   </a-layout>
 </template>
 <script lang="ts" setup>
-import { message, Popconfirm } from 'ant-design-vue'
-import { onMounted, onUnmounted, reactive, ref, watch } from 'vue'
-import { CURRENT_CONFIG } from '/@/api/http/config'
+import { message } from 'ant-design-vue'
+import { onMounted, reactive, ref } from 'vue'
 import { BindBody, bindDevice, getDeviceBySn, getPlatformInfo, getUserInfo } from '/@/api/manage'
 import apiPilot, { ApiParam, MapParam, ThingParam, WsParam } from '/@/api/pilot-bridge'
 import { getRoot } from '/@/root'
 import { EBizCode, EComponentName, EDownloadOwner, ELocalStorageKey, ERouterName, EStatusValue } from '/@/types'
 import cloudapi from '/@/assets/icons/cloudapi.png'
-import { RightOutlined, CloudOutlined, CloudSyncOutlined, SyncOutlined } from '@ant-design/icons-vue'
+import { SwapOutlined, RightOutlined, CloudSyncOutlined, SyncOutlined } from '@ant-design/icons-vue'
 import { useMyStore } from '/@/store'
 import { DeviceStatus } from '/@/types/device'
 import { useConnectWebSocket } from '/@/hooks/use-connect-websocket'
@@ -400,7 +411,7 @@ const showStatus = async () => {
   drawerVisible.value = true
 }
 
-function setWorkspaceInfo () {
+function setWorkspaceInfo() {
   if (localStorage.getItem(ELocalStorageKey.WorkspaceName)) {
     apiPilot.setPlatformMessage(
       '' + localStorage.getItem(ELocalStorageKey.PlatformName),
@@ -427,7 +438,7 @@ function setWorkspaceInfo () {
   })
 }
 
-function refreshStatus () {
+function refreshStatus() {
   thingState.value = apiPilot.thingGetConnectState() ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
   apiState.value = apiPilot.isComponentLoaded(EComponentName.Api) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
   liveState.value = apiPilot.isComponentLoaded(EComponentName.Liveshare) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
@@ -440,7 +451,7 @@ function refreshStatus () {
   waylineState.value = apiPilot.isComponentLoaded(EComponentName.Mission) ? EStatusValue.CONNECTED : EStatusValue.DISCONNECT
 }
 
-function moduleInstall (m: any) {
+function moduleInstall(m: any) {
   let param
   switch (m.module) {
     case EComponentName.Thing:
@@ -476,13 +487,13 @@ function moduleInstall (m: any) {
   refreshStatus()
 }
 
-function moduleUninstall (m: any) {
+function moduleUninstall(m: any) {
   message.info('uninstall ' + m.module)
   apiPilot.unloadComponent(m.module)
   refreshStatus()
 }
 
-function getDeviceInfo () {
+function getDeviceInfo() {
   if (!device.data.sn || device.data.sn === EStatusValue.DISCONNECT) {
     return
   }
@@ -501,18 +512,21 @@ function getDeviceInfo () {
 
 <style lang="scss" scoped>
 @import '/@/styles/index.scss';
+
 .page {
   display: flex;
   position: absolute;
   transition: width 0.2s ease;
   height: 100%;
   width: 100%;
+
   .left {
     height: 90%;
     background-color: white;
     margin-top: 6vh;
     margin-left: 2vh;
   }
+
   .right {
     height: 90%;
     margin-top: 6vh;
@@ -520,12 +534,15 @@ function getDeviceInfo () {
     margin-right: 5vh;
   }
 }
+
 .green {
   color: green
 }
+
 .red {
   color: red;
 }
+
 #exitBtn:hover :active {
   background-color: rgb(77, 75, 75);
   width: 10vw;
@@ -535,5 +552,4 @@ function getDeviceInfo () {
   left: 15vw;
   line-height: 10vh;
 }
-
 </style>

+ 22 - 36
Web/src/pages/page-pilot/pilot-index.vue

@@ -1,42 +1,26 @@
 <template>
   <div class="login flex-column flex-justify-center flex-align-center m0 b0">
-    <a-image
-      style="width: 17vw; height: 10vw; margin-bottom: 50px"
-      :src="djiLogo"
-    />
-    <p class="logo fz35 pb50">Pilot Cloud API Demo</p>
-    <a-form
-      layout="inline"
-      :model="formState"
-      class="flex-row flex-justify-center flex-align-center"
-    >
+    <a-image style="width: 17vw; height: 10vw; margin-bottom: 50px" :src="djiLogo" />
+    <p class="logo fz35 pb50">上云无人机管理平台</p>
+    <a-form layout="inline" :model="formState" class="flex-row flex-justify-center flex-align-center">
       <a-form-item>
-        <a-input v-model:value="formState.username" placeholder="Username">
-          <template #prefix
-            ><UserOutlined style="color: rgba(0, 0, 0, 0.25)"
-          /></template>
+        <a-input v-model:value="formState.username" placeholder="账号">
+          <template #prefix>
+            <UserOutlined style="color: rgba(0, 0, 0, 0.25)" />
+          </template>
         </a-input>
       </a-form-item>
       <a-form-item>
-        <a-input
-          v-model:value="formState.password"
-          type="password"
-          placeholder="Password"
-        >
-          <template #prefix
-            ><LockOutlined style="color: rgba(0, 0, 0, 0.25)"
-          /></template>
+        <a-input v-model:value="formState.password" type="password" placeholder="密码">
+          <template #prefix>
+            <LockOutlined style="color: rgba(0, 0, 0, 0.25)" />
+          </template>
         </a-input>
       </a-form-item>
       <a-form-item>
-        <a-button
-          class="m0"
-          type="primary"
-          html-type="submit"
-          :disabled="formState.user === '' || formState.password === ''"
-          @click="onSubmit"
-        >
-          Login
+        <a-button class="m0" type="primary" html-type="submit"
+          :disabled="formState.user === '' || formState.password === ''" @click="onSubmit">
+          登录
         </a-button>
       </a-form-item>
     </a-form>
@@ -81,7 +65,7 @@ onMounted(async () => {
         })
         const jsres = apiPilot.loadComponent(EComponentName.Api, apiPilot.getComponentParam(EComponentName.Api))
         if (!jsres) {
-          message.error('Failed to load api module.')
+          message.error('加载api模块失败')
           return
         }
         apiPilot.setToken(res.data.access_token)
@@ -97,7 +81,7 @@ const onSubmit = async (e: any) => {
   await login(formState)
     .then(res => {
       if (!isVerified.value) {
-        message.error('Please verify the license firstly.')
+        message.error('请先核实license')
         return
       }
       console.log('login res:', res)
@@ -117,7 +101,7 @@ const onSubmit = async (e: any) => {
         localStorage.setItem(ELocalStorageKey.UserId, res.data.user_id)
         localStorage.setItem(ELocalStorageKey.Username, res.data.username)
         localStorage.setItem(ELocalStorageKey.Flag, EUserType.Pilot.toString())
-        message.success('Login Success')
+        message.success('登录成功')
         root.$router.push(ERouterName.PILOT_HOME)
       }
     })
@@ -126,23 +110,25 @@ const onSubmit = async (e: any) => {
     })
 }
 
-function verifyLicense () {
+function verifyLicense() {
   isVerified.value = apiPilot.platformVerifyLicense(CURRENT_CONFIG.appId, CURRENT_CONFIG.appKey, CURRENT_CONFIG.appLicense) &&
     apiPilot.isPlatformVerifySuccess()
   if (isVerified.value) {
-    message.success('The license verification is successful.')
+    message.success('license认证成功')
   } else {
-    message.error('Filed to verify the license. Please check license whether the license is correct, or apply again.')
+    message.error('申请license验证。请检查license是否正确,或者重新申请')
   }
 }
 </script>
 
 <style lang="scss" scoped>
 @import '/@/styles/index.scss';
+
 .login {
   // background-color: $dark-highlight;
   height: 100vh;
 }
+
 .logo {
   color: $primary;
 }

+ 54 - 71
Web/src/pages/page-pilot/pilot-liveshare.vue

@@ -1,25 +1,14 @@
 <template>
-    <div class="width100 flex-column flex-justify-start flex-align-start" style="background-color: white;">
-
-      <p class="fz16 ml10 mt15 mb10 color-text-title color-font-bold" style="color: #939393">
-        Before starting manually, please select the publish mode and livestream type
-      </p>
-    <div
-      class="mt15 flex-row flex-align-center flex-justify-between"
-      style="width: 100%;">
+  <div class="width100 flex-column flex-justify-start flex-align-start" style="background-color: white;">
+    <p class="fz16 ml10 mt15 mb10 color-text-title color-font-bold" style="color: #939393">
+      在手动开始之前,请选择发布模式和直播类型
+    </p>
+    <div class="mt15 flex-row flex-align-center flex-justify-between" style="width: 100%;">
       <p class="ml10 mb0 fz16" style="color: black">
-        Select Video Publish Mode:
+        选择视频发布模式:
       </p>
-      <a-select
-        style="width: 200px; margin-right: 20px;"
-        placeholder="Select Mode"
-        @select="onPublishModeSelect"
-      >
-        <a-select-option
-          v-for="item in publishModeList"
-          :key="item.label"
-          :value="item.value"
-        >
+      <a-select style="width: 200px; margin-right: 20px;" placeholder="发布模式" @select="onPublishModeSelect">
+        <a-select-option v-for="item in publishModeList" :key="item.label" :value="item.value">
           {{ item.label }}
         </a-select-option>
       </a-select>
@@ -28,22 +17,13 @@
     <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
       <a-divider />
     </div>
-    <div
-      class="flex-row flex-align-center flex-justify-between"
-      style="width: 100%; margin-top: -10px;"
-    >
-      <p class="ml10 mb0 fz16">Select Livestream Type:</p>
-      <a-select
-        style="width: 200px; margin-right: 20px;"
-        placeholder="Select Live Type"
-        :value="liveStreamStatus.type"
-        @select="onLiveTypeSelect"
-      >
-        <a-select-option
-          v-for="item in liveTypeList"
-          :key="item.label"
-          :value="item.value"
-        >
+    <div class="flex-row flex-align-center flex-justify-between" style="width: 100%; margin-top: -10px;">
+      <p class="ml10 mb0 fz16">
+        选择直播类型:
+      </p>
+      <a-select style="width: 200px; margin-right: 20px;" placeholder="直播类型" :value="liveStreamStatus.type"
+        @select="onLiveTypeSelect">
+        <a-select-option v-for="item in liveTypeList" :key="item.label" :value="item.value">
           {{ item.label }}
         </a-select-option>
       </a-select>
@@ -53,76 +33,80 @@
     </div>
     <div class="width-100" style="margin-top: -10px;">
       <div class="ml10" style="width: 97%;">
-        <span class="fz16">Param: </span>
+        <span class="fz16">参数: </span>
         <span v-if="liveStreamStatus.type === ELiveTypeValue.Agora" style="word-break: break-all; color: #75c5f6;">
           <div class="flex-col flex-justify-center flex-align-center">
             <div>
               <span class="ml10">Token:</span>
-              <a-input
-                class="ml10"
-                v-model:value="agoraParam.token"
-                placeholder="Token"
-              ></a-input>
+              <a-input class="ml10" v-model:value="agoraParam.token" placeholder="Token"></a-input>
             </div>
             <div>
               <span class="ml10">Channel:</span>
-              <a-input
-                class="ml10"
-                v-model:value="agoraParam.channelId"
-                placeholder="Channel"
-              ></a-input>
+              <a-input class="ml10" v-model:value="agoraParam.channelId" placeholder="Channel"></a-input>
             </div>
           </div>
         </span>
-        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.RTMP" style="word-break: break-all; color: #75c5f6;">{{ rtmpParam }}</span>
-        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.RTSP" style="word-break: break-all; color: #75c5f6;">{{ rtspParam }}</span>
-        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.GB28181" style="word-break: break-all; color: #75c5f6;">{{ gb28181Param }}</span>
+        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.RTMP"
+          style="word-break: break-all; color: #75c5f6;">{{ rtmpParam }}</span>
+        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.RTSP"
+          style="word-break: break-all; color: #75c5f6;">{{ rtspParam }}</span>
+        <span v-else-if="liveStreamStatus.type === ELiveTypeValue.GB28181"
+          style="word-break: break-all; color: #75c5f6;">{{ gb28181Param }}</span>
         <span v-else></span>
       </div>
-
     </div>
     <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
       <a-divider />
     </div>
-    <div class="mb20 flex-row flex-align-center flex-justify-center"
-      style="width: 100%; ">
-      <a-button class="flex-column fz20 flex-align-center flex-justify-center" style="width: 100px;" type="ghost" @click="onPlay">Play</a-button>
-      <a-button class="flex-column fz20 flex-align-center flex-justify-center ml40" style="width: 100px;" type="ghost" @click="onStop">Stop</a-button>
+    <div class="mb20 flex-row flex-align-center flex-justify-center" style="width: 100%; ">
+      <a-button class="flex-column fz20 flex-align-center flex-justify-center" style="width: 100px;" type="ghost"
+        @click="onPlay">播放</a-button>
+      <a-button class="flex-column fz20 flex-align-center flex-justify-center ml40" style="width: 100px;" type="ghost"
+        @click="onStop">停止</a-button>
     </div>
     <a-button v-if="playVisiable" class="flex-column flex-align-center" shape="circle" @click="showLivingStatus"
       style="position: fixed; top: 13vh; left: 5vw; opacity: 0.8; background-color: rgb(0,0,0,0)">
-      <template #icon><CaretRightFilled style="font-size: 26px; color: " /></template>
+      <template #icon>
+        <CaretRightFilled style="font-size: 26px; color: " />
+      </template>
     </a-button>
-
-    <a-drawer  placement="right" v-model:visible="drawerVisible" width="280px" :mask="false" @close="closeDrawer">
+    <a-drawer placement="right" v-model:visible="drawerVisible" width="280px" :mask="false" @close="closeDrawer">
       <div class="fz16 width-100">
         <div class="mt20" style=" margin-bottom: -10px;">
           <span class="fz20 flex-row flex-align-center flex-justify-center">
-            <font :color="liveState === EStatusValue.LIVING ? 'green' : liveState === EStatusValue.CONNECTED ? 'blue' : 'red'">{{ liveState }}</font></span>
+            <font
+              :color="liveState === EStatusValue.LIVING ? 'green' : liveState === EStatusValue.CONNECTED ? 'blue' : 'red'">
+              {{ liveState }}</font>
+          </span>
         </div>
         <a-divider />
         <div style=" margin-top: -10px; margin-bottom: -15px;">
-          <span>Frame Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.fps }}<span v-if="liveStreamStatus.fps != -1"> fps</span></span><br/>
+          <span>Frame Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.fps }}<span
+              v-if="liveStreamStatus.fps != -1"> fps</span></span><br />
         </div>
         <a-divider />
         <div style=" margin-top: -10px; margin-bottom: -10px;">
-          <span>Video Bit Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.videoBitRate }}<span v-if="liveStreamStatus.videoBitRate != -1"> kbps</span></span><br/>
+          <span>Video Bit Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.videoBitRate
+            }}<span v-if="liveStreamStatus.videoBitRate != -1"> kbps</span></span><br />
         </div>
         <a-divider />
         <div style=" margin-top: -10px; margin-bottom: -10px;">
-          <span>Audio Bit Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.audioBitRate }}<span v-if="liveStreamStatus.audioBitRate != -1"> kbps</span></span><br/>
+          <span>Audio Bit Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.audioBitRate
+            }}<span v-if="liveStreamStatus.audioBitRate != -1"> kbps</span></span><br />
         </div>
         <a-divider />
         <div style=" margin-top: -10px; margin-bottom: -10px;">
-          <span>Packet Loss Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.dropRate }}<span v-if="liveStreamStatus.dropRate != -1"> %</span></span><br/>
+          <span>Packet Loss Rate:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.dropRate }}<span
+              v-if="liveStreamStatus.dropRate != -1"> %</span></span><br />
         </div>
         <a-divider />
         <div style=" margin-top: -10px; margin-bottom: -10px;">
-          <span>RTT:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.rtt }}<span v-if="liveStreamStatus.rtt != -1"> ms</span></span><br/>
+          <span>RTT:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.rtt }}<span
+              v-if="liveStreamStatus.rtt != -1"> ms</span></span><br />
         </div>
         <a-divider />
         <div style=" margin-top: -10px;">
-          <span >Jitter:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.jitter }}</span><br/>
+          <span>Jitter:</span><span style="float: right; color: #75c5f6;">{{ liveStreamStatus.jitter }}</span><br />
         </div>
       </div>
     </a-drawer>
@@ -245,7 +229,7 @@ const liveStatusCallback = async (arg: LiveStreamStatus) => {
       liveState.value = EStatusValue.DISCONNECT
   }
 }
-function refreshLiveType () {
+function refreshLiveType() {
   switch (liveStreamStatus.type) {
     case ELiveTypeValue.Agora:
       liveTypeSelected.value = ELiveTypeName.Agora
@@ -274,11 +258,11 @@ const onPublishModeSelect = (val: string) => {
 const onPlay = () => {
   console.info(JSON.stringify(agoraParam))
   if (!publishModeSelected.value) {
-    message.warn('Please select publish mode!')
+    message.warn('请选择发布模式!')
     return
   }
   if (liveTypeSelected.value === ELiveTypeName.Unknown) {
-    message.warn('Please select livestream type!')
+    message.warn('请选择直播类型!')
     return
   }
   switch (liveStreamStatus.type) {
@@ -303,7 +287,7 @@ const onPlay = () => {
   if (status) {
     playVisiable.value = true
     drawerVisible.value = true
-    message.success('success')
+    message.success('成功')
   }
 }
 
@@ -314,7 +298,7 @@ const showLivingStatus = () => {
 const onStop = () => {
   const status = apiPilot.stopLiveshare()
   if (status) {
-    message.success('success')
+    message.success('成功')
     playVisiable.value = false
     drawerVisible.value = false
     setTimeout(() => {
@@ -331,5 +315,4 @@ const onStop = () => {
 </script>
 
 <style lang="scss" scoped>
-// @import '/@/styles/index.scss';
-</style>
+// @import '/@/styles/index.scss';</style>

+ 38 - 64
Web/src/pages/page-pilot/pilot-media.vue

@@ -1,69 +1,44 @@
 <template>
   <a-layout>
-  <div class="width100 flex-column flex-justify-start flex-align-start" style="background-color: white;">
-
-    <p class="fz16 ml10 mt15 mb10 color-text-title color-font-bold" style="color: #939393">
-      When enabled, photos and videos will be automatically uploaded to this server
-    </p>
-    <div
-      class="flex-row flex-align-center mt20"
-      style="width: 100%;"
-    >
-      <p class="ml10 mb0 fz16" style="margin-right: 73vw;">Auto Photo Upload</p>
-      <a-switch
-        v-model:checked="enablePhotoUpload"
-        @change="onPhotoUpload"
-      ></a-switch>
-    </div>
-    <div
-      class="flex-row flex-align-center flex-justify-between"
-      style="width: 100%"
-    >
-      <a-radio-group
-        class="mt10 ml20"
-        v-if="enablePhotoUpload === true"
-        v-model:value="photoType"
-        defaultChecked="0"
-        @change="onPhototype"
-      >
-        <a-radio :value="EPhotoType.Original">Original Photo</a-radio>
-        <a-radio class="ml20" :value="EPhotoType.Preview">Preview Photo</a-radio>
-      </a-radio-group>
-    </div>
-    <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
-      <a-divider />
-    </div>
-    <div
-      class="flex-row flex-align-center"
-      style="width: 100%; margin-top: -10px;"
-    >
-      <p class="ml10 mb0 fz16" style="margin-right: 73vw;">Auto Video Upload</p>
-      <a-switch
-        @change="onVideoUpload"
-        v-model:checked="enableVideoUpload"
-      ></a-switch>
-    </div>
-    <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
-      <a-divider />
-    </div>
-    <div
-      class="flex-row flex-align-center flex-justify-between mb15"
-      style="width: 100%; margin-top: -10px;"
-    >
-      <p class="ml10 mb0 fz16 color-font-bold">
-        Path for uploading media resources in dual-controller mode
+    <div class="width100 flex-column flex-justify-start flex-align-start" style="background-color: white;">
+      <p class="fz16 ml10 mt15 mb10 color-text-title color-font-bold" style="color: #939393">
+        启用后,照片和视频将自动上传到该服务器
       </p>
-      <a-radio-group
-        class="mt0 mb0"
-        v-model:value="uploadPath"
-        button-style="solid"
-        @change="onUploadPath"
-      >
-        <a-radio-button :value="EDownloadOwner.Mine">Mine</a-radio-button>
-        <a-radio-button :value="EDownloadOwner.Others">Another</a-radio-button>
-      </a-radio-group>
+      <div class="flex-row flex-align-center mt20" style="width: 100%;">
+        <p class="ml10 mb0 fz16" style="margin-right: 73vw;">自动上传照片 </p>
+        <a-switch v-model:checked="enablePhotoUpload" @change="onPhotoUpload"></a-switch>
+      </div>
+      <div class="flex-row flex-align-center flex-justify-between" style="width: 100%">
+        <a-radio-group class="mt10 ml20" v-if="enablePhotoUpload === true" v-model:value="photoType" defaultChecked="0"
+          @change="onPhototype">
+          <a-radio :value="EPhotoType.Original">
+            原图
+          </a-radio>
+          <a-radio class="ml20" :value="EPhotoType.Preview">
+            缩略图
+          </a-radio>
+        </a-radio-group>
+      </div>
+      <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
+        <a-divider />
+      </div>
+      <div class="flex-row flex-align-center" style="width: 100%; margin-top: -10px;">
+        <p class="ml10 mb0 fz16" style="margin-right: 73vw;">自动上传视频</p>
+        <a-switch @change="onVideoUpload" v-model:checked="enableVideoUpload"></a-switch>
+      </div>
+      <div class="ml10 mr10" style="width: 96%; margin-top: -10px;">
+        <a-divider />
+      </div>
+      <div class="flex-row flex-align-center flex-justify-between mb15" style="width: 100%; margin-top: -10px;">
+        <p class="ml10 mb0 fz16 color-font-bold">
+          用于双控模式下上传媒体资源
+        </p>
+        <a-radio-group class="mt0 mb0" v-model:value="uploadPath" button-style="solid" @change="onUploadPath">
+          <a-radio-button :value="EDownloadOwner.Mine">我的</a-radio-button>
+          <a-radio-button :value="EDownloadOwner.Others">其它</a-radio-button>
+        </a-radio-group>
+      </div>
     </div>
-  </div>
   </a-layout>
 </template>
 
@@ -100,5 +75,4 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
-// @import '/@/styles/index.scss';
-</style>
+// @import '/@/styles/index.scss';</style>

+ 23 - 12
Web/src/pages/page-web/home.vue

@@ -1,18 +1,21 @@
 <template>
   <a-layout class="width-100 flex-display" style="height: 100vh">
-    <a-layout-header class="header">
-      <Topbar />
-    </a-layout-header>
-    <a-layout-content>
-      <router-view />
-    </a-layout-content>
-
+    <Nav></Nav>
+    <a-layout>
+      <a-layout-header class="header">
+        <Topbar />
+      </a-layout-header>
+      <a-layout-content class="content">
+        <router-view />
+      </a-layout-content>
+    </a-layout>
   </a-layout>
 </template>
 
 <script lang="ts" setup>
-import Topbar from '/@/components/common/topbar.vue'
-import { onMounted, reactive, ref, UnwrapRef, watch } from 'vue'
+import { onMounted, ref } from 'vue'
+import Nav from '/@/components/common/nav.vue';
+import Topbar from '/@/components/common/topbar.vue';
 import { getRoot } from '/@/root'
 import { EBizCode, ELocalStorageKey, ERouterName } from '/@/types'
 import { useConnectWebSocket } from '/@/hooks/use-connect-websocket'
@@ -23,6 +26,8 @@ interface FormState {
   password: string
 }
 
+const collapsed = ref<boolean>(false);
+
 const root = getRoot()
 
 const messageHandler = async (payload: any) => {
@@ -62,10 +67,16 @@ onMounted(() => {
 }
 
 .header {
-  background-color: black;
-  color: white;
+  background-color: #FFFFFF;
   height: 60px;
   font-size: 15px;
   padding: 0 20px;
 }
-</style>
+
+.content {
+  width: 100%;
+  height: 100%;
+  background: #F7F9FA;
+  overflow: auto;
+}
+</style>

+ 19 - 39
Web/src/pages/page-web/index.vue

@@ -1,48 +1,29 @@
 <template>
-  <div
-    class="login flex-column flex-justify-center flex-align-center m0 b0">
-    <a-image
-      style="width: 17vw; height: 10vw; margin-bottom: 50px"
-      :src="djiLogo"
-    />
-    <p class="fz35 pb50" style="color: #2d8cf0">Cloud API Demo</p>
-    <a-form
-      layout="inline"
-      :model="formState"
-      class="flex-row flex-justify-center flex-align-center"
-    >
+  <div class="login flex-column flex-justify-center flex-align-center m0 b0">
+    <a-image :preview="false" style="width: 17vw; height: 10vw; margin-bottom: 50px" :src="djiLogo" />
+    <p class="fz35 pb50" style="color: #2d8cf0">上云无人机管理平台</p>
+    <a-form layout="inline" :model="formState" class="flex-row flex-justify-center flex-align-center">
       <a-form-item>
-        <a-input v-model:value="formState.username" placeholder="Username">
-          <template #prefix
-            ><UserOutlined style="color: rgba(0, 0, 0, 0.25)"
-          /></template>
+        <a-input v-model:value="formState.username" placeholder="账号">
+          <template #prefix>
+            <UserOutlined style="color: rgba(0, 0, 0, 0.25)" />
+          </template>
         </a-input>
       </a-form-item>
       <a-form-item>
-        <a-input
-          v-model:value="formState.password"
-          type="password"
-          placeholder="Password"
-        >
-          <template #prefix
-            ><LockOutlined style="color: rgba(0, 0, 0, 0.25)"
-          /></template>
+        <a-input v-model:value="formState.password" type="password" placeholder="密码">
+          <template #prefix>
+            <LockOutlined style="color: rgba(0, 0, 0, 0.25)" />
+          </template>
         </a-input>
       </a-form-item>
       <a-form-item>
-        <a-button
-          class="m0"
-          type="primary"
-          html-type="submit"
-          :disabled="loginBtnDisabled"
-          @click="onSubmit"
-        >
-          Login
+        <a-button class="m0" type="primary" html-type="submit" :disabled="loginBtnDisabled" @click="onSubmit">
+          登录
         </a-button>
       </a-form-item>
     </a-form>
   </div>
-
 </template>
 
 <script lang="ts" setup>
@@ -53,13 +34,12 @@ import { reactive, computed, UnwrapRef } from 'vue'
 import { login, LoginBody } from '/@/api/manage'
 import { getRoot } from '/@/root'
 import { ELocalStorageKey, ERouterName, EUserType } from '/@/types'
-import router from '/@/router'
 
 const root = getRoot()
 
 const formState: UnwrapRef<LoginBody> = reactive({
-  username: 'adminPC',
-  password: 'adminPC',
+  username: '',
+  password: '',
   flag: EUserType.Web,
 })
 
@@ -75,18 +55,18 @@ const onSubmit = async (e: any) => {
     localStorage.setItem(ELocalStorageKey.Username, result.data.username)
     localStorage.setItem(ELocalStorageKey.UserId, result.data.user_id)
     localStorage.setItem(ELocalStorageKey.Flag, EUserType.Web.toString())
-    root.$router.push(ERouterName.MEMBERS)
+    root.$router.push(ERouterName.DEVICES)
   } else {
     message.error(result.message)
   }
 }
-
 </script>
 
 <style lang="scss" scoped>
 @import '/@/styles/index.scss';
+
 .login {
   background-color: $dark-highlight;
   height: 100vh;
 }
-</style>
+</style>

+ 24 - 432
Web/src/pages/page-web/projects/devices.vue

@@ -1,443 +1,35 @@
-
 <template>
-  <a-menu v-model:selectedKeys="current" mode="horizontal" @select="select">
-    <a-menu-item :key="EDeviceTypeName.Aircraft" class="ml20">
-      Aircraft
+  <a-menu v-model:selectedKeys="state.selectedKeys" mode="horizontal">
+    <a-menu-item :key="1">
+      设备列表
+    </a-menu-item>
+    <a-menu-item :key="2">
+      机场异常反馈记录
     </a-menu-item>
-    <a-menu-item :key="EDeviceTypeName.Dock">
-      Dock
+    <a-menu-item :key="3">
+      所有设备变化记录
     </a-menu-item>
   </a-menu>
-  <div class="device-table-wrap table flex-display flex-column">
-    <a-table :columns="columns" :data-source="data.device" :pagination="paginationProp" @change="refreshData" row-key="device_sn" :expandedRowKeys="expandRows"
-    :row-selection="rowSelection" :rowClassName="rowClassName" :scroll="{ x: '100%', y: 600 }"
-      :expandIcon="expandIcon" :loading="loading">
-      <template v-for="col in ['nickname']" #[col]="{ text, record }" :key="col">
-        <div>
-          <a-input
-            v-if="editableData[record.device_sn]"
-            v-model:value="editableData[record.device_sn][col]"
-            style="margin: -5px 0"
-          />
-          <template v-else>
-            <a-tooltip :title="text">
-              {{ text }}
-            </a-tooltip>
-          </template>
-        </div>
-      </template>
-      <template v-for="col in ['sn', 'workspace']" #[col]="{ text }" :key="col">
-        <a-tooltip :title="text">
-            <span>{{ text }}</span>
-        </a-tooltip>
-      </template>
-      <!-- 固件版本 -->
-      <template #firmware_version="{ record }">
-        <span v-if="judgeCurrentType(EDeviceTypeName.Dock)">
-          <DeviceFirmwareUpgrade :device="record"
-                                  class="table-flex-col"
-                                  @device-upgrade="onDeviceUpgrade"
-                                 />
-        </span>
-        <span v-else>
-          {{ record.firmware_version }}
-        </span>
-      </template>
-      <!-- 状态 -->
-      <template #status="{ text }">
-        <span v-if="text" class="flex-row flex-align-center">
-            <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: green;" />
-            <span>Online</span>
-        </span>
-        <span class="flex-row flex-align-center" v-else>
-            <span class="mr5" style="width: 12px; height: 12px; border-radius: 50%; background-color: red;" />
-            <span>Offline</span>
-        </span>
-      </template>
-      <!-- 操作 -->
-      <template #action="{ record }">
-        <div class="editable-row-operations">
-          <!-- 编辑态操作 -->
-          <div v-if="editableData[record.device_sn]">
-            <a-tooltip title="Confirm changes">
-              <span @click="save(record)" style="color: #28d445;"><CheckOutlined /></span>
-            </a-tooltip>
-            <a-tooltip title="Modification canceled">
-              <span @click="() => delete editableData[record.device_sn]" style="color: #e70102;"><CloseOutlined /></span>
-            </a-tooltip>
-          </div>
-          <!-- 非编辑态操作 -->
-          <div v-else class="flex-align-center flex-row" style="color: #2d8cf0">
-            <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="设备日志">
-              <CloudServerOutlined @click="showDeviceLogUploadRecord(record)"/>
-            </a-tooltip>
-            <a-tooltip v-if="current.indexOf(EDeviceTypeName.Dock) !== -1" title="Hms Info">
-              <FileSearchOutlined @click="showHms(record)"/>
-            </a-tooltip>
-            <a-tooltip title="Edit">
-              <EditOutlined @click="edit(record)"/>
-            </a-tooltip>
-            <a-tooltip title="Delete">
-              <DeleteOutlined @click="() => { deleteTip = true, deleteSn = record.device_sn }"/>
-            </a-tooltip>
-          </div>
-        </div>
-      </template>
-
-    </a-table>
-    <a-modal v-model:visible="deleteTip" width="450px" :closable="false" centered :okButtonProps="{ danger: true }" @ok="unbind">
-        <p class="pt10 pl20" style="height: 50px;">Delete device from workspace?</p>
-        <template #title>
-            <div class="flex-row flex-justify-center">
-                <span>Delete devices</span>
-            </div>
-        </template>
-    </a-modal>
-
-    <!-- 设备升级 -->
-    <DeviceFirmwareUpgradeModal title="设备升级"
-      v-model:visible="deviceFirmwareUpgradeModalVisible"
-      :device="selectedDevice"
-      @ok="onUpgradeDeviceOk"
-    ></DeviceFirmwareUpgradeModal>
-
-    <!-- 设备日志上传记录 -->
-    <DeviceLogUploadRecordDrawer
-      v-model:visible="deviceLogUploadRecordVisible"
-      :device="currentDevice"
-    ></DeviceLogUploadRecordDrawer>
-
-    <!-- hms 信息 -->
-    <DeviceHmsDrawer
-       v-model:visible="hmsVisible"
-      :device="currentDevice">
-    </DeviceHmsDrawer>
+  <div v-if="state.selectedKeys[0] === 1">
+    <DeviceList />
+  </div>
+  <div v-else-if="state.selectedKeys[0] === 2">
+    <FeedbackRecord />
+  </div>
+  <div v-else-if="state.selectedKeys[0] === 3">
+    <ChangeRecord />
   </div>
 </template>
-<script lang="ts" setup>
-import { ColumnProps, TableState } from 'ant-design-vue/lib/table/interface'
-import { h, onMounted, reactive, ref, UnwrapRef } from 'vue'
-import { IPage } from '/@/api/http/type'
-import { BindBody, bindDevice, getBindingDevices, unbindDevice, updateDevice } from '/@/api/manage'
-import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
-import { EditOutlined, CheckOutlined, CloseOutlined, DeleteOutlined, FileSearchOutlined, CloudServerOutlined } from '@ant-design/icons-vue'
-import { Device, DeviceFirmwareStatusEnum } from '/@/types/device'
-import DeviceFirmwareUpgrade from '/@/components/devices/device-upgrade/DeviceFirmwareUpgrade.vue'
-import DeviceFirmwareUpgradeModal from '/@/components/devices/device-upgrade/DeviceFirmwareUpgradeModal.vue'
-import { useDeviceFirmwareUpgrade } from '/@/components/devices/device-upgrade/use-device-upgrade'
-import { useDeviceUpgradeEvent } from '/@/components/devices/device-upgrade/use-device-upgrade-event'
-import { DeviceCmdExecuteInfo, DeviceCmdExecuteStatus } from '/@/types/device-cmd'
-import DeviceLogUploadRecordDrawer from '/@/components/devices/device-log/DeviceLogUploadRecordDrawer.vue'
-import DeviceHmsDrawer from '/@/components/devices/device-hms/DeviceHmsDrawer.vue'
-import { message, notification } from 'ant-design-vue'
-
-interface DeviceData {
-  device: Device[]
-}
-
-const loading = ref(true)
-const deleteTip = ref<boolean>(false)
-const deleteSn = ref<string>()
-const columns: ColumnProps[] = [
-  { title: 'Model', dataIndex: 'device_name', width: 100, className: 'titleStyle' },
-  { title: 'SN', dataIndex: 'device_sn', width: 100, className: 'titleStyle', ellipsis: true, slots: { customRender: 'sn' } },
-  {
-    title: 'Name',
-    dataIndex: 'nickname',
-    width: 100,
-    sorter: (a: Device, b: Device) => a.nickname.localeCompare(b.nickname),
-    className: 'titleStyle',
-    ellipsis: true,
-    slots: { customRender: 'nickname' }
-  },
-  { title: 'Firmware Version', dataIndex: 'firmware_version', width: 150, className: 'titleStyle', slots: { customRender: 'firmware_version' } },
-  { title: 'Status', dataIndex: 'status', width: 100, className: 'titleStyle', slots: { customRender: 'status' } },
-  {
-    title: 'Workspace',
-    dataIndex: 'workspace_name',
-    width: 100,
-    className: 'titleStyle',
-    ellipsis: true,
-    slots: { customRender: 'workspace' },
-    customRender: ({ text, record, index }) => {
-      const obj = {
-        children: text,
-        props: {} as any,
-      }
-      if (current.value.indexOf(EDeviceTypeName.Dock) !== -1) {
-        if (record.domain === EDeviceTypeName.Aircraft) {
-          obj.children = ''
-        }
-      }
-      return obj
-    }
-  },
-  { title: 'Joined', dataIndex: 'bound_time', width: 150, sorter: (a: Device, b: Device) => a.bound_time.localeCompare(b.bound_time), className: 'titleStyle' },
-  { title: 'Last Online', dataIndex: 'login_time', width: 150, sorter: (a: Device, b: Device) => a.login_time.localeCompare(b.login_time), className: 'titleStyle' },
-  {
-    title: 'Actions',
-    dataIndex: 'actions',
-    width: 100,
-    className: 'titleStyle',
-    slots: { customRender: 'action' }
-  },
-]
-
-const expandIcon = (props: any) => {
-  if (judgeCurrentType(EDeviceTypeName.Dock) && !props.expanded) {
-    return h('div',
-      {
-        style: 'border-left: 2px solid rgb(200,200,200); border-bottom: 2px solid rgb(200,200,200); height: 16px; width: 16px; float: left;',
-        class: 'mt-5 ml0',
-      })
-  }
-}
-
-const rowClassName = (record: any, index: number) => {
-  const className = []
-  if ((index & 1) === 0) {
-    className.push('table-striped')
-  }
-  if (record.domain !== EDeviceTypeName.Dock) {
-    className.push('child-row')
-  }
-  return className.toString().replaceAll(',', ' ')
-}
-
-const expandRows = ref<string[]>([])
-const data = reactive<DeviceData>({
-  device: []
-})
-
-const paginationProp = reactive({
-  pageSizeOptions: ['20', '50', '100'],
-  showQuickJumper: true,
-  showSizeChanger: true,
-  pageSize: 50,
-  current: 1,
-  total: 0
-})
-
-// 获取分页信息
-function getPaginationBody () {
-  return {
-    page: paginationProp.current,
-    page_size: paginationProp.pageSize
-  } as IPage
-}
 
-const rowSelection = {
-  onChange: (selectedRowKeys: (string | number)[], selectedRows: []) => {
-    console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
-  },
-  onSelect: (record: any, selected: boolean, selectedRows: []) => {
-    console.log(record, selected, selectedRows)
-  },
-  onSelectAll: (selected: boolean, selectedRows: [], changeRows: []) => {
-    console.log(selected, selectedRows, changeRows)
-  },
-  getCheckboxProps: (record: any) => ({
-    disabled: judgeCurrentType(EDeviceTypeName.Dock) && record.domain !== EDeviceTypeName.Dock,
-    style: judgeCurrentType(EDeviceTypeName.Dock) && record.domain !== EDeviceTypeName.Dock ? 'display: none' : ''
-  }),
-}
-type Pagination = TableState['pagination']
-
-const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || ''
-const editableData: UnwrapRef<Record<string, Device>> = reactive({})
-const current = ref([EDeviceTypeName.Aircraft])
-
-function judgeCurrentType (type: EDeviceTypeName): boolean {
-  return current.value.indexOf(type) !== -1
-}
-
-// 设备升级
-const {
-  deviceFirmwareUpgradeModalVisible,
-  selectedDevice,
-  onDeviceUpgrade,
-  onUpgradeDeviceOk
-} = useDeviceFirmwareUpgrade(workspaceId)
-
-function onDeviceUpgradeWs (payload: DeviceCmdExecuteInfo) {
-  updateDevicesByWs(data.device, payload)
-}
-
-function updateDevicesByWs (devices: Device[], payload: DeviceCmdExecuteInfo) {
-  if (!devices || devices.length <= 0) {
-    return
-  }
-  for (let i = 0; i < devices.length; i++) {
-    if (devices[i].device_sn === payload.sn) {
-      if (!payload.output) return
-      const { status, progress, ext } = payload.output
-      if (status === DeviceCmdExecuteStatus.Sent || status === DeviceCmdExecuteStatus.InProgress) { // 升级中
-        const rate = ext?.rate ? (ext.rate / 1024).toFixed(2) + 'kb/s' : ''
-        devices[i].firmware_status = DeviceFirmwareStatusEnum.DuringUpgrade
-        devices[i].firmware_progress = (progress?.percent || 0) + '% ' + rate
-      } else { // 终态:成功,失败,超时
-        if (status === DeviceCmdExecuteStatus.Failed || status === DeviceCmdExecuteStatus.Timeout) {
-          notification.error({
-            message: `(${payload.sn}) Upgrade failed`,
-            description: `Error Code: ${payload.result}`,
-            duration: null
-          })
-        }
-        // 拉取列表
-        getDevices(current.value[0], true)
-      }
-      return
-    }
-    if (devices[i].children) {
-      updateDevicesByWs(devices[i].children || [], payload)
-    }
-  }
-}
-
-useDeviceUpgradeEvent(onDeviceUpgradeWs)
-
-// 获取设备列表信息
-function getDevices (domain: number, closeLoading?: boolean) {
-  if (!closeLoading) {
-    loading.value = true
-  }
-  getBindingDevices(workspaceId, getPaginationBody(), domain).then(res => {
-    if (res.code !== 0) {
-      return
-    }
-    const resData: Device[] = res.data.list
-    expandRows.value = []
-    resData.forEach((val: any) => {
-      if (val.children) {
-        val.children = [val.children]
-      }
-      if (judgeCurrentType(EDeviceTypeName.Dock)) {
-        expandRows.value.push(val.device_sn)
-      }
-    })
-    data.device = resData
-    paginationProp.total = res.data.pagination.total
-    paginationProp.current = res.data.pagination.page
-    paginationProp.pageSize = res.data.pagination.page_size
-    loading.value = false
-  })
-}
-
-function refreshData (page: Pagination) {
-  paginationProp.current = page?.current!
-  paginationProp.pageSize = page?.pageSize!
-  getDevices(current.value[0])
-}
-
-// 编辑
-function edit (record: Device) {
-  editableData[record.device_sn] = record
-}
-
-// 保存
-function save (record: Device) {
-  delete editableData[record.device_sn]
-  updateDevice({ nickname: record.nickname }, workspaceId, record.device_sn)
-}
-
-// 删除
-function showDeleteTip (sn: any) {
-  deleteTip.value = true
-}
-
-// 解绑
-function unbind () {
-  deleteTip.value = false
-  unbindDevice(deleteSn.value?.toString()!).then(res => {
-    if (res.code !== 0) {
-      return
-    }
-    getDevices(current.value[0])
-  })
-}
-
-// 选择设备
-function select (item: any) {
-  getDevices(item.key)
-}
-
-const currentDevice = ref({} as Device)
-// 设备日志
-const deviceLogUploadRecordVisible = ref(false)
-function showDeviceLogUploadRecord (dock: Device) {
-  deviceLogUploadRecordVisible.value = true
-  currentDevice.value = dock
-}
-
-// 健康状态
-const hmsVisible = ref<boolean>(false)
-
-function showHms (dock: Device) {
-  hmsVisible.value = true
-  currentDevice.value = dock
-}
+<script lang="ts" setup>
+import { reactive } from 'vue';
+import DeviceList from '/@/components/devices/deviceList/index.vue'
+import FeedbackRecord from '/@/components/devices/feedbackRecord/index.vue'
+import ChangeRecord from '/@/components/devices/changeRecord/index.vue'
 
-onMounted(() => {
-  getDevices(current.value[0])
+const state = reactive({
+  selectedKeys: [1],
 })
 </script>
 
-<style lang="scss" scoped>
-.device-table-wrap{
-  .editable-row-operations{
-    div > span {
-      margin-right: 10px;
-    }
-  }
-}
-</style>
-
-<style lang="scss">
-.table {
-  background-color: white;
-  margin: 20px;
-  padding: 20px;
-  height: 88vh;
-}
-.table-striped {
-  background-color: #f7f9fa;
-}
-.ant-table {
-  border-top: 1px solid rgb(0,0,0,0.06);
-  border-bottom: 1px solid rgb(0,0,0,0.06);
-}
-.ant-table-tbody tr td {
-  border: 0;
-}
-.ant-table td {
-  white-space: nowrap;
-}
-.ant-table-thead tr th {
-  background: white !important;
-  border: 0;
-}
-th.ant-table-selection-column {
-  background-color: white !important;
-}
-.ant-table-header {
-  background-color: white !important;
-}
-.child-row {
-  height: 70px;
-}
-.notice {
-  background: $success;
-  overflow: hidden;
-  cursor: pointer;
-}
-.caution {
-  background: orange;
-  cursor: pointer;
-  overflow: hidden;
-}
-.warn {
-  background: red;
-  cursor: pointer;
-  overflow: hidden;
-}
-</style>
+<style lang="scss" scoped></style>

+ 14 - 9
Web/src/pages/page-web/projects/dock.vue

@@ -7,17 +7,20 @@
         <a-col :span="1"></a-col>
       </a-row>
     </div>
-    <div class="scrollbar height-100" :style="{ height: scorllHeight + 'px'}">
+    <div class="scrollbar height-100" :style="{ height: scorllHeight + 'px' }">
       <div id="data" class=" uranus-scrollbar" v-if="docksData.data.length !== 0" @scroll="onScroll">
         <div v-for="dock in docksData.data" :key="dock.device_sn">
           <div class="panel" style="padding-top: 5px;" @click="selectDock(dock)">
             <div class="title">
               <a-tooltip :title="dock.nickname">
-                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{ dock.nickname }}</div>
+                <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
+                  {{ dock.nickname }}</div>
               </a-tooltip>
             </div>
             <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
-              <span><RocketOutlined /></span>
+              <span>
+                <RocketOutlined />
+              </span>
               <span class="ml5">{{ dock.children?.nickname ?? 'No drone' }}</span>
             </div>
           </div>
@@ -31,9 +34,8 @@
 </template>
 
 <script lang="ts" setup>
-import { reactive } from '@vue/reactivity'
 import { message } from 'ant-design-vue'
-import { onMounted, ref } from 'vue'
+import { onMounted, reactive, ref } from 'vue'
 import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles } from '/@/api/wayline'
 import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
 import { EllipsisOutlined, RocketOutlined, CameraFilled, UserOutlined } from '@ant-design/icons-vue'
@@ -66,13 +68,14 @@ onMounted(() => {
     getDocks()
   }, 1000)
 })
+
 const body: IPage = {
   page: 1,
   total: -1,
   page_size: 10,
 }
 
-async function getDocks () {
+async function getDocks() {
   if (!canRefresh.value) {
     return
   }
@@ -91,7 +94,7 @@ async function getDocks () {
   })
 }
 
-function onScroll (e: any) {
+function onScroll(e: any) {
   const element = e.srcElement
   if (element.scrollTop + element.clientHeight >= element.scrollHeight - 5 && Math.ceil(body.total / body.page_size) > body.page && canRefresh.value) {
     body.page++
@@ -99,7 +102,7 @@ function onScroll (e: any) {
   }
 }
 
-function selectDock (dock: Device) {
+function selectDock(dock: Device) {
   store.commit('SET_SELECT_DOCK_INFO', dock)
 }
 
@@ -116,6 +119,7 @@ function selectDock (dock: Device) {
   font-size: 13px;
   border-radius: 2px;
   cursor: pointer;
+
   .title {
     display: flex;
     flex-direction: row;
@@ -125,10 +129,11 @@ function selectDock (dock: Device) {
     margin: 0px 10px 0 10px;
   }
 }
+
 .uranus-scrollbar {
   overflow: auto;
   scrollbar-width: thin;
   scrollbar-color: #c5c8cc transparent;
   height: 100%;
 }
-</style>
+</style>

+ 42 - 81
Web/src/pages/page-web/projects/layer.vue

@@ -1,80 +1,32 @@
 <template>
   <div class="project-layer-wrapper height-100">
-    <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #4f4f4f; font-weight: 450;">
-      <a-row>
-        <a-col :span="1"></a-col>
-        <a-col :span="22">Annotations</a-col>
-        <a-col :span="1"></a-col>
-      </a-row>
+    <div class="scrollbar">
+      <LayersTree :layer-data="mapLayers" class="project-layer-content" @check="checkLayer" @select="selectLayer"
+        v-model:selectedKeys="selectedKeys" v-model:checkedKeys="checkedKeys" />
     </div>
-    <div class="scrollbar" :style="{ height: scorllHeight + 'px'}">
-    <LayersTree
-      :layer-data="mapLayers"
-      class="project-layer-content"
-      @check="checkLayer"
-      @select="selectLayer"
-      v-model:selectedKeys="selectedKeys"
-      v-model:checkedKeys="checkedKeys"
-    />
-    </div>
-    <a-drawer
-      title="Map Element"
-      placement="right"
-      :closable="true"
-      v-model:visible="visible"
-      :mask="false"
-      wrapClassName="drawer-element-wrapper"
-      @close="closeDrawer"
-      width="300"
-    >
+    <a-drawer title="Map Element" placement="right" :closable="true" v-model:visible="visible" :mask="false"
+      wrapClassName="drawer-element-wrapper" @close="closeDrawer" width="300">
       <div class="drawer-element-content">
         <div class="name element-item">
           <span class="title">Name:</span>
-          <a-input
-            v-model:value="layerState.layerName"
-            style="width:120px"
-            placeholder="element name"
-            @change="changeLayer"
-          />
+          <a-input v-model:value="layerState.layerName" style="width:120px" placeholder="element name"
+            @change="changeLayer" />
         </div>
-        <div
-          class="longitude element-item"
-          v-if="layerState.currentType === geoType.Point"
-        >
+        <div class="longitude element-item" v-if="layerState.currentType === geoType.Point">
           <span class="title">Longitude:</span>
-          <a-input
-            v-model:value="layerState.longitude"
-            style="width:120px"
-            placeholder="longitude"
-            @change="changeLayer"
-          />
+          <a-input v-model:value="layerState.longitude" style="width:120px" placeholder="longitude"
+            @change="changeLayer" />
         </div>
-        <div
-          class="latitude element-item"
-          v-if="layerState.currentType === geoType.Point"
-        >
+        <div class="latitude element-item" v-if="layerState.currentType === geoType.Point">
           <span class="title">Latitude:</span>
-          <a-input
-            v-model:value="layerState.latitude"
-            style="width:120px"
-            placeholder="latitude"
-            @change="changeLayer"
-          />
+          <a-input v-model:value="layerState.latitude" style="width:120px" placeholder="latitude"
+            @change="changeLayer" />
         </div>
         <div class="color-content">
           <span class="mr30">Color: </span>
-          <div
-            v-for="item in colors"
-            :key="item.id"
-            class="color-item"
-            :style="'background:' + item.color"
-            @click="changeColor(item)"
-          >
-            <svg-icon
-              v-if="item.color === layerState.color"
-              :size="18"
-              name="check"
-            ></svg-icon>
+          <div v-for="item in colors" :key="item.id" class="color-item" :style="'background:' + item.color"
+            @click="changeColor(item)">
+            <svg-icon v-if="item.color === layerState.color" :size="18" name="check"></svg-icon>
           </div>
         </div>
       </div>
@@ -132,14 +84,14 @@ const colors = ref<Color[]>([
 ])
 const scorllHeight = ref()
 
-async function getAllElement () {
+async function getAllElement() {
   getElementGroups('init')
   setTimeout(() => {
     useGMapCoverHook = useGMapCover()
     initMapCover()
   }, 1000)
 }
-function initMapCover () {
+function initMapCover() {
   mapLayers.value.forEach(item => {
     if (item.elements) {
       setMapCoverByElement(item.elements)
@@ -155,7 +107,7 @@ watch(
     deep: true
   }
 )
-function setMapCoverByElement (elements: LayerResource[]) {
+function setMapCoverByElement(elements: LayerResource[]) {
   elements.forEach(element => {
     const name = element.name
     const color = element.resource?.content.properties.color
@@ -163,7 +115,7 @@ function setMapCoverByElement (elements: LayerResource[]) {
     updateMapElement(element, name, color)
   })
 }
-function updateMapElement (
+function updateMapElement(
   element: LayerResource,
   name: string,
   color: string | undefined
@@ -185,10 +137,10 @@ function updateMapElement (
     useGMapCoverHook.updatePolygonElement(id, name, coordinates, color)
   }
 }
-function checkLayer (keys: string[]) {
+function checkLayer(keys: string[]) {
   console.log('checkLayer', keys, selectedKeys.value, checkedKeys.value)
 }
-function selectLayer (keys: string[], e) {
+function selectLayer(keys: string[], e) {
   // console.log('selectLayer', e.node.eventKey, e.selected)
   if (e.selected) {
     selectedKey.value = e.node.eventKey
@@ -199,7 +151,7 @@ function selectLayer (keys: string[], e) {
   store.commit('SET_DRAW_VISIBLE_INFO', visible.value)
   // store.dispatch('updateElement', { type: 'is_select', id: e.node.eventKey, bool: e.selected })
 }
-function getCurrentLayer (id: string) {
+function getCurrentLayer(id: string) {
   const Layers = store.state.Layers
   const key = id.replaceAll('resource__', '')
   // console.log('selectedKey.value', selectedKey.value)
@@ -219,7 +171,7 @@ function getCurrentLayer (id: string) {
   console.log('layer', layer)
   return layer
 }
-function setBaseInfo () {
+function setBaseInfo() {
   const layer = selectedLayer.value
   if (layer) {
     const geoType = layer.resource?.content.geometry.type
@@ -248,19 +200,19 @@ onMounted(() => {
   scorllHeight.value = parent?.clientHeight - parent.firstElementChild!.clientHeight
   getAllElement()
 })
-function closeDrawer () {
+function closeDrawer() {
   store.commit('SET_DRAW_VISIBLE_INFO', false)
   selectedKeys.value = []
 }
-function changeColor (color: Color) {
+function changeColor(color: Color) {
   layerState.color = color.color
 
   updateElements()
 }
-function changeLayer (val: string) {
+function changeLayer(val: string) {
   updateElements()
 }
-async function deleteElement () {
+async function deleteElement() {
   const elementid = selectedLayer.value.id
 
   await deleteElementReq(elementid, {}).then(async (res: any) => {
@@ -275,7 +227,7 @@ async function deleteElement () {
     getElementGroups()
   })
 }
-async function getElementGroups (type?: string) {
+async function getElementGroups(type?: string) {
   const result = await getElementGroupsReq({
     groupId: '',
     isDistributed: true
@@ -287,7 +239,7 @@ async function getElementGroups (type?: string) {
   }
   store.commit('SET_LAYER_INFO', mapLayers.value)
 }
-async function updateElements () {
+async function updateElements() {
   let content = null
   if (layerState.currentType === GeoType.Point) {
     const position = {
@@ -320,7 +272,7 @@ async function updateElements () {
   getElementGroups()
 }
 
-function updateWgs84togcj02 () {
+function updateWgs84togcj02() {
   const layers = mapLayers.value
   layers.forEach(item => {
     if (item.elements) {
@@ -331,7 +283,7 @@ function updateWgs84togcj02 () {
   })
   return layers
 }
-function updateCoordinates (transformType: string, element: LayerResource) {
+function updateCoordinates(transformType: string, element: LayerResource) {
   const geoType = element.resource?.content.geometry.type
   const type = element.resource?.type as number
   if (element.resource) {
@@ -403,25 +355,31 @@ function updateCoordinates (transformType: string, element: LayerResource) {
   .ant-drawer-content {
     background-color: $dark-highlight;
     color: $text-white-basic;
+
     .ant-drawer-header {
       background-color: $dark-highlight;
+
       .ant-drawer-title {
         color: $text-white-basic;
       }
+
       .ant-drawer-close {
         color: $text-white-basic;
       }
     }
+
     .ant-input {
       background-color: #101010;
       border-color: $dark-border;
       color: $text-white-basic;
     }
   }
+
   .color-content {
     display: flex;
     align-items: center;
     margin-top: 8px;
+
     .color-item {
       cursor: pointer;
       width: 18px;
@@ -432,15 +390,18 @@ function updateCoordinates (transformType: string, element: LayerResource) {
       margin-left: 5px;
     }
   }
+
   .title {
     display: inline-flex;
     width: 80px;
   }
+
   .element-item {
     margin-bottom: 10px;
   }
 }
+
 .scrollbar {
   overflow: auto;
 }
-</style>
+</style>

+ 0 - 10
Web/src/pages/page-web/projects/media.vue

@@ -1,10 +0,0 @@
-<template>
-  <div class="project-media-wrapper">
-  </div>
-</template>
-
-<script lang="ts" setup>
-</script>
-
-<style lang="scss" scoped>
-</style>

+ 11 - 0
Web/src/pages/page-web/projects/media/index.vue

@@ -0,0 +1,11 @@
+<template>
+  <div>
+    照片管理
+  </div>
+</template>
+
+<script lang="ts" setup>
+
+</script>
+
+<style lang="scss" scoped></style>

+ 36 - 30
Web/src/pages/page-web/projects/members.vue

@@ -1,15 +1,12 @@
-
 <template>
   <div class="table flex-display flex-column">
-    <a-table :columns="columns" :data-source="data.member" :pagination="paginationProp" @change="refreshData" row-key="user_id"
-    :row-selection="rowSelection" :rowClassName="(record, index) => ((index % 2) === 0 ? 'table-striped' : null)" :scroll="{ x: '100%', y: 600 }">
+    <a-table :columns="columns" :data-source="data.member" :pagination="paginationProp" @change="refreshData"
+      row-key="user_id" :row-selection="rowSelection"
+      :rowClassName="(record, index) => ((index % 2) === 0 ? 'table-striped' : null)" :scroll="{ x: '100%', y: 600 }">
       <template v-for="col in ['mqtt_username', 'mqtt_password']" #[col]="{ text, record }" :key="col">
         <div>
-          <a-input
-            v-if="editableData[record.user_id]"
-            v-model:value="editableData[record.user_id][col]"
-            style="margin: -5px 0"
-          />
+          <a-input v-if="editableData[record.user_id]" v-model:value="editableData[record.user_id][col]"
+            style="margin: -5px 0" />
           <template v-else>
             {{ text }}
           </template>
@@ -19,10 +16,14 @@
         <div class="editable-row-operations">
           <span v-if="editableData[record.user_id]">
             <a-tooltip title="Confirm changes">
-              <span @click="save(record)" style="color: #28d445;"><CheckOutlined /></span>
+              <span @click="save(record)" style="color: #28d445;">
+                <CheckOutlined />
+              </span>
             </a-tooltip>
             <a-tooltip title="Modification canceled">
-              <span @click="() => delete editableData[record.user_id]" class="ml15" style="color: #e70102;"><CloseOutlined /></span>
+              <span @click="() => delete editableData[record.user_id]" class="ml15" style="color: #e70102;">
+                <CloseOutlined />
+              </span>
             </a-tooltip>
           </span>
           <span v-else class="fz18 flex-align-center flex-row" style="color: #2d8cf0">
@@ -30,12 +31,11 @@
           </span>
         </div>
       </template>
-
     </a-table>
   </div>
 </template>
 <script lang="ts" setup>
-import { message, PaginationProps } from 'ant-design-vue'
+import { message } from 'ant-design-vue'
 import { TableState } from 'ant-design-vue/lib/table/interface'
 import { onMounted, reactive, Ref, ref, UnwrapRef } from 'vue'
 import { IPage } from '/@/api/http/type'
@@ -44,13 +44,13 @@ import { ELocalStorageKey } from '/@/types'
 import { EditOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons-vue'
 
 export interface Member {
-    user_id: string
-    username: string
-    user_type: string
-    workspace_name: string
-    create_time: string
-    mqtt_username: string
-    mqtt_password: string
+  user_id: string
+  username: string
+  user_type: string
+  workspace_name: string
+  create_time: string
+  mqtt_username: string
+  mqtt_password: string
 }
 
 interface MemberData {
@@ -105,13 +105,13 @@ onMounted(() => {
   getAllUsers(workspaceId, body)
 })
 
-function refreshData (page: Pagination) {
+function refreshData(page: Pagination) {
   body.page = page?.current!
   body.page_size = page?.pageSize!
   getAllUsers(workspaceId, body)
 }
 
-function getAllUsers (workspaceId: string, page: IPage) {
+function getAllUsers(workspaceId: string, page: IPage) {
   getAllUsersInfo(workspaceId, page).then(res => {
     const userList: Member[] = res.data.list
     data.member = userList
@@ -120,11 +120,11 @@ function getAllUsers (workspaceId: string, page: IPage) {
   })
 }
 
-function edit (record: Member) {
+function edit(record: Member) {
   editableData[record.user_id] = record
 }
 
-function save (record: Member) {
+function save(record: Member) {
   delete editableData[record.user_id]
   updateUserInfo(workspaceId, record.user_id, record).then(res => {
     if (res.code !== 0) {
@@ -135,33 +135,39 @@ function save (record: Member) {
 
 </script>
 <style>
-
 .table {
-    background-color: white;
-    margin: 20px;
-    padding: 20px;
-    height: 88vh;
+  background-color: white;
+  margin: 20px;
+  padding: 20px;
+  height: 88vh;
 }
+
 .table-striped {
   background-color: #f7f9fa;
 }
+
 .ant-table {
-  border-top: 1px solid rgb(0,0,0,0.06);
-  border-bottom: 1px solid rgb(0,0,0,0.06);
+  border-top: 1px solid rgb(0, 0, 0, 0.06);
+  border-bottom: 1px solid rgb(0, 0, 0, 0.06);
 }
+
 .ant-table-tbody tr td {
   border: 0;
 }
+
 .ant-table td {
   white-space: nowrap;
 }
+
 .ant-table-thead tr th {
   background: white !important;
   border: 0;
 }
+
 th.ant-table-selection-column {
   background-color: white !important;
 }
+
 .ant-table-header {
   background-color: white !important;
 }

+ 11 - 0
Web/src/pages/page-web/projects/replay/index.vue

@@ -0,0 +1,11 @@
+<template>
+  <div>
+    视频回放
+  </div>
+</template>
+
+<script lang="ts" setup>
+
+</script>
+
+<style lang="scss" scoped></style>

+ 5 - 5
Web/src/pages/page-web/projects/task.vue

@@ -6,13 +6,13 @@
         <a-col :span="20">Task Plan Library</a-col>
         <a-col :span="2">
           <span v-if="taskRoute">
-            <router-link :to="{ name: ERouterName.CREATE_PLAN}">
-              <PlusOutlined class="route-icon"/>
+            <router-link :to="{ name: ERouterName.CREATE_PLAN }">
+              <PlusOutlined class="route-icon" />
             </router-link>
           </span>
           <span v-else>
-            <router-link :to="{ name: ERouterName.TASK}">
-              <MinusOutlined class="route-icon"/>
+            <router-link :to="{ name: ERouterName.TASK }">
+              <MinusOutlined class="route-icon" />
             </router-link>
           </span>
         </a-col>
@@ -20,7 +20,7 @@
       </a-row>
     </div>
     <div v-if="!taskRoute">
-      <router-view/>
+      <router-view />
     </div>
   </div>
 </template>

+ 11 - 0
Web/src/pages/page-web/projects/trajectory/index.vue

@@ -0,0 +1,11 @@
+<template>
+  <div>
+    轨迹回放
+  </div>
+</template>
+
+<script lang="ts" setup>
+
+</script>
+
+<style lang="scss" scoped></style>

+ 159 - 84
Web/src/pages/page-web/projects/tsa.vue

@@ -1,68 +1,71 @@
 <template>
   <div class="project-tsa-wrapper ">
-    <div>
-      <a-row>
-        <a-col :span="1"></a-col>
-        <a-col :span="11">My Username</a-col>
-        <a-col :span="11" align="right" style="font-weight: 700">{{ username }}</a-col>
-        <a-col :span="1"></a-col>
-      </a-row>
-    </div>
-    <div class="scrollbar" :style="{ height: scorllHeight + 'px'}">
+    <div class="scrollbar" :style="{ height: scorllHeight + 'px' }">
       <a-collapse :bordered="false" expandIconPosition="right" accordion style="background: #232323;">
-        <a-collapse-panel :key="EDeviceTypeName.Dock" header="Dock" style="border-bottom: 1px solid #4f4f4f;">
+        <a-collapse-panel :key="EDeviceTypeName.Dock" header="机场" style="border-bottom: 1px solid #4f4f4f;">
           <div v-if="onlineDocks.data.length === 0" style="height: 150px; color: white;">
             <a-empty :image="noData" :image-style="{ height: '60px' }" />
           </div>
           <div v-else class="fz12" style="color: white;">
-            <div v-for="dock in onlineDocks.data" :key="dock.sn" style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;">
-              <div style="border-radius: 2px; height: 100%; width: 100%;" class="flex-row flex-justify-between flex-align-center">
+            <div v-for="dock in onlineDocks.data" :key="dock.sn"
+              style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;">
+              <div style="border-radius: 2px; height: 100%; width: 100%;"
+                class="flex-row flex-justify-between flex-align-center">
                 <div style="float: left; padding: 0px 5px 8px 8px; width: 88%">
                   <div style="width: 80%; height: 30px; line-height: 30px; font-size: 16px;">
                     <a-tooltip :title="`${dock.gateway.callsign} - ${dock.callsign ?? 'No Drone'}`">
-                      <div class="text-hidden" style="max-width: 200px;">{{ dock.gateway.callsign }} - {{ dock.callsign ?? 'No Drone' }}</div>
+                      <div class="text-hidden" style="max-width: 200px;">{{ dock.gateway.callsign }} - {{ dock.callsign
+                        ?? 'No Drone' }}</div>
                     </a-tooltip>
                   </div>
                   <div class="mt5 flex-align-center flex-row flex-justify-between" style="background: #595959;">
                     <div class="flex-align-center flex-row">
-                      <span class="ml5 mr5"><RobotOutlined /></span>
-                      <div class="font-bold text-hidden" style="max-width: 80px;" :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color: #00ee8b' :  'color: red;'">
-                        {{ dockInfo[dock.gateway.sn] ? EDockModeCode[dockInfo[dock.gateway.sn].basic_osd?.mode_code] : EDockModeCode[EDockModeCode.Disconnected] }}
+                      <span class="ml5 mr5">
+                        <RobotOutlined />
+                      </span>
+                      <div class="font-bold text-hidden" style="max-width: 80px;"
+                        :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
+                        {{ dockInfo[dock.gateway.sn] ? EDockModeCode[dockInfo[dock.gateway.sn].basic_osd?.mode_code] :
+                          EDockModeCode[EDockModeCode.Disconnected] }}
                       </div>
                     </div>
                     <div class="mr5 flex-align-center flex-row" style="width: 85px; margin-right: 0; height: 18px;">
                       <div v-if="hmsInfo[dock.gateway.sn]" class="flex-align-center flex-row">
-                          <div :class="hmsInfo[dock.gateway.sn][0].level === EHmsLevel.CAUTION ? 'caution-blink' :
-                            hmsInfo[dock.gateway.sn][0].level === EHmsLevel.WARN ? 'warn-blink' : 'notice-blink'" style="width: 18px; height: 16px; text-align: center;">
-                            <span :style="hmsInfo[dock.gateway.sn].length > 99 ? 'font-size: 11px' : 'font-size: 12px'">{{ hmsInfo[dock.gateway.sn].length }}</span>
-                            <span class="fz10">{{ hmsInfo[dock.gateway.sn].length > 99 ? '+' : ''}}</span>
-                          </div>
-                        <a-popover trigger="click" placement="bottom" color="black" v-model:visible="hmsVisible[dock.gateway.sn]"
+                        <div :class="hmsInfo[dock.gateway.sn][0].level === EHmsLevel.CAUTION ? 'caution-blink' :
+                          hmsInfo[dock.gateway.sn][0].level === EHmsLevel.WARN ? 'warn-blink' : 'notice-blink'"
+                          style="width: 18px; height: 16px; text-align: center;">
+                          <span :style="hmsInfo[dock.gateway.sn].length > 99 ? 'font-size: 11px' : 'font-size: 12px'">{{
+                            hmsInfo[dock.gateway.sn].length }}</span>
+                          <span class="fz10">{{ hmsInfo[dock.gateway.sn].length > 99 ? '+' : '' }}</span>
+                        </div>
+                        <a-popover trigger="click" placement="bottom" color="black"
+                          v-model:visible="hmsVisible[dock.gateway.sn]"
                           @visibleChange="readHms(hmsVisible[dock.gateway.sn], dock.gateway.sn)"
-                          :overlayStyle="{width: '200px', height: '300px'}">
+                          :overlayStyle="{ width: '200px', height: '300px' }">
                           <div :class="hmsInfo[dock.gateway.sn][0].level === EHmsLevel.CAUTION ? 'caution' :
-                            hmsInfo[dock.gateway.sn][0].level === EHmsLevel.WARN ? 'warn' : 'notice'" style="margin-left: 3px; width: 62px; height: 16px;">
+                            hmsInfo[dock.gateway.sn][0].level === EHmsLevel.WARN ? 'warn' : 'notice'"
+                            style="margin-left: 3px; width: 62px; height: 16px;">
                             <span class="word-loop">{{ hmsInfo[dock.gateway.sn][0].message_en }}</span>
                           </div>
                           <template #content>
-                            <a-collapse style="background: black; height: 300px; overflow-y: auto;" :bordered="false" expand-icon-position="right" :accordion="true">
-                              <a-collapse-panel v-for="hms in hmsInfo[dock.gateway.sn]" :key="hms.hms_id" :showArrow="false"
+                            <a-collapse style="background: black; height: 300px; overflow-y: auto;" :bordered="false"
+                              expand-icon-position="right" :accordion="true">
+                              <a-collapse-panel v-for="hms in hmsInfo[dock.gateway.sn]" :key="hms.hms_id"
+                                :showArrow="false"
                                 style=" margin: 0 auto 3px auto; border: 0; width: 140px; border-radius: 3px"
-                                :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'"
-                                >
+                                :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'">
                                 <template #header="{ isActive }">
                                   <div class="flex-row flex-align-center" style="width: 130px;">
                                     <div style="width: 110px;">
                                       <span class="word-loop">{{ hms.message_en }}</span>
                                     </div>
-                                    <div style="width: 20px; height: 15px; font-size: 10px; z-index: 2 " class="flex-row flex-align-center flex-justify-center"
-                                      :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'"
-                                    >
+                                    <div style="width: 20px; height: 15px; font-size: 10px; z-index: 2 "
+                                      class="flex-row flex-align-center flex-justify-center"
+                                      :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'">
                                       <DoubleRightOutlined :rotate="isActive ? 90 : 0" />
                                     </div>
                                   </div>
                                 </template>
-
                                 <a-tooltip :title="hms.create_time">
                                   <div style="color: white;" class="text-hidden">{{ hms.create_time }}</div>
                                 </a-tooltip>
@@ -76,43 +79,51 @@
                   </div>
                   <div class="mt5 flex-align-center flex-row flex-justify-between" style="background: #595959;">
                     <div class="flex-row">
-                      <span class="ml5 mr5"><RocketOutlined /></span>
-                      <div class="font-bold text-hidden" style="max-width: 80px" :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' :  'color: red;'">
-                        {{ deviceInfo[dock.sn] ? EModeCode[deviceInfo[dock.sn].mode_code] : EModeCode[EModeCode.Disconnected] }}
+                      <span class="ml5 mr5">
+                        <RocketOutlined />
+                      </span>
+                      <div class="font-bold text-hidden" style="max-width: 80px"
+                        :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
+                        {{ deviceInfo[dock.sn] ? EModeCode[deviceInfo[dock.sn].mode_code] :
+                          EModeCode[EModeCode.Disconnected] }}
                       </div>
                     </div>
                     <div class="mr5 flex-align-center flex-row" style="width: 85px; margin-right: 0; height: 18px;">
                       <div v-if="hmsInfo[dock.sn]" class="flex-align-center flex-row">
                         <div :class="hmsInfo[dock.sn][0].level === EHmsLevel.CAUTION ? 'caution-blink' :
-                          hmsInfo[dock.sn][0].level === EHmsLevel.WARN ? 'warn-blink' : 'notice-blink'" style="width: 18px; height: 16px; text-align: center;">
-                          <span :style="hmsInfo[dock.sn].length > 99 ? 'font-size: 11px' : 'font-size: 12px'">{{ hmsInfo[dock.sn].length }}</span>
-                          <span class="fz10">{{ hmsInfo[dock.sn].length > 99 ? '+' : ''}}</span>
+                          hmsInfo[dock.sn][0].level === EHmsLevel.WARN ? 'warn-blink' : 'notice-blink'"
+                          style="width: 18px; height: 16px; text-align: center;">
+                          <span :style="hmsInfo[dock.sn].length > 99 ? 'font-size: 11px' : 'font-size: 12px'">{{
+                            hmsInfo[dock.sn].length
+                            }}</span>
+                          <span class="fz10">{{ hmsInfo[dock.sn].length > 99 ? '+' : '' }}</span>
                         </div>
-                        <a-popover trigger="click" placement="bottom" color="black" v-model:visible="hmsVisible[dock.sn]" @visibleChange="readHms(hmsVisible[dock.sn], dock.sn)"
-                          :overlayStyle="{width: '200px', height: '300px'}">
+                        <a-popover trigger="click" placement="bottom" color="black"
+                          v-model:visible="hmsVisible[dock.sn]" @visibleChange="readHms(hmsVisible[dock.sn], dock.sn)"
+                          :overlayStyle="{ width: '200px', height: '300px' }">
                           <div :class="hmsInfo[dock.sn][0].level === EHmsLevel.CAUTION ? 'caution' :
-                            hmsInfo[dock.sn][0].level === EHmsLevel.WARN ? 'warn' : 'notice'" style="margin-left: 3px; width: 62px; height: 16px;">
+                            hmsInfo[dock.sn][0].level === EHmsLevel.WARN ? 'warn' : 'notice'"
+                            style="margin-left: 3px; width: 62px; height: 16px;">
                             <span class="word-loop">{{ hmsInfo[dock.sn][0].message_en }}</span>
                           </div>
                           <template #content>
-                            <a-collapse style="background: black; height: 300px; overflow-y: auto;" :bordered="false" expand-icon-position="right" :accordion="true">
+                            <a-collapse style="background: black; height: 300px; overflow-y: auto;" :bordered="false"
+                              expand-icon-position="right" :accordion="true">
                               <a-collapse-panel v-for="hms in hmsInfo[dock.sn]" :key="hms.hms_id" :showArrow="false"
                                 style=" margin: 0 auto 3px auto; border: 0; width: 140px; border-radius: 3px"
-                                :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'"
-                                >
+                                :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'">
                                 <template #header="{ isActive }">
                                   <div class="flex-row flex-align-center" style="width: 130px;">
                                     <div style="width: 110px;">
                                       <span class="word-loop">{{ hms.message_en }}</span>
                                     </div>
-                                    <div style="width: 20px; height: 15px; font-size: 10px; z-index: 2 " class="flex-row flex-align-center flex-justify-center"
-                                      :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'"
-                                    >
+                                    <div style="width: 20px; height: 15px; font-size: 10px; z-index: 2 "
+                                      class="flex-row flex-align-center flex-justify-center"
+                                      :class="hms.level === EHmsLevel.CAUTION ? 'caution' : hms.level === EHmsLevel.WARN ? 'warn' : 'notice'">
                                       <DoubleRightOutlined :rotate="isActive ? 90 : 0" />
                                     </div>
                                   </div>
                                 </template>
-
                                 <a-tooltip :title="hms.create_time">
                                   <div style="color: white;" class="text-hidden">{{ hms.create_time }}</div>
                                 </a-tooltip>
@@ -125,10 +136,16 @@
                     </div>
                   </div>
                 </div>
-                <div style="float: right; background: #595959; height: 100%; width: 40px;" class="flex-row flex-justify-center flex-align-center">
-                  <div class="fz16" @click="switchVisible($event, dock, true, dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected)">
-                    <a v-if="osdVisible.gateway_sn === dock.gateway.sn && osdVisible.visible"><EyeOutlined /></a>
-                    <a v-else><EyeInvisibleOutlined /></a>
+                <div style="float: right; background: #595959; height: 100%; width: 40px;"
+                  class="flex-row flex-justify-center flex-align-center">
+                  <div class="fz16"
+                    @click="switchVisible($event, dock, true, dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected)">
+                    <a v-if="osdVisible.gateway_sn === dock.gateway.sn && osdVisible.visible">
+                      <EyeOutlined />
+                    </a>
+                    <a v-else>
+                      <EyeInvisibleOutlined />
+                    </a>
                   </div>
                 </div>
               </div>
@@ -137,47 +154,66 @@
         </a-collapse-panel>
       </a-collapse>
       <a-collapse :bordered="false" expandIconPosition="right" accordion style="background: #232323;">
-        <a-collapse-panel :key="EDeviceTypeName.Aircraft" header="Online Devices" style="border-bottom: 1px solid #4f4f4f;">
+        <a-collapse-panel :key="EDeviceTypeName.Aircraft" header="在线设备" style="border-bottom: 1px solid #4f4f4f;">
           <div v-if="onlineDevices.data.length === 0" style="height: 150px; color: white;">
             <a-empty :image="noData" :image-style="{ height: '60px' }" />
           </div>
           <div v-else class="fz12" style="color: white;">
-            <div v-for="device in onlineDevices.data" :key="device.sn" style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;">
+            <div v-for="device in onlineDevices.data" :key="device.sn"
+              style="background: #3c3c3c; height: 90px; width: 250px; margin-bottom: 10px;">
               <div class="battery-slide" v-if="deviceInfo[device.sn]">
                 <div style="background: #535759; width: 100%;"></div>
-                <div class="capacity-percent" :style="{ width: deviceInfo[device.sn].battery.capacity_percent + '%'}"></div>
-                <div class="return-home" :style="{ width: deviceInfo[device.sn].battery.return_home_power + '%'}"></div>
-                <div class="landing" :style="{ width: deviceInfo[device.sn].battery.landing_power + '%'}"></div>
+                <div class="capacity-percent" :style="{ width: deviceInfo[device.sn].battery.capacity_percent + '%' }">
+                </div>
+                <div class="return-home" :style="{ width: deviceInfo[device.sn].battery.return_home_power + '%' }">
+                </div>
+                <div class="landing" :style="{ width: deviceInfo[device.sn].battery.landing_power + '%' }"></div>
                 <div class="battery" :style="{ left: deviceInfo[device.sn].battery.capacity_percent + '%' }"></div>
               </div>
-              <div style="border-bottom: 1px solid #515151; border-radius: 2px; height: 50px; width: 100%;" class="flex-row flex-justify-between flex-align-center">
+              <div style="border-bottom: 1px solid #515151; border-radius: 2px; height: 50px; width: 100%;"
+                class="flex-row flex-justify-between flex-align-center">
                 <div style="float: left; padding: 5px 5px 8px 8px; width: 88%">
                   <div style="width: 100%; height: 100%;">
                     <a-tooltip>
-                      <template #title>{{ device.model ? `${device.model} - ${device.callsign}` : 'No Drone'}}</template>
-                      <span class="text-hidden" style="max-width: 200px; display: block; height: 20px;">{{ device.model ? `${device.model} - ${device.callsign}` : 'No Drone'}}</span>
+                      <template #title>
+                        {{ device.model ? `${device.model} - ${device.callsign}` : 'NoDrone' }}</template>
+                      <span class="text-hidden" style="max-width: 200px; display: block; height: 20px;">
+                        {{ device.model ? `${device.model} - ${device.callsign}` : 'No Drone' }}
+                      </span>
                     </a-tooltip>
                   </div>
                   <div class="mt5" style="background: #595959;">
-                    <span class="ml5 mr5"><RocketOutlined /></span>
-                    <span class="font-bold" :style="deviceInfo[device.sn] && deviceInfo[device.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' :  'color: red;'">
-                      {{ deviceInfo[device.sn] ? EModeCode[deviceInfo[device.sn].mode_code] : EModeCode[EModeCode.Disconnected] }}
+                    <span class="ml5 mr5">
+                      <RocketOutlined />
+                    </span>
+                    <span class="font-bold"
+                      :style="deviceInfo[device.sn] && deviceInfo[device.sn].mode_code !== EModeCode.Disconnected ? 'color: #00ee8b' : 'color: red;'">
+                      {{ deviceInfo[device.sn] ? EModeCode[deviceInfo[device.sn].mode_code] :
+                        EModeCode[EModeCode.Disconnected] }}
                     </span>
                   </div>
                 </div>
-                <div style="float: right; background: #595959; height: 50px; width: 40px;" class="flex-row flex-justify-center flex-align-center">
-                  <div class="fz16" @click="switchVisible($event, device, false, deviceInfo[device.sn] && deviceInfo[device.sn].mode_code !== EModeCode.Disconnected)">
-                    <a v-if="osdVisible.sn === device.sn && osdVisible.visible"><EyeOutlined /></a>
-                    <a v-else><EyeInvisibleOutlined /></a>
+                <div style="float: right; background: #595959; height: 50px; width: 40px;"
+                  class="flex-row flex-justify-center flex-align-center">
+                  <div class="fz16"
+                    @click="switchVisible($event, device, false, deviceInfo[device.sn] && deviceInfo[device.sn].mode_code !== EModeCode.Disconnected)">
+                    <a v-if="osdVisible.sn === device.sn && osdVisible.visible">
+                      <EyeOutlined />
+                    </a>
+                    <a v-else>
+                      <EyeInvisibleOutlined />
+                    </a>
                   </div>
                 </div>
               </div>
               <div class="flex-row flex-justify-center flex-align-center" style="height: 40px;">
-                <div class="flex-row" style="height: 20px; background: #595959; width: 94%;" >
-                  <span class="mr5"><a-image style="margin-left: 2px; margin-top: -2px; height: 20px; width: 20px;" :src="rc" /></span>
+                <div class="flex-row" style="height: 20px; background: #595959; width: 94%;">
+                  <span class="mr5"><a-image style="margin-left: 2px; margin-top: -2px; height: 20px; width: 20px;"
+                      :src="rc" /></span>
                   <a-tooltip>
                     <template #title>{{ device.gateway.model }} - {{ device.gateway.callsign }} </template>
-                    <div class="text-hidden" style="max-width: 200px;">{{ device.gateway.model }} - {{ device.gateway.callsign }}</div>
+                    <div class="text-hidden" style="max-width: 200px;">
+                      {{ device.gateway.model }} - {{ device.gateway.callsign }}</div>
                   </a-tooltip>
                 </div>
               </div>
@@ -185,20 +221,34 @@
           </div>
         </a-collapse-panel>
       </a-collapse>
+      <a-collapse :bordered="false" expandIconPosition="right" accordion style="background: #232323;">
+        <a-collapse-panel :key="EDeviceTypeName.Aircraft" header="地图标注管理" style="border-bottom: 1px solid #4f4f4f;">
+          <Layer />
+        </a-collapse-panel>
+      </a-collapse>
+    </div>
+    <div style="width: 100%;display: flex;justify-content: center; align-items: center;">
+      <a-tooltip title="返回" placement="right">
+        <a-button type="primary" @click="onClickGoHome">
+          <ImportOutlined style="font-size: 22px; color: white" />
+        </a-button>
+      </a-tooltip>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
 import { computed, onMounted, reactive, ref, watch, WritableComputedRef } from 'vue'
+import Layer from '/@/pages/page-web/projects/layer.vue'
 import { EDeviceTypeName, ELocalStorageKey } from '/@/types'
 import noData from '/@/assets/icons/no-data.png'
 import rc from '/@/assets/icons/rc.png'
 import { OnlineDevice, EModeCode, OSDVisible, EDockModeCode, DeviceOsd } from '/@/types/device'
 import { useMyStore } from '/@/store'
 import { getDeviceTopo, getUnreadDeviceHms, updateDeviceHms } from '/@/api/manage'
-import { RocketOutlined, EyeInvisibleOutlined, EyeOutlined, RobotOutlined, DoubleRightOutlined } from '@ant-design/icons-vue'
-import { EHmsLevel } from '/@/types/enums'
+import { RocketOutlined, EyeInvisibleOutlined, EyeOutlined, RobotOutlined, DoubleRightOutlined, ImportOutlined } from '@ant-design/icons-vue'
+import { EHmsLevel, ERouterName } from '/@/types/enums'
+import { getRoot } from '/@/root'
 
 const store = useMyStore()
 const username = ref(localStorage.getItem(ELocalStorageKey.Username))
@@ -245,7 +295,7 @@ onMounted(() => {
   scorllHeight.value = parent?.clientHeight - parent?.firstElementChild?.clientHeight
 })
 
-function getOnlineTopo () {
+function getOnlineTopo() {
   getDeviceTopo(workspaceId.value).then((res) => {
     if (res.code !== 0) {
       return
@@ -289,7 +339,7 @@ function getOnlineTopo () {
   })
 }
 
-function switchVisible (e: any, device: OnlineDevice, isDock: boolean, isClick: boolean) {
+function switchVisible(e: any, device: OnlineDevice, isDock: boolean, isClick: boolean) {
   if (!isClick) {
     e.target.style.cursor = 'not-allowed'
     return
@@ -309,7 +359,7 @@ function switchVisible (e: any, device: OnlineDevice, isDock: boolean, isClick:
   store.commit('SET_OSD_VISIBLE_INFO', osdVisible)
 }
 
-function getUnreadHms (sn: string) {
+function getUnreadHms(sn: string) {
   getUnreadDeviceHms(workspaceId.value, sn).then(res => {
     if (res.data.length !== 0) {
       hmsInfo.value[sn] = res.data
@@ -318,7 +368,7 @@ function getUnreadHms (sn: string) {
   console.info(hmsInfo.value)
 }
 
-function getOnlineDeviceHms () {
+function getOnlineDeviceHms() {
   const snList = Object.keys(dockInfo.value)
   if (snList.length === 0) {
     return
@@ -335,7 +385,7 @@ function getOnlineDeviceHms () {
   })
 }
 
-function readHms (visiable: boolean, sn: string) {
+function readHms(visiable: boolean, sn: string) {
   if (!visiable) {
     updateDeviceHms(workspaceId.value, sn).then(res => {
       if (res.code === 0) {
@@ -345,33 +395,41 @@ function readHms (visiable: boolean, sn: string) {
   }
 }
 
-function openLivestreamOthers () {
+const onClickGoHome = () => {
+  const root = getRoot()
+  root.$router.push('/' + ERouterName.DEVICES)
+}
+
+function openLivestreamOthers() {
   store.commit('SET_LIVESTREAM_OTHERS_VISIBLE', true)
 }
 
-function openLivestreamAgora () {
+function openLivestreamAgora() {
   store.commit('SET_LIVESTREAM_AGORA_VISIBLE', true)
 }
-
 </script>
 
 <style lang="scss">
-.project-tsa-wrapper > :first-child {
+.project-tsa-wrapper> :first-child {
   height: 50px;
   line-height: 50px;
   align-items: center;
   border-bottom: 1px solid #4f4f4f;
 }
+
 .project-tsa-wrapper {
   height: 100%;
+
   .scrollbar {
     overflow: auto;
   }
+
   ::-webkit-scrollbar {
     display: none;
   }
 }
-.ant-collapse > .ant-collapse-item > .ant-collapse-header {
+
+.ant-collapse>.ant-collapse-item>.ant-collapse-header {
   color: white;
   border: 0;
   padding-left: 14px;
@@ -383,21 +441,26 @@ function openLivestreamAgora () {
   white-space: nowrap;
   -o-text-overflow: ellipsis;
 }
+
 .font-bold {
   font-weight: 700;
 }
 
 .battery-slide {
   width: 100%;
+
   .capacity-percent {
     background: #00ee8b;
   }
+
   .return-home {
     background: #ff9f0a;
   }
+
   .landing {
     background: #f5222d;
   }
+
   .battery {
     background: white;
     border-radius: 1px;
@@ -406,13 +469,15 @@ function openLivestreamAgora () {
     margin-top: -3px;
   }
 }
-.battery-slide > div {
+
+.battery-slide>div {
   position: relative;
   margin-top: -2px;
   min-height: 2px;
   border-radius: 2px;
   white-space: nowrap;
 }
+
 .disable {
   cursor: not-allowed;
 }
@@ -421,54 +486,64 @@ function openLivestreamAgora () {
   background: $success;
   animation: blink 500ms infinite;
 }
+
 .caution-blink {
   background: orange;
   animation: blink 500ms infinite;
 }
+
 .warn-blink {
   background: red;
   animation: blink 500ms infinite;
 }
+
 .notice {
   background: $success;
   overflow: hidden;
   cursor: pointer;
 }
+
 .caution {
   background: orange;
   cursor: pointer;
   overflow: hidden;
 }
+
 .warn {
   background: red;
   cursor: pointer;
   overflow: hidden;
 }
+
 .word-loop {
   white-space: nowrap;
   display: inline-block;
   animation: 10s loop linear infinite normal;
 }
+
 @keyframes blink {
   from {
     opacity: 1;
   }
+
   50% {
     opacity: 0.35;
   }
+
   to {
     opacity: 1;
   }
 }
+
 @keyframes loop {
   0% {
     transform: translateX(20px);
     -webkit-transform: translateX(20px);
   }
+
   100% {
     transform: translateX(-100%);
     -webkit-transform: translateX(-100%);
   }
 }
-
 </style>

+ 1 - 2
Web/src/pages/page-web/projects/wayline.vue

@@ -81,9 +81,8 @@
 </template>
 
 <script lang="ts" setup>
-import { reactive } from '@vue/reactivity'
 import { message } from 'ant-design-vue'
-import { onMounted, onUpdated, ref } from 'vue'
+import { onMounted, reactive, ref } from 'vue'
 import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile } from '/@/api/wayline'
 import { ELocalStorageKey, ERouterName } from '/@/types'
 import { EllipsisOutlined, RocketOutlined, CameraFilled, UserOutlined, SelectOutlined } from '@ant-design/icons-vue'

+ 28 - 15
Web/src/pages/page-web/projects/workspace.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="project-app-wrapper">
     <div class="left">
-      <Sidebar />
+      <!-- <Sidebar /> -->
       <div class="main-content uranus-scrollbar dark">
-        <router-view />
+        <Tsa />
       </div>
     </div>
     <div class="right">
@@ -21,6 +21,7 @@
 </template>
 <script lang="ts" setup>
 import Sidebar from '/@/components/common/sidebar.vue'
+import Tsa from '/@/pages/page-web/projects/tsa.vue'
 import MediaPanel from '/@/components/MediaPanel.vue'
 import TaskPanel from '/@/components/task/TaskPanel.vue'
 import GMap from '/@/components/GMap.vue'
@@ -92,23 +93,23 @@ const messageHandler = async (payload: any) => {
     case EBizCode.ChargeClose:
     case EBizCode.DeviceFormat:
     case EBizCode.DroneFormat:
-    {
-      store.commit('SET_DEVICES_CMD_EXECUTE_INFO', {
-        biz_code: payload.biz_code,
-        timestamp: payload.timestamp,
-        ...payload.data,
-      })
-      break
-    }
+      {
+        store.commit('SET_DEVICES_CMD_EXECUTE_INFO', {
+          biz_code: payload.biz_code,
+          timestamp: payload.timestamp,
+          ...payload.data,
+        })
+        break
+      }
     case EBizCode.ControlSourceChange:
     case EBizCode.FlyToPointProgress:
     case EBizCode.TakeoffToPointProgress:
     case EBizCode.JoystickInvalidNotify:
     case EBizCode.DrcStatusNotify:
-    {
-      EventBus.emit('droneControlWs', payload)
-      break
-    }
+      {
+        EventBus.emit('droneControlWs', payload)
+        break
+      }
     case EBizCode.FlightAreasSyncProgress: {
       EventBus.emit('flightAreasSyncProgressWs', payload.data)
       break
@@ -133,6 +134,18 @@ useConnectWebSocket(messageHandler)
 <style lang="scss" scoped>
 @import '/@/styles/index.scss';
 
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+  background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+  border-radius: 4px;
+  border: none;
+  background: rgb(89, 89, 89);
+}
+
 .project-app-wrapper {
   display: flex;
   transition: width 0.2s ease;
@@ -156,7 +169,7 @@ useConnectWebSocket(messageHandler)
     flex-grow: 1;
     position: relative;
 
-    .map-wrapper{
+    .map-wrapper {
       width: 100%;
       height: 100%;
     }

+ 7 - 5
Web/src/root.ts

@@ -1,4 +1,5 @@
-import { createApp, ComponentCustomProperties, App as VueApp } from 'vue'
+import { createApp, ComponentCustomProperties, App as VueApp } from 'vue';
+
 declare module '@vue/runtime-core' {
   interface ComponentCustomProperties {
     $aMap: any // Map类
@@ -6,19 +7,20 @@ declare module '@vue/runtime-core' {
     $mouseTool: any
   }
 }
+
 let root: ComponentCustomProperties
 let app = null as any
 
-export function createInstance (App: any): VueApp {
+export function createInstance(App: any): VueApp {
   app = createApp(App)
   root = app.config.globalProperties as ComponentCustomProperties
   return app
 }
 
-export function getRoot (): ComponentCustomProperties {
+export function getRoot(): ComponentCustomProperties {
   return root
 }
 
-export function getApp (): VueApp {
+export function getApp(): VueApp {
   return app
-}
+}

+ 15 - 45
Web/src/router/index.ts

@@ -17,7 +17,6 @@ const routes: Array<RouteRecordRaw> = [
     name: ERouterName.PROJECT,
     component: () => import('/@/pages/page-web/index.vue')
   },
-  // members, devices
   {
     path: '/' + ERouterName.HOME,
     name: ERouterName.HOME,
@@ -37,49 +36,21 @@ const routes: Array<RouteRecordRaw> = [
         path: '/' + ERouterName.FIRMWARES,
         name: ERouterName.FIRMWARES,
         component: () => import('../pages/page-web/projects/Firmwares.vue')
-      }
-    ]
-  },
-  // workspace
-  {
-    path: '/' + ERouterName.WORKSPACE,
-    name: ERouterName.WORKSPACE,
-    component: () => import('/@/pages/page-web/projects/workspace.vue'),
-    redirect: '/' + ERouterName.TSA,
-    children: [
-      {
-        path: '/' + ERouterName.TSA,
-        component: () => import('/@/pages/page-web/projects/tsa.vue')
-      },
-      {
-        path: '/' + ERouterName.LIVESTREAM,
-        name: ERouterName.LIVESTREAM,
-        component: () => import('/@/pages/page-web/projects/livestream.vue'),
-        children: [
-          {
-            path: ERouterName.LIVING,
-            name: ERouterName.LIVING,
-            components: {
-              LiveAgora,
-              LiveOthers
-            }
-          }
-        ]
-      },
-      {
-        path: '/' + ERouterName.LAYER,
-        name: ERouterName.LAYER,
-        component: () => import('/@/pages/page-web/projects/layer.vue')
       },
       {
         path: '/' + ERouterName.MEDIA,
         name: ERouterName.MEDIA,
-        component: () => import('/@/pages/page-web/projects/media.vue')
+        component: () => import('/@/pages/page-web/projects/media/index.vue')
       },
       {
-        path: '/' + ERouterName.WAYLINE,
-        name: ERouterName.WAYLINE,
-        component: () => import('/@/pages/page-web/projects/wayline.vue')
+        path: '/' + ERouterName.REPLAY,
+        name: ERouterName.REPLAY,
+        component: () => import('/@/pages/page-web/projects/replay/index.vue')
+      },
+      {
+        path: '/' + ERouterName.TRAJECTORY,
+        name: ERouterName.TRAJECTORY,
+        component: () => import('/@/pages/page-web/projects/trajectory/index.vue')
       },
       {
         path: '/' + ERouterName.TASK,
@@ -104,14 +75,13 @@ const routes: Array<RouteRecordRaw> = [
 
         ]
       },
-      {
-        path: '/' + ERouterName.FLIGHT_AREA,
-        name: ERouterName.FLIGHT_AREA,
-        component: () => import('/@/pages/page-web/projects/flight-area.vue')
-      },
     ]
   },
-  // pilot
+  {
+    path: '/' + ERouterName.WORKSPACE,
+    name: ERouterName.WORKSPACE,
+    component: () => import('/@/pages/page-web/projects/workspace.vue'),
+  },
   {
     path: '/' + ERouterName.PILOT,
     name: ERouterName.PILOT,
@@ -140,4 +110,4 @@ const router = createRouter({
   routes
 })
 
-export default router
+export default router

+ 29 - 29
Web/src/store/index.ts

@@ -30,7 +30,7 @@ const initStateFunc = () => ({
     }
   ],
   layerBaseInfo: {} as {
-    [key:string]:string
+    [key: string]: string
   },
   drawVisible: false,
   livestreamOthersVisible: false,
@@ -100,25 +100,25 @@ export type RootStateType = ReturnType<typeof initStateFunc>
 const getters: GetterTree<RootStateType, RootStateType> = {
 }
 const mutations: MutationTree<RootStateType> = {
-  SET_LAYER_INFO (state, info) {
+  SET_LAYER_INFO(state, info) {
     state.Layers = info
   },
-  SET_DEVICE_INFO (state, info) {
+  SET_DEVICE_INFO(state, info) {
     state.deviceState.deviceInfo[info.sn] = info.host
     state.deviceState.currentSn = info.sn
     state.deviceState.currentType = EDeviceTypeName.Aircraft
   },
-  SET_GATEWAY_INFO (state, info) {
+  SET_GATEWAY_INFO(state, info) {
     state.deviceState.gatewayInfo[info.sn] = info.host
     state.deviceState.currentSn = info.sn
     state.deviceState.currentType = EDeviceTypeName.Gateway
   },
-  SET_DOCK_INFO (state, info) {
+  SET_DOCK_INFO(state, info) {
     if (Object.keys(info.host).length === 0) {
       return
     }
     if (!state.deviceState.dockInfo[info.sn]) {
-      state.deviceState.dockInfo[info.sn] = { } as DockOsd
+      state.deviceState.dockInfo[info.sn] = {} as DockOsd
     }
     state.deviceState.currentSn = info.sn
     state.deviceState.currentType = EDeviceTypeName.Dock
@@ -135,28 +135,28 @@ const mutations: MutationTree<RootStateType> = {
       dock.work_osd = info.host
     }
   },
-  SET_DRAW_VISIBLE_INFO (state, bool) {
+  SET_DRAW_VISIBLE_INFO(state, bool) {
     state.drawVisible = bool
   },
-  SET_LIVESTREAM_OTHERS_VISIBLE (state, bool) {
+  SET_LIVESTREAM_OTHERS_VISIBLE(state, bool) {
     state.livestreamOthersVisible = bool
   },
-  SET_LIVESTREAM_AGORA_VISIBLE (state, bool) {
+  SET_LIVESTREAM_AGORA_VISIBLE(state, bool) {
     state.livestreamAgoraVisible = bool
   },
-  SET_MAP_ELEMENT_CREATE (state, info) {
+  SET_MAP_ELEMENT_CREATE(state, info) {
     state.wsEvent.mapElementCreat = info
   },
-  SET_MAP_ELEMENT_UPDATE (state, info) {
+  SET_MAP_ELEMENT_UPDATE(state, info) {
     state.wsEvent.mapElementUpdate = info
   },
-  SET_MAP_ELEMENT_DELETE (state, info) {
+  SET_MAP_ELEMENT_DELETE(state, info) {
     state.wsEvent.mapElementDelete = info
   },
-  SET_DEVICE_ONLINE (state, info) {
+  SET_DEVICE_ONLINE(state, info) {
     state.deviceStatusEvent.deviceOnline = info
   },
-  SET_DEVICE_OFFLINE (state, info) {
+  SET_DEVICE_OFFLINE(state, info) {
     state.deviceStatusEvent.deviceOffline = info
     delete state.deviceState.gatewayInfo[info.sn]
     delete state.deviceState.deviceInfo[info.sn]
@@ -165,20 +165,20 @@ const mutations: MutationTree<RootStateType> = {
     // delete state.markerInfo.coverMap[info.sn]
     // delete state.markerInfo.pathMap[info.sn]
   },
-  SET_OSD_VISIBLE_INFO (state, info) {
+  SET_OSD_VISIBLE_INFO(state, info) {
     state.osdVisible = info
   },
-  SET_SELECT_WAYLINE_INFO (state, info) {
+  SET_SELECT_WAYLINE_INFO(state, info) {
     state.waylineInfo = info
   },
-  SET_SELECT_DOCK_INFO (state, info) {
+  SET_SELECT_DOCK_INFO(state, info) {
     state.dockInfo = info
   },
-  SET_DEVICE_HMS_INFO (state, info) {
+  SET_DEVICE_HMS_INFO(state, info) {
     const hmsList: Array<DeviceHms> = state.hmsInfo[info.sn]
     state.hmsInfo[info.sn] = info.host.concat(hmsList ?? [])
   },
-  SET_DEVICES_CMD_EXECUTE_INFO (state, info) { // 保存设备指令ws消息推送
+  SET_DEVICES_CMD_EXECUTE_INFO(state, info) { // 保存设备指令ws消息推送
     if (!info.sn) {
       return
     }
@@ -197,16 +197,16 @@ const mutations: MutationTree<RootStateType> = {
       state.devicesCmdExecuteInfo[info.sn] = [info]
     }
   },
-  SET_MQTT_STATE (state, mqttState) {
+  SET_MQTT_STATE(state, mqttState) {
     state.mqttState = mqttState
   },
-  SET_CLIENT_ID (state, clientId) {
+  SET_CLIENT_ID(state, clientId) {
     state.clientId = clientId
   },
 }
 
 const actions: ActionTree<RootStateType, RootStateType> = {
-  async getAllElement ({ commit }) {
+  async getAllElement({ commit }) {
     const result = await getLayers({
       groupId: '',
       isDistributed: true
@@ -214,7 +214,7 @@ const actions: ActionTree<RootStateType, RootStateType> = {
     commit('SET_LAYER_INFO', result.data?.list)
     console.log(result)
   },
-  updateElement ({ state }, content: {type: 'is_check' | 'is_select', id: string, bool:boolean}) {
+  updateElement({ state }, content: { type: 'is_check' | 'is_select', id: string, bool: boolean }) {
     const key = content.id.replaceAll('resource__', '')
     const type = content.type
     const layers = state.Layers
@@ -223,10 +223,10 @@ const actions: ActionTree<RootStateType, RootStateType> = {
       layer[type] = content.bool
     }
   },
-  setLayerInfo ({ state }, layers) {
+  setLayerInfo({ state }, layers) {
     // const layers = state.Layers
-    const obj:{
-      [key:string]:string
+    const obj: {
+      [key: string]: string
     } = {}
     layers.forEach(layer => {
       if (layer.type === LayerType.Default) {
@@ -240,7 +240,7 @@ const actions: ActionTree<RootStateType, RootStateType> = {
     state.layerBaseInfo = obj
     console.log('state.layerBaseInfo', state.layerBaseInfo)
   },
-  getLayerInfo ({ state }, id:string) {
+  getLayerInfo({ state }, id: string) {
     return state.layerBaseInfo[id]
   }
 }
@@ -262,6 +262,6 @@ type AllStateStoreTypes = RootStateType & {
   // moduleName: moduleType
 }
 
-export function useMyStore<T = AllStateStoreTypes> () {
+export function useMyStore<T = AllStateStoreTypes>() {
   return useStore<T>(storeKey)
-}
+}

+ 11 - 15
Web/src/styles/common.scss

@@ -1,13 +1,20 @@
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
 
-html, body, #app, #my-app {
+html,
+body {
+  height: 100%;
   height: 100%;
-  overflow: hidden;
+  padding: 0;
+  margin: 0;
 }
 
 body {
-  background-color: #f7f9fa;
+  background-color: #F7F9FA;
   -webkit-font-smoothing: antialiased;
-  // Prevent font enlargement in horizontal screen
   text-size-adjust: 100%;
 
   font-family: sans-serif, Roboto, sans-serif-medium, Arial;
@@ -17,15 +24,4 @@ body {
 
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
-  ::-webkit-scrollbar {
-    width: 8px;
-    height: 8px;
-    background: transparent;
-  }
-  
-  ::-webkit-scrollbar-thumb {
-    border-radius: 4px;
-    border: none;
-    background: rgb(89, 89, 89);
-  }
 }

+ 2 - 2
Web/src/types/device-cmd.ts

@@ -29,7 +29,7 @@ export enum DeviceCmd {
 
 export type DeviceCmdItemAction = AlarmModeEnum | BatteryStoreModeEnum | DroneBatteryModeEnum | LinkWorkModeEnum
 
-export interface DeviceCmdItem{
+export interface DeviceCmdItem {
   label: string, // 标题
   status: string, // 当前状态
   operateText: string, // 按钮文字
@@ -286,7 +286,7 @@ export interface DeviceCmdExecuteInfo {
   timestamp: number,
   sn: string,
   bid: string,
-  output:{
+  output: {
     status: DeviceCmdExecuteStatus,
     progress?: {
       percent: number,

+ 8 - 5
Web/src/types/enums.ts

@@ -1,17 +1,20 @@
 export enum ERouterName {
+    WORKSPACE = 'workspace',
+    DEVICES = 'devices',
+    TASK = 'task',
+    MEDIA = 'media',
+    REPLAY = 'replay',
+    TRAJECTORY = 'trajectory',
+    MEMBERS = 'members',
+
     ELEMENT = 'element',
     PROJECT = 'project',
     HOME = 'home',
     TSA = 'tsa',
     LAYER = 'layer',
-    MEDIA = 'media',
     WAYLINE = 'wayline',
     LIVESTREAM = 'livestream',
     LIVING = 'living',
-    WORKSPACE = 'workspace',
-    MEMBERS = 'members',
-    DEVICES = 'devices',
-    TASK = 'task',
     CREATE_PLAN = 'create-plan',
     SELECT_PLAN = 'select-plan',
     FIRMWARES = 'firmwares',

+ 4 - 4
Web/src/types/flight-area.ts

@@ -70,11 +70,11 @@ export interface FlightAreaSyncProgress {
 
 export const FlightAreaTypeTitleMap = {
   [EFlightAreaType.NFZ]: {
-    [EGeometryType.CIRCLE]: 'Circular GEO Zone',
-    [EGeometryType.POLYGON]: 'Polygonal GEO Zone',
+    [EGeometryType.CIRCLE]: '圆形地带',
+    [EGeometryType.POLYGON]: '多边形地带',
   },
   [EFlightAreaType.DFENCE]: {
-    [EGeometryType.CIRCLE]: 'Circular Task Area',
-    [EGeometryType.POLYGON]: 'Polygonal Task Area',
+    [EGeometryType.CIRCLE]: '圆形任务区',
+    [EGeometryType.POLYGON]: '多边形任务区',
   },
 }

+ 0 - 0
Web/src/shims-mqtt.d.ts → Web/src/typings/shims-mqtt.d.ts


+ 0 - 0
Web/src/shims-vue.d.ts → Web/src/typings/shims-vue.d.ts


+ 0 - 0
Web/src/vite-env.d.ts → Web/src/typings/vite-env.d.ts


+ 0 - 13
Web/src/use-common-components.ts

@@ -1,13 +0,0 @@
-import { App, DefineComponent } from 'vue'
-
-const components: Record<string, DefineComponent<{}, {}, any>> = {
-
-}
-
-export const CommonComponents = {
-  install (app: App): void {
-    Object.keys(components).forEach(name => {
-      app.component(name, components[name])
-    })
-  }
-}

+ 4 - 9
Web/src/utils/bytes.ts

@@ -7,7 +7,7 @@ import { DEFAULT_PLACEHOLDER, SIZES as byteSizes, BYTE_SIZES } from './constants
  * @param holder 0字节占位符,默认 --
  * @returns
  */
-export function bytesToSize (bytes: number, holder = DEFAULT_PLACEHOLDER, fix = 1, unit = false): string {
+export function bytesToSize(bytes: number, holder = DEFAULT_PLACEHOLDER, fix = 1, unit = false): string {
   if (isNaN(bytes) || bytes === 0) {
     return holder
   }
@@ -24,7 +24,7 @@ export function bytesToSize (bytes: number, holder = DEFAULT_PLACEHOLDER, fix =
 }
 
 //  获取转化后数据及单位
-export function getBytesObject (bytes: number, holder = DEFAULT_PLACEHOLDER, fix = 1): {
+export function getBytesObject(bytes: number, holder = DEFAULT_PLACEHOLDER, fix = 1): {
   value: string,
   size: string
   index: number
@@ -60,7 +60,7 @@ export function getBytesObject (bytes: number, holder = DEFAULT_PLACEHOLDER, fix
  * @param fix
  * @returns
  */
-export function bytesToSizeWithMinUnit (bytes: number, minUnit = 'B', fix = 1): string {
+export function bytesToSizeWithMinUnit(bytes: number, minUnit = 'B', fix = 1): string {
   const holder = `0${minUnit}`
   const sizes = byteSizes// ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
   const k = 1024
@@ -78,9 +78,4 @@ export function bytesToSizeWithMinUnit (bytes: number, minUnit = 'B', fix = 1):
   }
   // 其他
   return value + size
-}
-// console.log('size', bytesToSizeWithMinUnit(0))
-// console.log('size', bytesToSizeWithMinUnit(1023))
-// console.log('size', bytesToSizeWithMinUnit(1024))
-// console.log('size', bytesToSizeWithMinUnit(1000 * 1024, 'MB', 2))
-// console.log('size', bytesToSizeWithMinUnit(1024 * 1024, 'MB', 2))
+}

+ 1 - 1
Web/src/utils/color.ts

@@ -4,5 +4,5 @@ export const commonColor = {
   WHITE: '#FFFFFF', // 白色
   NORMAL: '#19BE6B', // 绿色
   BLUE: '#2B85E4', // 蓝色
-  PINK: '#F7C0BA', // 粉
+  PINK: '#F7C0BA', // 粉
 }

+ 2 - 2
Web/src/utils/error-code/index.ts

@@ -9,7 +9,7 @@ export interface ErrorCode {
  * @param errorMsg
  * @returns
  */
-export function getErrorMessage (code: number, errorMsg?: string): string {
+export function getErrorMessage(code: number, errorMsg?: string): string {
   const errorInfo = ERROR_CODE.find((item: ErrorCode) => item.code === code)
   return errorInfo ? errorInfo.msg : errorMsg || 'Server error'
 }
@@ -307,4 +307,4 @@ export const ERROR_CODE = [
     code: 514150,
     msg: 'DJI Dock is automatically restarting',
   },
-]
+]

+ 9 - 9
Web/src/utils/logger.ts

@@ -3,26 +3,26 @@
  * Used for log printing in a non-production environment
  * @param args
  */
-export function consoleLog (...args: Parameters<typeof console.log>) {
+export function consoleLog(...args: Parameters<typeof console.log>) {
   if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
-    window.console.log.apply(null, args) // eslint-disable-line no-console
+    window.console.log.apply(null, args)
   }
 }
 
-export function consoleWarn (...args: Parameters<typeof console.warn>) {
+export function consoleWarn(...args: Parameters<typeof console.warn>) {
   if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
-    console.warn.apply(null, args) // eslint-disable-line no-console
+    console.warn.apply(null, args)
   }
 }
 
-export function consoleError (...args: Parameters<typeof console.error>) {
+export function consoleError(...args: Parameters<typeof console.error>) {
   if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
-    console.error.apply(null, args) // eslint-disable-line no-console
+    console.error.apply(null, args)
   }
 }
 
-export function testEnvLog (...args: Parameters<typeof console.log>) {
+export function testEnvLog(...args: Parameters<typeof console.log>) {
   if (import.meta.env.VITE_APP_ENVIRONMENT !== 'PROD') {
-    console.log.apply(null, args) // eslint-disable-line no-console
+    console.log.apply(null, args)
   }
-}
+}

+ 4 - 4
Web/src/utils/time.ts

@@ -2,14 +2,14 @@ import {
   DATE_FORMAT,
   DEFAULT_PLACEHOLDER
 } from '/@/utils/constants'
-import moment, { Moment } from 'moment'
+import moment from 'moment'
 
 // 时间字符串 或者 Unix 时间戳(毫秒数)
-export function formatDateTime (time: string | number, format = DATE_FORMAT) {
+export function formatDateTime(time: string | number, format = DATE_FORMAT) {
   return time ? moment(time).format(format) : DEFAULT_PLACEHOLDER
 }
 
 // Unix 时间戳 (秒)
-export function formatUnixTime (time: number, format = DATE_FORMAT): string {
+export function formatUnixTime(time: number, format = DATE_FORMAT): string {
   return time ? moment.unix(time).format(format) : DEFAULT_PLACEHOLDER
-}
+}

+ 5 - 3
Web/tsconfig.json

@@ -9,7 +9,9 @@
     "resolveJsonModule": true,
     "esModuleInterop": true,
     "baseUrl": ".",
-    "types": ["vite/client"],
+    "types": [
+      "vite/client"
+    ],
     "lib": [
       "esnext",
       "dom"
@@ -24,7 +26,7 @@
     "src/**/*.ts",
     "src/**/*.d.ts",
     "src/**/*.tsx",
-    "src/**/*.vue", 
-    "src/vendors/coordtransform.js"  
+    "src/**/*.vue",
+    "src/vendors/coordtransform.js"
   ]
 }

+ 47 - 52
Web/vite.config.ts

@@ -1,31 +1,57 @@
 import vue from '@vitejs/plugin-vue'
-// config alias
 import path from 'path'
+import { CURRENT_CONFIG } from './src/api/http/config';
 import { ConfigEnv, defineConfig, UserConfigExport } from 'vite'
-import ViteComponents, { AntDesignVueResolver } from 'vite-plugin-components'
-// Introduce eslint plugin
-import eslintPlugin from 'vite-plugin-eslint'
-import OptimizationPersist from 'vite-plugin-optimize-persist'
-import PkgConfig from 'vite-plugin-package-config'
-import viteSvgIcons from 'vite-plugin-svg-icons'
 import { viteVConsole } from 'vite-plugin-vconsole'
 
-// https://vitejs.dev/config/
 export default ({ command, mode }: ConfigEnv): UserConfigExport => defineConfig({
+  base: '/',
+  css: {
+    preprocessorOptions: {
+      scss: {
+        additionalData: '@import "./src/styles/variables";'
+      },
+    }
+  },
+  resolve: {
+    alias: [
+      {
+        find: '/@',
+        replacement: path.resolve(__dirname, './src'),
+      }
+    ]
+  },
+  server: {
+    // 监听所有地址
+    host: '0.0.0.0',
+    // 自定义端口号
+    port: 8080,
+    // 自动打开浏览器
+    open: true,
+    // 开启热更新
+    hmr: true,
+    // 若端口被占用,自动尝试下一个可用端口
+    strictPort: false,
+    // 代理规则
+    proxy: {
+      '/api': {
+        // 开启跨域
+        changeOrigin: true,
+        // 转发地址
+        target: CURRENT_CONFIG.apiURL,
+        // 路径重写
+        rewrite: (path) => path.replace(/^\/api/, ''),
+      }
+    }
+  },
+  build: {
+    // target: ['es2015'], // 最低支持 es2015
+    sourcemap: false,// 构建后不生成源代码
+    write: true,// 构建的文件写入磁盘
+    chunkSizeWarningLimit: 10240,// 触发警告的chunk大小10M
+  },
   plugins: [
     vue(),
-    eslintPlugin({
-      fix: true
-    }),
-    ViteComponents({
-      customComponentResolvers: [AntDesignVueResolver()],
-    }),
-    viteSvgIcons({
-      // 指定需要缓存的图标文件夹
-      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
-      // 指定symbolId格式
-      symbolId: 'icon-[dir]-[name]',
-    }),
     viteVConsole({
       entry: path.resolve(__dirname, './src/main.ts'), // 入口文件
       localEnabled: command === 'serve', // serve开发环境下
@@ -35,36 +61,5 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => defineConfig(
         theme: 'light'
       }
     }),
-    PkgConfig(),
-    OptimizationPersist()
-    // [svgBuilder('./src/assets/icons/')] // All svg under src/icons/svg/ have been imported here, no need to import separately
   ],
-  server: {
-    open: true,
-    host: '0.0.0.0',
-    port: 8080
-  },
-  envDir: './env',
-  resolve: {
-    alias: [{
-      // https://github.com/vitejs/vite/issues/279#issuecomment-635646269
-      find: '/@',
-      replacement: path.resolve(__dirname, './src'),
-    }
-    ]
-  },
-  css: {
-    preprocessorOptions: {
-      scss: {
-        // example : additionalData: `@import "./src/design/styles/variables";`
-        // dont need include file extend .scss
-        additionalData: '@import "./src/styles/variables";'
-      },
-    }
-  },
-  base: '/',
-  build: {
-    target: ['es2015'], // 最低支持 es2015
-    sourcemap: true
-  }
-})
+})

+ 0 - 4114
Web/yarn.lock

@@ -1,4114 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@amap/amap-jsapi-loader@^1.0.1":
-  "integrity" "sha1-nsS01dJGfqxFH2yFLjXbaen58MA="
-  "resolved" "https://registry.npmmirror.com/@amap/amap-jsapi-loader/download/@amap/amap-jsapi-loader-1.0.1.tgz"
-  "version" "1.0.1"
-
-"@ant-design/colors@^5.0.0":
-  "integrity" "sha1-gAshhrHifmZDLmfQPtlq8+IdiUA="
-  "resolved" "https://registry.npmmirror.com/@ant-design/colors/download/@ant-design/colors-5.1.1.tgz"
-  "version" "5.1.1"
-  dependencies:
-    "@ctrl/tinycolor" "^3.3.1"
-
-"@ant-design/icons-svg@^4.0.0":
-  "integrity" "sha1-hjDajrRHGkqr2u19H/apfcss8Fo="
-  "resolved" "https://registry.npmmirror.com/@ant-design/icons-svg/download/@ant-design/icons-svg-4.2.1.tgz?cache=0&sync_timestamp=1632478211055&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40ant-design%2Ficons-svg%2Fdownload%2F%40ant-design%2Ficons-svg-4.2.1.tgz"
-  "version" "4.2.1"
-
-"@ant-design/icons-vue@^6.0.0", "@ant-design/icons-vue@^6.0.1":
-  "integrity" "sha1-nYBMPHTSz6+XyxjlgtO5QAk09f0="
-  "resolved" "https://registry.npmmirror.com/@ant-design/icons-vue/download/@ant-design/icons-vue-6.0.1.tgz"
-  "version" "6.0.1"
-  dependencies:
-    "@ant-design/colors" "^5.0.0"
-    "@ant-design/icons-svg" "^4.0.0"
-    "@types/lodash" "^4.14.165"
-    "lodash" "^4.17.15"
-
-"@babel/code-frame@^7.16.7":
-  "integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="
-  "resolved" "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/highlight" "^7.16.7"
-
-"@babel/code-frame@7.12.11":
-  "integrity" "sha1-9K1DWqJj25NbjxDyxVLSP7cWpj8="
-  "resolved" "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.12.11.tgz"
-  "version" "7.12.11"
-  dependencies:
-    "@babel/highlight" "^7.10.4"
-
-"@babel/compat-data@^7.16.4":
-  "integrity" "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q=="
-  "resolved" "https://registry.npmmirror.com/@babel/compat-data/download/@babel/compat-data-7.16.8.tgz"
-  "version" "7.16.8"
-
-"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.17":
-  "integrity" "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA=="
-  "resolved" "https://registry.npmmirror.com/@babel/core/download/@babel/core-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/code-frame" "^7.16.7"
-    "@babel/generator" "^7.16.7"
-    "@babel/helper-compilation-targets" "^7.16.7"
-    "@babel/helper-module-transforms" "^7.16.7"
-    "@babel/helpers" "^7.16.7"
-    "@babel/parser" "^7.16.7"
-    "@babel/template" "^7.16.7"
-    "@babel/traverse" "^7.16.7"
-    "@babel/types" "^7.16.7"
-    "convert-source-map" "^1.7.0"
-    "debug" "^4.1.0"
-    "gensync" "^1.0.0-beta.2"
-    "json5" "^2.1.2"
-    "semver" "^6.3.0"
-    "source-map" "^0.5.0"
-
-"@babel/generator@^7.16.7", "@babel/generator@^7.16.8":
-  "integrity" "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw=="
-  "resolved" "https://registry.npmmirror.com/@babel/generator/download/@babel/generator-7.16.8.tgz"
-  "version" "7.16.8"
-  dependencies:
-    "@babel/types" "^7.16.8"
-    "jsesc" "^2.5.1"
-    "source-map" "^0.5.0"
-
-"@babel/helper-compilation-targets@^7.16.7":
-  "integrity" "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/compat-data" "^7.16.4"
-    "@babel/helper-validator-option" "^7.16.7"
-    "browserslist" "^4.17.5"
-    "semver" "^6.3.0"
-
-"@babel/helper-environment-visitor@^7.16.7":
-  "integrity" "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-environment-visitor/download/@babel/helper-environment-visitor-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-function-name@^7.16.7":
-  "integrity" "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-function-name/download/@babel/helper-function-name-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/helper-get-function-arity" "^7.16.7"
-    "@babel/template" "^7.16.7"
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-get-function-arity@^7.16.7":
-  "integrity" "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-hoist-variables@^7.16.7":
-  "integrity" "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7":
-  "integrity" "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-module-imports/download/@babel/helper-module-imports-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-module-transforms@^7.16.7":
-  "integrity" "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.16.7"
-    "@babel/helper-module-imports" "^7.16.7"
-    "@babel/helper-simple-access" "^7.16.7"
-    "@babel/helper-split-export-declaration" "^7.16.7"
-    "@babel/helper-validator-identifier" "^7.16.7"
-    "@babel/template" "^7.16.7"
-    "@babel/traverse" "^7.16.7"
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-plugin-utils@^7.10.4":
-  "integrity" "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.16.7.tgz"
-  "version" "7.16.7"
-
-"@babel/helper-simple-access@^7.16.7":
-  "integrity" "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-simple-access/download/@babel/helper-simple-access-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-split-export-declaration@^7.16.7":
-  "integrity" "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/types" "^7.16.7"
-
-"@babel/helper-validator-identifier@^7.16.7":
-  "integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.16.7.tgz"
-  "version" "7.16.7"
-
-"@babel/helper-validator-option@^7.16.7":
-  "integrity" "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
-  "resolved" "https://registry.npmmirror.com/@babel/helper-validator-option/download/@babel/helper-validator-option-7.16.7.tgz"
-  "version" "7.16.7"
-
-"@babel/helpers@^7.16.7":
-  "integrity" "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw=="
-  "resolved" "https://registry.npmmirror.com/@babel/helpers/download/@babel/helpers-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/template" "^7.16.7"
-    "@babel/traverse" "^7.16.7"
-    "@babel/types" "^7.16.7"
-
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7":
-  "integrity" "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw=="
-  "resolved" "https://registry.npmmirror.com/@babel/highlight/download/@babel/highlight-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.16.7"
-    "chalk" "^2.0.0"
-    "js-tokens" "^4.0.0"
-
-"@babel/parser@^7.16.4", "@babel/parser@^7.16.7", "@babel/parser@^7.16.8":
-  "integrity" "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw=="
-  "resolved" "https://registry.npmmirror.com/@babel/parser/download/@babel/parser-7.16.8.tgz"
-  "version" "7.16.8"
-
-"@babel/plugin-syntax-import-meta@^7.10.4":
-  "integrity" "sha1-7mATSMNw+jNNIge+FYd3SWUh/VE="
-  "resolved" "https://registry.npmmirror.com/@babel/plugin-syntax-import-meta/download/@babel/plugin-syntax-import-meta-7.10.4.tgz"
-  "version" "7.10.4"
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.5":
-  "integrity" "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ=="
-  "resolved" "https://registry.npmmirror.com/@babel/runtime/download/@babel/runtime-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "regenerator-runtime" "^0.13.4"
-
-"@babel/standalone@^7.16.4":
-  "integrity" "sha512-2xC+uqniw1MNMTxzkfRUD8y0koEav+cGyWNCTVFAMC58Mb6HYfxqzQt+YtdMpSEcNqrDjvatthhyU0v18PNrnA=="
-  "resolved" "https://registry.npmmirror.com/@babel/standalone/download/@babel/standalone-7.16.9.tgz"
-  "version" "7.16.9"
-
-"@babel/template@^7.16.7":
-  "integrity" "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w=="
-  "resolved" "https://registry.npmmirror.com/@babel/template/download/@babel/template-7.16.7.tgz"
-  "version" "7.16.7"
-  dependencies:
-    "@babel/code-frame" "^7.16.7"
-    "@babel/parser" "^7.16.7"
-    "@babel/types" "^7.16.7"
-
-"@babel/traverse@^7.16.7":
-  "integrity" "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ=="
-  "resolved" "https://registry.npmmirror.com/@babel/traverse/download/@babel/traverse-7.16.8.tgz"
-  "version" "7.16.8"
-  dependencies:
-    "@babel/code-frame" "^7.16.7"
-    "@babel/generator" "^7.16.8"
-    "@babel/helper-environment-visitor" "^7.16.7"
-    "@babel/helper-function-name" "^7.16.7"
-    "@babel/helper-hoist-variables" "^7.16.7"
-    "@babel/helper-split-export-declaration" "^7.16.7"
-    "@babel/parser" "^7.16.8"
-    "@babel/types" "^7.16.8"
-    "debug" "^4.1.0"
-    "globals" "^11.1.0"
-
-"@babel/types@^7.16.7", "@babel/types@^7.16.8":
-  "integrity" "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg=="
-  "resolved" "https://registry.npmmirror.com/@babel/types/download/@babel/types-7.16.8.tgz"
-  "version" "7.16.8"
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.16.7"
-    "to-fast-properties" "^2.0.0"
-
-"@ctrl/tinycolor@^3.3.1":
-  "integrity" "sha1-w8WuVDyJfKqcKmhjC+01W+X5mQ8="
-  "resolved" "https://registry.npmmirror.com/@ctrl/tinycolor/download/@ctrl/tinycolor-3.4.0.tgz"
-  "version" "3.4.0"
-
-"@eslint/eslintrc@^0.4.3":
-  "integrity" "sha1-nkKYHvA1vrPdSa3ResuW6P9vOUw="
-  "resolved" "https://registry.npmmirror.com/@eslint/eslintrc/download/@eslint/eslintrc-0.4.3.tgz"
-  "version" "0.4.3"
-  dependencies:
-    "ajv" "^6.12.4"
-    "debug" "^4.1.1"
-    "espree" "^7.3.0"
-    "globals" "^13.9.0"
-    "ignore" "^4.0.6"
-    "import-fresh" "^3.2.1"
-    "js-yaml" "^3.13.1"
-    "minimatch" "^3.0.4"
-    "strip-json-comments" "^3.1.1"
-
-"@humanwhocodes/config-array@^0.5.0":
-  "integrity" "sha1-FAeWfUxu7Nc4j4Os8er00Mbljvk="
-  "resolved" "https://registry.npmmirror.com/@humanwhocodes/config-array/download/@humanwhocodes/config-array-0.5.0.tgz?cache=0&sync_timestamp=1635880739605&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40humanwhocodes%2Fconfig-array%2Fdownload%2F%40humanwhocodes%2Fconfig-array-0.5.0.tgz"
-  "version" "0.5.0"
-  dependencies:
-    "@humanwhocodes/object-schema" "^1.2.0"
-    "debug" "^4.1.1"
-    "minimatch" "^3.0.4"
-
-"@humanwhocodes/object-schema@^1.2.0":
-  "integrity" "sha1-tSBSnsIdjllFoYUd/Rwy6U45/0U="
-  "resolved" "https://registry.npmmirror.com/@humanwhocodes/object-schema/download/@humanwhocodes/object-schema-1.2.1.tgz"
-  "version" "1.2.1"
-
-"@intlify/core-base@9.1.9":
-  "integrity" "sha1-5OjJUQEHKOSvOg0T10zz+eet1/Y="
-  "resolved" "https://registry.npmmirror.com/@intlify/core-base/download/@intlify/core-base-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/devtools-if" "9.1.9"
-    "@intlify/message-compiler" "9.1.9"
-    "@intlify/message-resolver" "9.1.9"
-    "@intlify/runtime" "9.1.9"
-    "@intlify/shared" "9.1.9"
-    "@intlify/vue-devtools" "9.1.9"
-
-"@intlify/devtools-if@9.1.9":
-  "integrity" "sha1-ow4d0SVv8sXJjY110HU4T7qJjl0="
-  "resolved" "https://registry.npmmirror.com/@intlify/devtools-if/download/@intlify/devtools-if-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/shared" "9.1.9"
-
-"@intlify/message-compiler@9.1.9":
-  "integrity" "sha1-EZPL0iSnHC+5gUVbhTSjx2bSlI0="
-  "resolved" "https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/message-resolver" "9.1.9"
-    "@intlify/shared" "9.1.9"
-    "source-map" "0.6.1"
-
-"@intlify/message-resolver@9.1.9":
-  "integrity" "sha1-MVXM0vXm0NwWyti38djpf82gW/w="
-  "resolved" "https://registry.npmmirror.com/@intlify/message-resolver/download/@intlify/message-resolver-9.1.9.tgz?cache=0&sync_timestamp=1633533008021&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40intlify%2Fmessage-resolver%2Fdownload%2F%40intlify%2Fmessage-resolver-9.1.9.tgz"
-  "version" "9.1.9"
-
-"@intlify/runtime@9.1.9":
-  "integrity" "sha1-LBLOKVGKB1Yp7+0KjtKT7nQMsoU="
-  "resolved" "https://registry.npmmirror.com/@intlify/runtime/download/@intlify/runtime-9.1.9.tgz?cache=0&sync_timestamp=1633534552005&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40intlify%2Fruntime%2Fdownload%2F%40intlify%2Fruntime-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/message-compiler" "9.1.9"
-    "@intlify/message-resolver" "9.1.9"
-    "@intlify/shared" "9.1.9"
-
-"@intlify/shared@9.1.9":
-  "integrity" "sha1-C6r5YSi4VWBma+x4T/sB9mI8wXo="
-  "resolved" "https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.1.9.tgz"
-  "version" "9.1.9"
-
-"@intlify/vue-devtools@9.1.9":
-  "integrity" "sha1-K+j02+f37UEVZ26zI0gUHUEeQms="
-  "resolved" "https://registry.npmmirror.com/@intlify/vue-devtools/download/@intlify/vue-devtools-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/message-resolver" "9.1.9"
-    "@intlify/runtime" "9.1.9"
-    "@intlify/shared" "9.1.9"
-
-"@nodelib/fs.scandir@2.1.5":
-  "integrity" "sha1-dhnC6yGyVIP20WdUi0z9WnSIw9U="
-  "resolved" "https://registry.nlark.com/@nodelib/fs.scandir/download/@nodelib/fs.scandir-2.1.5.tgz"
-  "version" "2.1.5"
-  dependencies:
-    "@nodelib/fs.stat" "2.0.5"
-    "run-parallel" "^1.1.9"
-
-"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
-  "integrity" "sha1-W9Jir5Tp0lvR5xsF3u1Eh2oiLos="
-  "resolved" "https://registry.npmmirror.com/@nodelib/fs.stat/download/@nodelib/fs.stat-2.0.5.tgz"
-  "version" "2.0.5"
-
-"@nodelib/fs.walk@^1.2.3":
-  "integrity" "sha1-6Vc36LtnRt3t9pxVaVNJTxlv5po="
-  "resolved" "https://registry.nlark.com/@nodelib/fs.walk/download/@nodelib/fs.walk-1.2.8.tgz?cache=0&sync_timestamp=1625769815389&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40nodelib%2Ffs.walk%2Fdownload%2F%40nodelib%2Ffs.walk-1.2.8.tgz"
-  "version" "1.2.8"
-  dependencies:
-    "@nodelib/fs.scandir" "2.1.5"
-    "fastq" "^1.6.0"
-
-"@rollup/pluginutils@^4.0.0", "@rollup/pluginutils@^4.1.0", "@rollup/pluginutils@^4.1.2":
-  "integrity" "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ=="
-  "resolved" "https://registry.npmmirror.com/@rollup/pluginutils/download/@rollup/pluginutils-4.1.2.tgz"
-  "version" "4.1.2"
-  dependencies:
-    "estree-walker" "^2.0.1"
-    "picomatch" "^2.2.2"
-
-"@simonwep/pickr@~1.8.0":
-  "integrity" "sha1-ltyGZ1lA18rWPWnCIIPdHLuXl8s="
-  "resolved" "https://registry.nlark.com/@simonwep/pickr/download/@simonwep/pickr-1.8.2.tgz"
-  "version" "1.8.2"
-  dependencies:
-    "core-js" "^3.15.1"
-    "nanopop" "^2.1.0"
-
-"@trysound/sax@0.2.0":
-  "integrity" "sha1-zMqrdYr1Z2Hre/N69vA/Mm3XmK0="
-  "resolved" "https://registry.nlark.com/@trysound/sax/download/@trysound/sax-0.2.0.tgz"
-  "version" "0.2.0"
-
-"@types/estree@*":
-  "integrity" "sha1-Hgyqk2TT/M0pMcPtlv2+ql1MyoM="
-  "resolved" "https://registry.npmmirror.com/@types/estree/download/@types/estree-0.0.50.tgz?cache=0&sync_timestamp=1637266061438&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Festree%2Fdownload%2F%40types%2Festree-0.0.50.tgz"
-  "version" "0.0.50"
-
-"@types/json-schema@^7.0.9":
-  "integrity" "sha1-l+3JA36gw4WFMgsolk3eOznkZg0="
-  "resolved" "https://registry.npmmirror.com/@types/json-schema/download/@types/json-schema-7.0.9.tgz?cache=0&sync_timestamp=1637265456183&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.9.tgz"
-  "version" "7.0.9"
-
-"@types/json5@^0.0.29":
-  "integrity" "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
-  "resolved" "https://registry.npmmirror.com/@types/json5/download/@types/json5-0.0.29.tgz"
-  "version" "0.0.29"
-
-"@types/lodash@^4.14.165":
-  "integrity" "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
-  "resolved" "https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz"
-  "version" "4.14.178"
-
-"@types/node@*", "@types/node@^16.3.2":
-  "integrity" "sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng=="
-  "resolved" "https://registry.npmmirror.com/@types/node/download/@types/node-16.11.19.tgz"
-  "version" "16.11.19"
-
-"@types/svgo@^2.6.0":
-  "integrity" "sha512-4BfUnd19L25BD2iRyZTNuG4pfL9HBs+rvF7zp5maKhbX42uOpc5prGdBXXmCdHlVZfTWq8pNP/vxQt9v8ACxqQ=="
-  "resolved" "https://registry.npmmirror.com/@types/svgo/download/@types/svgo-2.6.1.tgz"
-  "version" "2.6.1"
-  dependencies:
-    "@types/node" "*"
-
-"@types/urlencode@^1.1.2":
-  "integrity" "sha1-YMiiBmZ+TJaom0rkfowKna35A0s="
-  "resolved" "https://registry.npmmirror.com/@types/urlencode/download/@types/urlencode-1.1.2.tgz"
-  "version" "1.1.2"
-
-"@typescript-eslint/eslint-plugin@^5.8.1":
-  "integrity" "sha512-Xv9tkFlyD4MQGpJgTo6wqDqGvHIRmRgah/2Sjz1PUnJTawjHWIwBivUE9x0QtU2WVii9baYgavo/bHjrZJkqTw=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/download/@typescript-eslint/eslint-plugin-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/experimental-utils" "5.9.1"
-    "@typescript-eslint/scope-manager" "5.9.1"
-    "@typescript-eslint/type-utils" "5.9.1"
-    "debug" "^4.3.2"
-    "functional-red-black-tree" "^1.0.1"
-    "ignore" "^5.1.8"
-    "regexpp" "^3.2.0"
-    "semver" "^7.3.5"
-    "tsutils" "^3.21.0"
-
-"@typescript-eslint/experimental-utils@5.9.1":
-  "integrity" "sha512-cb1Njyss0mLL9kLXgS/eEY53SZQ9sT519wpX3i+U457l2UXRDuo87hgKfgRazmu9/tQb0x2sr3Y0yrU+Zz0y+w=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/experimental-utils/download/@typescript-eslint/experimental-utils-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@types/json-schema" "^7.0.9"
-    "@typescript-eslint/scope-manager" "5.9.1"
-    "@typescript-eslint/types" "5.9.1"
-    "@typescript-eslint/typescript-estree" "5.9.1"
-    "eslint-scope" "^5.1.1"
-    "eslint-utils" "^3.0.0"
-
-"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.8.1":
-  "integrity" "sha512-PLYO0AmwD6s6n0ZQB5kqPgfvh73p0+VqopQQLuNfi7Lm0EpfKyDalchpVwkE+81k5HeiRrTV/9w1aNHzjD7C4g=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/parser/download/@typescript-eslint/parser-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/scope-manager" "5.9.1"
-    "@typescript-eslint/types" "5.9.1"
-    "@typescript-eslint/typescript-estree" "5.9.1"
-    "debug" "^4.3.2"
-
-"@typescript-eslint/scope-manager@5.9.1":
-  "integrity" "sha512-8BwvWkho3B/UOtzRyW07ffJXPaLSUKFBjpq8aqsRvu6HdEuzCY57+ffT7QoV4QXJXWSU1+7g3wE4AlgImmQ9pQ=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/scope-manager/download/@typescript-eslint/scope-manager-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/types" "5.9.1"
-    "@typescript-eslint/visitor-keys" "5.9.1"
-
-"@typescript-eslint/type-utils@5.9.1":
-  "integrity" "sha512-tRSpdBnPRssjlUh35rE9ug5HrUvaB9ntREy7gPXXKwmIx61TNN7+l5YKgi1hMKxo5NvqZCfYhA5FvyuJG6X6vg=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/type-utils/download/@typescript-eslint/type-utils-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/experimental-utils" "5.9.1"
-    "debug" "^4.3.2"
-    "tsutils" "^3.21.0"
-
-"@typescript-eslint/types@5.9.1":
-  "integrity" "sha512-SsWegWudWpkZCwwYcKoDwuAjoZXnM1y2EbEerTHho19Hmm+bQ56QG4L4jrtCu0bI5STaRTvRTZmjprWlTw/5NQ=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/types/download/@typescript-eslint/types-5.9.1.tgz"
-  "version" "5.9.1"
-
-"@typescript-eslint/typescript-estree@5.9.1":
-  "integrity" "sha512-gL1sP6A/KG0HwrahVXI9fZyeVTxEYV//6PmcOn1tD0rw8VhUWYeZeuWHwwhnewnvEMcHjhnJLOBhA9rK4vmb8A=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/download/@typescript-eslint/typescript-estree-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/types" "5.9.1"
-    "@typescript-eslint/visitor-keys" "5.9.1"
-    "debug" "^4.3.2"
-    "globby" "^11.0.4"
-    "is-glob" "^4.0.3"
-    "semver" "^7.3.5"
-    "tsutils" "^3.21.0"
-
-"@typescript-eslint/visitor-keys@5.9.1":
-  "integrity" "sha512-Xh37pNz9e9ryW4TVdwiFzmr4hloty8cFj8GTWMXh3Z8swGwyQWeCcNgF0hm6t09iZd6eiZmIf4zHedQVP6TVtg=="
-  "resolved" "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/download/@typescript-eslint/visitor-keys-5.9.1.tgz"
-  "version" "5.9.1"
-  dependencies:
-    "@typescript-eslint/types" "5.9.1"
-    "eslint-visitor-keys" "^3.0.0"
-
-"@vitejs/plugin-legacy@^1.6.2":
-  "integrity" "sha512-geH2F3hTRN++E4n9NZ0JFumxIWUKqW4FA9PAgM7Q6RvUOUUYW4tlURhEmCBYfZSN24H/yX3mEolX+wFVErsAYQ=="
-  "resolved" "https://registry.npmmirror.com/@vitejs/plugin-legacy/download/@vitejs/plugin-legacy-1.6.4.tgz"
-  "version" "1.6.4"
-  dependencies:
-    "@babel/standalone" "^7.16.4"
-    "core-js" "^3.19.1"
-    "magic-string" "^0.25.7"
-    "regenerator-runtime" "^0.13.9"
-    "systemjs" "^6.11.0"
-
-"@vitejs/plugin-vue@^1.2.4":
-  "integrity" "sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw=="
-  "resolved" "https://registry.npmmirror.com/@vitejs/plugin-vue/download/@vitejs/plugin-vue-1.10.2.tgz"
-  "version" "1.10.2"
-
-"@vue/compiler-core@3.2.26":
-  "integrity" "sha512-N5XNBobZbaASdzY9Lga2D9Lul5vdCIOXvUMd6ThcN8zgqQhPKfCV+wfAJNNJKQkSHudnYRO2gEB+lp0iN3g2Tw=="
-  "resolved" "https://registry.npmmirror.com/@vue/compiler-core/download/@vue/compiler-core-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/shared" "3.2.26"
-    "estree-walker" "^2.0.2"
-    "source-map" "^0.6.1"
-
-"@vue/compiler-dom@3.2.26":
-  "integrity" "sha512-smBfaOW6mQDxcT3p9TKT6mE22vjxjJL50GFVJiI0chXYGU/xzC05QRGrW3HHVuJrmLTLx5zBhsZ2dIATERbarg=="
-  "resolved" "https://registry.npmmirror.com/@vue/compiler-dom/download/@vue/compiler-dom-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/compiler-core" "3.2.26"
-    "@vue/shared" "3.2.26"
-
-"@vue/compiler-sfc@^3.0.5", "@vue/compiler-sfc@>=3.1.0", "@vue/compiler-sfc@3.2.26":
-  "integrity" "sha512-ePpnfktV90UcLdsDQUh2JdiTuhV0Skv2iYXxfNMOK/F3Q+2BO0AulcVcfoksOpTJGmhhfosWfMyEaEf0UaWpIw=="
-  "resolved" "https://registry.npmmirror.com/@vue/compiler-sfc/download/@vue/compiler-sfc-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.26"
-    "@vue/compiler-dom" "3.2.26"
-    "@vue/compiler-ssr" "3.2.26"
-    "@vue/reactivity-transform" "3.2.26"
-    "@vue/shared" "3.2.26"
-    "estree-walker" "^2.0.2"
-    "magic-string" "^0.25.7"
-    "postcss" "^8.1.10"
-    "source-map" "^0.6.1"
-
-"@vue/compiler-ssr@3.2.26":
-  "integrity" "sha512-2mywLX0ODc4Zn8qBoA2PDCsLEZfpUGZcyoFRLSOjyGGK6wDy2/5kyDOWtf0S0UvtoyVq95OTSGIALjZ4k2q/ag=="
-  "resolved" "https://registry.npmmirror.com/@vue/compiler-ssr/download/@vue/compiler-ssr-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/compiler-dom" "3.2.26"
-    "@vue/shared" "3.2.26"
-
-"@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.0.0-beta.18", "@vue/devtools-api@^6.0.0-beta.7":
-  "integrity" "sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw=="
-  "resolved" "https://registry.npmmirror.com/@vue/devtools-api/download/@vue/devtools-api-6.0.0-beta.21.1.tgz"
-  "version" "6.0.0-beta.21.1"
-
-"@vue/reactivity-transform@3.2.26":
-  "integrity" "sha512-XKMyuCmzNA7nvFlYhdKwD78rcnmPb7q46uoR00zkX6yZrUmcCQ5OikiwUEVbvNhL5hBJuvbSO95jB5zkUon+eQ=="
-  "resolved" "https://registry.npmmirror.com/@vue/reactivity-transform/download/@vue/reactivity-transform-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.26"
-    "@vue/shared" "3.2.26"
-    "estree-walker" "^2.0.2"
-    "magic-string" "^0.25.7"
-
-"@vue/reactivity@3.2.26":
-  "integrity" "sha512-h38bxCZLW6oFJVDlCcAiUKFnXI8xP8d+eO0pcDxx+7dQfSPje2AO6M9S9QO6MrxQB7fGP0DH0dYQ8ksf6hrXKQ=="
-  "resolved" "https://registry.npmmirror.com/@vue/reactivity/download/@vue/reactivity-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/shared" "3.2.26"
-
-"@vue/runtime-core@3.2.26":
-  "integrity" "sha512-BcYi7qZ9Nn+CJDJrHQ6Zsmxei2hDW0L6AB4vPvUQGBm2fZyC0GXd/4nVbyA2ubmuhctD5RbYY8L+5GUJszv9mQ=="
-  "resolved" "https://registry.npmmirror.com/@vue/runtime-core/download/@vue/runtime-core-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/reactivity" "3.2.26"
-    "@vue/shared" "3.2.26"
-
-"@vue/runtime-dom@3.2.26":
-  "integrity" "sha512-dY56UIiZI+gjc4e8JQBwAifljyexfVCkIAu/WX8snh8vSOt/gMSEGwPRcl2UpYpBYeyExV8WCbgvwWRNt9cHhQ=="
-  "resolved" "https://registry.npmmirror.com/@vue/runtime-dom/download/@vue/runtime-dom-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/runtime-core" "3.2.26"
-    "@vue/shared" "3.2.26"
-    "csstype" "^2.6.8"
-
-"@vue/server-renderer@3.2.26":
-  "integrity" "sha512-Jp5SggDUvvUYSBIvYEhy76t4nr1vapY/FIFloWmQzn7UxqaHrrBpbxrqPcTrSgGrcaglj0VBp22BKJNre4aA1w=="
-  "resolved" "https://registry.npmmirror.com/@vue/server-renderer/download/@vue/server-renderer-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/compiler-ssr" "3.2.26"
-    "@vue/shared" "3.2.26"
-
-"@vue/shared@3.2.26":
-  "integrity" "sha512-vPV6Cq+NIWbH5pZu+V+2QHE9y1qfuTq49uNWw4f7FDEeZaDU2H2cx5jcUZOAKW7qTrUS4k6qZPbMy1x4N96nbA=="
-  "resolved" "https://registry.npmmirror.com/@vue/shared/download/@vue/shared-3.2.26.tgz"
-  "version" "3.2.26"
-
-"acorn-jsx@^5.2.0", "acorn-jsx@^5.3.1":
-  "integrity" "sha1-ftW7VZCLOy8bxVxq8WU7rafweTc="
-  "resolved" "https://registry.nlark.com/acorn-jsx/download/acorn-jsx-5.3.2.tgz"
-  "version" "5.3.2"
-
-"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^7.1.1", "acorn@^7.4.0":
-  "integrity" "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
-  "resolved" "https://registry.npmmirror.com/acorn/download/acorn-7.4.1.tgz"
-  "version" "7.4.1"
-
-"agora-rtc-sdk-ng@^4.12.1":
-  "integrity" "sha512-kmc+ZyKDdnY/BN3iAwBs+MSgTX8Zkc6THFSIAXN9WebjZ/F+N/JXItoNEcgQe3MdTABUli6w3pZ+iObnDqVkBw=="
-  "resolved" "https://registry.npmmirror.com/agora-rtc-sdk-ng/-/agora-rtc-sdk-ng-4.12.1.tgz"
-  "version" "4.12.1"
-  dependencies:
-    "agora-rte-extension" "^1.0.22"
-
-"agora-rte-extension@^1.0.22":
-  "integrity" "sha512-X2cGBg+L5ZJIFU91qvMASvRsBfg1HXTktVG3YROw9wxHsILSI7jgF9R9XraLc3fNX/UjovaYAlUW+hiJe0v6Xw=="
-  "resolved" "https://registry.npmmirror.com/agora-rte-extension/-/agora-rte-extension-1.0.23.tgz"
-  "version" "1.0.23"
-
-"ajv@^6.10.0", "ajv@^6.12.4":
-  "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="
-  "resolved" "https://registry.npmmirror.com/ajv/download/ajv-6.12.6.tgz"
-  "version" "6.12.6"
-  dependencies:
-    "fast-deep-equal" "^3.1.1"
-    "fast-json-stable-stringify" "^2.0.0"
-    "json-schema-traverse" "^0.4.1"
-    "uri-js" "^4.2.2"
-
-"ajv@^8.0.1":
-  "integrity" "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw=="
-  "resolved" "https://registry.npmmirror.com/ajv/download/ajv-8.8.2.tgz"
-  "version" "8.8.2"
-  dependencies:
-    "fast-deep-equal" "^3.1.1"
-    "json-schema-traverse" "^1.0.0"
-    "require-from-string" "^2.0.2"
-    "uri-js" "^4.2.2"
-
-"ansi-colors@^4.1.1":
-  "integrity" "sha1-y7muJWv3UK8eqzRPIpqif+lLo0g="
-  "resolved" "https://registry.nlark.com/ansi-colors/download/ansi-colors-4.1.1.tgz"
-  "version" "4.1.1"
-
-"ansi-regex@^2.0.0":
-  "integrity" "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
-  "resolved" "https://registry.nlark.com/ansi-regex/download/ansi-regex-2.1.1.tgz?cache=0&sync_timestamp=1631634988487&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-regex%2Fdownload%2Fansi-regex-2.1.1.tgz"
-  "version" "2.1.1"
-
-"ansi-regex@^5.0.1":
-  "integrity" "sha1-CCyyyJyf6GWaMRpTvWpNxTAdswQ="
-  "resolved" "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.1.tgz?cache=0&sync_timestamp=1631634988487&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-regex%2Fdownload%2Fansi-regex-5.0.1.tgz"
-  "version" "5.0.1"
-
-"ansi-styles@^2.2.1":
-  "integrity" "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="
-  "resolved" "https://registry.npmmirror.com/ansi-styles/download/ansi-styles-2.2.1.tgz"
-  "version" "2.2.1"
-
-"ansi-styles@^3.2.1":
-  "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="
-  "resolved" "https://registry.npmmirror.com/ansi-styles/download/ansi-styles-3.2.1.tgz"
-  "version" "3.2.1"
-  dependencies:
-    "color-convert" "^1.9.0"
-
-"ansi-styles@^4.0.0", "ansi-styles@^4.1.0":
-  "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
-  "resolved" "https://registry.npmmirror.com/ansi-styles/download/ansi-styles-4.3.0.tgz"
-  "version" "4.3.0"
-  dependencies:
-    "color-convert" "^2.0.1"
-
-"ant-design-vue@^2.2.8":
-  "integrity" "sha512-3graq9/gCfJQs6hznrHV6sa9oDmk/D1H3Oo0vLdVpPS/I61fZPk8NEyNKCHpNA6fT2cx6xx9U3QS63uuyikg/Q=="
-  "resolved" "https://registry.npmmirror.com/ant-design-vue/download/ant-design-vue-2.2.8.tgz"
-  "version" "2.2.8"
-  dependencies:
-    "@ant-design/icons-vue" "^6.0.0"
-    "@babel/runtime" "^7.10.5"
-    "@simonwep/pickr" "~1.8.0"
-    "array-tree-filter" "^2.1.0"
-    "async-validator" "^3.3.0"
-    "dom-align" "^1.12.1"
-    "dom-scroll-into-view" "^2.0.0"
-    "lodash" "^4.17.21"
-    "lodash-es" "^4.17.15"
-    "moment" "^2.27.0"
-    "omit.js" "^2.0.0"
-    "resize-observer-polyfill" "^1.5.1"
-    "scroll-into-view-if-needed" "^2.2.25"
-    "shallow-equal" "^1.0.0"
-    "vue-types" "^3.0.0"
-    "warning" "^4.0.0"
-
-"anymatch@~3.1.2":
-  "integrity" "sha1-wFV8CWrzLxBhmPT04qODU343hxY="
-  "resolved" "https://registry.npmmirror.com/anymatch/download/anymatch-3.1.2.tgz"
-  "version" "3.1.2"
-  dependencies:
-    "normalize-path" "^3.0.0"
-    "picomatch" "^2.0.4"
-
-"argparse@^1.0.7":
-  "integrity" "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE="
-  "resolved" "https://registry.npmmirror.com/argparse/download/argparse-1.0.10.tgz"
-  "version" "1.0.10"
-  dependencies:
-    "sprintf-js" "~1.0.2"
-
-"arr-diff@^4.0.0":
-  "integrity" "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
-  "resolved" "https://registry.npmmirror.com/arr-diff/download/arr-diff-4.0.0.tgz"
-  "version" "4.0.0"
-
-"arr-flatten@^1.1.0":
-  "integrity" "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE="
-  "resolved" "https://registry.nlark.com/arr-flatten/download/arr-flatten-1.1.0.tgz"
-  "version" "1.1.0"
-
-"arr-union@^3.1.0":
-  "integrity" "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
-  "resolved" "https://registry.npmmirror.com/arr-union/download/arr-union-3.1.0.tgz"
-  "version" "3.1.0"
-
-"array-includes@^3.1.4":
-  "integrity" "sha1-9bSTFix2DzU5Yx8AW6K7Rqy0W6k="
-  "resolved" "https://registry.npmmirror.com/array-includes/download/array-includes-3.1.4.tgz"
-  "version" "3.1.4"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "define-properties" "^1.1.3"
-    "es-abstract" "^1.19.1"
-    "get-intrinsic" "^1.1.1"
-    "is-string" "^1.0.7"
-
-"array-tree-filter@^2.1.0":
-  "integrity" "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA="
-  "resolved" "https://registry.npmmirror.com/array-tree-filter/download/array-tree-filter-2.1.0.tgz"
-  "version" "2.1.0"
-
-"array-union@^2.1.0":
-  "integrity" "sha1-t5hCCtvrHego2ErNii4j0+/oXo0="
-  "resolved" "https://registry.nlark.com/array-union/download/array-union-2.1.0.tgz"
-  "version" "2.1.0"
-
-"array-unique@^0.3.2":
-  "integrity" "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
-  "resolved" "https://registry.npmmirror.com/array-unique/download/array-unique-0.3.2.tgz"
-  "version" "0.3.2"
-
-"array.prototype.flat@^1.2.5":
-  "integrity" "sha1-B+CXXYS7x8SM0YedYJ5oJZjTPhM="
-  "resolved" "https://registry.npmmirror.com/array.prototype.flat/download/array.prototype.flat-1.2.5.tgz?cache=0&sync_timestamp=1633109609894&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Farray.prototype.flat%2Fdownload%2Farray.prototype.flat-1.2.5.tgz"
-  "version" "1.2.5"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "define-properties" "^1.1.3"
-    "es-abstract" "^1.19.0"
-
-"assign-symbols@^1.0.0":
-  "integrity" "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
-  "resolved" "https://registry.npmmirror.com/assign-symbols/download/assign-symbols-1.0.0.tgz"
-  "version" "1.0.0"
-
-"astral-regex@^2.0.0":
-  "integrity" "sha1-SDFDxWeu7UeFdZwIZXhtx319LjE="
-  "resolved" "https://registry.npmmirror.com/astral-regex/download/astral-regex-2.0.0.tgz"
-  "version" "2.0.0"
-
-"async-validator@^3.3.0":
-  "integrity" "sha1-aOhmqWgk6LJpT/eoMcGiXETV5QA="
-  "resolved" "https://registry.npmmirror.com/async-validator/download/async-validator-3.5.2.tgz"
-  "version" "3.5.2"
-
-"atob@^2.1.2":
-  "integrity" "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k="
-  "resolved" "https://registry.npmmirror.com/atob/download/atob-2.1.2.tgz"
-  "version" "2.1.2"
-
-"axios@^0.21.1":
-  "integrity" "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="
-  "resolved" "https://registry.npmmirror.com/axios/download/axios-0.21.4.tgz"
-  "version" "0.21.4"
-  dependencies:
-    "follow-redirects" "^1.14.0"
-
-"babel-plugin-import@^1.13.3":
-  "integrity" "sha1-nbu6fRrHK9QSkXqDDUReAJQdJtc="
-  "resolved" "https://registry.npmmirror.com/babel-plugin-import/download/babel-plugin-import-1.13.3.tgz"
-  "version" "1.13.3"
-  dependencies:
-    "@babel/helper-module-imports" "^7.0.0"
-    "@babel/runtime" "^7.0.0"
-
-"balanced-match@^1.0.0":
-  "integrity" "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4="
-  "resolved" "https://registry.npmmirror.com/balanced-match/download/balanced-match-1.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fbalanced-match%2Fdownload%2Fbalanced-match-1.0.2.tgz"
-  "version" "1.0.2"
-
-"base@^0.11.1":
-  "integrity" "sha1-e95c7RRbbVUakNuH+DxVi060io8="
-  "resolved" "https://registry.npmmirror.com/base/download/base-0.11.2.tgz"
-  "version" "0.11.2"
-  dependencies:
-    "cache-base" "^1.0.1"
-    "class-utils" "^0.3.5"
-    "component-emitter" "^1.2.1"
-    "define-property" "^1.0.0"
-    "isobject" "^3.0.1"
-    "mixin-deep" "^1.2.0"
-    "pascalcase" "^0.1.1"
-
-"base64-js@^1.3.1":
-  "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
-  "resolved" "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz"
-  "version" "1.5.1"
-
-"big-integer@^1.6.17":
-  "integrity" "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
-  "resolved" "https://registry.npmmirror.com/big-integer/download/big-integer-1.6.51.tgz"
-  "version" "1.6.51"
-
-"big.js@^5.2.2":
-  "integrity" "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
-  "resolved" "https://registry.npmmirror.com/big.js/download/big.js-5.2.2.tgz"
-  "version" "5.2.2"
-
-"binary-extensions@^2.0.0":
-  "integrity" "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0="
-  "resolved" "https://registry.nlark.com/binary-extensions/download/binary-extensions-2.2.0.tgz"
-  "version" "2.2.0"
-
-"binary@~0.3.0":
-  "integrity" "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk="
-  "resolved" "https://registry.npmmirror.com/binary/download/binary-0.3.0.tgz"
-  "version" "0.3.0"
-  dependencies:
-    "buffers" "~0.1.1"
-    "chainsaw" "~0.1.0"
-
-"bl@^4.0.2":
-  "integrity" "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="
-  "resolved" "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz"
-  "version" "4.1.0"
-  dependencies:
-    "buffer" "^5.5.0"
-    "inherits" "^2.0.4"
-    "readable-stream" "^3.4.0"
-
-"bluebird@^3.5.0":
-  "integrity" "sha1-nyKcFb4nJFT/qXOs4NvueaGww28="
-  "resolved" "https://registry.npmmirror.com/bluebird/download/bluebird-3.7.2.tgz"
-  "version" "3.7.2"
-
-"bluebird@~3.4.1":
-  "integrity" "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM="
-  "resolved" "https://registry.npmmirror.com/bluebird/download/bluebird-3.4.7.tgz"
-  "version" "3.4.7"
-
-"boolbase@^1.0.0":
-  "integrity" "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
-  "resolved" "https://registry.npmmirror.com/boolbase/download/boolbase-1.0.0.tgz"
-  "version" "1.0.0"
-
-"brace-expansion@^1.1.7":
-  "integrity" "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0="
-  "resolved" "https://registry.npmmirror.com/brace-expansion/download/brace-expansion-1.1.11.tgz?cache=0&sync_timestamp=1614010709807&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fbrace-expansion%2Fdownload%2Fbrace-expansion-1.1.11.tgz"
-  "version" "1.1.11"
-  dependencies:
-    "balanced-match" "^1.0.0"
-    "concat-map" "0.0.1"
-
-"braces@^2.2.2":
-  "integrity" "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk="
-  "resolved" "https://registry.npmmirror.com/braces/download/braces-2.3.2.tgz"
-  "version" "2.3.2"
-  dependencies:
-    "arr-flatten" "^1.1.0"
-    "array-unique" "^0.3.2"
-    "extend-shallow" "^2.0.1"
-    "fill-range" "^4.0.0"
-    "isobject" "^3.0.1"
-    "repeat-element" "^1.1.2"
-    "snapdragon" "^0.8.1"
-    "snapdragon-node" "^2.0.1"
-    "split-string" "^3.0.2"
-    "to-regex" "^3.0.1"
-
-"braces@^3.0.1", "braces@~3.0.2":
-  "integrity" "sha1-NFThpGLujVmeI23zNs2epPiv4Qc="
-  "resolved" "https://registry.npmmirror.com/braces/download/braces-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "fill-range" "^7.0.1"
-
-"browserslist@^4.17.5":
-  "integrity" "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A=="
-  "resolved" "https://registry.npmmirror.com/browserslist/download/browserslist-4.19.1.tgz"
-  "version" "4.19.1"
-  dependencies:
-    "caniuse-lite" "^1.0.30001286"
-    "electron-to-chromium" "^1.4.17"
-    "escalade" "^3.1.1"
-    "node-releases" "^2.0.1"
-    "picocolors" "^1.0.0"
-
-"buffer-from@^1.0.0":
-  "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
-  "resolved" "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
-  "version" "1.1.2"
-
-"buffer-indexof-polyfill@~1.0.0":
-  "integrity" "sha1-0nMhNcWZnGSyd/z5savjSYJUcpw="
-  "resolved" "https://registry.npmmirror.com/buffer-indexof-polyfill/download/buffer-indexof-polyfill-1.0.2.tgz"
-  "version" "1.0.2"
-
-"buffer@^5.5.0":
-  "integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="
-  "resolved" "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz"
-  "version" "5.7.1"
-  dependencies:
-    "base64-js" "^1.3.1"
-    "ieee754" "^1.1.13"
-
-"buffers@~0.1.1":
-  "integrity" "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
-  "resolved" "https://registry.npmmirror.com/buffers/download/buffers-0.1.1.tgz"
-  "version" "0.1.1"
-
-"cache-base@^1.0.1":
-  "integrity" "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI="
-  "resolved" "https://registry.npmmirror.com/cache-base/download/cache-base-1.0.1.tgz?cache=0&sync_timestamp=1636237629294&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcache-base%2Fdownload%2Fcache-base-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "collection-visit" "^1.0.0"
-    "component-emitter" "^1.2.1"
-    "get-value" "^2.0.6"
-    "has-value" "^1.0.0"
-    "isobject" "^3.0.1"
-    "set-value" "^2.0.0"
-    "to-object-path" "^0.3.0"
-    "union-value" "^1.0.0"
-    "unset-value" "^1.0.0"
-
-"call-bind@^1.0.0", "call-bind@^1.0.2":
-  "integrity" "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw="
-  "resolved" "https://registry.nlark.com/call-bind/download/call-bind-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "function-bind" "^1.1.1"
-    "get-intrinsic" "^1.0.2"
-
-"callsites@^3.0.0":
-  "integrity" "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M="
-  "resolved" "https://registry.nlark.com/callsites/download/callsites-3.1.0.tgz"
-  "version" "3.1.0"
-
-"camel-case@^4.1.2":
-  "integrity" "sha1-lygHKpVPgFIoIlpt7qazhGHhvVo="
-  "resolved" "https://registry.npmmirror.com/camel-case/download/camel-case-4.1.2.tgz?cache=0&sync_timestamp=1606867297052&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcamel-case%2Fdownload%2Fcamel-case-4.1.2.tgz"
-  "version" "4.1.2"
-  dependencies:
-    "pascal-case" "^3.1.2"
-    "tslib" "^2.0.3"
-
-"caniuse-lite@^1.0.30001286":
-  "integrity" "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw=="
-  "resolved" "https://registry.npmmirror.com/caniuse-lite/download/caniuse-lite-1.0.30001299.tgz"
-  "version" "1.0.30001299"
-
-"capital-case@^1.0.4":
-  "integrity" "sha1-nRMCkjU8kkn2sA+lhSvuOKcX5mk="
-  "resolved" "https://registry.nlark.com/capital-case/download/capital-case-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "no-case" "^3.0.4"
-    "tslib" "^2.0.3"
-    "upper-case-first" "^2.0.2"
-
-"chainsaw@~0.1.0":
-  "integrity" "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg="
-  "resolved" "https://registry.npmmirror.com/chainsaw/download/chainsaw-0.1.0.tgz"
-  "version" "0.1.0"
-  dependencies:
-    "traverse" ">=0.3.0 <0.4"
-
-"chalk@^1.1.3":
-  "integrity" "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg="
-  "resolved" "https://registry.npmmirror.com/chalk/download/chalk-1.1.3.tgz"
-  "version" "1.1.3"
-  dependencies:
-    "ansi-styles" "^2.2.1"
-    "escape-string-regexp" "^1.0.2"
-    "has-ansi" "^2.0.0"
-    "strip-ansi" "^3.0.0"
-    "supports-color" "^2.0.0"
-
-"chalk@^2.0.0":
-  "integrity" "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ="
-  "resolved" "https://registry.npmmirror.com/chalk/download/chalk-2.4.2.tgz"
-  "version" "2.4.2"
-  dependencies:
-    "ansi-styles" "^3.2.1"
-    "escape-string-regexp" "^1.0.5"
-    "supports-color" "^5.3.0"
-
-"chalk@^4.0.0":
-  "integrity" "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE="
-  "resolved" "https://registry.npmmirror.com/chalk/download/chalk-4.1.2.tgz"
-  "version" "4.1.2"
-  dependencies:
-    "ansi-styles" "^4.1.0"
-    "supports-color" "^7.1.0"
-
-"change-case@^4.1.2":
-  "integrity" "sha1-/t/F8TYEXiOYwEEO5EH5VwRkHhI="
-  "resolved" "https://registry.npmmirror.com/change-case/download/change-case-4.1.2.tgz?cache=0&sync_timestamp=1606867326259&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fchange-case%2Fdownload%2Fchange-case-4.1.2.tgz"
-  "version" "4.1.2"
-  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.0.3"
-
-"chokidar@>=3.0.0 <4.0.0":
-  "integrity" "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ=="
-  "resolved" "https://registry.npmmirror.com/chokidar/download/chokidar-3.5.2.tgz"
-  "version" "3.5.2"
-  dependencies:
-    "anymatch" "~3.1.2"
-    "braces" "~3.0.2"
-    "glob-parent" "~5.1.2"
-    "is-binary-path" "~2.1.0"
-    "is-glob" "~4.0.1"
-    "normalize-path" "~3.0.0"
-    "readdirp" "~3.6.0"
-  optionalDependencies:
-    "fsevents" "~2.3.2"
-
-"class-utils@^0.3.5":
-  "integrity" "sha1-+TNprouafOAv1B+q0MqDAzGQxGM="
-  "resolved" "https://registry.npmmirror.com/class-utils/download/class-utils-0.3.6.tgz"
-  "version" "0.3.6"
-  dependencies:
-    "arr-union" "^3.1.0"
-    "define-property" "^0.2.5"
-    "isobject" "^3.0.0"
-    "static-extend" "^0.1.1"
-
-"clone@^2.1.1":
-  "integrity" "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
-  "resolved" "https://registry.npmmirror.com/clone/download/clone-2.1.2.tgz?cache=0&sync_timestamp=1589682821772&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fclone%2Fdownload%2Fclone-2.1.2.tgz"
-  "version" "2.1.2"
-
-"collection-visit@^1.0.0":
-  "integrity" "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA="
-  "resolved" "https://registry.npmmirror.com/collection-visit/download/collection-visit-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "map-visit" "^1.0.0"
-    "object-visit" "^1.0.0"
-
-"color-convert@^1.9.0":
-  "integrity" "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg="
-  "resolved" "https://registry.npmmirror.com/color-convert/download/color-convert-1.9.3.tgz"
-  "version" "1.9.3"
-  dependencies:
-    "color-name" "1.1.3"
-
-"color-convert@^2.0.1":
-  "integrity" "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM="
-  "resolved" "https://registry.npmmirror.com/color-convert/download/color-convert-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "color-name" "~1.1.4"
-
-"color-name@~1.1.4":
-  "integrity" "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI="
-  "resolved" "https://registry.npmmirror.com/color-name/download/color-name-1.1.4.tgz"
-  "version" "1.1.4"
-
-"color-name@1.1.3":
-  "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
-  "resolved" "https://registry.npmmirror.com/color-name/download/color-name-1.1.3.tgz"
-  "version" "1.1.3"
-
-"commander@^7.2.0":
-  "integrity" "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
-  "resolved" "https://registry.npmmirror.com/commander/download/commander-7.2.0.tgz"
-  "version" "7.2.0"
-
-"commist@^1.0.0":
-  "integrity" "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg=="
-  "resolved" "https://registry.npmmirror.com/commist/-/commist-1.1.0.tgz"
-  "version" "1.1.0"
-  dependencies:
-    "leven" "^2.1.0"
-    "minimist" "^1.1.0"
-
-"component-emitter@^1.2.1":
-  "integrity" "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A="
-  "resolved" "https://registry.npmmirror.com/component-emitter/download/component-emitter-1.3.0.tgz"
-  "version" "1.3.0"
-
-"compute-scroll-into-view@^1.0.17":
-  "integrity" "sha1-aojxis2dQunPS6pr7H4FImB6t6s="
-  "resolved" "https://registry.npmmirror.com/compute-scroll-into-view/download/compute-scroll-into-view-1.0.17.tgz?cache=0&sync_timestamp=1614043178722&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcompute-scroll-into-view%2Fdownload%2Fcompute-scroll-into-view-1.0.17.tgz"
-  "version" "1.0.17"
-
-"concat-map@0.0.1":
-  "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
-  "resolved" "https://registry.npmmirror.com/concat-map/download/concat-map-0.0.1.tgz"
-  "version" "0.0.1"
-
-"concat-stream@^2.0.0":
-  "integrity" "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="
-  "resolved" "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz"
-  "version" "2.0.0"
-  dependencies:
-    "buffer-from" "^1.0.0"
-    "inherits" "^2.0.3"
-    "readable-stream" "^3.0.2"
-    "typedarray" "^0.0.6"
-
-"constant-case@^3.0.4":
-  "integrity" "sha1-O4Sprq9M8x7EXmv13pG9+wWJ+vE="
-  "resolved" "https://registry.npmmirror.com/constant-case/download/constant-case-3.0.4.tgz?cache=0&sync_timestamp=1606867325763&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fconstant-case%2Fdownload%2Fconstant-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "no-case" "^3.0.4"
-    "tslib" "^2.0.3"
-    "upper-case" "^2.0.2"
-
-"convert-source-map@^1.7.0":
-  "integrity" "sha1-8zc8MtIbTXgN2ABFFGhPt5HKQ2k="
-  "resolved" "https://registry.nlark.com/convert-source-map/download/convert-source-map-1.8.0.tgz?cache=0&sync_timestamp=1624045304679&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fconvert-source-map%2Fdownload%2Fconvert-source-map-1.8.0.tgz"
-  "version" "1.8.0"
-  dependencies:
-    "safe-buffer" "~5.1.1"
-
-"cookie-storage@^6.1.0":
-  "integrity" "sha1-KRsvZi2WG+RPmZYmWTQhy/zyN5A="
-  "resolved" "https://registry.nlark.com/cookie-storage/download/cookie-storage-6.1.0.tgz"
-  "version" "6.1.0"
-
-"copy-descriptor@^0.1.0":
-  "integrity" "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
-  "resolved" "https://registry.npmmirror.com/copy-descriptor/download/copy-descriptor-0.1.1.tgz"
-  "version" "0.1.1"
-
-"copy-text-to-clipboard@^3.0.1":
-  "integrity" "sha1-jL+PkOCkfxLkokdDc2Jl0Ve85pw="
-  "resolved" "https://registry.npmmirror.com/copy-text-to-clipboard/download/copy-text-to-clipboard-3.0.1.tgz"
-  "version" "3.0.1"
-
-"core-js@^3.11.0", "core-js@^3.15.1", "core-js@^3.19.1":
-  "integrity" "sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw=="
-  "resolved" "https://registry.npmmirror.com/core-js/download/core-js-3.20.2.tgz"
-  "version" "3.20.2"
-
-"core-util-is@~1.0.0":
-  "integrity" "sha1-pgQtNjTCsn6TKPg3uWX6yDgI24U="
-  "resolved" "https://registry.nlark.com/core-util-is/download/core-util-is-1.0.3.tgz"
-  "version" "1.0.3"
-
-"cors@^2.8.5":
-  "integrity" "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="
-  "resolved" "https://registry.npmmirror.com/cors/download/cors-2.8.5.tgz"
-  "version" "2.8.5"
-  dependencies:
-    "object-assign" "^4"
-    "vary" "^1"
-
-"cross-spawn@^7.0.2":
-  "integrity" "sha1-9zqFudXUHQRVUcF34ogtSshXKKY="
-  "resolved" "https://registry.npmmirror.com/cross-spawn/download/cross-spawn-7.0.3.tgz"
-  "version" "7.0.3"
-  dependencies:
-    "path-key" "^3.1.0"
-    "shebang-command" "^2.0.0"
-    "which" "^2.0.1"
-
-"css-select@^4.1.3":
-  "integrity" "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ=="
-  "resolved" "https://registry.npmmirror.com/css-select/download/css-select-4.2.1.tgz"
-  "version" "4.2.1"
-  dependencies:
-    "boolbase" "^1.0.0"
-    "css-what" "^5.1.0"
-    "domhandler" "^4.3.0"
-    "domutils" "^2.8.0"
-    "nth-check" "^2.0.1"
-
-"css-tree@^1.1.2", "css-tree@^1.1.3":
-  "integrity" "sha1-60hw+2/XcHMn7JXC/yqwm16NuR0="
-  "resolved" "https://registry.npmmirror.com/css-tree/download/css-tree-1.1.3.tgz"
-  "version" "1.1.3"
-  dependencies:
-    "mdn-data" "2.0.14"
-    "source-map" "^0.6.1"
-
-"css-what@^5.1.0":
-  "integrity" "sha1-P3tweq32M7r2LCzrhXm1RbtA9/4="
-  "resolved" "https://registry.npmmirror.com/css-what/download/css-what-5.1.0.tgz"
-  "version" "5.1.0"
-
-"csso@^4.2.0":
-  "integrity" "sha1-6jpWE0bo3J9UbW/r7dUBh884lSk="
-  "resolved" "https://registry.npmmirror.com/csso/download/csso-4.2.0.tgz"
-  "version" "4.2.0"
-  dependencies:
-    "css-tree" "^1.1.2"
-
-"csstype@^2.6.8":
-  "integrity" "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ=="
-  "resolved" "https://registry.npmmirror.com/csstype/download/csstype-2.6.19.tgz?cache=0&sync_timestamp=1637224514674&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcsstype%2Fdownload%2Fcsstype-2.6.19.tgz"
-  "version" "2.6.19"
-
-"debug@^2.2.0":
-  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
-  "resolved" "https://registry.npmmirror.com/debug/download/debug-2.6.9.tgz"
-  "version" "2.6.9"
-  dependencies:
-    "ms" "2.0.0"
-
-"debug@^2.3.3":
-  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
-  "resolved" "https://registry.npmmirror.com/debug/download/debug-2.6.9.tgz"
-  "version" "2.6.9"
-  dependencies:
-    "ms" "2.0.0"
-
-"debug@^2.6.9":
-  "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
-  "resolved" "https://registry.npmmirror.com/debug/download/debug-2.6.9.tgz"
-  "version" "2.6.9"
-  dependencies:
-    "ms" "2.0.0"
-
-"debug@^3.2.7":
-  "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
-  "resolved" "https://registry.npmmirror.com/debug/download/debug-3.2.7.tgz"
-  "version" "3.2.7"
-  dependencies:
-    "ms" "^2.1.1"
-
-"debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1", "debug@^4.3.2", "debug@^4.3.3":
-  "integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="
-  "resolved" "https://registry.npmmirror.com/debug/download/debug-4.3.3.tgz"
-  "version" "4.3.3"
-  dependencies:
-    "ms" "2.1.2"
-
-"decode-uri-component@^0.2.0":
-  "integrity" "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
-  "resolved" "https://registry.npmmirror.com/decode-uri-component/download/decode-uri-component-0.2.0.tgz"
-  "version" "0.2.0"
-
-"deep-is@^0.1.3":
-  "integrity" "sha1-pvLc5hL63S7x9Rm3NVHxfoUZmDE="
-  "resolved" "https://registry.nlark.com/deep-is/download/deep-is-0.1.4.tgz"
-  "version" "0.1.4"
-
-"define-properties@^1.1.3":
-  "integrity" "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE="
-  "resolved" "https://registry.npmmirror.com/define-properties/download/define-properties-1.1.3.tgz"
-  "version" "1.1.3"
-  dependencies:
-    "object-keys" "^1.0.12"
-
-"define-property@^0.2.5":
-  "integrity" "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY="
-  "resolved" "https://registry.npmmirror.com/define-property/download/define-property-0.2.5.tgz"
-  "version" "0.2.5"
-  dependencies:
-    "is-descriptor" "^0.1.0"
-
-"define-property@^1.0.0":
-  "integrity" "sha1-dp66rz9KY6rTr56NMEybvnm/sOY="
-  "resolved" "https://registry.npmmirror.com/define-property/download/define-property-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "is-descriptor" "^1.0.0"
-
-"define-property@^2.0.2":
-  "integrity" "sha1-1Flono1lS6d+AqgX+HENcCyxbp0="
-  "resolved" "https://registry.npmmirror.com/define-property/download/define-property-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "is-descriptor" "^1.0.2"
-    "isobject" "^3.0.1"
-
-"dir-glob@^3.0.1":
-  "integrity" "sha1-Vtv3PZkqSpO6FYT0U0Bj/S5BcX8="
-  "resolved" "https://registry.npmmirror.com/dir-glob/download/dir-glob-3.0.1.tgz"
-  "version" "3.0.1"
-  dependencies:
-    "path-type" "^4.0.0"
-
-"doctrine@^2.1.0":
-  "integrity" "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850="
-  "resolved" "https://registry.npmmirror.com/doctrine/download/doctrine-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "esutils" "^2.0.2"
-
-"doctrine@^3.0.0":
-  "integrity" "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE="
-  "resolved" "https://registry.npmmirror.com/doctrine/download/doctrine-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "esutils" "^2.0.2"
-
-"dom-align@^1.12.1":
-  "integrity" "sha1-D4Fk69DJwhsMeQMQSTzYVYkqzUs="
-  "resolved" "https://registry.nlark.com/dom-align/download/dom-align-1.12.2.tgz"
-  "version" "1.12.2"
-
-"dom-scroll-into-view@^2.0.0":
-  "integrity" "sha1-DezIUigB/Y0/HGujVadNOCxfmJs="
-  "resolved" "https://registry.npmmirror.com/dom-scroll-into-view/download/dom-scroll-into-view-2.0.1.tgz"
-  "version" "2.0.1"
-
-"dom-serializer@^1.0.1":
-  "integrity" "sha1-YgZDfTLO767HFhgDIwx6ILwbTZE="
-  "resolved" "https://registry.nlark.com/dom-serializer/download/dom-serializer-1.3.2.tgz?cache=0&sync_timestamp=1621256830355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdom-serializer%2Fdownload%2Fdom-serializer-1.3.2.tgz"
-  "version" "1.3.2"
-  dependencies:
-    "domelementtype" "^2.0.1"
-    "domhandler" "^4.2.0"
-    "entities" "^2.0.0"
-
-"dom-serializer@0":
-  "integrity" "sha1-GvuB9TNxcXXUeGVd68XjMtn5u1E="
-  "resolved" "https://registry.nlark.com/dom-serializer/download/dom-serializer-0.2.2.tgz?cache=0&sync_timestamp=1621256830355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdom-serializer%2Fdownload%2Fdom-serializer-0.2.2.tgz"
-  "version" "0.2.2"
-  dependencies:
-    "domelementtype" "^2.0.1"
-    "entities" "^2.0.0"
-
-"domelementtype@^1.3.1", "domelementtype@1":
-  "integrity" "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8="
-  "resolved" "https://registry.npmmirror.com/domelementtype/download/domelementtype-1.3.1.tgz?cache=0&sync_timestamp=1617298554829&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdomelementtype%2Fdownload%2Fdomelementtype-1.3.1.tgz"
-  "version" "1.3.1"
-
-"domelementtype@^2.0.1", "domelementtype@^2.2.0":
-  "integrity" "sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc="
-  "resolved" "https://registry.npmmirror.com/domelementtype/download/domelementtype-2.2.0.tgz?cache=0&sync_timestamp=1617298554829&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdomelementtype%2Fdownload%2Fdomelementtype-2.2.0.tgz"
-  "version" "2.2.0"
-
-"domhandler@^2.3.0":
-  "integrity" "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM="
-  "resolved" "https://registry.npmmirror.com/domhandler/download/domhandler-2.4.2.tgz"
-  "version" "2.4.2"
-  dependencies:
-    "domelementtype" "1"
-
-"domhandler@^4.2.0", "domhandler@^4.3.0":
-  "integrity" "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g=="
-  "resolved" "https://registry.npmmirror.com/domhandler/download/domhandler-4.3.0.tgz"
-  "version" "4.3.0"
-  dependencies:
-    "domelementtype" "^2.2.0"
-
-"domutils@^1.5.1":
-  "integrity" "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo="
-  "resolved" "https://registry.npmmirror.com/domutils/download/domutils-1.7.0.tgz"
-  "version" "1.7.0"
-  dependencies:
-    "dom-serializer" "0"
-    "domelementtype" "1"
-
-"domutils@^2.8.0":
-  "integrity" "sha1-RDfe9dtuLR9dbuhZvZXKfQIEgTU="
-  "resolved" "https://registry.npmmirror.com/domutils/download/domutils-2.8.0.tgz"
-  "version" "2.8.0"
-  dependencies:
-    "dom-serializer" "^1.0.1"
-    "domelementtype" "^2.2.0"
-    "domhandler" "^4.2.0"
-
-"dot-case@^3.0.4":
-  "integrity" "sha1-mytnDQCkMWZ6inW6Kc0bmICc51E="
-  "resolved" "https://registry.npmmirror.com/dot-case/download/dot-case-3.0.4.tgz?cache=0&sync_timestamp=1606867327042&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdot-case%2Fdownload%2Fdot-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "no-case" "^3.0.4"
-    "tslib" "^2.0.3"
-
-"duplexer2@~0.1.4":
-  "integrity" "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME="
-  "resolved" "https://registry.npmmirror.com/duplexer2/download/duplexer2-0.1.4.tgz"
-  "version" "0.1.4"
-  dependencies:
-    "readable-stream" "^2.0.2"
-
-"duplexify@^4.1.1":
-  "integrity" "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw=="
-  "resolved" "https://registry.npmmirror.com/duplexify/-/duplexify-4.1.2.tgz"
-  "version" "4.1.2"
-  dependencies:
-    "end-of-stream" "^1.4.1"
-    "inherits" "^2.0.3"
-    "readable-stream" "^3.1.1"
-    "stream-shift" "^1.0.0"
-
-"electron-to-chromium@^1.4.17":
-  "integrity" "sha512-PO3kEfcxPrti/4STbXvCkNIF4fgWvCKl2508e6UI7KomCDffpIfeBZLXsh5DK/XGsjUw3kwq6WEsi0MJTlGAdg=="
-  "resolved" "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.4.43.tgz"
-  "version" "1.4.43"
-
-"emoji-regex@^8.0.0":
-  "integrity" "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc="
-  "resolved" "https://registry.npmmirror.com/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1632751333727&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz"
-  "version" "8.0.0"
-
-"emojis-list@^3.0.0":
-  "integrity" "sha1-VXBmIEatKeLpFucariYKvf9Pang="
-  "resolved" "https://registry.npmmirror.com/emojis-list/download/emojis-list-3.0.0.tgz"
-  "version" "3.0.0"
-
-"end-of-stream@^1.1.0", "end-of-stream@^1.4.1":
-  "integrity" "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="
-  "resolved" "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz"
-  "version" "1.4.4"
-  dependencies:
-    "once" "^1.4.0"
-
-"enquirer@^2.3.5":
-  "integrity" "sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00="
-  "resolved" "https://registry.npmmirror.com/enquirer/download/enquirer-2.3.6.tgz"
-  "version" "2.3.6"
-  dependencies:
-    "ansi-colors" "^4.1.1"
-
-"entities@^1.1.1":
-  "integrity" "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY="
-  "resolved" "https://registry.nlark.com/entities/download/entities-1.1.2.tgz?cache=0&sync_timestamp=1628508126700&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fentities%2Fdownload%2Fentities-1.1.2.tgz"
-  "version" "1.1.2"
-
-"entities@^2.0.0":
-  "integrity" "sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU="
-  "resolved" "https://registry.nlark.com/entities/download/entities-2.2.0.tgz?cache=0&sync_timestamp=1628508126700&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fentities%2Fdownload%2Fentities-2.2.0.tgz"
-  "version" "2.2.0"
-
-"es-abstract@^1.19.0", "es-abstract@^1.19.1":
-  "integrity" "sha1-1IhXlodpFpWd547aoN9FZicRXsM="
-  "resolved" "https://registry.npmmirror.com/es-abstract/download/es-abstract-1.19.1.tgz?cache=0&sync_timestamp=1633234313248&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fes-abstract%2Fdownload%2Fes-abstract-1.19.1.tgz"
-  "version" "1.19.1"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "es-to-primitive" "^1.2.1"
-    "function-bind" "^1.1.1"
-    "get-intrinsic" "^1.1.1"
-    "get-symbol-description" "^1.0.0"
-    "has" "^1.0.3"
-    "has-symbols" "^1.0.2"
-    "internal-slot" "^1.0.3"
-    "is-callable" "^1.2.4"
-    "is-negative-zero" "^2.0.1"
-    "is-regex" "^1.1.4"
-    "is-shared-array-buffer" "^1.0.1"
-    "is-string" "^1.0.7"
-    "is-weakref" "^1.0.1"
-    "object-inspect" "^1.11.0"
-    "object-keys" "^1.1.1"
-    "object.assign" "^4.1.2"
-    "string.prototype.trimend" "^1.0.4"
-    "string.prototype.trimstart" "^1.0.4"
-    "unbox-primitive" "^1.0.1"
-
-"es-module-lexer@^0.9.3":
-  "integrity" "sha1-bxPbAMw4QXE32vdDZvU1yOtDjxk="
-  "resolved" "https://registry.npmmirror.com/es-module-lexer/download/es-module-lexer-0.9.3.tgz?cache=0&sync_timestamp=1633645560577&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fes-module-lexer%2Fdownload%2Fes-module-lexer-0.9.3.tgz"
-  "version" "0.9.3"
-
-"es-to-primitive@^1.2.1":
-  "integrity" "sha1-5VzUyc3BiLzvsDs2bHNjI/xciYo="
-  "resolved" "https://registry.nlark.com/es-to-primitive/download/es-to-primitive-1.2.1.tgz"
-  "version" "1.2.1"
-  dependencies:
-    "is-callable" "^1.1.4"
-    "is-date-object" "^1.0.1"
-    "is-symbol" "^1.0.2"
-
-"esbuild-darwin-arm64@0.13.15":
-  "integrity" "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ=="
-  "resolved" "https://registry.npmmirror.com/esbuild-darwin-arm64/download/esbuild-darwin-arm64-0.13.15.tgz"
-  "version" "0.13.15"
-
-"esbuild@^0.13.12":
-  "integrity" "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw=="
-  "resolved" "https://registry.npmmirror.com/esbuild/download/esbuild-0.13.15.tgz"
-  "version" "0.13.15"
-  optionalDependencies:
-    "esbuild-android-arm64" "0.13.15"
-    "esbuild-darwin-64" "0.13.15"
-    "esbuild-darwin-arm64" "0.13.15"
-    "esbuild-freebsd-64" "0.13.15"
-    "esbuild-freebsd-arm64" "0.13.15"
-    "esbuild-linux-32" "0.13.15"
-    "esbuild-linux-64" "0.13.15"
-    "esbuild-linux-arm" "0.13.15"
-    "esbuild-linux-arm64" "0.13.15"
-    "esbuild-linux-mips64le" "0.13.15"
-    "esbuild-linux-ppc64le" "0.13.15"
-    "esbuild-netbsd-64" "0.13.15"
-    "esbuild-openbsd-64" "0.13.15"
-    "esbuild-sunos-64" "0.13.15"
-    "esbuild-windows-32" "0.13.15"
-    "esbuild-windows-64" "0.13.15"
-    "esbuild-windows-arm64" "0.13.15"
-
-"escalade@^3.1.1":
-  "integrity" "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA="
-  "resolved" "https://registry.npmmirror.com/escalade/download/escalade-3.1.1.tgz?cache=0&sync_timestamp=1602567224085&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fescalade%2Fdownload%2Fescalade-3.1.1.tgz"
-  "version" "3.1.1"
-
-"escape-string-regexp@^1.0.2":
-  "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
-  "resolved" "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz"
-  "version" "1.0.5"
-
-"escape-string-regexp@^1.0.5":
-  "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
-  "resolved" "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz"
-  "version" "1.0.5"
-
-"escape-string-regexp@^4.0.0":
-  "integrity" "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ="
-  "resolved" "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz"
-  "version" "4.0.0"
-
-"escape-string-regexp@1.0.5":
-  "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
-  "resolved" "https://registry.npmmirror.com/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz"
-  "version" "1.0.5"
-
-"eslint-config-standard@^16.0.3":
-  "integrity" "sha1-bIdh5UTpbFMf+SZC7rh4QrhIhRY="
-  "resolved" "https://registry.npmmirror.com/eslint-config-standard/download/eslint-config-standard-16.0.3.tgz"
-  "version" "16.0.3"
-
-"eslint-import-resolver-node@^0.3.6":
-  "integrity" "sha1-QEi5WDldqJZoJSAB29nsprg7rL0="
-  "resolved" "https://registry.nlark.com/eslint-import-resolver-node/download/eslint-import-resolver-node-0.3.6.tgz?cache=0&sync_timestamp=1629046546232&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-import-resolver-node%2Fdownload%2Feslint-import-resolver-node-0.3.6.tgz"
-  "version" "0.3.6"
-  dependencies:
-    "debug" "^3.2.7"
-    "resolve" "^1.20.0"
-
-"eslint-module-utils@^2.7.2":
-  "integrity" "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg=="
-  "resolved" "https://registry.npmmirror.com/eslint-module-utils/download/eslint-module-utils-2.7.2.tgz"
-  "version" "2.7.2"
-  dependencies:
-    "debug" "^3.2.7"
-    "find-up" "^2.1.0"
-
-"eslint-plugin-es@^3.0.0":
-  "integrity" "sha1-dafN/czdwFiZNK7rOEF18iHFeJM="
-  "resolved" "https://registry.npmmirror.com/eslint-plugin-es/download/eslint-plugin-es-3.0.1.tgz?cache=0&sync_timestamp=1605769798981&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-plugin-es%2Fdownload%2Feslint-plugin-es-3.0.1.tgz"
-  "version" "3.0.1"
-  dependencies:
-    "eslint-utils" "^2.0.0"
-    "regexpp" "^3.0.0"
-
-"eslint-plugin-import@^2.22.1", "eslint-plugin-import@^2.23.4":
-  "integrity" "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA=="
-  "resolved" "https://registry.npmmirror.com/eslint-plugin-import/download/eslint-plugin-import-2.25.4.tgz"
-  "version" "2.25.4"
-  dependencies:
-    "array-includes" "^3.1.4"
-    "array.prototype.flat" "^1.2.5"
-    "debug" "^2.6.9"
-    "doctrine" "^2.1.0"
-    "eslint-import-resolver-node" "^0.3.6"
-    "eslint-module-utils" "^2.7.2"
-    "has" "^1.0.3"
-    "is-core-module" "^2.8.0"
-    "is-glob" "^4.0.3"
-    "minimatch" "^3.0.4"
-    "object.values" "^1.1.5"
-    "resolve" "^1.20.0"
-    "tsconfig-paths" "^3.12.0"
-
-"eslint-plugin-node@^11.1.0":
-  "integrity" "sha1-yVVEQW7kraJnQKMEdO78VALcZx0="
-  "resolved" "https://registry.npmmirror.com/eslint-plugin-node/download/eslint-plugin-node-11.1.0.tgz"
-  "version" "11.1.0"
-  dependencies:
-    "eslint-plugin-es" "^3.0.0"
-    "eslint-utils" "^2.0.0"
-    "ignore" "^5.1.1"
-    "minimatch" "^3.0.4"
-    "resolve" "^1.10.1"
-    "semver" "^6.1.0"
-
-"eslint-plugin-promise@^4.2.1 || ^5.0.0", "eslint-plugin-promise@^5.1.0":
-  "integrity" "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw=="
-  "resolved" "https://registry.npmmirror.com/eslint-plugin-promise/download/eslint-plugin-promise-5.2.0.tgz"
-  "version" "5.2.0"
-
-"eslint-plugin-vue@^7.13.0":
-  "integrity" "sha512-oVNDqzBC9h3GO+NTgWeLMhhGigy6/bQaQbHS+0z7C4YEu/qK/yxHvca/2PTZtGNPsCrHwOTgKMrwu02A9iPBmw=="
-  "resolved" "https://registry.npmmirror.com/eslint-plugin-vue/download/eslint-plugin-vue-7.20.0.tgz"
-  "version" "7.20.0"
-  dependencies:
-    "eslint-utils" "^2.1.0"
-    "natural-compare" "^1.4.0"
-    "semver" "^6.3.0"
-    "vue-eslint-parser" "^7.10.0"
-
-"eslint-scope@^5.1.1":
-  "integrity" "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw="
-  "resolved" "https://registry.npmmirror.com/eslint-scope/download/eslint-scope-5.1.1.tgz?cache=0&sync_timestamp=1637466913662&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-scope%2Fdownload%2Feslint-scope-5.1.1.tgz"
-  "version" "5.1.1"
-  dependencies:
-    "esrecurse" "^4.3.0"
-    "estraverse" "^4.1.1"
-
-"eslint-utils@^2.0.0":
-  "integrity" "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc="
-  "resolved" "https://registry.nlark.com/eslint-utils/download/eslint-utils-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "eslint-visitor-keys" "^1.1.0"
-
-"eslint-utils@^2.1.0":
-  "integrity" "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc="
-  "resolved" "https://registry.nlark.com/eslint-utils/download/eslint-utils-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "eslint-visitor-keys" "^1.1.0"
-
-"eslint-utils@^3.0.0":
-  "integrity" "sha1-iuuvrOc0W7M1WdsKHxOh0tSMNnI="
-  "resolved" "https://registry.nlark.com/eslint-utils/download/eslint-utils-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "eslint-visitor-keys" "^2.0.0"
-
-"eslint-visitor-keys@^1.1.0":
-  "integrity" "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4="
-  "resolved" "https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1636378395014&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz"
-  "version" "1.3.0"
-
-"eslint-visitor-keys@^1.3.0":
-  "integrity" "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4="
-  "resolved" "https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz?cache=0&sync_timestamp=1636378395014&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-1.3.0.tgz"
-  "version" "1.3.0"
-
-"eslint-visitor-keys@^2.0.0":
-  "integrity" "sha1-9lMoJZMFknOSyTjtROsKXJsr0wM="
-  "resolved" "https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-2.1.0.tgz?cache=0&sync_timestamp=1636378395014&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-2.1.0.tgz"
-  "version" "2.1.0"
-
-"eslint-visitor-keys@^3.0.0":
-  "integrity" "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA=="
-  "resolved" "https://registry.npmmirror.com/eslint-visitor-keys/download/eslint-visitor-keys-3.1.0.tgz?cache=0&sync_timestamp=1636378395014&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Feslint-visitor-keys%2Fdownload%2Feslint-visitor-keys-3.1.0.tgz"
-  "version" "3.1.0"
-
-"eslint@*", "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.2.0 || ^7.0.0 || ^8.0.0", "eslint@^7.0.0", "eslint@^7.12.1", "eslint@^7.26.0", "eslint@^7.30.0", "eslint@>=4.19.1", "eslint@>=5", "eslint@>=5.0.0", "eslint@>=5.16.0":
-  "integrity" "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA=="
-  "resolved" "https://registry.npmmirror.com/eslint/download/eslint-7.32.0.tgz"
-  "version" "7.32.0"
-  dependencies:
-    "@babel/code-frame" "7.12.11"
-    "@eslint/eslintrc" "^0.4.3"
-    "@humanwhocodes/config-array" "^0.5.0"
-    "ajv" "^6.10.0"
-    "chalk" "^4.0.0"
-    "cross-spawn" "^7.0.2"
-    "debug" "^4.0.1"
-    "doctrine" "^3.0.0"
-    "enquirer" "^2.3.5"
-    "escape-string-regexp" "^4.0.0"
-    "eslint-scope" "^5.1.1"
-    "eslint-utils" "^2.1.0"
-    "eslint-visitor-keys" "^2.0.0"
-    "espree" "^7.3.1"
-    "esquery" "^1.4.0"
-    "esutils" "^2.0.2"
-    "fast-deep-equal" "^3.1.3"
-    "file-entry-cache" "^6.0.1"
-    "functional-red-black-tree" "^1.0.1"
-    "glob-parent" "^5.1.2"
-    "globals" "^13.6.0"
-    "ignore" "^4.0.6"
-    "import-fresh" "^3.0.0"
-    "imurmurhash" "^0.1.4"
-    "is-glob" "^4.0.0"
-    "js-yaml" "^3.13.1"
-    "json-stable-stringify-without-jsonify" "^1.0.1"
-    "levn" "^0.4.1"
-    "lodash.merge" "^4.6.2"
-    "minimatch" "^3.0.4"
-    "natural-compare" "^1.4.0"
-    "optionator" "^0.9.1"
-    "progress" "^2.0.0"
-    "regexpp" "^3.1.0"
-    "semver" "^7.2.1"
-    "strip-ansi" "^6.0.0"
-    "strip-json-comments" "^3.1.0"
-    "table" "^6.0.9"
-    "text-table" "^0.2.0"
-    "v8-compile-cache" "^2.0.3"
-
-"espree@^6.2.1":
-  "integrity" "sha1-d/xy4f10SiBSwg84pbV1gy6Cc0o="
-  "resolved" "https://registry.npmmirror.com/espree/download/espree-6.2.1.tgz"
-  "version" "6.2.1"
-  dependencies:
-    "acorn" "^7.1.1"
-    "acorn-jsx" "^5.2.0"
-    "eslint-visitor-keys" "^1.1.0"
-
-"espree@^7.3.0", "espree@^7.3.1":
-  "integrity" "sha1-8t8zC3Usb1UBn4vYm3ZgA5wbu7Y="
-  "resolved" "https://registry.npmmirror.com/espree/download/espree-7.3.1.tgz"
-  "version" "7.3.1"
-  dependencies:
-    "acorn" "^7.4.0"
-    "acorn-jsx" "^5.3.1"
-    "eslint-visitor-keys" "^1.3.0"
-
-"esprima@^4.0.0":
-  "integrity" "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE="
-  "resolved" "https://registry.nlark.com/esprima/download/esprima-4.0.1.tgz"
-  "version" "4.0.1"
-
-"esquery@^1.4.0":
-  "integrity" "sha1-IUj/w4uC6McFff7UhCWz5h8PJKU="
-  "resolved" "https://registry.npmmirror.com/esquery/download/esquery-1.4.0.tgz"
-  "version" "1.4.0"
-  dependencies:
-    "estraverse" "^5.1.0"
-
-"esrecurse@^4.3.0":
-  "integrity" "sha1-eteWTWeauyi+5yzsY3WLHF0smSE="
-  "resolved" "https://registry.npmmirror.com/esrecurse/download/esrecurse-4.3.0.tgz"
-  "version" "4.3.0"
-  dependencies:
-    "estraverse" "^5.2.0"
-
-"estraverse@^4.1.1":
-  "integrity" "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0="
-  "resolved" "https://registry.npmmirror.com/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1635237716974&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz"
-  "version" "4.3.0"
-
-"estraverse@^5.1.0":
-  "integrity" "sha1-LupSkHAvJquP5TcDcP+GyWXSESM="
-  "resolved" "https://registry.npmmirror.com/estraverse/download/estraverse-5.3.0.tgz?cache=0&sync_timestamp=1635237716974&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Festraverse%2Fdownload%2Festraverse-5.3.0.tgz"
-  "version" "5.3.0"
-
-"estraverse@^5.2.0":
-  "integrity" "sha1-LupSkHAvJquP5TcDcP+GyWXSESM="
-  "resolved" "https://registry.npmmirror.com/estraverse/download/estraverse-5.3.0.tgz?cache=0&sync_timestamp=1635237716974&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Festraverse%2Fdownload%2Festraverse-5.3.0.tgz"
-  "version" "5.3.0"
-
-"estree-walker@^2.0.1", "estree-walker@^2.0.2":
-  "integrity" "sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw="
-  "resolved" "https://registry.npmmirror.com/estree-walker/download/estree-walker-2.0.2.tgz"
-  "version" "2.0.2"
-
-"esutils@^2.0.2":
-  "integrity" "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q="
-  "resolved" "https://registry.npmmirror.com/esutils/download/esutils-2.0.3.tgz"
-  "version" "2.0.3"
-
-"etag@^1.8.1":
-  "integrity" "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
-  "resolved" "https://registry.npmmirror.com/etag/download/etag-1.8.1.tgz"
-  "version" "1.8.1"
-
-"eventemitter3@^5.0.0":
-  "integrity" "sha512-riuVbElZZNXLeLEoprfNYoDSwTBRR44X3mnhdI1YcnENpWTCsTTVZ2zFuqQcpoyqPQIUXdiPEU0ECAq0KQRaHg=="
-  "resolved" "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.0.tgz"
-  "version" "5.0.0"
-
-"expand-brackets@^2.1.4":
-  "integrity" "sha1-t3c14xXOMPa27/D4OwQVGiJEliI="
-  "resolved" "https://registry.npmmirror.com/expand-brackets/download/expand-brackets-2.1.4.tgz"
-  "version" "2.1.4"
-  dependencies:
-    "debug" "^2.3.3"
-    "define-property" "^0.2.5"
-    "extend-shallow" "^2.0.1"
-    "posix-character-classes" "^0.1.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
-"extend-shallow@^2.0.1":
-  "integrity" "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8="
-  "resolved" "https://registry.npmmirror.com/extend-shallow/download/extend-shallow-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "is-extendable" "^0.1.0"
-
-"extend-shallow@^3.0.0":
-  "integrity" "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg="
-  "resolved" "https://registry.npmmirror.com/extend-shallow/download/extend-shallow-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "assign-symbols" "^1.0.0"
-    "is-extendable" "^1.0.1"
-
-"extend-shallow@^3.0.2":
-  "integrity" "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg="
-  "resolved" "https://registry.npmmirror.com/extend-shallow/download/extend-shallow-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "assign-symbols" "^1.0.0"
-    "is-extendable" "^1.0.1"
-
-"extglob@^2.0.2":
-  "integrity" "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM="
-  "resolved" "https://registry.npmmirror.com/extglob/download/extglob-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "array-unique" "^0.3.2"
-    "define-property" "^1.0.0"
-    "expand-brackets" "^2.1.4"
-    "extend-shallow" "^2.0.1"
-    "fragment-cache" "^0.2.1"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
-"fast-deep-equal@^3.1.1", "fast-deep-equal@^3.1.3":
-  "integrity" "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU="
-  "resolved" "https://registry.npmmirror.com/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz"
-  "version" "3.1.3"
-
-"fast-glob@^3.2.7", "fast-glob@^3.2.9":
-  "integrity" "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A=="
-  "resolved" "https://registry.npmmirror.com/fast-glob/download/fast-glob-3.2.10.tgz"
-  "version" "3.2.10"
-  dependencies:
-    "@nodelib/fs.stat" "^2.0.2"
-    "@nodelib/fs.walk" "^1.2.3"
-    "glob-parent" "^5.1.2"
-    "merge2" "^1.3.0"
-    "micromatch" "^4.0.4"
-
-"fast-json-stable-stringify@^2.0.0":
-  "integrity" "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM="
-  "resolved" "https://registry.npmmirror.com/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz"
-  "version" "2.1.0"
-
-"fast-levenshtein@^2.0.6":
-  "integrity" "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
-  "resolved" "https://registry.npmmirror.com/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz"
-  "version" "2.0.6"
-
-"fastq@^1.6.0":
-  "integrity" "sha1-YWdg+Ip1Jr38WWt8q4wYk4w2uYw="
-  "resolved" "https://registry.nlark.com/fastq/download/fastq-1.13.0.tgz"
-  "version" "1.13.0"
-  dependencies:
-    "reusify" "^1.0.4"
-
-"file-entry-cache@^6.0.1":
-  "integrity" "sha1-IRst2WWcsDlLBz5zI6w8kz1SICc="
-  "resolved" "https://registry.npmmirror.com/file-entry-cache/download/file-entry-cache-6.0.1.tgz?cache=0&sync_timestamp=1613794357372&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffile-entry-cache%2Fdownload%2Ffile-entry-cache-6.0.1.tgz"
-  "version" "6.0.1"
-  dependencies:
-    "flat-cache" "^3.0.4"
-
-"fill-range@^4.0.0":
-  "integrity" "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc="
-  "resolved" "https://registry.npmmirror.com/fill-range/download/fill-range-4.0.0.tgz"
-  "version" "4.0.0"
-  dependencies:
-    "extend-shallow" "^2.0.1"
-    "is-number" "^3.0.0"
-    "repeat-string" "^1.6.1"
-    "to-regex-range" "^2.1.0"
-
-"fill-range@^7.0.1":
-  "integrity" "sha1-GRmmp8df44ssfHflGYU12prN2kA="
-  "resolved" "https://registry.npmmirror.com/fill-range/download/fill-range-7.0.1.tgz"
-  "version" "7.0.1"
-  dependencies:
-    "to-regex-range" "^5.0.1"
-
-"filter-obj@^1.1.0":
-  "integrity" "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
-  "resolved" "https://registry.nlark.com/filter-obj/download/filter-obj-1.1.0.tgz?cache=0&sync_timestamp=1630004006859&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffilter-obj%2Fdownload%2Ffilter-obj-1.1.0.tgz"
-  "version" "1.1.0"
-
-"find-up@^2.1.0":
-  "integrity" "sha1-RdG35QbHF93UgndaK3eSCjwMV6c="
-  "resolved" "https://registry.npmmirror.com/find-up/download/find-up-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "locate-path" "^2.0.0"
-
-"flat-cache@^3.0.4":
-  "integrity" "sha1-YbAzgwKy/p+Vfcwy/CqH8cMEixE="
-  "resolved" "https://registry.nlark.com/flat-cache/download/flat-cache-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "flatted" "^3.1.0"
-    "rimraf" "^3.0.2"
-
-"flatted@^3.1.0":
-  "integrity" "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
-  "resolved" "https://registry.npmmirror.com/flatted/download/flatted-3.2.4.tgz?cache=0&sync_timestamp=1636473813364&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fflatted%2Fdownload%2Fflatted-3.2.4.tgz"
-  "version" "3.2.4"
-
-"follow-redirects@^1.14.0":
-  "integrity" "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
-  "resolved" "https://registry.npmmirror.com/follow-redirects/download/follow-redirects-1.14.7.tgz"
-  "version" "1.14.7"
-
-"for-in@^1.0.2":
-  "integrity" "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
-  "resolved" "https://registry.npmmirror.com/for-in/download/for-in-1.0.2.tgz"
-  "version" "1.0.2"
-
-"fragment-cache@^0.2.1":
-  "integrity" "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk="
-  "resolved" "https://registry.npmmirror.com/fragment-cache/download/fragment-cache-0.2.1.tgz"
-  "version" "0.2.1"
-  dependencies:
-    "map-cache" "^0.2.2"
-
-"fs-extra@^10.0.0":
-  "integrity" "sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E="
-  "resolved" "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz?cache=0&sync_timestamp=1622604476909&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffs-extra%2Fdownload%2Ffs-extra-10.0.0.tgz"
-  "version" "10.0.0"
-  dependencies:
-    "graceful-fs" "^4.2.0"
-    "jsonfile" "^6.0.1"
-    "universalify" "^2.0.0"
-
-"fs.realpath@^1.0.0":
-  "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
-  "resolved" "https://registry.npmmirror.com/fs.realpath/download/fs.realpath-1.0.0.tgz"
-  "version" "1.0.0"
-
-"fsevents@~2.3.2":
-  "integrity" "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro="
-  "resolved" "https://registry.npmmirror.com/fsevents/download/fsevents-2.3.2.tgz"
-  "version" "2.3.2"
-
-"fstream@^1.0.12":
-  "integrity" "sha1-Touo7i1Ivk99DeUFRVVI6uWTIEU="
-  "resolved" "https://registry.npmmirror.com/fstream/download/fstream-1.0.12.tgz"
-  "version" "1.0.12"
-  dependencies:
-    "graceful-fs" "^4.1.2"
-    "inherits" "~2.0.0"
-    "mkdirp" ">=0.5 0"
-    "rimraf" "2"
-
-"function-bind@^1.1.1":
-  "integrity" "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
-  "resolved" "https://registry.npmmirror.com/function-bind/download/function-bind-1.1.1.tgz"
-  "version" "1.1.1"
-
-"functional-red-black-tree@^1.0.1":
-  "integrity" "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
-  "resolved" "https://registry.nlark.com/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz?cache=0&sync_timestamp=1626768951311&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffunctional-red-black-tree%2Fdownload%2Ffunctional-red-black-tree-1.0.1.tgz"
-  "version" "1.0.1"
-
-"gensync@^1.0.0-beta.2":
-  "integrity" "sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA="
-  "resolved" "https://registry.npmmirror.com/gensync/download/gensync-1.0.0-beta.2.tgz"
-  "version" "1.0.0-beta.2"
-
-"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1":
-  "integrity" "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y="
-  "resolved" "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz"
-  "version" "1.1.1"
-  dependencies:
-    "function-bind" "^1.1.1"
-    "has" "^1.0.3"
-    "has-symbols" "^1.0.1"
-
-"get-symbol-description@^1.0.0":
-  "integrity" "sha1-f9uByQAQH71WTdXxowr1qtweWNY="
-  "resolved" "https://registry.nlark.com/get-symbol-description/download/get-symbol-description-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "get-intrinsic" "^1.1.1"
-
-"get-value@^2.0.3", "get-value@^2.0.6":
-  "integrity" "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
-  "resolved" "https://registry.npmmirror.com/get-value/download/get-value-2.0.6.tgz"
-  "version" "2.0.6"
-
-"glob-parent@^5.1.2", "glob-parent@~5.1.2":
-  "integrity" "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ="
-  "resolved" "https://registry.npmmirror.com/glob-parent/download/glob-parent-5.1.2.tgz"
-  "version" "5.1.2"
-  dependencies:
-    "is-glob" "^4.0.1"
-
-"glob@^7.1.3", "glob@^7.1.6":
-  "integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="
-  "resolved" "https://registry.npmmirror.com/glob/download/glob-7.2.0.tgz"
-  "version" "7.2.0"
-  dependencies:
-    "fs.realpath" "^1.0.0"
-    "inflight" "^1.0.4"
-    "inherits" "2"
-    "minimatch" "^3.0.4"
-    "once" "^1.3.0"
-    "path-is-absolute" "^1.0.0"
-
-"globals@^11.1.0":
-  "integrity" "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4="
-  "resolved" "https://registry.npmmirror.com/globals/download/globals-11.12.0.tgz?cache=0&sync_timestamp=1635390798667&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fglobals%2Fdownload%2Fglobals-11.12.0.tgz"
-  "version" "11.12.0"
-
-"globals@^13.6.0", "globals@^13.9.0":
-  "integrity" "sha1-TXM3YDBCMKAILtluIeXFZfiYCJ4="
-  "resolved" "https://registry.npmmirror.com/globals/download/globals-13.12.0.tgz?cache=0&sync_timestamp=1635390798667&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fglobals%2Fdownload%2Fglobals-13.12.0.tgz"
-  "version" "13.12.0"
-  dependencies:
-    "type-fest" "^0.20.2"
-
-"globby@^11.0.4":
-  "integrity" "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="
-  "resolved" "https://registry.npmmirror.com/globby/download/globby-11.1.0.tgz"
-  "version" "11.1.0"
-  dependencies:
-    "array-union" "^2.1.0"
-    "dir-glob" "^3.0.1"
-    "fast-glob" "^3.2.9"
-    "ignore" "^5.2.0"
-    "merge2" "^1.4.1"
-    "slash" "^3.0.0"
-
-"graceful-fs@^4.1.2", "graceful-fs@^4.1.6", "graceful-fs@^4.2.0", "graceful-fs@^4.2.2":
-  "integrity" "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
-  "resolved" "https://registry.npmmirror.com/graceful-fs/download/graceful-fs-4.2.9.tgz"
-  "version" "4.2.9"
-
-"has-ansi@^2.0.0":
-  "integrity" "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE="
-  "resolved" "https://registry.nlark.com/has-ansi/download/has-ansi-2.0.0.tgz?cache=0&sync_timestamp=1631556755105&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-ansi%2Fdownload%2Fhas-ansi-2.0.0.tgz"
-  "version" "2.0.0"
-  dependencies:
-    "ansi-regex" "^2.0.0"
-
-"has-bigints@^1.0.1":
-  "integrity" "sha1-ZP5qywIGc+O3jbA1pa9pqp0HsRM="
-  "resolved" "https://registry.npmmirror.com/has-bigints/download/has-bigints-1.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhas-bigints%2Fdownload%2Fhas-bigints-1.0.1.tgz"
-  "version" "1.0.1"
-
-"has-flag@^1.0.0":
-  "integrity" "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
-  "resolved" "https://registry.nlark.com/has-flag/download/has-flag-1.0.0.tgz"
-  "version" "1.0.0"
-
-"has-flag@^3.0.0":
-  "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
-  "resolved" "https://registry.nlark.com/has-flag/download/has-flag-3.0.0.tgz"
-  "version" "3.0.0"
-
-"has-flag@^4.0.0":
-  "integrity" "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s="
-  "resolved" "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz"
-  "version" "4.0.0"
-
-"has-symbols@^1.0.1", "has-symbols@^1.0.2":
-  "integrity" "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM="
-  "resolved" "https://registry.npmmirror.com/has-symbols/download/has-symbols-1.0.2.tgz"
-  "version" "1.0.2"
-
-"has-tostringtag@^1.0.0":
-  "integrity" "sha1-fhM4GKfTlHNPlB5zw9P5KR5liyU="
-  "resolved" "https://registry.nlark.com/has-tostringtag/download/has-tostringtag-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "has-symbols" "^1.0.2"
-
-"has-value@^0.3.1":
-  "integrity" "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8="
-  "resolved" "https://registry.npmmirror.com/has-value/download/has-value-0.3.1.tgz"
-  "version" "0.3.1"
-  dependencies:
-    "get-value" "^2.0.3"
-    "has-values" "^0.1.4"
-    "isobject" "^2.0.0"
-
-"has-value@^1.0.0":
-  "integrity" "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc="
-  "resolved" "https://registry.npmmirror.com/has-value/download/has-value-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "get-value" "^2.0.6"
-    "has-values" "^1.0.0"
-    "isobject" "^3.0.0"
-
-"has-values@^0.1.4":
-  "integrity" "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
-  "resolved" "https://registry.npmmirror.com/has-values/download/has-values-0.1.4.tgz"
-  "version" "0.1.4"
-
-"has-values@^1.0.0":
-  "integrity" "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8="
-  "resolved" "https://registry.npmmirror.com/has-values/download/has-values-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "is-number" "^3.0.0"
-    "kind-of" "^4.0.0"
-
-"has@^1.0.3":
-  "integrity" "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y="
-  "resolved" "https://registry.npmmirror.com/has/download/has-1.0.3.tgz"
-  "version" "1.0.3"
-  dependencies:
-    "function-bind" "^1.1.1"
-
-"he@^1.1.1":
-  "integrity" "sha1-hK5l+n6vsWX922FWauFLrwVmTw8="
-  "resolved" "https://registry.npmmirror.com/he/download/he-1.2.0.tgz"
-  "version" "1.2.0"
-
-"header-case@^2.0.4":
-  "integrity" "sha1-WkLmO1UXc0nPQFvrjXdayruSwGM="
-  "resolved" "https://registry.npmmirror.com/header-case/download/header-case-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "capital-case" "^1.0.4"
-    "tslib" "^2.0.3"
-
-"help-me@^3.0.0":
-  "integrity" "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ=="
-  "resolved" "https://registry.npmmirror.com/help-me/-/help-me-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "glob" "^7.1.6"
-    "readable-stream" "^3.6.0"
-
-"htmlparser2@^3.8.3":
-  "integrity" "sha1-vWedw/WYl7ajS7EHSchVu1OpOS8="
-  "resolved" "https://registry.npmmirror.com/htmlparser2/download/htmlparser2-3.10.1.tgz?cache=0&sync_timestamp=1636640933377&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-3.10.1.tgz"
-  "version" "3.10.1"
-  dependencies:
-    "domelementtype" "^1.3.1"
-    "domhandler" "^2.3.0"
-    "domutils" "^1.5.1"
-    "entities" "^1.1.1"
-    "inherits" "^2.0.1"
-    "readable-stream" "^3.1.1"
-
-"ieee754@^1.1.13":
-  "integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
-  "resolved" "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz"
-  "version" "1.2.1"
-
-"ignore@^4.0.6":
-  "integrity" "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
-  "resolved" "https://registry.npmmirror.com/ignore/download/ignore-4.0.6.tgz"
-  "version" "4.0.6"
-
-"ignore@^5.1.1", "ignore@^5.1.8", "ignore@^5.2.0":
-  "integrity" "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
-  "resolved" "https://registry.npmmirror.com/ignore/download/ignore-5.2.0.tgz"
-  "version" "5.2.0"
-
-"image-size@^0.5.1":
-  "integrity" "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w="
-  "resolved" "https://registry.npmmirror.com/image-size/download/image-size-0.5.5.tgz"
-  "version" "0.5.5"
-
-"immutable@^4.0.0":
-  "integrity" "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw=="
-  "resolved" "https://registry.npmmirror.com/immutable/download/immutable-4.0.0.tgz"
-  "version" "4.0.0"
-
-"import-fresh@^3.0.0", "import-fresh@^3.2.1":
-  "integrity" "sha1-NxYsJfy566oublPVtNiM4X2eDCs="
-  "resolved" "https://registry.nlark.com/import-fresh/download/import-fresh-3.3.0.tgz"
-  "version" "3.3.0"
-  dependencies:
-    "parent-module" "^1.0.0"
-    "resolve-from" "^4.0.0"
-
-"imurmurhash@^0.1.4":
-  "integrity" "sha1-khi5srkoojixPcT7a21XbyMUU+o="
-  "resolved" "https://registry.nlark.com/imurmurhash/download/imurmurhash-0.1.4.tgz"
-  "version" "0.1.4"
-
-"inflight@^1.0.4":
-  "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk="
-  "resolved" "https://registry.npmmirror.com/inflight/download/inflight-1.0.6.tgz"
-  "version" "1.0.6"
-  dependencies:
-    "once" "^1.3.0"
-    "wrappy" "1"
-
-"inherits@^2.0.1", "inherits@^2.0.3", "inherits@^2.0.4", "inherits@~2.0.0", "inherits@~2.0.3", "inherits@2":
-  "integrity" "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w="
-  "resolved" "https://registry.npmmirror.com/inherits/download/inherits-2.0.4.tgz"
-  "version" "2.0.4"
-
-"internal-slot@^1.0.3":
-  "integrity" "sha1-c0fjB97uovqsKsYgXUvH00ln9Zw="
-  "resolved" "https://registry.npmmirror.com/internal-slot/download/internal-slot-1.0.3.tgz?cache=0&sync_timestamp=1611694392178&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Finternal-slot%2Fdownload%2Finternal-slot-1.0.3.tgz"
-  "version" "1.0.3"
-  dependencies:
-    "get-intrinsic" "^1.1.0"
-    "has" "^1.0.3"
-    "side-channel" "^1.0.4"
-
-"is-accessor-descriptor@^0.1.6":
-  "integrity" "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY="
-  "resolved" "https://registry.npmmirror.com/is-accessor-descriptor/download/is-accessor-descriptor-0.1.6.tgz"
-  "version" "0.1.6"
-  dependencies:
-    "kind-of" "^3.0.2"
-
-"is-accessor-descriptor@^1.0.0":
-  "integrity" "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY="
-  "resolved" "https://registry.npmmirror.com/is-accessor-descriptor/download/is-accessor-descriptor-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "kind-of" "^6.0.0"
-
-"is-bigint@^1.0.1":
-  "integrity" "sha1-CBR6GHW8KzIAXUHM2Ckd/8ZpHfM="
-  "resolved" "https://registry.nlark.com/is-bigint/download/is-bigint-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "has-bigints" "^1.0.1"
-
-"is-binary-path@~2.1.0":
-  "integrity" "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk="
-  "resolved" "https://registry.npmmirror.com/is-binary-path/download/is-binary-path-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "binary-extensions" "^2.0.0"
-
-"is-boolean-object@^1.1.0":
-  "integrity" "sha1-XG3CACRt2TIa5LiFoRS7H3X2Nxk="
-  "resolved" "https://registry.nlark.com/is-boolean-object/download/is-boolean-object-1.1.2.tgz"
-  "version" "1.1.2"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "has-tostringtag" "^1.0.0"
-
-"is-buffer@^1.1.5":
-  "integrity" "sha1-76ouqdqg16suoTqXsritUf776L4="
-  "resolved" "https://registry.npmmirror.com/is-buffer/download/is-buffer-1.1.6.tgz?cache=0&sync_timestamp=1604429452232&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fis-buffer%2Fdownload%2Fis-buffer-1.1.6.tgz"
-  "version" "1.1.6"
-
-"is-callable@^1.1.4", "is-callable@^1.2.4":
-  "integrity" "sha1-RzAdWN0CWUB4ZVR4U99tYf5HGUU="
-  "resolved" "https://registry.nlark.com/is-callable/download/is-callable-1.2.4.tgz"
-  "version" "1.2.4"
-
-"is-core-module@^2.8.0":
-  "integrity" "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA=="
-  "resolved" "https://registry.npmmirror.com/is-core-module/download/is-core-module-2.8.1.tgz"
-  "version" "2.8.1"
-  dependencies:
-    "has" "^1.0.3"
-
-"is-data-descriptor@^0.1.4":
-  "integrity" "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y="
-  "resolved" "https://registry.npmmirror.com/is-data-descriptor/download/is-data-descriptor-0.1.4.tgz"
-  "version" "0.1.4"
-  dependencies:
-    "kind-of" "^3.0.2"
-
-"is-data-descriptor@^1.0.0":
-  "integrity" "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc="
-  "resolved" "https://registry.npmmirror.com/is-data-descriptor/download/is-data-descriptor-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "kind-of" "^6.0.0"
-
-"is-date-object@^1.0.1":
-  "integrity" "sha1-CEHVU25yTCVZe/bqYuG9OCmN8x8="
-  "resolved" "https://registry.nlark.com/is-date-object/download/is-date-object-1.0.5.tgz"
-  "version" "1.0.5"
-  dependencies:
-    "has-tostringtag" "^1.0.0"
-
-"is-descriptor@^0.1.0":
-  "integrity" "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco="
-  "resolved" "https://registry.npmmirror.com/is-descriptor/download/is-descriptor-0.1.6.tgz"
-  "version" "0.1.6"
-  dependencies:
-    "is-accessor-descriptor" "^0.1.6"
-    "is-data-descriptor" "^0.1.4"
-    "kind-of" "^5.0.0"
-
-"is-descriptor@^1.0.0", "is-descriptor@^1.0.2":
-  "integrity" "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw="
-  "resolved" "https://registry.npmmirror.com/is-descriptor/download/is-descriptor-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "is-accessor-descriptor" "^1.0.0"
-    "is-data-descriptor" "^1.0.0"
-    "kind-of" "^6.0.2"
-
-"is-extendable@^0.1.0", "is-extendable@^0.1.1":
-  "integrity" "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
-  "resolved" "https://registry.nlark.com/is-extendable/download/is-extendable-0.1.1.tgz"
-  "version" "0.1.1"
-
-"is-extendable@^1.0.1":
-  "integrity" "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ="
-  "resolved" "https://registry.nlark.com/is-extendable/download/is-extendable-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "is-plain-object" "^2.0.4"
-
-"is-extglob@^2.1.1":
-  "integrity" "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
-  "resolved" "https://registry.npmmirror.com/is-extglob/download/is-extglob-2.1.1.tgz"
-  "version" "2.1.1"
-
-"is-fullwidth-code-point@^3.0.0":
-  "integrity" "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0="
-  "resolved" "https://registry.npmmirror.com/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-3.0.0.tgz"
-  "version" "3.0.0"
-
-"is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1":
-  "integrity" "sha1-ZPYeQsu7LuwgcanawLKLoeZdUIQ="
-  "resolved" "https://registry.npmmirror.com/is-glob/download/is-glob-4.0.3.tgz"
-  "version" "4.0.3"
-  dependencies:
-    "is-extglob" "^2.1.1"
-
-"is-negative-zero@^2.0.1":
-  "integrity" "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
-  "resolved" "https://registry.npmmirror.com/is-negative-zero/download/is-negative-zero-2.0.2.tgz"
-  "version" "2.0.2"
-
-"is-number-object@^1.0.4":
-  "integrity" "sha1-anqvg4x/BoalC0VT9+VKlklOifA="
-  "resolved" "https://registry.nlark.com/is-number-object/download/is-number-object-1.0.6.tgz"
-  "version" "1.0.6"
-  dependencies:
-    "has-tostringtag" "^1.0.0"
-
-"is-number@^3.0.0":
-  "integrity" "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU="
-  "resolved" "https://registry.npmmirror.com/is-number/download/is-number-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "kind-of" "^3.0.2"
-
-"is-number@^7.0.0":
-  "integrity" "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss="
-  "resolved" "https://registry.npmmirror.com/is-number/download/is-number-7.0.0.tgz"
-  "version" "7.0.0"
-
-"is-plain-obj@^1.1":
-  "integrity" "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
-  "resolved" "https://registry.npmmirror.com/is-plain-obj/download/is-plain-obj-1.1.0.tgz?cache=0&sync_timestamp=1618600489644&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fis-plain-obj%2Fdownload%2Fis-plain-obj-1.1.0.tgz"
-  "version" "1.1.0"
-
-"is-plain-object@^2.0.3":
-  "integrity" "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc="
-  "resolved" "https://registry.npmmirror.com/is-plain-object/download/is-plain-object-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "isobject" "^3.0.1"
-
-"is-plain-object@^2.0.4":
-  "integrity" "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc="
-  "resolved" "https://registry.npmmirror.com/is-plain-object/download/is-plain-object-2.0.4.tgz"
-  "version" "2.0.4"
-  dependencies:
-    "isobject" "^3.0.1"
-
-"is-plain-object@3.0.1":
-  "integrity" "sha1-Zi2S0kwKpDAkB7DUXSHyJRyF+Fs="
-  "resolved" "https://registry.npmmirror.com/is-plain-object/download/is-plain-object-3.0.1.tgz"
-  "version" "3.0.1"
-
-"is-reference@^1.2.1":
-  "integrity" "sha1-iy2sCzcfS8mU/eq6nrVC0DAC0Lc="
-  "resolved" "https://registry.nlark.com/is-reference/download/is-reference-1.2.1.tgz"
-  "version" "1.2.1"
-  dependencies:
-    "@types/estree" "*"
-
-"is-regex@^1.1.4":
-  "integrity" "sha1-7vVmPNWfpMCuM5UFMj32hUuxWVg="
-  "resolved" "https://registry.nlark.com/is-regex/download/is-regex-1.1.4.tgz"
-  "version" "1.1.4"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "has-tostringtag" "^1.0.0"
-
-"is-shared-array-buffer@^1.0.1":
-  "integrity" "sha1-l7DIX72stZycRG/mU7gs8rW3z+Y="
-  "resolved" "https://registry.npmmirror.com/is-shared-array-buffer/download/is-shared-array-buffer-1.0.1.tgz"
-  "version" "1.0.1"
-
-"is-string@^1.0.5", "is-string@^1.0.7":
-  "integrity" "sha1-DdEr8gBvJVu1j2lREO/3SR7rwP0="
-  "resolved" "https://registry.nlark.com/is-string/download/is-string-1.0.7.tgz"
-  "version" "1.0.7"
-  dependencies:
-    "has-tostringtag" "^1.0.0"
-
-"is-symbol@^1.0.2", "is-symbol@^1.0.3":
-  "integrity" "sha1-ptrJO2NbBjymhyI23oiRClevE5w="
-  "resolved" "https://registry.nlark.com/is-symbol/download/is-symbol-1.0.4.tgz?cache=0&sync_timestamp=1620501174327&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-symbol%2Fdownload%2Fis-symbol-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "has-symbols" "^1.0.2"
-
-"is-weakref@^1.0.1":
-  "integrity" "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ=="
-  "resolved" "https://registry.npmmirror.com/is-weakref/download/is-weakref-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "call-bind" "^1.0.2"
-
-"is-windows@^1.0.2":
-  "integrity" "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0="
-  "resolved" "https://registry.npmmirror.com/is-windows/download/is-windows-1.0.2.tgz"
-  "version" "1.0.2"
-
-"isarray@~1.0.0", "isarray@1.0.0":
-  "integrity" "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
-  "resolved" "https://registry.nlark.com/isarray/download/isarray-1.0.0.tgz"
-  "version" "1.0.0"
-
-"isexe@^2.0.0":
-  "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
-  "resolved" "https://registry.npmmirror.com/isexe/download/isexe-2.0.0.tgz"
-  "version" "2.0.0"
-
-"isobject@^2.0.0":
-  "integrity" "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA=="
-  "resolved" "https://registry.npmmirror.com/isobject/download/isobject-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "isarray" "1.0.0"
-
-"isobject@^2.1.0":
-  "integrity" "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA=="
-  "resolved" "https://registry.npmmirror.com/isobject/download/isobject-2.1.0.tgz"
-  "version" "2.1.0"
-  dependencies:
-    "isarray" "1.0.0"
-
-"isobject@^3.0.0":
-  "integrity" "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="
-  "resolved" "https://registry.npmmirror.com/isobject/download/isobject-3.0.1.tgz"
-  "version" "3.0.1"
-
-"isobject@^3.0.1":
-  "integrity" "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="
-  "resolved" "https://registry.npmmirror.com/isobject/download/isobject-3.0.1.tgz"
-  "version" "3.0.1"
-
-"js-base64@^2.1.9":
-  "integrity" "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ=="
-  "resolved" "https://registry.npmmirror.com/js-base64/download/js-base64-2.6.4.tgz"
-  "version" "2.6.4"
-
-"js-sdsl@4.3.0":
-  "integrity" "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ=="
-  "resolved" "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz"
-  "version" "4.3.0"
-
-"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0":
-  "integrity" "sha1-GSA/tZmR35jjoocFDUZHzerzJJk="
-  "resolved" "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz?cache=0&sync_timestamp=1619345098261&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fjs-tokens%2Fdownload%2Fjs-tokens-4.0.0.tgz"
-  "version" "4.0.0"
-
-"js-yaml@^3.13.1":
-  "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="
-  "resolved" "https://registry.npmmirror.com/js-yaml/download/js-yaml-3.14.1.tgz"
-  "version" "3.14.1"
-  dependencies:
-    "argparse" "^1.0.7"
-    "esprima" "^4.0.0"
-
-"jsesc@^2.5.1":
-  "integrity" "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q="
-  "resolved" "https://registry.npmmirror.com/jsesc/download/jsesc-2.5.2.tgz?cache=0&sync_timestamp=1603891232110&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjsesc%2Fdownload%2Fjsesc-2.5.2.tgz"
-  "version" "2.5.2"
-
-"json-schema-traverse@^0.4.1":
-  "integrity" "sha1-afaofZUTq4u4/mO9sJecRI5oRmA="
-  "resolved" "https://registry.npmmirror.com/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1607999852153&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz"
-  "version" "0.4.1"
-
-"json-schema-traverse@^1.0.0":
-  "integrity" "sha1-rnvLNlard6c7pcSb9lTzjmtoYOI="
-  "resolved" "https://registry.npmmirror.com/json-schema-traverse/download/json-schema-traverse-1.0.0.tgz?cache=0&sync_timestamp=1607999852153&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-1.0.0.tgz"
-  "version" "1.0.0"
-
-"json-stable-stringify-without-jsonify@^1.0.1":
-  "integrity" "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
-  "resolved" "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz"
-  "version" "1.0.1"
-
-"json5@^1.0.1":
-  "integrity" "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="
-  "resolved" "https://registry.npmmirror.com/json5/download/json5-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "minimist" "^1.2.0"
-
-"json5@^2.1.2":
-  "integrity" "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA=="
-  "resolved" "https://registry.npmmirror.com/json5/download/json5-2.2.0.tgz"
-  "version" "2.2.0"
-  dependencies:
-    "minimist" "^1.2.5"
-
-"jsonfile@^6.0.1":
-  "integrity" "sha1-vFWyY0eTxnnsZAMJTrE2mKbsCq4="
-  "resolved" "https://registry.nlark.com/jsonfile/download/jsonfile-6.1.0.tgz"
-  "version" "6.1.0"
-  dependencies:
-    "universalify" "^2.0.0"
-  optionalDependencies:
-    "graceful-fs" "^4.1.6"
-
-"kind-of@^3.0.2", "kind-of@^3.0.3":
-  "integrity" "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-3.2.2.tgz"
-  "version" "3.2.2"
-  dependencies:
-    "is-buffer" "^1.1.5"
-
-"kind-of@^3.2.0":
-  "integrity" "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-3.2.2.tgz"
-  "version" "3.2.2"
-  dependencies:
-    "is-buffer" "^1.1.5"
-
-"kind-of@^4.0.0":
-  "integrity" "sha1-IIE989cSkosgc3hpGkUGb65y3Vc="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-4.0.0.tgz"
-  "version" "4.0.0"
-  dependencies:
-    "is-buffer" "^1.1.5"
-
-"kind-of@^5.0.0", "kind-of@^5.0.2":
-  "integrity" "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-5.1.0.tgz"
-  "version" "5.1.0"
-
-"kind-of@^6.0.0":
-  "integrity" "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-6.0.3.tgz"
-  "version" "6.0.3"
-
-"kind-of@^6.0.2":
-  "integrity" "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0="
-  "resolved" "https://registry.npmmirror.com/kind-of/download/kind-of-6.0.3.tgz"
-  "version" "6.0.3"
-
-"leven@^2.1.0":
-  "integrity" "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA=="
-  "resolved" "https://registry.npmmirror.com/leven/-/leven-2.1.0.tgz"
-  "version" "2.1.0"
-
-"levn@^0.4.1":
-  "integrity" "sha1-rkViwAdHO5MqYgDUAyaN0v/8at4="
-  "resolved" "https://registry.npmmirror.com/levn/download/levn-0.4.1.tgz"
-  "version" "0.4.1"
-  dependencies:
-    "prelude-ls" "^1.2.1"
-    "type-check" "~0.4.0"
-
-"listenercount@~1.0.1":
-  "integrity" "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc="
-  "resolved" "https://registry.npmmirror.com/listenercount/download/listenercount-1.0.1.tgz"
-  "version" "1.0.1"
-
-"loader-utils@^1.1.0":
-  "integrity" "sha1-xXm140yzSxp07cbB+za/o3HVphM="
-  "resolved" "https://registry.npmmirror.com/loader-utils/download/loader-utils-1.4.0.tgz"
-  "version" "1.4.0"
-  dependencies:
-    "big.js" "^5.2.2"
-    "emojis-list" "^3.0.0"
-    "json5" "^1.0.1"
-
-"locate-path@^2.0.0":
-  "integrity" "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4="
-  "resolved" "https://registry.nlark.com/locate-path/download/locate-path-2.0.0.tgz?cache=0&sync_timestamp=1629895618224&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flocate-path%2Fdownload%2Flocate-path-2.0.0.tgz"
-  "version" "2.0.0"
-  dependencies:
-    "p-locate" "^2.0.0"
-    "path-exists" "^3.0.0"
-
-"lodash-es@^4.17.15":
-  "integrity" "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
-  "resolved" "https://registry.npmmirror.com/lodash-es/download/lodash-es-4.17.21.tgz"
-  "version" "4.17.21"
-
-"lodash.merge@^4.6.2":
-  "integrity" "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo="
-  "resolved" "https://registry.npmmirror.com/lodash.merge/download/lodash.merge-4.6.2.tgz"
-  "version" "4.6.2"
-
-"lodash.truncate@^4.4.2":
-  "integrity" "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM="
-  "resolved" "https://registry.nlark.com/lodash.truncate/download/lodash.truncate-4.4.2.tgz"
-  "version" "4.4.2"
-
-"lodash@^4.17.15", "lodash@^4.17.21":
-  "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
-  "resolved" "https://registry.npmmirror.com/lodash/download/lodash-4.17.21.tgz"
-  "version" "4.17.21"
-
-"loose-envify@^1.0.0":
-  "integrity" "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8="
-  "resolved" "https://registry.nlark.com/loose-envify/download/loose-envify-1.4.0.tgz?cache=0&sync_timestamp=1631633000868&other_urls=https%3A%2F%2Fregistry.nlark.com%2Floose-envify%2Fdownload%2Floose-envify-1.4.0.tgz"
-  "version" "1.4.0"
-  dependencies:
-    "js-tokens" "^3.0.0 || ^4.0.0"
-
-"lower-case@^2.0.2":
-  "integrity" "sha1-b6I3xj29xKgsoP2ILkci3F5jTig="
-  "resolved" "https://registry.npmmirror.com/lower-case/download/lower-case-2.0.2.tgz?cache=0&sync_timestamp=1606867333511&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Flower-case%2Fdownload%2Flower-case-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "tslib" "^2.0.3"
-
-"lru-cache@^6.0.0":
-  "integrity" "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ="
-  "resolved" "https://registry.npmmirror.com/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1599054167787&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz"
-  "version" "6.0.0"
-  dependencies:
-    "yallist" "^4.0.0"
-
-"magic-string@^0.25.7":
-  "integrity" "sha1-P0l9b9NMZpxnmNy4IfLvMfVEUFE="
-  "resolved" "https://registry.npmmirror.com/magic-string/download/magic-string-0.25.7.tgz"
-  "version" "0.25.7"
-  dependencies:
-    "sourcemap-codec" "^1.4.4"
-
-"map-cache@^0.2.2":
-  "integrity" "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
-  "resolved" "https://registry.npmmirror.com/map-cache/download/map-cache-0.2.2.tgz"
-  "version" "0.2.2"
-
-"map-visit@^1.0.0":
-  "integrity" "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48="
-  "resolved" "https://registry.nlark.com/map-visit/download/map-visit-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "object-visit" "^1.0.0"
-
-"mdn-data@2.0.14":
-  "integrity" "sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA="
-  "resolved" "https://registry.npmmirror.com/mdn-data/download/mdn-data-2.0.14.tgz"
-  "version" "2.0.14"
-
-"merge-options@1.0.1":
-  "integrity" "sha1-KmSyRFe+zU5NxggoMkfpTOWJqjI="
-  "resolved" "https://registry.npmmirror.com/merge-options/download/merge-options-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "is-plain-obj" "^1.1"
-
-"merge2@^1.3.0", "merge2@^1.4.1":
-  "integrity" "sha1-Q2iJL4hekHRVpv19xVwMnUBJkK4="
-  "resolved" "https://registry.npmmirror.com/merge2/download/merge2-1.4.1.tgz"
-  "version" "1.4.1"
-
-"micromatch@^4.0.4":
-  "integrity" "sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k="
-  "resolved" "https://registry.npmmirror.com/micromatch/download/micromatch-4.0.4.tgz?cache=0&sync_timestamp=1618054740956&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmicromatch%2Fdownload%2Fmicromatch-4.0.4.tgz"
-  "version" "4.0.4"
-  dependencies:
-    "braces" "^3.0.1"
-    "picomatch" "^2.2.3"
-
-"micromatch@3.1.0":
-  "integrity" "sha1-UQLU6vILaZfWAI46z+HESj+oFeI="
-  "resolved" "https://registry.npmmirror.com/micromatch/download/micromatch-3.1.0.tgz?cache=0&sync_timestamp=1618054740956&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmicromatch%2Fdownload%2Fmicromatch-3.1.0.tgz"
-  "version" "3.1.0"
-  dependencies:
-    "arr-diff" "^4.0.0"
-    "array-unique" "^0.3.2"
-    "braces" "^2.2.2"
-    "define-property" "^1.0.0"
-    "extend-shallow" "^2.0.1"
-    "extglob" "^2.0.2"
-    "fragment-cache" "^0.2.1"
-    "kind-of" "^5.0.2"
-    "nanomatch" "^1.2.1"
-    "object.pick" "^1.3.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
-"minimatch@^3.0.4":
-  "integrity" "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM="
-  "resolved" "https://registry.npmmirror.com/minimatch/download/minimatch-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "brace-expansion" "^1.1.7"
-
-"minimist@^1.1.0", "minimist@^1.2.0", "minimist@^1.2.5":
-  "integrity" "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
-  "resolved" "https://registry.npmmirror.com/minimist/download/minimist-1.2.5.tgz"
-  "version" "1.2.5"
-
-"mitt@^3.0.0":
-  "integrity" "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ=="
-  "resolved" "https://registry.npmmirror.com/mitt/-/mitt-3.0.0.tgz"
-  "version" "3.0.0"
-
-"mixin-deep@^1.2.0":
-  "integrity" "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY="
-  "resolved" "https://registry.npmmirror.com/mixin-deep/download/mixin-deep-1.3.2.tgz"
-  "version" "1.3.2"
-  dependencies:
-    "for-in" "^1.0.2"
-    "is-extendable" "^1.0.1"
-
-"mkdirp@>=0.5 0":
-  "integrity" "sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8="
-  "resolved" "https://registry.npmmirror.com/mkdirp/download/mkdirp-0.5.5.tgz?cache=0&sync_timestamp=1636300883420&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fmkdirp%2Fdownload%2Fmkdirp-0.5.5.tgz"
-  "version" "0.5.5"
-  dependencies:
-    "minimist" "^1.2.5"
-
-"moment@^2.27.0":
-  "integrity" "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
-  "resolved" "https://registry.npmmirror.com/moment/download/moment-2.29.1.tgz"
-  "version" "2.29.1"
-
-"mqtt-packet@^6.8.0":
-  "integrity" "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA=="
-  "resolved" "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-6.10.0.tgz"
-  "version" "6.10.0"
-  dependencies:
-    "bl" "^4.0.2"
-    "debug" "^4.1.1"
-    "process-nextick-args" "^2.0.1"
-
-"mqtt@^4.3.7":
-  "integrity" "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw=="
-  "resolved" "https://registry.npmmirror.com/mqtt/-/mqtt-4.3.7.tgz"
-  "version" "4.3.7"
-  dependencies:
-    "commist" "^1.0.0"
-    "concat-stream" "^2.0.0"
-    "debug" "^4.1.1"
-    "duplexify" "^4.1.1"
-    "help-me" "^3.0.0"
-    "inherits" "^2.0.3"
-    "lru-cache" "^6.0.0"
-    "minimist" "^1.2.5"
-    "mqtt-packet" "^6.8.0"
-    "number-allocator" "^1.0.9"
-    "pump" "^3.0.0"
-    "readable-stream" "^3.6.0"
-    "reinterval" "^1.1.0"
-    "rfdc" "^1.3.0"
-    "split2" "^3.1.0"
-    "ws" "^7.5.5"
-    "xtend" "^4.0.2"
-
-"ms@^2.1.1", "ms@2.1.2":
-  "integrity" "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
-  "resolved" "https://registry.npmmirror.com/ms/download/ms-2.1.2.tgz"
-  "version" "2.1.2"
-
-"ms@2.0.0":
-  "integrity" "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
-  "resolved" "https://registry.npmmirror.com/ms/download/ms-2.0.0.tgz"
-  "version" "2.0.0"
-
-"mutation-observer@^1.0.3":
-  "integrity" "sha1-QukiKxAbyoLlup1aes9KFMDyY9A="
-  "resolved" "https://registry.npmmirror.com/mutation-observer/download/mutation-observer-1.0.3.tgz"
-  "version" "1.0.3"
-
-"nanoid@^3.1.30":
-  "integrity" "sha512-ZivnJm0o9bb13p2Ot5CpgC2rQdzB9Uxm/mFZweqm5eMViqOJe3PV6LU2E30SiLgheesmcPrjquqraoolONSA0A=="
-  "resolved" "https://registry.npmmirror.com/nanoid/download/nanoid-3.1.31.tgz"
-  "version" "3.1.31"
-
-"nanomatch@^1.2.1":
-  "integrity" "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk="
-  "resolved" "https://registry.npmmirror.com/nanomatch/download/nanomatch-1.2.13.tgz"
-  "version" "1.2.13"
-  dependencies:
-    "arr-diff" "^4.0.0"
-    "array-unique" "^0.3.2"
-    "define-property" "^2.0.2"
-    "extend-shallow" "^3.0.2"
-    "fragment-cache" "^0.2.1"
-    "is-windows" "^1.0.2"
-    "kind-of" "^6.0.2"
-    "object.pick" "^1.3.0"
-    "regex-not" "^1.0.0"
-    "snapdragon" "^0.8.1"
-    "to-regex" "^3.0.1"
-
-"nanopop@^2.1.0":
-  "integrity" "sha1-I0dlE87iQFiIr9LopLVAZrcLnmA="
-  "resolved" "https://registry.npmmirror.com/nanopop/download/nanopop-2.1.0.tgz"
-  "version" "2.1.0"
-
-"natural-compare@^1.4.0":
-  "integrity" "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
-  "resolved" "https://registry.nlark.com/natural-compare/download/natural-compare-1.4.0.tgz"
-  "version" "1.4.0"
-
-"no-case@^3.0.4":
-  "integrity" "sha1-02H9XJgA9VhVGoNp/A3NRmK2Ek0="
-  "resolved" "https://registry.npmmirror.com/no-case/download/no-case-3.0.4.tgz?cache=0&sync_timestamp=1606867308811&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fno-case%2Fdownload%2Fno-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "lower-case" "^2.0.2"
-    "tslib" "^2.0.3"
-
-"node-releases@^2.0.1":
-  "integrity" "sha1-PR05XyBPHy8ppUNYuftnh2WtL8U="
-  "resolved" "https://registry.npmmirror.com/node-releases/download/node-releases-2.0.1.tgz"
-  "version" "2.0.1"
-
-"normalize-path@^3.0.0", "normalize-path@~3.0.0":
-  "integrity" "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU="
-  "resolved" "https://registry.npmmirror.com/normalize-path/download/normalize-path-3.0.0.tgz"
-  "version" "3.0.0"
-
-"nth-check@^2.0.1":
-  "integrity" "sha1-Lv4WL1w9oGoolZ+9PbddvuqfD8I="
-  "resolved" "https://registry.nlark.com/nth-check/download/nth-check-2.0.1.tgz?cache=0&sync_timestamp=1631793617973&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnth-check%2Fdownload%2Fnth-check-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "boolbase" "^1.0.0"
-
-"number-allocator@^1.0.9":
-  "integrity" "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA=="
-  "resolved" "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz"
-  "version" "1.0.14"
-  dependencies:
-    "debug" "^4.3.1"
-    "js-sdsl" "4.3.0"
-
-"object-assign@^4", "object-assign@^4.1.0":
-  "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
-  "resolved" "https://registry.npmmirror.com/object-assign/download/object-assign-4.1.1.tgz"
-  "version" "4.1.1"
-
-"object-copy@^0.1.0":
-  "integrity" "sha1-fn2Fi3gb18mRpBupde04EnVOmYw="
-  "resolved" "https://registry.nlark.com/object-copy/download/object-copy-0.1.0.tgz"
-  "version" "0.1.0"
-  dependencies:
-    "copy-descriptor" "^0.1.0"
-    "define-property" "^0.2.5"
-    "kind-of" "^3.0.3"
-
-"object-inspect@^1.11.0", "object-inspect@^1.9.0":
-  "integrity" "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
-  "resolved" "https://registry.npmmirror.com/object-inspect/download/object-inspect-1.12.0.tgz"
-  "version" "1.12.0"
-
-"object-keys@^1.0.12", "object-keys@^1.1.1":
-  "integrity" "sha1-HEfyct8nfzsdrwYWd9nILiMixg4="
-  "resolved" "https://registry.npmmirror.com/object-keys/download/object-keys-1.1.1.tgz"
-  "version" "1.1.1"
-
-"object-visit@^1.0.0":
-  "integrity" "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs="
-  "resolved" "https://registry.npmmirror.com/object-visit/download/object-visit-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "isobject" "^3.0.0"
-
-"object.assign@^4.1.2":
-  "integrity" "sha1-DtVKNC7Os3s4/3brgxoOeIy2OUA="
-  "resolved" "https://registry.npmmirror.com/object.assign/download/object.assign-4.1.2.tgz?cache=0&sync_timestamp=1604115158081&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fobject.assign%2Fdownload%2Fobject.assign-4.1.2.tgz"
-  "version" "4.1.2"
-  dependencies:
-    "call-bind" "^1.0.0"
-    "define-properties" "^1.1.3"
-    "has-symbols" "^1.0.1"
-    "object-keys" "^1.1.1"
-
-"object.pick@^1.3.0":
-  "integrity" "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c="
-  "resolved" "https://registry.npmmirror.com/object.pick/download/object.pick-1.3.0.tgz"
-  "version" "1.3.0"
-  dependencies:
-    "isobject" "^3.0.1"
-
-"object.values@^1.1.5":
-  "integrity" "sha1-lZ9j486e8QhyAzMIITHkpFm3Fqw="
-  "resolved" "https://registry.npmmirror.com/object.values/download/object.values-1.1.5.tgz"
-  "version" "1.1.5"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "define-properties" "^1.1.3"
-    "es-abstract" "^1.19.1"
-
-"omit.js@^2.0.0":
-  "integrity" "sha1-3ZuENvq5R6Xz/yFMslOGMeMT7C8="
-  "resolved" "https://registry.npmmirror.com/omit.js/download/omit.js-2.0.2.tgz"
-  "version" "2.0.2"
-
-"once@^1.3.0", "once@^1.3.1", "once@^1.4.0":
-  "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="
-  "resolved" "https://registry.npmmirror.com/once/download/once-1.4.0.tgz"
-  "version" "1.4.0"
-  dependencies:
-    "wrappy" "1"
-
-"optionator@^0.9.1":
-  "integrity" "sha1-TyNqY3Pa4FZqbUPhMmZ09QwpFJk="
-  "resolved" "https://registry.npmmirror.com/optionator/download/optionator-0.9.1.tgz"
-  "version" "0.9.1"
-  dependencies:
-    "deep-is" "^0.1.3"
-    "fast-levenshtein" "^2.0.6"
-    "levn" "^0.4.1"
-    "prelude-ls" "^1.2.1"
-    "type-check" "^0.4.0"
-    "word-wrap" "^1.2.3"
-
-"p-limit@^1.1.0":
-  "integrity" "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg="
-  "resolved" "https://registry.nlark.com/p-limit/download/p-limit-1.3.0.tgz"
-  "version" "1.3.0"
-  dependencies:
-    "p-try" "^1.0.0"
-
-"p-locate@^2.0.0":
-  "integrity" "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM="
-  "resolved" "https://registry.nlark.com/p-locate/download/p-locate-2.0.0.tgz?cache=0&sync_timestamp=1629892721671&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fp-locate%2Fdownload%2Fp-locate-2.0.0.tgz"
-  "version" "2.0.0"
-  dependencies:
-    "p-limit" "^1.1.0"
-
-"p-try@^1.0.0":
-  "integrity" "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
-  "resolved" "https://registry.npmmirror.com/p-try/download/p-try-1.0.0.tgz?cache=0&sync_timestamp=1633364462890&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fp-try%2Fdownload%2Fp-try-1.0.0.tgz"
-  "version" "1.0.0"
-
-"param-case@^3.0.4":
-  "integrity" "sha1-fRf+SqEr3jTUp32RrPtiGcqtAcU="
-  "resolved" "https://registry.npmmirror.com/param-case/download/param-case-3.0.4.tgz?cache=0&sync_timestamp=1606867292797&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fparam-case%2Fdownload%2Fparam-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "dot-case" "^3.0.4"
-    "tslib" "^2.0.3"
-
-"parent-module@^1.0.0":
-  "integrity" "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI="
-  "resolved" "https://registry.npmmirror.com/parent-module/download/parent-module-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "callsites" "^3.0.0"
-
-"pascal-case@^3.1.2":
-  "integrity" "sha1-tI4O8rmOIF58Ha50fQsVCCN2YOs="
-  "resolved" "https://registry.npmmirror.com/pascal-case/download/pascal-case-3.1.2.tgz?cache=0&sync_timestamp=1606867325163&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpascal-case%2Fdownload%2Fpascal-case-3.1.2.tgz"
-  "version" "3.1.2"
-  dependencies:
-    "no-case" "^3.0.4"
-    "tslib" "^2.0.3"
-
-"pascalcase@^0.1.1":
-  "integrity" "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
-  "resolved" "https://registry.npmmirror.com/pascalcase/download/pascalcase-0.1.1.tgz"
-  "version" "0.1.1"
-
-"path-case@^3.0.4":
-  "integrity" "sha1-kWhkUzTrlCZYN1xW+AtMDLX4LG8="
-  "resolved" "https://registry.npmmirror.com/path-case/download/path-case-3.0.4.tgz?cache=0&sync_timestamp=1606867325967&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpath-case%2Fdownload%2Fpath-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "dot-case" "^3.0.4"
-    "tslib" "^2.0.3"
-
-"path-exists@^3.0.0":
-  "integrity" "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
-  "resolved" "https://registry.nlark.com/path-exists/download/path-exists-3.0.0.tgz"
-  "version" "3.0.0"
-
-"path-is-absolute@^1.0.0":
-  "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
-  "resolved" "https://registry.npmmirror.com/path-is-absolute/download/path-is-absolute-1.0.1.tgz"
-  "version" "1.0.1"
-
-"path-key@^3.1.0":
-  "integrity" "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U="
-  "resolved" "https://registry.npmmirror.com/path-key/download/path-key-3.1.1.tgz"
-  "version" "3.1.1"
-
-"path-parse@^1.0.7":
-  "integrity" "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU="
-  "resolved" "https://registry.nlark.com/path-parse/download/path-parse-1.0.7.tgz"
-  "version" "1.0.7"
-
-"path-type@^4.0.0":
-  "integrity" "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs="
-  "resolved" "https://registry.nlark.com/path-type/download/path-type-4.0.0.tgz"
-  "version" "4.0.0"
-
-"picocolors@^1.0.0":
-  "integrity" "sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw="
-  "resolved" "https://registry.npmmirror.com/picocolors/download/picocolors-1.0.0.tgz?cache=0&sync_timestamp=1634093442271&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fpicocolors%2Fdownload%2Fpicocolors-1.0.0.tgz"
-  "version" "1.0.0"
-
-"picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.2.2", "picomatch@^2.2.3":
-  "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
-  "resolved" "https://registry.npmmirror.com/picomatch/download/picomatch-2.3.1.tgz"
-  "version" "2.3.1"
-
-"posix-character-classes@^0.1.0":
-  "integrity" "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
-  "resolved" "https://registry.npmmirror.com/posix-character-classes/download/posix-character-classes-0.1.1.tgz"
-  "version" "0.1.1"
-
-"postcss-prefix-selector@^1.6.0":
-  "integrity" "sha512-8d5fiBQZWMtGWH/7ewEeo6RnBNyT2kLD5wTIfV2oHYqH4hjiofg/rP5X3SUwnqOINzE4mM/K/UOAiNrIaKzd4w=="
-  "resolved" "https://registry.npmmirror.com/postcss-prefix-selector/download/postcss-prefix-selector-1.14.0.tgz"
-  "version" "1.14.0"
-
-"postcss@^5.2.17":
-  "integrity" "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg=="
-  "resolved" "https://registry.npmmirror.com/postcss/download/postcss-5.2.18.tgz"
-  "version" "5.2.18"
-  dependencies:
-    "chalk" "^1.1.3"
-    "js-base64" "^2.1.9"
-    "source-map" "^0.5.6"
-    "supports-color" "^3.2.3"
-
-"postcss@^8.1.10", "postcss@^8.4.5", "postcss@7.x || 8.x":
-  "integrity" "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg=="
-  "resolved" "https://registry.npmmirror.com/postcss/download/postcss-8.4.5.tgz"
-  "version" "8.4.5"
-  dependencies:
-    "nanoid" "^3.1.30"
-    "picocolors" "^1.0.0"
-    "source-map-js" "^1.0.1"
-
-"posthtml-parser@^0.2.0", "posthtml-parser@^0.2.1":
-  "integrity" "sha1-NdUw3jhnQMK6JP8usvrznM3ycd0="
-  "resolved" "https://registry.nlark.com/posthtml-parser/download/posthtml-parser-0.2.1.tgz"
-  "version" "0.2.1"
-  dependencies:
-    "htmlparser2" "^3.8.3"
-    "isobject" "^2.1.0"
-
-"posthtml-rename-id@^1.0":
-  "integrity" "sha1-z39us3FGvxr6wx5o8YxswZrmFDM="
-  "resolved" "https://registry.npmmirror.com/posthtml-rename-id/download/posthtml-rename-id-1.0.12.tgz"
-  "version" "1.0.12"
-  dependencies:
-    "escape-string-regexp" "1.0.5"
-
-"posthtml-render@^1.0.5", "posthtml-render@^1.0.6":
-  "integrity" "sha1-QBFAcMRYgcrLkzR9rj7/U6+8/xM="
-  "resolved" "https://registry.nlark.com/posthtml-render/download/posthtml-render-1.4.0.tgz"
-  "version" "1.4.0"
-
-"posthtml-svg-mode@^1.0.3":
-  "integrity" "sha1-q9VU+s6BIjyrDLNn4Y5O/SpOdLA="
-  "resolved" "https://registry.npmmirror.com/posthtml-svg-mode/download/posthtml-svg-mode-1.0.3.tgz"
-  "version" "1.0.3"
-  dependencies:
-    "merge-options" "1.0.1"
-    "posthtml" "^0.9.2"
-    "posthtml-parser" "^0.2.1"
-    "posthtml-render" "^1.0.6"
-
-"posthtml@^0.9.2":
-  "integrity" "sha1-9MBtufZ7Yf0XxOJW5+PZUVv3Jv0="
-  "resolved" "https://registry.nlark.com/posthtml/download/posthtml-0.9.2.tgz?cache=0&sync_timestamp=1627459255104&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fposthtml%2Fdownload%2Fposthtml-0.9.2.tgz"
-  "version" "0.9.2"
-  dependencies:
-    "posthtml-parser" "^0.2.0"
-    "posthtml-render" "^1.0.5"
-
-"prelude-ls@^1.2.1":
-  "integrity" "sha1-3rxkidem5rDnYRiIzsiAM30xY5Y="
-  "resolved" "https://registry.npmmirror.com/prelude-ls/download/prelude-ls-1.2.1.tgz"
-  "version" "1.2.1"
-
-"process-nextick-args@^2.0.1", "process-nextick-args@~2.0.0":
-  "integrity" "sha1-eCDZsWEgzFXKmud5JoCufbptf+I="
-  "resolved" "https://registry.npmmirror.com/process-nextick-args/download/process-nextick-args-2.0.1.tgz"
-  "version" "2.0.1"
-
-"progress@^2.0.0":
-  "integrity" "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
-  "resolved" "https://registry.npmmirror.com/progress/download/progress-2.0.3.tgz"
-  "version" "2.0.3"
-
-"pump@^3.0.0":
-  "integrity" "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="
-  "resolved" "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz"
-  "version" "3.0.0"
-  dependencies:
-    "end-of-stream" "^1.1.0"
-    "once" "^1.3.1"
-
-"punycode@^2.1.0":
-  "integrity" "sha1-tYsBCsQMIsVldhbI0sLALHv0eew="
-  "resolved" "https://registry.npmmirror.com/punycode/download/punycode-2.1.1.tgz"
-  "version" "2.1.1"
-
-"query-string@^4.3.2":
-  "integrity" "sha1-u7aTucqRXCMlFbIosaArYJBD2+s="
-  "resolved" "https://registry.npmmirror.com/query-string/download/query-string-4.3.4.tgz"
-  "version" "4.3.4"
-  dependencies:
-    "object-assign" "^4.1.0"
-    "strict-uri-encode" "^1.0.0"
-
-"query-string@^7.0.1":
-  "integrity" "sha512-wnJ8covk+S9isYR5JIXPt93kFUmI2fQ4R/8130fuq+qwLiGVTurg7Klodgfw4NSz/oe7xnyi09y3lSrogUeM3g=="
-  "resolved" "https://registry.npmmirror.com/query-string/download/query-string-7.1.0.tgz"
-  "version" "7.1.0"
-  dependencies:
-    "decode-uri-component" "^0.2.0"
-    "filter-obj" "^1.1.0"
-    "split-on-first" "^1.0.0"
-    "strict-uri-encode" "^2.0.0"
-
-"queue-microtask@^1.2.2":
-  "integrity" "sha1-SSkii7xyTfrEPg77BYyve2z7YkM="
-  "resolved" "https://registry.npmmirror.com/queue-microtask/download/queue-microtask-1.2.3.tgz?cache=0&sync_timestamp=1616391641179&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fqueue-microtask%2Fdownload%2Fqueue-microtask-1.2.3.tgz"
-  "version" "1.2.3"
-
-"readable-stream@^2.0.2":
-  "integrity" "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c="
-  "resolved" "https://registry.npmmirror.com/readable-stream/download/readable-stream-2.3.7.tgz"
-  "version" "2.3.7"
-  dependencies:
-    "core-util-is" "~1.0.0"
-    "inherits" "~2.0.3"
-    "isarray" "~1.0.0"
-    "process-nextick-args" "~2.0.0"
-    "safe-buffer" "~5.1.1"
-    "string_decoder" "~1.1.1"
-    "util-deprecate" "~1.0.1"
-
-"readable-stream@^3.0.0", "readable-stream@^3.0.2", "readable-stream@^3.1.1", "readable-stream@^3.4.0", "readable-stream@^3.6.0":
-  "integrity" "sha1-M3u9o63AcGvT4CRCaihtS0sskZg="
-  "resolved" "https://registry.npmmirror.com/readable-stream/download/readable-stream-3.6.0.tgz"
-  "version" "3.6.0"
-  dependencies:
-    "inherits" "^2.0.3"
-    "string_decoder" "^1.1.1"
-    "util-deprecate" "^1.0.1"
-
-"readable-stream@~2.3.6":
-  "integrity" "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c="
-  "resolved" "https://registry.npmmirror.com/readable-stream/download/readable-stream-2.3.7.tgz"
-  "version" "2.3.7"
-  dependencies:
-    "core-util-is" "~1.0.0"
-    "inherits" "~2.0.3"
-    "isarray" "~1.0.0"
-    "process-nextick-args" "~2.0.0"
-    "safe-buffer" "~5.1.1"
-    "string_decoder" "~1.1.1"
-    "util-deprecate" "~1.0.1"
-
-"readdirp@~3.6.0":
-  "integrity" "sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc="
-  "resolved" "https://registry.npmmirror.com/readdirp/download/readdirp-3.6.0.tgz?cache=0&sync_timestamp=1615717369278&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Freaddirp%2Fdownload%2Freaddirp-3.6.0.tgz"
-  "version" "3.6.0"
-  dependencies:
-    "picomatch" "^2.2.1"
-
-"reconnecting-websocket@^4.4.0":
-  "integrity" "sha1-Ow5blu8RnnigMTWGW4uwrxuUh4M="
-  "resolved" "https://registry.npmmirror.com/reconnecting-websocket/download/reconnecting-websocket-4.4.0.tgz"
-  "version" "4.4.0"
-
-"regenerator-runtime@^0.13.4", "regenerator-runtime@^0.13.9":
-  "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
-  "resolved" "https://registry.npmmirror.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz"
-  "version" "0.13.9"
-
-"regex-not@^1.0.0", "regex-not@^1.0.2":
-  "integrity" "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw="
-  "resolved" "https://registry.npmmirror.com/regex-not/download/regex-not-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "extend-shallow" "^3.0.2"
-    "safe-regex" "^1.1.0"
-
-"regexpp@^3.0.0", "regexpp@^3.1.0", "regexpp@^3.2.0":
-  "integrity" "sha1-BCWido2PI7rXDKS5BGH6LxIT4bI="
-  "resolved" "https://registry.nlark.com/regexpp/download/regexpp-3.2.0.tgz"
-  "version" "3.2.0"
-
-"reinterval@^1.1.0":
-  "integrity" "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ=="
-  "resolved" "https://registry.npmmirror.com/reinterval/-/reinterval-1.1.0.tgz"
-  "version" "1.1.0"
-
-"repeat-element@^1.1.2":
-  "integrity" "sha1-vmgVIIR6tYx1aKx1+/rSjtQtOek="
-  "resolved" "https://registry.nlark.com/repeat-element/download/repeat-element-1.1.4.tgz"
-  "version" "1.1.4"
-
-"repeat-string@^1.6.1":
-  "integrity" "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
-  "resolved" "https://registry.npmmirror.com/repeat-string/download/repeat-string-1.6.1.tgz?cache=0&sync_timestamp=1589682793094&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Frepeat-string%2Fdownload%2Frepeat-string-1.6.1.tgz"
-  "version" "1.6.1"
-
-"require-from-string@^2.0.2":
-  "integrity" "sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk="
-  "resolved" "https://registry.npmmirror.com/require-from-string/download/require-from-string-2.0.2.tgz"
-  "version" "2.0.2"
-
-"resize-observer-polyfill@^1.5.1":
-  "integrity" "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ="
-  "resolved" "https://registry.npmmirror.com/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz"
-  "version" "1.5.1"
-
-"resolve-from@^4.0.0":
-  "integrity" "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY="
-  "resolved" "https://registry.npmmirror.com/resolve-from/download/resolve-from-4.0.0.tgz"
-  "version" "4.0.0"
-
-"resolve-url@^0.2.1":
-  "integrity" "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
-  "resolved" "https://registry.npmmirror.com/resolve-url/download/resolve-url-0.2.1.tgz"
-  "version" "0.2.1"
-
-"resolve@^1.10.1", "resolve@^1.20.0":
-  "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
-  "resolved" "https://registry.npmmirror.com/resolve/download/resolve-1.21.0.tgz"
-  "version" "1.21.0"
-  dependencies:
-    "is-core-module" "^2.8.0"
-    "path-parse" "^1.0.7"
-    "supports-preserve-symlinks-flag" "^1.0.0"
-
-"ret@~0.1.10":
-  "integrity" "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w="
-  "resolved" "https://registry.npmmirror.com/ret/download/ret-0.1.15.tgz"
-  "version" "0.1.15"
-
-"reusify@^1.0.4":
-  "integrity" "sha1-kNo4Kx4SbvwCFG6QhFqI2xKSXXY="
-  "resolved" "https://registry.npmmirror.com/reusify/download/reusify-1.0.4.tgz"
-  "version" "1.0.4"
-
-"rfdc@^1.3.0":
-  "integrity" "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
-  "resolved" "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.0.tgz"
-  "version" "1.3.0"
-
-"rimraf@^3.0.2":
-  "integrity" "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho="
-  "resolved" "https://registry.npmmirror.com/rimraf/download/rimraf-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "glob" "^7.1.3"
-
-"rimraf@2":
-  "integrity" "sha1-NXl/E6f9rcVmFCwp1PB8ytSD4+w="
-  "resolved" "https://registry.npmmirror.com/rimraf/download/rimraf-2.7.1.tgz"
-  "version" "2.7.1"
-  dependencies:
-    "glob" "^7.1.3"
-
-"rollup-plugin-external-globals@^0.6.1":
-  "integrity" "sha1-hhwmC1cnFE4P0bQksQP58Cgvw2U="
-  "resolved" "https://registry.nlark.com/rollup-plugin-external-globals/download/rollup-plugin-external-globals-0.6.1.tgz"
-  "version" "0.6.1"
-  dependencies:
-    "@rollup/pluginutils" "^4.0.0"
-    "estree-walker" "^2.0.1"
-    "is-reference" "^1.2.1"
-    "magic-string" "^0.25.7"
-
-"rollup@^2.25.0", "rollup@^2.47.0", "rollup@^2.59.0":
-  "integrity" "sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA=="
-  "resolved" "https://registry.npmmirror.com/rollup/-/rollup-2.68.0.tgz"
-  "version" "2.68.0"
-  optionalDependencies:
-    "fsevents" "~2.3.2"
-
-"run-parallel@^1.1.9":
-  "integrity" "sha1-ZtE2jae9+SHrnZW9GpIp5/IaQ+4="
-  "resolved" "https://registry.npmmirror.com/run-parallel/download/run-parallel-1.2.0.tgz?cache=0&sync_timestamp=1612925943325&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Frun-parallel%2Fdownload%2Frun-parallel-1.2.0.tgz"
-  "version" "1.2.0"
-  dependencies:
-    "queue-microtask" "^1.2.2"
-
-"safe-buffer@~5.1.0", "safe-buffer@~5.1.1":
-  "integrity" "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
-  "resolved" "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.1.2.tgz"
-  "version" "5.1.2"
-
-"safe-buffer@~5.2.0":
-  "integrity" "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY="
-  "resolved" "https://registry.nlark.com/safe-buffer/download/safe-buffer-5.2.1.tgz"
-  "version" "5.2.1"
-
-"safe-regex@^1.1.0":
-  "integrity" "sha1-QKNmnzsHfR6UPURinhV91IAjvy4="
-  "resolved" "https://registry.npmmirror.com/safe-regex/download/safe-regex-1.1.0.tgz"
-  "version" "1.1.0"
-  dependencies:
-    "ret" "~0.1.10"
-
-"sass@*", "sass@^1.35.1":
-  "integrity" "sha512-GtXwvwgD7/6MLUZPnlA5/8cdRgC9SzT5kAnnJMRmEZQFRE3J56Foswig4NyyyQGsnmNvg6EUM/FP0Pe9Y2zywQ=="
-  "resolved" "https://registry.npmmirror.com/sass/download/sass-1.47.0.tgz"
-  "version" "1.47.0"
-  dependencies:
-    "chokidar" ">=3.0.0 <4.0.0"
-    "immutable" "^4.0.0"
-    "source-map-js" ">=0.6.2 <2.0.0"
-
-"scroll-into-view-if-needed@^2.2.25":
-  "integrity" "sha1-WhWy9YpSZCyIyOylhGROAXA9ZFo="
-  "resolved" "https://registry.npmmirror.com/scroll-into-view-if-needed/download/scroll-into-view-if-needed-2.2.28.tgz"
-  "version" "2.2.28"
-  dependencies:
-    "compute-scroll-into-view" "^1.0.17"
-
-"semver@^6.1.0":
-  "integrity" "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0="
-  "resolved" "https://registry.npmmirror.com/semver/download/semver-6.3.0.tgz"
-  "version" "6.3.0"
-
-"semver@^6.3.0":
-  "integrity" "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0="
-  "resolved" "https://registry.npmmirror.com/semver/download/semver-6.3.0.tgz"
-  "version" "6.3.0"
-
-"semver@^7.2.1", "semver@^7.3.5":
-  "integrity" "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc="
-  "resolved" "https://registry.npmmirror.com/semver/download/semver-7.3.5.tgz"
-  "version" "7.3.5"
-  dependencies:
-    "lru-cache" "^6.0.0"
-
-"sentence-case@^3.0.4":
-  "integrity" "sha1-NkWnuMEXx4f96HAgViJbtipFEx8="
-  "resolved" "https://registry.npmmirror.com/sentence-case/download/sentence-case-3.0.4.tgz?cache=0&sync_timestamp=1606867325535&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsentence-case%2Fdownload%2Fsentence-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "no-case" "^3.0.4"
-    "tslib" "^2.0.3"
-    "upper-case-first" "^2.0.2"
-
-"set-value@^2.0.0", "set-value@^2.0.1":
-  "integrity" "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs="
-  "resolved" "https://registry.nlark.com/set-value/download/set-value-2.0.1.tgz"
-  "version" "2.0.1"
-  dependencies:
-    "extend-shallow" "^2.0.1"
-    "is-extendable" "^0.1.1"
-    "is-plain-object" "^2.0.3"
-    "split-string" "^3.0.1"
-
-"setimmediate@~1.0.4":
-  "integrity" "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
-  "resolved" "https://registry.npmmirror.com/setimmediate/download/setimmediate-1.0.5.tgz"
-  "version" "1.0.5"
-
-"shallow-equal@^1.0.0":
-  "integrity" "sha1-TBar+lYEOqINBQMk76aJQLDaedo="
-  "resolved" "https://registry.npmmirror.com/shallow-equal/download/shallow-equal-1.2.1.tgz"
-  "version" "1.2.1"
-
-"shebang-command@^2.0.0":
-  "integrity" "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo="
-  "resolved" "https://registry.npmmirror.com/shebang-command/download/shebang-command-2.0.0.tgz"
-  "version" "2.0.0"
-  dependencies:
-    "shebang-regex" "^3.0.0"
-
-"shebang-regex@^3.0.0":
-  "integrity" "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI="
-  "resolved" "https://registry.nlark.com/shebang-regex/download/shebang-regex-3.0.0.tgz"
-  "version" "3.0.0"
-
-"side-channel@^1.0.4":
-  "integrity" "sha1-785cj9wQTudRslxY1CkAEfpeos8="
-  "resolved" "https://registry.npmmirror.com/side-channel/download/side-channel-1.0.4.tgz?cache=0&sync_timestamp=1609270210432&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fside-channel%2Fdownload%2Fside-channel-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "call-bind" "^1.0.0"
-    "get-intrinsic" "^1.0.2"
-    "object-inspect" "^1.9.0"
-
-"slash@^3.0.0":
-  "integrity" "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ="
-  "resolved" "https://registry.nlark.com/slash/download/slash-3.0.0.tgz"
-  "version" "3.0.0"
-
-"slice-ansi@^4.0.0":
-  "integrity" "sha1-UA6N0P1VsFgVCGJVsxla3ypF/ms="
-  "resolved" "https://registry.nlark.com/slice-ansi/download/slice-ansi-4.0.0.tgz"
-  "version" "4.0.0"
-  dependencies:
-    "ansi-styles" "^4.0.0"
-    "astral-regex" "^2.0.0"
-    "is-fullwidth-code-point" "^3.0.0"
-
-"snake-case@^3.0.4":
-  "integrity" "sha1-Tyu9Vo6ZNavf1ZPzTGkdrbScRSw="
-  "resolved" "https://registry.npmmirror.com/snake-case/download/snake-case-3.0.4.tgz?cache=0&sync_timestamp=1606867326057&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsnake-case%2Fdownload%2Fsnake-case-3.0.4.tgz"
-  "version" "3.0.4"
-  dependencies:
-    "dot-case" "^3.0.4"
-    "tslib" "^2.0.3"
-
-"snapdragon-node@^2.0.1":
-  "integrity" "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs="
-  "resolved" "https://registry.npmmirror.com/snapdragon-node/download/snapdragon-node-2.1.1.tgz"
-  "version" "2.1.1"
-  dependencies:
-    "define-property" "^1.0.0"
-    "isobject" "^3.0.0"
-    "snapdragon-util" "^3.0.1"
-
-"snapdragon-util@^3.0.1":
-  "integrity" "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI="
-  "resolved" "https://registry.npmmirror.com/snapdragon-util/download/snapdragon-util-3.0.1.tgz"
-  "version" "3.0.1"
-  dependencies:
-    "kind-of" "^3.2.0"
-
-"snapdragon@^0.8.1":
-  "integrity" "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0="
-  "resolved" "https://registry.npmmirror.com/snapdragon/download/snapdragon-0.8.2.tgz"
-  "version" "0.8.2"
-  dependencies:
-    "base" "^0.11.1"
-    "debug" "^2.2.0"
-    "define-property" "^0.2.5"
-    "extend-shallow" "^2.0.1"
-    "map-cache" "^0.2.2"
-    "source-map" "^0.5.6"
-    "source-map-resolve" "^0.5.0"
-    "use" "^3.1.0"
-
-"source-map-js@^1.0.1", "source-map-js@>=0.6.2 <2.0.0":
-  "integrity" "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
-  "resolved" "https://registry.npmmirror.com/source-map-js/download/source-map-js-1.0.1.tgz"
-  "version" "1.0.1"
-
-"source-map-resolve@^0.5.0":
-  "integrity" "sha1-GQhmvs51U+H48mei7oLGBrVQmho="
-  "resolved" "https://registry.npmmirror.com/source-map-resolve/download/source-map-resolve-0.5.3.tgz"
-  "version" "0.5.3"
-  dependencies:
-    "atob" "^2.1.2"
-    "decode-uri-component" "^0.2.0"
-    "resolve-url" "^0.2.1"
-    "source-map-url" "^0.4.0"
-    "urix" "^0.1.0"
-
-"source-map-url@^0.4.0":
-  "integrity" "sha1-CvZmBadFpaL5HPG7+KevvCg97FY="
-  "resolved" "https://registry.npmmirror.com/source-map-url/download/source-map-url-0.4.1.tgz"
-  "version" "0.4.1"
-
-"source-map@^0.5.0":
-  "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
-  "resolved" "https://registry.npmmirror.com/source-map/download/source-map-0.5.7.tgz"
-  "version" "0.5.7"
-
-"source-map@^0.5.6":
-  "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
-  "resolved" "https://registry.npmmirror.com/source-map/download/source-map-0.5.7.tgz"
-  "version" "0.5.7"
-
-"source-map@^0.6.1", "source-map@0.6.1":
-  "integrity" "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
-  "resolved" "https://registry.npmmirror.com/source-map/download/source-map-0.6.1.tgz"
-  "version" "0.6.1"
-
-"sourcemap-codec@^1.4.4":
-  "integrity" "sha1-6oBL2UhXQC5pktBaOO8a41qatMQ="
-  "resolved" "https://registry.npmmirror.com/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz"
-  "version" "1.4.8"
-
-"split-on-first@^1.0.0":
-  "integrity" "sha1-9hCv7uOxK84dDDBCXnY5i3gkml8="
-  "resolved" "https://registry.npmmirror.com/split-on-first/download/split-on-first-1.1.0.tgz?cache=0&sync_timestamp=1618467042029&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsplit-on-first%2Fdownload%2Fsplit-on-first-1.1.0.tgz"
-  "version" "1.1.0"
-
-"split-string@^3.0.1", "split-string@^3.0.2":
-  "integrity" "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I="
-  "resolved" "https://registry.npmmirror.com/split-string/download/split-string-3.1.0.tgz"
-  "version" "3.1.0"
-  dependencies:
-    "extend-shallow" "^3.0.0"
-
-"split2@^3.1.0":
-  "integrity" "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg=="
-  "resolved" "https://registry.npmmirror.com/split2/-/split2-3.2.2.tgz"
-  "version" "3.2.2"
-  dependencies:
-    "readable-stream" "^3.0.0"
-
-"sprintf-js@~1.0.2":
-  "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
-  "resolved" "https://registry.npmmirror.com/sprintf-js/download/sprintf-js-1.0.3.tgz"
-  "version" "1.0.3"
-
-"stable@^0.1.8":
-  "integrity" "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88="
-  "resolved" "https://registry.npmmirror.com/stable/download/stable-0.1.8.tgz"
-  "version" "0.1.8"
-
-"static-extend@^0.1.1":
-  "integrity" "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY="
-  "resolved" "https://registry.npmmirror.com/static-extend/download/static-extend-0.1.2.tgz"
-  "version" "0.1.2"
-  dependencies:
-    "define-property" "^0.2.5"
-    "object-copy" "^0.1.0"
-
-"stream-shift@^1.0.0":
-  "integrity" "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
-  "resolved" "https://registry.npmmirror.com/stream-shift/-/stream-shift-1.0.1.tgz"
-  "version" "1.0.1"
-
-"strict-uri-encode@^1.0.0":
-  "integrity" "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
-  "resolved" "https://registry.npmmirror.com/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz"
-  "version" "1.1.0"
-
-"strict-uri-encode@^2.0.0":
-  "integrity" "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
-  "resolved" "https://registry.npmmirror.com/strict-uri-encode/download/strict-uri-encode-2.0.0.tgz"
-  "version" "2.0.0"
-
-"string_decoder@^1.1.1":
-  "integrity" "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4="
-  "resolved" "https://registry.npmmirror.com/string_decoder/download/string_decoder-1.3.0.tgz"
-  "version" "1.3.0"
-  dependencies:
-    "safe-buffer" "~5.2.0"
-
-"string_decoder@~1.1.1":
-  "integrity" "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g="
-  "resolved" "https://registry.npmmirror.com/string_decoder/download/string_decoder-1.1.1.tgz"
-  "version" "1.1.1"
-  dependencies:
-    "safe-buffer" "~5.1.0"
-
-"string-width@^4.2.3":
-  "integrity" "sha1-JpxxF9J7Ba0uU2gwqOyJXvnG0BA="
-  "resolved" "https://registry.npmmirror.com/string-width/download/string-width-4.2.3.tgz"
-  "version" "4.2.3"
-  dependencies:
-    "emoji-regex" "^8.0.0"
-    "is-fullwidth-code-point" "^3.0.0"
-    "strip-ansi" "^6.0.1"
-
-"string.prototype.trimend@^1.0.4":
-  "integrity" "sha1-51rpDClCxjUEaGwYsoe0oLGkX4A="
-  "resolved" "https://registry.npmmirror.com/string.prototype.trimend/download/string.prototype.trimend-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "define-properties" "^1.1.3"
-
-"string.prototype.trimstart@^1.0.4":
-  "integrity" "sha1-s2OZr0qymZtMnGSL16P7K7Jv7u0="
-  "resolved" "https://registry.npmmirror.com/string.prototype.trimstart/download/string.prototype.trimstart-1.0.4.tgz?cache=0&sync_timestamp=1614127357785&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fstring.prototype.trimstart%2Fdownload%2Fstring.prototype.trimstart-1.0.4.tgz"
-  "version" "1.0.4"
-  dependencies:
-    "call-bind" "^1.0.2"
-    "define-properties" "^1.1.3"
-
-"strip-ansi@^3.0.0":
-  "integrity" "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8="
-  "resolved" "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-3.0.1.tgz"
-  "version" "3.0.1"
-  dependencies:
-    "ansi-regex" "^2.0.0"
-
-"strip-ansi@^6.0.0", "strip-ansi@^6.0.1":
-  "integrity" "sha1-nibGPTD1NEPpSJSVshBdN7Z6hdk="
-  "resolved" "https://registry.npmmirror.com/strip-ansi/download/strip-ansi-6.0.1.tgz"
-  "version" "6.0.1"
-  dependencies:
-    "ansi-regex" "^5.0.1"
-
-"strip-bom@^3.0.0":
-  "integrity" "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
-  "resolved" "https://registry.npmmirror.com/strip-bom/download/strip-bom-3.0.0.tgz?cache=0&sync_timestamp=1618599587805&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fstrip-bom%2Fdownload%2Fstrip-bom-3.0.0.tgz"
-  "version" "3.0.0"
-
-"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1":
-  "integrity" "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY="
-  "resolved" "https://registry.nlark.com/strip-json-comments/download/strip-json-comments-3.1.1.tgz"
-  "version" "3.1.1"
-
-"supports-color@^2.0.0":
-  "integrity" "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
-  "resolved" "https://registry.npmmirror.com/supports-color/download/supports-color-2.0.0.tgz"
-  "version" "2.0.0"
-
-"supports-color@^3.2.3":
-  "integrity" "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY="
-  "resolved" "https://registry.npmmirror.com/supports-color/download/supports-color-3.2.3.tgz"
-  "version" "3.2.3"
-  dependencies:
-    "has-flag" "^1.0.0"
-
-"supports-color@^5.3.0":
-  "integrity" "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8="
-  "resolved" "https://registry.npmmirror.com/supports-color/download/supports-color-5.5.0.tgz"
-  "version" "5.5.0"
-  dependencies:
-    "has-flag" "^3.0.0"
-
-"supports-color@^7.1.0":
-  "integrity" "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo="
-  "resolved" "https://registry.npmmirror.com/supports-color/download/supports-color-7.2.0.tgz"
-  "version" "7.2.0"
-  dependencies:
-    "has-flag" "^4.0.0"
-
-"supports-preserve-symlinks-flag@^1.0.0":
-  "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
-  "resolved" "https://registry.npmmirror.com/supports-preserve-symlinks-flag/download/supports-preserve-symlinks-flag-1.0.0.tgz"
-  "version" "1.0.0"
-
-"svg-baker@1.7.0":
-  "integrity" "sha1-g2f3jYdVUMUv5HVvcwPVxdfC6ac="
-  "resolved" "https://registry.npmmirror.com/svg-baker/download/svg-baker-1.7.0.tgz"
-  "version" "1.7.0"
-  dependencies:
-    "bluebird" "^3.5.0"
-    "clone" "^2.1.1"
-    "he" "^1.1.1"
-    "image-size" "^0.5.1"
-    "loader-utils" "^1.1.0"
-    "merge-options" "1.0.1"
-    "micromatch" "3.1.0"
-    "postcss" "^5.2.17"
-    "postcss-prefix-selector" "^1.6.0"
-    "posthtml-rename-id" "^1.0"
-    "posthtml-svg-mode" "^1.0.3"
-    "query-string" "^4.3.2"
-    "traverse" "^0.6.6"
-
-"svgo@^2.8.0":
-  "integrity" "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg=="
-  "resolved" "https://registry.npmmirror.com/svgo/download/svgo-2.8.0.tgz"
-  "version" "2.8.0"
-  dependencies:
-    "@trysound/sax" "0.2.0"
-    "commander" "^7.2.0"
-    "css-select" "^4.1.3"
-    "css-tree" "^1.1.3"
-    "csso" "^4.2.0"
-    "picocolors" "^1.0.0"
-    "stable" "^0.1.8"
-
-"systemjs@^6.11.0":
-  "integrity" "sha512-7YPIY44j+BoY+E6cGBSw0oCU8SNTTIHKZgftcBdwWkDzs/M86Fdlr21FrzAyph7Zo8r3CFGscyFe4rrBtixrBg=="
-  "resolved" "https://registry.npmmirror.com/systemjs/download/systemjs-6.11.0.tgz"
-  "version" "6.11.0"
-
-"table@^6.0.9":
-  "integrity" "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA=="
-  "resolved" "https://registry.npmmirror.com/table/download/table-6.8.0.tgz"
-  "version" "6.8.0"
-  dependencies:
-    "ajv" "^8.0.1"
-    "lodash.truncate" "^4.4.2"
-    "slice-ansi" "^4.0.0"
-    "string-width" "^4.2.3"
-    "strip-ansi" "^6.0.1"
-
-"text-table@^0.2.0":
-  "integrity" "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
-  "resolved" "https://registry.nlark.com/text-table/download/text-table-0.2.0.tgz"
-  "version" "0.2.0"
-
-"to-fast-properties@^2.0.0":
-  "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
-  "resolved" "https://registry.nlark.com/to-fast-properties/download/to-fast-properties-2.0.0.tgz?cache=0&sync_timestamp=1628418893613&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-2.0.0.tgz"
-  "version" "2.0.0"
-
-"to-object-path@^0.3.0":
-  "integrity" "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68="
-  "resolved" "https://registry.npmmirror.com/to-object-path/download/to-object-path-0.3.0.tgz"
-  "version" "0.3.0"
-  dependencies:
-    "kind-of" "^3.0.2"
-
-"to-regex-range@^2.1.0":
-  "integrity" "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg="
-  "resolved" "https://registry.npmmirror.com/to-regex-range/download/to-regex-range-2.1.1.tgz"
-  "version" "2.1.1"
-  dependencies:
-    "is-number" "^3.0.0"
-    "repeat-string" "^1.6.1"
-
-"to-regex-range@^5.0.1":
-  "integrity" "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ="
-  "resolved" "https://registry.npmmirror.com/to-regex-range/download/to-regex-range-5.0.1.tgz"
-  "version" "5.0.1"
-  dependencies:
-    "is-number" "^7.0.0"
-
-"to-regex@^3.0.1":
-  "integrity" "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4="
-  "resolved" "https://registry.npmmirror.com/to-regex/download/to-regex-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "define-property" "^2.0.2"
-    "extend-shallow" "^3.0.2"
-    "regex-not" "^1.0.2"
-    "safe-regex" "^1.1.0"
-
-"traverse@^0.6.6":
-  "integrity" "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="
-  "resolved" "https://registry.npmmirror.com/traverse/download/traverse-0.6.6.tgz"
-  "version" "0.6.6"
-
-"traverse@>=0.3.0 <0.4":
-  "integrity" "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
-  "resolved" "https://registry.npmmirror.com/traverse/download/traverse-0.3.9.tgz"
-  "version" "0.3.9"
-
-"tsconfig-paths@^3.12.0":
-  "integrity" "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg=="
-  "resolved" "https://registry.npmmirror.com/tsconfig-paths/download/tsconfig-paths-3.12.0.tgz"
-  "version" "3.12.0"
-  dependencies:
-    "@types/json5" "^0.0.29"
-    "json5" "^1.0.1"
-    "minimist" "^1.2.0"
-    "strip-bom" "^3.0.0"
-
-"tslib@^1.8.1":
-  "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
-  "resolved" "https://registry.npmmirror.com/tslib/download/tslib-1.14.1.tgz"
-  "version" "1.14.1"
-
-"tslib@^2.0.3":
-  "integrity" "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
-  "resolved" "https://registry.npmmirror.com/tslib/download/tslib-2.3.1.tgz"
-  "version" "2.3.1"
-
-"tsutils@^3.21.0":
-  "integrity" "sha1-tIcX05TOpsHglpg+7Vjp1hcVtiM="
-  "resolved" "https://registry.npmmirror.com/tsutils/download/tsutils-3.21.0.tgz?cache=0&sync_timestamp=1615138184534&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ftsutils%2Fdownload%2Ftsutils-3.21.0.tgz"
-  "version" "3.21.0"
-  dependencies:
-    "tslib" "^1.8.1"
-
-"type-check@^0.4.0", "type-check@~0.4.0":
-  "integrity" "sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE="
-  "resolved" "https://registry.npmmirror.com/type-check/download/type-check-0.4.0.tgz"
-  "version" "0.4.0"
-  dependencies:
-    "prelude-ls" "^1.2.1"
-
-"type-fest@^0.20.2":
-  "integrity" "sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ="
-  "resolved" "https://registry.npmmirror.com/type-fest/download/type-fest-0.20.2.tgz"
-  "version" "0.20.2"
-
-"typedarray@^0.0.6":
-  "integrity" "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
-  "resolved" "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz"
-  "version" "0.0.6"
-
-"typescript@^4.5.4", "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":
-  "integrity" "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
-  "resolved" "https://registry.npmmirror.com/typescript/download/typescript-4.5.4.tgz"
-  "version" "4.5.4"
-
-"unbox-primitive@^1.0.1":
-  "integrity" "sha1-CF4hViXsMWJXTciFmr7nilmxRHE="
-  "resolved" "https://registry.npmmirror.com/unbox-primitive/download/unbox-primitive-1.0.1.tgz?cache=0&sync_timestamp=1616706302651&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Funbox-primitive%2Fdownload%2Funbox-primitive-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "function-bind" "^1.1.1"
-    "has-bigints" "^1.0.1"
-    "has-symbols" "^1.0.2"
-    "which-boxed-primitive" "^1.0.2"
-
-"union-value@^1.0.0":
-  "integrity" "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc="
-  "resolved" "https://registry.npmmirror.com/union-value/download/union-value-1.0.1.tgz"
-  "version" "1.0.1"
-  dependencies:
-    "arr-union" "^3.1.0"
-    "get-value" "^2.0.6"
-    "is-extendable" "^0.1.1"
-    "set-value" "^2.0.1"
-
-"universalify@^2.0.0":
-  "integrity" "sha1-daSYTv7cSwiXXFrrc/Uw0C3yVxc="
-  "resolved" "https://registry.npmmirror.com/universalify/download/universalify-2.0.0.tgz?cache=0&sync_timestamp=1603179967633&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Funiversalify%2Fdownload%2Funiversalify-2.0.0.tgz"
-  "version" "2.0.0"
-
-"unset-value@^1.0.0":
-  "integrity" "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk="
-  "resolved" "https://registry.npmmirror.com/unset-value/download/unset-value-1.0.0.tgz"
-  "version" "1.0.0"
-  dependencies:
-    "has-value" "^0.3.1"
-    "isobject" "^3.0.0"
-
-"unzipper@0.10.11":
-  "integrity" "sha1-C0mRRGRyy9uS7nQDkJ8mwkGceC4="
-  "resolved" "https://registry.npmmirror.com/unzipper/download/unzipper-0.10.11.tgz"
-  "version" "0.10.11"
-  dependencies:
-    "big-integer" "^1.6.17"
-    "binary" "~0.3.0"
-    "bluebird" "~3.4.1"
-    "buffer-indexof-polyfill" "~1.0.0"
-    "duplexer2" "~0.1.4"
-    "fstream" "^1.0.12"
-    "graceful-fs" "^4.2.2"
-    "listenercount" "~1.0.1"
-    "readable-stream" "~2.3.6"
-    "setimmediate" "~1.0.4"
-
-"upper-case-first@^2.0.2":
-  "integrity" "sha1-mSwyc/iCq9GdHgKJTMFHEX+EQyQ="
-  "resolved" "https://registry.npmmirror.com/upper-case-first/download/upper-case-first-2.0.2.tgz?cache=0&sync_timestamp=1606867326586&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fupper-case-first%2Fdownload%2Fupper-case-first-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "tslib" "^2.0.3"
-
-"upper-case@^2.0.2":
-  "integrity" "sha1-2JgQgj+qsd8VSbfZenb4Ziuub3o="
-  "resolved" "https://registry.npmmirror.com/upper-case/download/upper-case-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "tslib" "^2.0.3"
-
-"uri-js@^4.2.2":
-  "integrity" "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34="
-  "resolved" "https://registry.npmmirror.com/uri-js/download/uri-js-4.4.1.tgz?cache=0&sync_timestamp=1610237624359&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Furi-js%2Fdownload%2Furi-js-4.4.1.tgz"
-  "version" "4.4.1"
-  dependencies:
-    "punycode" "^2.1.0"
-
-"urix@^0.1.0":
-  "integrity" "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
-  "resolved" "https://registry.npmmirror.com/urix/download/urix-0.1.0.tgz"
-  "version" "0.1.0"
-
-"use@^3.1.0":
-  "integrity" "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8="
-  "resolved" "https://registry.npmmirror.com/use/download/use-3.1.1.tgz"
-  "version" "3.1.1"
-
-"util-deprecate@^1.0.1", "util-deprecate@~1.0.1":
-  "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-  "resolved" "https://registry.npmmirror.com/util-deprecate/download/util-deprecate-1.0.2.tgz"
-  "version" "1.0.2"
-
-"v8-compile-cache@^2.0.3":
-  "integrity" "sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4="
-  "resolved" "https://registry.npmmirror.com/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz?cache=0&sync_timestamp=1614993994061&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fv8-compile-cache%2Fdownload%2Fv8-compile-cache-2.3.0.tgz"
-  "version" "2.3.0"
-
-"vary@^1":
-  "integrity" "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
-  "resolved" "https://registry.npmmirror.com/vary/download/vary-1.1.2.tgz"
-  "version" "1.1.2"
-
-"vconsole@^3.8.1":
-  "integrity" "sha512-DZ6WrSy+5ep11FWxq89DHv8we83rCCrGZaZqlHEXZ+wCvivFd6kfo8OizIP5iQZ0Ynf8Qxj3UfnilFp4HtTVcA=="
-  "resolved" "https://registry.npmmirror.com/vconsole/download/vconsole-3.11.0.tgz"
-  "version" "3.11.0"
-  dependencies:
-    "cookie-storage" "^6.1.0"
-    "copy-text-to-clipboard" "^3.0.1"
-    "core-js" "^3.11.0"
-    "mutation-observer" "^1.0.3"
-
-"vite-plugin-components@^0.13.3":
-  "integrity" "sha1-i9oPUI7pAkmgZrpj1ZhXmOXKn+0="
-  "resolved" "https://registry.nlark.com/vite-plugin-components/download/vite-plugin-components-0.13.3.tgz"
-  "version" "0.13.3"
-  dependencies:
-    "debug" "^4.3.2"
-    "fast-glob" "^3.2.7"
-    "magic-string" "^0.25.7"
-    "minimatch" "^3.0.4"
-
-"vite-plugin-eslint@^1.3.0":
-  "integrity" "sha1-y8PxVCyl6Q1ZLM+2tJV+m2P5mg4="
-  "resolved" "https://registry.nlark.com/vite-plugin-eslint/download/vite-plugin-eslint-1.3.0.tgz"
-  "version" "1.3.0"
-  dependencies:
-    "@rollup/pluginutils" "^4.1.0"
-    "eslint" "^7.26.0"
-    "rollup" "^2.47.0"
-
-"vite-plugin-importer@^0.2.5":
-  "integrity" "sha1-I2PcDZfU7OxTDuQBcTEKF8LbB34="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-importer/download/vite-plugin-importer-0.2.5.tgz"
-  "version" "0.2.5"
-  dependencies:
-    "@babel/core" "^7.12.17"
-    "@babel/plugin-syntax-import-meta" "^7.10.4"
-    "babel-plugin-import" "^1.13.3"
-
-"vite-plugin-optimize-persist@^0.1.2":
-  "integrity" "sha512-H/Ebn2kZO8PvwUF08SsT5K5xMJNCWKoGX71+e9/ER3yNj7GHiFjNQlvGg5ih/zEx09MZ9m7WCxOwmEKbeIVzww=="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-optimize-persist/download/vite-plugin-optimize-persist-0.1.2.tgz"
-  "version" "0.1.2"
-  dependencies:
-    "debug" "^4.3.2"
-    "fs-extra" "^10.0.0"
-
-"vite-plugin-package-config@^0.1.0", "vite-plugin-package-config@^0.1.1":
-  "integrity" "sha512-w9B3I8ZnqoyhlbzimXjXNk85imrMZgvI9m8f6j3zonK5IVA5KXzpT+PZOHlDz8lqh1vqvoEI1uhy+ZDoLAiA/w=="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-package-config/download/vite-plugin-package-config-0.1.1.tgz"
-  "version" "0.1.1"
-  dependencies:
-    "debug" "^4.3.3"
-
-"vite-plugin-style-import@^1.0.1":
-  "integrity" "sha512-lJCRvm7+So0hHdnSJiJPg9gD5mxtL6YY0jmhEph+k7ArpsyvqOh6han2kG5htbWWDZxHkUN9d1BuTFL//yCLLQ=="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-style-import/download/vite-plugin-style-import-1.4.1.tgz"
-  "version" "1.4.1"
-  dependencies:
-    "@rollup/pluginutils" "^4.1.2"
-    "change-case" "^4.1.2"
-    "debug" "^4.3.3"
-    "es-module-lexer" "^0.9.3"
-    "fs-extra" "^10.0.0"
-    "magic-string" "^0.25.7"
-
-"vite-plugin-svg-icons@^1.0.5":
-  "integrity" "sha512-dmpr7Wq8vQN6ajBrVTrBxy8wJjQfcP30i73q+40uAZc8p7EwphBNZ+bVTI0enFaCrsITI8y0Ruo/mN/SaJQ6Hw=="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-svg-icons/download/vite-plugin-svg-icons-1.1.0.tgz"
-  "version" "1.1.0"
-  dependencies:
-    "@types/svgo" "^2.6.0"
-    "cors" "^2.8.5"
-    "debug" "^4.3.3"
-    "etag" "^1.8.1"
-    "fs-extra" "^10.0.0"
-    "svg-baker" "1.7.0"
-    "svgo" "^2.8.0"
-
-"vite-plugin-vconsole@^1.1.0":
-  "integrity" "sha512-8oODvR4inPCVbfeWkxmV++sP6qypH7DfxBAzCT3Erm7XnoK8aTuRls30wXlXL6LDB6e090vTELOYyreGe7OOLA=="
-  "resolved" "https://registry.npmmirror.com/vite-plugin-vconsole/download/vite-plugin-vconsole-1.1.1.tgz"
-  "version" "1.1.1"
-
-"vite@^2.0.0", "vite@^2.4.0", "vite@^2.5.10", "vite@>=2.0.0":
-  "integrity" "sha512-KEY96ntXUid1/xJihJbgmLZx7QSC2D4Tui0FdS0Old5OokYzFclcofhtxtjDdGOk/fFpPbHv9yw88+rB93Tb8w=="
-  "resolved" "https://registry.npmmirror.com/vite/download/vite-2.7.10.tgz"
-  "version" "2.7.10"
-  dependencies:
-    "esbuild" "^0.13.12"
-    "postcss" "^8.4.5"
-    "resolve" "^1.20.0"
-    "rollup" "^2.59.0"
-  optionalDependencies:
-    "fsevents" "~2.3.2"
-
-"vue-cookies@^1.7.4":
-  "integrity" "sha1-0kHQoEMdoHlYN2UdELTXPnyNPo0="
-  "resolved" "https://registry.nlark.com/vue-cookies/download/vue-cookies-1.7.4.tgz"
-  "version" "1.7.4"
-
-"vue-eslint-parser@^7.10.0":
-  "integrity" "sha1-IUtd6pYQB/z/su5luJEjB2KNDa8="
-  "resolved" "https://registry.npmmirror.com/vue-eslint-parser/download/vue-eslint-parser-7.11.0.tgz"
-  "version" "7.11.0"
-  dependencies:
-    "debug" "^4.1.1"
-    "eslint-scope" "^5.1.1"
-    "eslint-visitor-keys" "^1.1.0"
-    "espree" "^6.2.1"
-    "esquery" "^1.4.0"
-    "lodash" "^4.17.21"
-    "semver" "^6.3.0"
-
-"vue-i18n@^9.1.6":
-  "integrity" "sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA=="
-  "resolved" "https://registry.npmmirror.com/vue-i18n/download/vue-i18n-9.1.9.tgz"
-  "version" "9.1.9"
-  dependencies:
-    "@intlify/core-base" "9.1.9"
-    "@intlify/shared" "9.1.9"
-    "@intlify/vue-devtools" "9.1.9"
-    "@vue/devtools-api" "^6.0.0-beta.7"
-
-"vue-router@4":
-  "integrity" "sha512-CPXvfqe+mZLB1kBWssssTiWg4EQERyqJZes7USiqfW9B5N2x+nHlnsM1D3b5CaJ6qgCvMmYJnz+G0iWjNCvXrg=="
-  "resolved" "https://registry.npmmirror.com/vue-router/download/vue-router-4.0.12.tgz"
-  "version" "4.0.12"
-  dependencies:
-    "@vue/devtools-api" "^6.0.0-beta.18"
-
-"vue-tsc@^0.0.24":
-  "integrity" "sha1-DNkNtnn1PqFpQlS4Zj/bPWJKCHI="
-  "resolved" "https://registry.npmmirror.com/vue-tsc/download/vue-tsc-0.0.24.tgz"
-  "version" "0.0.24"
-  dependencies:
-    "unzipper" "0.10.11"
-
-"vue-types@^3.0.0":
-  "integrity" "sha1-7BbgXUEsA4Ji/B76TOuWR+f7YB0="
-  "resolved" "https://registry.npmmirror.com/vue-types/download/vue-types-3.0.2.tgz"
-  "version" "3.0.2"
-  dependencies:
-    "is-plain-object" "3.0.1"
-
-"vue@^3.0.0", "vue@^3.0.2", "vue@^3.2.26", "vue@>=3.0.3", "vue@>=3.1.0", "vue@3.2.26":
-  "integrity" "sha512-KD4lULmskL5cCsEkfhERVRIOEDrfEL9CwAsLYpzptOGjaGFNWo3BQ9g8MAb7RaIO71rmVOziZ/uEN/rHwcUIhg=="
-  "resolved" "https://registry.npmmirror.com/vue/download/vue-3.2.26.tgz"
-  "version" "3.2.26"
-  dependencies:
-    "@vue/compiler-dom" "3.2.26"
-    "@vue/compiler-sfc" "3.2.26"
-    "@vue/runtime-dom" "3.2.26"
-    "@vue/server-renderer" "3.2.26"
-    "@vue/shared" "3.2.26"
-
-"vuex@^4.0.2":
-  "integrity" "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q=="
-  "resolved" "https://registry.npmmirror.com/vuex/download/vuex-4.0.2.tgz"
-  "version" "4.0.2"
-  dependencies:
-    "@vue/devtools-api" "^6.0.0-beta.11"
-
-"warning@^4.0.0":
-  "integrity" "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM="
-  "resolved" "https://registry.npmmirror.com/warning/download/warning-4.0.3.tgz"
-  "version" "4.0.3"
-  dependencies:
-    "loose-envify" "^1.0.0"
-
-"which-boxed-primitive@^1.0.2":
-  "integrity" "sha1-E3V7yJsgmwSf5dhkMOIc9AqJqOY="
-  "resolved" "https://registry.npmmirror.com/which-boxed-primitive/download/which-boxed-primitive-1.0.2.tgz"
-  "version" "1.0.2"
-  dependencies:
-    "is-bigint" "^1.0.1"
-    "is-boolean-object" "^1.1.0"
-    "is-number-object" "^1.0.4"
-    "is-string" "^1.0.5"
-    "is-symbol" "^1.0.3"
-
-"which@^2.0.1":
-  "integrity" "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE="
-  "resolved" "https://registry.npmmirror.com/which/download/which-2.0.2.tgz"
-  "version" "2.0.2"
-  dependencies:
-    "isexe" "^2.0.0"
-
-"word-wrap@^1.2.3":
-  "integrity" "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w="
-  "resolved" "https://registry.npmmirror.com/word-wrap/download/word-wrap-1.2.3.tgz?cache=0&sync_timestamp=1589683603678&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fword-wrap%2Fdownload%2Fword-wrap-1.2.3.tgz"
-  "version" "1.2.3"
-
-"wrappy@1":
-  "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
-  "resolved" "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz"
-  "version" "1.0.2"
-
-"ws@^7.5.5":
-  "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="
-  "resolved" "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz"
-  "version" "7.5.9"
-
-"xtend@^4.0.2":
-  "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
-  "resolved" "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz"
-  "version" "4.0.2"
-
-"yallist@^4.0.0":
-  "integrity" "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI="
-  "resolved" "https://registry.npmmirror.com/yallist/download/yallist-4.0.0.tgz"
-  "version" "4.0.0"

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