ソースを参照

邹小华提出的若干新需求点

刘洋 2 年 前
コミット
17213377ed
5 ファイル変更1593 行追加4856 行削除
  1. 2 0
      .gitignore
  2. 0 3299
      pnpm-lock.yaml
  3. 345 344
      src/pages/exam-manage/index.vue
  4. 592 564
      src/pages/subjects-manage/index.vue
  5. 654 649
      src/pages/user-manage/index.vue

+ 2 - 0
.gitignore

@@ -22,3 +22,5 @@ dist-ssr
 *.njsproj
 *.sln
 *.sw?
+
+package-lock.json

+ 0 - 3299
pnpm-lock.yaml

@@ -1,3299 +0,0 @@
-lockfileVersion: 5.4
-
-specifiers:
-  '@ant-design/icons-vue': ^6.1.0
-  '@types/crypto-js': ^4.1.1
-  '@types/lodash-es': ^4.17.6
-  '@types/node': ^18.7.6
-  '@vitejs/plugin-vue': ^3.0.3
-  '@vitejs/plugin-vue-jsx': ^2.0.0
-  ant-design-vue: ^3.2.11
-  autoprefixer: ^10.4.8
-  axios: ^0.27.2
-  axios-progress-bar: ^1.2.0
-  crypto-js: ^4.1.1
-  date-fns: ^2.29.1
-  less: ^4.1.3
-  lodash-es: ^4.17.21
-  pinia: ^2.0.18
-  postcss-pxtorem: ^6.0.0
-  qrcode: ^1.5.1
-  tailwindcss: ^3.1.8
-  typescript: ^4.6.4
-  unplugin-vue-components: ^0.22.4
-  unplugin-vue-setup-extend-plus: ^0.3.2
-  vite: ^3.0.7
-  vite-plugin-svg-icons: ^2.0.1
-  vue: ^3.2.37
-  vue-qrcode: ^2.0.0
-  vue-router: ^4.1.3
-  vue-tsc: ^0.39.5
-
-dependencies:
-  '@ant-design/icons-vue': 6.1.0_vue@3.2.37
-  ant-design-vue: 3.2.11_vue@3.2.37
-  axios: 0.27.2
-  axios-progress-bar: 1.2.0_axios@0.27.2
-  crypto-js: 4.1.1
-  date-fns: 2.29.1
-  lodash-es: 4.17.21
-  pinia: 2.0.18_j6bzmzd4ujpabbp5objtwxyjp4
-  qrcode: 1.5.1
-  tailwindcss: 3.1.8
-  vue: 3.2.37
-  vue-qrcode: 2.0.0_qrcode@1.5.1+vue@3.2.37
-  vue-router: 4.1.3_vue@3.2.37
-
-devDependencies:
-  '@types/crypto-js': 4.1.1
-  '@types/lodash-es': 4.17.6
-  '@types/node': 18.7.6
-  '@vitejs/plugin-vue': 3.0.3_vite@3.0.8+vue@3.2.37
-  '@vitejs/plugin-vue-jsx': 2.0.0_vite@3.0.8+vue@3.2.37
-  autoprefixer: 10.4.8
-  less: 4.1.3
-  postcss-pxtorem: 6.0.0
-  typescript: 4.7.4
-  unplugin-vue-components: 0.22.4_vite@3.0.8+vue@3.2.37
-  unplugin-vue-setup-extend-plus: 0.3.2_vite@3.0.8
-  vite: 3.0.8_less@4.1.3
-  vite-plugin-svg-icons: 2.0.1_vite@3.0.8
-  vue-tsc: 0.39.5_typescript@4.7.4
-
-packages:
-
-  /@ampproject/remapping/2.2.0:
-    resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
-    engines: {node: '>=6.0.0'}
-    dependencies:
-      '@jridgewell/gen-mapping': 0.1.1
-      '@jridgewell/trace-mapping': 0.3.15
-    dev: true
-
-  /@ant-design/colors/6.0.0:
-    resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==}
-    dependencies:
-      '@ctrl/tinycolor': 3.4.1
-    dev: false
-
-  /@ant-design/icons-svg/4.2.1:
-    resolution: {integrity: sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==}
-    dev: false
-
-  /@ant-design/icons-vue/6.1.0_vue@3.2.37:
-    resolution: {integrity: sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==}
-    peerDependencies:
-      vue: '>=3.0.3'
-    dependencies:
-      '@ant-design/colors': 6.0.0
-      '@ant-design/icons-svg': 4.2.1
-      vue: 3.2.37
-    dev: false
-
-  /@antfu/utils/0.5.2:
-    resolution: {integrity: sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==}
-    dev: true
-
-  /@babel/code-frame/7.18.6:
-    resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/highlight': 7.18.6
-    dev: true
-
-  /@babel/compat-data/7.18.8:
-    resolution: {integrity: sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==}
-    engines: {node: '>=6.9.0'}
-    dev: true
-
-  /@babel/core/7.18.10:
-    resolution: {integrity: sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@ampproject/remapping': 2.2.0
-      '@babel/code-frame': 7.18.6
-      '@babel/generator': 7.18.12
-      '@babel/helper-compilation-targets': 7.18.9_@babel+core@7.18.10
-      '@babel/helper-module-transforms': 7.18.9
-      '@babel/helpers': 7.18.9
-      '@babel/parser': 7.18.11
-      '@babel/template': 7.18.10
-      '@babel/traverse': 7.18.11
-      '@babel/types': 7.18.10
-      convert-source-map: 1.8.0
-      debug: 4.3.4
-      gensync: 1.0.0-beta.2
-      json5: 2.2.1
-      semver: 6.3.0
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/generator/7.18.12:
-    resolution: {integrity: sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-      '@jridgewell/gen-mapping': 0.3.2
-      jsesc: 2.5.2
-    dev: true
-
-  /@babel/helper-annotate-as-pure/7.18.6:
-    resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-compilation-targets/7.18.9_@babel+core@7.18.10:
-    resolution: {integrity: sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
-    dependencies:
-      '@babel/compat-data': 7.18.8
-      '@babel/core': 7.18.10
-      '@babel/helper-validator-option': 7.18.6
-      browserslist: 4.21.3
-      semver: 6.3.0
-    dev: true
-
-  /@babel/helper-create-class-features-plugin/7.18.9_@babel+core@7.18.10:
-    resolution: {integrity: sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/helper-annotate-as-pure': 7.18.6
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-function-name': 7.18.9
-      '@babel/helper-member-expression-to-functions': 7.18.9
-      '@babel/helper-optimise-call-expression': 7.18.6
-      '@babel/helper-replace-supers': 7.18.9
-      '@babel/helper-split-export-declaration': 7.18.6
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/helper-environment-visitor/7.18.9:
-    resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
-    engines: {node: '>=6.9.0'}
-    dev: true
-
-  /@babel/helper-function-name/7.18.9:
-    resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/template': 7.18.10
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-hoist-variables/7.18.6:
-    resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-member-expression-to-functions/7.18.9:
-    resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-module-imports/7.18.6:
-    resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-module-transforms/7.18.9:
-    resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-module-imports': 7.18.6
-      '@babel/helper-simple-access': 7.18.6
-      '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/helper-validator-identifier': 7.18.6
-      '@babel/template': 7.18.10
-      '@babel/traverse': 7.18.11
-      '@babel/types': 7.18.10
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/helper-optimise-call-expression/7.18.6:
-    resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-plugin-utils/7.18.9:
-    resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==}
-    engines: {node: '>=6.9.0'}
-    dev: true
-
-  /@babel/helper-replace-supers/7.18.9:
-    resolution: {integrity: sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-member-expression-to-functions': 7.18.9
-      '@babel/helper-optimise-call-expression': 7.18.6
-      '@babel/traverse': 7.18.11
-      '@babel/types': 7.18.10
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/helper-simple-access/7.18.6:
-    resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-split-export-declaration/7.18.6:
-    resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/helper-string-parser/7.18.10:
-    resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==}
-    engines: {node: '>=6.9.0'}
-
-  /@babel/helper-validator-identifier/7.18.6:
-    resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==}
-    engines: {node: '>=6.9.0'}
-
-  /@babel/helper-validator-option/7.18.6:
-    resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==}
-    engines: {node: '>=6.9.0'}
-    dev: true
-
-  /@babel/helpers/7.18.9:
-    resolution: {integrity: sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/template': 7.18.10
-      '@babel/traverse': 7.18.11
-      '@babel/types': 7.18.10
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/highlight/7.18.6:
-    resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/helper-validator-identifier': 7.18.6
-      chalk: 2.4.2
-      js-tokens: 4.0.0
-    dev: true
-
-  /@babel/parser/7.18.11:
-    resolution: {integrity: sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
-    dependencies:
-      '@babel/types': 7.18.10
-
-  /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.18.10:
-    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/helper-plugin-utils': 7.18.9
-    dev: true
-
-  /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.18.10:
-    resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/helper-plugin-utils': 7.18.9
-    dev: true
-
-  /@babel/plugin-syntax-typescript/7.18.6_@babel+core@7.18.10:
-    resolution: {integrity: sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/helper-plugin-utils': 7.18.9
-    dev: true
-
-  /@babel/plugin-transform-typescript/7.18.12_@babel+core@7.18.10:
-    resolution: {integrity: sha512-2vjjam0cum0miPkenUbQswKowuxs/NjMwIKEq0zwegRxXk12C9YOF9STXnaUptITOtOJHKHpzvvWYOjbm6tc0w==}
-    engines: {node: '>=6.9.0'}
-    peerDependencies:
-      '@babel/core': ^7.0.0-0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/helper-create-class-features-plugin': 7.18.9_@babel+core@7.18.10
-      '@babel/helper-plugin-utils': 7.18.9
-      '@babel/plugin-syntax-typescript': 7.18.6_@babel+core@7.18.10
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/runtime/7.18.9:
-    resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      regenerator-runtime: 0.13.9
-    dev: false
-
-  /@babel/template/7.18.10:
-    resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/code-frame': 7.18.6
-      '@babel/parser': 7.18.11
-      '@babel/types': 7.18.10
-    dev: true
-
-  /@babel/traverse/7.18.11:
-    resolution: {integrity: sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/code-frame': 7.18.6
-      '@babel/generator': 7.18.12
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-function-name': 7.18.9
-      '@babel/helper-hoist-variables': 7.18.6
-      '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/parser': 7.18.11
-      '@babel/types': 7.18.10
-      debug: 4.3.4
-      globals: 11.12.0
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@babel/types/7.18.10:
-    resolution: {integrity: sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      '@babel/helper-string-parser': 7.18.10
-      '@babel/helper-validator-identifier': 7.18.6
-      to-fast-properties: 2.0.0
-
-  /@ctrl/tinycolor/3.4.1:
-    resolution: {integrity: sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==}
-    engines: {node: '>=10'}
-    dev: false
-
-  /@esbuild/linux-loong64/0.14.54:
-    resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@jridgewell/gen-mapping/0.1.1:
-    resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
-    engines: {node: '>=6.0.0'}
-    dependencies:
-      '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
-    dev: true
-
-  /@jridgewell/gen-mapping/0.3.2:
-    resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
-    engines: {node: '>=6.0.0'}
-    dependencies:
-      '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
-      '@jridgewell/trace-mapping': 0.3.15
-    dev: true
-
-  /@jridgewell/resolve-uri/3.1.0:
-    resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
-    engines: {node: '>=6.0.0'}
-    dev: true
-
-  /@jridgewell/set-array/1.1.2:
-    resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
-    engines: {node: '>=6.0.0'}
-    dev: true
-
-  /@jridgewell/sourcemap-codec/1.4.14:
-    resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
-    dev: true
-
-  /@jridgewell/trace-mapping/0.3.15:
-    resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==}
-    dependencies:
-      '@jridgewell/resolve-uri': 3.1.0
-      '@jridgewell/sourcemap-codec': 1.4.14
-    dev: true
-
-  /@nodelib/fs.scandir/2.1.5:
-    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
-    engines: {node: '>= 8'}
-    dependencies:
-      '@nodelib/fs.stat': 2.0.5
-      run-parallel: 1.2.0
-
-  /@nodelib/fs.stat/2.0.5:
-    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
-    engines: {node: '>= 8'}
-
-  /@nodelib/fs.walk/1.2.8:
-    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
-    engines: {node: '>= 8'}
-    dependencies:
-      '@nodelib/fs.scandir': 2.1.5
-      fastq: 1.13.0
-
-  /@rollup/pluginutils/4.2.1:
-    resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
-    engines: {node: '>= 8.0.0'}
-    dependencies:
-      estree-walker: 2.0.2
-      picomatch: 2.3.1
-    dev: true
-
-  /@simonwep/pickr/1.8.2:
-    resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==}
-    dependencies:
-      core-js: 3.24.1
-      nanopop: 2.1.0
-    dev: false
-
-  /@trysound/sax/0.2.0:
-    resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
-    engines: {node: '>=10.13.0'}
-    dev: true
-
-  /@types/crypto-js/4.1.1:
-    resolution: {integrity: sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==}
-    dev: true
-
-  /@types/lodash-es/4.17.6:
-    resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==}
-    dependencies:
-      '@types/lodash': 4.14.183
-    dev: true
-
-  /@types/lodash/4.14.183:
-    resolution: {integrity: sha512-UXavyuxzXKMqJPEpFPri6Ku5F9af6ZJXUneHhvQJxavrEjuHkFp2YnDWHcxJiG7hk8ZkWqjcyNeW1s/smZv5cw==}
-    dev: true
-
-  /@types/node/18.7.6:
-    resolution: {integrity: sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==}
-    dev: true
-
-  /@types/svgo/2.6.4:
-    resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==}
-    dependencies:
-      '@types/node': 18.7.6
-    dev: true
-
-  /@vitejs/plugin-vue-jsx/2.0.0_vite@3.0.8+vue@3.2.37:
-    resolution: {integrity: sha512-WF9ApZ/ivyyW3volQfu0Td0KNPhcccYEaRNzNY1NxRLVJQLSX0nFqquv3e2g7MF74p1XZK4bGtDL2y5i5O5+1A==}
-    engines: {node: '>=14.18.0'}
-    peerDependencies:
-      vite: ^3.0.0
-      vue: ^3.0.0
-    dependencies:
-      '@babel/core': 7.18.10
-      '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.18.10
-      '@babel/plugin-transform-typescript': 7.18.12_@babel+core@7.18.10
-      '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.18.10
-      vite: 3.0.8_less@4.1.3
-      vue: 3.2.37
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@vitejs/plugin-vue/3.0.3_vite@3.0.8+vue@3.2.37:
-    resolution: {integrity: sha512-U4zNBlz9mg+TA+i+5QPc3N5lQvdUXENZLO2h0Wdzp56gI1MWhqJOv+6R+d4kOzoaSSq6TnGPBdZAXKOe4lXy6g==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    peerDependencies:
-      vite: ^3.0.0
-      vue: ^3.2.25
-    dependencies:
-      vite: 3.0.8_less@4.1.3
-      vue: 3.2.37
-    dev: true
-
-  /@volar/code-gen/0.39.5:
-    resolution: {integrity: sha512-vQr5VoCH8T2NHmqLc/AA1/4F8l41WB+24+I+VjxBaev/Hmwjye9K0GlmMHAOl84WB3hWGOqpHaPX6JkqzRNjJg==}
-    dependencies:
-      '@volar/source-map': 0.39.5
-    dev: true
-
-  /@volar/source-map/0.39.5:
-    resolution: {integrity: sha512-IVOX+v++Sr5Kok4/cLbDJp2vf1ia1rChpV7adgcnMle6uORBuGFEur234UzamK0iHRCcfFFRz7z+hSPf2CO23Q==}
-    dev: true
-
-  /@volar/typescript-faster/0.39.5:
-    resolution: {integrity: sha512-IzLqlxefmKkjNKXC/8aFiqPcTqnj6RG31D2f9cIWxmW9pvUYJxLED+y9phnOxNxq0OmeRtQ3Pfmvu85tUBoZsQ==}
-    dependencies:
-      semver: 7.3.7
-    dev: true
-
-  /@volar/vue-code-gen/0.39.5:
-    resolution: {integrity: sha512-y+QUV9MuuasiIuRoGKQl+gMhDaAX6XNhckAyJCvD1FZ8f2eJuPY2VtoFxmu/Z2bGWBdtUW/g98jaeKJ+j3wwOw==}
-    dependencies:
-      '@volar/code-gen': 0.39.5
-      '@volar/source-map': 0.39.5
-      '@vue/compiler-core': 3.2.37
-      '@vue/compiler-dom': 3.2.37
-      '@vue/shared': 3.2.37
-    dev: true
-
-  /@volar/vue-language-core/0.39.5:
-    resolution: {integrity: sha512-m+e1tYuL/WRPhSeC7hZ0NuSwHsfnnGJVxCBHLaP7jR0f6xcC0DAegP3QF+gfu9ZJFPGznpZYFKadngMjuhQS9Q==}
-    dependencies:
-      '@volar/code-gen': 0.39.5
-      '@volar/source-map': 0.39.5
-      '@volar/vue-code-gen': 0.39.5
-      '@vue/compiler-sfc': 3.2.37
-      '@vue/reactivity': 3.2.37
-    dev: true
-
-  /@volar/vue-typescript/0.39.5:
-    resolution: {integrity: sha512-ckhWD1xOi0OMr702XVkv/Npsb9FKAp5gvhxyLv0QqWekPdSo04t4KrZfwosJLGERIEcyr50SuB7HqBp8ndQmzA==}
-    dependencies:
-      '@volar/code-gen': 0.39.5
-      '@volar/typescript-faster': 0.39.5
-      '@volar/vue-language-core': 0.39.5
-    dev: true
-
-  /@vue/babel-helper-vue-transform-on/1.0.2:
-    resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==}
-    dev: true
-
-  /@vue/babel-plugin-jsx/1.1.1_@babel+core@7.18.10:
-    resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==}
-    dependencies:
-      '@babel/helper-module-imports': 7.18.6
-      '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.10
-      '@babel/template': 7.18.10
-      '@babel/traverse': 7.18.11
-      '@babel/types': 7.18.10
-      '@vue/babel-helper-vue-transform-on': 1.0.2
-      camelcase: 6.3.0
-      html-tags: 3.2.0
-      svg-tags: 1.0.0
-    transitivePeerDependencies:
-      - '@babel/core'
-      - supports-color
-    dev: true
-
-  /@vue/compiler-core/3.2.37:
-    resolution: {integrity: sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==}
-    dependencies:
-      '@babel/parser': 7.18.11
-      '@vue/shared': 3.2.37
-      estree-walker: 2.0.2
-      source-map: 0.6.1
-
-  /@vue/compiler-dom/3.2.37:
-    resolution: {integrity: sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==}
-    dependencies:
-      '@vue/compiler-core': 3.2.37
-      '@vue/shared': 3.2.37
-
-  /@vue/compiler-sfc/3.2.37:
-    resolution: {integrity: sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==}
-    dependencies:
-      '@babel/parser': 7.18.11
-      '@vue/compiler-core': 3.2.37
-      '@vue/compiler-dom': 3.2.37
-      '@vue/compiler-ssr': 3.2.37
-      '@vue/reactivity-transform': 3.2.37
-      '@vue/shared': 3.2.37
-      estree-walker: 2.0.2
-      magic-string: 0.25.9
-      postcss: 8.4.16
-      source-map: 0.6.1
-
-  /@vue/compiler-ssr/3.2.37:
-    resolution: {integrity: sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==}
-    dependencies:
-      '@vue/compiler-dom': 3.2.37
-      '@vue/shared': 3.2.37
-
-  /@vue/devtools-api/6.2.1:
-    resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==}
-    dev: false
-
-  /@vue/reactivity-transform/3.2.37:
-    resolution: {integrity: sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==}
-    dependencies:
-      '@babel/parser': 7.18.11
-      '@vue/compiler-core': 3.2.37
-      '@vue/shared': 3.2.37
-      estree-walker: 2.0.2
-      magic-string: 0.25.9
-
-  /@vue/reactivity/3.2.37:
-    resolution: {integrity: sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==}
-    dependencies:
-      '@vue/shared': 3.2.37
-
-  /@vue/runtime-core/3.2.37:
-    resolution: {integrity: sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==}
-    dependencies:
-      '@vue/reactivity': 3.2.37
-      '@vue/shared': 3.2.37
-
-  /@vue/runtime-dom/3.2.37:
-    resolution: {integrity: sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==}
-    dependencies:
-      '@vue/runtime-core': 3.2.37
-      '@vue/shared': 3.2.37
-      csstype: 2.6.20
-
-  /@vue/server-renderer/3.2.37_vue@3.2.37:
-    resolution: {integrity: sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==}
-    peerDependencies:
-      vue: 3.2.37
-    dependencies:
-      '@vue/compiler-ssr': 3.2.37
-      '@vue/shared': 3.2.37
-      vue: 3.2.37
-
-  /@vue/shared/3.2.37:
-    resolution: {integrity: sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==}
-
-  /acorn-node/1.8.2:
-    resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==}
-    dependencies:
-      acorn: 7.4.1
-      acorn-walk: 7.2.0
-      xtend: 4.0.2
-    dev: false
-
-  /acorn-walk/7.2.0:
-    resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
-    engines: {node: '>=0.4.0'}
-    dev: false
-
-  /acorn/7.4.1:
-    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
-    dev: false
-
-  /acorn/8.8.0:
-    resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==}
-    engines: {node: '>=0.4.0'}
-    hasBin: true
-    dev: true
-
-  /ansi-regex/2.1.1:
-    resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /ansi-regex/5.0.1:
-    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
-    engines: {node: '>=8'}
-    dev: false
-
-  /ansi-styles/2.2.1:
-    resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /ansi-styles/3.2.1:
-    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
-    engines: {node: '>=4'}
-    dependencies:
-      color-convert: 1.9.3
-    dev: true
-
-  /ansi-styles/4.3.0:
-    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
-    engines: {node: '>=8'}
-    dependencies:
-      color-convert: 2.0.1
-    dev: false
-
-  /ant-design-vue/3.2.11_vue@3.2.37:
-    resolution: {integrity: sha512-QKCAcOY5EJF0PepiVGA4X5PzUetYUvG5qALmA+2TON40pc2+brOEiVTwr3kjF9N+f7q4MpyiLPu4pIErwoajOQ==}
-    engines: {node: '>=12.22.0'}
-    peerDependencies:
-      vue: '>=3.2.0'
-    dependencies:
-      '@ant-design/colors': 6.0.0
-      '@ant-design/icons-vue': 6.1.0_vue@3.2.37
-      '@babel/runtime': 7.18.9
-      '@ctrl/tinycolor': 3.4.1
-      '@simonwep/pickr': 1.8.2
-      array-tree-filter: 2.1.0
-      async-validator: 4.2.5
-      dayjs: 1.11.5
-      dom-align: 1.12.3
-      dom-scroll-into-view: 2.0.1
-      lodash: 4.17.21
-      lodash-es: 4.17.21
-      resize-observer-polyfill: 1.5.1
-      scroll-into-view-if-needed: 2.2.29
-      shallow-equal: 1.2.1
-      vue: 3.2.37
-      vue-types: 3.0.2_vue@3.2.37
-      warning: 4.0.3
-    dev: false
-
-  /anymatch/3.1.2:
-    resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
-    engines: {node: '>= 8'}
-    dependencies:
-      normalize-path: 3.0.0
-      picomatch: 2.3.1
-
-  /arg/5.0.2:
-    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
-    dev: false
-
-  /arr-diff/4.0.0:
-    resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /arr-flatten/1.1.0:
-    resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /arr-union/3.1.0:
-    resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /array-tree-filter/2.1.0:
-    resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==}
-    dev: false
-
-  /array-unique/0.3.2:
-    resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /assign-symbols/1.0.0:
-    resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /async-validator/4.2.5:
-    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
-    dev: false
-
-  /asynckit/0.4.0:
-    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
-    dev: false
-
-  /atob/2.1.2:
-    resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
-    engines: {node: '>= 4.5.0'}
-    hasBin: true
-    dev: true
-
-  /autoprefixer/10.4.8:
-    resolution: {integrity: sha512-75Jr6Q/XpTqEf6D2ltS5uMewJIx5irCU1oBYJrWjFenq/m12WRRrz6g15L1EIoYvPLXTbEry7rDOwrcYNj77xw==}
-    engines: {node: ^10 || ^12 || >=14}
-    hasBin: true
-    peerDependencies:
-      postcss: ^8.1.0
-    dependencies:
-      browserslist: 4.21.3
-      caniuse-lite: 1.0.30001377
-      fraction.js: 4.2.0
-      normalize-range: 0.1.2
-      picocolors: 1.0.0
-      postcss-value-parser: 4.2.0
-    dev: true
-
-  /axios-progress-bar/1.2.0_axios@0.27.2:
-    resolution: {integrity: sha512-PEgWb/b2SMyHnKJ/cxA46OdCuNeVlo8eqL0HxXPtz+6G/Jtpyo49icPbW+jpO1wUeDEjbqpseMoCyWxESxf5pA==}
-    peerDependencies:
-      axios: 0.x
-    dependencies:
-      axios: 0.27.2
-    dev: false
-
-  /axios/0.27.2:
-    resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
-    dependencies:
-      follow-redirects: 1.15.1
-      form-data: 4.0.0
-    transitivePeerDependencies:
-      - debug
-    dev: false
-
-  /balanced-match/1.0.2:
-    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
-    dev: true
-
-  /base/0.11.2:
-    resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      cache-base: 1.0.1
-      class-utils: 0.3.6
-      component-emitter: 1.3.0
-      define-property: 1.0.0
-      isobject: 3.0.1
-      mixin-deep: 1.3.2
-      pascalcase: 0.1.1
-    dev: true
-
-  /big.js/5.2.2:
-    resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
-    dev: true
-
-  /binary-extensions/2.2.0:
-    resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
-    engines: {node: '>=8'}
-
-  /bluebird/3.7.2:
-    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
-    dev: true
-
-  /boolbase/1.0.0:
-    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
-    dev: true
-
-  /brace-expansion/2.0.1:
-    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
-    dependencies:
-      balanced-match: 1.0.2
-    dev: true
-
-  /braces/2.3.2:
-    resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      arr-flatten: 1.1.0
-      array-unique: 0.3.2
-      extend-shallow: 2.0.1
-      fill-range: 4.0.0
-      isobject: 3.0.1
-      repeat-element: 1.1.4
-      snapdragon: 0.8.2
-      snapdragon-node: 2.1.1
-      split-string: 3.1.0
-      to-regex: 3.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /braces/3.0.2:
-    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
-    engines: {node: '>=8'}
-    dependencies:
-      fill-range: 7.0.1
-
-  /browserslist/4.21.3:
-    resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==}
-    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
-    hasBin: true
-    dependencies:
-      caniuse-lite: 1.0.30001377
-      electron-to-chromium: 1.4.222
-      node-releases: 2.0.6
-      update-browserslist-db: 1.0.5_browserslist@4.21.3
-    dev: true
-
-  /cache-base/1.0.1:
-    resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      collection-visit: 1.0.0
-      component-emitter: 1.3.0
-      get-value: 2.0.6
-      has-value: 1.0.0
-      isobject: 3.0.1
-      set-value: 2.0.1
-      to-object-path: 0.3.0
-      union-value: 1.0.1
-      unset-value: 1.0.0
-    dev: true
-
-  /camelcase-css/2.0.1:
-    resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
-    engines: {node: '>= 6'}
-    dev: false
-
-  /camelcase/5.3.1:
-    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
-    engines: {node: '>=6'}
-    dev: false
-
-  /camelcase/6.3.0:
-    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
-    engines: {node: '>=10'}
-    dev: true
-
-  /caniuse-lite/1.0.30001377:
-    resolution: {integrity: sha512-I5XeHI1x/mRSGl96LFOaSk528LA/yZG3m3iQgImGujjO8gotd/DL8QaI1R1h1dg5ATeI2jqPblMpKq4Tr5iKfQ==}
-    dev: true
-
-  /chalk/1.1.3:
-    resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      ansi-styles: 2.2.1
-      escape-string-regexp: 1.0.5
-      has-ansi: 2.0.0
-      strip-ansi: 3.0.1
-      supports-color: 2.0.0
-    dev: true
-
-  /chalk/2.4.2:
-    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
-    engines: {node: '>=4'}
-    dependencies:
-      ansi-styles: 3.2.1
-      escape-string-regexp: 1.0.5
-      supports-color: 5.5.0
-    dev: true
-
-  /chokidar/3.5.3:
-    resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
-    engines: {node: '>= 8.10.0'}
-    dependencies:
-      anymatch: 3.1.2
-      braces: 3.0.2
-      glob-parent: 5.1.2
-      is-binary-path: 2.1.0
-      is-glob: 4.0.3
-      normalize-path: 3.0.0
-      readdirp: 3.6.0
-    optionalDependencies:
-      fsevents: 2.3.2
-
-  /class-utils/0.3.6:
-    resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      arr-union: 3.1.0
-      define-property: 0.2.5
-      isobject: 3.0.1
-      static-extend: 0.1.2
-    dev: true
-
-  /cliui/6.0.0:
-    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
-    dependencies:
-      string-width: 4.2.3
-      strip-ansi: 6.0.1
-      wrap-ansi: 6.2.0
-    dev: false
-
-  /clone/2.1.2:
-    resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
-    engines: {node: '>=0.8'}
-    dev: true
-
-  /collection-visit/1.0.0:
-    resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      map-visit: 1.0.0
-      object-visit: 1.0.1
-    dev: true
-
-  /color-convert/1.9.3:
-    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
-    dependencies:
-      color-name: 1.1.3
-    dev: true
-
-  /color-convert/2.0.1:
-    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
-    engines: {node: '>=7.0.0'}
-    dependencies:
-      color-name: 1.1.4
-    dev: false
-
-  /color-name/1.1.3:
-    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
-    dev: true
-
-  /color-name/1.1.4:
-    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-    dev: false
-
-  /combined-stream/1.0.8:
-    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
-    engines: {node: '>= 0.8'}
-    dependencies:
-      delayed-stream: 1.0.0
-    dev: false
-
-  /commander/7.2.0:
-    resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
-    engines: {node: '>= 10'}
-    dev: true
-
-  /component-emitter/1.3.0:
-    resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
-    dev: true
-
-  /compute-scroll-into-view/1.0.17:
-    resolution: {integrity: sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==}
-    dev: false
-
-  /convert-source-map/1.8.0:
-    resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==}
-    dependencies:
-      safe-buffer: 5.1.2
-    dev: true
-
-  /copy-anything/2.0.6:
-    resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
-    dependencies:
-      is-what: 3.14.1
-    dev: true
-
-  /copy-descriptor/0.1.1:
-    resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /core-js/3.24.1:
-    resolution: {integrity: sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==}
-    requiresBuild: true
-    dev: false
-
-  /cors/2.8.5:
-    resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
-    engines: {node: '>= 0.10'}
-    dependencies:
-      object-assign: 4.1.1
-      vary: 1.1.2
-    dev: true
-
-  /crypto-js/4.1.1:
-    resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==}
-    dev: false
-
-  /css-select/4.3.0:
-    resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
-    dependencies:
-      boolbase: 1.0.0
-      css-what: 6.1.0
-      domhandler: 4.3.1
-      domutils: 2.8.0
-      nth-check: 2.1.1
-    dev: true
-
-  /css-tree/1.1.3:
-    resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
-    engines: {node: '>=8.0.0'}
-    dependencies:
-      mdn-data: 2.0.14
-      source-map: 0.6.1
-    dev: true
-
-  /css-what/6.1.0:
-    resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
-    engines: {node: '>= 6'}
-    dev: true
-
-  /cssesc/3.0.0:
-    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
-    engines: {node: '>=4'}
-    hasBin: true
-    dev: false
-
-  /csso/4.2.0:
-    resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==}
-    engines: {node: '>=8.0.0'}
-    dependencies:
-      css-tree: 1.1.3
-    dev: true
-
-  /csstype/2.6.20:
-    resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==}
-
-  /date-fns/2.29.1:
-    resolution: {integrity: sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==}
-    engines: {node: '>=0.11'}
-    dev: false
-
-  /dayjs/1.11.5:
-    resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==}
-    dev: false
-
-  /debug/2.6.9:
-    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
-    dependencies:
-      ms: 2.0.0
-    dev: true
-
-  /debug/3.2.7:
-    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
-    dependencies:
-      ms: 2.1.3
-    dev: true
-    optional: true
-
-  /debug/4.3.4:
-    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
-    engines: {node: '>=6.0'}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
-    dependencies:
-      ms: 2.1.2
-    dev: true
-
-  /decamelize/1.2.0:
-    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
-    engines: {node: '>=0.10.0'}
-    dev: false
-
-  /decode-uri-component/0.2.0:
-    resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==}
-    engines: {node: '>=0.10'}
-    dev: true
-
-  /define-property/0.2.5:
-    resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-descriptor: 0.1.6
-    dev: true
-
-  /define-property/1.0.0:
-    resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-descriptor: 1.0.2
-    dev: true
-
-  /define-property/2.0.2:
-    resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-descriptor: 1.0.2
-      isobject: 3.0.1
-    dev: true
-
-  /defined/1.0.0:
-    resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==}
-    dev: false
-
-  /delayed-stream/1.0.0:
-    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
-    engines: {node: '>=0.4.0'}
-    dev: false
-
-  /detective/5.2.1:
-    resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==}
-    engines: {node: '>=0.8.0'}
-    hasBin: true
-    dependencies:
-      acorn-node: 1.8.2
-      defined: 1.0.0
-      minimist: 1.2.6
-    dev: false
-
-  /didyoumean/1.2.2:
-    resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
-    dev: false
-
-  /dijkstrajs/1.0.2:
-    resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==}
-    dev: false
-
-  /dlv/1.1.3:
-    resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
-    dev: false
-
-  /dom-align/1.12.3:
-    resolution: {integrity: sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==}
-    dev: false
-
-  /dom-scroll-into-view/2.0.1:
-    resolution: {integrity: sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==}
-    dev: false
-
-  /dom-serializer/0.2.2:
-    resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
-    dependencies:
-      domelementtype: 2.3.0
-      entities: 2.2.0
-    dev: true
-
-  /dom-serializer/1.4.1:
-    resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
-    dependencies:
-      domelementtype: 2.3.0
-      domhandler: 4.3.1
-      entities: 2.2.0
-    dev: true
-
-  /domelementtype/1.3.1:
-    resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
-    dev: true
-
-  /domelementtype/2.3.0:
-    resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
-    dev: true
-
-  /domhandler/2.4.2:
-    resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==}
-    dependencies:
-      domelementtype: 1.3.1
-    dev: true
-
-  /domhandler/4.3.1:
-    resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
-    engines: {node: '>= 4'}
-    dependencies:
-      domelementtype: 2.3.0
-    dev: true
-
-  /domutils/1.7.0:
-    resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
-    dependencies:
-      dom-serializer: 0.2.2
-      domelementtype: 1.3.1
-    dev: true
-
-  /domutils/2.8.0:
-    resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
-    dependencies:
-      dom-serializer: 1.4.1
-      domelementtype: 2.3.0
-      domhandler: 4.3.1
-    dev: true
-
-  /electron-to-chromium/1.4.222:
-    resolution: {integrity: sha512-gEM2awN5HZknWdLbngk4uQCVfhucFAfFzuchP3wM3NN6eow1eDU0dFy2kts43FB20ZfhVFF0jmFSTb1h5OhyIg==}
-    dev: true
-
-  /emoji-regex/8.0.0:
-    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
-    dev: false
-
-  /emojis-list/3.0.0:
-    resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
-    engines: {node: '>= 4'}
-    dev: true
-
-  /encode-utf8/1.0.3:
-    resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
-    dev: false
-
-  /entities/1.1.2:
-    resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
-    dev: true
-
-  /entities/2.2.0:
-    resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
-    dev: true
-
-  /errno/0.1.8:
-    resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
-    hasBin: true
-    requiresBuild: true
-    dependencies:
-      prr: 1.0.1
-    dev: true
-    optional: true
-
-  /esbuild-android-64/0.14.54:
-    resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-android-arm64/0.14.54:
-    resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-darwin-64/0.14.54:
-    resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-darwin-arm64/0.14.54:
-    resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-freebsd-64/0.14.54:
-    resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-freebsd-arm64/0.14.54:
-    resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-32/0.14.54:
-    resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-64/0.14.54:
-    resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-arm/0.14.54:
-    resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-arm64/0.14.54:
-    resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-mips64le/0.14.54:
-    resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-ppc64le/0.14.54:
-    resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-riscv64/0.14.54:
-    resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-linux-s390x/0.14.54:
-    resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-netbsd-64/0.14.54:
-    resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-openbsd-64/0.14.54:
-    resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-sunos-64/0.14.54:
-    resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-windows-32/0.14.54:
-    resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-windows-64/0.14.54:
-    resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild-windows-arm64/0.14.54:
-    resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /esbuild/0.14.54:
-    resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/linux-loong64': 0.14.54
-      esbuild-android-64: 0.14.54
-      esbuild-android-arm64: 0.14.54
-      esbuild-darwin-64: 0.14.54
-      esbuild-darwin-arm64: 0.14.54
-      esbuild-freebsd-64: 0.14.54
-      esbuild-freebsd-arm64: 0.14.54
-      esbuild-linux-32: 0.14.54
-      esbuild-linux-64: 0.14.54
-      esbuild-linux-arm: 0.14.54
-      esbuild-linux-arm64: 0.14.54
-      esbuild-linux-mips64le: 0.14.54
-      esbuild-linux-ppc64le: 0.14.54
-      esbuild-linux-riscv64: 0.14.54
-      esbuild-linux-s390x: 0.14.54
-      esbuild-netbsd-64: 0.14.54
-      esbuild-openbsd-64: 0.14.54
-      esbuild-sunos-64: 0.14.54
-      esbuild-windows-32: 0.14.54
-      esbuild-windows-64: 0.14.54
-      esbuild-windows-arm64: 0.14.54
-    dev: true
-
-  /escalade/3.1.1:
-    resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
-    engines: {node: '>=6'}
-    dev: true
-
-  /escape-string-regexp/1.0.5:
-    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
-    engines: {node: '>=0.8.0'}
-    dev: true
-
-  /estree-walker/2.0.2:
-    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
-
-  /etag/1.8.1:
-    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
-    engines: {node: '>= 0.6'}
-    dev: true
-
-  /expand-brackets/2.1.4:
-    resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      debug: 2.6.9
-      define-property: 0.2.5
-      extend-shallow: 2.0.1
-      posix-character-classes: 0.1.1
-      regex-not: 1.0.2
-      snapdragon: 0.8.2
-      to-regex: 3.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /extend-shallow/2.0.1:
-    resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-extendable: 0.1.1
-    dev: true
-
-  /extend-shallow/3.0.2:
-    resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      assign-symbols: 1.0.0
-      is-extendable: 1.0.1
-    dev: true
-
-  /extglob/2.0.4:
-    resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      array-unique: 0.3.2
-      define-property: 1.0.0
-      expand-brackets: 2.1.4
-      extend-shallow: 2.0.1
-      fragment-cache: 0.2.1
-      regex-not: 1.0.2
-      snapdragon: 0.8.2
-      to-regex: 3.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /fast-glob/3.2.11:
-    resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
-    engines: {node: '>=8.6.0'}
-    dependencies:
-      '@nodelib/fs.stat': 2.0.5
-      '@nodelib/fs.walk': 1.2.8
-      glob-parent: 5.1.2
-      merge2: 1.4.1
-      micromatch: 4.0.5
-
-  /fastq/1.13.0:
-    resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
-    dependencies:
-      reusify: 1.0.4
-
-  /fill-range/4.0.0:
-    resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      extend-shallow: 2.0.1
-      is-number: 3.0.0
-      repeat-string: 1.6.1
-      to-regex-range: 2.1.1
-    dev: true
-
-  /fill-range/7.0.1:
-    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
-    engines: {node: '>=8'}
-    dependencies:
-      to-regex-range: 5.0.1
-
-  /find-up/4.1.0:
-    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
-    engines: {node: '>=8'}
-    dependencies:
-      locate-path: 5.0.0
-      path-exists: 4.0.0
-    dev: false
-
-  /follow-redirects/1.15.1:
-    resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
-    engines: {node: '>=4.0'}
-    peerDependencies:
-      debug: '*'
-    peerDependenciesMeta:
-      debug:
-        optional: true
-    dev: false
-
-  /for-in/1.0.2:
-    resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /form-data/4.0.0:
-    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
-    engines: {node: '>= 6'}
-    dependencies:
-      asynckit: 0.4.0
-      combined-stream: 1.0.8
-      mime-types: 2.1.35
-    dev: false
-
-  /fraction.js/4.2.0:
-    resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
-    dev: true
-
-  /fragment-cache/0.2.1:
-    resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      map-cache: 0.2.2
-    dev: true
-
-  /fs-extra/10.1.0:
-    resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
-    engines: {node: '>=12'}
-    dependencies:
-      graceful-fs: 4.2.10
-      jsonfile: 6.1.0
-      universalify: 2.0.0
-    dev: true
-
-  /fsevents/2.3.2:
-    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
-    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
-    os: [darwin]
-    requiresBuild: true
-    optional: true
-
-  /function-bind/1.1.1:
-    resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
-
-  /gensync/1.0.0-beta.2:
-    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
-    engines: {node: '>=6.9.0'}
-    dev: true
-
-  /get-caller-file/2.0.5:
-    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
-    engines: {node: 6.* || 8.* || >= 10.*}
-    dev: false
-
-  /get-value/2.0.6:
-    resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /glob-parent/5.1.2:
-    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
-    engines: {node: '>= 6'}
-    dependencies:
-      is-glob: 4.0.3
-
-  /glob-parent/6.0.2:
-    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
-    engines: {node: '>=10.13.0'}
-    dependencies:
-      is-glob: 4.0.3
-    dev: false
-
-  /globals/11.12.0:
-    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
-    engines: {node: '>=4'}
-    dev: true
-
-  /graceful-fs/4.2.10:
-    resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
-    requiresBuild: true
-    dev: true
-
-  /has-ansi/2.0.0:
-    resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      ansi-regex: 2.1.1
-    dev: true
-
-  /has-flag/1.0.0:
-    resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /has-flag/3.0.0:
-    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
-    engines: {node: '>=4'}
-    dev: true
-
-  /has-value/0.3.1:
-    resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      get-value: 2.0.6
-      has-values: 0.1.4
-      isobject: 2.1.0
-    dev: true
-
-  /has-value/1.0.0:
-    resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      get-value: 2.0.6
-      has-values: 1.0.0
-      isobject: 3.0.1
-    dev: true
-
-  /has-values/0.1.4:
-    resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /has-values/1.0.0:
-    resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-number: 3.0.0
-      kind-of: 4.0.0
-    dev: true
-
-  /has/1.0.3:
-    resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
-    engines: {node: '>= 0.4.0'}
-    dependencies:
-      function-bind: 1.1.1
-
-  /he/1.2.0:
-    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
-    hasBin: true
-    dev: true
-
-  /html-tags/3.2.0:
-    resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==}
-    engines: {node: '>=8'}
-    dev: true
-
-  /htmlparser2/3.10.1:
-    resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
-    dependencies:
-      domelementtype: 1.3.1
-      domhandler: 2.4.2
-      domutils: 1.7.0
-      entities: 1.1.2
-      inherits: 2.0.4
-      readable-stream: 3.6.0
-    dev: true
-
-  /iconv-lite/0.6.3:
-    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      safer-buffer: 2.1.2
-    dev: true
-    optional: true
-
-  /image-size/0.5.5:
-    resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
-    engines: {node: '>=0.10.0'}
-    hasBin: true
-    requiresBuild: true
-    dev: true
-
-  /inherits/2.0.4:
-    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-    dev: true
-
-  /is-accessor-descriptor/0.1.6:
-    resolution: {integrity: sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 3.2.2
-    dev: true
-
-  /is-accessor-descriptor/1.0.0:
-    resolution: {integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 6.0.3
-    dev: true
-
-  /is-binary-path/2.1.0:
-    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
-    engines: {node: '>=8'}
-    dependencies:
-      binary-extensions: 2.2.0
-
-  /is-buffer/1.1.6:
-    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
-    dev: true
-
-  /is-core-module/2.10.0:
-    resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
-    dependencies:
-      has: 1.0.3
-
-  /is-data-descriptor/0.1.4:
-    resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 3.2.2
-    dev: true
-
-  /is-data-descriptor/1.0.0:
-    resolution: {integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 6.0.3
-    dev: true
-
-  /is-descriptor/0.1.6:
-    resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-accessor-descriptor: 0.1.6
-      is-data-descriptor: 0.1.4
-      kind-of: 5.1.0
-    dev: true
-
-  /is-descriptor/1.0.2:
-    resolution: {integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-accessor-descriptor: 1.0.0
-      is-data-descriptor: 1.0.0
-      kind-of: 6.0.3
-    dev: true
-
-  /is-extendable/0.1.1:
-    resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /is-extendable/1.0.1:
-    resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-plain-object: 2.0.4
-    dev: true
-
-  /is-extglob/2.1.1:
-    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
-    engines: {node: '>=0.10.0'}
-
-  /is-fullwidth-code-point/3.0.0:
-    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
-    engines: {node: '>=8'}
-    dev: false
-
-  /is-glob/4.0.3:
-    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-extglob: 2.1.1
-
-  /is-number/3.0.0:
-    resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 3.2.2
-    dev: true
-
-  /is-number/7.0.0:
-    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
-    engines: {node: '>=0.12.0'}
-
-  /is-plain-obj/1.1.0:
-    resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /is-plain-object/2.0.4:
-    resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      isobject: 3.0.1
-    dev: true
-
-  /is-plain-object/3.0.1:
-    resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==}
-    engines: {node: '>=0.10.0'}
-    dev: false
-
-  /is-what/3.14.1:
-    resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
-    dev: true
-
-  /is-windows/1.0.2:
-    resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /isarray/1.0.0:
-    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
-    dev: true
-
-  /isobject/2.1.0:
-    resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      isarray: 1.0.0
-    dev: true
-
-  /isobject/3.0.1:
-    resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /js-base64/2.6.4:
-    resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
-    dev: true
-
-  /js-tokens/4.0.0:
-    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
-  /jsesc/2.5.2:
-    resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
-    engines: {node: '>=4'}
-    hasBin: true
-    dev: true
-
-  /json5/1.0.1:
-    resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
-    hasBin: true
-    dependencies:
-      minimist: 1.2.6
-    dev: true
-
-  /json5/2.2.1:
-    resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
-    engines: {node: '>=6'}
-    hasBin: true
-    dev: true
-
-  /jsonfile/6.1.0:
-    resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
-    dependencies:
-      universalify: 2.0.0
-    optionalDependencies:
-      graceful-fs: 4.2.10
-    dev: true
-
-  /kind-of/3.2.2:
-    resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-buffer: 1.1.6
-    dev: true
-
-  /kind-of/4.0.0:
-    resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-buffer: 1.1.6
-    dev: true
-
-  /kind-of/5.1.0:
-    resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /kind-of/6.0.3:
-    resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /less/4.1.3:
-    resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==}
-    engines: {node: '>=6'}
-    hasBin: true
-    dependencies:
-      copy-anything: 2.0.6
-      parse-node-version: 1.0.1
-      tslib: 2.4.0
-    optionalDependencies:
-      errno: 0.1.8
-      graceful-fs: 4.2.10
-      image-size: 0.5.5
-      make-dir: 2.1.0
-      mime: 1.6.0
-      needle: 3.1.0
-      source-map: 0.6.1
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /lilconfig/2.0.6:
-    resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==}
-    engines: {node: '>=10'}
-    dev: false
-
-  /loader-utils/1.4.0:
-    resolution: {integrity: sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==}
-    engines: {node: '>=4.0.0'}
-    dependencies:
-      big.js: 5.2.2
-      emojis-list: 3.0.0
-      json5: 1.0.1
-    dev: true
-
-  /local-pkg/0.4.2:
-    resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==}
-    engines: {node: '>=14'}
-    dev: true
-
-  /locate-path/5.0.0:
-    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
-    engines: {node: '>=8'}
-    dependencies:
-      p-locate: 4.1.0
-    dev: false
-
-  /lodash-es/4.17.21:
-    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
-    dev: false
-
-  /lodash/4.17.21:
-    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
-    dev: false
-
-  /loose-envify/1.4.0:
-    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
-    hasBin: true
-    dependencies:
-      js-tokens: 4.0.0
-    dev: false
-
-  /lru-cache/6.0.0:
-    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
-    engines: {node: '>=10'}
-    dependencies:
-      yallist: 4.0.0
-    dev: true
-
-  /magic-string/0.25.9:
-    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
-    dependencies:
-      sourcemap-codec: 1.4.8
-
-  /magic-string/0.26.2:
-    resolution: {integrity: sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==}
-    engines: {node: '>=12'}
-    dependencies:
-      sourcemap-codec: 1.4.8
-    dev: true
-
-  /make-dir/2.1.0:
-    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
-    engines: {node: '>=6'}
-    requiresBuild: true
-    dependencies:
-      pify: 4.0.1
-      semver: 5.7.1
-    dev: true
-    optional: true
-
-  /map-cache/0.2.2:
-    resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /map-visit/1.0.0:
-    resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      object-visit: 1.0.1
-    dev: true
-
-  /mdn-data/2.0.14:
-    resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
-    dev: true
-
-  /merge-options/1.0.1:
-    resolution: {integrity: sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==}
-    engines: {node: '>=4'}
-    dependencies:
-      is-plain-obj: 1.1.0
-    dev: true
-
-  /merge2/1.4.1:
-    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
-    engines: {node: '>= 8'}
-
-  /micromatch/3.1.0:
-    resolution: {integrity: sha512-3StSelAE+hnRvMs8IdVW7Uhk8CVed5tp+kLLGlBP6WiRAXS21GPGu/Nat4WNPXj2Eoc24B02SaeoyozPMfj0/g==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      arr-diff: 4.0.0
-      array-unique: 0.3.2
-      braces: 2.3.2
-      define-property: 1.0.0
-      extend-shallow: 2.0.1
-      extglob: 2.0.4
-      fragment-cache: 0.2.1
-      kind-of: 5.1.0
-      nanomatch: 1.2.13
-      object.pick: 1.3.0
-      regex-not: 1.0.2
-      snapdragon: 0.8.2
-      to-regex: 3.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /micromatch/4.0.5:
-    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
-    engines: {node: '>=8.6'}
-    dependencies:
-      braces: 3.0.2
-      picomatch: 2.3.1
-
-  /mime-db/1.52.0:
-    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
-    engines: {node: '>= 0.6'}
-    dev: false
-
-  /mime-types/2.1.35:
-    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
-    engines: {node: '>= 0.6'}
-    dependencies:
-      mime-db: 1.52.0
-    dev: false
-
-  /mime/1.6.0:
-    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
-    engines: {node: '>=4'}
-    hasBin: true
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /minimatch/5.1.0:
-    resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==}
-    engines: {node: '>=10'}
-    dependencies:
-      brace-expansion: 2.0.1
-    dev: true
-
-  /minimist/1.2.6:
-    resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
-
-  /mixin-deep/1.3.2:
-    resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      for-in: 1.0.2
-      is-extendable: 1.0.1
-    dev: true
-
-  /ms/2.0.0:
-    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
-    dev: true
-
-  /ms/2.1.2:
-    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
-    dev: true
-
-  /ms/2.1.3:
-    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-    dev: true
-    optional: true
-
-  /nanoid/3.3.4:
-    resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
-
-  /nanomatch/1.2.13:
-    resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      arr-diff: 4.0.0
-      array-unique: 0.3.2
-      define-property: 2.0.2
-      extend-shallow: 3.0.2
-      fragment-cache: 0.2.1
-      is-windows: 1.0.2
-      kind-of: 6.0.3
-      object.pick: 1.3.0
-      regex-not: 1.0.2
-      snapdragon: 0.8.2
-      to-regex: 3.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /nanopop/2.1.0:
-    resolution: {integrity: sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw==}
-    dev: false
-
-  /needle/3.1.0:
-    resolution: {integrity: sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==}
-    engines: {node: '>= 4.4.x'}
-    hasBin: true
-    requiresBuild: true
-    dependencies:
-      debug: 3.2.7
-      iconv-lite: 0.6.3
-      sax: 1.2.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-    optional: true
-
-  /node-releases/2.0.6:
-    resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==}
-    dev: true
-
-  /normalize-path/3.0.0:
-    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
-    engines: {node: '>=0.10.0'}
-
-  /normalize-range/0.1.2:
-    resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /nth-check/2.1.1:
-    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
-    dependencies:
-      boolbase: 1.0.0
-    dev: true
-
-  /object-assign/4.1.1:
-    resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /object-copy/0.1.0:
-    resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      copy-descriptor: 0.1.1
-      define-property: 0.2.5
-      kind-of: 3.2.2
-    dev: true
-
-  /object-hash/3.0.0:
-    resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
-    engines: {node: '>= 6'}
-    dev: false
-
-  /object-visit/1.0.1:
-    resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      isobject: 3.0.1
-    dev: true
-
-  /object.pick/1.3.0:
-    resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      isobject: 3.0.1
-    dev: true
-
-  /p-limit/2.3.0:
-    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
-    engines: {node: '>=6'}
-    dependencies:
-      p-try: 2.2.0
-    dev: false
-
-  /p-locate/4.1.0:
-    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
-    engines: {node: '>=8'}
-    dependencies:
-      p-limit: 2.3.0
-    dev: false
-
-  /p-try/2.2.0:
-    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
-    engines: {node: '>=6'}
-    dev: false
-
-  /parse-node-version/1.0.1:
-    resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
-    engines: {node: '>= 0.10'}
-    dev: true
-
-  /pascalcase/0.1.1:
-    resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /path-exists/4.0.0:
-    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
-    engines: {node: '>=8'}
-    dev: false
-
-  /path-parse/1.0.7:
-    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-
-  /pathe/0.2.0:
-    resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
-    dev: true
-
-  /picocolors/1.0.0:
-    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
-
-  /picomatch/2.3.1:
-    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
-    engines: {node: '>=8.6'}
-
-  /pify/2.3.0:
-    resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
-    engines: {node: '>=0.10.0'}
-    dev: false
-
-  /pify/4.0.1:
-    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
-    engines: {node: '>=6'}
-    dev: true
-    optional: true
-
-  /pinia/2.0.18_j6bzmzd4ujpabbp5objtwxyjp4:
-    resolution: {integrity: sha512-I5MW05UVX6a5Djka136oH3VzYFiZUgeOApBwFjMx6pL91eHtGVlE3adjNUKLgtwGnrxiBRuJ8+4R3LKJKwnyZg==}
-    peerDependencies:
-      '@vue/composition-api': ^1.4.0
-      typescript: '>=4.4.4'
-      vue: ^2.6.14 || ^3.2.0
-    peerDependenciesMeta:
-      '@vue/composition-api':
-        optional: true
-      typescript:
-        optional: true
-    dependencies:
-      '@vue/devtools-api': 6.2.1
-      typescript: 4.7.4
-      vue: 3.2.37
-      vue-demi: 0.13.8_vue@3.2.37
-    dev: false
-
-  /pngjs/5.0.0:
-    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
-    engines: {node: '>=10.13.0'}
-    dev: false
-
-  /posix-character-classes/0.1.1:
-    resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /postcss-import/14.1.0_postcss@8.4.16:
-    resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
-    engines: {node: '>=10.0.0'}
-    peerDependencies:
-      postcss: ^8.0.0
-    dependencies:
-      postcss: 8.4.16
-      postcss-value-parser: 4.2.0
-      read-cache: 1.0.0
-      resolve: 1.22.1
-    dev: false
-
-  /postcss-js/4.0.0_postcss@8.4.16:
-    resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==}
-    engines: {node: ^12 || ^14 || >= 16}
-    peerDependencies:
-      postcss: ^8.3.3
-    dependencies:
-      camelcase-css: 2.0.1
-      postcss: 8.4.16
-    dev: false
-
-  /postcss-load-config/3.1.4_postcss@8.4.16:
-    resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
-    engines: {node: '>= 10'}
-    peerDependencies:
-      postcss: '>=8.0.9'
-      ts-node: '>=9.0.0'
-    peerDependenciesMeta:
-      postcss:
-        optional: true
-      ts-node:
-        optional: true
-    dependencies:
-      lilconfig: 2.0.6
-      postcss: 8.4.16
-      yaml: 1.10.2
-    dev: false
-
-  /postcss-nested/5.0.6_postcss@8.4.16:
-    resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==}
-    engines: {node: '>=12.0'}
-    peerDependencies:
-      postcss: ^8.2.14
-    dependencies:
-      postcss: 8.4.16
-      postcss-selector-parser: 6.0.10
-    dev: false
-
-  /postcss-prefix-selector/1.16.0_postcss@5.2.18:
-    resolution: {integrity: sha512-rdVMIi7Q4B0XbXqNUEI+Z4E+pueiu/CS5E6vRCQommzdQ/sgsS4dK42U7GX8oJR+TJOtT+Qv3GkNo6iijUMp3Q==}
-    peerDependencies:
-      postcss: '>4 <9'
-    dependencies:
-      postcss: 5.2.18
-    dev: true
-
-  /postcss-pxtorem/6.0.0:
-    resolution: {integrity: sha512-ZRXrD7MLLjLk2RNGV6UA4f5Y7gy+a/j1EqjAfp9NdcNYVjUMvg5HTYduTjSkKBkRkfqbg/iKrjMO70V4g1LZeg==}
-    peerDependencies:
-      postcss: ^8.0.0
-    dev: true
-
-  /postcss-selector-parser/6.0.10:
-    resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
-    engines: {node: '>=4'}
-    dependencies:
-      cssesc: 3.0.0
-      util-deprecate: 1.0.2
-    dev: false
-
-  /postcss-value-parser/4.2.0:
-    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
-
-  /postcss/5.2.18:
-    resolution: {integrity: sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==}
-    engines: {node: '>=0.12'}
-    dependencies:
-      chalk: 1.1.3
-      js-base64: 2.6.4
-      source-map: 0.5.7
-      supports-color: 3.2.3
-    dev: true
-
-  /postcss/8.4.16:
-    resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==}
-    engines: {node: ^10 || ^12 || >=14}
-    dependencies:
-      nanoid: 3.3.4
-      picocolors: 1.0.0
-      source-map-js: 1.0.2
-
-  /posthtml-parser/0.2.1:
-    resolution: {integrity: sha512-nPC53YMqJnc/+1x4fRYFfm81KV2V+G9NZY+hTohpYg64Ay7NemWWcV4UWuy/SgMupqQ3kJ88M/iRfZmSnxT+pw==}
-    dependencies:
-      htmlparser2: 3.10.1
-      isobject: 2.1.0
-    dev: true
-
-  /posthtml-rename-id/1.0.12:
-    resolution: {integrity: sha512-UKXf9OF/no8WZo9edRzvuMenb6AD5hDLzIepJW+a4oJT+T/Lx7vfMYWT4aWlGNQh0WMhnUx1ipN9OkZ9q+ddEw==}
-    dependencies:
-      escape-string-regexp: 1.0.5
-    dev: true
-
-  /posthtml-render/1.4.0:
-    resolution: {integrity: sha512-W1779iVHGfq0Fvh2PROhCe2QhB8mEErgqzo1wpIt36tCgChafP+hbXIhLDOM8ePJrZcFs0vkNEtdibEWVqChqw==}
-    engines: {node: '>=10'}
-    dev: true
-
-  /posthtml-svg-mode/1.0.3:
-    resolution: {integrity: sha512-hEqw9NHZ9YgJ2/0G7CECOeuLQKZi8HjWLkBaSVtOWjygQ9ZD8P7tqeowYs7WrFdKsWEKG7o+IlsPY8jrr0CJpQ==}
-    dependencies:
-      merge-options: 1.0.1
-      posthtml: 0.9.2
-      posthtml-parser: 0.2.1
-      posthtml-render: 1.4.0
-    dev: true
-
-  /posthtml/0.9.2:
-    resolution: {integrity: sha512-spBB5sgC4cv2YcW03f/IAUN1pgDJWNWD8FzkyY4mArLUMJW+KlQhlmUdKAHQuPfb00Jl5xIfImeOsf6YL8QK7Q==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      posthtml-parser: 0.2.1
-      posthtml-render: 1.4.0
-    dev: true
-
-  /prr/1.0.1:
-    resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
-    dev: true
-    optional: true
-
-  /qrcode/1.5.1:
-    resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==}
-    engines: {node: '>=10.13.0'}
-    hasBin: true
-    dependencies:
-      dijkstrajs: 1.0.2
-      encode-utf8: 1.0.3
-      pngjs: 5.0.0
-      yargs: 15.4.1
-    dev: false
-
-  /query-string/4.3.4:
-    resolution: {integrity: sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      object-assign: 4.1.1
-      strict-uri-encode: 1.1.0
-    dev: true
-
-  /queue-microtask/1.2.3:
-    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
-
-  /quick-lru/5.1.1:
-    resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
-    engines: {node: '>=10'}
-    dev: false
-
-  /read-cache/1.0.0:
-    resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
-    dependencies:
-      pify: 2.3.0
-    dev: false
-
-  /readable-stream/3.6.0:
-    resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
-    engines: {node: '>= 6'}
-    dependencies:
-      inherits: 2.0.4
-      string_decoder: 1.3.0
-      util-deprecate: 1.0.2
-    dev: true
-
-  /readdirp/3.6.0:
-    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
-    engines: {node: '>=8.10.0'}
-    dependencies:
-      picomatch: 2.3.1
-
-  /regenerator-runtime/0.13.9:
-    resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
-    dev: false
-
-  /regex-not/1.0.2:
-    resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      extend-shallow: 3.0.2
-      safe-regex: 1.1.0
-    dev: true
-
-  /repeat-element/1.1.4:
-    resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /repeat-string/1.6.1:
-    resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
-    engines: {node: '>=0.10'}
-    dev: true
-
-  /require-directory/2.1.1:
-    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
-    engines: {node: '>=0.10.0'}
-    dev: false
-
-  /require-main-filename/2.0.0:
-    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
-    dev: false
-
-  /resize-observer-polyfill/1.5.1:
-    resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
-    dev: false
-
-  /resolve-url/0.2.1:
-    resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
-    deprecated: https://github.com/lydell/resolve-url#deprecated
-    dev: true
-
-  /resolve/1.22.1:
-    resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
-    hasBin: true
-    dependencies:
-      is-core-module: 2.10.0
-      path-parse: 1.0.7
-      supports-preserve-symlinks-flag: 1.0.0
-
-  /ret/0.1.15:
-    resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
-    engines: {node: '>=0.12'}
-    dev: true
-
-  /reusify/1.0.4:
-    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
-    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-
-  /rollup/2.77.3:
-    resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==}
-    engines: {node: '>=10.0.0'}
-    hasBin: true
-    optionalDependencies:
-      fsevents: 2.3.2
-    dev: true
-
-  /run-parallel/1.2.0:
-    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
-    dependencies:
-      queue-microtask: 1.2.3
-
-  /safe-buffer/5.1.2:
-    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
-    dev: true
-
-  /safe-buffer/5.2.1:
-    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
-    dev: true
-
-  /safe-regex/1.1.0:
-    resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==}
-    dependencies:
-      ret: 0.1.15
-    dev: true
-
-  /safer-buffer/2.1.2:
-    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
-    dev: true
-    optional: true
-
-  /sax/1.2.4:
-    resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
-    dev: true
-    optional: true
-
-  /scroll-into-view-if-needed/2.2.29:
-    resolution: {integrity: sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==}
-    dependencies:
-      compute-scroll-into-view: 1.0.17
-    dev: false
-
-  /semver/5.7.1:
-    resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
-    hasBin: true
-    dev: true
-    optional: true
-
-  /semver/6.3.0:
-    resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
-    hasBin: true
-    dev: true
-
-  /semver/7.3.7:
-    resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==}
-    engines: {node: '>=10'}
-    hasBin: true
-    dependencies:
-      lru-cache: 6.0.0
-    dev: true
-
-  /set-blocking/2.0.0:
-    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
-    dev: false
-
-  /set-value/2.0.1:
-    resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      extend-shallow: 2.0.1
-      is-extendable: 0.1.1
-      is-plain-object: 2.0.4
-      split-string: 3.1.0
-    dev: true
-
-  /shallow-equal/1.2.1:
-    resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
-    dev: false
-
-  /snapdragon-node/2.1.1:
-    resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      define-property: 1.0.0
-      isobject: 3.0.1
-      snapdragon-util: 3.0.1
-    dev: true
-
-  /snapdragon-util/3.0.1:
-    resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 3.2.2
-    dev: true
-
-  /snapdragon/0.8.2:
-    resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      base: 0.11.2
-      debug: 2.6.9
-      define-property: 0.2.5
-      extend-shallow: 2.0.1
-      map-cache: 0.2.2
-      source-map: 0.5.7
-      source-map-resolve: 0.5.3
-      use: 3.1.1
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /source-map-js/1.0.2:
-    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
-    engines: {node: '>=0.10.0'}
-
-  /source-map-resolve/0.5.3:
-    resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
-    deprecated: See https://github.com/lydell/source-map-resolve#deprecated
-    dependencies:
-      atob: 2.1.2
-      decode-uri-component: 0.2.0
-      resolve-url: 0.2.1
-      source-map-url: 0.4.1
-      urix: 0.1.0
-    dev: true
-
-  /source-map-url/0.4.1:
-    resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==}
-    deprecated: See https://github.com/lydell/source-map-url#deprecated
-    dev: true
-
-  /source-map/0.5.7:
-    resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /source-map/0.6.1:
-    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
-    engines: {node: '>=0.10.0'}
-
-  /sourcemap-codec/1.4.8:
-    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
-
-  /split-string/3.1.0:
-    resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      extend-shallow: 3.0.2
-    dev: true
-
-  /stable/0.1.8:
-    resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
-    deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
-    dev: true
-
-  /static-extend/0.1.2:
-    resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      define-property: 0.2.5
-      object-copy: 0.1.0
-    dev: true
-
-  /strict-uri-encode/1.1.0:
-    resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /string-width/4.2.3:
-    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
-    engines: {node: '>=8'}
-    dependencies:
-      emoji-regex: 8.0.0
-      is-fullwidth-code-point: 3.0.0
-      strip-ansi: 6.0.1
-    dev: false
-
-  /string_decoder/1.3.0:
-    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
-    dependencies:
-      safe-buffer: 5.2.1
-    dev: true
-
-  /strip-ansi/3.0.1:
-    resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      ansi-regex: 2.1.1
-    dev: true
-
-  /strip-ansi/6.0.1:
-    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
-    engines: {node: '>=8'}
-    dependencies:
-      ansi-regex: 5.0.1
-    dev: false
-
-  /supports-color/2.0.0:
-    resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
-    engines: {node: '>=0.8.0'}
-    dev: true
-
-  /supports-color/3.2.3:
-    resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==}
-    engines: {node: '>=0.8.0'}
-    dependencies:
-      has-flag: 1.0.0
-    dev: true
-
-  /supports-color/5.5.0:
-    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
-    engines: {node: '>=4'}
-    dependencies:
-      has-flag: 3.0.0
-    dev: true
-
-  /supports-preserve-symlinks-flag/1.0.0:
-    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
-    engines: {node: '>= 0.4'}
-
-  /svg-baker/1.7.0:
-    resolution: {integrity: sha512-nibslMbkXOIkqKVrfcncwha45f97fGuAOn1G99YwnwTj8kF9YiM6XexPcUso97NxOm6GsP0SIvYVIosBis1xLg==}
-    dependencies:
-      bluebird: 3.7.2
-      clone: 2.1.2
-      he: 1.2.0
-      image-size: 0.5.5
-      loader-utils: 1.4.0
-      merge-options: 1.0.1
-      micromatch: 3.1.0
-      postcss: 5.2.18
-      postcss-prefix-selector: 1.16.0_postcss@5.2.18
-      posthtml-rename-id: 1.0.12
-      posthtml-svg-mode: 1.0.3
-      query-string: 4.3.4
-      traverse: 0.6.6
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /svg-tags/1.0.0:
-    resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
-    dev: true
-
-  /svgo/2.8.0:
-    resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==}
-    engines: {node: '>=10.13.0'}
-    hasBin: true
-    dependencies:
-      '@trysound/sax': 0.2.0
-      commander: 7.2.0
-      css-select: 4.3.0
-      css-tree: 1.1.3
-      csso: 4.2.0
-      picocolors: 1.0.0
-      stable: 0.1.8
-    dev: true
-
-  /tailwindcss/3.1.8:
-    resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==}
-    engines: {node: '>=12.13.0'}
-    hasBin: true
-    dependencies:
-      arg: 5.0.2
-      chokidar: 3.5.3
-      color-name: 1.1.4
-      detective: 5.2.1
-      didyoumean: 1.2.2
-      dlv: 1.1.3
-      fast-glob: 3.2.11
-      glob-parent: 6.0.2
-      is-glob: 4.0.3
-      lilconfig: 2.0.6
-      normalize-path: 3.0.0
-      object-hash: 3.0.0
-      picocolors: 1.0.0
-      postcss: 8.4.16
-      postcss-import: 14.1.0_postcss@8.4.16
-      postcss-js: 4.0.0_postcss@8.4.16
-      postcss-load-config: 3.1.4_postcss@8.4.16
-      postcss-nested: 5.0.6_postcss@8.4.16
-      postcss-selector-parser: 6.0.10
-      postcss-value-parser: 4.2.0
-      quick-lru: 5.1.1
-      resolve: 1.22.1
-    transitivePeerDependencies:
-      - ts-node
-    dev: false
-
-  /to-fast-properties/2.0.0:
-    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
-    engines: {node: '>=4'}
-
-  /to-object-path/0.3.0:
-    resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      kind-of: 3.2.2
-    dev: true
-
-  /to-regex-range/2.1.1:
-    resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      is-number: 3.0.0
-      repeat-string: 1.6.1
-    dev: true
-
-  /to-regex-range/5.0.1:
-    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
-    engines: {node: '>=8.0'}
-    dependencies:
-      is-number: 7.0.0
-
-  /to-regex/3.0.2:
-    resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      define-property: 2.0.2
-      extend-shallow: 3.0.2
-      regex-not: 1.0.2
-      safe-regex: 1.1.0
-    dev: true
-
-  /traverse/0.6.6:
-    resolution: {integrity: sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==}
-    dev: true
-
-  /tslib/2.4.0:
-    resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
-
-  /typescript/4.7.4:
-    resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
-    engines: {node: '>=4.2.0'}
-    hasBin: true
-
-  /union-value/1.0.1:
-    resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      arr-union: 3.1.0
-      get-value: 2.0.6
-      is-extendable: 0.1.1
-      set-value: 2.0.1
-    dev: true
-
-  /universalify/2.0.0:
-    resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
-    engines: {node: '>= 10.0.0'}
-    dev: true
-
-  /unplugin-vue-components/0.22.4_vite@3.0.8+vue@3.2.37:
-    resolution: {integrity: sha512-2rRZcM9OnJGXnYxQNfaceEYuPeVACcWySIjy8WBwIiN3onr980TmA3XE5pRJFt8zoQrUA+c46oyIq96noLqrEQ==}
-    engines: {node: '>=14'}
-    peerDependencies:
-      '@babel/parser': ^7.15.8
-      vue: 2 || 3
-    peerDependenciesMeta:
-      '@babel/parser':
-        optional: true
-    dependencies:
-      '@antfu/utils': 0.5.2
-      '@rollup/pluginutils': 4.2.1
-      chokidar: 3.5.3
-      debug: 4.3.4
-      fast-glob: 3.2.11
-      local-pkg: 0.4.2
-      magic-string: 0.26.2
-      minimatch: 5.1.0
-      resolve: 1.22.1
-      unplugin: 0.9.2_vite@3.0.8
-      vue: 3.2.37
-    transitivePeerDependencies:
-      - esbuild
-      - rollup
-      - supports-color
-      - vite
-      - webpack
-    dev: true
-
-  /unplugin-vue-setup-extend-plus/0.3.2_vite@3.0.8:
-    resolution: {integrity: sha512-wvX/mgVriD6wviBEUSmX1S9uEcd4P3XWR5L6M++TFUS1rU/j0vvyld1D56FXWl7CT41Dll5S5WbD6sQNaMNNUA==}
-    dependencies:
-      '@vue/compiler-sfc': 3.2.37
-      magic-string: 0.26.2
-      unplugin: 0.6.3_vite@3.0.8
-    transitivePeerDependencies:
-      - esbuild
-      - rollup
-      - vite
-      - webpack
-    dev: true
-
-  /unplugin/0.6.3_vite@3.0.8:
-    resolution: {integrity: sha512-CoW88FQfCW/yabVc4bLrjikN9HC8dEvMU4O7B6K2jsYMPK0l6iAnd9dpJwqGcmXJKRCU9vwSsy653qg+RK0G6A==}
-    peerDependencies:
-      esbuild: '>=0.13'
-      rollup: ^2.50.0
-      vite: ^2.3.0
-      webpack: 4 || 5
-    peerDependenciesMeta:
-      esbuild:
-        optional: true
-      rollup:
-        optional: true
-      vite:
-        optional: true
-      webpack:
-        optional: true
-    dependencies:
-      chokidar: 3.5.3
-      vite: 3.0.8_less@4.1.3
-      webpack-sources: 3.2.3
-      webpack-virtual-modules: 0.4.4
-    dev: true
-
-  /unplugin/0.9.2_vite@3.0.8:
-    resolution: {integrity: sha512-Wo9lx9rA0O3AWhLYYNZ6DgnNhL5t5r7kV/Jg5BXjTQtY+DEWrD8VLFSaOmKN0tgqZCMqZ+XrzgOe/3DzIO4/SA==}
-    peerDependencies:
-      esbuild: '>=0.13'
-      rollup: ^2.50.0
-      vite: ^2.3.0 || ^3.0.0-0
-      webpack: 4 || 5
-    peerDependenciesMeta:
-      esbuild:
-        optional: true
-      rollup:
-        optional: true
-      vite:
-        optional: true
-      webpack:
-        optional: true
-    dependencies:
-      acorn: 8.8.0
-      chokidar: 3.5.3
-      vite: 3.0.8_less@4.1.3
-      webpack-sources: 3.2.3
-      webpack-virtual-modules: 0.4.4
-    dev: true
-
-  /unset-value/1.0.0:
-    resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
-    engines: {node: '>=0.10.0'}
-    dependencies:
-      has-value: 0.3.1
-      isobject: 3.0.1
-    dev: true
-
-  /update-browserslist-db/1.0.5_browserslist@4.21.3:
-    resolution: {integrity: sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==}
-    hasBin: true
-    peerDependencies:
-      browserslist: '>= 4.21.0'
-    dependencies:
-      browserslist: 4.21.3
-      escalade: 3.1.1
-      picocolors: 1.0.0
-    dev: true
-
-  /urix/0.1.0:
-    resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
-    deprecated: Please see https://github.com/lydell/urix#deprecated
-    dev: true
-
-  /use/3.1.1:
-    resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
-  /util-deprecate/1.0.2:
-    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-
-  /vary/1.1.2:
-    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
-    engines: {node: '>= 0.8'}
-    dev: true
-
-  /vite-plugin-svg-icons/2.0.1_vite@3.0.8:
-    resolution: {integrity: sha512-6ktD+DhV6Rz3VtedYvBKKVA2eXF+sAQVaKkKLDSqGUfnhqXl3bj5PPkVTl3VexfTuZy66PmINi8Q6eFnVfRUmA==}
-    peerDependencies:
-      vite: '>=2.0.0'
-    dependencies:
-      '@types/svgo': 2.6.4
-      cors: 2.8.5
-      debug: 4.3.4
-      etag: 1.8.1
-      fs-extra: 10.1.0
-      pathe: 0.2.0
-      svg-baker: 1.7.0
-      svgo: 2.8.0
-      vite: 3.0.8_less@4.1.3
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /vite/3.0.8_less@4.1.3:
-    resolution: {integrity: sha512-AOZ4eN7mrkJiOLuw8IA7piS4IdOQyQCA81GxGsAQvAZzMRi9ZwGB3TOaYsj4uLAWK46T5L4AfQ6InNGlxX30IQ==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    hasBin: true
-    peerDependencies:
-      less: '*'
-      sass: '*'
-      stylus: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      less:
-        optional: true
-      sass:
-        optional: true
-      stylus:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      esbuild: 0.14.54
-      less: 4.1.3
-      postcss: 8.4.16
-      resolve: 1.22.1
-      rollup: 2.77.3
-    optionalDependencies:
-      fsevents: 2.3.2
-    dev: true
-
-  /vue-demi/0.13.8_vue@3.2.37:
-    resolution: {integrity: sha512-Vy1zbZhCOdsmvGR6tJhAvO5vhP7eiS8xkbYQSoVa7o6KlIy3W8Rc53ED4qI4qpeRDjv3mLfXSEpYU6Yq4pgXRg==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    peerDependencies:
-      '@vue/composition-api': ^1.0.0-rc.1
-      vue: ^3.0.0-0 || ^2.6.0
-    peerDependenciesMeta:
-      '@vue/composition-api':
-        optional: true
-    dependencies:
-      vue: 3.2.37
-    dev: false
-
-  /vue-qrcode/2.0.0_qrcode@1.5.1+vue@3.2.37:
-    resolution: {integrity: sha512-j+kQQCWm0454zyPyAl1tyfUlo1TNih1nE05k+qepOQE91wdfH98I9mxbtNfVk4FZlVi5cjLjLkeVese7amxnMQ==}
-    peerDependencies:
-      qrcode: ^1.0.0
-      vue: ^2.7.0 || ^3.0.0
-    dependencies:
-      qrcode: 1.5.1
-      tslib: 2.4.0
-      vue: 3.2.37
-    dev: false
-
-  /vue-router/4.1.3_vue@3.2.37:
-    resolution: {integrity: sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==}
-    peerDependencies:
-      vue: ^3.2.0
-    dependencies:
-      '@vue/devtools-api': 6.2.1
-      vue: 3.2.37
-    dev: false
-
-  /vue-tsc/0.39.5_typescript@4.7.4:
-    resolution: {integrity: sha512-jhTsrKhZkafpIeN4Cbhr1K53hNfa/oesSrlh7hUaeHyCk55VhZT6oJkwJbtqN4MYkWZIwPrm3/xTwsELuf2ocg==}
-    hasBin: true
-    peerDependencies:
-      typescript: '*'
-    dependencies:
-      '@volar/vue-language-core': 0.39.5
-      '@volar/vue-typescript': 0.39.5
-      typescript: 4.7.4
-    dev: true
-
-  /vue-types/3.0.2_vue@3.2.37:
-    resolution: {integrity: sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==}
-    engines: {node: '>=10.15.0'}
-    peerDependencies:
-      vue: ^3.0.0
-    dependencies:
-      is-plain-object: 3.0.1
-      vue: 3.2.37
-    dev: false
-
-  /vue/3.2.37:
-    resolution: {integrity: sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==}
-    dependencies:
-      '@vue/compiler-dom': 3.2.37
-      '@vue/compiler-sfc': 3.2.37
-      '@vue/runtime-dom': 3.2.37
-      '@vue/server-renderer': 3.2.37_vue@3.2.37
-      '@vue/shared': 3.2.37
-
-  /warning/4.0.3:
-    resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
-    dependencies:
-      loose-envify: 1.4.0
-    dev: false
-
-  /webpack-sources/3.2.3:
-    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
-    engines: {node: '>=10.13.0'}
-    dev: true
-
-  /webpack-virtual-modules/0.4.4:
-    resolution: {integrity: sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==}
-    dev: true
-
-  /which-module/2.0.0:
-    resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==}
-    dev: false
-
-  /wrap-ansi/6.2.0:
-    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
-    engines: {node: '>=8'}
-    dependencies:
-      ansi-styles: 4.3.0
-      string-width: 4.2.3
-      strip-ansi: 6.0.1
-    dev: false
-
-  /xtend/4.0.2:
-    resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
-    engines: {node: '>=0.4'}
-    dev: false
-
-  /y18n/4.0.3:
-    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
-    dev: false
-
-  /yallist/4.0.0:
-    resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
-    dev: true
-
-  /yaml/1.10.2:
-    resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
-    engines: {node: '>= 6'}
-    dev: false
-
-  /yargs-parser/18.1.3:
-    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
-    engines: {node: '>=6'}
-    dependencies:
-      camelcase: 5.3.1
-      decamelize: 1.2.0
-    dev: false
-
-  /yargs/15.4.1:
-    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
-    engines: {node: '>=8'}
-    dependencies:
-      cliui: 6.0.0
-      decamelize: 1.2.0
-      find-up: 4.1.0
-      get-caller-file: 2.0.5
-      require-directory: 2.1.1
-      require-main-filename: 2.0.0
-      set-blocking: 2.0.0
-      string-width: 4.2.3
-      which-module: 2.0.0
-      y18n: 4.0.3
-      yargs-parser: 18.1.3
-    dev: false

+ 345 - 344
src/pages/exam-manage/index.vue

@@ -1,344 +1,345 @@
-<template>
-  <div class="exam-manage">
-    <Block class="header-block tw-flex tw-items-center tw-justify-between">
-      <a-form layout="inline">
-        <a-form-item label="学校名称">
-          <a-select
-            v-model:value="query.schoolId"
-            show-search
-            :filterOption="false"
-            @search="(name:string) => querySchoolList(name, 'list')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="考试批次">
-          <a-input
-            v-model:value="query.name"
-            placeholder="考试批次"
-            maxlength="50"
-          ></a-input>
-        </a-form-item>
-        <a-form-item>
-          <a-button class="search-button" type="primary" @click="queryExamList"
-            >查询</a-button
-          >
-        </a-form-item>
-      </a-form>
-      <!-- <a-button
-        type="primary"
-        class="tw-flex tw-items-center operation-button"
-        @click="syncExamData"
-      >
-        <template #icon>
-          <CloudSyncOutlined />
-        </template>
-        同步
-      </a-button> -->
-      <a-button
-        type="primary"
-        class="tw-flex tw-items-center operation-button"
-        @click="toggleAddExamModal"
-      >
-        <template #icon>
-          <PlusCircleOutlined />
-        </template>
-        新增
-      </a-button>
-    </Block>
-    <Block class="exam-table">
-      <a-table
-        :columns="columns"
-        :data-source="examTableData.result"
-        emptyText="暂无考试信息"
-        :loading="tableLoading"
-        :pagination="{
-          total: examTableData.totalCount,
-          pageSize: query.pageSize,
-        }"
-        @change="currentPageChange"
-        :row-class-name="
-          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
-        "
-      >
-        <template #bodyCell="{ column, record, index }">
-          <template v-if="column.dataIndex === 'index'">
-            {{ index + 1 }}
-          </template>
-          <template v-else-if="column.dataIndex === 'examStatus'">
-            {{ EXAM_STATUS[record.examStatus as keyof typeof EXAM_STATUS] }}
-          </template>
-          <template v-else-if="column.dataIndex === 'operation'">
-            <div class="tw-flex tw-items-center">
-              <span
-                class="tw-cursor-pointer tw-p-2 tw-ml-1"
-                @click="onEdit(record)"
-                >编辑</span
-              >
-            </div>
-          </template>
-        </template>
-      </a-table>
-    </Block>
-    <a-modal
-      v-model:visible="showModal"
-      :title="`${examInfo.id ? '编辑' : '新增'}考试`"
-      okText="确定"
-      cancelText="取消"
-      :maskClosable="false"
-      @ok="onAddNewExam"
-      :afterClose="resetFields"
-    >
-      <a-form :labelCol="{ span: 6 }">
-        <a-form-item label="学校名称" v-bind="validateInfos.schoolId">
-          <a-select
-            v-model:value="examInfo.schoolId"
-            show-search
-            :disabled="!!examInfo.id"
-            @search="(name: string) => querySchoolList(name,'form')"
-            :filterOption="false"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in examInfo.schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="考试批次" v-bind="validateInfos.name">
-          <a-input
-            v-model:value="examInfo.name"
-            maxlength="50"
-            placeholder="请输入考试批次"
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="状态" v-bind="validateInfos.examStatus">
-          <a-select
-            v-model:value="examInfo.examStatus"
-            placeholder="选择考试状态"
-          >
-            <a-select-option value="EDIT">{{
-              EXAM_STATUS.EDIT
-            }}</a-select-option>
-            <a-select-option value="FINISH">{{
-              EXAM_STATUS.FINISH
-            }}</a-select-option>
-            <a-select-option value="CLOSE">{{
-              EXAM_STATUS.CLOSE
-            }}</a-select-option>
-          </a-select>
-        </a-form-item>
-      </a-form>
-    </a-modal>
-  </div>
-</template>
-
-<script setup lang="ts" name="PageExam">
-import { reactive, ref, watch, unref, markRaw, toRaw } from "vue";
-import { PlusCircleOutlined } from "@ant-design/icons-vue";
-import { getSchoolListHttp } from "@/apis/school";
-import {
-  getExamListHttp,
-  editExamInfoHttp,
-  syncExamDataHttp,
-} from "@/apis/exam";
-import Block from "@/components/block/index.vue";
-import { message, TableColumnType } from "ant-design-vue";
-import { Form } from "ant-design-vue";
-import { throttle } from "lodash-es";
-import { EXAM_STATUS } from "@/constants/dicts";
-import { useMainStore } from "@/store/main";
-
-const mainStore = useMainStore();
-
-const showModal = ref(false);
-const tableLoading = ref(false);
-
-/** 请求参数 */
-const query = reactive<FetchExamListQuery>({
-  name: "",
-  schoolId: mainStore.systemUserInfo?.schoolId || "",
-  pageNumber: 1,
-  pageSize: 10,
-});
-
-/** table配置 */
-const columns: TableColumnType[] = [
-  { title: "序号", dataIndex: "index", align: "center", width: 60 },
-  { title: "考试ID", dataIndex: "id", width: 100, ellipsis: true },
-  { title: "考试批次", dataIndex: "name", ellipsis: true },
-  {
-    title: "状态",
-    dataIndex: "examStatus",
-    align: "center",
-    width: 160,
-    ellipsis: true,
-  },
-  { title: "科目数量", dataIndex: "paperCount", align: "center", width: 100, ellipsis: true },
-  { title: "操作", dataIndex: "operation", align: "center", width: 100 },
-];
-
-/** 学校列表信息 */
-const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 考试列表信息 */
-const examTableData = reactive<MultiplePageData<ExamListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-const examInfo = reactive<
-  BaseExamInfo & { schoolTableData: MultiplePageData<SchoolListInfo> }
->({
-  schoolTableData: { totalCount: 0, result: [] },
-  examStatus: void 0,
-  name: "",
-  schoolId: void 0,
-  id: void 0,
-});
-
-const examRules = {
-  name: [{ required: true, message: "请填写考试批次" }],
-  examStatus: [{ required: true, message: "请选择考试状态" }],
-  schoolId: [{ required: true, message: "请选择学校" }],
-};
-
-const { validate, validateInfos, resetFields } = Form.useForm(
-  examInfo,
-  examRules
-);
-
-/** 查询学校列表 */
-const querySchoolList = throttle(
-  async (name: string = "", type: "list" | "form" = "list") => {
-    const isList = type === "list";
-    try {
-      const { result = [], totalCount } = await getSchoolListHttp({
-        pageNumber: 1,
-        pageSize: 10,
-        name,
-      });
-      Object.assign(isList ? schoolTableData : examInfo.schoolTableData, {
-        result,
-        totalCount,
-      });
-    } catch (error) {
-      console.error(error);
-    }
-  },
-  100
-);
-
-/** 显示新增考试弹窗 */
-const toggleAddExamModal = (show: boolean = true) => {
-  showModal.value = show;
-  if (show) {
-    if (!examInfo.id) {
-      Object.assign(examInfo, {
-        schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
-      });
-    }
-    querySchoolList("", "form");
-  }
-};
-
-/** 查询考试列表 */
-const queryExamList = async () => {
-  try {
-    tableLoading.value = true;
-    const { result = [], totalCount } = await getExamListHttp(query);
-    Object.assign(examTableData, { result, totalCount });
-  } catch (error) {
-    console.error(error);
-  }
-  tableLoading.value = false;
-};
-
-watch(() => query.pageNumber, queryExamList);
-
-/** 编辑考试 */
-const onEdit = (record: ExamListInfo) => {
-  Object.assign(examInfo, {
-    id: record.id,
-    examStatus: record.examStatus,
-    name: record.name,
-    schoolId: record.schoolId,
-  });
-  toggleAddExamModal(true);
-};
-
-/** 新增考试 */
-const onAddNewExam = () => {
-  validate().then((valid) => {
-    if (valid) {
-      const { schoolTableData, ...info } = examInfo;
-      editExamInfoHttp(info).then(() => {
-        message.success(`${info.id ? "修改" : "添加"}成功`);
-        toggleAddExamModal(false);
-        query.schoolId && queryExamList();
-      });
-    }
-  });
-};
-
-const currentPageChange = ({ current }: { current: number }) => {
-  query.pageNumber = current;
-};
-
-/** 同步考试数据 */
-const syncExamData = () => {
-  if (!query.schoolId) {
-    return message.error("请选择需要同步数据的学校");
-  }
-  syncExamDataHttp({ schoolId: query.schoolId }).then(queryExamList);
-};
-
-querySchoolList();
-
-/** effect */
-if (query.schoolId) {
-  queryExamList();
-}
-</script>
-
-<style scoped lang="less">
-.exam-manage {
-  .header-block {
-    :deep(.ant-select-selector) {
-      width: 160px;
-    }
-    .search-button {
-      background-color: @font-color;
-      color: @white;
-      border: none;
-      width: 56px;
-      padding: 0;
-      &:after {
-        display: none;
-        opacity: 0;
-      }
-    }
-    .operation-button {
-      width: 72px;
-      padding: 0;
-      margin-left: auto;
-      & ~ .operation-button {
-        margin-left: 8px;
-      }
-    }
-  }
-  .exam-table {
-  }
-}
-</style>
+<template>
+  <div class="exam-manage">
+    <Block class="header-block tw-flex tw-items-center tw-justify-between">
+      <a-form layout="inline">
+        <a-form-item label="学校名称">
+          <a-select
+            v-model:value="query.schoolId"
+            show-search
+            :filterOption="false"
+            @search="(name:string) => querySchoolList(name, 'list')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="考试批次">
+          <a-input
+            v-model:value="query.name"
+            placeholder="考试批次"
+            maxlength="50"
+          ></a-input>
+        </a-form-item>
+        <a-form-item>
+          <a-button class="search-button" type="primary" @click="queryExamList"
+            >查询</a-button
+          >
+        </a-form-item>
+      </a-form>
+      <!-- <a-button
+        type="primary"
+        class="tw-flex tw-items-center operation-button"
+        @click="syncExamData"
+      >
+        <template #icon>
+          <CloudSyncOutlined />
+        </template>
+        同步
+      </a-button> -->
+      <a-button
+        type="primary"
+        class="tw-flex tw-items-center operation-button"
+        @click="toggleAddExamModal"
+      >
+        <template #icon>
+          <PlusCircleOutlined />
+        </template>
+        新增
+      </a-button>
+    </Block>
+    <Block class="exam-table">
+      <a-table
+        :columns="columns"
+        :data-source="examTableData.result"
+        emptyText="暂无考试信息"
+        :loading="tableLoading"
+        :pagination="{
+          total: examTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
+        @change="currentPageChange"
+        :row-class-name="
+          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
+        "
+      >
+        <template #bodyCell="{ column, record, index }">
+          <template v-if="column.dataIndex === 'index'">
+            {{ index + 1 }}
+          </template>
+          <template v-else-if="column.dataIndex === 'examStatus'">
+            {{ EXAM_STATUS[record.examStatus as keyof typeof EXAM_STATUS] }}
+          </template>
+          <template v-else-if="column.dataIndex === 'operation'">
+            <div class="tw-flex tw-items-center">
+              <span
+                class="tw-cursor-pointer tw-p-2 tw-ml-1"
+                @click="onEdit(record)"
+                >编辑</span
+              >
+            </div>
+          </template>
+        </template>
+      </a-table>
+    </Block>
+    <a-modal
+      v-model:visible="showModal"
+      :title="`${examInfo.id ? '编辑' : '新增'}考试`"
+      okText="确定"
+      cancelText="取消"
+      :maskClosable="false"
+      @ok="onAddNewExam"
+      :afterClose="resetFields"
+    >
+      <a-form :labelCol="{ span: 6 }">
+        <a-form-item label="学校名称" v-bind="validateInfos.schoolId">
+          <a-select
+            v-model:value="examInfo.schoolId"
+            show-search
+            :disabled="!!examInfo.id"
+            @search="(name: string) => querySchoolList(name,'form')"
+            :filterOption="false"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in examInfo.schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="考试批次" v-bind="validateInfos.name">
+          <a-input
+            v-model:value="examInfo.name"
+            maxlength="50"
+            placeholder="请输入考试批次"
+          ></a-input>
+        </a-form-item>
+        <a-form-item label="状态" v-bind="validateInfos.examStatus">
+          <a-select
+            v-model:value="examInfo.examStatus"
+            placeholder="选择考试状态"
+          >
+            <a-select-option value="EDIT">{{
+              EXAM_STATUS.EDIT
+            }}</a-select-option>
+            <a-select-option value="FINISH">{{
+              EXAM_STATUS.FINISH
+            }}</a-select-option>
+            <a-select-option value="CLOSE">{{
+              EXAM_STATUS.CLOSE
+            }}</a-select-option>
+          </a-select>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts" name="PageExam">
+import { reactive, ref, watch, unref, markRaw, toRaw } from "vue";
+import { PlusCircleOutlined } from "@ant-design/icons-vue";
+import { getSchoolListHttp } from "@/apis/school";
+import {
+  getExamListHttp,
+  editExamInfoHttp,
+  syncExamDataHttp,
+} from "@/apis/exam";
+import Block from "@/components/block/index.vue";
+import { message, TableColumnType } from "ant-design-vue";
+import { Form } from "ant-design-vue";
+import { throttle } from "lodash-es";
+import { EXAM_STATUS } from "@/constants/dicts";
+import { useMainStore } from "@/store/main";
+
+const mainStore = useMainStore();
+
+const showModal = ref(false);
+const tableLoading = ref(false);
+
+/** 请求参数 */
+const query = reactive<FetchExamListQuery>({
+  name: "",
+  // schoolId: mainStore.systemUserInfo?.schoolId || "",
+  schoolId: "",
+  pageNumber: 1,
+  pageSize: 10,
+});
+
+/** table配置 */
+const columns: TableColumnType[] = [
+  { title: "序号", dataIndex: "index", align: "center", width: 60 },
+  { title: "考试ID", dataIndex: "id", width: 100, ellipsis: true },
+  { title: "考试批次", dataIndex: "name", ellipsis: true },
+  {
+    title: "状态",
+    dataIndex: "examStatus",
+    align: "center",
+    width: 160,
+    ellipsis: true,
+  },
+  { title: "科目数量", dataIndex: "paperCount", align: "center", width: 100, ellipsis: true },
+  { title: "操作", dataIndex: "operation", align: "center", width: 100 },
+];
+
+/** 学校列表信息 */
+const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 考试列表信息 */
+const examTableData = reactive<MultiplePageData<ExamListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+const examInfo = reactive<
+  BaseExamInfo & { schoolTableData: MultiplePageData<SchoolListInfo> }
+>({
+  schoolTableData: { totalCount: 0, result: [] },
+  examStatus: void 0,
+  name: "",
+  schoolId: void 0,
+  id: void 0,
+});
+
+const examRules = {
+  name: [{ required: true, message: "请填写考试批次" }],
+  examStatus: [{ required: true, message: "请选择考试状态" }],
+  schoolId: [{ required: true, message: "请选择学校" }],
+};
+
+const { validate, validateInfos, resetFields } = Form.useForm(
+  examInfo,
+  examRules
+);
+
+/** 查询学校列表 */
+const querySchoolList = throttle(
+  async (name: string = "", type: "list" | "form" = "list") => {
+    const isList = type === "list";
+    try {
+      const { result = [], totalCount } = await getSchoolListHttp({
+        pageNumber: 1,
+        pageSize: 10,
+        name,
+      });
+      Object.assign(isList ? schoolTableData : examInfo.schoolTableData, {
+        result,
+        totalCount,
+      });
+    } catch (error) {
+      console.error(error);
+    }
+  },
+  100
+);
+
+/** 显示新增考试弹窗 */
+const toggleAddExamModal = (show: boolean = true) => {
+  showModal.value = show;
+  if (show) {
+    if (!examInfo.id) {
+      Object.assign(examInfo, {
+        schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
+      });
+    }
+    querySchoolList("", "form");
+  }
+};
+
+/** 查询考试列表 */
+const queryExamList = async () => {
+  try {
+    tableLoading.value = true;
+    const { result = [], totalCount } = await getExamListHttp(query);
+    Object.assign(examTableData, { result, totalCount });
+  } catch (error) {
+    console.error(error);
+  }
+  tableLoading.value = false;
+};
+
+watch(() => query.pageNumber, queryExamList);
+
+/** 编辑考试 */
+const onEdit = (record: ExamListInfo) => {
+  Object.assign(examInfo, {
+    id: record.id,
+    examStatus: record.examStatus,
+    name: record.name,
+    schoolId: record.schoolId,
+  });
+  toggleAddExamModal(true);
+};
+
+/** 新增考试 */
+const onAddNewExam = () => {
+  validate().then((valid) => {
+    if (valid) {
+      const { schoolTableData, ...info } = examInfo;
+      editExamInfoHttp(info).then(() => {
+        message.success(`${info.id ? "修改" : "添加"}成功`);
+        toggleAddExamModal(false);
+        query.schoolId && queryExamList();
+      });
+    }
+  });
+};
+
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
+};
+
+/** 同步考试数据 */
+const syncExamData = () => {
+  if (!query.schoolId) {
+    return message.error("请选择需要同步数据的学校");
+  }
+  syncExamDataHttp({ schoolId: query.schoolId }).then(queryExamList);
+};
+
+querySchoolList();
+
+/** effect */
+if (query.schoolId) {
+  queryExamList();
+}
+</script>
+
+<style scoped lang="less">
+.exam-manage {
+  .header-block {
+    :deep(.ant-select-selector) {
+      width: 160px;
+    }
+    .search-button {
+      background-color: @font-color;
+      color: @white;
+      border: none;
+      width: 56px;
+      padding: 0;
+      &:after {
+        display: none;
+        opacity: 0;
+      }
+    }
+    .operation-button {
+      width: 72px;
+      padding: 0;
+      margin-left: auto;
+      & ~ .operation-button {
+        margin-left: 8px;
+      }
+    }
+  }
+  .exam-table {
+  }
+}
+</style>

