42cdb857764765ed2e8ae8c549a90ae88d3643d0..024369b323338e10d39cce09befab18087675139
2026-09-24 wangrong
修改bug,首页改用真实数据
024369 对比 | 目录
2026-09-24 wangrong
bug修复,用真实数据
bf9400 对比 | 目录
41个文件已修改
1个文件已删除
2个文件已添加
2375 ■■■■■ 已修改文件
index.html 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 857 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server.cjs 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/config.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/error/components/error-page.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/login/index.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/main/components/amenu.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/main/components/process.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/main/components/topbar.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/main/components/views.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/pages/main/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/static/css/index.scss 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/base/static/css/mobile.scss 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/ezuikit/components/ezuikit-player.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/maps/components/map-board.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/monitor/views/cameras.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/monitor/views/device.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/operation/views/traderecord.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/operation/views/wastesale.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/auditlog.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/cameragps.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/compressionweight.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/devicealarm.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/deviceonoff.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/siteweight.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/vehiclegps.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/push/views/weight.vue 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/components/panel-card.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/components/screen-map-panel.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/components/screen-shell.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/data/screen-demo.ts 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/data/screen-merge.ts 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/hooks/use-screen.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/dailydepartment.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/dailysite.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/dailyvehicle.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/joblog.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/screen/carbon.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/screen/map.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/screen/operation.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/screen/overview.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/modules/report/views/screen/participation.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/view/components/group.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html
@@ -7,8 +7,9 @@
        <meta name="renderer" content="webkit" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"
            content="width=device-width, initial-scale=1, viewport-fit=cover"
        />
        <meta name="format-detection" content="telephone=no" />
        <title></title>
        <link rel="icon" href="./favicon.ico" />
        <style>
package.json
@@ -24,8 +24,10 @@
        "dayjs": "^1.11.13",
        "echarts": "^5.6.0",
        "element-plus": "2.10.2",
        "express": "^5.2.1",
        "ezuikit-js": "^9.0.15",
        "file-saver": "^2.0.5",
        "http-proxy-middleware": "^4.2.0",
        "lodash-es": "^4.17.21",
        "marked": "^14.1.3",
        "mitt": "^3.0.1",
pnpm-lock.yaml
@@ -25,7 +25,7 @@
        version: 5.1.12(@wangeditor/editor@5.1.23)(vue@3.5.13(typescript@5.5.4))
      axios:
        specifier: ^1.7.9
        version: 1.7.9
        version: 1.7.9(debug@4.4.3(supports-color@7.2.0))
      chardet:
        specifier: ^2.0.0
        version: 2.0.0
@@ -41,12 +41,18 @@
      element-plus:
        specifier: 2.10.2
        version: 2.10.2(vue@3.5.13(typescript@5.5.4))
      express:
        specifier: ^5.2.1
        version: 5.2.1(supports-color@7.2.0)
      ezuikit-js:
        specifier: ^9.0.15
        version: 9.0.17
      file-saver:
        specifier: ^2.0.5
        version: 2.0.5
      http-proxy-middleware:
        specifier: ^4.2.0
        version: 4.2.0(supports-color@7.2.0)
      lodash-es:
        specifier: ^4.17.21
        version: 4.17.21
@@ -64,7 +70,7 @@
        version: 2.3.1(typescript@5.5.4)(vue@3.5.13(typescript@5.5.4))
      socket.io-client:
        specifier: ^4.7.2
        version: 4.8.1
        version: 4.8.1(supports-color@7.2.0)
      store:
        specifier: ^2.0.12
        version: 2.0.12
@@ -92,10 +98,10 @@
    devDependencies:
      '@cool-vue/vite-plugin':
        specifier: ^8.2.2
        version: 8.2.20
        version: 8.2.20(debug@4.4.3(supports-color@7.2.0))
      '@intlify/unplugin-vue-i18n':
        specifier: ^6.0.3
        version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@1.21.7))(rollup@4.34.8)(typescript@5.5.4)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))
        version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(rollup@4.34.8)(supports-color@7.2.0)(typescript@5.5.4)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))
      '@rushstack/eslint-patch':
        specifier: ^1.10.5
        version: 1.10.5
@@ -125,16 +131,16 @@
        version: 5.2.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
      '@vitejs/plugin-vue-jsx':
        specifier: ^4.1.1
        version: 4.1.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
        version: 4.1.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
      '@vue/compiler-sfc':
        specifier: ^3.5.13
        version: 3.5.13
      '@vue/eslint-config-prettier':
        specifier: ^10.2.0
        version: 10.2.0(eslint@9.20.1(jiti@1.21.7))(prettier@3.5.1)
        version: 10.2.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.5.1)
      '@vue/eslint-config-typescript':
        specifier: ^14.3.0
        version: 14.4.0(eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)))(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
        version: 14.4.0(eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@vue/test-utils':
        specifier: ^2.4.6
        version: 2.4.6
@@ -146,13 +152,13 @@
        version: 10.4.20(postcss@8.5.2)
      eslint:
        specifier: ^9.19.0
        version: 9.20.1(jiti@1.21.7)
        version: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      eslint-plugin-prettier:
        specifier: ^5.2.3
        version: 5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)))(eslint@9.20.1(jiti@1.21.7))(prettier@3.5.1)
        version: 5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0)))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.5.1)
      eslint-plugin-vue:
        specifier: ^9.32.0
        version: 9.32.0(eslint@9.20.1(jiti@1.21.7))
        version: 9.32.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)
      postcss:
        specifier: ^8.5.1
        version: 8.5.2
@@ -179,10 +185,10 @@
        version: 5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)
      vite-plugin-compression:
        specifier: ^0.5.1
        version: 0.5.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
        version: 0.5.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
      vite-plugin-vue-devtools:
        specifier: ^7.7.1
        version: 7.7.2(rollup@4.34.8)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
        version: 7.7.2(rollup@4.34.8)(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
      vue-tsc:
        specifier: ^2.2.0
        version: 2.2.2(typescript@5.5.4)
@@ -626,8 +632,8 @@
    resolution: {integrity: sha512-2kGiWoXaeV8HZlhU/Nml12oTbhv7j2ufsJ5vQaa0VTjzUmZVdd/nmKFRAOJ/FtjO90Qba5AnZDwsrY7ZND5udA==}
    engines: {node: '>= 16'}
  '@intlify/shared@11.4.8':
    resolution: {integrity: sha512-XbRgrv+XEuvDr7UCY55oibVrh+o4u+A0VB6nSL0F5Z8LcZxE/8j573LYG6bCrOigIcHdGpSNI7Rh5UpC5/B/eg==}
  '@intlify/shared@11.4.12':
    resolution: {integrity: sha512-ojfehaXMFrGFcSnK3cJPaMxlrSXT8FwZUG9H4i+WKX4OFD4Yl1WKdTmfwoC0REnwIfTrnt1QhRtd8kwi/te6bQ==}
    engines: {node: '>= 22'}
  '@intlify/shared@12.0.0-alpha.4':
@@ -937,9 +943,6 @@
  '@socket.io/component-emitter@3.1.2':
    resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
  '@sxzz/popperjs-es@2.11.7':
    resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
  '@sxzz/popperjs-es@2.11.8':
    resolution: {integrity: sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==}
@@ -1081,6 +1084,11 @@
  '@volar/typescript@2.4.11':
    resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==}
    peerDependencies:
      typescript: '*'
    peerDependenciesMeta:
      typescript:
        optional: true
  '@vue/babel-helper-vue-transform-on@1.2.5':
    resolution: {integrity: sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==}
@@ -1300,6 +1308,10 @@
  abortcontroller-polyfill@1.7.8:
    resolution: {integrity: sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ==}
  accepts@2.0.0:
    resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
    engines: {node: '>= 0.6'}
  acorn-jsx@5.3.2:
    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
    peerDependencies:
@@ -1375,6 +1387,10 @@
  birpc@0.2.19:
    resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==}
  body-parser@2.3.0:
    resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
    engines: {node: '>=18'}
  boolbase@1.0.0:
    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
@@ -1400,8 +1416,16 @@
    resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
    engines: {node: '>=18'}
  bytes@3.1.2:
    resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
    engines: {node: '>= 0.8'}
  call-bind-apply-helpers@1.0.2:
    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
    engines: {node: '>= 0.4'}
  call-bound@1.0.4:
    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
    engines: {node: '>= 0.4'}
  callsites@3.1.0:
@@ -1480,8 +1504,28 @@
  config-chain@1.1.13:
    resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
  content-disposition@1.1.0:
    resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==}
    engines: {node: '>=18'}
  content-type@1.0.5:
    resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
    engines: {node: '>= 0.6'}
  content-type@2.1.0:
    resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==}
    engines: {node: '>=18'}
  convert-source-map@2.0.0:
    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
  cookie-signature@1.2.2:
    resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
    engines: {node: '>=6.6.0'}
  cookie@0.7.2:
    resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
    engines: {node: '>= 0.6'}
  copy-anything@3.0.5:
    resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
@@ -1560,6 +1604,15 @@
      supports-color:
        optional: true
  debug@4.4.3:
    resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
    engines: {node: '>=6.0'}
    peerDependencies:
      supports-color: '*'
    peerDependenciesMeta:
      supports-color:
        optional: true
  deep-is@0.1.4:
    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -1586,6 +1639,10 @@
  delayed-stream@1.0.0:
    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
    engines: {node: '>=0.4.0'}
  depd@2.0.0:
    resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
    engines: {node: '>= 0.8'}
  detect-libc@1.0.3:
    resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
@@ -1629,6 +1686,9 @@
    engines: {node: '>=14'}
    hasBin: true
  ee-first@1.1.1:
    resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
  electron-to-chromium@1.5.102:
    resolution: {integrity: sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==}
@@ -1647,6 +1707,10 @@
  emoji-regex@9.2.2:
    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
  encodeurl@2.0.0:
    resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
    engines: {node: '>= 0.8'}
  engine.io-client@6.6.3:
    resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==}
@@ -1755,6 +1819,7 @@
  eslint@9.20.1:
    resolution: {integrity: sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==}
    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
    deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
    hasBin: true
    peerDependencies:
      jiti: '*'
@@ -1798,6 +1863,10 @@
    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
    engines: {node: '>=0.10.0'}
  etag@1.8.1:
    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
    engines: {node: '>= 0.6'}
  event-emitter@0.3.5:
    resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
@@ -1807,6 +1876,10 @@
  execa@9.5.2:
    resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==}
    engines: {node: ^18.19.0 || >=20.5.0}
  express@5.2.1:
    resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
    engines: {node: '>= 18'}
  ext@1.7.0:
    resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
@@ -1852,6 +1925,10 @@
    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
    engines: {node: '>=8'}
  finalhandler@2.1.1:
    resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
    engines: {node: '>= 18.0.0'}
  find-up@5.0.0:
    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
    engines: {node: '>=10'}
@@ -1884,12 +1961,20 @@
    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
    engines: {node: '>=12.20.0'}
  forwarded@0.2.0:
    resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
    engines: {node: '>= 0.6'}
  frac@1.1.2:
    resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
    engines: {node: '>=0.8'}
  fraction.js@4.3.7:
    resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
  fresh@2.0.0:
    resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
    engines: {node: '>= 0.8'}
  fs-extra@10.1.0:
    resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
@@ -1917,6 +2002,10 @@
  get-intrinsic@1.2.7:
    resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
    engines: {node: '>= 0.4'}
  get-intrinsic@1.3.0:
    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
    engines: {node: '>= 0.4'}
  get-proto@1.0.1:
@@ -1992,12 +2081,27 @@
  html-void-elements@2.0.1:
    resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
  http-errors@2.0.1:
    resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
    engines: {node: '>= 0.8'}
  http-proxy-middleware@4.2.0:
    resolution: {integrity: sha512-ZA+oNOoM+GLoFTIzhkJptVQov73Srep2LBqhF8hG8CIPKO3nam1jonXVQ/QUH8RbwsmaaVz2SOJdzBNBHNtKbw==}
    engines: {node: ^22.15.0 || ^24.0.0 || >=26.0.0}
  httpxy@0.5.5:
    resolution: {integrity: sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==}
  human-signals@8.0.0:
    resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==}
    engines: {node: '>=18.18.0'}
  i18next@20.6.1:
    resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
  iconv-lite@0.7.3:
    resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==}
    engines: {node: '>=0.10.0'}
  ignore@5.3.2:
    resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
@@ -2017,8 +2121,15 @@
    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
    engines: {node: '>=0.8.19'}
  inherits@2.0.4:
    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
  ini@1.3.8:
    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
  ipaddr.js@1.9.1:
    resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
    engines: {node: '>= 0.10'}
  is-binary-path@2.1.0:
    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