+ 592 - 564
src/pages/subjects-manage/index.vue

@@ -1,564 +1,592 @@
-<template>
-  <div class="subjects-manage">
-    <Block class="header-block tw-flex tw-items-center">
-      <a-form layout="inline" class="tw-flex-1">
-        <a-form-item label="学校名称">
-          <a-select
-            v-model:value="query.schoolId"
-            show-search
-            :filterOption="false"
-            @search="(name:string) => querySchoolList(name, 'list')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="考试批次">
-          <a-select
-            v-model:value="query.examId"
-            :filterOption="false"
-            show-search
-            @search="(name:string) => queryExamList(name, 'list')"
-            placeholder="考试批次"
-          >
-            <a-select-option value="">全部</a-select-option>
-            <a-select-option
-              v-for="exam in examTableData.result"
-              :key="exam.id"
-              :value="`${exam.id}`"
-              >{{ exam.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="分组状态">
-          <a-select v-model:value="query.groupFinish" placeholder="考试批次">
-            <a-select-option :value="0">全部</a-select-option>
-            <a-select-option :value="1">已完成</a-select-option>
-            <a-select-option :value="2">未完成</a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item label="科目代码">
-          <a-input
-            v-model:value="query.courseCode"
-            placeholder="科目代码"
-            maxlength="50"
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="科目名称">
-          <a-input
-            v-model:value="query.courseName"
-            placeholder="科目名称"
-            maxlength="50"
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="试卷总分" class="range-item">
-          <a-input v-model:value="query.totalScoreMin"></a-input>
-          至
-          <a-input v-model:value="query.totalScoreMax"></a-input>
-        </a-form-item>
-        <a-form-item>
-          <a-button
-            class="search-button"
-            type="primary"
-            @click="querySubjectsList"
-            >查询</a-button
-          >
-        </a-form-item>
-      </a-form>
-      <a-dropdown-button type="primary">
-        <template #overlay>
-          <a-menu>
-            <a-menu-item key="1" @click="showImportModalType('subject')"
-              >导入科目</a-menu-item
-            >
-            <a-menu-item key="2" @click="showImportModalType('struct')"
-              >导入主观题</a-menu-item
-            >
-          </a-menu>
-        </template>
-        <template #icon><DownOutlined /></template>
-        导入
-      </a-dropdown-button>
-      <a-button
-        type="primary"
-        class="tw-flex tw-items-center operation-button"
-        @click="downloadPaperStruct"
-      >
-        <template #icon>
-          <UploadOutlined />
-        </template>
-        导出
-      </a-button>
-    </Block>
-    <Block class="subjects-table">
-      <a-table
-        :columns="columns"
-        :data-source="subjectsTableData.result"
-        :pagination="{
-          total: subjectsTableData.totalCount,
-          pageSize: query.pageSize,
-        }"
-        @change="currentPageChange"
-        :row-class-name="
-          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
-        "
-      >
-        <template #bodyCell="{ column, record, index, text }">
-          <template v-if="column.dataIndex === 'index'">
-            {{ index + 1 }}
-          </template>
-          <template v-else-if="column.dataIndex === 'courseName'">
-            {{ text }}
-            <a-tooltip placement="right">
-              <template #title>
-                <span>主观分未完成分组</span>
-              </template>
-              <img
-                v-if="!record.groupFinish"
-                class="star-icon"
-                src="@imgs/common/star-icon.png"
-              />
-            </a-tooltip>
-          </template>
-          <template v-else-if="column.dataIndex === 'enable'">
-            <template v-if="record.enable">
-              <CheckCircleFilled style="color: #30bf78" />
-            </template>
-            <template v-else>
-              <CloseCircleFilled style="color: #f4664a" />
-            </template>
-          </template>
-        </template>
-      </a-table>
-    </Block>
-    <a-modal
-      v-model:visible="showImportModal"
-      :maskClosable="false"
-      :title="`导入${uploadQuery.type === 'subject' ? '科目' : '主观题'}`"
-      okText="确认上传"
-      cancelText="取消"
-      @ok="onImport"
-      :afterClose="resetFields"
-    >
-      <a-form :labelCol="{ span: 6 }">
-        <a-form-item label="学校名称" v-bind="validateInfos.schoolId">
-          <a-select
-            v-model:value="uploadQuery.schoolId"
-            show-search
-            :filterOption="false"
-            @search="(name: string) => querySchoolList(name,'form')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in uploadQuery.schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="考试批次" v-bind="validateInfos.examId">
-          <a-select
-            v-model:value="uploadQuery.examId"
-            :filterOption="false"
-            show-search
-            @search="(name:string) => queryExamList(name, 'form')"
-            placeholder="考试批次"
-          >
-            <a-select-option
-              v-for="exam in uploadQuery.examTableData.result"
-              :key="exam.id"
-              :value="`${exam.id}`"
-              >{{ exam.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item
-          :label="`${
-            uploadQuery.type === 'subject' ? '科目' : '主观题'
-          }导入文件`"
-          v-bind="validateInfos.fileList"
-        >
-          <a-upload
-            :file-list="uploadQuery.fileList"
-            :before-upload="beforeUpload"
-            @remove="handleRemove"
-            :max-count="1"
-            type="primary"
-          >
-            <a-button>
-              <upload-outlined></upload-outlined>
-              选择文件
-            </a-button>
-            <a class="tw-ml-4 tw-align-bottom" @click.stop="downloadTemplate">
-              下载导入模板
-            </a>
-          </a-upload>
-        </a-form-item>
-      </a-form>
-    </a-modal>
-  </div>
-</template>
-
-<script setup lang="ts" name="PageSubjects">
-import { onBeforeMount, reactive, ref, watch } from "vue";
-import {
-  UploadOutlined,
-  CheckCircleFilled,
-  CloseCircleFilled,
-  DownOutlined,
-} from "@ant-design/icons-vue";
-
-import Block from "@/components/block/index.vue";
-import { message, TableColumnType, UploadProps } from "ant-design-vue";
-import { Form } from "ant-design-vue";
-import {
-  getSubjectsListHttp,
-  importSubjectsHttp,
-  importPaperStructHttp,
-  downloadPaperStructHttp,
-  downloadSubjectTemplateHttp,
-  downloadPaperStructTemplateHttp,
-} from "@/apis/struct";
-import { getSchoolListHttp } from "@/apis/school";
-import { getExamListHttp } from "@/apis/exam";
-import { useMainStore } from "@/store/main";
-import { throttle } from "lodash-es";
-import { fileTypeCheck } from "@/utils/file-type";
-
-type ImportType = "subject" | "struct";
-
-const mainStore = useMainStore();
-
-const showImportModal = ref(false);
-
-const tableLoading = ref(false);
-
-const ImportDownloadApi: Record<
-  ImportType,
-  {
-    upload: typeof importSubjectsHttp;
-    download: typeof downloadSubjectTemplateHttp;
-  }
-> = {
-  subject: {
-    upload: importSubjectsHttp,
-    download: downloadSubjectTemplateHttp,
-  },
-  struct: {
-    upload: importPaperStructHttp,
-    download: downloadPaperStructTemplateHttp,
-  },
-};
-
-/** 导入参数 */
-const uploadQuery = reactive<{
-  type: ImportType;
-  schoolId?: string | number;
-  examId?: string;
-  fileList: UploadProps["fileList"];
-  schoolTableData: MultiplePageData<SchoolListInfo>;
-  examTableData: MultiplePageData<ExamListInfo>;
-}>({
-  type: "subject",
-  schoolTableData: { totalCount: 0, result: [] },
-  examTableData: { totalCount: 0, result: [] },
-  schoolId: void 0,
-  examId: void 0,
-  fileList: [],
-});
-
-const uploadRules = {
-  schoolId: [{ required: true, message: "请选择学校" }],
-  examId: [{ required: true, message: "请选择考试批次" }],
-  fileList: [
-    { required: true, type: "array", len: 1, message: "请选择导入文件" },
-  ],
-};
-
-const { validate, validateInfos, resetFields } = Form.useForm(
-  uploadQuery,
-  uploadRules
-);
-
-/** 查询参数 */
-const query = reactive<
-  Omit<FetchSubjectsListQuery, "groupFinish"> & { groupFinish: number }
->({
-  /** 科目代码 */
-  courseCode: "",
-  courseName: "",
-  /** 考试id */
-  examId: "",
-  /** 	分组状态 */
-  groupFinish: 0,
-  /** 学校id */
-  schoolId: mainStore.systemUserInfo?.schoolId || "",
-  /** 总分截止值 */
-  totalScoreMax: "",
-  /** 总分起始值 */
-  totalScoreMin: "",
-  pageSize: 10,
-  pageNumber: 1,
-});
-
-/** table配置 */
-const columns: TableColumnType[] = [
-  { title: "序号", dataIndex: "index", align: "center", width: 60 },
-  {
-    title: "科目代码",
-    dataIndex: "courseCode",
-    align: "center",
-    width: 120,
-    ellipsis: true,
-  },
-  { title: "科目名称", dataIndex: "courseName", ellipsis: true },
-  {
-    title: "主观总分",
-    dataIndex: "subjectiveScore",
-    align: "center",
-    width: 100,
-  },
-  { title: "试卷总分", dataIndex: "totalScore", align: "center", width: 100 },
-  { title: "分组数", dataIndex: "groupCount", align: "center", width: 80 },
-];
-
-/** 学校列表信息 */
-const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 考试列表信息 */
-const examTableData = reactive<MultiplePageData<ExamListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 科目列表信息 */
-const subjectsTableData = reactive<MultiplePageData<SubjectsListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 查询学校列表 */
-const querySchoolList = throttle(
-  async (name: string = "", type: "list" | "form" = "list") => {
-    const isList = type === "list";
-    try {
-      const { result = [], totalCount } = await getSchoolListHttp({
-        name,
-        pageNumber: 1,
-        pageSize: 10,
-      });
-      Object.assign(isList ? schoolTableData : uploadQuery.schoolTableData, {
-        result,
-        totalCount,
-      });
-    } catch (error) {
-      return Promise.reject(error);
-    }
-  },
-  100
-);
-
-/** 查询考试列表 */
-const queryExamList = throttle(
-  async (name: string = "", type: "list" | "form" = "list") => {
-    try {
-      const isList = type === "list";
-      const schoolId = isList ? query.schoolId : uploadQuery.schoolId;
-      if (!schoolId) {
-        return Promise.reject(`schoolId got : ${schoolId}`);
-      }
-      const { result = [], totalCount } = await getExamListHttp({
-        pageNumber: 1,
-        pageSize: 10,
-        name,
-        schoolId,
-      });
-      Object.assign(isList ? examTableData : uploadQuery.examTableData, {
-        result,
-        totalCount,
-      });
-    } catch (error) {
-      return Promise.reject(error);
-    }
-  },
-  100
-);
-
-/** 查询科目列表 */
-const querySubjectsList = async () => {
-  try {
-    tableLoading.value = true;
-    const { result = [], totalCount } = await getSubjectsListHttp({
-      ...query,
-      groupFinish: [void 0, true, false][query.groupFinish],
-    });
-    Object.assign(subjectsTableData, { result, totalCount });
-  } catch (error) {
-    return Promise.reject(error);
-  }
-  tableLoading.value = false;
-};
-
-watch(() => query.pageNumber, querySubjectsList);
-
-watch(
-  () => query.schoolId,
-  () => {
-    query.examId = "";
-    Object.assign(examTableData, { result: [], totalCount: 0 });
-    if (query.schoolId) {
-      queryExamList("", "list");
-    }
-  }
-);
-
-watch(
-  () => uploadQuery.schoolId,
-  () => {
-    uploadQuery.examId = void 0;
-    Object.assign(uploadQuery.examTableData, { result: [], totalCount: 0 });
-    if (uploadQuery.schoolId) {
-      queryExamList("", "form");
-    }
-  }
-);
-
-const currentPageChange = ({ current }: { current: number }) => {
-  query.pageNumber = current;
-};
-
-/** 导出主观题 */
-const downloadPaperStruct = async () => {
-  try {
-    await downloadPaperStructHttp({
-      ...query,
-      groupFinish: [void 0, true, false][query.groupFinish],
-    });
-  } catch (error) {
-    return Promise.reject(error);
-  }
-};
-
-const handleRemove: UploadProps["onRemove"] = (file) => {
-  const index = uploadQuery.fileList!.indexOf(file);
-  const newFileList = uploadQuery.fileList!.slice();
-  newFileList.splice(index, 1);
-  uploadQuery.fileList = newFileList;
-};
-
-const beforeUpload: UploadProps["beforeUpload"] = async (file) => {
-  await fileTypeCheck(file, ["xls", "xlsx"]).catch((error) => {
-    message.error("文件类型错误, 请使用导入模板编辑");
-    return Promise.reject(error);
-  });
-  uploadQuery.fileList = [file];
-  return false;
-};
-
-/** 下载导入模板 */
-const downloadTemplate = async () => {
-  try {
-    await ImportDownloadApi[uploadQuery.type].download();
-  } catch (error) {
-    return Promise.reject(error);
-  }
-};
-
-/** 显示导入弹窗 */
-const showImportModalType = async (type: ImportType) => {
-  uploadQuery.type = type;
-  uploadQuery.schoolId = query.schoolId || mainStore.systemUserInfo?.schoolId;
-  showImportModal.value = true;
-  querySchoolList("", "form");
-};
-
-/** 导入数据 */
-const onImport = async () => {
-  try {
-    const valid = await validate();
-    if (valid) {
-      const formData = new FormData();
-      formData.append("examId", uploadQuery.examId || "");
-      uploadQuery.fileList?.forEach((file: any) => {
-        formData.append("file", file);
-      });
-      await ImportDownloadApi[uploadQuery.type].upload(formData);
-      querySubjectsList();
-      showImportModal.value = false;
-    }
-  } catch (error) {
-    return Promise.reject(error);
-  }
-};
-
-onBeforeMount(async () => {
-  try {
-    await querySchoolList();
-    if (
-      schoolTableData.result
-        .map((school) => `${school.id}`)
-        .some((id) => id === `${query.schoolId}`)
-    ) {
-      await queryExamList("", "list");
-      await querySubjectsList();
-    }
-  } catch (error) {
-    console.error(error);
-  }
-});
-</script>
-
-<style scoped lang="less">
-.subjects-manage {
-  .header-block {
-    .ant-input {
-      width: 160px;
-    }
-    :deep(.ant-select-selector) {
-      width: 160px;
-    }
-    :deep(.ant-form-item) {
-      margin-bottom: 8px;
-    }
-    .range-item {
-      .ant-input {
-        width: 69px;
-      }
-    }
-    .search-button {
-      background-color: @font-color;
-      color: @white;
-      border: none;
-      width: 56px;
-      padding: 0;
-      &:after {
-        display: none;
-        opacity: 0;
-      }
-    }
-
-    .operation-button {
-      width: 72px;
-      padding: 0;
-      margin-left: 8px;
-    }
-  }
-  .subjects-table {
-    .star-icon {
-      width: 14px;
-      height: 14px;
-      display: inline-block;
-      vertical-align: middle;
-    }
-  }
-}
-</style>
+<template>
+  <div class="subjects-manage">
+    <Block class="header-block tw-flex tw-items-end">
+      <a-form layout="inline" class="tw-flex-1">
+        <a-form-item label="学校名称">
+          <a-select
+            v-model:value="query.schoolId"
+            show-search
+            :filterOption="false"
+            @search="(name:string) => querySchoolList(name, 'list')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="考试批次">
+          <a-select
+            v-model:value="query.examId"
+            :filterOption="false"
+            show-search
+            @search="(name:string) => queryExamList(name, 'list')"
+            placeholder="考试批次"
+          >
+            <a-select-option value="">全部</a-select-option>
+            <a-select-option
+              v-for="exam in examTableData.result"
+              :key="exam.id"
+              :value="`${exam.id}`"
+              >{{ exam.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="分组状态">
+          <a-select v-model:value="query.groupFinish" placeholder="考试批次">
+            <a-select-option :value="0">全部</a-select-option>
+            <a-select-option :value="1">已完成</a-select-option>
+            <a-select-option :value="2">未完成</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="科目代码">
+          <a-input
+            v-model:value="query.courseCode"
+            placeholder="科目代码"
+            maxlength="50"
+          ></a-input>
+        </a-form-item>
+        <a-form-item label="科目名称">
+          <a-input
+            v-model:value="query.courseName"
+            placeholder="科目名称"
+            maxlength="50"
+          ></a-input>
+        </a-form-item>
+        <a-form-item label="试卷总分" class="range-item">
+          <a-input v-model:value="query.totalScoreMin"></a-input>
+          至
+          <a-input v-model:value="query.totalScoreMax"></a-input>
+        </a-form-item>
+        <a-form-item>
+          <a-button
+            class="search-button"
+            type="primary"
+            @click="querySubjectsList"
+            >查询</a-button
+          >
+        </a-form-item>
+      </a-form>
+        <div class="import-btns">
+          <a-button
+            type="primary"
+            class="tw-flex tw-items-center operation-button"
+            @click="showImportModalType('subject')"
+          >
+            导入科目
+          </a-button>
+          <br />
+          <a-button
+            type="primary"
+            class="tw-flex tw-items-center operation-button"
+            @click="showImportModalType('struct')"
+          >
+            导入主观题结构
+          </a-button>
+
+
+
+<!--        <a-dropdown-button type="primary">-->
+<!--          <template #overlay>-->
+<!--            <a-menu>-->
+<!--              <a-menu-item key="1" @click="showImportModalType('subject')"-->
+<!--              >导入科目</a-menu-item-->
+<!--              >-->
+<!--              <a-menu-item key="2" @click="showImportModalType('struct')"-->
+<!--              >导入主观题</a-menu-item-->
+<!--              >-->
+<!--            </a-menu>-->
+<!--          </template>-->
+<!--          <template #icon><DownOutlined /></template>-->
+<!--          导入-->
+<!--        </a-dropdown-button>-->
+      </div>
+      <div class="export-btns">
+        <a-button
+          type="primary"
+          class="tw-flex tw-items-center operation-button"
+          @click="downloadPaperStruct"
+        >
+          <!--          <template #icon>-->
+          <!--            <UploadOutlined />-->
+          <!--          </template>-->
+          导出
+        </a-button>
+      </div>
+    </Block>
+    <Block class="subjects-table">
+      <a-table
+        :columns="columns"
+        :data-source="subjectsTableData.result"
+        :pagination="{
+          total: subjectsTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
+        @change="currentPageChange"
+        :row-class-name="
+          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
+        "
+      >
+        <template #bodyCell="{ column, record, index, text }">
+          <template v-if="column.dataIndex === 'index'">
+            {{ index + 1 }}
+          </template>
+          <template v-else-if="column.dataIndex === 'courseName'">
+            {{ text }}
+            <a-tooltip placement="right">
+              <template #title>
+                <span>主观分未完成分组</span>
+              </template>
+              <img
+                v-if="!record.groupFinish"
+                class="star-icon"
+                src="@imgs/common/star-icon.png"
+              />
+            </a-tooltip>
+          </template>
+          <template v-else-if="column.dataIndex === 'enable'">
+            <template v-if="record.enable">
+              <CheckCircleFilled style="color: #30bf78" />
+            </template>
+            <template v-else>
+              <CloseCircleFilled style="color: #f4664a" />
+            </template>
+          </template>
+        </template>
+      </a-table>
+    </Block>
+    <a-modal
+      v-model:visible="showImportModal"
+      :maskClosable="false"
+      :title="`导入${uploadQuery.type === 'subject' ? '科目' : '主观题'}`"
+      okText="确认上传"
+      cancelText="取消"
+      @ok="onImport"
+      :afterClose="resetFields"
+    >
+      <a-form :labelCol="{ span: 6 }">
+        <a-form-item label="学校名称" v-bind="validateInfos.schoolId">
+          <a-select
+            v-model:value="uploadQuery.schoolId"
+            show-search
+            :filterOption="false"
+            @search="(name: string) => querySchoolList(name,'form')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in uploadQuery.schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="考试批次" v-bind="validateInfos.examId">
+          <a-select
+            v-model:value="uploadQuery.examId"
+            :filterOption="false"
+            show-search
+            @search="(name:string) => queryExamList(name, 'form')"
+            placeholder="考试批次"
+          >
+            <a-select-option
+              v-for="exam in uploadQuery.examTableData.result"
+              :key="exam.id"
+              :value="`${exam.id}`"
+              >{{ exam.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item
+          :label="`${
+            uploadQuery.type === 'subject' ? '科目' : '主观题'
+          }导入文件`"
+          v-bind="validateInfos.fileList"
+        >
+          <a-upload
+            :file-list="uploadQuery.fileList"
+            :before-upload="beforeUpload"
+            @remove="handleRemove"
+            :max-count="1"
+            type="primary"
+          >
+            <a-button>
+              <upload-outlined></upload-outlined>
+              选择文件
+            </a-button>
+            <a class="tw-ml-4 tw-align-bottom" @click.stop="downloadTemplate">
+              下载导入模板
+            </a>
+          </a-upload>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts" name="PageSubjects">
+import { onBeforeMount, reactive, ref, watch } from "vue";
+import {
+  UploadOutlined,
+  CheckCircleFilled,
+  CloseCircleFilled,
+  DownOutlined,
+} from "@ant-design/icons-vue";
+
+import Block from "@/components/block/index.vue";
+import { message, TableColumnType, UploadProps } from "ant-design-vue";
+import { Form } from "ant-design-vue";
+import {
+  getSubjectsListHttp,
+  importSubjectsHttp,
+  importPaperStructHttp,
+  downloadPaperStructHttp,
+  downloadSubjectTemplateHttp,
+  downloadPaperStructTemplateHttp,
+} from "@/apis/struct";
+import { getSchoolListHttp } from "@/apis/school";
+import { getExamListHttp } from "@/apis/exam";
+import { useMainStore } from "@/store/main";
+import { throttle } from "lodash-es";
+import { fileTypeCheck } from "@/utils/file-type";
+
+type ImportType = "subject" | "struct";
+
+const mainStore = useMainStore();
+
+const showImportModal = ref(false);
+
+const tableLoading = ref(false);
+
+const ImportDownloadApi: Record<
+  ImportType,
+  {
+    upload: typeof importSubjectsHttp;
+    download: typeof downloadSubjectTemplateHttp;
+  }
+> = {
+  subject: {
+    upload: importSubjectsHttp,
+    download: downloadSubjectTemplateHttp,
+  },
+  struct: {
+    upload: importPaperStructHttp,
+    download: downloadPaperStructTemplateHttp,
+  },
+};
+
+/** 导入参数 */
+const uploadQuery = reactive<{
+  type: ImportType;
+  schoolId?: string | number;
+  examId?: string;
+  fileList: UploadProps["fileList"];
+  schoolTableData: MultiplePageData<SchoolListInfo>;
+  examTableData: MultiplePageData<ExamListInfo>;
+}>({
+  type: "subject",
+  schoolTableData: { totalCount: 0, result: [] },
+  examTableData: { totalCount: 0, result: [] },
+  schoolId: void 0,
+  examId: void 0,
+  fileList: [],
+});
+
+const uploadRules = {
+  schoolId: [{ required: true, message: "请选择学校" }],
+  examId: [{ required: true, message: "请选择考试批次" }],
+  fileList: [
+    { required: true, type: "array", len: 1, message: "请选择导入文件" },
+  ],
+};
+
+const { validate, validateInfos, resetFields } = Form.useForm(
+  uploadQuery,
+  uploadRules
+);
+
+/** 查询参数 */
+const query = reactive<
+  Omit<FetchSubjectsListQuery, "groupFinish"> & { groupFinish: number }
+>({
+  /** 科目代码 */
+  courseCode: "",
+  courseName: "",
+  /** 考试id */
+  examId: "",
+  /** 	分组状态 */
+  groupFinish: 0,
+  /** 学校id */
+  // schoolId: mainStore.systemUserInfo?.schoolId || "",
+  schoolId: "",
+  /** 总分截止值 */
+  totalScoreMax: "",
+  /** 总分起始值 */
+  totalScoreMin: "",
+  pageSize: 10,
+  pageNumber: 1,
+});
+
+/** table配置 */
+const columns: TableColumnType[] = [
+  { title: "序号", dataIndex: "index", align: "center", width: 60 },
+  {
+    title: "科目代码",
+    dataIndex: "courseCode",
+    align: "center",
+    width: 120,
+    ellipsis: true,
+  },
+  { title: "科目名称", dataIndex: "courseName", ellipsis: true },
+  {
+    title: "主观总分",
+    dataIndex: "subjectiveScore",
+    align: "center",
+    width: 100,
+  },
+  { title: "试卷总分", dataIndex: "totalScore", align: "center", width: 100 },
+  { title: "分组数", dataIndex: "groupCount", align: "center", width: 80 },
+];
+
+/** 学校列表信息 */
+const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 考试列表信息 */
+const examTableData = reactive<MultiplePageData<ExamListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 科目列表信息 */
+const subjectsTableData = reactive<MultiplePageData<SubjectsListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 查询学校列表 */
+const querySchoolList = throttle(
+  async (name: string = "", type: "list" | "form" = "list") => {
+    const isList = type === "list";
+    try {
+      const { result = [], totalCount } = await getSchoolListHttp({
+        name,
+        pageNumber: 1,
+        pageSize: 10,
+      });
+      Object.assign(isList ? schoolTableData : uploadQuery.schoolTableData, {
+        result,
+        totalCount,
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  },
+  100
+);
+
+/** 查询考试列表 */
+const queryExamList = throttle(
+  async (name: string = "", type: "list" | "form" = "list") => {
+    try {
+      const isList = type === "list";
+      const schoolId = isList ? query.schoolId : uploadQuery.schoolId;
+      if (!schoolId) {
+        return Promise.reject(`schoolId got : ${schoolId}`);
+      }
+      const { result = [], totalCount } = await getExamListHttp({
+        pageNumber: 1,
+        pageSize: 10,
+        name,
+        schoolId,
+      });
+      Object.assign(isList ? examTableData : uploadQuery.examTableData, {
+        result,
+        totalCount,
+      });
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  },
+  100
+);
+
+/** 查询科目列表 */
+const querySubjectsList = async () => {
+  try {
+    tableLoading.value = true;
+    const { result = [], totalCount } = await getSubjectsListHttp({
+      ...query,
+      groupFinish: [void 0, true, false][query.groupFinish],
+    });
+    Object.assign(subjectsTableData, { result, totalCount });
+  } catch (error) {
+    return Promise.reject(error);
+  }
+  tableLoading.value = false;
+};
+
+watch(() => query.pageNumber, querySubjectsList);
+
+watch(
+  () => query.schoolId,
+  () => {
+    query.examId = "";
+    Object.assign(examTableData, { result: [], totalCount: 0 });
+    if (query.schoolId) {
+      queryExamList("", "list");
+    }
+  }
+);
+
+watch(
+  () => uploadQuery.schoolId,
+  () => {
+    uploadQuery.examId = void 0;
+    Object.assign(uploadQuery.examTableData, { result: [], totalCount: 0 });
+    if (uploadQuery.schoolId) {
+      queryExamList("", "form");
+    }
+  }
+);
+
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
+};
+
+/** 导出主观题 */
+const downloadPaperStruct = async () => {
+  try {
+    await downloadPaperStructHttp({
+      ...query,
+      groupFinish: [void 0, true, false][query.groupFinish],
+    });
+  } catch (error) {
+    return Promise.reject(error);
+  }
+};
+
+const handleRemove: UploadProps["onRemove"] = (file) => {
+  const index = uploadQuery.fileList!.indexOf(file);
+  const newFileList = uploadQuery.fileList!.slice();
+  newFileList.splice(index, 1);
+  uploadQuery.fileList = newFileList;
+};
+
+const beforeUpload: UploadProps["beforeUpload"] = async (file) => {
+  await fileTypeCheck(file, ["xls", "xlsx"]).catch((error) => {
+    message.error("文件类型错误, 请使用导入模板编辑");
+    return Promise.reject(error);
+  });
+  uploadQuery.fileList = [file];
+  return false;
+};
+
+/** 下载导入模板 */
+const downloadTemplate = async () => {
+  try {
+    await ImportDownloadApi[uploadQuery.type].download();
+  } catch (error) {
+    return Promise.reject(error);
+  }
+};
+
+/** 显示导入弹窗 */
+const showImportModalType = async (type: ImportType) => {
+  uploadQuery.type = type;
+  // uploadQuery.schoolId = query.schoolId || mainStore.systemUserInfo?.schoolId;
+  uploadQuery.schoolId = '';
+  showImportModal.value = true;
+  querySchoolList("", "form");
+};
+
+/** 导入数据 */
+const onImport = async () => {
+  try {
+    const valid = await validate();
+    if (valid) {
+      const formData = new FormData();
+      formData.append("examId", uploadQuery.examId || "");
+      uploadQuery.fileList?.forEach((file: any) => {
+        formData.append("file", file);
+      });
+      await ImportDownloadApi[uploadQuery.type].upload(formData);
+      querySubjectsList();
+      showImportModal.value = false;
+    }
+  } catch (error) {
+    return Promise.reject(error);
+  }
+};
+
+onBeforeMount(async () => {
+  try {
+    await querySchoolList();
+    if (
+      schoolTableData.result
+        .map((school) => `${school.id}`)
+        .some((id) => id === `${query.schoolId}`)
+    ) {
+      await queryExamList("", "list");
+      await querySubjectsList();
+    }
+  } catch (error) {
+    console.error(error);
+  }
+});
+</script>
+
+<style scoped lang="less">
+.subjects-manage {
+  .header-block {
+    .export-btns{
+      padding-left:6px;
+    }
+    .ant-input {
+      width: 160px;
+    }
+    :deep(.ant-select-selector) {
+      width: 160px;
+    }
+    :deep(.ant-form-item) {
+      margin-bottom: 8px;
+    }
+    .range-item {
+      .ant-input {
+        width: 69px;
+      }
+    }
+    .search-button {
+      background-color: @font-color;
+      color: @white;
+      border: none;
+      width: 56px;
+      padding: 0;
+      &:after {
+        display: none;
+        opacity: 0;
+      }
+    }
+
+    .operation-button {
+      //width: 72px;
+      padding:0 9px;
+      //padding: 0;
+      margin-bottom:10px;
+    }
+  }
+  .subjects-table {
+    .star-icon {
+      width: 14px;
+      height: 14px;
+      display: inline-block;
+      vertical-align: middle;
+    }
+  }
+}
+</style>

+ 654 - 649
src/pages/user-manage/index.vue

@@ -1,649 +1,654 @@
-<template>
-  <div class="user-manage">
-    <Block class="header-block tw-flex tw-items-center">
-      <a-form layout="inline">
-        <a-form-item label="学校名称">
-          <a-select
-            v-model:value="query.schoolId"
-            show-search
-            :filterOption="false"
-            @search="(name:string) => querySchoolList(name,'list')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="登录名">
-          <a-input
-            v-model:value="query.loginName"
-            maxlength="50"
-            placeholder="登录名"
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="角色">
-          <a-select v-model:value="query.role" placeholder="用户角色">
-            <a-select-option :value="void 0">全部</a-select-option>
-            <a-select-option value="SCHOOL_ADMIN">{{
-              ROLE.SCHOOL_ADMIN
-            }}</a-select-option>
-            <a-select-option value="SECTION_LEADER">{{
-              ROLE.SECTION_LEADER
-            }}</a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item>
-          <a-button class="search-button" type="primary" @click="queryUserList"
-            >查询</a-button
-          >
-        </a-form-item>
-      </a-form>
-      <a-button
-        type="primary"
-        class="tw-flex tw-items-center operation-button"
-        @click="toggleAddUserModal"
-      >
-        <template #icon>
-          <PlusCircleOutlined />
-        </template>
-        新增
-      </a-button>
-      <a-button
-        type="primary"
-        class="tw-flex tw-items-center operation-button"
-        @click="importUserList"
-      >
-        <template #icon>
-          <DownloadOutlined />
-        </template>
-        导入
-      </a-button>
-    </Block>
-    <Block class="user-table">
-      <a-table
-        :columns="columns"
-        :data-source="userTableData.result"
-        :pagination="{
-          total: userTableData.totalCount,
-          pageSize: query.pageSize,
-        }"
-        @change="currentPageChange"
-        :row-class-name="
-          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
-        "
-      >
-        <template #bodyCell="{ column, record, index }">
-          <template v-if="column.dataIndex === 'index'">
-            {{ index + 1 }}
-          </template>
-          <template v-else-if="column.dataIndex === 'enable'">
-            <template v-if="record.enable">
-              <CheckCircleFilled style="color: #30bf78" />
-            </template>
-            <template v-else>
-              <CloseCircleFilled style="color: #f4664a" />
-            </template>
-          </template>
-          <template v-else-if="column.dataIndex === 'operation'">
-            <div
-              class="tw-flex tw-items-center"
-              v-if="record.role !== 'SUPER_ADMIN'"
-            >
-              <span
-                class="tw-cursor-pointer tw-p-2"
-                @click="updateUserStatus(record)"
-                >{{ record.enable ? "禁用" : "启用" }}</span
-              >
-              <span
-                class="tw-cursor-pointer tw-p-2 tw-ml-1"
-                @click="onEdit(record)"
-                >编辑</span
-              >
-              <span
-                class="tw-cursor-pointer tw-p-2 tw-ml-1"
-                @click="onResetPwd(record)"
-                >重置密码
-              </span>
-            </div>
-          </template>
-        </template>
-      </a-table>
-    </Block>
-    <a-modal
-      v-model:visible="showModal"
-      :title="`${!userInfo.id ? '新增' : '编辑'}用户`"
-      okText="确定"
-      cancelText="取消"
-      :maskClosable="false"
-      @ok="onPutUser"
-      :afterClose="resetUserFields"
-    >
-      <a-form :labelCol="{ span: 6 }">
-        <a-form-item label="学校" v-bind="validateInfos.schoolId">
-          <a-select
-            v-model:value="userInfo.schoolId"
-            show-search
-            :disabled="!!userInfo.id"
-            :filterOption="false"
-            @search="(name:string) => querySchoolList(name,'form')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in userInfo.schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="姓名" v-bind="validateInfos.name">
-          <a-input
-            v-model:value="userInfo.name"
-            maxlength="50"
-            placeholder="请输入姓名"
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="登录名" v-bind="validateInfos.loginName">
-          <a-input
-            v-model:value="userInfo.loginName"
-            maxlength="11"
-            :placeholder="
-              userInfo.role === 'SECTION_LEADER'
-                ? '请输入登录手机号'
-                : '请输入登录名'
-            "
-          ></a-input>
-        </a-form-item>
-        <a-form-item
-          v-if="userInfo.role !== 'SECTION_LEADER' && !userInfo.id"
-          label="密码"
-          v-bind="validateInfos.passwd"
-        >
-          <a-input-password
-            v-model:value="userInfo.passwd"
-            placeholder="请输入密码"
-          ></a-input-password>
-        </a-form-item>
-        <a-form-item label="角色" v-bind="validateInfos.role">
-          <a-select v-model:value="userInfo.role" placeholder="请选择角色">
-            <a-select-option value="SCHOOL_ADMIN">{{
-              ROLE.SCHOOL_ADMIN
-            }}</a-select-option>
-            <a-select-option value="SECTION_LEADER">{{
-              ROLE.SECTION_LEADER
-            }}</a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item
-          v-if="userInfo.role === 'SECTION_LEADER'"
-          label="所属科目"
-          v-bind="validateInfos.course"
-        >
-          <a-textarea
-            v-model:value="userInfo.course"
-            placeholder="请填写所属科目代码, 以','分隔;"
-          ></a-textarea>
-        </a-form-item>
-      </a-form>
-    </a-modal>
-
-    <a-modal
-      v-model:visible="showResetPwdModal"
-      title="密码设置"
-      okText="确定"
-      cancelText="取消"
-      :maskClosable="false"
-      @ok="onUpdateUserPwd"
-      :afterClose="resetPwdFields"
-    >
-      <a-form :labelCol="{ span: 3 }">
-        <a-form-item label="密码" v-bind="validatePwdInfos.passwd">
-          <a-input-password v-model:value="resetPwd.passwd"></a-input-password>
-        </a-form-item>
-      </a-form>
-    </a-modal>
-
-    <a-modal
-      v-model:visible="showImportModal"
-      :maskClosable="false"
-      title="导入用户"
-      okText="确认上传"
-      cancelText="取消"
-      @ok="onImportUserList"
-      :afterClose="resetImportFields"
-    >
-      <a-form :labelCol="{ span: 6 }">
-        <a-form-item label="学校名称" v-bind="validateImportInfos.schoolId">
-          <a-select
-            v-model:value="importUserForm.schoolId"
-            show-search
-            :filterOption="false"
-            @search="(name: string) => querySchoolList(name,'import')"
-            placeholder="学校名称"
-          >
-            <a-select-option
-              v-for="school in importUserForm.schoolTableData.result"
-              :key="school.id"
-              :value="school.id"
-              >{{ school.name }}</a-select-option
-            >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="用户导入文件" v-bind="validateImportInfos.fileList">
-          <a-upload
-            :file-list="importUserForm.fileList"
-            :before-upload="beforeUpload"
-            @remove="handleRemove"
-            :max-count="1"
-            type="primary"
-          >
-            <a-button>
-              <upload-outlined></upload-outlined>
-              选择文件
-            </a-button>
-            <a class="tw-ml-4 tw-align-bottom" @click.stop="downloadTemplate">
-              下载导入模板
-            </a>
-          </a-upload>
-        </a-form-item>
-      </a-form>
-    </a-modal>
-  </div>
-</template>
-
-<script setup lang="ts" name="PageUsers">
-import { nextTick, reactive, ref, watch, markRaw } from "vue";
-import {
-  PlusCircleOutlined,
-  CheckCircleFilled,
-  CloseCircleFilled,
-  DownloadOutlined,
-} from "@ant-design/icons-vue";
-import {
-  getUserListHttp,
-  updateUserStatusHttp,
-  editUserInfoHttp,
-  resetUserPwdHttp,
-  importUserHttp,
-  downloadImportUserHttp,
-} from "@/apis/user";
-import Block from "@/components/block/index.vue";
-import { message } from "ant-design-vue";
-import { Form } from "ant-design-vue";
-import { getSchoolListHttp } from "@/apis/school";
-import type { UploadProps, TableColumnType } from "ant-design-vue";
-import { useMainStore } from "@/store/main";
-import { throttle } from "lodash-es";
-import { ROLE } from "@/constants/dicts";
-import { fileTypeCheck } from "@/utils/file-type";
-
-const mainStore = useMainStore();
-
-const showModal = ref(false);
-const showResetPwdModal = ref(false);
-const showImportModal = ref(false);
-
-const importUserForm = reactive<{
-  schoolId: string;
-  fileList: UploadProps["fileList"];
-  schoolTableData: MultiplePageData<SchoolListInfo>;
-}>({
-  schoolId: "",
-  fileList: [],
-  schoolTableData: { totalCount: 0, result: [] },
-});
-
-const importRules = {
-  schoolId: [{ required: true, message: "请选择学校" }],
-  fileList: [
-    { required: true, type: "array", len: 1, message: "请选择导入文件" },
-  ],
-};
-
-const userInfo = reactive<
-  EditUserInfo & { schoolTableData: MultiplePageData<SchoolListInfo> }
->({
-  schoolId: "",
-  name: "",
-  loginName: "",
-  course: "",
-  passwd: void 0,
-  role: void 0,
-  id: void 0,
-  schoolTableData: { totalCount: 0, result: [] },
-});
-
-const resetPwd = reactive({
-  passwd: "",
-  userId: "",
-});
-
-const editUserRules = () => ({
-  name: [{ required: true, message: "请填写用户姓名" }],
-  role: [{ required: true, message: "请选择用户角色" }],
-  loginName: [{ required: true, message: "请填写登录名" }],
-});
-
-const addUserRules = () => ({
-  schoolId: [{ required: true, message: "请选择用户所属学校" }],
-  passwd: [
-    { required: true, message: "请填写登录密码" },
-    {
-      pattern: /^[a-zA-Z0-9]{6,18}$/,
-      message: "密码只能由数字、字母组成,长度6-18个字符",
-    },
-  ],
-});
-
-const userRules = reactive({
-  ...addUserRules(),
-  ...editUserRules(),
-});
-
-const pwdRules = {
-  passwd: [
-    { required: true, message: "请填写登录密码" },
-    {
-      pattern: /^[a-zA-Z0-9]{6,18}$/,
-      message: "密码只能由数字、字母组成,长度6-18个字符",
-    },
-  ],
-};
-
-const {
-  validate,
-  validateInfos,
-  resetFields: resetUserFields,
-} = Form.useForm(userInfo, userRules);
-
-const {
-  validate: validatePwd,
-  validateInfos: validatePwdInfos,
-  resetFields: resetPwdFields,
-} = Form.useForm(resetPwd, pwdRules);
-
-const {
-  validate: validateImport,
-  validateInfos: validateImportInfos,
-  resetFields: resetImportFields,
-} = Form.useForm(importUserForm, importRules);
-
-/** 请求参数 */
-const query = reactive<FetchUserListQuery>({
-  loginName: "",
-  schoolId: mainStore.systemUserInfo?.schoolId || "",
-  role: void 0,
-  pageNumber: 1,
-  pageSize: 10,
-});
-
-/** table配置 */
-const columns: TableColumnType[] = [
-  { title: "序号", dataIndex: "index", align: "center", width: 60 },
-  { title: "ID", dataIndex: "id", width: 100, ellipsis: true },
-  { title: "姓名", dataIndex: "name", ellipsis: true },
-  { title: "登录名", dataIndex: "loginName", ellipsis: true },
-  {
-    title: "学校",
-    dataIndex: "schoolName",
-    align: "center",
-    ellipsis: true,
-  },
-  { title: "角色", dataIndex: "roleName", align: "center", width: 120 },
-  { title: "更新时间", dataIndex: "updateTime", width: 200, ellipsis: true },
-  { title: "状态", dataIndex: "enable", align: "center", width: 80 },
-  { title: "操作", dataIndex: "operation", width: 240 },
-];
-
-/** 用户列表信息 */
-const userTableData = reactive<MultiplePageData<UserInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 学校列表信息 */
-const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
-  totalCount: 0,
-  result: [],
-});
-
-/** 查询学校列表 */
-const querySchoolList = throttle(
-  async (name: string = "", type: "list" | "form" | "import" = "list") => {
-    const isList = type === "list";
-    const isForm = type === "form";
-    try {
-      const { result = [], totalCount } = await getSchoolListHttp({
-        name,
-        pageNumber: 1,
-        pageSize: 10,
-      });
-      Object.assign(
-        isList
-          ? schoolTableData
-          : isForm
-          ? userInfo.schoolTableData
-          : importUserForm.schoolTableData,
-        {
-          result,
-          totalCount,
-        }
-      );
-    } catch (error) {
-      return Promise.reject(error);
-    }
-  },
-  100
-);
-
-/** 显示新增用户弹窗 */
-const toggleAddUserModal = (show: boolean = true) => {
-  if (show) {
-    if (userInfo.id) {
-      Object.assign(userRules, { schoolId: [], passwd: [] });
-    } else {
-      Object.assign(userRules, { ...addUserRules() });
-      Object.assign(userInfo, {
-        schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
-      });
-    }
-    querySchoolList("", "form");
-  }
-  nextTick(() => {
-    showModal.value = show;
-  });
-};
-
-/** 查询用户列表 */
-const queryUserList = async () => {
-  try {
-    const { result = [], totalCount } = await getUserListHttp(query);
-    Object.assign(userTableData, { result, totalCount });
-  } catch (error) {
-    console.error(error);
-  }
-};
-
-watch(() => query.pageNumber, queryUserList);
-
-/* 启用/禁用 */
-const updateUserStatus = (record: UserInfo) => {
-  updateUserStatusHttp({ enable: !record.enable, ids: [record.id] }).then(
-    queryUserList
-  );
-};
-
-/** 编辑用户 */
-const onEdit = (record: UserInfo) => {
-  Object.assign(userInfo, {
-    course: record.courseCodes?.join(","),
-    id: record.id,
-    schoolId: record.schoolId,
-    name: record.name,
-    loginName: record.loginName,
-    role: record.role,
-  });
-  toggleAddUserModal(true);
-};
-
-/** 重置密码 */
-const onResetPwd = (record: UserInfo) => {
-  Object.assign(resetPwd, { passwd: "", userId: `${record.id}` });
-  showResetPwdModal.value = true;
-};
-
-/** 新增用户 */
-const onPutUser = () => {
-  const role = userInfo.role;
-  const isEdit = !!userInfo.id;
-  if (role === "SECTION_LEADER") {
-    Object.assign(userRules, {
-      loginName: [
-        { required: true, message: "请填写登录手机号" },
-        // @ts-ignore
-        { pattern: /\d{11}/, message: "请填写正确的手机号" },
-      ],
-      passwd: []
-    });
-  } else {
-    Object.assign(userRules, {
-      loginName: [{ required: true, message: "请填写登录名" }],
-    });
-  }
-  validate().then((valid) => {
-    if (valid) {
-      const { role, course, schoolTableData, passwd,...info } = userInfo;
-      editUserInfoHttp({
-        ...info,
-        role,
-        passwd: role === "SECTION_LEADER" ? "" : passwd,
-        course: role === "SECTION_LEADER" ? course : "",
-      }).then(() => {
-        message.success(`${isEdit ? "修改" : "添加"}成功`);
-        queryUserList();
-        toggleAddUserModal(false);
-      });
-    }
-  }).catch(()=>{
-    if (userInfo.id) {
-      Object.assign(userRules, { schoolId: [], passwd: [] });
-    } else {
-      Object.assign(userRules, { ...addUserRules() });
-    }
-  });
-};
-
-/** 导入用户 */
-const importUserList = () => {
-  showImportModal.value = true;
-  Object.assign(importUserForm, {
-    schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
-  });
-  querySchoolList("", "import");
-};
-
-const handleRemove: UploadProps["onRemove"] = (file) => {
-  const index = importUserForm.fileList!.indexOf(file);
-  const newFileList = importUserForm.fileList!.slice();
-  newFileList.splice(index, 1);
-  importUserForm.fileList = newFileList;
-};
-
-const beforeUpload: UploadProps["beforeUpload"] = async (file) => {
-  await fileTypeCheck(file, ["xls", "xlsx"]).catch((error) => {
-    message.error("文件类型错误, 请使用导入模板编辑");
-    return Promise.reject(error);
-  });
-  importUserForm.fileList = [file];
-  return false;
-};
-
-/** 下载导入模板 */
-const downloadTemplate = async () => {
-  try {
-    await downloadImportUserHttp();
-  } catch (error) {
-    return Promise.reject(error);
-  }
-};
-
-const onImportUserList = async () => {
-  try {
-    const valid = await validateImport();
-    if (valid) {
-      const formData = new FormData();
-      formData.append("schoolId", `${importUserForm.schoolId}`);
-      importUserForm.fileList?.forEach((file: any) => {
-        formData.append("file", file);
-      });
-      await importUserHttp(formData);
-      queryUserList();
-      showImportModal.value = false;
-    }
-  } catch (error) {
-    return Promise.reject(error);
-  }
-};
-
-/** 修改密码 */
-const onUpdateUserPwd = () => {
-  validatePwd().then((valid) => {
-    if (valid) {
-      resetUserPwdHttp(resetPwd).then(() => {
-        message.success(`重置成功`);
-        showResetPwdModal.value = false;
-      });
-    }
-  });
-};
-
-const currentPageChange = ({ current }: { current: number }) => {
-  query.pageNumber = current;
-};
-
-querySchoolList();
-
-/** effect */
-if (query.schoolId) {
-  queryUserList();
-}
-</script>
-
-<style scoped lang="less">
-.user-manage {
-  .header-block {
-    .ant-input {
-      width: 160px;
-    }
-    :deep(.ant-select-selector) {
-      width: 160px;
-    }
-    .search-button {
-      background-color: @font-color;
-      color: @white;
-      border: none;
-      width: 56px;
-      padding: 0;
-      &:after {
-        display: none;
-        opacity: 0;
-      }
-    }
-
-    .operation-button {
-      width: 72px;
-      padding: 0;
-      margin-left: auto;
-      & ~ .operation-button {
-        margin-left: 8px;
-      }
-    }
-  }
-  .user-table {
-  }
-}
-</style>
+<template>
+  <div class="user-manage">
+    <Block class="header-block tw-flex tw-items-center">
+      <a-form layout="inline">
+        <a-form-item label="学校名称">
+          <a-select
+            v-model:value="query.schoolId"
+            show-search
+            :filterOption="false"
+            @search="(name:string) => querySchoolList(name,'list')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="登录名">
+          <a-input
+            v-model:value="query.loginName"
+            maxlength="50"
+            placeholder="登录名"
+          ></a-input>
+        </a-form-item>
+        <a-form-item label="角色">
+          <a-select v-model:value="query.role" placeholder="用户角色">
+            <a-select-option :value="void 0">全部</a-select-option>
+            <a-select-option value="SCHOOL_ADMIN">{{
+              ROLE.SCHOOL_ADMIN
+            }}</a-select-option>
+            <a-select-option value="SECTION_LEADER">{{
+              ROLE.SECTION_LEADER
+            }}</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item>
+          <a-button class="search-button" type="primary" @click="queryUserList"
+            >查询</a-button
+          >
+        </a-form-item>
+      </a-form>
+      <a-button
+        type="primary"
+        class="tw-flex tw-items-center operation-button"
+        @click="toggleAddUserModal"
+      >
+        <template #icon>
+          <PlusCircleOutlined />
+        </template>
+        新增
+      </a-button>
+      <a-button
+        type="primary"
+        class="tw-flex tw-items-center operation-button"
+        @click="importUserList"
+      >
+        <template #icon>
+          <DownloadOutlined />
+        </template>
+        导入
+      </a-button>
+    </Block>
+    <Block class="user-table">
+      <a-table
+        :columns="columns"
+        :data-source="userTableData.result"
+        :pagination="{
+          total: userTableData.totalCount,
+          pageSize: query.pageSize,
+        }"
+        @change="currentPageChange"
+        :row-class-name="
+          (_:any, index:number) => (index % 2 === 1 ? 'table-striped' : null)
+        "
+      >
+        <template #bodyCell="{ column, record, index }">
+          <template v-if="column.dataIndex === 'index'">
+            {{ index + 1 }}
+          </template>
+          <template v-else-if="column.dataIndex === 'enable'">
+            <template v-if="record.enable">
+              <CheckCircleFilled style="color: #30bf78" />
+            </template>
+            <template v-else>
+              <CloseCircleFilled style="color: #f4664a" />
+            </template>
+          </template>
+          <template v-else-if="column.dataIndex === 'courseCodes'">
+            {{record.courseCodes.join('、')}}
+          </template>
+          <template v-else-if="column.dataIndex === 'operation'">
+            <div
+              class="tw-flex tw-items-center"
+              v-if="record.role !== 'SUPER_ADMIN'"
+            >
+              <span
+                class="tw-cursor-pointer tw-p-2"
+                @click="updateUserStatus(record)"
+                >{{ record.enable ? "禁用" : "启用" }}</span
+              >
+              <span
+                class="tw-cursor-pointer tw-p-2 tw-ml-1"
+                @click="onEdit(record)"
+                >编辑</span
+              >
+              <span
+                class="tw-cursor-pointer tw-p-2 tw-ml-1"
+                @click="onResetPwd(record)"
+                >重置密码
+              </span>
+            </div>
+          </template>
+        </template>
+      </a-table>
+    </Block>
+    <a-modal
+      v-model:visible="showModal"
+      :title="`${!userInfo.id ? '新增' : '编辑'}用户`"
+      okText="确定"
+      cancelText="取消"
+      :maskClosable="false"
+      @ok="onPutUser"
+      :afterClose="resetUserFields"
+    >
+      <a-form :labelCol="{ span: 6 }">
+        <a-form-item label="学校" v-bind="validateInfos.schoolId">
+          <a-select
+            v-model:value="userInfo.schoolId"
+            show-search
+            :disabled="!!userInfo.id"
+            :filterOption="false"
+            @search="(name:string) => querySchoolList(name,'form')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in userInfo.schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="姓名" v-bind="validateInfos.name">
+          <a-input
+            v-model:value="userInfo.name"
+            maxlength="50"
+            placeholder="请输入姓名"
+          ></a-input>
+        </a-form-item>
+        <a-form-item label="登录名" v-bind="validateInfos.loginName">
+          <a-input
+            v-model:value="userInfo.loginName"
+            maxlength="11"
+            :placeholder="
+              userInfo.role === 'SECTION_LEADER'
+                ? '请输入登录手机号'
+                : '请输入登录名'
+            "
+          ></a-input>
+        </a-form-item>
+        <a-form-item
+          v-if="userInfo.role !== 'SECTION_LEADER' && !userInfo.id"
+          label="密码"
+          v-bind="validateInfos.passwd"
+        >
+          <a-input-password
+            v-model:value="userInfo.passwd"
+            placeholder="请输入密码"
+          ></a-input-password>
+        </a-form-item>
+        <a-form-item label="角色" v-bind="validateInfos.role">
+          <a-select v-model:value="userInfo.role" placeholder="请选择角色">
+            <a-select-option value="SCHOOL_ADMIN">{{
+              ROLE.SCHOOL_ADMIN
+            }}</a-select-option>
+            <a-select-option value="SECTION_LEADER">{{
+              ROLE.SECTION_LEADER
+            }}</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item
+          v-if="userInfo.role === 'SECTION_LEADER'"
+          label="所属科目"
+          v-bind="validateInfos.course"
+        >
+          <a-textarea
+            v-model:value="userInfo.course"
+            placeholder="请填写所属科目代码, 以','分隔;"
+          ></a-textarea>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+
+    <a-modal
+      v-model:visible="showResetPwdModal"
+      title="密码设置"
+      okText="确定"
+      cancelText="取消"
+      :maskClosable="false"
+      @ok="onUpdateUserPwd"
+      :afterClose="resetPwdFields"
+    >
+      <a-form :labelCol="{ span: 3 }">
+        <a-form-item label="密码" v-bind="validatePwdInfos.passwd">
+          <a-input-password v-model:value="resetPwd.passwd"></a-input-password>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+
+    <a-modal
+      v-model:visible="showImportModal"
+      :maskClosable="false"
+      title="导入用户"
+      okText="确认上传"
+      cancelText="取消"
+      @ok="onImportUserList"
+      :afterClose="resetImportFields"
+    >
+      <a-form :labelCol="{ span: 6 }">
+        <a-form-item label="学校名称" v-bind="validateImportInfos.schoolId">
+          <a-select
+            v-model:value="importUserForm.schoolId"
+            show-search
+            :filterOption="false"
+            @search="(name: string) => querySchoolList(name,'import')"
+            placeholder="学校名称"
+          >
+            <a-select-option
+              v-for="school in importUserForm.schoolTableData.result"
+              :key="school.id"
+              :value="school.id"
+              >{{ school.name }}</a-select-option
+            >
+          </a-select>
+        </a-form-item>
+        <a-form-item label="用户导入文件" v-bind="validateImportInfos.fileList">
+          <a-upload
+            :file-list="importUserForm.fileList"
+            :before-upload="beforeUpload"
+            @remove="handleRemove"
+            :max-count="1"
+            type="primary"
+          >
+            <a-button>
+              <upload-outlined></upload-outlined>
+              选择文件
+            </a-button>
+            <a class="tw-ml-4 tw-align-bottom" @click.stop="downloadTemplate">
+              下载导入模板
+            </a>
+          </a-upload>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+  </div>
+</template>
+
+<script setup lang="ts" name="PageUsers">
+import { nextTick, reactive, ref, watch, markRaw } from "vue";
+import {
+  PlusCircleOutlined,
+  CheckCircleFilled,
+  CloseCircleFilled,
+  DownloadOutlined,
+} from "@ant-design/icons-vue";
+import {
+  getUserListHttp,
+  updateUserStatusHttp,
+  editUserInfoHttp,
+  resetUserPwdHttp,
+  importUserHttp,
+  downloadImportUserHttp,
+} from "@/apis/user";
+import Block from "@/components/block/index.vue";
+import { message } from "ant-design-vue";
+import { Form } from "ant-design-vue";
+import { getSchoolListHttp } from "@/apis/school";
+import type { UploadProps, TableColumnType } from "ant-design-vue";
+import { useMainStore } from "@/store/main";
+import { throttle } from "lodash-es";
+import { ROLE } from "@/constants/dicts";
+import { fileTypeCheck } from "@/utils/file-type";
+
+const mainStore = useMainStore();
+
+const showModal = ref(false);
+const showResetPwdModal = ref(false);
+const showImportModal = ref(false);
+
+const importUserForm = reactive<{
+  schoolId: string;
+  fileList: UploadProps["fileList"];
+  schoolTableData: MultiplePageData<SchoolListInfo>;
+}>({
+  schoolId: "",
+  fileList: [],
+  schoolTableData: { totalCount: 0, result: [] },
+});
+
+const importRules = {
+  schoolId: [{ required: true, message: "请选择学校" }],
+  fileList: [
+    { required: true, type: "array", len: 1, message: "请选择导入文件" },
+  ],
+};
+
+const userInfo = reactive<
+  EditUserInfo & { schoolTableData: MultiplePageData<SchoolListInfo> }
+>({
+  schoolId: "",
+  name: "",
+  loginName: "",
+  course: "",
+  passwd: void 0,
+  role: void 0,
+  id: void 0,
+  schoolTableData: { totalCount: 0, result: [] },
+});
+
+const resetPwd = reactive({
+  passwd: "",
+  userId: "",
+});
+
+const editUserRules = () => ({
+  name: [{ required: true, message: "请填写用户姓名" }],
+  role: [{ required: true, message: "请选择用户角色" }],
+  loginName: [{ required: true, message: "请填写登录名" }],
+});
+
+const addUserRules = () => ({
+  schoolId: [{ required: true, message: "请选择用户所属学校" }],
+  passwd: [
+    { required: true, message: "请填写登录密码" },
+    {
+      pattern: /^[a-zA-Z0-9]{6,18}$/,
+      message: "密码只能由数字、字母组成,长度6-18个字符",
+    },
+  ],
+});
+
+const userRules = reactive({
+  ...addUserRules(),
+  ...editUserRules(),
+});
+
+const pwdRules = {
+  passwd: [
+    { required: true, message: "请填写登录密码" },
+    {
+      pattern: /^[a-zA-Z0-9]{6,18}$/,
+      message: "密码只能由数字、字母组成,长度6-18个字符",
+    },
+  ],
+};
+
+const {
+  validate,
+  validateInfos,
+  resetFields: resetUserFields,
+} = Form.useForm(userInfo, userRules);
+
+const {
+  validate: validatePwd,
+  validateInfos: validatePwdInfos,
+  resetFields: resetPwdFields,
+} = Form.useForm(resetPwd, pwdRules);
+
+const {
+  validate: validateImport,
+  validateInfos: validateImportInfos,
+  resetFields: resetImportFields,
+} = Form.useForm(importUserForm, importRules);
+
+/** 请求参数 */
+const query = reactive<FetchUserListQuery>({
+  loginName: "",
+  // schoolId: mainStore.systemUserInfo?.schoolId || "",
+  schoolId: "",
+  role: void 0,
+  pageNumber: 1,
+  pageSize: 10,
+});
+
+/** table配置 */
+const columns: TableColumnType[] = [
+  { title: "序号", dataIndex: "index", align: "center", width: 60 },
+  { title: "ID", dataIndex: "id", width: 100, ellipsis: true },
+  { title: "姓名", dataIndex: "name", ellipsis: true },
+  { title: "登录名", dataIndex: "loginName", ellipsis: true },
+  {
+    title: "学校",
+    dataIndex: "schoolName",
+    align: "center",
+    ellipsis: true,
+  },
+  { title: "角色", dataIndex: "roleName", align: "center", width: 120 },
+  { title: "科目代码", dataIndex: "courseCodes", align: "center", minWidth: 80 },
+  { title: "更新时间", dataIndex: "updateTime", width: 200, ellipsis: true },
+  { title: "状态", dataIndex: "enable", align: "center", width: 80 },
+  { title: "操作", dataIndex: "operation", width: 240 },
+];
+
+/** 用户列表信息 */
+const userTableData = reactive<MultiplePageData<UserInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 学校列表信息 */
+const schoolTableData = reactive<MultiplePageData<SchoolListInfo>>({
+  totalCount: 0,
+  result: [],
+});
+
+/** 查询学校列表 */
+const querySchoolList = throttle(
+  async (name: string = "", type: "list" | "form" | "import" = "list") => {
+    const isList = type === "list";
+    const isForm = type === "form";
+    try {
+      const { result = [], totalCount } = await getSchoolListHttp({
+        name,
+        pageNumber: 1,
+        pageSize: 10,
+      });
+      Object.assign(
+        isList
+          ? schoolTableData
+          : isForm
+          ? userInfo.schoolTableData
+          : importUserForm.schoolTableData,
+        {
+          result,
+          totalCount,
+        }
+      );
+    } catch (error) {
+      return Promise.reject(error);
+    }
+  },
+  100
+);
+
+/** 显示新增用户弹窗 */
+const toggleAddUserModal = (show: boolean = true) => {
+  if (show) {
+    if (userInfo.id) {
+      Object.assign(userRules, { schoolId: [], passwd: [] });
+    } else {
+      Object.assign(userRules, { ...addUserRules() });
+      Object.assign(userInfo, {
+        schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
+      });
+    }
+    querySchoolList("", "form");
+  }
+  nextTick(() => {
+    showModal.value = show;
+  });
+};
+
+/** 查询用户列表 */
+const queryUserList = async () => {
+  try {
+    const { result = [], totalCount } = await getUserListHttp(query);
+    Object.assign(userTableData, { result, totalCount });
+  } catch (error) {
+    console.error(error);
+  }
+};
+
+watch(() => query.pageNumber, queryUserList);
+
+/* 启用/禁用 */
+const updateUserStatus = (record: UserInfo) => {
+  updateUserStatusHttp({ enable: !record.enable, ids: [record.id] }).then(
+    queryUserList
+  );
+};
+
+/** 编辑用户 */
+const onEdit = (record: UserInfo) => {
+  Object.assign(userInfo, {
+    course: record.courseCodes?.join(","),
+    id: record.id,
+    schoolId: record.schoolId,
+    name: record.name,
+    loginName: record.loginName,
+    role: record.role,
+  });
+  toggleAddUserModal(true);
+};
+
+/** 重置密码 */
+const onResetPwd = (record: UserInfo) => {
+  Object.assign(resetPwd, { passwd: "", userId: `${record.id}` });
+  showResetPwdModal.value = true;
+};
+
+/** 新增用户 */
+const onPutUser = () => {
+  const role = userInfo.role;
+  const isEdit = !!userInfo.id;
+  if (role === "SECTION_LEADER") {
+    Object.assign(userRules, {
+      loginName: [
+        { required: true, message: "请填写登录手机号" },
+        // @ts-ignore
+        { pattern: /\d{11}/, message: "请填写正确的手机号" },
+      ],
+      passwd: []
+    });
+  } else {
+    Object.assign(userRules, {
+      loginName: [{ required: true, message: "请填写登录名" }],
+    });
+  }
+  validate().then((valid) => {
+    if (valid) {
+      const { role, course, schoolTableData, passwd,...info } = userInfo;
+      editUserInfoHttp({
+        ...info,
+        role,
+        passwd: role === "SECTION_LEADER" ? "" : passwd,
+        course: role === "SECTION_LEADER" ? course : "",
+      }).then(() => {
+        message.success(`${isEdit ? "修改" : "添加"}成功`);
+        queryUserList();
+        toggleAddUserModal(false);
+      });
+    }
+  }).catch(()=>{
+    if (userInfo.id) {
+      Object.assign(userRules, { schoolId: [], passwd: [] });
+    } else {
+      Object.assign(userRules, { ...addUserRules() });
+    }
+  });
+};
+
+/** 导入用户 */
+const importUserList = () => {
+  showImportModal.value = true;
+  Object.assign(importUserForm, {
+    schoolId: query.schoolId || mainStore.systemUserInfo?.schoolId,
+  });
+  querySchoolList("", "import");
+};
+
+const handleRemove: UploadProps["onRemove"] = (file) => {
+  const index = importUserForm.fileList!.indexOf(file);
+  const newFileList = importUserForm.fileList!.slice();
+  newFileList.splice(index, 1);
+  importUserForm.fileList = newFileList;
+};
+
+const beforeUpload: UploadProps["beforeUpload"] = async (file) => {
+  await fileTypeCheck(file, ["xls", "xlsx"]).catch((error) => {
+    message.error("文件类型错误, 请使用导入模板编辑");
+    return Promise.reject(error);
+  });
+  importUserForm.fileList = [file];
+  return false;
+};
+
+/** 下载导入模板 */
+const downloadTemplate = async () => {
+  try {
+    await downloadImportUserHttp();
+  } catch (error) {
+    return Promise.reject(error);
+  }
+};
+
+const onImportUserList = async () => {
+  try {
+    const valid = await validateImport();
+    if (valid) {
+      const formData = new FormData();
+      formData.append("schoolId", `${importUserForm.schoolId}`);
+      importUserForm.fileList?.forEach((file: any) => {
+        formData.append("file", file);
+      });
+      await importUserHttp(formData);
+      queryUserList();
+      showImportModal.value = false;
+    }
+  } catch (error) {
+    return Promise.reject(error);
+  }
+};
+
+/** 修改密码 */
+const onUpdateUserPwd = () => {
+  validatePwd().then((valid) => {
+    if (valid) {
+      resetUserPwdHttp(resetPwd).then(() => {
+        message.success(`重置成功`);
+        showResetPwdModal.value = false;
+      });
+    }
+  });
+};
+
+const currentPageChange = ({ current }: { current: number }) => {
+  query.pageNumber = current;
+};
+
+querySchoolList();
+
+/** effect */
+if (query.schoolId) {
+  queryUserList();
+}
+</script>
+
+<style scoped lang="less">
+.user-manage {
+  .header-block {
+    .ant-input {
+      width: 160px;
+    }
+    :deep(.ant-select-selector) {
+      width: 160px;
+    }
+    .search-button {
+      background-color: @font-color;
+      color: @white;
+      border: none;
+      width: 56px;
+      padding: 0;
+      &:after {
+        display: none;
+        opacity: 0;
+      }
+    }
+
+    .operation-button {
+      width: 72px;
+      padding: 0;
+      margin-left: auto;
+      & ~ .operation-button {
+        margin-left: 8px;
+      }
+    }
+  }
+  .user-table {
+  }
+}
+</style>