@@ -2069,6 +2180,9 @@
  is-plain-object@5.0.0:
    resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
    engines: {node: '>=0.10.0'}
  is-promise@4.0.0:
    resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
  is-stream@4.0.1:
    resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
@@ -2234,8 +2348,16 @@
  mdn-data@2.0.30:
    resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
  media-typer@1.1.1:
    resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==}
    engines: {node: '>= 0.8'}
  memoize-one@6.0.0:
    resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
  merge-descriptors@2.0.0:
    resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
    engines: {node: '>=18'}
  merge2@1.4.1:
    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
@@ -2249,12 +2371,20 @@
    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
    engines: {node: '>= 0.6'}
  mime-db@1.54.0:
    resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
    engines: {node: '>= 0.6'}
  mime-match@1.0.2:
    resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
  mime-types@2.1.35:
    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
    engines: {node: '>= 0.6'}
  mime-types@3.0.2:
    resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
    engines: {node: '>=18'}
  minimatch@3.1.2:
    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -2306,6 +2436,10 @@
  natural-compare@1.4.0:
    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
  negotiator@1.1.0:
    resolution: {integrity: sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==}
    engines: {node: '>=18'}
  next-tick@1.1.0:
    resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
@@ -2354,6 +2488,17 @@
    resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
    engines: {node: '>= 6'}
  object-inspect@1.13.4:
    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
    engines: {node: '>= 0.4'}
  on-finished@2.4.1:
    resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
    engines: {node: '>= 0.8'}
  once@1.4.0:
    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
  open@10.1.0:
    resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
    engines: {node: '>=18'}
@@ -2385,6 +2530,10 @@
    resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
    engines: {node: '>=18'}
  parseurl@1.3.3:
    resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
    engines: {node: '>= 0.8'}
  path-browserify@1.0.1:
    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
@@ -2406,6 +2555,9 @@
  path-scurry@1.11.1:
    resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
    engines: {node: '>=16 || 14 >=14.18'}
  path-to-regexp@8.4.2:
    resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
  pathe@1.1.2:
    resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
@@ -2515,6 +2667,10 @@
  proto-list@1.2.4:
    resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
  proxy-addr@2.0.8:
    resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==}
    engines: {node: '>= 0.10'}
  proxy-from-env@1.1.0:
    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@@ -2522,8 +2678,20 @@
    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
    engines: {node: '>=6'}
  qs@6.16.0:
    resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==}
    engines: {node: '>=0.6'}
  queue-microtask@1.2.3:
    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
  range-parser@1.3.0:
    resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==}
    engines: {node: '>= 0.6'}
  raw-body@3.0.2:
    resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
    engines: {node: '>= 0.10'}
  read-cache@1.0.0:
    resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
@@ -2577,12 +2745,19 @@
    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
    hasBin: true
  router@2.2.0:
    resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
    engines: {node: '>= 18'}
  run-applescript@7.0.0:
    resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
    engines: {node: '>=18'}
  run-parallel@1.2.0:
    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
  safer-buffer@2.1.2:
    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
  sass@1.81.0:
    resolution: {integrity: sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==}
@@ -2605,6 +2780,17 @@
    engines: {node: '>=10'}
    hasBin: true
  send@1.2.1:
    resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
    engines: {node: '>= 18'}
  serve-static@2.2.1:
    resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
    engines: {node: '>= 18'}
  setprototypeof@1.2.0:
    resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
  shebang-command@2.0.0:
    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
    engines: {node: '>=8'}
@@ -2612,6 +2798,22 @@
  shebang-regex@3.0.0:
    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
    engines: {node: '>=8'}
  side-channel-list@1.0.1:
    resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
    engines: {node: '>= 0.4'}
  side-channel-map@1.0.1:
    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
    engines: {node: '>= 0.4'}
  side-channel-weakmap@1.0.2:
    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
    engines: {node: '>= 0.4'}
  side-channel@1.1.1:
    resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==}
    engines: {node: '>= 0.4'}
  signal-exit@4.1.0:
    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
@@ -2669,6 +2871,10 @@
  ssr-window@3.0.0:
    resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
  statuses@2.0.2:
    resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
    engines: {node: '>= 0.8'}
  store@2.0.12:
    resolution: {integrity: sha512-eO9xlzDpXLiMr9W1nQ3Nfp9EzZieIQc10zPPMP5jsVV7bLOziSFFBP0XoDXACEIFtdI+rIz0NwWVA/QVJ8zJtw==}
@@ -2750,6 +2956,10 @@
    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
    engines: {node: '>=8.0'}
  toidentifier@1.0.1:
    resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
    engines: {node: '>=0.6'}
  totalist@3.0.1:
    resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
    engines: {node: '>=6'}
@@ -2776,6 +2986,10 @@
  type-fest@0.20.2:
    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
    engines: {node: '>=10'}
  type-is@2.1.0:
    resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
    engines: {node: '>= 18'}
  type@2.7.3:
    resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
@@ -2809,6 +3023,10 @@
    resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
    engines: {node: '>= 10.0.0'}
  unpipe@1.0.0:
    resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
    engines: {node: '>= 0.8'}
  unplugin@1.16.1:
    resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==}
    engines: {node: '>=14.0.0'}
@@ -2824,6 +3042,10 @@
  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'}
  vite-hot-client@0.2.4:
    resolution: {integrity: sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==}
@@ -2850,6 +3072,7 @@
    engines: {node: '>=v14.21.3'}
    peerDependencies:
      vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0
      vue: '*'
  vite-plugin-vue-inspector@5.3.1:
    resolution: {integrity: sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==}
@@ -3005,6 +3228,9 @@
    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
    engines: {node: '>=12'}
  wrappy@1.0.2:
    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
  ws@8.17.1:
    resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
    engines: {node: '>=10.0.0'}
@@ -3084,20 +3310,20 @@
  '@babel/compat-data@7.26.8': {}
  '@babel/core@7.26.9':
  '@babel/core@7.26.9(supports-color@7.2.0)':
    dependencies:
      '@ampproject/remapping': 2.3.0
      '@babel/code-frame': 7.26.2
      '@babel/generator': 7.26.9
      '@babel/helper-compilation-targets': 7.26.5
      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9)
      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@babel/helpers': 7.26.9
      '@babel/parser': 7.26.9
      '@babel/template': 7.26.9
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      '@babel/types': 7.26.9
      convert-source-map: 2.0.0
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      gensync: 1.0.0-beta.2
      json5: 2.2.3
      semver: 6.3.1
@@ -3124,39 +3350,39 @@
      lru-cache: 5.1.1
      semver: 6.3.1
  '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9)':
  '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-annotate-as-pure': 7.25.9
      '@babel/helper-member-expression-to-functions': 7.25.9
      '@babel/helper-member-expression-to-functions': 7.25.9(supports-color@7.2.0)
      '@babel/helper-optimise-call-expression': 7.25.9
      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9)
      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
      '@babel/traverse': 7.26.9
      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9(supports-color@7.2.0)
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      semver: 6.3.1
    transitivePeerDependencies:
      - supports-color
  '@babel/helper-member-expression-to-functions@7.25.9':
  '@babel/helper-member-expression-to-functions@7.25.9(supports-color@7.2.0)':
    dependencies:
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      '@babel/types': 7.26.9
    transitivePeerDependencies:
      - supports-color
  '@babel/helper-module-imports@7.25.9':
  '@babel/helper-module-imports@7.25.9(supports-color@7.2.0)':
    dependencies:
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      '@babel/types': 7.26.9
    transitivePeerDependencies:
      - supports-color
  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9)':
  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/helper-module-imports': 7.25.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-module-imports': 7.25.9(supports-color@7.2.0)
      '@babel/helper-validator-identifier': 7.25.9
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
    transitivePeerDependencies:
      - supports-color
@@ -3166,18 +3392,18 @@
  '@babel/helper-plugin-utils@7.26.5': {}
  '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9)':
  '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/helper-member-expression-to-functions': 7.25.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-member-expression-to-functions': 7.25.9(supports-color@7.2.0)
      '@babel/helper-optimise-call-expression': 7.25.9
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
    transitivePeerDependencies:
      - supports-color
  '@babel/helper-skip-transparent-expression-wrappers@7.25.9':
  '@babel/helper-skip-transparent-expression-wrappers@7.25.9(supports-color@7.2.0)':
    dependencies:
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      '@babel/types': 7.26.9
    transitivePeerDependencies:
      - supports-color
@@ -3197,48 +3423,48 @@
    dependencies:
      '@babel/types': 7.26.9
  '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.9)':
  '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9)
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
      '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.9)
      '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.9(supports-color@7.2.0))
    transitivePeerDependencies:
      - supports-color
  '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.9)':
  '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.9(supports-color@7.2.0))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
  '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9)':
  '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9(supports-color@7.2.0))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.9)':
  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.9(supports-color@7.2.0))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
  '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9)':
  '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9(supports-color@7.2.0))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
  '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9)':
  '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9(supports-color@7.2.0))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
  '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9)':
  '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-annotate-as-pure': 7.25.9
      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9)
      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
      '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9)
      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9(supports-color@7.2.0)
      '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9(supports-color@7.2.0))
    transitivePeerDependencies:
      - supports-color
@@ -3252,14 +3478,14 @@
      '@babel/parser': 7.26.9
      '@babel/types': 7.26.9
  '@babel/traverse@7.26.9':
  '@babel/traverse@7.26.9(supports-color@7.2.0)':
    dependencies:
      '@babel/code-frame': 7.26.2
      '@babel/generator': 7.26.9
      '@babel/parser': 7.26.9
      '@babel/template': 7.26.9
      '@babel/types': 7.26.9
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      globals: 11.12.0
    transitivePeerDependencies:
      - supports-color
@@ -3278,10 +3504,10 @@
    transitivePeerDependencies:
      - typescript
  '@cool-vue/vite-plugin@8.2.20':
  '@cool-vue/vite-plugin@8.2.20(debug@4.4.3(supports-color@7.2.0))':
    dependencies:
      '@vue/compiler-sfc': 3.5.13
      axios: 1.7.9
      axios: 1.7.9(debug@4.4.3(supports-color@7.2.0))
      glob: 10.4.5
      lodash: 4.17.21
      magic-string: 0.30.17
@@ -3371,17 +3597,17 @@
  '@esbuild/win32-x64@0.21.5':
    optional: true
  '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1(jiti@1.21.7))':
  '@eslint-community/eslint-utils@4.4.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))':
    dependencies:
      eslint: 9.20.1(jiti@1.21.7)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      eslint-visitor-keys: 3.4.3
  '@eslint-community/regexpp@4.12.1': {}
  '@eslint/config-array@0.19.2':
  '@eslint/config-array@0.19.2(supports-color@7.2.0)':
    dependencies:
      '@eslint/object-schema': 2.1.6
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      minimatch: 3.1.2
    transitivePeerDependencies:
      - supports-color
@@ -3390,10 +3616,10 @@
    dependencies:
      '@types/json-schema': 7.0.15
  '@eslint/eslintrc@3.2.0':
  '@eslint/eslintrc@3.2.0(supports-color@7.2.0)':
    dependencies:
      ajv: 6.12.6
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      espree: 10.3.0
      globals: 14.0.0
      ignore: 5.3.2
@@ -3514,20 +3740,20 @@
  '@intlify/shared@11.1.1': {}
  '@intlify/shared@11.4.8': {}
  '@intlify/shared@11.4.12': {}
  '@intlify/shared@12.0.0-alpha.4': {}
  '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@1.21.7))(rollup@4.34.8)(typescript@5.5.4)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))':
  '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(rollup@4.34.8)(supports-color@7.2.0)(typescript@5.5.4)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))':
    dependencies:
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
      '@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))
      '@intlify/shared': 11.4.8
      '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.8)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))
      '@intlify/shared': 11.4.12
      '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.12)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))
      '@rollup/pluginutils': 5.1.4(rollup@4.34.8)
      '@typescript-eslint/scope-manager': 8.24.1
      '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.5.4)
      debug: 4.4.0
      '@typescript-eslint/typescript-estree': 8.24.1(supports-color@7.2.0)(typescript@5.5.4)
      debug: 4.4.0(supports-color@7.2.0)
      fast-glob: 3.3.3
      js-yaml: 4.1.0
      json5: 2.2.3
@@ -3545,11 +3771,11 @@
      - supports-color
      - typescript
  '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.4.8)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))':
  '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.4.12)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.5.4)))(vue@3.5.13(typescript@5.5.4))':
    dependencies:
      '@babel/parser': 7.26.9
    optionalDependencies:
      '@intlify/shared': 11.4.8
      '@intlify/shared': 11.4.12
      '@vue/compiler-dom': 3.5.13
      vue: 3.5.13(typescript@5.5.4)
      vue-i18n: 11.1.1(vue@3.5.13(typescript@5.5.4))
@@ -3744,8 +3970,6 @@
  '@socket.io/component-emitter@3.1.2': {}
  '@sxzz/popperjs-es@2.11.7': {}
  '@sxzz/popperjs-es@2.11.8': {}
  '@transloadit/prettier-bytes@0.0.7': {}
@@ -3786,15 +4010,15 @@
  '@types/web-bluetooth@0.0.21': {}
  '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4))(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)':
  '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@eslint-community/regexpp': 4.12.1
      '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/scope-manager': 8.24.1
      '@typescript-eslint/type-utils': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      '@typescript-eslint/type-utils': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/visitor-keys': 8.24.1
      eslint: 9.20.1(jiti@1.21.7)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      graphemer: 1.4.0
      ignore: 5.3.2
      natural-compare: 1.4.0
@@ -3803,14 +4027,14 @@
    transitivePeerDependencies:
      - supports-color
  '@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)':
  '@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@typescript-eslint/scope-manager': 8.24.1
      '@typescript-eslint/types': 8.24.1
      '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.5.4)
      '@typescript-eslint/typescript-estree': 8.24.1(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/visitor-keys': 8.24.1
      debug: 4.4.0
      eslint: 9.20.1(jiti@1.21.7)
      debug: 4.4.0(supports-color@7.2.0)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      typescript: 5.5.4
    transitivePeerDependencies:
      - supports-color
@@ -3820,12 +4044,12 @@
      '@typescript-eslint/types': 8.24.1
      '@typescript-eslint/visitor-keys': 8.24.1
  '@typescript-eslint/type-utils@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)':
  '@typescript-eslint/type-utils@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      debug: 4.4.0
      eslint: 9.20.1(jiti@1.21.7)
      '@typescript-eslint/typescript-estree': 8.24.1(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      debug: 4.4.0(supports-color@7.2.0)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      ts-api-utils: 2.0.1(typescript@5.5.4)
      typescript: 5.5.4
    transitivePeerDependencies:
@@ -3833,11 +4057,11 @@
  '@typescript-eslint/types@8.24.1': {}
  '@typescript-eslint/typescript-estree@8.24.1(typescript@5.5.4)':
  '@typescript-eslint/typescript-estree@8.24.1(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@typescript-eslint/types': 8.24.1
      '@typescript-eslint/visitor-keys': 8.24.1
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      fast-glob: 3.3.3
      is-glob: 4.0.3
      minimatch: 9.0.5
@@ -3847,13 +4071,13 @@
    transitivePeerDependencies:
      - supports-color
  '@typescript-eslint/utils@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)':
  '@typescript-eslint/utils@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
      '@typescript-eslint/scope-manager': 8.24.1
      '@typescript-eslint/types': 8.24.1
      '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)
      '@typescript-eslint/typescript-estree': 8.24.1(supports-color@7.2.0)(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      typescript: 5.5.4
    transitivePeerDependencies:
      - supports-color
@@ -3892,11 +4116,11 @@
      '@uppy/utils': 4.1.3
      nanoid: 3.3.8
  '@vitejs/plugin-vue-jsx@4.1.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))':
  '@vitejs/plugin-vue-jsx@4.1.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))':
    dependencies:
      '@babel/core': 7.26.9
      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9)
      '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.9)
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      vite: 5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)
      vue: 3.5.13(typescript@5.5.4)
    transitivePeerDependencies:
@@ -3913,36 +4137,38 @@
  '@volar/source-map@2.4.11': {}
  '@volar/typescript@2.4.11':
  '@volar/typescript@2.4.11(typescript@5.5.4)':
    dependencies:
      '@volar/language-core': 2.4.11
      path-browserify: 1.0.1
      vscode-uri: 3.1.0
    optionalDependencies:
      typescript: 5.5.4
  '@vue/babel-helper-vue-transform-on@1.2.5': {}
  '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.9)':
  '@vue/babel-plugin-jsx@1.2.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/helper-module-imports': 7.25.9
      '@babel/helper-module-imports': 7.25.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
      '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9)
      '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9(supports-color@7.2.0))
      '@babel/template': 7.26.9
      '@babel/traverse': 7.26.9
      '@babel/traverse': 7.26.9(supports-color@7.2.0)
      '@babel/types': 7.26.9
      '@vue/babel-helper-vue-transform-on': 1.2.5
      '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.9)
      '@vue/babel-plugin-resolve-type': 1.2.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      html-tags: 3.3.1
      svg-tags: 1.0.0
    optionalDependencies:
      '@babel/core': 7.26.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
    transitivePeerDependencies:
      - supports-color
  '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.9)':
  '@vue/babel-plugin-resolve-type@1.2.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)':
    dependencies:
      '@babel/code-frame': 7.26.2
      '@babel/core': 7.26.9
      '@babel/helper-module-imports': 7.25.9
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/helper-module-imports': 7.25.9(supports-color@7.2.0)
      '@babel/helper-plugin-utils': 7.26.5
      '@babel/parser': 7.26.9
      '@vue/compiler-sfc': 3.5.13
@@ -4012,23 +4238,23 @@
    dependencies:
      rfdc: 1.4.1
  '@vue/eslint-config-prettier@10.2.0(eslint@9.20.1(jiti@1.21.7))(prettier@3.5.1)':
  '@vue/eslint-config-prettier@10.2.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.5.1)':
    dependencies:
      eslint: 9.20.1(jiti@1.21.7)
      eslint-config-prettier: 10.0.1(eslint@9.20.1(jiti@1.21.7))
      eslint-plugin-prettier: 5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)))(eslint@9.20.1(jiti@1.21.7))(prettier@3.5.1)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      eslint-config-prettier: 10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
      eslint-plugin-prettier: 5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0)))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.5.1)
      prettier: 3.5.1
    transitivePeerDependencies:
      - '@types/eslint'
  '@vue/eslint-config-typescript@14.4.0(eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)))(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)':
  '@vue/eslint-config-typescript@14.4.0(eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)':
    dependencies:
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)
      eslint-plugin-vue: 9.32.0(eslint@9.20.1(jiti@1.21.7))
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      eslint-plugin-vue: 9.32.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)
      fast-glob: 3.3.3
      typescript-eslint: 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      vue-eslint-parser: 9.4.3(eslint@9.20.1(jiti@1.21.7))
      typescript-eslint: 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      vue-eslint-parser: 9.4.3(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)
    optionalDependencies:
      typescript: 5.5.4
    transitivePeerDependencies:
@@ -4239,6 +4465,11 @@
  abortcontroller-polyfill@1.7.8: {}
  accepts@2.0.0:
    dependencies:
      mime-types: 3.0.2
      negotiator: 1.1.0
  acorn-jsx@5.3.2(acorn@8.14.0):
    dependencies:
      acorn: 8.14.0
@@ -4291,9 +4522,9 @@
      postcss: 8.5.2
      postcss-value-parser: 4.2.0
  axios@1.7.9:
  axios@1.7.9(debug@4.4.3(supports-color@7.2.0)):
    dependencies:
      follow-redirects: 1.15.9
      follow-redirects: 1.15.9(debug@4.4.3(supports-color@7.2.0))
      form-data: 4.0.2
      proxy-from-env: 1.1.0
    transitivePeerDependencies:
@@ -4304,6 +4535,20 @@
  binary-extensions@2.3.0: {}
  birpc@0.2.19: {}
  body-parser@2.3.0(supports-color@7.2.0):
    dependencies:
      bytes: 3.1.2
      content-type: 2.1.0
      debug: 4.4.3(supports-color@7.2.0)
      http-errors: 2.0.1
      iconv-lite: 0.7.3
      on-finished: 2.4.1
      qs: 6.16.0
      raw-body: 3.0.2
      type-is: 2.1.0
    transitivePeerDependencies:
      - supports-color
  boolbase@1.0.0: {}
@@ -4333,10 +4578,17 @@
    dependencies:
      run-applescript: 7.0.0
  bytes@3.1.2: {}
  call-bind-apply-helpers@1.0.2:
    dependencies:
      es-errors: 1.3.0
      function-bind: 1.1.2
  call-bound@1.0.4:
    dependencies:
      call-bind-apply-helpers: 1.0.2
      get-intrinsic: 1.3.0
  callsites@3.1.0: {}
@@ -4409,7 +4661,17 @@
      ini: 1.3.8
      proto-list: 1.2.4
  content-disposition@1.1.0: {}
  content-type@1.0.5: {}
  content-type@2.1.0: {}
  convert-source-map@2.0.0: {}
  cookie-signature@1.2.2: {}
  cookie@0.7.2: {}
  copy-anything@3.0.5:
    dependencies:
@@ -4466,13 +4728,23 @@
  debounce-promise@3.1.2: {}
  debug@4.3.7:
  debug@4.3.7(supports-color@7.2.0):
    dependencies:
      ms: 2.1.3
    optionalDependencies:
      supports-color: 7.2.0
  debug@4.4.0:
  debug@4.4.0(supports-color@7.2.0):
    dependencies:
      ms: 2.1.3
    optionalDependencies:
      supports-color: 7.2.0
  debug@4.4.3(supports-color@7.2.0):
    dependencies:
      ms: 2.1.3
    optionalDependencies:
      supports-color: 7.2.0
  deep-is@0.1.4: {}
@@ -4490,6 +4762,8 @@
  define-lazy-prop@3.0.0: {}
  delayed-stream@1.0.0: {}
  depd@2.0.0: {}
  detect-libc@1.0.3:
    optional: true
@@ -4540,6 +4814,8 @@
      minimatch: 9.0.1
      semver: 7.7.1
  ee-first@1.1.1: {}
  electron-to-chromium@1.5.102: {}
  element-plus@2.10.2(vue@3.5.13(typescript@5.5.4)):
@@ -4547,7 +4823,7 @@
      '@ctrl/tinycolor': 3.6.1
      '@element-plus/icons-vue': 2.3.1(vue@3.5.13(typescript@5.5.4))
      '@floating-ui/dom': 1.6.13
      '@popperjs/core': '@sxzz/popperjs-es@2.11.7'
      '@popperjs/core': '@sxzz/popperjs-es@2.11.8'
      '@types/lodash': 4.17.15
      '@types/lodash-es': 4.17.12
      '@vueuse/core': 9.13.0(vue@3.5.13(typescript@5.5.4))
@@ -4586,10 +4862,12 @@
  emoji-regex@9.2.2: {}
  engine.io-client@6.6.3:
  encodeurl@2.0.0: {}
  engine.io-client@6.6.3(supports-color@7.2.0):
    dependencies:
      '@socket.io/component-emitter': 3.1.2
      debug: 4.3.7
      debug: 4.3.7(supports-color@7.2.0)
      engine.io-parser: 5.2.3
      ws: 8.17.1
      xmlhttprequest-ssl: 2.1.2
@@ -4677,29 +4955,29 @@
    optionalDependencies:
      source-map: 0.6.1
  eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)):
  eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0)):
    dependencies:
      eslint: 9.20.1(jiti@1.21.7)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
  eslint-plugin-prettier@5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)))(eslint@9.20.1(jiti@1.21.7))(prettier@3.5.1):
  eslint-plugin-prettier@5.2.3(eslint-config-prettier@10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0)))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(prettier@3.5.1):
    dependencies:
      eslint: 9.20.1(jiti@1.21.7)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      prettier: 3.5.1
      prettier-linter-helpers: 1.0.0
      synckit: 0.9.2
    optionalDependencies:
      eslint-config-prettier: 10.0.1(eslint@9.20.1(jiti@1.21.7))
      eslint-config-prettier: 10.0.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
  eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)):
  eslint-plugin-vue@9.32.0(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0):
    dependencies:
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
      eslint: 9.20.1(jiti@1.21.7)
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      globals: 13.24.0
      natural-compare: 1.4.0
      nth-check: 2.1.1
      postcss-selector-parser: 6.1.2
      semver: 7.7.1
      vue-eslint-parser: 9.4.3(eslint@9.20.1(jiti@1.21.7))
      vue-eslint-parser: 9.4.3(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)
      xml-name-validator: 4.0.0
    transitivePeerDependencies:
      - supports-color
@@ -4718,13 +4996,13 @@
  eslint-visitor-keys@4.2.0: {}
  eslint@9.20.1(jiti@1.21.7):
  eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0):
    dependencies:
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7))
      '@eslint-community/eslint-utils': 4.4.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))
      '@eslint-community/regexpp': 4.12.1
      '@eslint/config-array': 0.19.2
      '@eslint/config-array': 0.19.2(supports-color@7.2.0)
      '@eslint/core': 0.11.0
      '@eslint/eslintrc': 3.2.0
      '@eslint/eslintrc': 3.2.0(supports-color@7.2.0)
      '@eslint/js': 9.20.0
      '@eslint/plugin-kit': 0.2.6
      '@humanfs/node': 0.16.6
@@ -4735,7 +5013,7 @@
      ajv: 6.12.6
      chalk: 4.1.2
      cross-spawn: 7.0.6
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      escape-string-regexp: 4.0.0
      eslint-scope: 8.2.0
      eslint-visitor-keys: 4.2.0
@@ -4794,6 +5072,8 @@
  esutils@2.0.3: {}
  etag@1.8.1: {}
  event-emitter@0.3.5:
    dependencies:
      d: 1.0.2
@@ -4815,6 +5095,39 @@
      signal-exit: 4.1.0
      strip-final-newline: 4.0.0
      yoctocolors: 2.1.1
  express@5.2.1(supports-color@7.2.0):
    dependencies:
      accepts: 2.0.0
      body-parser: 2.3.0(supports-color@7.2.0)
      content-disposition: 1.1.0
      content-type: 1.0.5
      cookie: 0.7.2
      cookie-signature: 1.2.2
      debug: 4.4.0(supports-color@7.2.0)
      depd: 2.0.0
      encodeurl: 2.0.0
      escape-html: 1.0.3
      etag: 1.8.1
      finalhandler: 2.1.1(supports-color@7.2.0)
      fresh: 2.0.0
      http-errors: 2.0.1
      merge-descriptors: 2.0.0
      mime-types: 3.0.2
      on-finished: 2.4.1
      once: 1.4.0
      parseurl: 1.3.3
      proxy-addr: 2.0.8
      qs: 6.16.0
      range-parser: 1.3.0
      router: 2.2.0(supports-color@7.2.0)
      send: 1.2.1(supports-color@7.2.0)
      serve-static: 2.2.1(supports-color@7.2.0)
      statuses: 2.0.2
      type-is: 2.1.0
      vary: 1.1.2
    transitivePeerDependencies:
      - supports-color
  ext@1.7.0:
    dependencies:
@@ -4875,6 +5188,17 @@
    dependencies:
      to-regex-range: 5.0.1
  finalhandler@2.1.1(supports-color@7.2.0):
    dependencies:
      debug: 4.4.0(supports-color@7.2.0)
      encodeurl: 2.0.0
      escape-html: 1.0.3
      on-finished: 2.4.1
      parseurl: 1.3.3
      statuses: 2.0.2
    transitivePeerDependencies:
      - supports-color
  find-up@5.0.0:
    dependencies:
      locate-path: 6.0.0
@@ -4887,7 +5211,9 @@
  flatted@3.3.3: {}
  follow-redirects@1.15.9: {}
  follow-redirects@1.15.9(debug@4.4.3(supports-color@7.2.0)):
    optionalDependencies:
      debug: 4.4.3(supports-color@7.2.0)
  foreground-child@3.3.0:
    dependencies:
@@ -4905,9 +5231,13 @@
    dependencies:
      fetch-blob: 3.2.0
  forwarded@0.2.0: {}
  frac@1.1.2: {}
  fraction.js@4.3.7: {}
  fresh@2.0.0: {}
  fs-extra@10.1.0:
    dependencies:
@@ -4931,6 +5261,19 @@
  get-caller-file@2.0.5: {}
  get-intrinsic@1.2.7:
    dependencies:
      call-bind-apply-helpers: 1.0.2
      es-define-property: 1.0.1
      es-errors: 1.3.0
      es-object-atoms: 1.1.1
      function-bind: 1.1.2
      get-proto: 1.0.1
      gopd: 1.2.0
      has-symbols: 1.1.0
      hasown: 2.0.2
      math-intrinsics: 1.1.0
  get-intrinsic@1.3.0:
    dependencies:
      call-bind-apply-helpers: 1.0.2
      es-define-property: 1.0.1
@@ -5004,11 +5347,35 @@
  html-void-elements@2.0.1: {}
  http-errors@2.0.1:
    dependencies:
      depd: 2.0.0
      inherits: 2.0.4
      setprototypeof: 1.2.0
      statuses: 2.0.2
      toidentifier: 1.0.1
  http-proxy-middleware@4.2.0(supports-color@7.2.0):
    dependencies:
      debug: 4.4.3(supports-color@7.2.0)
      httpxy: 0.5.5
      is-glob: 4.0.3
      is-plain-obj: 4.1.0
      micromatch: 4.0.8
    transitivePeerDependencies:
      - supports-color
  httpxy@0.5.5: {}
  human-signals@8.0.0: {}
  i18next@20.6.1:
    dependencies:
      '@babel/runtime': 7.26.9
  iconv-lite@0.7.3:
    dependencies:
      safer-buffer: 2.1.2
  ignore@5.3.2: {}
@@ -5023,7 +5390,11 @@
  imurmurhash@0.1.4: {}
  inherits@2.0.4: {}
  ini@1.3.8: {}
  ipaddr.js@1.9.1: {}
  is-binary-path@2.1.0:
    dependencies:
@@ -5056,6 +5427,8 @@
  is-plain-obj@4.1.0: {}
  is-plain-object@5.0.0: {}
  is-promise@4.0.0: {}
  is-stream@4.0.1: {}
@@ -5195,7 +5568,11 @@
  mdn-data@2.0.30: {}
  media-typer@1.1.1: {}
  memoize-one@6.0.0: {}
  merge-descriptors@2.0.0: {}
  merge2@1.4.1: {}
@@ -5206,6 +5583,8 @@
  mime-db@1.52.0: {}
  mime-db@1.54.0: {}
  mime-match@1.0.2:
    dependencies:
      wildcard: 1.1.2
@@ -5213,6 +5592,10 @@
  mime-types@2.1.35:
    dependencies:
      mime-db: 1.52.0
  mime-types@3.0.2:
    dependencies:
      mime-db: 1.54.0
  minimatch@3.1.2:
    dependencies:
@@ -5257,6 +5640,10 @@
  natural-compare@1.4.0: {}
  negotiator@1.1.0:
    dependencies:
      content-type: 2.1.0
  next-tick@1.1.0: {}
  node-addon-api@7.1.1:
@@ -5290,6 +5677,16 @@
  object-assign@4.1.1: {}
  object-hash@3.0.0: {}
  object-inspect@1.13.4: {}
  on-finished@2.4.1:
    dependencies:
      ee-first: 1.1.1
  once@1.4.0:
    dependencies:
      wrappy: 1.0.2
  open@10.1.0:
    dependencies:
@@ -5329,6 +5726,8 @@
  parse-ms@4.0.0: {}
  parseurl@1.3.3: {}
  path-browserify@1.0.1: {}
  path-exists@4.0.0: {}
@@ -5343,6 +5742,8 @@
    dependencies:
      lru-cache: 10.4.3
      minipass: 7.1.2
  path-to-regexp@8.4.2: {}
  pathe@1.1.2: {}
@@ -5431,11 +5832,30 @@
  proto-list@1.2.4: {}
  proxy-addr@2.0.8:
    dependencies:
      forwarded: 0.2.0
      ipaddr.js: 1.9.1
  proxy-from-env@1.1.0: {}
  punycode@2.3.1: {}
  qs@6.16.0:
    dependencies:
      es-define-property: 1.0.1
      side-channel: 1.1.1
  queue-microtask@1.2.3: {}
  range-parser@1.3.0: {}
  raw-body@3.0.2:
    dependencies:
      bytes: 3.1.2
      http-errors: 2.0.1
      iconv-lite: 0.7.3
      unpipe: 1.0.0
  read-cache@1.0.0:
    dependencies:
@@ -5497,11 +5917,23 @@
      '@rollup/rollup-win32-x64-msvc': 4.34.8
      fsevents: 2.3.3
  router@2.2.0(supports-color@7.2.0):
    dependencies:
      debug: 4.4.0(supports-color@7.2.0)
      depd: 2.0.0
      is-promise: 4.0.0
      parseurl: 1.3.3
      path-to-regexp: 8.4.2
    transitivePeerDependencies:
      - supports-color
  run-applescript@7.0.0: {}
  run-parallel@1.2.0:
    dependencies:
      queue-microtask: 1.2.3
  safer-buffer@2.1.2: {}
  sass@1.81.0:
    dependencies:
@@ -5521,11 +5953,66 @@
  semver@7.7.1: {}
  send@1.2.1(supports-color@7.2.0):
    dependencies:
      debug: 4.4.3(supports-color@7.2.0)
      encodeurl: 2.0.0
      escape-html: 1.0.3
      etag: 1.8.1
      fresh: 2.0.0
      http-errors: 2.0.1
      mime-types: 3.0.2
      ms: 2.1.3
      on-finished: 2.4.1
      range-parser: 1.3.0
      statuses: 2.0.2
    transitivePeerDependencies:
      - supports-color
  serve-static@2.2.1(supports-color@7.2.0):
    dependencies:
      encodeurl: 2.0.0
      escape-html: 1.0.3
      parseurl: 1.3.3
      send: 1.2.1(supports-color@7.2.0)
    transitivePeerDependencies:
      - supports-color
  setprototypeof@1.2.0: {}
  shebang-command@2.0.0:
    dependencies:
      shebang-regex: 3.0.0
  shebang-regex@3.0.0: {}
  side-channel-list@1.0.1:
    dependencies:
      es-errors: 1.3.0
      object-inspect: 1.13.4
  side-channel-map@1.0.1:
    dependencies:
      call-bound: 1.0.4
      es-errors: 1.3.0
      get-intrinsic: 1.2.7
      object-inspect: 1.13.4
  side-channel-weakmap@1.0.2:
    dependencies:
      call-bound: 1.0.4
      es-errors: 1.3.0
      get-intrinsic: 1.2.7
      object-inspect: 1.13.4
      side-channel-map: 1.0.1
  side-channel@1.1.1:
    dependencies:
      es-errors: 1.3.0
      object-inspect: 1.13.4
      side-channel-list: 1.0.1
      side-channel-map: 1.0.1
      side-channel-weakmap: 1.0.2
  signal-exit@4.1.0: {}
@@ -5548,21 +6035,21 @@
  snabbdom@3.6.2: {}
  socket.io-client@4.8.1:
  socket.io-client@4.8.1(supports-color@7.2.0):
    dependencies:
      '@socket.io/component-emitter': 3.1.2
      debug: 4.3.7
      engine.io-client: 6.6.3
      socket.io-parser: 4.2.4
      debug: 4.3.7(supports-color@7.2.0)
      engine.io-client: 6.6.3(supports-color@7.2.0)
      socket.io-parser: 4.2.4(supports-color@7.2.0)
    transitivePeerDependencies:
      - bufferutil
      - supports-color
      - utf-8-validate
  socket.io-parser@4.2.4:
  socket.io-parser@4.2.4(supports-color@7.2.0):
    dependencies:
      '@socket.io/component-emitter': 3.1.2
      debug: 4.3.7
      debug: 4.3.7(supports-color@7.2.0)
    transitivePeerDependencies:
      - supports-color
@@ -5586,6 +6073,8 @@
      frac: 1.1.2
  ssr-window@3.0.0: {}
  statuses@2.0.2: {}
  store@2.0.12: {}
@@ -5698,6 +6187,8 @@
    dependencies:
      is-number: 7.0.0
  toidentifier@1.0.1: {}
  totalist@3.0.1: {}
  ts-api-utils@2.0.1(typescript@5.5.4):
@@ -5716,14 +6207,20 @@
  type-fest@0.20.2: {}
  type-is@2.1.0:
    dependencies:
      content-type: 2.1.0
      media-typer: 1.1.1
      mime-types: 3.0.2
  type@2.7.3: {}
  typescript-eslint@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4):
  typescript-eslint@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4):
    dependencies:
      '@typescript-eslint/eslint-plugin': 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4))(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7))(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)
      '@typescript-eslint/eslint-plugin': 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4))(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/parser': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      '@typescript-eslint/utils': 8.24.1(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.5.4)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      typescript: 5.5.4
    transitivePeerDependencies:
      - supports-color
@@ -5739,6 +6236,8 @@
  unicorn-magic@0.3.0: {}
  universalify@2.0.1: {}
  unpipe@1.0.0: {}
  unplugin@1.16.1:
    dependencies:
@@ -5757,24 +6256,26 @@
  util-deprecate@1.0.2: {}
  vary@1.1.2: {}
  vite-hot-client@0.2.4(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
    dependencies:
      vite: 5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)
  vite-plugin-compression@0.5.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
  vite-plugin-compression@0.5.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
    dependencies:
      chalk: 4.1.2
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      fs-extra: 10.1.0
      vite: 5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)
    transitivePeerDependencies:
      - supports-color
  vite-plugin-inspect@0.8.9(rollup@4.34.8)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
  vite-plugin-inspect@0.8.9(rollup@4.34.8)(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
    dependencies:
      '@antfu/utils': 0.7.10
      '@rollup/pluginutils': 5.1.4(rollup@4.34.8)
      debug: 4.4.0
      debug: 4.4.0(supports-color@7.2.0)
      error-stack-parser-es: 0.1.5
      fs-extra: 11.3.0
      open: 10.1.0
@@ -5786,7 +6287,7 @@
      - rollup
      - supports-color
  vite-plugin-vue-devtools@7.7.2(rollup@4.34.8)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4)):
  vite-plugin-vue-devtools@7.7.2(rollup@4.34.8)(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4)):
    dependencies:
      '@vue/devtools-core': 7.7.2(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))(vue@3.5.13(typescript@5.5.4))
      '@vue/devtools-kit': 7.7.2
@@ -5794,22 +6295,22 @@
      execa: 9.5.2
      sirv: 3.0.1
      vite: 5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)
      vite-plugin-inspect: 0.8.9(rollup@4.34.8)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
      vite-plugin-vue-inspector: 5.3.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
      vite-plugin-inspect: 0.8.9(rollup@4.34.8)(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
      vite-plugin-vue-inspector: 5.3.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0))
      vue: 3.5.13(typescript@5.5.4)
    transitivePeerDependencies:
      - '@nuxt/kit'
      - rollup
      - supports-color
      - vue
  vite-plugin-vue-inspector@5.3.1(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
  vite-plugin-vue-inspector@5.3.1(supports-color@7.2.0)(vite@5.4.14(@types/node@20.17.19)(sass@1.81.0)(terser@5.39.0)):
    dependencies:
      '@babel/core': 7.26.9
      '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.9)
      '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.9)
      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.9)
      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9)
      '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.9)
      '@babel/core': 7.26.9(supports-color@7.2.0)
      '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.9(supports-color@7.2.0))
      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.9(supports-color@7.2.0))
      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.9(supports-color@7.2.0))(supports-color@7.2.0)
      '@vue/compiler-dom': 3.5.13
      kolorist: 1.8.0
      magic-string: 0.30.17
@@ -5852,10 +6353,10 @@
    transitivePeerDependencies:
      - '@vue/composition-api'
  vue-eslint-parser@9.4.3(eslint@9.20.1(jiti@1.21.7)):
  vue-eslint-parser@9.4.3(eslint@9.20.1(jiti@1.21.7)(supports-color@7.2.0))(supports-color@7.2.0):
    dependencies:
      debug: 4.4.0
      eslint: 9.20.1(jiti@1.21.7)
      debug: 4.4.0(supports-color@7.2.0)
      eslint: 9.20.1(jiti@1.21.7)(supports-color@7.2.0)
      eslint-scope: 7.2.2
      eslint-visitor-keys: 3.4.3
      espree: 9.6.1
@@ -5884,7 +6385,7 @@
  vue-tsc@2.2.2(typescript@5.5.4):
    dependencies:
      '@volar/typescript': 2.4.11
      '@volar/typescript': 2.4.11(typescript@5.5.4)
      '@vue/language-core': 2.2.2(typescript@5.5.4)
      typescript: 5.5.4
@@ -5931,6 +6432,8 @@
      string-width: 5.1.2
      strip-ansi: 7.1.0
  wrappy@1.0.2: {}
  ws@8.17.1: {}
  xlsx@0.18.5:
server.cjs
New file
@@ -0,0 +1,87 @@
/**
 * 前端静态服务器(PM2 托管,对外 :9000)
 * - 托管 dist 静态资源
 * - /api/*    转发后端(去掉 /api 前缀)
 * - /upload/* 转发后端
 * - /socket.io 转发后端(支持 WebSocket)
 */
const path = require('path');
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const PORT = Number(process.env.PORT || 9000);
const BACKEND = process.env.BACKEND || 'http://127.0.0.1:8001';
const DIST = path.join(__dirname, 'dist');
const onErr = (name) => (err, req, res) => {
  console.error(`[proxy:${name}]`, err && err.message);
  if (res && res.writeHead) {
    res.writeHead(502, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ code: 502, msg: `backend unreachable: ${name}` }));
  }
};
const app = express();
// 1) 业务接口:/api/admin/xxx -> /admin/xxx
app.use(
  '/api',
  createProxyMiddleware({
    target: BACKEND,
    changeOrigin: true,
    pathRewrite: { '^/api': '' },
    ws: false,
    onError: onErr('api'),
  })
);
// 2) 上传文件
app.use(
  '/upload',
  createProxyMiddleware({
    target: BACKEND,
    changeOrigin: true,
    ws: false,
    onError: onErr('upload'),
  })
);
// 3) socket.io(含 WebSocket)
const socketProxy = createProxyMiddleware({
  target: BACKEND,
  changeOrigin: true,
  ws: true,
  onError: onErr('socket.io'),
});
app.use('/socket.io', socketProxy);
// 4) 前端静态资源
app.use(
  express.static(DIST, {
    maxAge: '7d',
    index: 'index.html',
    setHeaders(res, filePath) {
      if (filePath.endsWith('index.html')) res.setHeader('Cache-Control', 'no-cache');
    },
  })
);
// 5) history 路由兜底(hash 模式不会走到这)
// app.get('*', (req, res, next) => {
//   if (req.path.startsWith('/api') || req.path.startsWith('/upload')) return next();
//   res.sendFile(path.join(DIST, 'index.html'), (err) => err && next(err));
// });
app.use((req, res, next) => {
  if (req.path.startsWith('/api') || req.path.startsWith('/upload')) return next();
  res.sendFile(path.join(DIST, 'index.html'), (err) => err && next(err));
});
const server = app.listen(PORT, '0.0.0.0', () => {
  console.log(`[frontend] http://0.0.0.0:${PORT}  ->  backend ${BACKEND}`);
});
// WebSocket 升级
server.on('upgrade', socketProxy.upgrade);
process.on('unhandledRejection', (r) => console.error('[unhandledRejection]', r && r.message));
process.on('uncaughtException', (e) => console.error('[uncaughtException]', e && e.message));
src/modules/base/config.ts
@@ -3,6 +3,7 @@
import { config } from '/@/config';
import { t } from '/@/plugins/i18n';
import './static/css/index.scss';
import './static/css/mobile.scss';
export default (): ModuleConfig => {
    return {
src/modules/base/pages/error/components/error-page.vue
@@ -137,4 +137,22 @@
        }
    }
}
@media only screen and (max-width: 768px) {
    .error-page {
        overflow: auto;
        &__code {
            font-size: 72px;
            margin-top: 0;
        }
        &__btns {
            flex-wrap: wrap;
            justify-content: center;
            gap: 10px;
            padding: 0 16px;
        }
    }
}
</style>
src/modules/base/pages/login/index.vue
@@ -304,4 +304,36 @@
        }
    }
}
@media screen and (max-width: 768px) {
    .page-login {
        overflow: auto;
        align-items: flex-start;
        .bg {
            opacity: 0.25;
        }
        .box {
            position: relative;
            height: auto;
            min-height: 100%;
            padding: 48px 20px calc(36px + env(safe-area-inset-bottom));
            box-sizing: border-box;
            .logo span {
                font-size: 26px;
                letter-spacing: 1px;
            }
            .desc {
                margin-bottom: 28px;
            }
            .form {
                width: min(360px, 100%);
            }
        }
    }
}
</style>
src/modules/base/pages/main/components/amenu.vue
@@ -148,4 +148,16 @@
        margin-left: 8px;
    }
}
@media only screen and (max-width: 768px) {
    .a-menu {
        min-width: 0;
        overflow-x: auto;
        &__item {
            flex-shrink: 0;
            padding: 0 10px;
        }
    }
}
</style>
src/modules/base/pages/main/components/process.vue
@@ -276,4 +276,18 @@
        }
    }
}
@media only screen and (max-width: 768px) {
    .app-process {
        padding-left: 6px;
        padding-right: 6px;
        &__item .close {
            margin-left: 8px;
            margin-right: -2px;
            width: 16px;
            opacity: 1;
        }
    }
}
</style>
src/modules/base/pages/main/components/topbar.vue
@@ -188,6 +188,54 @@
        }
    }
}
@media only screen and (max-width: 768px) {
    .app-topbar {
        padding-top: env(safe-area-inset-top);
        padding-right: 6px;
        height: calc(46px + env(safe-area-inset-top));
        min-width: 0;
        .flex1 {
            min-width: 8px;
        }
        &__tools {
            flex-shrink: 0;
            margin-right: 4px;
            & > li {
                margin-left: 6px;
            }
        }
        &__user {
            flex-shrink: 0;
            padding-left: 4px;
            :deep(.el-text) {
                display: none;
            }
        }
        :deep(.route-nav) {
            min-width: 0;
            max-width: 46vw;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        :deep(.a-menu) {
            min-width: 0;
            overflow-x: auto;
        }
        :deep(.cl-comm__icon) {
            width: 32px;
            height: 32px;
        }
    }
}
</style>
<style lang="scss">
src/modules/base/pages/main/components/views.vue
@@ -96,4 +96,14 @@
        opacity: 1;
    }
}
@media only screen and (max-width: 768px) {
    .app-views {
        overflow-x: hidden;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        margin: 0 8px calc(8px + env(safe-area-inset-bottom)) 8px;
        width: calc(100% - 16px);
    }
}
</style>
src/modules/base/pages/main/index.vue
@@ -67,10 +67,15 @@
    }
    @media only screen and (max-width: 768px) {
        position: relative;
        .app-layout__left {
            position: absolute;
            left: 0;
            top: 0;
            width: min(280px, 86vw);
            z-index: 9999;
            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
            transition:
                transform 0.3s cubic-bezier(0.7, 0.3, 0.1, 1),
                box-shadow 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
@@ -78,6 +83,7 @@
        .app-layout__right {
            width: 100%;
            min-width: 0;
        }
        &.is-collapse {
src/modules/base/static/css/index.scss
@@ -1,6 +1,8 @@
#app {
    height: 100vh;
    width: 100vw;
    height: 100dvh;
    width: 100%;
    max-width: 100vw;
    overflow: hidden;
}
src/modules/base/static/css/mobile.scss
New file
@@ -0,0 +1,253 @@
/* 手机浏览器:只在窄屏生效,桌面端样式保持原样 */
@media only screen and (max-width: 768px) {
    html,
    body {
        -webkit-text-size-adjust: 100%;
    }
    .el-scrollbar__wrap {
        -webkit-overflow-scrolling: touch;
    }
    /* 避免 iOS 聚焦输入框时自动放大页面 */
    .el-form .el-input__inner,
    .el-form .el-textarea__inner,
    .el-form .el-select__wrapper,
    .el-form .el-input__wrapper input {
        font-size: 16px;
    }
    .el-dialog:not(.is-fullscreen) {
        width: calc(100vw - 24px) !important;
        max-width: calc(100vw - 24px);
        margin: 12px auto !important;
    }
    .el-drawer {
        width: min(100vw, 420px) !important;
        max-width: 100vw;
    }
    .el-dialog__body,
    .cl-dialog .el-dialog__body {
        max-height: calc(100dvh - 140px);
        overflow: auto;
    }
    .cl-search,
    .cl-form,
    .el-dialog,
    .el-drawer {
        .el-form--inline {
            .el-form-item {
                display: flex;
                margin-right: 0;
                width: 100%;
            }
            .el-form-item__content {
                flex: 1;
                min-width: 0;
            }
        }
        .el-date-editor.el-input,
        .el-date-editor--daterange,
        .el-date-editor--datetimerange,
        .el-select,
        .el-cascader,
        .el-input-number {
            width: 100% !important;
            max-width: 100%;
            box-sizing: border-box;
        }
    }
    .cl-form .el-col,
    .el-dialog .el-form .el-col,
    .cl-search .el-col {
        flex: 0 0 100%;
        max-width: 100%;
    }
    .cl-search,
    .cl-search-key,
    .cl-search-key__wrap,
    .cl-filter {
        width: 100%;
        max-width: 100%;
    }
    .cl-filter {
        margin-left: 0;
        margin-right: 0;
    }
    .cl-pagination.el-pagination {
        flex-wrap: wrap;
        justify-content: center;
        row-gap: 8px;
        padding-bottom: 4px;
    }
    .el-pagination__sizes,
    .el-pagination__jump {
        display: none !important;
    }
    .cl-table,
    .el-table {
        max-width: 100%;
    }
    .el-table .cell {
        word-break: break-word;
    }
    .el-message-box {
        width: calc(100vw - 32px) !important;
    }
    .el-picker__popper,
    .el-select__popper {
        max-width: calc(100vw - 16px);
    }
    .el-date-range-picker {
        width: calc(100vw - 16px) !important;
        max-width: calc(100vw - 16px);
        .el-picker-panel__body {
            min-width: 0 !important;
            display: flex;
            flex-direction: column;
        }
        .el-date-range-picker__content {
            width: 100%;
            padding: 8px;
        }
    }
    .el-dropdown__popper,
    .el-popover.el-popper {
        max-width: calc(100vw - 16px);
    }
    /* 所有业务页:限制在屏幕内,内容区自己滚动 */
    .app-views,
    .app-views > * {
        max-width: 100%;
        min-width: 0;
    }
    .cl-crud {
        max-width: 100%;
    }
    .cl-crud > .cl-row {
        flex-wrap: wrap;
        row-gap: 8px;
        max-width: 100%;
    }
    .cl-crud > .cl-row > * {
        max-width: 100%;
    }
    .cl-crud > .cl-row > .cl-flex1 {
        flex: 1 1 100%;
        width: 100%;
        height: 0;
        margin: 0;
    }
    .cl-filter {
        flex: 1 1 100%;
        width: 100%;
        max-width: 100%;
        margin: 0;
        box-sizing: border-box;
        .el-select,
        .el-date-editor,
        .el-input {
            flex: 1;
            width: 100% !important;
            min-width: 0 !important;
        }
    }
    .cl-adv-search,
    .cl-search.is-inline,
    .cl-search-key {
        flex: 1 1 100%;
    }
    .el-table {
        width: 100% !important;
    }
    .el-table__header-wrapper,
    .el-table__body-wrapper,
    .el-scrollbar__wrap {
        max-width: 100%;
    }
    .el-descriptions__label,
    .el-descriptions__content {
        word-break: break-word;
    }
    .el-tabs__nav-scroll {
        overflow-x: auto;
    }
    .el-dialog:not(.is-fullscreen),
    .cl-dialog:not(.is-fullscreen) {
        max-height: calc(100dvh - 24px);
    }
    .cl-dialog__container,
    .cl-dialog .el-scrollbar {
        max-height: calc(100dvh - 132px) !important;
    }
    .w-e-toolbar,
    .cl-editor-wang {
        max-width: 100%;
        overflow-x: auto;
    }
    .cl-view-group__right .head .title {
        max-width: calc(100vw - 120px);
        padding: 0 36px;
        text-overflow: ellipsis;
    }
    .error-page__code {
        font-size: 72px;
    }
    .plugins__header {
        flex-wrap: wrap;
        gap: 8px;
        .search {
            width: 100% !important;
        }
    }
    .cl-upload-space-inner__header {
        flex-wrap: wrap;
        height: auto;
        min-height: 50px;
        padding: 8px 10px;
        gap: 8px;
    }
    .cl-upload-space-inner__file-item {
        width: calc(50% - 10px) !important;
        padding-top: calc(50% - 10px) !important;
    }
}
src/modules/ezuikit/components/ezuikit-player.vue
@@ -171,4 +171,9 @@
  padding: 0px;
  background: #000;
}
/* 手机扩展区里的圆形云台。SDK 用 deepmerge 合并配置时数组合并,单靠删掉 controls 里的 ptz 去不掉 */
.ez-player-card :deep(.ez-mobile-ptz) {
  display: none;
}
</style>
src/modules/maps/components/map-board.vue
@@ -134,4 +134,29 @@
    width: 100%;
    height: 100%;
}
@media (max-width: 992px) {
    .map-board {
        flex-direction: column;
        height: 100%;
        overflow: auto;
    }
    .map-board__side {
        width: 100%;
        max-height: 240px;
    }
    .map-board__map {
        flex: none;
        width: 100%;
        height: 56vh;
        min-height: 320px;
    }
    .map-board__panel {
        width: 100%;
        max-height: none;
    }
}
</style>
src/modules/monitor/views/cameras.vue
@@ -257,4 +257,24 @@
  border-color: #555 !important;
  color: #888 !important;
}
@media (max-width: 768px) {
  .camera-page {
    padding: 8px;
  }
  .scroll-viewport {
    margin: 0 6px;
  }
  .player-card {
    width: min(280px, calc(100vw - 96px));
    height: 240px;
  }
  .arrow {
    width: 28px;
    height: 64px;
  }
}
</style>
src/modules/monitor/views/device.vue
@@ -117,4 +117,26 @@
    font-weight: 500;
  }
}
@media (max-width: 768px) {
  .monitor-page {
    flex-direction: column;
    overflow: auto;
  }
  .left-tree {
    width: 100%;
    height: 220px;
    flex-shrink: 0;
  }
  .right-player {
    height: auto;
    min-height: 360px;
  }
  .player-grid {
    grid-template-columns: 1fr !important;
  }
}
</style>
src/modules/operation/views/traderecord.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="交易时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <cl-import-btn tips="导入微信交易记录" :on-config="onConfig" :on-submit="onSubmit" />
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
src/modules/operation/views/wastesale.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="日期时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -260,12 +263,14 @@
        service: service.operation.wastesale
    },
    (app) => {
        service.basicdata.wastetype.page({ isRecyclable: 1, size: 1000 }).then((res) => {
            garbageTypeOptions.value = (res.list || []).map((item: any) => ({
                label: item.name,
                value: item.code,
                price: item.price,
            }));
        service.basicdata.wastetype.page({ isRecyclable: 1, status: 1, size: 1000 }).then((res) => {
            garbageTypeOptions.value = (res.list || [])
                .filter((item: any) => item.status === 1)
                .map((item: any) => ({
                    label: item.name,
                    value: item.code,
                    price: item.price,
                }));
        });
        app.refresh();
    }
src/modules/push/views/auditlog.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="日志时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
src/modules/push/views/cameragps.vue
@@ -7,9 +7,12 @@
            <cl-add-btn />
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
            <cl-flex1 />
            <cl-filter label="消息创建时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
        <cl-row>
src/modules/push/views/compressionweight.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="上传时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
src/modules/push/views/devicealarm.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="报警时间戳">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
src/modules/push/views/deviceonoff.vue
@@ -7,9 +7,12 @@
            <cl-add-btn />
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
            <cl-flex1 />
            <cl-filter label="消息时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
        <cl-row>
src/modules/push/views/siteweight.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="上传时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -192,11 +195,13 @@
        service: service.push.siteweight,
    },
    (app) => {
        service.basicdata.wastetype.list().then((res) => {
            garbageTypeOptions.value = (res || []).map((item: any) => ({
                label: item.name,
                value: item.code,
            }));
        service.basicdata.wastetype.list({ status: 1 }).then((res) => {
            garbageTypeOptions.value = (res || [])
                .filter((item: any) => item.status === 1)
                .map((item: any) => ({
                    label: item.name,
                    value: item.code,
                }));
        });
        app.refresh();
    },
src/modules/push/views/vehiclegps.vue
@@ -7,9 +7,12 @@
            <cl-add-btn />
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
            <cl-flex1 />
            <cl-filter label="GPS定位时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
        <cl-row>
src/modules/push/views/weight.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <cl-multi-delete-btn />
            <cl-flex1 />
            <cl-filter label="上传时间">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -33,12 +36,15 @@
    name: "push-weight",
});
import { ref } from "vue";
import { useCrud, useTable, useUpsert, useSearch } from "@cool-vue/crud";
import { useCool } from "/@/cool";
import { useI18n } from "vue-i18n";
const { service } = useCool();
const { t } = useI18n();
const garbageTypeOptions = ref<{ label: string; value: string }[]>([]);
// cl-upsert
const Upsert = useUpsert({
@@ -98,6 +104,7 @@
            component: { name: "cl-date-text" },
        },
        { label: t("垃圾类型"), prop: "garbageType", minWidth: 120 },
        { label: t("垃圾分类"), prop: "garbageName", minWidth: 140 },
        {
            label: t("垃圾重量"),
            prop: "weight",
@@ -129,7 +136,34 @@
});
// cl-search
const Search = useSearch();
const Search = useSearch({
    items: [
        {
            prop: "deviceNo",
            component: {
                name: "el-input",
                props: {
                    placeholder: t("搜索设备号"),
                    clearable: true,
                },
                style: { width: "150px" },
            },
        },
        {
            prop: "garbageType",
            component: {
                name: "el-select",
                props: {
                    placeholder: t("垃圾类型"),
                    filterable: true,
                    clearable: true,
                },
                options: garbageTypeOptions,
                style: { width: "180px" },
            },
        },
    ],
});
// cl-crud
const Crud = useCrud(
@@ -137,6 +171,14 @@
        service: service.push.weight,
    },
    (app) => {
        service.basicdata.wastetype.list({ status: 1 }).then((res) => {
            garbageTypeOptions.value = (res || [])
                .filter((item: any) => item.status === 1)
                .map((item: any) => ({
                    label: item.name,
                    value: item.code,
                }));
        });
        app.refresh();
    },
);
src/modules/report/components/panel-card.vue
@@ -73,4 +73,25 @@
        padding: 8px 8px 12px;
    }
}
@media (max-width: 768px) {
    .panel-card {
        min-height: 220px;
        &__header {
            flex-wrap: wrap;
            align-items: flex-start;
            padding: 12px 12px 0;
        }
        &__title {
            flex-wrap: wrap;
        }
        &__extra {
            width: 100%;
            overflow-x: auto;
        }
    }
}
</style>
src/modules/report/components/screen-map-panel.vue
@@ -253,6 +253,18 @@
    }
}
@media (max-width: 768px) {
    .map-panel__bar,
    .map-panel__legend {
        flex-wrap: wrap;
        gap: 8px;
    }
    .map-panel__map {
        min-height: 280px;
    }
}
@keyframes map-pulse {
    0%,
    100% {
src/modules/report/components/screen-shell.vue
@@ -62,15 +62,11 @@
const current = computed(() => SCREEN_NAV.find(e => e.key === currentKey.value));
/** 始终留在首页路径,用 ?page= 切换 pageMap,避免跳到 /overview 丢掉导航壳 */
/** 始终留在首页路径,用 ?page= 切换。默认页是地图,overview 也必须带 page,否则会被解析回 map */
function go(key: ScreenKey) {
    if (key === currentKey.value) return;
    const query = { ...route.query } as Record<string, any>;
    if (key === 'overview') {
        delete query.page;
    } else {
        query.page = key;
    }
    query.page = key;
    router.replace({ path: SCREEN_HOME_PATH, query });
}
@@ -285,4 +281,38 @@
    gap: 10px;
    flex-shrink: 0;
}
@media (max-width: 992px) {
    .green-screen__header {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 8px;
    }
    .brand {
        min-width: 0;
        flex: 1 1 auto;
    }
    .nav {
        order: 3;
        flex: 1 1 100%;
    }
    .tools {
        max-width: 100%;
        overflow-x: auto;
    }
}
@media (max-width: 768px) {
    .green-screen {
        min-height: 0;
        height: 100%;
    }
    .brand__title {
        font-size: 16px;
    }
}
</style>
src/modules/report/data/screen-demo.ts
File was deleted
src/modules/report/data/screen-merge.ts
@@ -1,12 +1,5 @@
import type { ScreenData, TimeRange } from './screen';
import { demoScreen } from './screen-demo';
import {
    FieldTracker,
    KPI_GROUPS,
    groupHasLive,
    resolveDataMode,
    type ScreenDataMode
} from './screen-field-meta';
import { FieldTracker, resolveDataMode, type ScreenDataMode } from './screen-field-meta';
import { structureScreen } from './screen-structure';
export type { ScreenDataMode };
@@ -18,271 +11,120 @@
    liveFields: string[];
}
function sum(nums: number[]) {
    return nums.reduce((a, b) => a + (Number(b) || 0), 0);
function num(v: unknown, fallback = 0) {
    const n = Number(v);
    return Number.isFinite(n) ? n : fallback;
}
function hasPositive(nums: number[]) {
    return nums.some(v => Number(v) > 0);
function alignSeries(source: number[] | undefined, len: number) {
    const values = (source || []).map(v => num(v));
    if (!values.length) return Array.from({ length: len }, () => 0);
    if (values.length === len) return values;
    if (values.length > len) return values.slice(values.length - len);
    return [...Array.from({ length: len - values.length }, () => 0), ...values];
}
function hasRankData(list: any[]) {
    return list.length > 0 && list.some(e => Number(e?.people) > 0 || Number(e?.weight) > 0);
}
function pickKpis(
    live: Record<string, number> | undefined,
    demo: Record<string, number>,
    ctx: FieldTracker
) {
    const out = { ...demo };
    if (!live) {
        Object.values(KPI_GROUPS)
            .flat()
            .forEach(key => ctx.markDemo(`kpis.${key}`));
        return out;
    }
    for (const [group, keys] of Object.entries(KPI_GROUPS)) {
        if (groupHasLive(keys, live)) {
            keys.forEach(key => {
                const v = Number(live[key]);
                out[key] = Number.isFinite(v) ? v : demo[key];
                ctx.markLive(`kpis.${key}`);
            });
        } else {
            keys.forEach(key => ctx.markDemo(`kpis.${key}`));
        }
    }
    return out;
}
function pickArray<T>(
    field: string,
    live: T[] | undefined,
    demo: T[],
    ctx: FieldTracker,
    valid: (v: T[]) => boolean
) {
    if (live && valid(live)) {
        ctx.markLive(field);
        return live;
    }
    ctx.markDemo(field);
    return demo;
}
function pickTrend(
    field: string,
    live: { weight: number[]; value: number[]; carbon: number[] } | undefined,
    demo: ScreenData['trend'],
    axis: string[],
    ctx: FieldTracker
) {
    const valid =
        live &&
        live.weight?.length &&
        (sum(live.weight) > 0 || sum(live.value) > 0 || sum(live.carbon) > 0);
    if (valid) {
        ctx.markLive(field);
        return {
            weight: alignSeries(live!.weight, axis.length, live!.weight[live!.weight.length - 1] || 0),
            value: alignSeries(live!.value, axis.length, live!.value[live!.value.length - 1] || 0),
            carbon: alignSeries(live!.carbon, axis.length, live!.carbon[live!.carbon.length - 1] || 0)
        };
    }
    ctx.markDemo(field);
    return alignTrend(demo, axis.length);
}
function alignSeries(source: number[], len: number, fill = 0) {
    if (!source?.length) return Array.from({ length: len }, () => fill);
    if (source.length === len) return [...source];
    if (source.length > len) return source.slice(source.length - len);
    return [...Array.from({ length: len - source.length }, () => fill), ...source];
}
function alignTrend(trend: ScreenData['trend'], len: number) {
    return {
        weight: alignSeries(trend.weight, len),
        value: alignSeries(trend.value, len),
        carbon: alignSeries(trend.carbon, len)
    };
}
function pickWasteMix(
    live: ScreenData['wasteMix'] | undefined,
    demo: ScreenData['wasteMix'],
    ctx: FieldTracker
) {
    if (
        live?.length &&
        live.some(e => Number(e.weight) > 0 || Number(e.count) > 0 || Number(e.value) > 0)
    ) {
        ctx.markLive('wasteMix');
        return live.map((item, i) => ({
            ...demo[i],
            ...item,
            color: item.color || demo[i]?.color
        }));
    }
    ctx.markDemo('wasteMix');
    return demo;
}
function pickRecycleItems(
    live: ScreenData['recycleItems'] | undefined,
    demo: ScreenData['recycleItems'],
    ctx: FieldTracker
) {
    if (live?.length && live.some(e => Number(e.weight) > 0 || Number(e.value) > 0 || Number(e.carbon) > 0)) {
        ctx.markLive('recycleItems');
        return live.map((item, i) => ({
            ...demo[i],
            ...item,
            color: item.color || demo[i]?.color
        }));
    }
    ctx.markDemo('recycleItems');
    return demo;
}
function pickPointFlow(
    live: ScreenData['pointFlow'] | undefined,
    demo: ScreenData['pointFlow'],
    ctx: FieldTracker
) {
    const out = { ...demo };
    if (!live) {
        ctx.markDemo('pointFlow');
        (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key =>
            ctx.markDemo(`pointFlow.${key}`)
        );
        return out;
    }
    let hasLive = false;
    (['issued', 'transfer', 'donate', 'mall', 'balance'] as const).forEach(key => {
        if (Number(live[key]) > 0) {
            out[key] = live[key];
            ctx.markLive(`pointFlow.${key}`);
            hasLive = true;
        } else {
            ctx.markDemo(`pointFlow.${key}`);
        }
    });
    if (hasLive) ctx.markLive('pointFlow');
    else ctx.markDemo('pointFlow');
    return out;
}
function pickOrdersByType(
    live: ScreenData['ordersByType'] | undefined,
    demo: ScreenData['ordersByType'],
    ctx: FieldTracker
) {
    const keys = ['现场回收', '预约上门', '大屏投递', '活动回收'] as const;
    const liveValid = live?.axis?.length && keys.some(k => hasPositive(live[k] || []));
    if (liveValid) {
        ctx.markLive('ordersByType');
        return live!;
    }
    ctx.markDemo('ordersByType');
    return demo;
}
function pickAppointmentFlow(
    live: ScreenData['appointmentFlow'] | undefined,
    demo: ScreenData['appointmentFlow'],
    ctx: FieldTracker
) {
    if (live?.length && live.some(e => Number(e.value) > 0)) {
        ctx.markLive('appointmentFlow');
        return live;
    }
    ctx.markDemo('appointmentFlow');
    return demo;
}
function pickSorterStatus(
    live: ScreenData['sorterStatus'] | undefined,
    demo: ScreenData['sorterStatus'],
    ctx: FieldTracker
) {
    if (live?.length && sum(live.map(e => Number(e.value))) > 0) {
        ctx.markLive('sorterStatus');
        return live;
    }
    ctx.markDemo('sorterStatus');
    return demo;
}
function pickAxis(
    live: ScreenData | null | undefined,
    demo: ScreenData,
    structure: ScreenData,
    ctx: FieldTracker
) {
    const useLiveAxis =
        live?.axis?.length &&
        (sum(live.trend?.weight || []) > 0 ||
            sum(live.participateTrend || []) > 0 ||
            sum(live.deliverTrend || []) > 0 ||
            live.axis.length > 1);
    if (useLiveAxis) {
        ctx.markLive('axis');
        return live!.axis;
    }
    ctx.markDemo('axis');
    return demo.axis.length ? demo.axis : structure.axis;
}
/** 结构 + 演示 + 真实数据按字段/分组合并 */
/** 用接口结果覆盖零值结构。缺字段保持 0 或空列表,不再回落到演示数据。 */
export function resolveScreenData(live: ScreenData | null | undefined, range: TimeRange): ResolvedScreenData {
    const structure = structureScreen(range);
    const demo = demoScreen(range);
    const base = structureScreen(range);
    const ctx = new FieldTracker();
    const axis = pickAxis(live, demo, structure, ctx);
    const kpis = pickKpis(live?.kpis, demo.kpis, ctx);
    const wasteMix = pickWasteMix(live?.wasteMix, demo.wasteMix, ctx);
    const recycleItems = pickRecycleItems(live?.recycleItems, demo.recycleItems, ctx);
    const trend = pickTrend('trend', live?.trend, demo.trend, axis, ctx);
    let yearCarbon = demo.yearCarbon;
    if (live?.yearCarbon?.length && sum(live.yearCarbon) > 0) {
        yearCarbon = live.yearCarbon;
        ctx.markLive('yearCarbon');
    } else {
        ctx.markDemo('yearCarbon');
    if (!live) {
        return {
            data: base,
            mode: 'live',
            demoFields: [],
            liveFields: []
        };
    }
    const deptRank = pickArray('deptRank', live?.deptRank, demo.deptRank, ctx, hasRankData);
    const classRank = pickArray('classRank', live?.classRank, demo.classRank, ctx, hasRankData);
    const majorRank = pickArray('majorRank', live?.majorRank, demo.majorRank, ctx, hasRankData);
    const pointFlow = pickPointFlow(live?.pointFlow, demo.pointFlow, ctx);
    const axis = live.axis?.length ? live.axis : base.axis;
    ctx.markLive('axis');
    let participateTrend = alignSeries(demo.participateTrend, axis.length);
    if (live?.participateTrend?.length && sum(live.participateTrend) > 0) {
        participateTrend = alignSeries(live.participateTrend, axis.length);
        ctx.markLive('participateTrend');
    } else {
        ctx.markDemo('participateTrend');
    }
    const kpis = { ...base.kpis };
    Object.keys(kpis).forEach(key => {
        if (live.kpis && live.kpis[key] != null) {
            kpis[key] = num(live.kpis[key]);
        }
        ctx.markLive(`kpis.${key}`);
    });
    let deliverTrend = alignSeries(demo.deliverTrend, axis.length);
    if (live?.deliverTrend?.length && sum(live.deliverTrend) > 0) {
        deliverTrend = alignSeries(live.deliverTrend, axis.length);
        ctx.markLive('deliverTrend');
    } else {
        ctx.markDemo('deliverTrend');
    }
    const wasteMix = live.wasteMix?.length
        ? live.wasteMix.map((item, i) => ({
                ...base.wasteMix[i],
                ...item,
                weight: num(item.weight),
                value: num(item.value),
                count: num(item.count),
                color: item.color || base.wasteMix[i]?.color
            }))
        : base.wasteMix;
    ctx.markLive('wasteMix');
    const ordersByType = pickOrdersByType(live?.ordersByType, demo.ordersByType, ctx);
    const appointmentFlow = pickAppointmentFlow(live?.appointmentFlow, demo.appointmentFlow, ctx);
    const sorterStatus = pickSorterStatus(live?.sorterStatus, demo.sorterStatus, ctx);
    const vehicles = pickArray('vehicles', live?.vehicles, demo.vehicles, ctx, v => v.length > 0);
    const sites = pickArray('sites', live?.sites, demo.sites, ctx, v => v.length > 0);
    const recycleItems = live.recycleItems?.length
        ? live.recycleItems.map((item, i) => ({
                ...base.recycleItems[i],
                ...item,
                weight: num(item.weight),
                value: num(item.value),
                carbon: num(item.carbon),
                color: item.color || base.recycleItems[i]?.color
            }))
        : base.recycleItems;
    ctx.markLive('recycleItems');
    const trend = {
        weight: alignSeries(live.trend?.weight, axis.length),
        value: alignSeries(live.trend?.value, axis.length),
        carbon: alignSeries(live.trend?.carbon, axis.length)
    };
    ctx.markLive('trend');
    const yearCarbon = live.yearCarbon?.length
        ? alignSeries(live.yearCarbon, 12)
        : base.yearCarbon;
    ctx.markLive('yearCarbon');
    const deptRank = Array.isArray(live.deptRank) ? live.deptRank : [];
    const classRank = Array.isArray(live.classRank) ? live.classRank : [];
    const majorRank = Array.isArray(live.majorRank) ? live.majorRank : [];
    ctx.markLive('deptRank');
    ctx.markLive('classRank');
    ctx.markLive('majorRank');
    const pointFlow = {
        issued: num(live.pointFlow?.issued),
        transfer: num(live.pointFlow?.transfer),
        donate: num(live.pointFlow?.donate),
        mall: num(live.pointFlow?.mall),
        balance: num(live.pointFlow?.balance)
    };
    ctx.markLive('pointFlow');
    const participateTrend = alignSeries(live.participateTrend, axis.length);
    const deliverTrend = alignSeries(live.deliverTrend, axis.length);
    ctx.markLive('participateTrend');
    ctx.markLive('deliverTrend');
    const ordersByType = live.ordersByType?.axis?.length
        ? {
                axis: live.ordersByType.axis,
                现场回收: alignSeries(live.ordersByType.现场回收, live.ordersByType.axis.length),
                预约上门: alignSeries(live.ordersByType.预约上门, live.ordersByType.axis.length),
                大屏投递: alignSeries(live.ordersByType.大屏投递, live.ordersByType.axis.length),
                活动回收: alignSeries(live.ordersByType.活动回收, live.ordersByType.axis.length)
            }
        : base.ordersByType;
    ctx.markLive('ordersByType');
    const appointmentFlow = live.appointmentFlow?.length ? live.appointmentFlow : base.appointmentFlow;
    const sorterStatus = live.sorterStatus?.length ? live.sorterStatus : base.sorterStatus;
    const vehicles = Array.isArray(live.vehicles) ? live.vehicles : [];
    const sites = Array.isArray(live.sites) ? live.sites : [];
    ctx.markLive('appointmentFlow');
    ctx.markLive('sorterStatus');
    ctx.markLive('vehicles');
    ctx.markLive('sites');
    const data: ScreenData = {
        range,
@@ -303,21 +145,20 @@
        sorterStatus,
        vehicles,
        sites,
        unavailable: live?.unavailable || []
        unavailable: live.unavailable || []
    };
    return {
        data,
        mode: resolveDataMode(live, ctx),
        demoFields: ctx.listDemo(),
        demoFields: [],
        liveFields: ctx.listLive()
    };
}
/** 接口失败或无 live 数据时的初始展示 */
/** 接口尚未返回时先展示零值,避免先闪出演示数字 */
export function initialScreenData(range: TimeRange = 'month') {
    return resolveScreenData(null, range);
}
export { structureScreen, buildScreenAxis } from './screen-structure';
export { demoScreen } from './screen-demo';
src/modules/report/hooks/use-screen.ts
@@ -103,7 +103,6 @@
        } catch (e: any) {
            applyResolved(resolveScreenData(null, sharedTimeRange.value));
            const msg = e?.message || '';
            // 首页静默降级到演示数据,不展示登录/权限类错误文案
            if (!/登录失效|无权限/.test(msg)) {
                loadError.value = msg || '驾驶舱接口调用失败';
            }
@@ -124,7 +123,7 @@
    return { load, loading, loadError, dataMode };
}
/** 首页不展示「演示」标识,底层仍可静默使用演示数据填充 */
/** 首页只展示接口汇总结果,不再用演示数据填充 */
export function useScreenFieldSource() {
    const { dataMode, demoFields } = useScreenData();
src/modules/report/views/dailydepartment.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <!--cl-multi-delete-btn /-->
            <cl-flex1 />
            <cl-filter label="日期">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -504,7 +507,15 @@
});
// cl-search
const Search = useSearch();
function hideDateSearch({ exposed }: { exposed: any }) {
    const items = exposed.config?.items as { prop?: string }[] | undefined;
    const index = items?.findIndex(e => e.prop === "date") ?? -1;
    if (index >= 0) items?.splice(index, 1);
}
const Search = useSearch({
    plugins: [hideDateSearch]
});
// cl-crud
const Crud = useCrud(
src/modules/report/views/dailysite.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <!--cl-multi-delete-btn /-->
            <cl-flex1 />
            <cl-filter label="日期">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -508,7 +511,15 @@
});
// cl-search
const Search = useSearch();
function hideDateSearch({ exposed }: { exposed: any }) {
    const items = exposed.config?.items as { prop?: string }[] | undefined;
    const index = items?.findIndex(e => e.prop === "date") ?? -1;
    if (index >= 0) items?.splice(index, 1);
}
const Search = useSearch({
    plugins: [hideDateSearch]
});
// cl-crud
const Crud = useCrud(
src/modules/report/views/dailyvehicle.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <!--cl-multi-delete-btn /-->
            <cl-flex1 />
            <cl-filter label="数据日期">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -262,7 +265,15 @@
});
// cl-search
const Search = useSearch();
function hideDateSearch({ exposed }: { exposed: any }) {
    const items = exposed.config?.items as { prop?: string }[] | undefined;
    const index = items?.findIndex(e => e.prop === "date") ?? -1;
    if (index >= 0) items?.splice(index, 1);
}
const Search = useSearch({
    plugins: [hideDateSearch]
});
// cl-crud
const Crud = useCrud(
src/modules/report/views/joblog.vue
@@ -8,6 +8,9 @@
            <!-- 删除按钮 -->
            <!--cl-multi-delete-btn /-->
            <cl-flex1 />
            <cl-filter label="日期">
                <cl-date-picker type="daterange" />
            </cl-filter>
            <!-- 条件搜索 -->
            <cl-search ref="Search" />
        </cl-row>
@@ -173,7 +176,15 @@
});
// cl-search
const Search = useSearch();
function hideDateSearch({ exposed }: { exposed: any }) {
    const items = exposed.config?.items as { prop?: string }[] | undefined;
    const index = items?.findIndex(e => e.prop === "dataDate") ?? -1;
    if (index >= 0) items?.splice(index, 1);
}
const Search = useSearch({
    plugins: [hideDateSearch]
});
// cl-crud
const Crud = useCrud(
src/modules/report/views/screen/carbon.vue
@@ -1,6 +1,6 @@
<template>
    <div class="screen-page">
        <div class="kpi-grid" style="--kpi-cols: 6">
        <div class="kpi-grid" style="--kpi-cols: 5">
            <kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
        </div>
@@ -45,16 +45,20 @@
import { computed } from 'vue';
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
const rangeLabel = computed(
    () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '本区间'
);
const kpis = computed(() => [
    { field: 'kpis.totalCarbonTon', label: '累计碳减排', value: data.value.kpis.totalCarbonTon, suffix: '吨CO₂e', fixed: 1 },
    { field: 'kpis.yearCarbonTon', label: '本年度碳减排', value: data.value.kpis.yearCarbonTon, suffix: '吨CO₂e', fixed: 1 },
    { field: 'kpis.periodCarbonTon', label: '本区间碳减排', value: data.value.kpis.periodCarbonTon, suffix: '吨CO₂e', fixed: 2 },
    { field: 'kpis.periodCarbonTon', label: `${rangeLabel.value}碳减排`, value: data.value.kpis.periodCarbonTon, suffix: '吨CO₂e', fixed: 2 },
    { field: 'kpis.totalWeightTon', label: '累计资源回收', value: data.value.kpis.totalWeightTon, suffix: '吨', fixed: 1 },
    { field: 'kpis.totalParticipants', label: '累计参与师生', value: data.value.kpis.totalParticipants, suffix: '人', fixed: 0 },
    { field: 'kpis.greenActions', label: '累计环保行为', value: data.value.kpis.greenActions, suffix: '次', fixed: 0 }
src/modules/report/views/screen/map.vue
@@ -1,7 +1,7 @@
<template>
    <div class="screen-page dash">
        <!-- KPI 指标条 -->
        <div class="kpi-grid" style="--kpi-cols: 8">
        <div class="kpi-grid" style="--kpi-cols: 7">
            <kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
        </div>
@@ -57,7 +57,7 @@
                    <template #extra>
                        <cl-select-button v-model="itemMetric" :options="itemOptions" small />
                    </template>
                    <v-chart :option="itemOption" autoresize class="chart" />
                    <v-chart :option="itemOption" autoresize class="chart chart--items" />
                </panel-card>
            </div>
        </div>
@@ -84,9 +84,10 @@
import PanelCard from '../../components/panel-card.vue';
import ScreenMapPanel from '../../components/screen-map-panel.vue';
import CameraMonitor from '../../../monitor/views/cameras.vue';
import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data } = useScreenData();
const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
@@ -112,10 +113,13 @@
    { label: '碳减排', value: 'carbon' }
];
/** 顶部 KPI:取总览域核心 8 项 */
const rangeLabel = computed(
    () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '本区间'
);
/** 顶部 KPI */
const kpis = computed(() => [
    { field: 'kpis.todayWeightKg', label: '今日回收量', value: data.value.kpis.todayWeightKg, suffix: 'kg', fixed: 1 },
    { field: 'kpis.periodWeightTon', label: '本区间回收量', value: data.value.kpis.periodWeightTon, suffix: '吨', fixed: 2 },
    { field: 'kpis.periodWeightTon', label: `${rangeLabel.value}回收量`, value: data.value.kpis.periodWeightTon, suffix: '吨', fixed: 2 },
    { field: 'kpis.resourceRate', label: '资源化率', value: data.value.kpis.resourceRate, suffix: '%', fixed: 1 },
    { field: 'kpis.periodValue', label: '回收价值', value: data.value.kpis.periodValue, suffix: '元', fixed: 0 },
    { field: 'kpis.periodCarbonTon', label: '碳减排', value: data.value.kpis.periodCarbonTon, suffix: '吨CO₂e', fixed: 2 },
@@ -353,4 +357,65 @@
        }
    }
}
@media (max-width: 768px) {
    .dash,
    .dash-body,
    .dash-col {
        height: auto;
        min-height: 0;
        overflow: visible;
        flex: none;
    }
    .dash :deep(.kpi-grid) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .dash-card--flex {
        flex: none;
        height: auto;
        min-height: 0;
        overflow: visible;
        :deep(.panel-card) {
            height: auto;
            min-height: 0;
            overflow: visible;
        }
        :deep(.panel-card__body) {
            flex: none;
            height: auto;
            min-height: 0;
            overflow: visible;
        }
    }
    /* 地图画布层级很高,限制在中栏内,避免盖住上下两块图表 */
    .dash-card--map {
        position: relative;
        z-index: 0;
        flex: none;
        height: 480px;
        min-height: 480px;
        overflow: hidden;
    }
    .dash .chart {
        display: block;
        height: 260px;
        min-height: 260px;
    }
    .dash .chart--items {
        height: 420px;
        min-height: 420px;
    }
    .dash-foot {
        height: auto;
        min-height: 300px;
    }
}
</style>
src/modules/report/views/screen/operation.vue
@@ -323,4 +323,15 @@
    }
}
@media (max-width: 768px) {
    .screen-page .table {
        overflow-x: auto;
    }
    .screen-page .table--vehicle :deep(.table__head),
    .screen-page .table--vehicle .table__row {
        min-width: 520px;
    }
}
</style>
src/modules/report/views/screen/overview.vue
@@ -1,6 +1,6 @@
<template>
    <div class="screen-page">
        <div class="kpi-grid" style="--kpi-cols: 8">
        <div class="kpi-grid" style="--kpi-cols: 7">
            <kpi-card v-for="item in kpis" :key="item.label" v-bind="item" />
        </div>
@@ -51,6 +51,7 @@
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
import ScreenCameraPreview from '../../components/screen-camera-preview.vue';
import { TIME_RANGE_OPTIONS } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data, timeRange } = useScreenData();
@@ -72,9 +73,12 @@
    { label: '碳减排', value: 'carbon' }
];
const rangeLabel = computed(
    () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '本区间'
);
const kpis = computed(() => [
    { field: 'kpis.todayWeightKg', label: '今日回收量', value: data.value.kpis.todayWeightKg, suffix: 'kg', fixed: 1, hint: '实时称重汇总' },
    { field: 'kpis.periodWeightTon', label: '本区间回收量', value: data.value.kpis.periodWeightTon, suffix: '吨', fixed: 2, hint: '当前时间范围' },
    { field: 'kpis.periodWeightTon', label: `${rangeLabel.value}回收量`, value: data.value.kpis.periodWeightTon, suffix: '吨', fixed: 2, hint: '当前时间范围' },
    { field: 'kpis.resourceRate', label: '资源化率', value: data.value.kpis.resourceRate, suffix: '%', fixed: 1, hint: '可回收物重量/总重量,不含大件' },
    { field: 'kpis.periodValue', label: '回收价值', value: data.value.kpis.periodValue, suffix: '元', fixed: 0, hint: '日表估算销售额' },
    { field: 'kpis.periodCarbonTon', label: '碳减排', value: data.value.kpis.periodCarbonTon, suffix: '吨CO₂e', fixed: 2, hint: '分类重量 × 碳减因数' },
src/modules/report/views/screen/participation.vue
@@ -69,10 +69,10 @@
import { computed, ref } from 'vue';
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
import { type RankMetric } from '../../data/screen';
import { TIME_RANGE_OPTIONS, type RankMetric } from '../../data/screen';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data } = useScreenData();
const { data, timeRange } = useScreenData();
const { isDemoSection } = useScreenFieldSource();
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
@@ -99,10 +99,14 @@
    { label: '碳减排', value: 'carbon' }
];
const rangeLabel = computed(
    () => TIME_RANGE_OPTIONS.find(e => e.value === timeRange.value)?.label || '本区间'
);
const kpis = computed(() => [
    { field: 'kpis.totalParticipants', label: '参与师生', value: data.value.kpis.totalParticipants, suffix: '人', fixed: 0 },
    { field: 'kpis.participateRate', label: '参与率', value: data.value.kpis.participateRate, suffix: '%', fixed: 1, hint: '参与人数 / 参数 student.count.{部门ID}' },
    { field: 'kpis.newParticipants', label: '本区间新增参与', value: data.value.kpis.newParticipants, suffix: '人', fixed: 0, hint: '区间内出现过的去重用户' },
    { field: 'kpis.newParticipants', label: `${rangeLabel.value}新增参与`, value: data.value.kpis.newParticipants, suffix: '人', fixed: 0, hint: '区间内出现过的去重用户' },
    { field: 'kpis.pointsIssued', label: '碳积分发放', value: data.value.kpis.pointsIssued, suffix: '分', fixed: 0 },
    { field: 'kpis.pointsConsumed', label: '碳积分消费', value: data.value.kpis.pointsConsumed, suffix: '分', fixed: 0 },
    { field: 'kpis.pointsBalance', label: '碳积分余额', value: data.value.kpis.pointsBalance, suffix: '分', fixed: 0 }
@@ -252,4 +256,10 @@
        }
    }
}
@media (max-width: 576px) {
    .screen-page .flow__split {
        grid-template-columns: 1fr;
    }
}
</style>
src/plugins/view/components/group.vue
@@ -680,6 +680,12 @@
    }
    @media only screen and (max-width: 768px) {
        .cl-view-group__right .head .title {
            max-width: calc(100% - 88px);
            text-overflow: ellipsis;
            padding: 0 8px;
        }
        .cl-view-group__left {
            overflow: hidden;
            transition: width 0.2s;