wanshenmean
4 天以前 f288ccc545f8cc32bc922c96dfb3cab9a1f92ec6
feat: 初始化WMS前端项目并实现基础功能

新增WMS前端项目基础结构,包含以下功能:
- 使用Vue3 + Vite + Element Plus搭建前端框架
- 实现用户登录、菜单管理、权限控制等核心模块
- 添加库存、入库、出库等业务模块页面
- 配置axios请求拦截器和响应拦截器
- 实现动态路由加载和菜单权限控制
- 添加.env环境变量配置和开发代理
- 集成Pinia状态管理
- 实现基础布局和响应式设计
已添加41个文件
已重命名1个文件
已删除1个文件
已修改24个文件
7166 ■■■■■ 文件已修改
Code/.omc/state/last-tool-error.json 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/mission-state.json 532 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/subagent-tracking.json 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/src/extension/taskinfo/robotState.jsx 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/src/router/viewGird.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/src/views/taskinfo/robotState.vue 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/IRobotStateRepository.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/WIDESEAWCS_ITaskInfoRepository.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotStateService.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/Dt_RobotState.cs 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/RobotCraneDevice.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/RobotSocketState.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Robot/RobotCraneDevice.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/WIDESEAWCS_QuartzJob.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotStateController.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/RobotStateRepository.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotStateService.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotMessageRouter.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotPrefixCommandHandler.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotSimpleCommandHandler.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/ISocketClientGateway.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotMessageHandler.cs 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotStateManager.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/SocketClientGateway.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/.env.development 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/index.html 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/package-lock.json 1929 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/package.json 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/pnpm-lock.yaml 1297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/App.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/auth.ts 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/client.ts 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/index.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/inbound.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/menu.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/outbound.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/stock.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/user.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/layouts/MainLayout.vue 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/locales/zh-CN.ts 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/main.ts 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/router/index.ts 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/store/index.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/store/modules/menu.ts 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/store/user.ts 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/utils/menuTransform.ts 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/dashboard/index.vue 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/inbound/inboundOrderDetail.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/inbound/index.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/login/index.vue 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/outbound/index.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/outbound/outboundOrderDetail.vue 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/stock/index.vue 340 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/src/views/stock/stockInfoDetail.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/tsconfig.json 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/tsconfig.node.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben/vite.config.ts 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben_v2 @ 07c4ad 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WMS_Api_Design.md 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/last-tool-error.json
@@ -1,7 +1,7 @@
{
  "tool_name": "Bash",
  "tool_input_preview": "{\"command\":\"cd D:\\\\Git\\\\ShanMeiXinNengYuan\\\\Code\\\\WCS\\\\WIDESEAWCS_Client && npm run build 2>&1 | head -30\",\"timeout\":120000}",
  "error": "Exit code 1\n/usr/bin/bash: line 1: cd: D:GitShanMeiXinNengYuanCodeWCSWIDESEAWCS_Client: No such file or directory",
  "timestamp": "2026-04-19T07:15:17.022Z",
  "retry_count": 1
  "tool_input_preview": "{\"command\":\"cd \\\"D:/Git/ShanMeiXinNengYuan/Code/WMS\\\" && git clone --depth 1 https://ghproxy.com/https://github.com/vbenjs/vue-vben-admin.git WIDESEA_WMSClient_Vben 2>&1\",\"timeout\":300000,\"description...",
  "error": "Exit code 128\nCloning into 'WIDESEA_WMSClient_Vben'...\nfatal: unable to access 'https://ghproxy.com/https://github.com/vbenjs/vue-vben-admin.git/': Failed to connect to ghproxy.com port 443 after 21158 ms: Could not connect to server",
  "timestamp": "2026-04-19T13:54:19.051Z",
  "retry_count": 4
}
Code/.omc/state/mission-state.json
@@ -1,5 +1,5 @@
{
  "updatedAt": "2026-04-18T08:52:24.581Z",
  "updatedAt": "2026-04-19T13:53:57.853Z",
  "missions": [
    {
      "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none",
@@ -1268,6 +1268,536 @@
          "sourceKey": "session-stop:a6a0c97facebc27a6"
        }
      ]
    },
    {
      "id": "session:4a7d9ed6-773a-4962-9881-9dcda1653389:none",
      "source": "session",
      "name": "none",
      "objective": "Session mission",
      "createdAt": "2026-04-19T11:24:03.847Z",
      "updatedAt": "2026-04-19T12:58:38.564Z",
      "status": "done",
      "workerCount": 5,
      "taskCounts": {
        "total": 5,
        "pending": 0,
        "blocked": 0,
        "inProgress": 0,
        "completed": 5,
        "failed": 0
      },
      "agents": [
        {
          "name": "general-purpose:af12f69",
          "role": "general-purpose",
          "ownership": "af12f692dd4a3fb28",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T12:58:38.564Z"
        },
        {
          "name": "general-purpose:aa2a37e",
          "role": "general-purpose",
          "ownership": "aa2a37e07afb9d479",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T11:24:36.379Z"
        },
        {
          "name": "general-purpose:a6eb9a9",
          "role": "general-purpose",
          "ownership": "a6eb9a903c850f24a",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T11:24:47.161Z"
        },
        {
          "name": "general-purpose:a9803cf",
          "role": "general-purpose",
          "ownership": "a9803cf811cccaa24",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T11:25:43.000Z"
        },
        {
          "name": "general-purpose:a9e37be",
          "role": "general-purpose",
          "ownership": "a9e37bec52fcbdaa5",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T11:26:55.341Z"
        }
      ],
      "timeline": [
        {
          "id": "session-start:a9803cf811cccaa24:2026-04-19T11:25:09.331Z",
          "at": "2026-04-19T11:25:09.331Z",
          "kind": "update",
          "agent": "general-purpose:a9803cf",
          "detail": "started general-purpose:a9803cf",
          "sourceKey": "session-start:a9803cf811cccaa24"
        },
        {
          "id": "session-stop:a9803cf811cccaa24:2026-04-19T11:25:43.000Z",
          "at": "2026-04-19T11:25:43.000Z",
          "kind": "completion",
          "agent": "general-purpose:a9803cf",
          "detail": "completed",
          "sourceKey": "session-stop:a9803cf811cccaa24"
        },
        {
          "id": "session-start:a9e37bec52fcbdaa5:2026-04-19T11:25:51.811Z",
          "at": "2026-04-19T11:25:51.811Z",
          "kind": "update",
          "agent": "general-purpose:a9e37be",
          "detail": "started general-purpose:a9e37be",
          "sourceKey": "session-start:a9e37bec52fcbdaa5"
        },
        {
          "id": "session-stop:a9e37bec52fcbdaa5:2026-04-19T11:26:55.341Z",
          "at": "2026-04-19T11:26:55.341Z",
          "kind": "completion",
          "agent": "general-purpose:a9e37be",
          "detail": "completed",
          "sourceKey": "session-stop:a9e37bec52fcbdaa5"
        },
        {
          "id": "session-stop:a4f2a4a86620e67ac:2026-04-19T12:58:38.564Z",
          "at": "2026-04-19T12:58:38.564Z",
          "kind": "completion",
          "agent": "general-purpose:af12f69",
          "detail": "completed",
          "sourceKey": "session-stop:a4f2a4a86620e67ac"
        }
      ]
    },
    {
      "id": "session:d619041b-8d2b-4d40-ac1a-9c570d800e7d:none",
      "source": "session",
      "name": "none",
      "objective": "Session mission",
      "createdAt": "2026-04-19T13:39:55.243Z",
      "updatedAt": "2026-04-19T13:53:57.853Z",
      "status": "running",
      "workerCount": 34,
      "taskCounts": {
        "total": 34,
        "pending": 0,
        "blocked": 0,
        "inProgress": 3,
        "completed": 31,
        "failed": 0
      },
      "agents": [
        {
          "name": "agent-menu:a9260b4",
          "role": "agent-menu",
          "ownership": "a9260b44a0c26528b",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:41:04.664Z"
        },
        {
          "name": "agent-auth:a6f1e5c",
          "role": "agent-auth",
          "ownership": "a6f1e5c50a57e0d5d",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:40:20.808Z"
        },
        {
          "name": "agent-pages:a5a2a89",
          "role": "agent-pages",
          "ownership": "a5a2a89d2fb5f17ff",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:41:01.814Z"
        },
        {
          "name": "agent-scaffold:a1a6151",
          "role": "agent-scaffold",
          "ownership": "a1a6151ba7f364cfb",
          "status": "running",
          "currentStep": null,
          "latestUpdate": null,
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:39:55.484Z"
        },
        {
          "name": "agent-api:a4ce4ef",
          "role": "agent-api",
          "ownership": "a4ce4ef36b3693f58",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:40:12.096Z"
        },
        {
          "name": "agent-layout:af02a89",
          "role": "agent-layout",
          "ownership": "af02a89022a18c649",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:40:15.829Z"
        },
        {
          "name": "agent-api:ad03467",
          "role": "agent-api",
          "ownership": "ad03467a75e8afc0a",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:44:15.841Z"
        },
        {
          "name": "agent-auth:a3cc9be",
          "role": "agent-auth",
          "ownership": "a3cc9be047c9352e5",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:44:29.101Z"
        },
        {
          "name": "agent-menu:a77fb32",
          "role": "agent-menu",
          "ownership": "a77fb323ad44a6284",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:43:03.806Z"
        },
        {
          "name": "agent-layout:a81ba9f",
          "role": "agent-layout",
          "ownership": "a81ba9fdad4456dfd",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:42:27.425Z"
        },
        {
          "name": "agent-pages:a94adb2",
          "role": "agent-pages",
          "ownership": "a94adb2a88c1eb29c",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:42:26.922Z"
        },
        {
          "name": "agent-pages:a211822",
          "role": "agent-pages",
          "ownership": "a2118226e3813727c",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:42:56.060Z"
        },
        {
          "name": "agent-layout:ab75021",
          "role": "agent-layout",
          "ownership": "ab750215093131b28",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:42:55.376Z"
        },
        {
          "name": "agent-menu:ae9ed78",
          "role": "agent-menu",
          "ownership": "ae9ed78222ecc6cad",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:27.389Z"
        },
        {
          "name": "agent-api:ae5c327",
          "role": "agent-api",
          "ownership": "ae5c327157aec2fb1",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:46:52.233Z"
        },
        {
          "name": "agent-auth:adc223f",
          "role": "agent-auth",
          "ownership": "adc223f651f1328bd",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:44:53.789Z"
        },
        {
          "name": "agent-pages:a756617",
          "role": "agent-pages",
          "ownership": "a756617ca874ac3c1",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:51:43.427Z"
        },
        {
          "name": "agent-layout:a4c96b8",
          "role": "agent-layout",
          "ownership": "a4c96b89f113f809d",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:47:11.646Z"
        },
        {
          "name": "agent-auth:a8a57aa",
          "role": "agent-auth",
          "ownership": "a8a57aa22517c31f5",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:49:10.620Z"
        },
        {
          "name": "agent-api:ab1d288",
          "role": "agent-api",
          "ownership": "ab1d2884ac7a493bd",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:47:18.573Z"
        },
        {
          "name": "agent-layout:a0cbc46",
          "role": "agent-layout",
          "ownership": "a0cbc46d413ef4196",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:47:31.885Z"
        },
        {
          "name": "agent-api:a8d6281",
          "role": "agent-api",
          "ownership": "a8d6281531b04991f",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:47:38.716Z"
        },
        {
          "name": "writer:a8c91fb",
          "role": "writer",
          "ownership": "a8c91fb2cf222b293",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:50:25.144Z"
        },
        {
          "name": "agent-auth:ade32f8",
          "role": "agent-auth",
          "ownership": "ade32f8bf35b26757",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:13.860Z"
        },
        {
          "name": "agent-pages:ac557d7",
          "role": "agent-pages",
          "ownership": "ac557d7e2a1b5f729",
          "status": "running",
          "currentStep": null,
          "latestUpdate": null,
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:51:43.789Z"
        },
        {
          "name": "agent-layout:a9c6179",
          "role": "agent-layout",
          "ownership": "a9c6179a801e0e434",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:12.657Z"
        },
        {
          "name": "writer:a7627b0",
          "role": "writer",
          "ownership": "a7627b0b0e0b60be2",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:01.512Z"
        },
        {
          "name": "agent-api:aba045f",
          "role": "agent-api",
          "ownership": "aba045f68cd9f61d0",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:03.192Z"
        },
        {
          "name": "agent-auth:aeed34c",
          "role": "agent-auth",
          "ownership": "aeed34c94d463a92c",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:52:27.391Z"
        },
        {
          "name": "agent-menu:a9271b2",
          "role": "agent-menu",
          "ownership": "a9271b2a5525f053a",
          "status": "running",
          "currentStep": null,
          "latestUpdate": null,
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:53:39.468Z"
        },
        {
          "name": "agent-api:ae5d5fc",
          "role": "agent-api",
          "ownership": "ae5d5fcffcb393b67",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:53:47.265Z"
        },
        {
          "name": "agent-auth:ad92b78",
          "role": "agent-auth",
          "ownership": "ad92b7876bc72bf7e",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:53:57.853Z"
        },
        {
          "name": "agent-layout:affcaab",
          "role": "agent-layout",
          "ownership": "affcaabcac0234d22",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:53:49.029Z"
        },
        {
          "name": "writer:ac6c4a2",
          "role": "writer",
          "ownership": "ac6c4a28a6422e89d",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-19T13:53:49.217Z"
        }
      ],
      "timeline": [
        {
          "id": "session-start:ad92b7876bc72bf7e:2026-04-19T13:53:42.036Z",
          "at": "2026-04-19T13:53:42.036Z",
          "kind": "update",
          "agent": "agent-auth:ad92b78",
          "detail": "started agent-auth:ad92b78",
          "sourceKey": "session-start:ad92b7876bc72bf7e"
        },
        {
          "id": "session-start:affcaabcac0234d22:2026-04-19T13:53:42.701Z",
          "at": "2026-04-19T13:53:42.701Z",
          "kind": "update",
          "agent": "agent-layout:affcaab",
          "detail": "started agent-layout:affcaab",
          "sourceKey": "session-start:affcaabcac0234d22"
        },
        {
          "id": "session-start:ac6c4a28a6422e89d:2026-04-19T13:53:43.519Z",
          "at": "2026-04-19T13:53:43.519Z",
          "kind": "update",
          "agent": "writer:ac6c4a2",
          "detail": "started writer:ac6c4a2",
          "sourceKey": "session-start:ac6c4a28a6422e89d"
        },
        {
          "id": "session-stop:ae5d5fcffcb393b67:2026-04-19T13:53:47.265Z",
          "at": "2026-04-19T13:53:47.265Z",
          "kind": "completion",
          "agent": "agent-api:ae5d5fc",
          "detail": "completed",
          "sourceKey": "session-stop:ae5d5fcffcb393b67"
        },
        {
          "id": "session-stop:affcaabcac0234d22:2026-04-19T13:53:49.029Z",
          "at": "2026-04-19T13:53:49.029Z",
          "kind": "completion",
          "agent": "agent-layout:affcaab",
          "detail": "completed",
          "sourceKey": "session-stop:affcaabcac0234d22"
        },
        {
          "id": "session-stop:ac6c4a28a6422e89d:2026-04-19T13:53:49.217Z",
          "at": "2026-04-19T13:53:49.217Z",
          "kind": "completion",
          "agent": "writer:ac6c4a2",
          "detail": "completed",
          "sourceKey": "session-stop:ac6c4a28a6422e89d"
        },
        {
          "id": "session-stop:ad92b7876bc72bf7e:2026-04-19T13:53:57.853Z",
          "at": "2026-04-19T13:53:57.853Z",
          "kind": "completion",
          "agent": "agent-auth:ad92b78",
          "detail": "completed",
          "sourceKey": "session-stop:ad92b7876bc72bf7e"
        }
      ]
    }
  ]
}
Code/.omc/state/subagent-tracking.json
@@ -767,10 +767,355 @@
      "status": "completed",
      "completed_at": "2026-04-18T08:52:24.581Z",
      "duration_ms": 1093052
    },
    {
      "agent_id": "af12f692dd4a3fb28",
      "agent_type": "general-purpose",
      "started_at": "2026-04-19T11:24:03.847Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T11:24:57.433Z",
      "duration_ms": 53586
    },
    {
      "agent_id": "aa2a37e07afb9d479",
      "agent_type": "general-purpose",
      "started_at": "2026-04-19T11:24:03.863Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T11:24:36.379Z",
      "duration_ms": 32516
    },
    {
      "agent_id": "a6eb9a903c850f24a",
      "agent_type": "general-purpose",
      "started_at": "2026-04-19T11:24:03.887Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T11:24:47.161Z",
      "duration_ms": 43274
    },
    {
      "agent_id": "a9803cf811cccaa24",
      "agent_type": "general-purpose",
      "started_at": "2026-04-19T11:25:09.331Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T11:25:43.000Z",
      "duration_ms": 33669
    },
    {
      "agent_id": "a9e37bec52fcbdaa5",
      "agent_type": "general-purpose",
      "started_at": "2026-04-19T11:25:51.811Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T11:26:55.341Z",
      "duration_ms": 63530
    },
    {
      "agent_id": "a9260b44a0c26528b",
      "agent_type": "agent-menu",
      "started_at": "2026-04-19T13:39:55.243Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:41:04.664Z",
      "duration_ms": 69421
    },
    {
      "agent_id": "a6f1e5c50a57e0d5d",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:39:55.328Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:40:20.808Z",
      "duration_ms": 25480
    },
    {
      "agent_id": "a5a2a89d2fb5f17ff",
      "agent_type": "agent-pages",
      "started_at": "2026-04-19T13:39:55.416Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:41:01.814Z",
      "duration_ms": 66398
    },
    {
      "agent_id": "a1a6151ba7f364cfb",
      "agent_type": "agent-scaffold",
      "started_at": "2026-04-19T13:39:55.484Z",
      "parent_mode": "none",
      "status": "running"
    },
    {
      "agent_id": "a4ce4ef36b3693f58",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:39:55.588Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:40:12.096Z",
      "duration_ms": 16508
    },
    {
      "agent_id": "af02a89022a18c649",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:39:55.655Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:40:15.829Z",
      "duration_ms": 20174
    },
    {
      "agent_id": "ad03467a75e8afc0a",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:41:42.785Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:44:15.841Z",
      "duration_ms": 153056
    },
    {
      "agent_id": "a3cc9be047c9352e5",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:41:43.216Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:44:29.101Z",
      "duration_ms": 165885
    },
    {
      "agent_id": "a77fb323ad44a6284",
      "agent_type": "agent-menu",
      "started_at": "2026-04-19T13:41:43.564Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:43:03.806Z",
      "duration_ms": 80242
    },
    {
      "agent_id": "a81ba9fdad4456dfd",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:41:43.726Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:42:27.425Z",
      "duration_ms": 43699
    },
    {
      "agent_id": "a94adb2a88c1eb29c",
      "agent_type": "agent-pages",
      "started_at": "2026-04-19T13:41:44.247Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:42:26.922Z",
      "duration_ms": 42675
    },
    {
      "agent_id": "a2118226e3813727c",
      "agent_type": "agent-pages",
      "started_at": "2026-04-19T13:42:27.222Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:42:56.060Z",
      "duration_ms": 28838
    },
    {
      "agent_id": "ab750215093131b28",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:42:27.736Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:42:55.376Z",
      "duration_ms": 27640
    },
    {
      "agent_id": "ae9ed78222ecc6cad",
      "agent_type": "agent-menu",
      "started_at": "2026-04-19T13:43:04.113Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:53:39.187Z",
      "duration_ms": 635074
    },
    {
      "agent_id": "ae5c327157aec2fb1",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:44:16.103Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:46:52.232Z",
      "duration_ms": 156129
    },
    {
      "agent_id": "adc223f651f1328bd",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:44:29.361Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:44:53.787Z",
      "duration_ms": 24426
    },
    {
      "agent_id": "a756617ca874ac3c1",
      "agent_type": "agent-pages",
      "started_at": "2026-04-19T13:44:31.425Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:51:43.425Z",
      "duration_ms": 432000
    },
    {
      "agent_id": "a4c96b89f113f809d",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:44:31.949Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:47:11.645Z",
      "duration_ms": 159696
    },
    {
      "agent_id": "a8a57aa22517c31f5",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:44:54.061Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:49:10.619Z",
      "duration_ms": 256558
    },
    {
      "agent_id": "ab1d2884ac7a493bd",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:46:52.504Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:47:18.572Z",
      "duration_ms": 26068
    },
    {
      "agent_id": "a0cbc46d413ef4196",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:47:11.911Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:47:31.883Z",
      "duration_ms": 19972
    },
    {
      "agent_id": "a8d6281531b04991f",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:47:18.855Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:47:38.715Z",
      "duration_ms": 19860
    },
    {
      "agent_id": "a8c91fb2cf222b293",
      "agent_type": "writer",
      "started_at": "2026-04-19T13:48:10.651Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:50:25.143Z",
      "duration_ms": 134492
    },
    {
      "agent_id": "ade32f8bf35b26757",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:49:10.886Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:52:13.858Z",
      "duration_ms": 182972
    },
    {
      "agent_id": "ac557d7e2a1b5f729",
      "agent_type": "agent-pages",
      "started_at": "2026-04-19T13:51:43.789Z",
      "parent_mode": "none",
      "status": "running"
    },
    {
      "agent_id": "a9c6179a801e0e434",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:51:48.859Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:52:12.656Z",
      "duration_ms": 23797
    },
    {
      "agent_id": "a7627b0b0e0b60be2",
      "agent_type": "writer",
      "started_at": "2026-04-19T13:51:48.925Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:52:01.510Z",
      "duration_ms": 12585
    },
    {
      "agent_id": "aba045f68cd9f61d0",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:51:48.986Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:52:03.190Z",
      "duration_ms": 14204
    },
    {
      "agent_id": "aeed34c94d463a92c",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:52:14.179Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:52:27.389Z",
      "duration_ms": 13210
    },
    {
      "agent_id": "a9271b2a5525f053a",
      "agent_type": "agent-menu",
      "started_at": "2026-04-19T13:53:39.468Z",
      "parent_mode": "none",
      "status": "running"
    },
    {
      "agent_id": "ae5d5fcffcb393b67",
      "agent_type": "agent-api",
      "started_at": "2026-04-19T13:53:41.992Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:53:47.263Z",
      "duration_ms": 5271
    },
    {
      "agent_id": "ad92b7876bc72bf7e",
      "agent_type": "agent-auth",
      "started_at": "2026-04-19T13:53:42.036Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:53:57.851Z",
      "duration_ms": 15815
    },
    {
      "agent_id": "affcaabcac0234d22",
      "agent_type": "agent-layout",
      "started_at": "2026-04-19T13:53:42.701Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:53:49.028Z",
      "duration_ms": 6327
    },
    {
      "agent_id": "ac6c4a28a6422e89d",
      "agent_type": "writer",
      "started_at": "2026-04-19T13:53:43.519Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-19T13:53:49.216Z",
      "duration_ms": 5697
    }
  ],
  "total_spawned": 83,
  "total_completed": 83,
  "total_spawned": 115,
  "total_completed": 119,
  "total_failed": 0,
  "last_updated": "2026-04-18T14:41:25.052Z"
  "last_updated": "2026-04-19T13:53:57.967Z"
}
Code/WCS/WIDESEAWCS_Client/src/extension/taskinfo/robotState.jsx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
// è¯¥æ‰©å±•文件用于机械手状态管理页面的业务扩展。
let extension = {
  components: {
    gridHeader: "",
    gridBody: "",
    gridFooter: "",
    modelHeader: "",
    modelBody: "",
    modelFooter: "",
  },
  tableAction: "",
  buttons: { view: [], box: [], detail: [] },
  methods: {
    onInit() {},
    onInited() {},
    searchBefore(param) {
      return true;
    },
    searchAfter(result) {
      return true;
    },
    addBefore(formData) {
      return true;
    },
    addAfter(result) {
      return true;
    },
    updateBefore(formData) {
      return true;
    },
    updateAfter(result) {
      return true;
    },
    deleteBefore(ids) {
      return true;
    },
    deleteAfter(ids) {
      return true;
    },
    modelOpenAfter(row) {},
  },
};
export default extension;
Code/WCS/WIDESEAWCS_Client/src/router/viewGird.js
@@ -69,6 +69,11 @@
    component: () => import('@/views/taskinfo/robotTask.vue')
  },
  {
    path: '/robotState',
    name: 'robotState',
    component: () => import('@/views/taskinfo/robotState.vue')
  },
  {
    path: '/task',
    name: 'task',
    component: () => import('@/views/taskinfo/task.vue')
Code/WCS/WIDESEAWCS_Client/src/views/taskinfo/robotState.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,184 @@
<template>
  <view-grid
    ref="grid"
    :columns="columns"
    :detail="detail"
    :editFormFields="editFormFields"
    :editFormOptions="editFormOptions"
    :searchFormFields="searchFormFields"
    :searchFormOptions="searchFormOptions"
    :table="table"
    :extend="extend"
  >
  </view-grid>
</template>
<script>
import extend from "@/extension/taskinfo/robotState.jsx";
import { ref, defineComponent } from "vue";
export default defineComponent({
  setup() {
    const table = ref({
      key: "Id",
      footer: "Foots",
      cnName: "机械手状态管理",
      name: "robotState",
      url: "/robotState/",
      sortName: "IPAddress",
    });
    // ç¼–辑表单字段
    const editFormFields = ref({
      IPAddress: "",
      Version: "",
      IsEventSubscribed: false,
      RobotRunMode: "",
      RobotControlMode: "",
      RobotArmObject: "",
      Homed: "",
      CurrentAction: "",
      OperStatus: "",
      RobotTaskTotalNum: 0,
      IsSplitPallet: false,
      IsGroupPallet: false,
      IsInFakeBatteryMode: false,
      CurrentBatchIndex: 1,
      ChangePalletPhase: 0,
      IsScanNG: false,
      BatteryArrived: false,
    });
    // ç¼–辑表单配置
    const editFormOptions = ref([
      [
        { title: "IP地址", field: "IPAddress", type: "string", readonly: true },
        { title: "版本号", field: "Version", type: "int", readonly: true },
      ],
      [
        {
          title: "运行模式",
          field: "RobotRunMode",
          type: "select",
          data: [
            { key: 1, value: "手动模式" },
            { key: 2, value: "自动模式" },
          ],
        },
        {
          title: "控制模式",
          field: "RobotControlMode",
          type: "select",
          data: [
            { key: 1, value: "客户端控制" },
            { key: 2, value: "其他" },
          ],
        },
        {
          title: "手臂状态",
          field: "RobotArmObject",
          type: "select",
          data: [
            { key: 0, value: "空闲" },
            { key: 1, value: "有物料" },
          ],
        },
      ],
      [
        { title: "回零状态", field: "Homed", type: "string" },
        { title: "当前动作", field: "CurrentAction", type: "string" },
        { title: "运行状态", field: "OperStatus", type: "string" },
      ],
      [
        { title: "任务总数", field: "RobotTaskTotalNum", type: "int" },
        { title: "当前批次", field: "CurrentBatchIndex", type: "int" },
        { title: "换盘阶段", field: "ChangePalletPhase", type: "int" },
      ],
      [
        {
          title: "是否拆盘",
          field: "IsSplitPallet",
          type: "checkbox",
        },
        {
          title: "是否组盘",
          field: "IsGroupPallet",
          type: "checkbox",
        },
        {
          title: "假电芯模式",
          field: "IsInFakeBatteryMode",
          type: "checkbox",
        },
      ],
      [
        {
          title: "是否扫码NG",
          field: "IsScanNG",
          type: "checkbox",
        },
        {
          title: "电芯是否到位",
          field: "BatteryArrived",
          type: "checkbox",
        },
        {
          title: "消息已订阅",
          field: "IsEventSubscribed",
          type: "checkbox",
        },
      ],
    ]);
    // æœç´¢è¡¨å•字段
    const searchFormFields = ref({
      IPAddress: "",
      CurrentAction: "",
      OperStatus: "",
    });
    // æœç´¢è¡¨å•配置
    const searchFormOptions = ref([
      [
        { title: "IP地址", field: "IPAddress", type: "string" },
        { title: "当前动作", field: "CurrentAction", type: "string" },
        { title: "运行状态", field: "OperStatus", type: "string" },
      ],
    ]);
    // åˆ—定义
    const columns = ref([
      { field: "IPAddress", title: "IP地址", type: "string", width: 140, align: "left" },
      { field: "Version", title: "版本", type: "int", width: 80, align: "left" },
      { field: "RobotRunMode", title: "运行模式", type: "int", width: 100, bind: { key: "robotRunMode", data: [] }, align: "center" },
      { field: "RobotControlMode", title: "控制模式", type: "int", width: 100, bind: { key: "robotControlMode", data: [] }, align: "center" },
      { field: "RobotArmObject", title: "手臂状态", type: "int", width: 90, bind: { key: "robotArmObject", data: [] }, align: "center" },
      { field: "Homed", title: "回零状态", type: "string", width: 100, align: "center" },
      { field: "CurrentAction", title: "当前动作", type: "string", width: 100, align: "center" },
      { field: "OperStatus", title: "运行状态", type: "string", width: 100, align: "center" },
      { field: "RobotTaskTotalNum", title: "任务总数", type: "int", width: 90, align: "center" },
      { field: "IsSplitPallet", title: "拆盘", type: "byte", width: 60, align: "center" },
      { field: "IsGroupPallet", title: "组盘", type: "byte", width: 60, align: "center" },
      { field: "IsInFakeBatteryMode", title: "假电芯", type: "byte", width: 70, align: "center" },
      { field: "CurrentBatchIndex", title: "批次", type: "int", width: 60, align: "center" },
      { field: "ChangePalletPhase", title: "换盘阶段", type: "int", width: 80, align: "center" },
      { field: "IsScanNG", title: "扫码NG", type: "byte", width: 80, align: "center" },
      { field: "BatteryArrived", title: "电芯到位", type: "byte", width: 80, align: "center" },
      { field: "IsEventSubscribed", title: "已订阅", type: "byte", width: 70, align: "center" },
    ]);
    const detail = ref({});
    return {
      table,
      columns,
      detail,
      editFormFields,
      editFormOptions,
      searchFormFields,
      searchFormOptions,
      extend,
    };
  },
});
</script>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/IRobotStateRepository.cs
@@ -1,3 +1,5 @@
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_ITaskInfoRepository
@@ -10,7 +12,7 @@
    /// å¤æ‚对象(RobotCrane、CurrentTask、数组等)在调用方使用强类型,
    /// åœ¨æ­¤æŽ¥å£å±‚面以 Dt_RobotState å®žä½“为操作单位。
    /// </remarks>
    public interface IRobotStateRepository
    public interface IRobotStateRepository : IRepository<Dt_RobotState>
    {
        /// <summary>
        /// æ ¹æ® IP åœ°å€èŽ·å–æœºæ¢°æ‰‹çŠ¶æ€
@@ -31,10 +33,10 @@
        /// å®‰å…¨æ›´æ–°æœºæ¢°æ‰‹çŠ¶æ€ï¼ˆä¹è§‚é”ï¼‰
        /// </summary>
        /// <param name="ipAddress">设备 IP åœ°å€</param>
        /// <param name="newState">新状态实体(RowVersion ä¼šè¢«æ›´æ–°ï¼‰</param>
        /// <param name="expectedRowVersion">期望的行版本号(更新前的版本)</param>
        /// <param name="newState">新状态实体(Version ä¼šè‡ªå¢žï¼‰</param>
        /// <param name="expectedVersion">期望的版本号(更新前的版本)</param>
        /// <returns>是否更新成功;false è¡¨ç¤ºç‰ˆæœ¬å†²çªæˆ–记录不存在</returns>
        bool TryUpdate(string ipAddress, Dt_RobotState newState, byte[] expectedRowVersion);
        bool TryUpdate(string ipAddress, Dt_RobotState newState, long expectedVersion);
        /// <summary>
        /// å°† Dt_RobotState å®žä½“转换为 RobotSocketState å†…存对象
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/WIDESEAWCS_ITaskInfoRepository.csproj
@@ -8,6 +8,7 @@
    <ItemGroup>
      <ProjectReference Include="..\WIDESEAWCS_DTO\WIDESEAWCS_DTO.csproj" />
      <ProjectReference Include="..\WIDESEAWCS_Model\WIDESEAWCS_Model.csproj" />
    </ItemGroup>
</Project>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotStateService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_ITaskInfoService
{
    /// <summary>
    /// æœºæ¢°æ‰‹çŠ¶æ€æœåŠ¡æŽ¥å£
    /// </summary>
    public interface IRobotStateService : IService<Dt_RobotState>
    {
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/Dt_RobotState.cs
@@ -1,4 +1,3 @@
using Newtonsoft.Json;
using SqlSugar;
using WIDESEAWCS_Core.DB.Models;
@@ -8,7 +7,7 @@
    /// æœºæ¢°æ‰‹çŠ¶æ€æ•°æ®åº“å®žä½“
    /// </summary>
    /// <remarks>
    /// å¯¹åº”数据库表 Dt_RobotState,使用 RowVersion å®žçŽ°ä¹è§‚å¹¶å‘æŽ§åˆ¶ã€‚
    /// å¯¹åº”数据库表 Dt_RobotState,使用 Version å­—段实现乐观并发控制。
    /// å¤æ‚对象(RobotCrane、CurrentTask、数组等)以 JSON å­—符串存储。
    /// </remarks>
    [SugarTable(nameof(Dt_RobotState), "机械手状态表")]
@@ -23,141 +22,141 @@
        /// <summary>
        /// æœºæ¢°æ‰‹ IP åœ°å€ï¼Œå”¯ä¸€ç´¢å¼•
        /// </summary>
        [SugarColumn(Length = 50, ColumnDescription = "机械手IP地址", IsJsonKey = true)]
        [SugarColumn(Length = 50, ColumnDescription = "机械手IP地址")]
        public string IPAddress { get; set; } = string.Empty;
        /// <summary>
        /// è¡Œç‰ˆæœ¬ï¼Œç”¨äºŽä¹è§‚并发控制
        /// ç‰ˆæœ¬å·ï¼Œç”¨äºŽä¹è§‚并发控制
        /// </summary>
        /// <remarks>
        /// SqlSugar ä¼šè‡ªåŠ¨ç®¡ç†æ­¤å­—æ®µï¼Œæ¯æ¬¡æ›´æ–°æ—¶æ•°æ®åº“è‡ªåŠ¨é€’å¢žã€‚
        /// æ›´æ–°æ—¶ WHERE RowVersion = @expectedRowVersion,检查影响行数判断是否冲突。
        /// æ¯æ¬¡æ›´æ–°æ—¶è‡ªå¢žã€‚æ›´æ–°æ—¶ WHERE IPAddress = @ip AND Version = @expectedVersion。
        /// å¦‚果影响行数为 0,说明版本不匹配,返回 false。
        /// </remarks>
        [SugarColumn(ColumnDescription = "行版本(乐观锁)", IsJsonKey = true)]
        public byte[] RowVersion { get; set; } = Array.Empty<byte>();
        [SugarColumn(ColumnDescription = "版本号(乐观锁)")]
        public long Version { get; set; }
        /// <summary>
        /// æ˜¯å¦å·²è®¢é˜…消息事件
        /// </summary>
        [SugarColumn(ColumnDescription = "是否已订阅消息事件", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "是否已订阅消息事件")]
        public bool IsEventSubscribed { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è¿è¡Œæ¨¡å¼
        /// </summary>
        /// <remarks>1: æ‰‹åŠ¨æ¨¡å¼, 2: è‡ªåŠ¨æ¨¡å¼</remarks>
        [SugarColumn(ColumnDescription = "运行模式", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "运行模式", IsNullable = true)]
        public int? RobotRunMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æŽ§åˆ¶æ¨¡å¼
        /// </summary>
        /// <remarks>1: å®¢æˆ·ç«¯æŽ§åˆ¶, 2: å…¶ä»–</remarks>
        [SugarColumn(ColumnDescription = "控制模式", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "控制模式", IsNullable = true)]
        public int? RobotControlMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æ‰‹è‡‚抓取对象状态
        /// </summary>
        /// <remarks>0: æ— ç‰©æ–™ï¼ˆæ‰‹è‡‚空闲), 1: æœ‰ç‰©æ–™ï¼ˆå·²æŠ“取货物)</remarks>
        [SugarColumn(ColumnDescription = "手臂抓取状态", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "手臂抓取状态", IsNullable = true)]
        public int? RobotArmObject { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è®¾å¤‡åŸºç¡€ä¿¡æ¯ï¼ˆJSON åºåˆ—化)
        /// </summary>
        [SugarColumn(Length = 2000, ColumnDescription = "设备信息JSON", IsJsonKey = true)]
        public string RobotCraneJson { get; set; } = string.Empty;
        [SugarColumn(Length = 2000, ColumnDescription = "设备信息JSON", IsNullable = true)]
        public string? RobotCraneJson { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹åˆå§‹åŒ–完成回到待机位状态
        /// </summary>
        /// <remarks>Possible values: "Homed", "Homing"</remarks>
        [SugarColumn(Length = 50, ColumnDescription = "回零状态", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 50, ColumnDescription = "回零状态", IsNullable = true)]
        public string? Homed { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹å½“前正在执行的动作
        /// </summary>
        [SugarColumn(Length = 50, ColumnDescription = "当前动作", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 50, ColumnDescription = "当前动作", IsNullable = true)]
        public string? CurrentAction { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹å½“前运行状态
        /// </summary>
        [SugarColumn(Length = 50, ColumnDescription = "运行状态", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 50, ColumnDescription = "运行状态", IsNullable = true)]
        public string? OperStatus { get; set; }
        /// <summary>
        /// æœ€è¿‘一次取货完成的位置数组(JSON)
        /// </summary>
        [SugarColumn(Length = 500, ColumnDescription = "取货位置数组JSON", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 500, ColumnDescription = "取货位置数组JSON", IsNullable = true)]
        public string? LastPickPositionsJson { get; set; }
        /// <summary>
        /// æœ€è¿‘一次放货完成的位置数组(JSON)
        /// </summary>
        [SugarColumn(Length = 500, ColumnDescription = "放货位置数组JSON", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 500, ColumnDescription = "放货位置数组JSON", IsNullable = true)]
        public string? LastPutPositionsJson { get; set; }
        /// <summary>
        /// ç”µæ± /货位条码列表(JSON)
        /// </summary>
        [SugarColumn(Length = 2000, ColumnDescription = "电芯条码列表JSON", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 2000, ColumnDescription = "电芯条码列表JSON", IsNullable = true)]
        public string? CellBarcodeJson { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹å½“前正在执行的任务(JSON åºåˆ—化)
        /// </summary>
        [SugarColumn(Length = 2000, ColumnDescription = "当前任务JSON", IsNullable = true, IsJsonKey = true)]
        [SugarColumn(Length = 2000, ColumnDescription = "当前任务JSON", IsNullable = true)]
        public string? CurrentTaskJson { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦æ‰§è¡Œæ‹†ç›˜ä»»åŠ¡
        /// </summary>
        [SugarColumn(ColumnDescription = "是否拆盘任务", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "是否拆盘任务")]
        public bool IsSplitPallet { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦æ‰§è¡Œç»„盘任务
        /// </summary>
        [SugarColumn(ColumnDescription = "是否组盘任务", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "是否组盘任务")]
        public bool IsGroupPallet { get; set; }
        /// <summary>
        /// æœºå™¨äººå·²å¤„理的任务总数
        /// </summary>
        [SugarColumn(ColumnDescription = "已处理任务总数", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "已处理任务总数")]
        public int RobotTaskTotalNum { get; set; }
        /// <summary>
        /// æ˜¯å¦å¤„于假电芯补充模式
        /// </summary>
        [SugarColumn(ColumnDescription = "是否假电芯模式", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "是否假电芯模式")]
        public bool IsInFakeBatteryMode { get; set; }
        /// <summary>
        /// å½“前批次起始编号
        /// </summary>
        [SugarColumn(ColumnDescription = "当前批次编号", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "当前批次编号")]
        public int CurrentBatchIndex { get; set; } = 1;
        /// <summary>
        /// æ¢ç›˜ä»»åŠ¡å½“å‰é˜¶æ®µ
        /// </summary>
        [SugarColumn(ColumnDescription = "换盘阶段", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "换盘阶段")]
        public int ChangePalletPhase { get; set; }
        /// <summary>
        /// æ˜¯å¦æ‰«ç NG
        /// </summary>
        [SugarColumn(ColumnDescription = "是否扫码NG", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "是否扫码NG")]
        public bool IsScanNG { get; set; }
        /// <summary>
        /// æ˜¯å¦ç”µèŠ¯åˆ°ä½
        /// </summary>
        [SugarColumn(ColumnDescription = "电芯是否到位", IsJsonKey = true)]
        [SugarColumn(ColumnDescription = "电芯是否到位")]
        public bool BatteryArrived { get; set; }
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/RobotCraneDevice.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
namespace WIDESEAWCS_Model.Models
{
    /// <summary>
    /// æœºå™¨äººè®¾å¤‡åŸºç¡€ä¿¡æ¯
    /// </summary>
    public class RobotCraneDevice
    {
        /// <summary>
        /// è®¾å¤‡æ ‡è¯†
        /// </summary>
        public string Device { get; set; } = string.Empty;
        /// <summary>
        /// è®¾å¤‡ç¼–码
        /// </summary>
        public string DeviceCode { get; set; } = string.Empty;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName { get; set; } = string.Empty;
        /// <summary>
        /// IP åœ°å€
        /// </summary>
        public string IPAddress { get; set; } = string.Empty;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/RobotState/RobotSocketState.cs
ÎļþÃû´Ó Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs ÐÞ¸Ä
@@ -1,13 +1,10 @@
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks
namespace WIDESEAWCS_Model.Models
{
    /// <summary>
    /// æœºæ¢°æ‰‹ Socket é€šä¿¡çŠ¶æ€æ•°æ®ç±»
    /// </summary>
    /// <remarks>
    /// è¯¥ç±»ç”¨äºŽåœ¨ Redis ç¼“存中存储机械手的实时状态,包括位置、任务、手臂对象等信息。
    /// è¯¥ç±»ç”¨äºŽåœ¨æ•°æ®åº“中存储机械手的实时状态,包括位置、任务、手臂对象等信息。
    /// æ‰€æœ‰å±žæ€§å‡è®¾è®¡ä¸ºçº¿ç¨‹å®‰å…¨æ›´æ–°ï¼Œé€šè¿‡ <see cref="RobotStateManager"/> çš„版本控制机制来防止并发覆盖。
    /// </remarks>
    public class RobotSocketState
@@ -21,7 +18,7 @@
        /// ç‰ˆæœ¬å·ï¼Œç”¨äºŽä¹è§‚并发控制
        /// </summary>
        /// <remarks>
        /// æ¯æ¬¡ä¿®æ”¹çŠ¶æ€æ—¶æ›´æ–°ä¸º DateTime.UtcNow.Ticks。
        /// æ¯æ¬¡ä¿®æ”¹çŠ¶æ€æ—¶è‡ªå¢žã€‚
        /// <see cref="RobotStateManager"/> ä½¿ç”¨æ­¤å­—段实现乐观锁,防止并发更新时旧值覆盖新值。
        /// </remarks>
        public long Version { get; set; } = DateTime.UtcNow.Ticks;
@@ -212,8 +209,6 @@
        /// æ‹‰å¸¦çº¿ä¸Šç”µèŠ¯æ‰«ç æ˜¯å¦NG。
        /// </remarks>
        public bool IsScanNG { get; set; } = false;
        /// <summary>
        /// æ˜¯å¦ç”µèŠ¯åˆ°ä½
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/QuartzNetExtension.cs
@@ -4,6 +4,7 @@
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Service;
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Robot/RobotCraneDevice.cs
ÎļþÒÑɾ³ý
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/WIDESEAWCS_QuartzJob.csproj
@@ -43,6 +43,7 @@
        <ProjectReference Include="..\WIDESEAWCS_Common\WIDESEAWCS_Common.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_Communicator\WIDESEAWCS_Communicator.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_Core\WIDESEAWCS_Core.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_Model\WIDESEAWCS_Model.csproj" />
    </ItemGroup>
</Project>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotStateController.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEAWCS_Core.BaseController;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_WCSServer.Controllers.Task
{
    /// <summary>
    /// æœºæ¢°æ‰‹çŠ¶æ€ç®¡ç†æŽ§åˆ¶å™¨
    /// </summary>
    [Route("api/RobotState")]
    [ApiController]
    public class RobotStateController : ApiBaseController<IRobotStateService, Dt_RobotState>
    {
        public RobotStateController(IRobotStateService service) : base(service)
        {
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
@@ -54,7 +54,7 @@
  "ApiName": "WIDESEAWCS",
  "ExpMinutes": 120,
  "QuartzJobAutoStart": true,
  "DBSeedEnable": false,
  "DBSeedEnable": true,
  "QuartzDBSeedEnable": false,
  "LogDeubgEnable": false, //是否记录调试日志
  "PrintSql": false, //打印SQL语句
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/RobotStateRepository.cs
@@ -1,7 +1,6 @@
using Newtonsoft.Json;
using SqlSugar;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.UnitOfWork;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_Model.Models;
@@ -10,20 +9,15 @@
    /// <summary>
    /// æœºæ¢°æ‰‹çŠ¶æ€ SqlSugar ä»“储实现
    /// </summary>
    public class RobotStateRepository : IUnitOfWork, IRobotStateRepository
    public class RobotStateRepository : RepositoryBase<Dt_RobotState>, IRobotStateRepository
    {
        private readonly IUnitOfWorkManage _unitOfWork;
        private readonly SqlSugarClient _db;
        public RobotStateRepository(IUnitOfWorkManage unitOfWork)
        public RobotStateRepository(IUnitOfWorkManage unitOfWork) : base(unitOfWork)
        {
            _unitOfWork = unitOfWork;
            _db = unitOfWork.GetDbClient();
        }
        public Dt_RobotState? GetByIp(string ipAddress)
        {
            return _db.Queryable<Dt_RobotState>()
            return Db.Queryable<Dt_RobotState>()
                .Where(x => x.IPAddress == ipAddress)
                .First();
        }
@@ -39,22 +33,23 @@
            var newState = new Dt_RobotState
            {
                IPAddress = ipAddress,
                Version = DateTime.UtcNow.Ticks,
                RobotCraneJson = JsonConvert.SerializeObject(robotCrane),
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
                CreateDate = DateTime.Now,
                ModifyDate = DateTime.Now
            };
            _db.Insertable(newState).ExecuteCommand();
            Db.Insertable(newState).ExecuteCommand();
            return newState;
        }
        public bool TryUpdate(string ipAddress, Dt_RobotState newState, byte[] expectedRowVersion)
        public bool TryUpdate(string ipAddress, Dt_RobotState newState, long expectedVersion)
        {
            newState.UpdateTime = DateTime.Now;
            newState.ModifyDate = DateTime.Now;
            var affectedRows = _db.Updateable<Dt_RobotState>(newState)
                .Where(x => x.IPAddress == ipAddress)
                .WhereRowVersion(x => x.RowVersion, expectedRowVersion)
            // ä¹è§‚锁:WHERE IPAddress = @ip AND Version = @expectedVersion,版本匹配才更新
            var affectedRows = Db.Updateable<Dt_RobotState>(newState)
                .Where(x => x.IPAddress == ipAddress && x.Version == expectedVersion)
                .ExecuteCommand();
            return affectedRows > 0;
@@ -65,7 +60,7 @@
            var state = new RobotSocketState
            {
                IPAddress = entity.IPAddress,
                Version = BitConverter.ToInt64(entity.RowVersion.Length >= 8 ? entity.RowVersion.Take(8).ToArray() : new byte[8], 0),
                Version = entity.Version,
                IsEventSubscribed = entity.IsEventSubscribed,
                RobotRunMode = entity.RobotRunMode,
                RobotControlMode = entity.RobotControlMode,
@@ -162,13 +157,5 @@
            return entity;
        }
        public SqlSugarClient GetDbClient() => _db;
        public void BeginTran() => _unitOfWork.BeginTran();
        public void CommitTran() => _unitOfWork.CommitTran();
        public void RollbackTran() => _unitOfWork.RollbackTran();
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotStateService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
using WIDESEA_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_TaskInfoService
{
    /// <summary>
    /// æœºæ¢°æ‰‹çŠ¶æ€æœåŠ¡å®žçŽ°
    /// </summary>
    public class RobotStateService : ServiceBase<Dt_RobotState, IRobotStateRepository>, IRobotStateService
    {
        public RobotStateService(IRobotStateRepository repository) : base(repository)
        {
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotMessageRouter.cs
@@ -1,4 +1,5 @@
using System.Net.Sockets;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Tasks.Workflow.Abstractions
{
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotPrefixCommandHandler.cs
@@ -1,4 +1,5 @@
using System.Net.Sockets;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Tasks.Workflow.Abstractions
{
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotSimpleCommandHandler.cs
@@ -1,3 +1,5 @@
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Tasks.Workflow.Abstractions
{
    /// <summary>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/ISocketClientGateway.cs
@@ -1,4 +1,5 @@
using System.Net.Sockets;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks.Workflow.Abstractions
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs
@@ -2,6 +2,7 @@
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_Tasks.SocketServer;
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
@@ -7,7 +7,8 @@
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_RedisService;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Tasks.SocketServer;
using WIDESEAWCS_Tasks.Workflow;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
@@ -129,7 +130,7 @@
            var prefixCommandHandler = new RobotPrefixCommandHandler(robotTaskService, _taskProcessor, _stateManager, socketGateway, fakeBatteryPositionService);
            // åˆå§‹åŒ–消息路由器
            _messageRouter = new RobotMessageHandler(socketGateway, _stateManager, cache, simpleCommandHandler, prefixCommandHandler, logger);
            _messageRouter = new RobotMessageHandler(socketGateway, _stateManager, simpleCommandHandler, prefixCommandHandler, logger);
            // åˆå§‹åŒ–工作流编排器
            _workflowOrchestrator = new RobotWorkflowOrchestrator(_stateManager, _clientManager, _taskProcessor, robotTaskService, _logger);
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotMessageHandler.cs
@@ -1,8 +1,8 @@
using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using WIDESEAWCS_Common;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
namespace WIDESEAWCS_Tasks
@@ -12,7 +12,7 @@
    /// </summary>
    /// <remarks>
    /// æ ¸å¿ƒèŒè´£ï¼š
    /// 1. ç¼“存状态读取:从 Redis ä¸­èŽ·å–æœºå™¨äººæœ€æ–°çš„çŠ¶æ€
    /// 1. çŠ¶æ€æŽ¥æ”¶ï¼šä»Žè°ƒç”¨æ–¹èŽ·å–æœºå™¨äººæœ€æ–°çš„çŠ¶æ€
    /// 2. å‘½ä»¤åˆ†å‘:根据消息类型分发给不同的处理器
    ///    - ç®€å•命令(如 homing、running):由 <see cref="IRobotSimpleCommandHandler"/> å¤„理
    ///    - å‰ç¼€å‘½ä»¤ï¼ˆå¦‚ pickfinished、putfinished):由 <see cref="IRobotPrefixCommandHandler"/> å¤„理
@@ -25,41 +25,21 @@
        /// <summary>
        /// Socket å®¢æˆ·ç«¯ç½‘关接口
        /// </summary>
        /// <remarks>
        /// ç”¨äºŽå‘客户端发送响应消息。
        /// </remarks>
        private readonly ISocketClientGateway _socketClientGateway;
        /// <summary>
        /// æœºæ¢°æ‰‹çŠ¶æ€ç®¡ç†å™¨
        /// </summary>
        /// <remarks>
        /// ç”¨äºŽè¯»å–和更新机器人的状态。
        /// </remarks>
        private readonly RobotStateManager _stateManager;
        /// <summary>
        /// ç¼“存服务
        /// </summary>
        /// <remarks>
        /// ç›´æŽ¥ä½¿ç”¨ç¼“存服务检查状态是否存在。
        /// </remarks>
        private readonly ICacheService _cache;
        /// <summary>
        /// ç®€å•命令处理器
        /// </summary>
        /// <remarks>
        /// å¤„理简单的状态更新命令,如运行状态、模式切换等。
        /// </remarks>
        private readonly IRobotSimpleCommandHandler _simpleCommandHandler;
        /// <summary>
        /// å‰ç¼€å‘½ä»¤å¤„理器
        /// </summary>
        /// <remarks>
        /// å¤„理带参数的前缀命令,如 pickfinished(取货完成)、putfinished(放货完成)。
        /// </remarks>
        private readonly IRobotPrefixCommandHandler _prefixCommandHandler;
        /// <summary>
@@ -72,21 +52,18 @@
        /// </summary>
        /// <param name="socketClientGateway">Socket ç½‘å…³</param>
        /// <param name="stateManager">状态管理器</param>
        /// <param name="cache">缓存服务</param>
        /// <param name="simpleCommandHandler">简单命令处理器</param>
        /// <param name="prefixCommandHandler">前缀命令处理器</param>
        /// <param name="logger">日志记录器</param>
        public RobotMessageHandler(
            ISocketClientGateway socketClientGateway,
            RobotStateManager stateManager,
            ICacheService cache,
            IRobotSimpleCommandHandler simpleCommandHandler,
            IRobotPrefixCommandHandler prefixCommandHandler,
            ILogger<RobotJob> logger)
        {
            _socketClientGateway = socketClientGateway;
            _stateManager = stateManager;
            _cache = cache;
            _simpleCommandHandler = simpleCommandHandler;
            _prefixCommandHandler = prefixCommandHandler;
            _logger = logger;
@@ -98,12 +75,11 @@
        /// <remarks>
        /// å¤„理流程:
        /// 1. è®°å½•日志(记录原始消息内容)
        /// 2. éªŒè¯ç¼“存中是否存在该设备的状态
        /// 3. å°è¯•用简单命令处理器处理(状态更新类命令)
        /// 2. å°è¯•用简单命令处理器处理(状态更新类命令)
        ///    - å¦‚果处理成功,回写原消息并更新状态
        /// 4. å¦‚果不是简单命令,检查是否是前缀命令(pickfinished/putfinished)
        /// 3. å¦‚果不是简单命令,检查是否是前缀命令(pickfinished/putfinished)
        ///    - å¦‚果是,调用前缀命令处理器处理
        /// 5. ä¿æŒåŽŸæœ‰è¡Œä¸ºï¼šç®€å•å‘½ä»¤å’Œå‰ç¼€å‘½ä»¤éƒ½å›žå†™åŽŸæ¶ˆæ¯
        /// 4. ä¿æŒåŽŸæœ‰è¡Œä¸ºï¼šç®€å•å‘½ä»¤å’Œå‰ç¼€å‘½ä»¤éƒ½å›žå†™åŽŸæ¶ˆæ¯
        ///
        /// æ³¨æ„ï¼šæ­¤æ–¹æ³•可能在 TCP æ¶ˆæ¯æŽ¥æ”¶çš„上下文中被频繁调用,需注意性能。
        /// </remarks>
@@ -115,46 +91,31 @@
        public async Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state)
        {
            // è®°å½•接收到的消息日志
            _logger.LogInformation($"接收到客户端【{state.RobotCrane.DeviceName}】发送消息【{message}】");
            QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane.DeviceName);
            _logger.LogInformation($"接收到客户端【{state.RobotCrane?.DeviceName}】发送消息【{message}】");
            QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane?.DeviceName);
            // æ£€æŸ¥ä»»åŠ¡æ€»æ•°æ˜¯å¦æœªè¾¾åˆ°ä¸Šé™
            if (state.RobotTaskTotalNum > RobotConst.MaxTaskTotalNum)
            {
                // è®°å½•接收到的消息日志
                _logger.LogInformation($"接收到客户端【{state.RobotCrane.DeviceName}】发送消息【{message}】");
                QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane.DeviceName);
                // å¤„理成功后,将原消息回写到客户端(保持原有行为)
                _logger.LogInformation($"接收到客户端【{state.RobotCrane?.DeviceName}】发送消息【{message}】");
                QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane?.DeviceName);
                await _socketClientGateway.SendMessageAsync(client, message);
                return null;
            }
            // æž„建缓存键,检查 Redis ä¸­æ˜¯å¦å­˜åœ¨è¯¥è®¾å¤‡çš„状态
            var cacheKey = $"{RedisPrefix.Code}:{RedisName.SocketDevices}:{client.Client.RemoteEndPoint}";
            // å¦‚果缓存中不存在或状态为 null,忽略此消息
            if (!_cache.TryGetValue(cacheKey, out RobotSocketState? cachedState) || cachedState == null)
            {
                _logger.LogInformation($"缓存中不存在或状态为 null,忽略此消息");
                return null;
            }
            // ä½¿ç”¨ç¼“存中获取的状态
            var activeState = cachedState;
            // å°†æ¶ˆæ¯è½¬æ¢ä¸ºå°å†™ï¼ˆç”¨äºŽç®€å•命令匹配)
            string messageLower = message.ToLowerInvariant();
            // å°è¯•用简单命令处理器处理
            // ç®€å•命令包括:homing、homed、running、pausing、runmode、controlmode ç­‰
            if (await _simpleCommandHandler.HandleAsync(messageLower, activeState))
            if (await _simpleCommandHandler.HandleAsync(messageLower, state))
            {
                // å¤„理成功后,将原消息回写到客户端(保持原有行为)
                await _socketClientGateway.SendMessageAsync(client, message);
                QuartzLogger.Info($"发送消息:【{message}】", state.RobotCrane.DeviceName);
                QuartzLogger.Info($"发送消息:【{message}】", state.RobotCrane?.DeviceName);
                // å®‰å…¨æ›´æ–°çŠ¶æ€åˆ° Redis
                _stateManager.TryUpdateStateSafely(activeState.IPAddress, activeState);
                // å®‰å…¨æ›´æ–°çŠ¶æ€åˆ°æ•°æ®åº“
                _stateManager.TryUpdateStateSafely(state.IPAddress, state);
                return null;
            }
@@ -163,11 +124,9 @@
            if (_prefixCommandHandler.IsPrefixCommand(messageLower))
            {
                // è°ƒç”¨å‰ç¼€å‘½ä»¤å¤„理器
                // å‰ç¼€å‘½ä»¤å¤„理器会解析位置参数并更新状态
                await _prefixCommandHandler.HandleAsync(message, activeState, client);
                await _prefixCommandHandler.HandleAsync(message, state, client);
            }
            // é»˜è®¤è¿”回 null,不产生响应消息
            return null;
        }
    }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotStateManager.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using WIDESEAWCS_Common;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_Model.Models;
@@ -12,7 +11,7 @@
    /// </summary>
    /// <remarks>
    /// æ ¸å¿ƒåŠŸèƒ½æ˜¯é€šè¿‡ IRobotStateRepository ç®¡ç†æ•°æ®åº“中的机械手状态。
    /// æä¾›ä¹è§‚并发控制,通过 RowVersion é˜²æ­¢å¹¶å‘更新时的数据覆盖问题。
    /// æä¾›ä¹è§‚并发控制,通过 Version å­—段防止并发更新时的数据覆盖问题。
    /// </remarks>
    public class RobotStateManager
    {
@@ -38,11 +37,11 @@
        }
        /// <summary>
        /// å®‰å…¨æ›´æ–° RobotSocketState ç¼“存,防止并发覆盖
        /// å®‰å…¨æ›´æ–° RobotSocketState,防止并发覆盖
        /// </summary>
        /// <remarks>
        /// ä½¿ç”¨ä¹è§‚并发模式:先读取当前 RowVersion,执行更新时检查版本是否一致。
        /// å¦‚æžœ RowVersion ä¸åŒ¹é…ï¼ˆè¯´æ˜Žæœ‰å…¶ä»–线程已更新),则更新失败返回 false。
        /// ä½¿ç”¨ä¹è§‚并发模式:先读取当前 Version,执行更新时检查版本是否一致。
        /// å¦‚æžœ Version ä¸åŒ¹é…ï¼ˆè¯´æ˜Žæœ‰å…¶ä»–线程已更新),则更新失败返回 false。
        /// </remarks>
        /// <param name="ipAddress">设备 IP åœ°å€</param>
        /// <param name="updateAction">更新状态的委托函数,传入当前状态副本,返回修改后的新状态</param>
@@ -57,8 +56,8 @@
                return false;
            }
            // è®°å½•当前存储的 RowVersion,作为更新时的期望版本
            var expectedRowVersion = currentEntity.RowVersion;
            // è®°å½•当前存储的 Version,作为更新时的期望版本
            var expectedVersion = currentEntity.Version;
            // åˆ›å»ºçŠ¶æ€çš„æ·±æ‹·è´å‰¯æœ¬ï¼ˆä½¿ç”¨ JSON åºåˆ—化实现)
            var stateCopy = CloneState(_repository.ToSocketState(currentEntity));
@@ -68,12 +67,12 @@
            // å°†æ–°çŠ¶æ€è½¬æ¢ä¸ºæ•°æ®åº“å®žä½“
            var newEntity = _repository.ToEntity(newState);
            newEntity.RowVersion = Array.Empty<byte>(); // SqlSugar ä¼šè‡ªåŠ¨ç®¡ç†
            newEntity.Id = currentEntity.Id;
            newEntity.Version = expectedVersion + 1; // ç‰ˆæœ¬è‡ªå¢ž
            // è°ƒç”¨ä»“储的安全更新方法,传入期望 RowVersion
            // å¦‚æžœ RowVersion ä¸ä¸€è‡´ï¼ˆå·²è¢«å…¶ä»–线程更新),则更新失败
            return _repository.TryUpdate(ipAddress, newEntity, expectedRowVersion);
            // è°ƒç”¨ä»“储的安全更新方法,传入期望 Version
            // å¦‚æžœ Version ä¸ä¸€è‡´ï¼ˆå·²è¢«å…¶ä»–线程更新),则更新失败
            return _repository.TryUpdate(ipAddress, newEntity, expectedVersion);
        }
        /// <summary>
@@ -94,29 +93,26 @@
            // å¦‚果当前不存在该设备的状态,创建新记录
            if (currentEntity == null)
            {
                var entity = _repository.ToEntity(newState);
                entity.CreateTime = DateTime.Now;
                entity.UpdateTime = DateTime.Now;
                _repository.GetOrCreate(newState.IPAddress, newState.RobotCrane ?? new RobotCraneDevice());
                _logger.LogDebug("TryUpdateStateSafely:创建新状态,IP: {IpAddress}", ipAddress);
                QuartzLogger.Debug($"创建新状态,IP: {ipAddress}", ipAddress);
                return true;
            }
            // å½“前存在状态,记录期望 RowVersion ç”¨äºŽä¹è§‚锁检查
            var expectedRowVersion = currentEntity.RowVersion;
            // å½“前存在状态,记录期望 Version ç”¨äºŽä¹è§‚锁检查
            var expectedVersion = currentEntity.Version;
            // å°†æ–°çŠ¶æ€è½¬æ¢ä¸ºæ•°æ®åº“å®žä½“
            var newEntity = _repository.ToEntity(newState);
            newEntity.Id = currentEntity.Id;
            newEntity.RowVersion = Array.Empty<byte>();
            newEntity.Version = expectedVersion + 1; // ç‰ˆæœ¬è‡ªå¢ž
            // å°è¯•安全更新,如果版本冲突则返回 false
            bool success = _repository.TryUpdate(ipAddress, newEntity, expectedRowVersion);
            bool success = _repository.TryUpdate(ipAddress, newEntity, expectedVersion);
            if (!success)
            {
                _logger.LogWarning("TryUpdateStateSafely:版本冲突,更新失败,IP: {IpAddress},期望版本字节长度: {ExpectedLength}", ipAddress, expectedRowVersion.Length);
                _logger.LogWarning("TryUpdateStateSafely:版本冲突,更新失败,IP: {IpAddress},期望版本: {ExpectedVersion}", ipAddress, expectedVersion);
                QuartzLogger.Warn($"版本冲突,更新失败,IP: {ipAddress}", ipAddress);
            }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs
@@ -1,5 +1,6 @@
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
namespace WIDESEAWCS_Tasks.Workflow
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/SocketClientGateway.cs
@@ -1,4 +1,5 @@
using System.Net.Sockets;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -2,6 +2,7 @@
using System.Text;
using System.Text.Json;
using System.IO;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Tasks.SocketServer
{
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs
@@ -6,6 +6,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks.SocketServer
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj
@@ -7,6 +7,7 @@
    </PropertyGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_Model\WIDESEAWCS_Model.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_QuartzJob\WIDESEAWCS_QuartzJob.csproj" />
        <ProjectReference Include="..\WIDESEAWCS_TaskInfoService\WIDESEAWCS_TaskInfoService.csproj" />
    </ItemGroup>
Code/WMS/WIDESEA_WMSClient_Vben/.env.development
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
VITE_API_BASE_URL=http://localhost:9291
Code/WMS/WIDESEA_WMSClient_Vben/index.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WMS管理系统</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
Code/WMS/WIDESEA_WMSClient_Vben/package-lock.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1929 @@
{
  "name": "widesea-wms-client-vben",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "widesea-wms-client-vben",
      "version": "1.0.0",
      "dependencies": {
        "@element-plus/icons-vue": "^2.3.1",
        "axios": "^1.6.7",
        "element-plus": "^2.5.6",
        "pinia": "^2.1.7",
        "vue": "^3.4.21",
        "vue-router": "^4.3.0"
      },
      "devDependencies": {
        "@vitejs/plugin-vue": "^5.0.4",
        "typescript": "^5.4.2",
        "vite": "^5.1.6",
        "vue-tsc": "^2.0.6"
      }
    },
    "node_modules/@babel/helper-string-parser": {
      "version": "7.27.1",
      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@babel/helper-validator-identifier": {
      "version": "7.28.5",
      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@babel/parser": {
      "version": "7.29.2",
      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
      "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
      "license": "MIT",
      "dependencies": {
        "@babel/types": "^7.29.0"
      },
      "bin": {
        "parser": "bin/babel-parser.js"
      },
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/@babel/types": {
      "version": "7.29.0",
      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
      "license": "MIT",
      "dependencies": {
        "@babel/helper-string-parser": "^7.27.1",
        "@babel/helper-validator-identifier": "^7.28.5"
      },
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@ctrl/tinycolor": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz",
      "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==",
      "license": "MIT",
      "engines": {
        "node": ">=14"
      }
    },
    "node_modules/@element-plus/icons-vue": {
      "version": "2.3.2",
      "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
      "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
      "license": "MIT",
      "peerDependencies": {
        "vue": "^3.2.0"
      }
    },
    "node_modules/@esbuild/aix-ppc64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
      "cpu": [
        "ppc64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "aix"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/android-arm": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/android-arm64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/android-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/darwin-arm64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/darwin-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/freebsd-arm64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/freebsd-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-arm": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-arm64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-ia32": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
      "cpu": [
        "ia32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-loong64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
      "cpu": [
        "loong64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-mips64el": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
      "cpu": [
        "mips64el"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-ppc64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
      "cpu": [
        "ppc64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-riscv64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
      "cpu": [
        "riscv64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-s390x": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
      "cpu": [
        "s390x"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/linux-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/netbsd-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "netbsd"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/openbsd-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "openbsd"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/sunos-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "sunos"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/win32-arm64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/win32-ia32": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
      "cpu": [
        "ia32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@esbuild/win32-x64": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ],
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/@floating-ui/core": {
      "version": "1.7.5",
      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
      "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
      "license": "MIT",
      "dependencies": {
        "@floating-ui/utils": "^0.2.11"
      }
    },
    "node_modules/@floating-ui/dom": {
      "version": "1.7.6",
      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
      "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
      "license": "MIT",
      "dependencies": {
        "@floating-ui/core": "^1.7.5",
        "@floating-ui/utils": "^0.2.11"
      }
    },
    "node_modules/@floating-ui/utils": {
      "version": "0.2.11",
      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
      "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
      "license": "MIT"
    },
    "node_modules/@jridgewell/sourcemap-codec": {
      "version": "1.5.5",
      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
      "license": "MIT"
    },
    "node_modules/@popperjs/core": {
      "name": "@sxzz/popperjs-es",
      "version": "2.11.8",
      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz",
      "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==",
      "license": "MIT",
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/popperjs"
      }
    },
    "node_modules/@rollup/rollup-android-arm-eabi": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz",
      "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ]
    },
    "node_modules/@rollup/rollup-android-arm64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz",
      "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "android"
      ]
    },
    "node_modules/@rollup/rollup-darwin-arm64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz",
      "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ]
    },
    "node_modules/@rollup/rollup-darwin-x64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz",
      "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ]
    },
    "node_modules/@rollup/rollup-freebsd-arm64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz",
      "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ]
    },
    "node_modules/@rollup/rollup-freebsd-x64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz",
      "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "freebsd"
      ]
    },
    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz",
      "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz",
      "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==",
      "cpu": [
        "arm"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-arm64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz",
      "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-arm64-musl": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz",
      "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-loong64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz",
      "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==",
      "cpu": [
        "loong64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-loong64-musl": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz",
      "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==",
      "cpu": [
        "loong64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz",
      "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==",
      "cpu": [
        "ppc64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-ppc64-musl": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz",
      "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==",
      "cpu": [
        "ppc64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz",
      "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==",
      "cpu": [
        "riscv64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-riscv64-musl": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz",
      "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==",
      "cpu": [
        "riscv64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-s390x-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz",
      "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==",
      "cpu": [
        "s390x"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-x64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz",
      "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-linux-x64-musl": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz",
      "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "linux"
      ]
    },
    "node_modules/@rollup/rollup-openbsd-x64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz",
      "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "openbsd"
      ]
    },
    "node_modules/@rollup/rollup-openharmony-arm64": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz",
      "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "openharmony"
      ]
    },
    "node_modules/@rollup/rollup-win32-arm64-msvc": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz",
      "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==",
      "cpu": [
        "arm64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@rollup/rollup-win32-ia32-msvc": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz",
      "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==",
      "cpu": [
        "ia32"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@rollup/rollup-win32-x64-gnu": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz",
      "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@rollup/rollup-win32-x64-msvc": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz",
      "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==",
      "cpu": [
        "x64"
      ],
      "dev": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "win32"
      ]
    },
    "node_modules/@types/estree": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@types/lodash": {
      "version": "4.17.24",
      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz",
      "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==",
      "license": "MIT"
    },
    "node_modules/@types/lodash-es": {
      "version": "4.17.12",
      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
      "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
      "license": "MIT",
      "dependencies": {
        "@types/lodash": "*"
      }
    },
    "node_modules/@types/web-bluetooth": {
      "version": "0.0.20",
      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
      "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
      "license": "MIT"
    },
    "node_modules/@vitejs/plugin-vue": {
      "version": "5.2.4",
      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
      "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==",
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": "^18.0.0 || >=20.0.0"
      },
      "peerDependencies": {
        "vite": "^5.0.0 || ^6.0.0",
        "vue": "^3.2.25"
      }
    },
    "node_modules/@volar/language-core": {
      "version": "2.4.15",
      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz",
      "integrity": "sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@volar/source-map": "2.4.15"
      }
    },
    "node_modules/@volar/source-map": {
      "version": "2.4.15",
      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.15.tgz",
      "integrity": "sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/@volar/typescript": {
      "version": "2.4.15",
      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.15.tgz",
      "integrity": "sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@volar/language-core": "2.4.15",
        "path-browserify": "^1.0.1",
        "vscode-uri": "^3.0.8"
      }
    },
    "node_modules/@vue/compiler-core": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.32.tgz",
      "integrity": "sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==",
      "license": "MIT",
      "dependencies": {
        "@babel/parser": "^7.29.2",
        "@vue/shared": "3.5.32",
        "entities": "^7.0.1",
        "estree-walker": "^2.0.2",
        "source-map-js": "^1.2.1"
      }
    },
    "node_modules/@vue/compiler-dom": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.32.tgz",
      "integrity": "sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==",
      "license": "MIT",
      "dependencies": {
        "@vue/compiler-core": "3.5.32",
        "@vue/shared": "3.5.32"
      }
    },
    "node_modules/@vue/compiler-sfc": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.32.tgz",
      "integrity": "sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==",
      "license": "MIT",
      "dependencies": {
        "@babel/parser": "^7.29.2",
        "@vue/compiler-core": "3.5.32",
        "@vue/compiler-dom": "3.5.32",
        "@vue/compiler-ssr": "3.5.32",
        "@vue/shared": "3.5.32",
        "estree-walker": "^2.0.2",
        "magic-string": "^0.30.21",
        "postcss": "^8.5.8",
        "source-map-js": "^1.2.1"
      }
    },
    "node_modules/@vue/compiler-ssr": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.32.tgz",
      "integrity": "sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==",
      "license": "MIT",
      "dependencies": {
        "@vue/compiler-dom": "3.5.32",
        "@vue/shared": "3.5.32"
      }
    },
    "node_modules/@vue/compiler-vue2": {
      "version": "2.7.16",
      "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
      "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "de-indent": "^1.0.2",
        "he": "^1.2.0"
      }
    },
    "node_modules/@vue/devtools-api": {
      "version": "6.6.4",
      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
      "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
      "license": "MIT"
    },
    "node_modules/@vue/language-core": {
      "version": "2.2.12",
      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.12.tgz",
      "integrity": "sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@volar/language-core": "2.4.15",
        "@vue/compiler-dom": "^3.5.0",
        "@vue/compiler-vue2": "^2.7.16",
        "@vue/shared": "^3.5.0",
        "alien-signals": "^1.0.3",
        "minimatch": "^9.0.3",
        "muggle-string": "^0.4.1",
        "path-browserify": "^1.0.1"
      },
      "peerDependencies": {
        "typescript": "*"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/@vue/reactivity": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.32.tgz",
      "integrity": "sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==",
      "license": "MIT",
      "dependencies": {
        "@vue/shared": "3.5.32"
      }
    },
    "node_modules/@vue/runtime-core": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.32.tgz",
      "integrity": "sha512-pDrXCejn4UpFDFmMd27AcJEbHaLemaE5o4pbb7sLk79SRIhc6/t34BQA7SGNgYtbMnvbF/HHOftYBgFJtUoJUQ==",
      "license": "MIT",
      "dependencies": {
        "@vue/reactivity": "3.5.32",
        "@vue/shared": "3.5.32"
      }
    },
    "node_modules/@vue/runtime-dom": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.32.tgz",
      "integrity": "sha512-1CDVv7tv/IV13V8Nip1k/aaObVbWqRlVCVezTwx3K07p7Vxossp5JU1dcPNhJk3w347gonIUT9jQOGutyJrSVQ==",
      "license": "MIT",
      "dependencies": {
        "@vue/reactivity": "3.5.32",
        "@vue/runtime-core": "3.5.32",
        "@vue/shared": "3.5.32",
        "csstype": "^3.2.3"
      }
    },
    "node_modules/@vue/server-renderer": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.32.tgz",
      "integrity": "sha512-IOjm2+JQwRFS7W28HNuJeXQle9KdZbODFY7hFGVtnnghF51ta20EWAZJHX+zLGtsHhaU6uC9BGPV52KVpYryMQ==",
      "license": "MIT",
      "dependencies": {
        "@vue/compiler-ssr": "3.5.32",
        "@vue/shared": "3.5.32"
      },
      "peerDependencies": {
        "vue": "3.5.32"
      }
    },
    "node_modules/@vue/shared": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.32.tgz",
      "integrity": "sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==",
      "license": "MIT"
    },
    "node_modules/@vueuse/core": {
      "version": "12.0.0",
      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz",
      "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==",
      "license": "MIT",
      "dependencies": {
        "@types/web-bluetooth": "^0.0.20",
        "@vueuse/metadata": "12.0.0",
        "@vueuse/shared": "12.0.0",
        "vue": "^3.5.13"
      },
      "funding": {
        "url": "https://github.com/sponsors/antfu"
      }
    },
    "node_modules/@vueuse/metadata": {
      "version": "12.0.0",
      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz",
      "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==",
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/antfu"
      }
    },
    "node_modules/@vueuse/shared": {
      "version": "12.0.0",
      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz",
      "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==",
      "license": "MIT",
      "dependencies": {
        "vue": "^3.5.13"
      },
      "funding": {
        "url": "https://github.com/sponsors/antfu"
      }
    },
    "node_modules/alien-signals": {
      "version": "1.0.13",
      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz",
      "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/async-validator": {
      "version": "4.2.5",
      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
      "license": "MIT"
    },
    "node_modules/asynckit": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
      "license": "MIT"
    },
    "node_modules/axios": {
      "version": "1.15.0",
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
      "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==",
      "license": "MIT",
      "dependencies": {
        "follow-redirects": "^1.15.11",
        "form-data": "^4.0.5",
        "proxy-from-env": "^2.1.0"
      }
    },
    "node_modules/balanced-match": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/brace-expansion": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
      "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "balanced-match": "^1.0.0"
      }
    },
    "node_modules/call-bind-apply-helpers": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/combined-stream": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
      "license": "MIT",
      "dependencies": {
        "delayed-stream": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/csstype": {
      "version": "3.2.3",
      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
      "license": "MIT"
    },
    "node_modules/dayjs": {
      "version": "1.11.20",
      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz",
      "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
      "license": "MIT"
    },
    "node_modules/de-indent": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
      "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/delayed-stream": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
      "license": "MIT",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/dunder-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.1",
        "es-errors": "^1.3.0",
        "gopd": "^1.2.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/element-plus": {
      "version": "2.13.7",
      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.13.7.tgz",
      "integrity": "sha512-XdHATFZOyzVFL1DaHQ90IOJQSg9UnSAV+bhDW+YB5UoZ0Hxs50mwqjqfwXkuwpSag+VXXizVcErBR6Movo5daw==",
      "license": "MIT",
      "dependencies": {
        "@ctrl/tinycolor": "^4.2.0",
        "@element-plus/icons-vue": "^2.3.2",
        "@floating-ui/dom": "^1.0.1",
        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
        "@types/lodash": "^4.17.20",
        "@types/lodash-es": "^4.17.12",
        "@vueuse/core": "12.0.0",
        "async-validator": "^4.2.5",
        "dayjs": "^1.11.19",
        "lodash": "^4.17.23",
        "lodash-es": "^4.17.23",
        "lodash-unified": "^1.0.3",
        "memoize-one": "^6.0.0",
        "normalize-wheel-es": "^1.2.0",
        "vue-component-type-helpers": "^3.2.4"
      },
      "peerDependencies": {
        "vue": "^3.3.0"
      }
    },
    "node_modules/entities": {
      "version": "7.0.1",
      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=0.12"
      },
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-object-atoms": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
      "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/esbuild": {
      "version": "0.21.5",
      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
      "dev": true,
      "hasInstallScript": true,
      "license": "MIT",
      "bin": {
        "esbuild": "bin/esbuild"
      },
      "engines": {
        "node": ">=12"
      },
      "optionalDependencies": {
        "@esbuild/aix-ppc64": "0.21.5",
        "@esbuild/android-arm": "0.21.5",
        "@esbuild/android-arm64": "0.21.5",
        "@esbuild/android-x64": "0.21.5",
        "@esbuild/darwin-arm64": "0.21.5",
        "@esbuild/darwin-x64": "0.21.5",
        "@esbuild/freebsd-arm64": "0.21.5",
        "@esbuild/freebsd-x64": "0.21.5",
        "@esbuild/linux-arm": "0.21.5",
        "@esbuild/linux-arm64": "0.21.5",
        "@esbuild/linux-ia32": "0.21.5",
        "@esbuild/linux-loong64": "0.21.5",
        "@esbuild/linux-mips64el": "0.21.5",
        "@esbuild/linux-ppc64": "0.21.5",
        "@esbuild/linux-riscv64": "0.21.5",
        "@esbuild/linux-s390x": "0.21.5",
        "@esbuild/linux-x64": "0.21.5",
        "@esbuild/netbsd-x64": "0.21.5",
        "@esbuild/openbsd-x64": "0.21.5",
        "@esbuild/sunos-x64": "0.21.5",
        "@esbuild/win32-arm64": "0.21.5",
        "@esbuild/win32-ia32": "0.21.5",
        "@esbuild/win32-x64": "0.21.5"
      }
    },
    "node_modules/estree-walker": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
      "license": "MIT"
    },
    "node_modules/follow-redirects": {
      "version": "1.16.0",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
      "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
      "funding": [
        {
          "type": "individual",
          "url": "https://github.com/sponsors/RubenVerborgh"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=4.0"
      },
      "peerDependenciesMeta": {
        "debug": {
          "optional": true
        }
      }
    },
    "node_modules/form-data": {
      "version": "4.0.5",
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
      "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
      "license": "MIT",
      "dependencies": {
        "asynckit": "^0.4.0",
        "combined-stream": "^1.0.8",
        "es-set-tostringtag": "^2.1.0",
        "hasown": "^2.0.2",
        "mime-types": "^2.1.12"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/fsevents": {
      "version": "2.3.3",
      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
      "dev": true,
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "os": [
        "darwin"
      ],
      "engines": {
        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
      "license": "MIT",
      "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"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
      "license": "MIT",
      "dependencies": {
        "has-symbols": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hasown": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
      "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
      "license": "MIT",
      "dependencies": {
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/he": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
      "dev": true,
      "license": "MIT",
      "bin": {
        "he": "bin/he"
      }
    },
    "node_modules/lodash": {
      "version": "4.18.1",
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
      "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
      "license": "MIT"
    },
    "node_modules/lodash-es": {
      "version": "4.18.1",
      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz",
      "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==",
      "license": "MIT"
    },
    "node_modules/lodash-unified": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
      "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
      "license": "MIT",
      "peerDependencies": {
        "@types/lodash-es": "*",
        "lodash": "*",
        "lodash-es": "*"
      }
    },
    "node_modules/magic-string": {
      "version": "0.30.21",
      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
      "license": "MIT",
      "dependencies": {
        "@jridgewell/sourcemap-codec": "^1.5.5"
      }
    },
    "node_modules/math-intrinsics": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/memoize-one": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
      "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
      "license": "MIT"
    },
    "node_modules/mime-db": {
      "version": "1.52.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
      "license": "MIT",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.35",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
      "license": "MIT",
      "dependencies": {
        "mime-db": "1.52.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/minimatch": {
      "version": "9.0.9",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
      "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
      "dev": true,
      "license": "ISC",
      "dependencies": {
        "brace-expansion": "^2.0.2"
      },
      "engines": {
        "node": ">=16 || 14 >=14.17"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/muggle-string": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
      "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/nanoid": {
      "version": "3.3.11",
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "bin": {
        "nanoid": "bin/nanoid.cjs"
      },
      "engines": {
        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
      }
    },
    "node_modules/normalize-wheel-es": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
      "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==",
      "license": "BSD-3-Clause"
    },
    "node_modules/path-browserify": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/picocolors": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
      "license": "ISC"
    },
    "node_modules/pinia": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
      "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
      "license": "MIT",
      "dependencies": {
        "@vue/devtools-api": "^6.6.3",
        "vue-demi": "^0.14.10"
      },
      "funding": {
        "url": "https://github.com/sponsors/posva"
      },
      "peerDependencies": {
        "typescript": ">=4.4.4",
        "vue": "^2.7.0 || ^3.5.11"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/postcss": {
      "version": "8.5.10",
      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
      "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
      "funding": [
        {
          "type": "opencollective",
          "url": "https://opencollective.com/postcss/"
        },
        {
          "type": "tidelift",
          "url": "https://tidelift.com/funding/github/npm/postcss"
        },
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "nanoid": "^3.3.11",
        "picocolors": "^1.1.1",
        "source-map-js": "^1.2.1"
      },
      "engines": {
        "node": "^10 || ^12 || >=14"
      }
    },
    "node_modules/proxy-from-env": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
      "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/rollup": {
      "version": "4.60.2",
      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz",
      "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@types/estree": "1.0.8"
      },
      "bin": {
        "rollup": "dist/bin/rollup"
      },
      "engines": {
        "node": ">=18.0.0",
        "npm": ">=8.0.0"
      },
      "optionalDependencies": {
        "@rollup/rollup-android-arm-eabi": "4.60.2",
        "@rollup/rollup-android-arm64": "4.60.2",
        "@rollup/rollup-darwin-arm64": "4.60.2",
        "@rollup/rollup-darwin-x64": "4.60.2",
        "@rollup/rollup-freebsd-arm64": "4.60.2",
        "@rollup/rollup-freebsd-x64": "4.60.2",
        "@rollup/rollup-linux-arm-gnueabihf": "4.60.2",
        "@rollup/rollup-linux-arm-musleabihf": "4.60.2",
        "@rollup/rollup-linux-arm64-gnu": "4.60.2",
        "@rollup/rollup-linux-arm64-musl": "4.60.2",
        "@rollup/rollup-linux-loong64-gnu": "4.60.2",
        "@rollup/rollup-linux-loong64-musl": "4.60.2",
        "@rollup/rollup-linux-ppc64-gnu": "4.60.2",
        "@rollup/rollup-linux-ppc64-musl": "4.60.2",
        "@rollup/rollup-linux-riscv64-gnu": "4.60.2",
        "@rollup/rollup-linux-riscv64-musl": "4.60.2",
        "@rollup/rollup-linux-s390x-gnu": "4.60.2",
        "@rollup/rollup-linux-x64-gnu": "4.60.2",
        "@rollup/rollup-linux-x64-musl": "4.60.2",
        "@rollup/rollup-openbsd-x64": "4.60.2",
        "@rollup/rollup-openharmony-arm64": "4.60.2",
        "@rollup/rollup-win32-arm64-msvc": "4.60.2",
        "@rollup/rollup-win32-ia32-msvc": "4.60.2",
        "@rollup/rollup-win32-x64-gnu": "4.60.2",
        "@rollup/rollup-win32-x64-msvc": "4.60.2",
        "fsevents": "~2.3.2"
      }
    },
    "node_modules/source-map-js": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/typescript": {
      "version": "5.9.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
      "devOptional": true,
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/vite": {
      "version": "5.4.21",
      "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
      "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "esbuild": "^0.21.3",
        "postcss": "^8.4.43",
        "rollup": "^4.20.0"
      },
      "bin": {
        "vite": "bin/vite.js"
      },
      "engines": {
        "node": "^18.0.0 || >=20.0.0"
      },
      "funding": {
        "url": "https://github.com/vitejs/vite?sponsor=1"
      },
      "optionalDependencies": {
        "fsevents": "~2.3.3"
      },
      "peerDependencies": {
        "@types/node": "^18.0.0 || >=20.0.0",
        "less": "*",
        "lightningcss": "^1.21.0",
        "sass": "*",
        "sass-embedded": "*",
        "stylus": "*",
        "sugarss": "*",
        "terser": "^5.4.0"
      },
      "peerDependenciesMeta": {
        "@types/node": {
          "optional": true
        },
        "less": {
          "optional": true
        },
        "lightningcss": {
          "optional": true
        },
        "sass": {
          "optional": true
        },
        "sass-embedded": {
          "optional": true
        },
        "stylus": {
          "optional": true
        },
        "sugarss": {
          "optional": true
        },
        "terser": {
          "optional": true
        }
      }
    },
    "node_modules/vscode-uri": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
      "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/vue": {
      "version": "3.5.32",
      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz",
      "integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==",
      "license": "MIT",
      "dependencies": {
        "@vue/compiler-dom": "3.5.32",
        "@vue/compiler-sfc": "3.5.32",
        "@vue/runtime-dom": "3.5.32",
        "@vue/server-renderer": "3.5.32",
        "@vue/shared": "3.5.32"
      },
      "peerDependencies": {
        "typescript": "*"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/vue-component-type-helpers": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.2.7.tgz",
      "integrity": "sha512-+gPp5YGmhfsj1IN+xUo7y0fb4clfnOiiUA39y07yW1VzCRjzVgwLbtmdWlghh7mXrPsEaYc7rrIir/HT6C8vYQ==",
      "license": "MIT"
    },
    "node_modules/vue-demi": {
      "version": "0.14.10",
      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
      "hasInstallScript": true,
      "license": "MIT",
      "bin": {
        "vue-demi-fix": "bin/vue-demi-fix.js",
        "vue-demi-switch": "bin/vue-demi-switch.js"
      },
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://github.com/sponsors/antfu"
      },
      "peerDependencies": {
        "@vue/composition-api": "^1.0.0-rc.1",
        "vue": "^3.0.0-0 || ^2.6.0"
      },
      "peerDependenciesMeta": {
        "@vue/composition-api": {
          "optional": true
        }
      }
    },
    "node_modules/vue-router": {
      "version": "4.6.4",
      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
      "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
      "license": "MIT",
      "dependencies": {
        "@vue/devtools-api": "^6.6.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/posva"
      },
      "peerDependencies": {
        "vue": "^3.5.0"
      }
    },
    "node_modules/vue-tsc": {
      "version": "2.2.12",
      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.12.tgz",
      "integrity": "sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@volar/typescript": "2.4.15",
        "@vue/language-core": "2.2.12"
      },
      "bin": {
        "vue-tsc": "bin/vue-tsc.js"
      },
      "peerDependencies": {
        "typescript": ">=5.0.0"
      }
    }
  }
}
Code/WMS/WIDESEA_WMSClient_Vben/package.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
{
  "name": "widesea-wms-client-vben",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@element-plus/icons-vue": "^2.3.1",
    "axios": "^1.6.7",
    "element-plus": "^2.5.6",
    "pinia": "^2.1.7",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.4",
    "typescript": "^5.4.2",
    "vite": "^5.1.6",
    "vue-tsc": "^2.0.6"
  }
}
Code/WMS/WIDESEA_WMSClient_Vben/pnpm-lock.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1297 @@
lockfileVersion: '9.0'
settings:
  autoInstallPeers: true
  excludeLinksFromLockfile: false
importers:
  .:
    dependencies:
      '@element-plus/icons-vue':
        specifier: ^2.3.1
        version: 2.3.2(vue@3.5.32(typescript@5.9.3))
      axios:
        specifier: ^1.6.7
        version: 1.15.0
      element-plus:
        specifier: ^2.5.6
        version: 2.13.7(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3))
      pinia:
        specifier: ^2.1.7
        version: 2.3.1(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3))
      vue:
        specifier: ^3.4.21
        version: 3.5.32(typescript@5.9.3)
      vue-router:
        specifier: ^4.3.0
        version: 4.6.4(vue@3.5.32(typescript@5.9.3))
    devDependencies:
      '@vitejs/plugin-vue':
        specifier: ^5.0.4
        version: 5.2.4(vite@5.4.21)(vue@3.5.32(typescript@5.9.3))
      typescript:
        specifier: ^5.4.2
        version: 5.9.3
      vite:
        specifier: ^5.1.6
        version: 5.4.21
      vue-tsc:
        specifier: ^2.0.6
        version: 2.2.12(typescript@5.9.3)
packages:
  '@babel/helper-string-parser@7.27.1':
    resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
    engines: {node: '>=6.9.0'}
  '@babel/helper-validator-identifier@7.28.5':
    resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
    engines: {node: '>=6.9.0'}
  '@babel/parser@7.29.2':
    resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
    engines: {node: '>=6.0.0'}
    hasBin: true
  '@babel/types@7.29.0':
    resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
    engines: {node: '>=6.9.0'}
  '@ctrl/tinycolor@4.2.0':
    resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==}
    engines: {node: '>=14'}
  '@element-plus/icons-vue@2.3.2':
    resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==}
    peerDependencies:
      vue: ^3.2.0
  '@esbuild/aix-ppc64@0.21.5':
    resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
    engines: {node: '>=12'}
    cpu: [ppc64]
    os: [aix]
  '@esbuild/android-arm64@0.21.5':
    resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
    engines: {node: '>=12'}
    cpu: [arm64]
    os: [android]
  '@esbuild/android-arm@0.21.5':
    resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
    engines: {node: '>=12'}
    cpu: [arm]
    os: [android]
  '@esbuild/android-x64@0.21.5':
    resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [android]
  '@esbuild/darwin-arm64@0.21.5':
    resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
    engines: {node: '>=12'}
    cpu: [arm64]
    os: [darwin]
  '@esbuild/darwin-x64@0.21.5':
    resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [darwin]
  '@esbuild/freebsd-arm64@0.21.5':
    resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
    engines: {node: '>=12'}
    cpu: [arm64]
    os: [freebsd]
  '@esbuild/freebsd-x64@0.21.5':
    resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [freebsd]
  '@esbuild/linux-arm64@0.21.5':
    resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
    engines: {node: '>=12'}
    cpu: [arm64]
    os: [linux]
  '@esbuild/linux-arm@0.21.5':
    resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
    engines: {node: '>=12'}
    cpu: [arm]
    os: [linux]
  '@esbuild/linux-ia32@0.21.5':
    resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
    engines: {node: '>=12'}
    cpu: [ia32]
    os: [linux]
  '@esbuild/linux-loong64@0.21.5':
    resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
    engines: {node: '>=12'}
    cpu: [loong64]
    os: [linux]
  '@esbuild/linux-mips64el@0.21.5':
    resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
    engines: {node: '>=12'}
    cpu: [mips64el]
    os: [linux]
  '@esbuild/linux-ppc64@0.21.5':
    resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
    engines: {node: '>=12'}
    cpu: [ppc64]
    os: [linux]
  '@esbuild/linux-riscv64@0.21.5':
    resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
    engines: {node: '>=12'}
    cpu: [riscv64]
    os: [linux]
  '@esbuild/linux-s390x@0.21.5':
    resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
    engines: {node: '>=12'}
    cpu: [s390x]
    os: [linux]
  '@esbuild/linux-x64@0.21.5':
    resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [linux]
  '@esbuild/netbsd-x64@0.21.5':
    resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [netbsd]
  '@esbuild/openbsd-x64@0.21.5':
    resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [openbsd]
  '@esbuild/sunos-x64@0.21.5':
    resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [sunos]
  '@esbuild/win32-arm64@0.21.5':
    resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
    engines: {node: '>=12'}
    cpu: [arm64]
    os: [win32]
  '@esbuild/win32-ia32@0.21.5':
    resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
    engines: {node: '>=12'}
    cpu: [ia32]
    os: [win32]
  '@esbuild/win32-x64@0.21.5':
    resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
    engines: {node: '>=12'}
    cpu: [x64]
    os: [win32]
  '@floating-ui/core@1.7.5':
    resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
  '@floating-ui/dom@1.7.6':
    resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==}
  '@floating-ui/utils@0.2.11':
    resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
  '@jridgewell/sourcemap-codec@1.5.5':
    resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
  '@rollup/rollup-android-arm-eabi@4.60.2':
    resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==}
    cpu: [arm]
    os: [android]
  '@rollup/rollup-android-arm64@4.60.2':
    resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==}
    cpu: [arm64]
    os: [android]
  '@rollup/rollup-darwin-arm64@4.60.2':
    resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==}
    cpu: [arm64]
    os: [darwin]
  '@rollup/rollup-darwin-x64@4.60.2':
    resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==}
    cpu: [x64]
    os: [darwin]
  '@rollup/rollup-freebsd-arm64@4.60.2':
    resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==}
    cpu: [arm64]
    os: [freebsd]
  '@rollup/rollup-freebsd-x64@4.60.2':
    resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==}
    cpu: [x64]
    os: [freebsd]
  '@rollup/rollup-linux-arm-gnueabihf@4.60.2':
    resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==}
    cpu: [arm]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-arm-musleabihf@4.60.2':
    resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==}
    cpu: [arm]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-arm64-gnu@4.60.2':
    resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==}
    cpu: [arm64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-arm64-musl@4.60.2':
    resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==}
    cpu: [arm64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-loong64-gnu@4.60.2':
    resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==}
    cpu: [loong64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-loong64-musl@4.60.2':
    resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==}
    cpu: [loong64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-ppc64-gnu@4.60.2':
    resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==}
    cpu: [ppc64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-ppc64-musl@4.60.2':
    resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==}
    cpu: [ppc64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-riscv64-gnu@4.60.2':
    resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==}
    cpu: [riscv64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-riscv64-musl@4.60.2':
    resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==}
    cpu: [riscv64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-linux-s390x-gnu@4.60.2':
    resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==}
    cpu: [s390x]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-x64-gnu@4.60.2':
    resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==}
    cpu: [x64]
    os: [linux]
    libc: [glibc]
  '@rollup/rollup-linux-x64-musl@4.60.2':
    resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==}
    cpu: [x64]
    os: [linux]
    libc: [musl]
  '@rollup/rollup-openbsd-x64@4.60.2':
    resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==}
    cpu: [x64]
    os: [openbsd]
  '@rollup/rollup-openharmony-arm64@4.60.2':
    resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==}
    cpu: [arm64]
    os: [openharmony]
  '@rollup/rollup-win32-arm64-msvc@4.60.2':
    resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==}
    cpu: [arm64]
    os: [win32]
  '@rollup/rollup-win32-ia32-msvc@4.60.2':
    resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==}
    cpu: [ia32]
    os: [win32]
  '@rollup/rollup-win32-x64-gnu@4.60.2':
    resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==}
    cpu: [x64]
    os: [win32]
  '@rollup/rollup-win32-x64-msvc@4.60.2':
    resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==}
    cpu: [x64]
    os: [win32]
  '@sxzz/popperjs-es@2.11.8':
    resolution: {integrity: sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==}
  '@types/estree@1.0.8':
    resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
  '@types/lodash-es@4.17.12':
    resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
  '@types/lodash@4.17.24':
    resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==}
  '@types/web-bluetooth@0.0.20':
    resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
  '@vitejs/plugin-vue@5.2.4':
    resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==}
    engines: {node: ^18.0.0 || >=20.0.0}
    peerDependencies:
      vite: ^5.0.0 || ^6.0.0
      vue: ^3.2.25
  '@volar/language-core@2.4.15':
    resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
  '@volar/source-map@2.4.15':
    resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==}
  '@volar/typescript@2.4.15':
    resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==}
  '@vue/compiler-core@3.5.32':
    resolution: {integrity: sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==}
  '@vue/compiler-dom@3.5.32':
    resolution: {integrity: sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==}
  '@vue/compiler-sfc@3.5.32':
    resolution: {integrity: sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==}
  '@vue/compiler-ssr@3.5.32':
    resolution: {integrity: sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==}
  '@vue/compiler-vue2@2.7.16':
    resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
  '@vue/devtools-api@6.6.4':
    resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
  '@vue/language-core@2.2.12':
    resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==}
    peerDependencies:
      typescript: '*'
    peerDependenciesMeta:
      typescript:
        optional: true
  '@vue/reactivity@3.5.32':
    resolution: {integrity: sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==}
  '@vue/runtime-core@3.5.32':
    resolution: {integrity: sha512-pDrXCejn4UpFDFmMd27AcJEbHaLemaE5o4pbb7sLk79SRIhc6/t34BQA7SGNgYtbMnvbF/HHOftYBgFJtUoJUQ==}
  '@vue/runtime-dom@3.5.32':
    resolution: {integrity: sha512-1CDVv7tv/IV13V8Nip1k/aaObVbWqRlVCVezTwx3K07p7Vxossp5JU1dcPNhJk3w347gonIUT9jQOGutyJrSVQ==}
  '@vue/server-renderer@3.5.32':
    resolution: {integrity: sha512-IOjm2+JQwRFS7W28HNuJeXQle9KdZbODFY7hFGVtnnghF51ta20EWAZJHX+zLGtsHhaU6uC9BGPV52KVpYryMQ==}
    peerDependencies:
      vue: 3.5.32
  '@vue/shared@3.5.32':
    resolution: {integrity: sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==}
  '@vueuse/core@12.0.0':
    resolution: {integrity: sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==}
  '@vueuse/metadata@12.0.0':
    resolution: {integrity: sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==}
  '@vueuse/shared@12.0.0':
    resolution: {integrity: sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==}
  alien-signals@1.0.13:
    resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==}
  async-validator@4.2.5:
    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
  asynckit@0.4.0:
    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
  axios@1.15.0:
    resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
  balanced-match@1.0.2:
    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
  brace-expansion@2.1.0:
    resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==}
  call-bind-apply-helpers@1.0.2:
    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
    engines: {node: '>= 0.4'}
  combined-stream@1.0.8:
    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
    engines: {node: '>= 0.8'}
  csstype@3.2.3:
    resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
  dayjs@1.11.20:
    resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
  de-indent@1.0.2:
    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
  delayed-stream@1.0.0:
    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
    engines: {node: '>=0.4.0'}
  dunder-proto@1.0.1:
    resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
    engines: {node: '>= 0.4'}
  element-plus@2.13.7:
    resolution: {integrity: sha512-XdHATFZOyzVFL1DaHQ90IOJQSg9UnSAV+bhDW+YB5UoZ0Hxs50mwqjqfwXkuwpSag+VXXizVcErBR6Movo5daw==}
    peerDependencies:
      vue: ^3.3.0
  entities@7.0.1:
    resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
    engines: {node: '>=0.12'}
  es-define-property@1.0.1:
    resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
    engines: {node: '>= 0.4'}
  es-errors@1.3.0:
    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
    engines: {node: '>= 0.4'}
  es-object-atoms@1.1.1:
    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
    engines: {node: '>= 0.4'}
  es-set-tostringtag@2.1.0:
    resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
    engines: {node: '>= 0.4'}
  esbuild@0.21.5:
    resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
    engines: {node: '>=12'}
    hasBin: true
  estree-walker@2.0.2:
    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
  follow-redirects@1.16.0:
    resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
    engines: {node: '>=4.0'}
    peerDependencies:
      debug: '*'
    peerDependenciesMeta:
      debug:
        optional: true
  form-data@4.0.5:
    resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
    engines: {node: '>= 6'}
  fsevents@2.3.3:
    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
    os: [darwin]
  function-bind@1.1.2:
    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
  get-intrinsic@1.3.0:
    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
    engines: {node: '>= 0.4'}
  get-proto@1.0.1:
    resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
    engines: {node: '>= 0.4'}
  gopd@1.2.0:
    resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
    engines: {node: '>= 0.4'}
  has-symbols@1.1.0:
    resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
    engines: {node: '>= 0.4'}
  has-tostringtag@1.0.2:
    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
    engines: {node: '>= 0.4'}
  hasown@2.0.3:
    resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
    engines: {node: '>= 0.4'}
  he@1.2.0:
    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
    hasBin: true
  lodash-es@4.18.1:
    resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==}
  lodash-unified@1.0.3:
    resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==}
    peerDependencies:
      '@types/lodash-es': '*'
      lodash: '*'
      lodash-es: '*'
  lodash@4.18.1:
    resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
  magic-string@0.30.21:
    resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
  math-intrinsics@1.1.0:
    resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
    engines: {node: '>= 0.4'}
  memoize-one@6.0.0:
    resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
  mime-db@1.52.0:
    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
    engines: {node: '>= 0.6'}
  mime-types@2.1.35:
    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
    engines: {node: '>= 0.6'}
  minimatch@9.0.9:
    resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
    engines: {node: '>=16 || 14 >=14.17'}
  muggle-string@0.4.1:
    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
  nanoid@3.3.11:
    resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
    hasBin: true
  normalize-wheel-es@1.2.0:
    resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
  path-browserify@1.0.1:
    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
  picocolors@1.1.1:
    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
  pinia@2.3.1:
    resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
    peerDependencies:
      typescript: '>=4.4.4'
      vue: ^2.7.0 || ^3.5.11
    peerDependenciesMeta:
      typescript:
        optional: true
  postcss@8.5.10:
    resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
    engines: {node: ^10 || ^12 || >=14}
  proxy-from-env@2.1.0:
    resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
    engines: {node: '>=10'}
  rollup@4.60.2:
    resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==}
    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
    hasBin: true
  source-map-js@1.2.1:
    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
    engines: {node: '>=0.10.0'}
  typescript@5.9.3:
    resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
    engines: {node: '>=14.17'}
    hasBin: true
  vite@5.4.21:
    resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
    engines: {node: ^18.0.0 || >=20.0.0}
    hasBin: true
    peerDependencies:
      '@types/node': ^18.0.0 || >=20.0.0
      less: '*'
      lightningcss: ^1.21.0
      sass: '*'
      sass-embedded: '*'
      stylus: '*'
      sugarss: '*'
      terser: ^5.4.0
    peerDependenciesMeta:
      '@types/node':
        optional: true
      less:
        optional: true
      lightningcss:
        optional: true
      sass:
        optional: true
      sass-embedded:
        optional: true
      stylus:
        optional: true
      sugarss:
        optional: true
      terser:
        optional: true
  vscode-uri@3.1.0:
    resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
  vue-component-type-helpers@3.2.7:
    resolution: {integrity: sha512-+gPp5YGmhfsj1IN+xUo7y0fb4clfnOiiUA39y07yW1VzCRjzVgwLbtmdWlghh7mXrPsEaYc7rrIir/HT6C8vYQ==}
  vue-demi@0.14.10:
    resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
    engines: {node: '>=12'}
    hasBin: true
    peerDependencies:
      '@vue/composition-api': ^1.0.0-rc.1
      vue: ^3.0.0-0 || ^2.6.0
    peerDependenciesMeta:
      '@vue/composition-api':
        optional: true
  vue-router@4.6.4:
    resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
    peerDependencies:
      vue: ^3.5.0
  vue-tsc@2.2.12:
    resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==}
    hasBin: true
    peerDependencies:
      typescript: '>=5.0.0'
  vue@3.5.32:
    resolution: {integrity: sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==}
    peerDependencies:
      typescript: '*'
    peerDependenciesMeta:
      typescript:
        optional: true
snapshots:
  '@babel/helper-string-parser@7.27.1': {}
  '@babel/helper-validator-identifier@7.28.5': {}
  '@babel/parser@7.29.2':
    dependencies:
      '@babel/types': 7.29.0
  '@babel/types@7.29.0':
    dependencies:
      '@babel/helper-string-parser': 7.27.1
      '@babel/helper-validator-identifier': 7.28.5
  '@ctrl/tinycolor@4.2.0': {}
  '@element-plus/icons-vue@2.3.2(vue@3.5.32(typescript@5.9.3))':
    dependencies:
      vue: 3.5.32(typescript@5.9.3)
  '@esbuild/aix-ppc64@0.21.5':
    optional: true
  '@esbuild/android-arm64@0.21.5':
    optional: true
  '@esbuild/android-arm@0.21.5':
    optional: true
  '@esbuild/android-x64@0.21.5':
    optional: true
  '@esbuild/darwin-arm64@0.21.5':
    optional: true
  '@esbuild/darwin-x64@0.21.5':
    optional: true
  '@esbuild/freebsd-arm64@0.21.5':
    optional: true
  '@esbuild/freebsd-x64@0.21.5':
    optional: true
  '@esbuild/linux-arm64@0.21.5':
    optional: true
  '@esbuild/linux-arm@0.21.5':
    optional: true
  '@esbuild/linux-ia32@0.21.5':
    optional: true
  '@esbuild/linux-loong64@0.21.5':
    optional: true
  '@esbuild/linux-mips64el@0.21.5':
    optional: true
  '@esbuild/linux-ppc64@0.21.5':
    optional: true
  '@esbuild/linux-riscv64@0.21.5':
    optional: true
  '@esbuild/linux-s390x@0.21.5':
    optional: true
  '@esbuild/linux-x64@0.21.5':
    optional: true
  '@esbuild/netbsd-x64@0.21.5':
    optional: true
  '@esbuild/openbsd-x64@0.21.5':
    optional: true
  '@esbuild/sunos-x64@0.21.5':
    optional: true
  '@esbuild/win32-arm64@0.21.5':
    optional: true
  '@esbuild/win32-ia32@0.21.5':
    optional: true
  '@esbuild/win32-x64@0.21.5':
    optional: true
  '@floating-ui/core@1.7.5':
    dependencies:
      '@floating-ui/utils': 0.2.11
  '@floating-ui/dom@1.7.6':
    dependencies:
      '@floating-ui/core': 1.7.5
      '@floating-ui/utils': 0.2.11
  '@floating-ui/utils@0.2.11': {}
  '@jridgewell/sourcemap-codec@1.5.5': {}
  '@rollup/rollup-android-arm-eabi@4.60.2':
    optional: true
  '@rollup/rollup-android-arm64@4.60.2':
    optional: true
  '@rollup/rollup-darwin-arm64@4.60.2':
    optional: true
  '@rollup/rollup-darwin-x64@4.60.2':
    optional: true
  '@rollup/rollup-freebsd-arm64@4.60.2':
    optional: true
  '@rollup/rollup-freebsd-x64@4.60.2':
    optional: true
  '@rollup/rollup-linux-arm-gnueabihf@4.60.2':
    optional: true
  '@rollup/rollup-linux-arm-musleabihf@4.60.2':
    optional: true
  '@rollup/rollup-linux-arm64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-arm64-musl@4.60.2':
    optional: true
  '@rollup/rollup-linux-loong64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-loong64-musl@4.60.2':
    optional: true
  '@rollup/rollup-linux-ppc64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-ppc64-musl@4.60.2':
    optional: true
  '@rollup/rollup-linux-riscv64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-riscv64-musl@4.60.2':
    optional: true
  '@rollup/rollup-linux-s390x-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-x64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-linux-x64-musl@4.60.2':
    optional: true
  '@rollup/rollup-openbsd-x64@4.60.2':
    optional: true
  '@rollup/rollup-openharmony-arm64@4.60.2':
    optional: true
  '@rollup/rollup-win32-arm64-msvc@4.60.2':
    optional: true
  '@rollup/rollup-win32-ia32-msvc@4.60.2':
    optional: true
  '@rollup/rollup-win32-x64-gnu@4.60.2':
    optional: true
  '@rollup/rollup-win32-x64-msvc@4.60.2':
    optional: true
  '@sxzz/popperjs-es@2.11.8': {}
  '@types/estree@1.0.8': {}
  '@types/lodash-es@4.17.12':
    dependencies:
      '@types/lodash': 4.17.24
  '@types/lodash@4.17.24': {}
  '@types/web-bluetooth@0.0.20': {}
  '@vitejs/plugin-vue@5.2.4(vite@5.4.21)(vue@3.5.32(typescript@5.9.3))':
    dependencies:
      vite: 5.4.21
      vue: 3.5.32(typescript@5.9.3)
  '@volar/language-core@2.4.15':
    dependencies:
      '@volar/source-map': 2.4.15
  '@volar/source-map@2.4.15': {}
  '@volar/typescript@2.4.15':
    dependencies:
      '@volar/language-core': 2.4.15
      path-browserify: 1.0.1
      vscode-uri: 3.1.0
  '@vue/compiler-core@3.5.32':
    dependencies:
      '@babel/parser': 7.29.2
      '@vue/shared': 3.5.32
      entities: 7.0.1
      estree-walker: 2.0.2
      source-map-js: 1.2.1
  '@vue/compiler-dom@3.5.32':
    dependencies:
      '@vue/compiler-core': 3.5.32
      '@vue/shared': 3.5.32
  '@vue/compiler-sfc@3.5.32':
    dependencies:
      '@babel/parser': 7.29.2
      '@vue/compiler-core': 3.5.32
      '@vue/compiler-dom': 3.5.32
      '@vue/compiler-ssr': 3.5.32
      '@vue/shared': 3.5.32
      estree-walker: 2.0.2
      magic-string: 0.30.21
      postcss: 8.5.10
      source-map-js: 1.2.1
  '@vue/compiler-ssr@3.5.32':
    dependencies:
      '@vue/compiler-dom': 3.5.32
      '@vue/shared': 3.5.32
  '@vue/compiler-vue2@2.7.16':
    dependencies:
      de-indent: 1.0.2
      he: 1.2.0
  '@vue/devtools-api@6.6.4': {}
  '@vue/language-core@2.2.12(typescript@5.9.3)':
    dependencies:
      '@volar/language-core': 2.4.15
      '@vue/compiler-dom': 3.5.32
      '@vue/compiler-vue2': 2.7.16
      '@vue/shared': 3.5.32
      alien-signals: 1.0.13
      minimatch: 9.0.9
      muggle-string: 0.4.1
      path-browserify: 1.0.1
    optionalDependencies:
      typescript: 5.9.3
  '@vue/reactivity@3.5.32':
    dependencies:
      '@vue/shared': 3.5.32
  '@vue/runtime-core@3.5.32':
    dependencies:
      '@vue/reactivity': 3.5.32
      '@vue/shared': 3.5.32
  '@vue/runtime-dom@3.5.32':
    dependencies:
      '@vue/reactivity': 3.5.32
      '@vue/runtime-core': 3.5.32
      '@vue/shared': 3.5.32
      csstype: 3.2.3
  '@vue/server-renderer@3.5.32(vue@3.5.32(typescript@5.9.3))':
    dependencies:
      '@vue/compiler-ssr': 3.5.32
      '@vue/shared': 3.5.32
      vue: 3.5.32(typescript@5.9.3)
  '@vue/shared@3.5.32': {}
  '@vueuse/core@12.0.0(typescript@5.9.3)':
    dependencies:
      '@types/web-bluetooth': 0.0.20
      '@vueuse/metadata': 12.0.0
      '@vueuse/shared': 12.0.0(typescript@5.9.3)
      vue: 3.5.32(typescript@5.9.3)
    transitivePeerDependencies:
      - typescript
  '@vueuse/metadata@12.0.0': {}
  '@vueuse/shared@12.0.0(typescript@5.9.3)':
    dependencies:
      vue: 3.5.32(typescript@5.9.3)
    transitivePeerDependencies:
      - typescript
  alien-signals@1.0.13: {}
  async-validator@4.2.5: {}
  asynckit@0.4.0: {}
  axios@1.15.0:
    dependencies:
      follow-redirects: 1.16.0
      form-data: 4.0.5
      proxy-from-env: 2.1.0
    transitivePeerDependencies:
      - debug
  balanced-match@1.0.2: {}
  brace-expansion@2.1.0:
    dependencies:
      balanced-match: 1.0.2
  call-bind-apply-helpers@1.0.2:
    dependencies:
      es-errors: 1.3.0
      function-bind: 1.1.2
  combined-stream@1.0.8:
    dependencies:
      delayed-stream: 1.0.0
  csstype@3.2.3: {}
  dayjs@1.11.20: {}
  de-indent@1.0.2: {}
  delayed-stream@1.0.0: {}
  dunder-proto@1.0.1:
    dependencies:
      call-bind-apply-helpers: 1.0.2
      es-errors: 1.3.0
      gopd: 1.2.0
  element-plus@2.13.7(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)):
    dependencies:
      '@ctrl/tinycolor': 4.2.0
      '@element-plus/icons-vue': 2.3.2(vue@3.5.32(typescript@5.9.3))
      '@floating-ui/dom': 1.7.6
      '@popperjs/core': '@sxzz/popperjs-es@2.11.8'
      '@types/lodash': 4.17.24
      '@types/lodash-es': 4.17.12
      '@vueuse/core': 12.0.0(typescript@5.9.3)
      async-validator: 4.2.5
      dayjs: 1.11.20
      lodash: 4.18.1
      lodash-es: 4.18.1
      lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.18.1)(lodash@4.18.1)
      memoize-one: 6.0.0
      normalize-wheel-es: 1.2.0
      vue: 3.5.32(typescript@5.9.3)
      vue-component-type-helpers: 3.2.7
    transitivePeerDependencies:
      - typescript
  entities@7.0.1: {}
  es-define-property@1.0.1: {}
  es-errors@1.3.0: {}
  es-object-atoms@1.1.1:
    dependencies:
      es-errors: 1.3.0
  es-set-tostringtag@2.1.0:
    dependencies:
      es-errors: 1.3.0
      get-intrinsic: 1.3.0
      has-tostringtag: 1.0.2
      hasown: 2.0.3
  esbuild@0.21.5:
    optionalDependencies:
      '@esbuild/aix-ppc64': 0.21.5
      '@esbuild/android-arm': 0.21.5
      '@esbuild/android-arm64': 0.21.5
      '@esbuild/android-x64': 0.21.5
      '@esbuild/darwin-arm64': 0.21.5
      '@esbuild/darwin-x64': 0.21.5
      '@esbuild/freebsd-arm64': 0.21.5
      '@esbuild/freebsd-x64': 0.21.5
      '@esbuild/linux-arm': 0.21.5
      '@esbuild/linux-arm64': 0.21.5
      '@esbuild/linux-ia32': 0.21.5
      '@esbuild/linux-loong64': 0.21.5
      '@esbuild/linux-mips64el': 0.21.5
      '@esbuild/linux-ppc64': 0.21.5
      '@esbuild/linux-riscv64': 0.21.5
      '@esbuild/linux-s390x': 0.21.5
      '@esbuild/linux-x64': 0.21.5
      '@esbuild/netbsd-x64': 0.21.5
      '@esbuild/openbsd-x64': 0.21.5
      '@esbuild/sunos-x64': 0.21.5
      '@esbuild/win32-arm64': 0.21.5
      '@esbuild/win32-ia32': 0.21.5
      '@esbuild/win32-x64': 0.21.5
  estree-walker@2.0.2: {}
  follow-redirects@1.16.0: {}
  form-data@4.0.5:
    dependencies:
      asynckit: 0.4.0
      combined-stream: 1.0.8
      es-set-tostringtag: 2.1.0
      hasown: 2.0.3
      mime-types: 2.1.35
  fsevents@2.3.3:
    optional: true
  function-bind@1.1.2: {}
  get-intrinsic@1.3.0:
    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.3
      math-intrinsics: 1.1.0
  get-proto@1.0.1:
    dependencies:
      dunder-proto: 1.0.1
      es-object-atoms: 1.1.1
  gopd@1.2.0: {}
  has-symbols@1.1.0: {}
  has-tostringtag@1.0.2:
    dependencies:
      has-symbols: 1.1.0
  hasown@2.0.3:
    dependencies:
      function-bind: 1.1.2
  he@1.2.0: {}
  lodash-es@4.18.1: {}
  lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.18.1)(lodash@4.18.1):
    dependencies:
      '@types/lodash-es': 4.17.12
      lodash: 4.18.1
      lodash-es: 4.18.1
  lodash@4.18.1: {}
  magic-string@0.30.21:
    dependencies:
      '@jridgewell/sourcemap-codec': 1.5.5
  math-intrinsics@1.1.0: {}
  memoize-one@6.0.0: {}
  mime-db@1.52.0: {}
  mime-types@2.1.35:
    dependencies:
      mime-db: 1.52.0
  minimatch@9.0.9:
    dependencies:
      brace-expansion: 2.1.0
  muggle-string@0.4.1: {}
  nanoid@3.3.11: {}
  normalize-wheel-es@1.2.0: {}
  path-browserify@1.0.1: {}
  picocolors@1.1.1: {}
  pinia@2.3.1(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)):
    dependencies:
      '@vue/devtools-api': 6.6.4
      vue: 3.5.32(typescript@5.9.3)
      vue-demi: 0.14.10(vue@3.5.32(typescript@5.9.3))
    optionalDependencies:
      typescript: 5.9.3
    transitivePeerDependencies:
      - '@vue/composition-api'
  postcss@8.5.10:
    dependencies:
      nanoid: 3.3.11
      picocolors: 1.1.1
      source-map-js: 1.2.1
  proxy-from-env@2.1.0: {}
  rollup@4.60.2:
    dependencies:
      '@types/estree': 1.0.8
    optionalDependencies:
      '@rollup/rollup-android-arm-eabi': 4.60.2
      '@rollup/rollup-android-arm64': 4.60.2
      '@rollup/rollup-darwin-arm64': 4.60.2
      '@rollup/rollup-darwin-x64': 4.60.2
      '@rollup/rollup-freebsd-arm64': 4.60.2
      '@rollup/rollup-freebsd-x64': 4.60.2
      '@rollup/rollup-linux-arm-gnueabihf': 4.60.2
      '@rollup/rollup-linux-arm-musleabihf': 4.60.2
      '@rollup/rollup-linux-arm64-gnu': 4.60.2
      '@rollup/rollup-linux-arm64-musl': 4.60.2
      '@rollup/rollup-linux-loong64-gnu': 4.60.2
      '@rollup/rollup-linux-loong64-musl': 4.60.2
      '@rollup/rollup-linux-ppc64-gnu': 4.60.2
      '@rollup/rollup-linux-ppc64-musl': 4.60.2
      '@rollup/rollup-linux-riscv64-gnu': 4.60.2
      '@rollup/rollup-linux-riscv64-musl': 4.60.2
      '@rollup/rollup-linux-s390x-gnu': 4.60.2
      '@rollup/rollup-linux-x64-gnu': 4.60.2
      '@rollup/rollup-linux-x64-musl': 4.60.2
      '@rollup/rollup-openbsd-x64': 4.60.2
      '@rollup/rollup-openharmony-arm64': 4.60.2
      '@rollup/rollup-win32-arm64-msvc': 4.60.2
      '@rollup/rollup-win32-ia32-msvc': 4.60.2
      '@rollup/rollup-win32-x64-gnu': 4.60.2
      '@rollup/rollup-win32-x64-msvc': 4.60.2
      fsevents: 2.3.3
  source-map-js@1.2.1: {}
  typescript@5.9.3: {}
  vite@5.4.21:
    dependencies:
      esbuild: 0.21.5
      postcss: 8.5.10
      rollup: 4.60.2
    optionalDependencies:
      fsevents: 2.3.3
  vscode-uri@3.1.0: {}
  vue-component-type-helpers@3.2.7: {}
  vue-demi@0.14.10(vue@3.5.32(typescript@5.9.3)):
    dependencies:
      vue: 3.5.32(typescript@5.9.3)
  vue-router@4.6.4(vue@3.5.32(typescript@5.9.3)):
    dependencies:
      '@vue/devtools-api': 6.6.4
      vue: 3.5.32(typescript@5.9.3)
  vue-tsc@2.2.12(typescript@5.9.3):
    dependencies:
      '@volar/typescript': 2.4.15
      '@vue/language-core': 2.2.12(typescript@5.9.3)
      typescript: 5.9.3
  vue@3.5.32(typescript@5.9.3):
    dependencies:
      '@vue/compiler-dom': 3.5.32
      '@vue/compiler-sfc': 3.5.32
      '@vue/runtime-dom': 3.5.32
      '@vue/server-renderer': 3.5.32(vue@3.5.32(typescript@5.9.3))
      '@vue/shared': 3.5.32
    optionalDependencies:
      typescript: 5.9.3
Code/WMS/WIDESEA_WMSClient_Vben/src/App.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
<template>
  <router-view />
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
onMounted(() => {
  console.log('WMS Vben Admin App mounted');
});
</script>
<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html,
body,
#app {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/api/auth.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
import axios from 'axios';
import type { AxiosInstance, AxiosResponse } from 'axios';
const baseURL = import.meta.env.VITE_APP_API_URL || 'http://localhost:9291';
const http: AxiosInstance = axios.create({
  baseURL,
  timeout: 30000,
});
http.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);
http.interceptors.response.use(
  (response: AxiosResponse) => response.data,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);
export interface LoginRequest {
  username: string;
  password: string;
}
export interface LoginResponse {
  success: boolean;
  message?: string;
  data?: {
    token: string;
  };
}
export const login = (data: LoginRequest): Promise<LoginResponse> => {
  return http.post('/api/Login', data);
};
export default http;
Code/WMS/WIDESEA_WMSClient_Vben/src/api/client.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
/**
 * axios å®¢æˆ·ç«¯å°è£…
 * ç»Ÿä¸€é…ç½®ï¼šbaseURL、timeout、请求/响应拦截器
 */
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9291';
/** åˆ›å»º axios å®žä¾‹ */
const client: AxiosInstance = axios.create({
  baseURL: BASE_URL,
  timeout: 30000,
  headers: { 'Content-Type': 'application/json' },
});
let isRefreshing = false;
let refreshQueue: Array<(token?: string) => void> = [];
/** è¯·æ±‚拦截器:注入 Bearer Token */
client.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    const userStr = localStorage.getItem('user');
    if (userStr) {
      try {
        const userData = JSON.parse(userStr);
        if (userData.token) {
          config.headers.Authorization = `Bearer ${userData.token}`;
        }
      } catch {}
    }
    return config;
  },
  (error) => Promise.reject(error)
);
/** å“åº”拦截器:统一错误处理 + 401 Token è¿‡æœŸè·³è½¬ç™»å½• */
client.interceptors.response.use(
  (response: AxiosResponse) => response.data,
  async (error) => {
    const status = error.response?.status;
    const data = error.response?.data;
    // 401 æœªæŽˆæƒ
    if (status === 401 || data?.code === 401) {
      localStorage.removeItem('user');
      window.location.href = '/#/login';
      return Promise.reject(error);
    }
    return Promise.reject(error);
  }
);
export { client };
export type { AxiosRequestConfig };
Code/WMS/WIDESEA_WMSClient_Vben/src/api/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
export { client } from './client';
export { userApi } from './modules/user';
export { menuApi } from './modules/menu';
export { stockApi } from './modules/stock';
export { inboundApi } from './modules/inbound';
export { outboundApi } from './modules/outbound';
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/inbound.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
import { client } from '../client';
export const inboundApi = {
  getPageList: (params: any) => client.get('/api/InboundOrder/getPageList', { params }),
  getDetail: (id: number) => client.get(`/api/InboundOrderDetail/${id}`),
};
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/menu.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
/**
 * èœå• API æ¨¡å—
 * å¯¹æŽ¥ WMS åŽç«¯ /api/Sys_Menu/getTreeMenu æŽ¥å£
 */
import { client } from '../client';
/** åŽç«¯è¿”回的菜单节点 */
export interface BackendMenuNode {
  id: string | number;
  name?: string;
  text?: string;
  url?: string;
  path?: string;
  icon?: string;
  children?: BackendMenuNode[];
  [key: string]: unknown;
}
export const menuApi = {
  /**
   * èŽ·å–æ ‘å½¢èœå•
   * GET /api/Sys_Menu/getTreeMenu
   */
  getTreeMenu: async (): Promise<BackendMenuNode[]> => {
    const res = await client.get('/api/Sys_Menu/getTreeMenu');
    return res || [];
  },
};
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/outbound.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
import { client } from '../client';
export const outboundApi = {
  getPageList: (params: any) => client.get('/api/OutboundOrder/getPageList', { params }),
  getDetail: (id: number) => client.get(`/api/OutboundOrderDetail/${id}`),
};
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/stock.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
import { client } from '../client';
export const stockApi = {
  getPageList: (params: any) => client.get('/api/StockInfo/getDetailPageList', { params }),
  getDetail: (id: number) => client.get(`/api/StockInfoDetail/${id}`),
};
Code/WMS/WIDESEA_WMSClient_Vben/src/api/modules/user.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
import { client } from '../client';
export const userApi = {
  getCaptcha: () => client.get('/api/User/getVierificationCode'),
  login: (params: any) => client.post('/api/User/login', params),
  getCurrentUser: () => client.post('/api/User/getCurrentUserInfo'),
  replaceToken: () => client.post('/api/User/replaceToken'),
};
Code/WMS/WIDESEA_WMSClient_Vben/src/layouts/MainLayout.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,158 @@
<template>
  <el-container class="main-layout">
    <el-aside :width="collapsed ? '64px' : '200px'">
      <div class="logo" @click="collapsed = !collapsed">
        <span v-if="!collapsed">WMS管理系统</span>
        <span v-else>W</span>
      </div>
      <el-scrollbar>
        <el-menu
          :default-active="activeMenu"
          class="el-menu-vertical"
          :collapse="collapsed"
          :router="true"
          @select="handleMenuSelect"
        >
          <template v-for="item in menuList" :key="item.id">
            <el-sub-menu v-if="item.children?.length" :index="String(item.id)">
              <template #title>
                <span>{{ item.name || item.text }}</span>
              </template>
              <el-menu-item
                v-for="child in item.children"
                :key="child.id"
                :index="child.path || String(child.id)"
              >
                <span>{{ child.name || child.text }}</span>
              </el-menu-item>
            </el-sub-menu>
            <el-menu-item v-else :index="item.path || String(item.id)">
              <span>{{ item.name || item.text }}</span>
            </el-menu-item>
          </template>
        </el-menu>
      </el-scrollbar>
    </el-aside>
    <el-container>
      <el-header>
        <div class="header-left">
          <span class="project-title">WIDESEA WMS</span>
        </div>
        <div class="header-right">
          <span class="username">{{ username }}</span>
          <el-button link @click="handleLogout">退出</el-button>
        </div>
      </el-header>
      <el-main>
        <router-view />
      </el-main>
    </el-container>
  </el-container>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useMenuStore } from '@/store/modules/menu';
import { ElMessage } from 'element-plus';
const route = useRoute();
const router = useRouter();
const menuStore = useMenuStore();
const collapsed = ref(false);
const menuList = ref<any[]>([]);
const username = computed(() => {
  const userStr = localStorage.getItem('user');
  if (userStr) {
    try {
      const user = JSON.parse(userStr);
      return user.userTrueName || user.userName || '未登录';
    } catch {}
  }
  return '未登录';
});
const activeMenu = computed(() => route.path);
function handleMenuSelect(index: string) {
  const menu = menuStore.findMenuByPath(index);
  if (menu?.path) {
    router.push(menu.path);
  }
}
async function loadMenus() {
  try {
    const menus = await menuStore.loadMenus();
    menuList.value = menus || [];
  } catch (error) {
    console.error('加载菜单失败:', error);
    ElMessage.error('加载菜单失败');
  }
}
function handleLogout() {
  localStorage.removeItem('user');
  menuStore.resetMenus();
  router.push('/login');
}
onMounted(() => {
  loadMenus();
});
</script>
<style scoped>
.main-layout {
  height: 100%;
}
.el-aside {
  background-color: #304156;
  color: #fff;
  transition: width 0.3s;
}
.logo {
  height: 60px;
  line-height: 60px;
  text-align: center;
  font-size: 18px;
  color: #fff;
  cursor: pointer;
  background-color: #263445;
}
.el-menu-vertical {
  border-right: none;
  background-color: transparent;
}
.el-menu-vertical:not(.el-menu--collapse) {
  width: 200px;
}
.el-header {
  background-color: #fff;
  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
  line-height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
}
.project-title {
  font-weight: 600;
  font-size: 16px;
  color: #333;
}
.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
}
.username {
  color: #666;
}
.el-main {
  background-color: #f0f2f5;
  padding: 16px;
}
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/locales/zh-CN.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
export default {
  common: {
    ok: '确定',
    cancel: '取消',
    save: '保存',
    delete: '删除',
    edit: '编辑',
    add: '新增',
    search: '搜索',
    reset: '重置',
  },
  login: {
    title: 'WMS管理系统',
    username: '用户名',
    password: '密码',
    loginBtn: '登录',
  },
  menu: {
    dashboard: '首页',
  },
};
Code/WMS/WIDESEA_WMSClient_Vben/src/main.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import App from './App.vue';
import router from './router';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.use(router);
app.use(ElementPlus);
app.mount('#app');
Code/WMS/WIDESEA_WMSClient_Vben/src/router/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
/**
 * è·¯ç”±é…ç½®
 * æ”¯æŒåŠ¨æ€èœå•è·¯ç”±æ³¨å†Œ
 */
import { createRouter, createWebHashHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
import { useMenuStore } from '@/store/modules/menu';
import { transformMenuToRoutes } from '@/utils/menuTransform';
const routes: RouteRecordRaw[] = [
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/login/index.vue'),
    meta: { anonymous: true },
  },
  {
    path: '/',
    name: 'root',
    component: () => import('@/layouts/MainLayout.vue'),
    redirect: '/home',
    children: [
      { path: '/home', name: 'Home', component: () => import('@/views/dashboard/index.vue'), meta: { title: '首页', icon: 'el-icon-home' } },
    ],
  },
  { path: '/:pathMatch(.*)*', redirect: '/home' },
];
const router = createRouter({
  history: createWebHashHistory(),
  routes,
});
/**
 * åŠ¨æ€æ³¨å†Œè·¯ç”±
 */
export async function registerDynamicRoutes() {
  const menuStore = useMenuStore();
  if (!menuStore.loaded) {
    await menuStore.loadMenus();
  }
  const dynamicRoutes = transformMenuToRoutes(menuStore.menus);
  const rootRoute = router.getRoutes().find((r) => r.name === 'root');
  if (!rootRoute) return;
  dynamicRoutes.forEach((route) => {
    const exists = router.getRoutes().some((r) => r.name === route.name);
    if (!exists && route.name) {
      router.addRoute('root', route);
    }
  });
  return dynamicRoutes;
}
router.beforeEach(async (to, from, next) => {
  if (to.meta?.anonymous) {
    return next();
  }
  const userStr = localStorage.getItem('user');
  if (!userStr) {
    return next('/login');
  }
  const menuStore = useMenuStore();
  if (!menuStore.loaded) {
    try {
      await registerDynamicRoutes();
    } catch (error) {
      console.error('注册动态路由失败:', error);
    }
  }
  next();
});
export { router };
export default router;
Code/WMS/WIDESEA_WMSClient_Vben/src/store/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
/**
 * Store ç»Ÿä¸€å¯¼å‡º
 */
export { useMenuStore } from './modules/menu';
export { useUserStore } from './user';
Code/WMS/WIDESEA_WMSClient_Vben/src/store/modules/menu.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
/**
 * èœå•状态管理
 */
import { defineStore } from 'pinia';
import { menuApi, type BackendMenuNode } from '@/api/modules/menu';
import { normalizeMenus, addHomeMenu } from '@/utils/menuTransform';
interface MenuState {
  menus: BackendMenuNode[];
  loaded: boolean;
}
export const useMenuStore = defineStore('menu', {
  state: (): MenuState => ({
    menus: [],
    loaded: false,
  }),
  getters: {
    flatMenus: (state) => {
      const flat: BackendMenuNode[] = [];
      const flatten = (items: BackendMenuNode[]) => {
        items.forEach((item) => {
          flat.push(item);
          if (item.children?.length) {
            flatten(item.children);
          }
        });
      };
      flatten(state.menus);
      return flat;
    },
  },
  actions: {
    async loadMenus() {
      try {
        const data = await menuApi.getTreeMenu();
        this.menus = addHomeMenu(data || []);
        this.loaded = true;
        return this.menus;
      } catch (error) {
        console.error('加载菜单失败:', error);
        throw error;
      }
    },
    findMenuByPath(path: string): BackendMenuNode | null {
      return this.flatMenus.find((m) => m.path === path) || null;
    },
    resetMenus() {
      this.menus = [];
      this.loaded = false;
    },
  },
});
Code/WMS/WIDESEA_WMSClient_Vben/src/store/user.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
interface UserInfo {
  token: string;
  userName: string;
  userTrueName: string;
  img: string;
}
export const useUserStore = defineStore('user', () => {
  const userInfo = ref<UserInfo | null>(null);
  const token = ref<string>('');
  const isLogin = computed(() => !!token.value);
  function init() {
    const stored = localStorage.getItem('user');
    if (stored) {
      try {
        const info = JSON.parse(stored) as UserInfo;
        userInfo.value = info;
        token.value = info?.token || '';
      } catch {
        token.value = '';
      }
    }
  }
  function setUserInfo(info: UserInfo) {
    userInfo.value = info;
    token.value = info?.token || '';
    localStorage.setItem('user', JSON.stringify(info));
  }
  function clearUserInfo() {
    userInfo.value = null;
    token.value = '';
    localStorage.removeItem('user');
  }
  init();
  return { userInfo, token, isLogin, setUserInfo, clearUserInfo };
});
Code/WMS/WIDESEA_WMSClient_Vben/src/utils/menuTransform.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
/**
 * èœå•数据转换工具
 * å°†åŽç«¯èœå•格式转换为 Vben Admin èœå•格式
 */
import type { RouteRecordRaw } from 'vue-router';
import type { BackendMenuNode } from '@/api/modules/menu';
/** Element Plus å›¾æ ‡åç§°æ˜ å°„ */
const iconMap: Record<string, string> = {
  'el-icon-menu': 'Menu',
  'el-icon-user': 'User',
  'el-icon-setting': 'Setting',
  'el-icon-home': 'HomeFilled',
  'el-icon-document': 'Document',
  'el-icon-edit': 'Edit',
  'el-icon-view': 'View',
  'el-icon-delete': 'Delete',
  'el-icon-search': 'Search',
  'el-icon-refresh': 'Refresh',
  'el-icon-download': 'Download',
  'el-icon-upload': 'Upload',
  'el-icon-goods': 'Goods',
  'el-icon-box': 'Box',
  'el-icon-truck': 'Van',
  'el-icon-shop': 'Shop',
  'el-icon-list': 'List',
  'el-icon-grid': 'Grid',
  'el-icon-s-custom': 'UserFilled',
  'el-icon-s-order': 'List',
  'el-icon-s-grid': 'Grid',
  'el-icon-s-home': 'HomeFilled',
  'el-icon-s-data': 'DataLine',
  'el-icon-s-check': 'CircleCheck',
  'el-icon-s-management': 'Management',
};
/**
 * è½¬æ¢å›¾æ ‡åç§°
 * el-icon-menu -> Menu
 */
export function transformIcon(icon?: string): string {
  if (!icon) return 'Menu';
  return iconMap[icon] || 'Menu';
}
/**
 * æ ‡å‡†åŒ–菜单路径
 * "/Manager/home" -> "/home"
 */
export function normalizePath(url?: string): string {
  if (!url) return '/';
  let path = url.replace('/Manager', '') || '/';
  if (!path.startsWith('/')) {
    path = '/' + path;
  }
  return path;
}
/**
 * æ£€æŸ¥æ˜¯å¦ä¸ºå¤–部链接
 */
function isExternalUrl(url?: string): boolean {
  if (!url) return false;
  return url.startsWith('http://') || url.startsWith('https://');
}
/**
 * å°†åŽç«¯èœå•节点转换为 Vben èœå•项
 */
export function transformMenuItem(menu: BackendMenuNode): RouteRecordRaw | null {
  const name = menu.name || menu.text || '未命名';
  const url = menu.url || menu.path || '';
  const path = normalizePath(url);
  // è·³è¿‡å¤–部链接
  if (isExternalUrl(url)) {
    return null;
  }
  const route: RouteRecordRaw = {
    path,
    name: path.replace(/\//g, '_').replace(/^_/, '') || 'root',
    meta: {
      title: name,
      icon: menu.icon || 'el-icon-menu',
    },
  };
  // é€’归处理子菜单
  if (menu.children?.length) {
    const children = menu.children
      .map((child) => transformMenuItem(child))
      .filter((r): r is RouteRecordRaw => r !== null);
    if (children.length > 0) {
      route.children = children;
    }
  }
  return route;
}
/**
 * å°†åŽç«¯èœå•数组转换为路由数组
 */
export function transformMenuToRoutes(menus: BackendMenuNode[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = [];
  menus.forEach((menu) => {
    const route = transformMenuItem(menu);
    if (route) {
      routes.push(route);
    }
  });
  return routes;
}
/**
 * å°†åŽç«¯èœå•数组标准化
 */
export function normalizeMenus(menus: BackendMenuNode[]): BackendMenuNode[] {
  return menus.map((menu) => ({
    ...menu,
    path: normalizePath(menu.url || menu.path),
    icon: menu.icon || 'el-icon-menu',
    children: menu.children ? normalizeMenus(menu.children) : undefined,
  }));
}
/**
 * ä¸ºèœå•列表添加首页项
 */
export function addHomeMenu(menus: BackendMenuNode[]): BackendMenuNode[] {
  const normalized = normalizeMenus(menus);
  normalized.push({
    id: 'home',
    name: '首页',
    text: '首页',
    path: '/home',
    icon: 'el-icon-home',
  });
  return normalized;
}
Code/WMS/WIDESEA_WMSClient_Vben/src/views/dashboard/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
<template>
  <div class="dashboard">
    <h1>欢迎使用WMS管理系统</h1>
    <el-row :gutter="20">
      <el-col :span="6">
        <el-card>
          <template #header>总库存</template>
          <div class="stat-value">10,000</div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <template #header>今日入库</template>
          <div class="stat-value">150</div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <template #header>今日出库</template>
          <div class="stat-value">120</div>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <template #header>待处理任务</template>
          <div class="stat-value">25</div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.dashboard h1 {
  margin-bottom: 20px;
  color: #333;
}
.stat-value {
  font-size: 28px;
  font-weight: bold;
  text-align: center;
  color: #409eff;
}
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/inbound/inboundOrderDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
<template>
  <div class="inbound-detail-page">
    <el-card shadow="never">
      <template #header>
        <span>入库单明细 - {{ route.query.inboundOrderNo || '' }}</span>
      </template>
      <el-form :inline="true" :model="queryForm" class="search-form">
        <el-form-item label="物料编号">
          <el-input v-model="queryForm.materielCode" placeholder="请输入物料编号" clearable />
        </el-form-item>
        <el-form-item label="物料名称">
          <el-input v-model="queryForm.materielName" placeholder="请输入物料名称" clearable />
        </el-form-item>
        <el-form-item label="批次号">
          <el-input v-model="queryForm.batchNo" placeholder="请输入批次号" clearable />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
      <el-table v-loading="loading" :data="tableData" border stripe>
        <el-table-column prop="materielCode" label="物料编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="materielName" label="物料名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="batchNo" label="批次号" min-width="120" align="center" />
        <el-table-column prop="orderQuantity" label="单据数量" min-width="100" align="center" />
        <el-table-column prop="receiptQuantity" label="组盘数量" min-width="120" align="center" />
        <el-table-column prop="overInQuantity" label="上架数量" min-width="120" align="center" />
        <el-table-column prop="orderDetailStatus" label="明细状态" min-width="110" align="center">
          <template #default="{ row }">
            {{ getDetailStatusText(row.orderDetailStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import { client } from '@/api/client';
const route = useRoute();
const loading = ref(false);
const tableData = ref([]);
const detailStatusOptions = ref([]);
const queryForm = reactive({ materielCode: '', materielName: '', batchNo: '' });
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
async function loadData() {
  loading.value = true;
  try {
    const orderId = route.query.id;
    const wheres = [{ name: 'orderId', value: String(orderId), displayType: 'int' }];
    if (queryForm.materielCode) wheres.push({ name: 'materielCode', value: queryForm.materielCode, displayType: 'like' });
    if (queryForm.materielName) wheres.push({ name: 'materielName', value: queryForm.materielName, displayType: 'like' });
    if (queryForm.batchNo) wheres.push({ name: 'batchNo', value: queryForm.batchNo, displayType: 'like' });
    const res = await client.post('/api/InboundOrderDetail/getPageList', {
      page: pagination.page, rows: pagination.pageSize, sort: 'id', order: 'asc',
      wheres: JSON.stringify(wheres),
    });
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch { ElMessage.error('加载数据失败'); }
  finally { loading.value = false; }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['orderDetailStatusEnum']);
    detailStatusOptions.value = res?.find(item => item.dicNo === 'orderDetailStatusEnum')?.data || [];
  } catch { detailStatusOptions.value = []; }
}
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() { queryForm.materielCode = ''; queryForm.materielName = ''; queryForm.batchNo = ''; handleSearch(); }
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getDetailStatusText = (val) => detailStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.inbound-detail-page { padding: 16px; }
.search-form { margin-bottom: 12px; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/inbound/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,275 @@
<template>
  <div class="inbound-page">
    <!-- æœç´¢ -->
    <el-card class="search-card" shadow="never">
      <el-form :inline="true" :model="queryForm" label-width="90px">
        <el-form-item label="单据编号">
          <el-input v-model="queryForm.inboundOrderNo" placeholder="请输入单据编号" clearable style="width: 170px" />
        </el-form-item>
        <el-form-item label="上游单据">
          <el-input v-model="queryForm.upperOrderNo" placeholder="请输入上游单据编号" clearable style="width: 170px" />
        </el-form-item>
        <el-form-item label="单据类型">
          <el-select v-model="queryForm.orderType" placeholder="请选择" clearable style="width: 150px">
            <el-option v-for="item in orderTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="单据状态">
          <el-select v-model="queryForm.orderStatus" placeholder="请选择" clearable style="width: 140px">
            <el-option v-for="item in orderStatusOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="创建时间">
          <el-date-picker v-model="queryForm.createDate" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" value-format="YYYY-MM-DD" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- è¡¨æ ¼ -->
    <el-card class="table-card" shadow="never">
      <div class="toolbar">
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">批量删除</el-button>
      </div>
      <el-table v-loading="loading" :data="tableData" border stripe @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="50" align="center" />
        <el-table-column prop="inboundOrderNo" label="单据编号" min-width="140" show-overflow-tooltip />
        <el-table-column prop="upperOrderNo" label="上游单据编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="warehouseId" label="仓库" min-width="100" align="center">
          <template #default="{ row }">
            {{ getWarehouseText(row.warehouseId) }}
          </template>
        </el-table-column>
        <el-table-column prop="orderType" label="单据类型" min-width="140" align="center">
          <template #default="{ row }">
            {{ getOrderTypeText(row.orderType) }}
          </template>
        </el-table-column>
        <el-table-column prop="orderStatus" label="单据状态" min-width="100" align="center">
          <template #default="{ row }">
            {{ getOrderStatusText(row.orderStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="createType" label="创建方式" min-width="110" align="center">
          <template #default="{ row }">
            {{ getCreateTypeText(row.createType) }}
          </template>
        </el-table-column>
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
        <el-table-column label="操作" width="180" align="center" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" size="small" @click="goDetail(row)">明细</el-button>
            <el-button link type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
    <!-- æ˜Žç»†æŠ½å±‰ -->
    <el-drawer v-model="detailDrawerVisible" title="入库单明细" size="70%" direction="rtl" destroy-on-close>
      <el-table :data="detailTableData" border stripe max-height="600">
        <el-table-column prop="materielCode" label="物料编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="materielName" label="物料名称" min-width="150" show-overflow-tooltip />
        <el-table-column prop="batchNo" label="批次号" min-width="120" align="center" />
        <el-table-column prop="orderQuantity" label="单据数量" min-width="100" align="center" />
        <el-table-column prop="receiptQuantity" label="组盘数量" min-width="120" align="center" />
        <el-table-column prop="overInQuantity" label="上架数量" min-width="120" align="center" />
        <el-table-column prop="orderDetailStatus" label="明细状态" min-width="110" align="center">
          <template #default="{ row }">
            {{ getDetailStatusText(row.orderDetailStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
      </el-table>
    </el-drawer>
    <!-- ç¼–辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" destroy-on-close>
      <el-form :model="editForm" :rules="editRules" ref="editFormRef" label-width="100px">
        <el-form-item label="单据类型" prop="orderType">
          <el-select v-model="editForm.orderType" placeholder="请选择单据类型" style="width: 100%">
            <el-option v-for="item in orderTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="单据编号" prop="inboundOrderNo">
          <el-input v-model="editForm.inboundOrderNo" placeholder="请输入单据编号" />
        </el-form-item>
        <el-form-item label="上游单据">
          <el-input v-model="editForm.upperOrderNo" placeholder="请输入上游单据编号" />
        </el-form-item>
        <el-form-item label="仓库" prop="warehouseId">
          <el-select v-model="editForm.warehouseId" placeholder="请选择仓库" style="width: 100%">
            <el-option v-for="item in warehouseOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="editForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { inboundApi } from '@/api/modules/inbound';
import { client } from '@/api/client';
const router = useRouter();
// æœç´¢
const queryForm = reactive({ inboundOrderNo: '', upperOrderNo: '', orderType: undefined, orderStatus: undefined, createDate: '' });
// è¡¨æ ¼
const loading = ref(false);
const tableData = ref([]);
const selectedRows = ref([]);
// å­—å…¸
const orderTypeOptions = ref([]);
const orderStatusOptions = ref([]);
const warehouseOptions = ref([]);
const createTypeOptions = ref([]);
const detailStatusOptions = ref([]);
// åˆ†é¡µ
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
// æ˜Žç»†æŠ½å±‰
const detailDrawerVisible = ref(false);
const detailTableData = ref([]);
const currentRow = ref(null);
// ç¼–辑弹窗
const dialogVisible = ref(false);
const dialogTitle = ref('新增入库单');
const editFormRef = ref(null);
const submitLoading = ref(false);
const editForm = reactive({ id: undefined, orderType: undefined, inboundOrderNo: '', upperOrderNo: '', warehouseId: undefined, remark: '' });
const editRules = {
  orderType: [{ required: true, message: '请选择单据类型', trigger: 'change' }],
  inboundOrderNo: [{ required: true, message: '请输入单据编号', trigger: 'blur' }],
  warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
};
async function loadData() {
  loading.value = true;
  try {
    const wheres = [
      queryForm.inboundOrderNo ? { name: 'inboundOrderNo', value: queryForm.inboundOrderNo, displayType: 'like' } : null,
      queryForm.upperOrderNo ? { name: 'upperOrderNo', value: queryForm.upperOrderNo, displayType: 'like' } : null,
      queryForm.orderType !== undefined ? { name: 'orderType', value: queryForm.orderType, displayType: 'int' } : null,
      queryForm.orderStatus !== undefined ? { name: 'orderStatus', value: queryForm.orderStatus, displayType: 'int' } : null,
    ].filter(Boolean);
    const res = await inboundApi.getPageList({ page: pagination.page, rows: pagination.pageSize, sort: 'id', order: 'desc', wheres: JSON.stringify(wheres) });
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch { ElMessage.error('加载数据失败'); }
  finally { loading.value = false; }
}
async function loadDetail(row) {
  try {
    const res = await client.post('/api/InboundOrderDetail/getPageList', {
      page: 1, rows: 200, sort: 'id', order: 'asc',
      wheres: JSON.stringify([{ name: 'orderId', value: row.id, displayType: 'int' }]),
    });
    detailTableData.value = res?.rows || [];
  } catch { detailTableData.value = []; ElMessage.error('加载明细失败'); }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['inOrderType', 'inboundState', 'warehouses', 'createType', 'orderDetailStatusEnum']);
    const findData = (dicNo) => res?.find(item => item.dicNo === dicNo)?.data || [];
    orderTypeOptions.value = findData('inOrderType');
    orderStatusOptions.value = findData('inboundState');
    warehouseOptions.value = findData('warehouses');
    createTypeOptions.value = findData('createType');
    detailStatusOptions.value = findData('orderDetailStatusEnum');
  } catch {
    orderTypeOptions.value = []; orderStatusOptions.value = []; warehouseOptions.value = [];
  }
}
function goDetail(row) { router.push({ path: '/inbound/inboundOrderDetail', query: { id: row.id, inboundOrderNo: row.inboundOrderNo } }); }
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() { queryForm.inboundOrderNo = ''; queryForm.upperOrderNo = ''; queryForm.orderType = undefined; queryForm.orderStatus = undefined; queryForm.createDate = ''; handleSearch(); }
function handleAdd() {
  editForm.id = undefined; editForm.orderType = undefined; editForm.inboundOrderNo = ''; editForm.upperOrderNo = ''; editForm.warehouseId = undefined; editForm.remark = '';
  dialogTitle.value = '新增入库单'; dialogVisible.value = true;
}
function handleEdit(row) {
  Object.assign(editForm, { id: row.id, orderType: row.orderType, inboundOrderNo: row.inboundOrderNo, upperOrderNo: row.upperOrderNo, warehouseId: row.warehouseId, remark: row.remark });
  dialogTitle.value = '编辑入库单'; dialogVisible.value = true;
}
async function handleSubmit() {
  await editFormRef.value.validate();
  submitLoading.value = true;
  try {
    if (editForm.id) { await inboundApi.update(editForm); ElMessage.success('更新成功'); }
    else { await inboundApi.add(editForm); ElMessage.success('新增成功'); }
    dialogVisible.value = false; loadData();
  } catch { ElMessage.error('操作失败'); }
  finally { submitLoading.value = false; }
}
function handleDelete(row) {
  ElMessageBox.confirm(`确定删除入库单「${row.inboundOrderNo}」吗?`, '提示', { type: 'warning' })
    .then(async () => { await inboundApi.deleteById(row.id); ElMessage.success('删除成功'); loadData(); }).catch(() => {});
}
function handleBatchDelete() {
  const ids = selectedRows.value.map(r => r.id);
  ElMessageBox.confirm(`确定删除选中的 ${ids.length} æ¡è®°å½•吗?`, '提示', { type: 'warning' })
    .then(async () => { await Promise.all(ids.map(id => inboundApi.deleteById(id))); ElMessage.success('删除成功'); loadData(); }).catch(() => {});
}
function handleSelectionChange(rows) { selectedRows.value = rows; }
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getWarehouseText = (val) => warehouseOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getOrderTypeText = (val) => orderTypeOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getOrderStatusText = (val) => orderStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getCreateTypeText = (val) => createTypeOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getDetailStatusText = (val) => detailStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.inbound-page { padding: 16px; }
.search-card { margin-bottom: 12px; }
.table-card { margin-bottom: 12px; }
.toolbar { margin-bottom: 12px; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/login/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,196 @@
<template>
  <div class="login-container">
    <div class="login-box">
      <div class="login-header">
        <h2>WIDESEA WMS</h2>
        <p>仓库管理系统</p>
      </div>
      <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form">
        <el-form-item prop="username">
          <el-input
            v-model="loginForm.username"
            placeholder="请输入账号"
            size="large"
            prefix-icon="User"
          />
        </el-form-item>
        <el-form-item prop="password">
          <el-input
            v-model="loginForm.password"
            type="password"
            placeholder="请输入密码"
            size="large"
            prefix-icon="Lock"
            show-password
          />
        </el-form-item>
        <el-form-item prop="verificationCode">
          <el-input
            v-model="loginForm.verificationCode"
            placeholder="请输入验证码"
            size="large"
            prefix-icon="CircleCheck"
            style="width: 60%"
            @keyup.enter="handleLogin"
          />
          <div class="captcha-box" @click="loadCaptcha">
            <img v-if="captchaImg" :src="captchaImg" alt="验证码" />
            <span v-else class="captcha-placeholder">点击刷新</span>
          </div>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" size="large" style="width: 100%" :loading="loading" @click="handleLogin">
            {{ loading ? '登录中...' : '登 å½•' }}
          </el-button>
        </el-form-item>
      </el-form>
      <div class="login-footer">
        <span>演示账号:admin666 &nbsp;&nbsp; å¯†ç ï¼š123456</span>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { User, Lock, CircleCheck } from '@element-plus/icons-vue';
import { userApi } from '@/api/modules/user';
import { useUserStore } from '@/store';
const router = useRouter();
const userStore = useUserStore();
const loginFormRef = ref();
const loading = ref(false);
const captchaImg = ref('');
const uuid = ref('');
const loginForm = reactive({
  username: 'admin',
  password: '123456',
  verificationCode: '',
});
const loginRules = {
  username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
  verificationCode: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
};
async function loadCaptcha() {
  try {
    const res = await userApi.getCaptcha();
    if (res?.img) {
      captchaImg.value = `data:image/png;base64,${res.img}`;
      uuid.value = res.uuid;
    }
  } catch {
    ElMessage.error('获取验证码失败');
  }
}
async function handleLogin() {
  if (!loginFormRef.value) return;
  await loginFormRef.value.validate(async (valid) => {
    if (!valid) return;
    loading.value = true;
    try {
      const res = await userApi.login({
        userName: loginForm.username,
        password: loginForm.password,
        verificationCode: loginForm.verificationCode,
        UUID: uuid.value,
      });
      if (res?.status === false) {
        ElMessage.error(res.message || '登录失败');
        loadCaptcha();
        return;
      }
      const userData = res.data || res;
      userStore.setUserInfo({
        token: userData.token || userData.access_token || '',
        userName: userData.userName || loginForm.username,
        userTrueName: userData.userTrueName || userData.name || '',
        img: userData.img || '',
      });
      ElMessage.success('登录成功');
      router.push('/');
    } catch {
      ElMessage.error('登录异常');
      loadCaptcha();
    } finally {
      loading.value = false;
    }
  });
}
onMounted(() => {
  loadCaptcha();
});
</script>
<style scoped>
.login-container {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-box {
  width: 420px;
  padding: 40px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.login-header {
  text-align: center;
  margin-bottom: 30px;
}
.login-header h2 {
  margin: 0 0 8px;
  font-size: 28px;
  color: #333;
  font-weight: 600;
}
.login-header p {
  margin: 0;
  font-size: 14px;
  color: #999;
}
.login-form {
  margin-top: 20px;
}
.captcha-box {
  width: 38%;
  height: 40px;
  margin-left: 10px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  background: #f5f7fa;
}
.captcha-box img {
  width: 100%;
  height: 100%;
  object-fit: fill;
}
.captcha-placeholder {
  font-size: 12px;
  color: #999;
}
.login-footer {
  margin-top: 20px;
  text-align: center;
  font-size: 12px;
  color: #999;
}
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/outbound/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,267 @@
<template>
  <div class="outbound-page">
    <!-- æœç´¢ -->
    <el-card class="search-card" shadow="never">
      <el-form :inline="true" :model="queryForm" label-width="90px">
        <el-form-item label="单据编号">
          <el-input v-model="queryForm.orderNo" placeholder="请输入单据编号" clearable style="width: 170px" />
        </el-form-item>
        <el-form-item label="上游单据">
          <el-input v-model="queryForm.upperOrderNo" placeholder="请输入上游单据编号" clearable style="width: 170px" />
        </el-form-item>
        <el-form-item label="单据类型">
          <el-select v-model="queryForm.orderType" placeholder="请选择" clearable style="width: 150px">
            <el-option v-for="item in orderTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="单据状态">
          <el-select v-model="queryForm.orderStatus" placeholder="请选择" clearable style="width: 140px">
            <el-option v-for="item in orderStatusOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="创建时间">
          <el-date-picker v-model="queryForm.createDate" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" value-format="YYYY-MM-DD" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- è¡¨æ ¼ -->
    <el-card class="table-card" shadow="never">
      <div class="toolbar">
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">批量删除</el-button>
      </div>
      <el-table v-loading="loading" :data="tableData" border stripe @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="50" align="center" />
        <el-table-column prop="orderNo" label="单据编号" min-width="160" show-overflow-tooltip />
        <el-table-column prop="upperOrderNo" label="上游单据编号" min-width="160" show-overflow-tooltip />
        <el-table-column prop="warehouseId" label="仓库" min-width="100" align="center">
          <template #default="{ row }">
            {{ getWarehouseText(row.warehouseId) }}
          </template>
        </el-table-column>
        <el-table-column prop="orderType" label="单据类型" min-width="150" align="center">
          <template #default="{ row }">
            {{ getOrderTypeText(row.orderType) }}
          </template>
        </el-table-column>
        <el-table-column prop="orderStatus" label="单据状态" min-width="100" align="center">
          <template #default="{ row }">
            {{ getOrderStatusText(row.orderStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="createType" label="创建方式" min-width="110" align="center">
          <template #default="{ row }">
            {{ getCreateTypeText(row.createType) }}
          </template>
        </el-table-column>
        <el-table-column prop="departmentName" label="部门名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
        <el-table-column label="操作" width="180" align="center" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" size="small" @click="goDetail(row)">明细</el-button>
            <el-button link type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
    <!-- æ˜Žç»†æŠ½å±‰ -->
    <el-drawer v-model="detailDrawerVisible" title="出库单明细" size="70%" direction="rtl" destroy-on-close>
      <el-table :data="detailTableData" border stripe max-height="600">
        <el-table-column prop="materielCode" label="物料编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="materielName" label="物料名称" min-width="150" show-overflow-tooltip />
        <el-table-column prop="batchNo" label="批次号" min-width="120" align="center" />
        <el-table-column prop="orderQuantity" label="单据数量" min-width="100" align="center" />
        <el-table-column prop="rowNo" label="行号" min-width="80" align="center" />
        <el-table-column prop="lockQuantity" label="锁定数量" min-width="120" align="center" />
        <el-table-column prop="overOutQuantity" label="已出数量" min-width="120" align="center" />
        <el-table-column prop="orderDetailStatus" label="明细状态" min-width="110" align="center">
          <template #default="{ row }">
            {{ getDetailStatusText(row.orderDetailStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
      </el-table>
    </el-drawer>
    <!-- ç¼–辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" destroy-on-close>
      <el-form :model="editForm" :rules="editRules" ref="editFormRef" label-width="100px">
        <el-form-item label="单据类型" prop="orderType">
          <el-select v-model="editForm.orderType" placeholder="请选择单据类型" style="width: 100%">
            <el-option v-for="item in orderTypeOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="单据编号" prop="orderNo">
          <el-input v-model="editForm.orderNo" placeholder="请输入单据编号" readonly />
        </el-form-item>
        <el-form-item label="上游单据">
          <el-input v-model="editForm.upperOrderNo" placeholder="请输入上游单据编号" />
        </el-form-item>
        <el-form-item label="仓库" prop="warehouseId">
          <el-select v-model="editForm.warehouseId" placeholder="请选择仓库" style="width: 100%">
            <el-option v-for="item in warehouseOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="editForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { outboundApi } from '@/api/modules/outbound';
import { client } from '@/api/client';
const router = useRouter();
const queryForm = reactive({ orderNo: '', upperOrderNo: '', orderType: undefined, orderStatus: undefined, createDate: '' });
const loading = ref(false);
const tableData = ref([]);
const selectedRows = ref([]);
const orderTypeOptions = ref([]);
const orderStatusOptions = ref([]);
const warehouseOptions = ref([]);
const createTypeOptions = ref([]);
const detailStatusOptions = ref([]);
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
const detailDrawerVisible = ref(false);
const detailTableData = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref('新增出库单');
const editFormRef = ref(null);
const submitLoading = ref(false);
const editForm = reactive({ id: undefined, orderType: undefined, orderNo: '', upperOrderNo: '', warehouseId: undefined, remark: '' });
const editRules = {
  orderType: [{ required: true, message: '请选择单据类型', trigger: 'change' }],
  orderNo: [{ required: true, message: '请输入单据编号', trigger: 'blur' }],
  warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
};
async function loadData() {
  loading.value = true;
  try {
    const wheres = [
      queryForm.orderNo ? { name: 'orderNo', value: queryForm.orderNo, displayType: 'like' } : null,
      queryForm.upperOrderNo ? { name: 'upperOrderNo', value: queryForm.upperOrderNo, displayType: 'like' } : null,
      queryForm.orderType !== undefined ? { name: 'orderType', value: queryForm.orderType, displayType: 'int' } : null,
      queryForm.orderStatus !== undefined ? { name: 'orderStatus', value: queryForm.orderStatus, displayType: 'int' } : null,
    ].filter(Boolean);
    const res = await outboundApi.getPageList({ page: pagination.page, rows: pagination.pageSize, sort: 'id', order: 'desc', wheres: JSON.stringify(wheres) });
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch { ElMessage.error('加载数据失败'); }
  finally { loading.value = false; }
}
async function loadDetail(row) {
  try {
    const res = await client.post('/api/OutboundOrderDetail/getPageList', {
      page: 1, rows: 200, sort: 'id', order: 'asc',
      wheres: JSON.stringify([{ name: 'orderId', value: row.id, displayType: 'int' }]),
    });
    detailTableData.value = res?.rows || [];
  } catch { detailTableData.value = []; ElMessage.error('加载明细失败'); }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['outOrderType', 'outboundStatusEnum', 'warehouses', 'createType', 'orderDetailStatusEnum']);
    const findData = (dicNo) => res?.find(item => item.dicNo === dicNo)?.data || [];
    orderTypeOptions.value = findData('outOrderType');
    orderStatusOptions.value = findData('outboundStatusEnum');
    warehouseOptions.value = findData('warehouses');
    createTypeOptions.value = findData('createType');
    detailStatusOptions.value = findData('orderDetailStatusEnum');
  } catch { orderTypeOptions.value = []; orderStatusOptions.value = []; warehouseOptions.value = []; }
}
function goDetail(row) { router.push({ path: '/outbound/outboundOrderDetail', query: { id: row.id, orderNo: row.orderNo } }); }
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() { queryForm.orderNo = ''; queryForm.upperOrderNo = ''; queryForm.orderType = undefined; queryForm.orderStatus = undefined; queryForm.createDate = ''; handleSearch(); }
function handleAdd() {
  editForm.id = undefined; editForm.orderType = undefined; editForm.orderNo = ''; editForm.upperOrderNo = ''; editForm.warehouseId = undefined; editForm.remark = '';
  dialogTitle.value = '新增出库单'; dialogVisible.value = true;
}
function handleEdit(row) {
  Object.assign(editForm, { id: row.id, orderType: row.orderType, orderNo: row.orderNo, upperOrderNo: row.upperOrderNo, warehouseId: row.warehouseId, remark: row.remark });
  dialogTitle.value = '编辑出库单'; dialogVisible.value = true;
}
async function handleSubmit() {
  await editFormRef.value.validate();
  submitLoading.value = true;
  try {
    if (editForm.id) { await outboundApi.update(editForm); ElMessage.success('更新成功'); }
    else { await outboundApi.add(editForm); ElMessage.success('新增成功'); }
    dialogVisible.value = false; loadData();
  } catch { ElMessage.error('操作失败'); }
  finally { submitLoading.value = false; }
}
function handleDelete(row) {
  ElMessageBox.confirm(`确定删除出库单「${row.orderNo}」吗?`, '提示', { type: 'warning' })
    .then(async () => { await outboundApi.deleteById(row.id); ElMessage.success('删除成功'); loadData(); }).catch(() => {});
}
function handleBatchDelete() {
  const ids = selectedRows.value.map(r => r.id);
  ElMessageBox.confirm(`确定删除选中的 ${ids.length} æ¡è®°å½•吗?`, '提示', { type: 'warning' })
    .then(async () => { await Promise.all(ids.map(id => outboundApi.deleteById(id))); ElMessage.success('删除成功'); loadData(); }).catch(() => {});
}
function handleSelectionChange(rows) { selectedRows.value = rows; }
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getWarehouseText = (val) => warehouseOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getOrderTypeText = (val) => orderTypeOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getOrderStatusText = (val) => orderStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getCreateTypeText = (val) => createTypeOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getDetailStatusText = (val) => detailStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.outbound-page { padding: 16px; }
.search-card { margin-bottom: 12px; }
.table-card { margin-bottom: 12px; }
.toolbar { margin-bottom: 12px; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/outbound/outboundOrderDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
<template>
  <div class="outbound-detail-page">
    <el-card shadow="never">
      <template #header>
        <span>出库单明细 - {{ route.query.orderNo || '' }}</span>
      </template>
      <el-form :inline="true" :model="queryForm" class="search-form">
        <el-form-item label="物料编号">
          <el-input v-model="queryForm.materielCode" placeholder="请输入物料编号" clearable />
        </el-form-item>
        <el-form-item label="物料名称">
          <el-input v-model="queryForm.materielName" placeholder="请输入物料名称" clearable />
        </el-form-item>
        <el-form-item label="批次号">
          <el-input v-model="queryForm.batchNo" placeholder="请输入批次号" clearable />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
      <el-table v-loading="loading" :data="tableData" border stripe>
        <el-table-column prop="materielCode" label="物料编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="materielName" label="物料名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="batchNo" label="批次号" min-width="120" align="center" />
        <el-table-column prop="orderQuantity" label="单据数量" min-width="100" align="center" />
        <el-table-column prop="rowNo" label="行号" min-width="80" align="center" />
        <el-table-column prop="lockQuantity" label="锁定数量" min-width="120" align="center" />
        <el-table-column prop="overOutQuantity" label="已出数量" min-width="120" align="center" />
        <el-table-column prop="orderDetailStatus" label="明细状态" min-width="110" align="center">
          <template #default="{ row }">
            {{ getDetailStatusText(row.orderDetailStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="creater" label="创建人" min-width="90" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import { client } from '@/api/client';
const route = useRoute();
const loading = ref(false);
const tableData = ref([]);
const detailStatusOptions = ref([]);
const queryForm = reactive({ materielCode: '', materielName: '', batchNo: '' });
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
async function loadData() {
  loading.value = true;
  try {
    const orderId = route.query.id;
    const wheres = [{ name: 'orderId', value: String(orderId), displayType: 'int' }];
    if (queryForm.materielCode) wheres.push({ name: 'materielCode', value: queryForm.materielCode, displayType: 'like' });
    if (queryForm.materielName) wheres.push({ name: 'materielName', value: queryForm.materielName, displayType: 'like' });
    if (queryForm.batchNo) wheres.push({ name: 'batchNo', value: queryForm.batchNo, displayType: 'like' });
    const res = await client.post('/api/OutboundOrderDetail/getPageList', {
      page: pagination.page, rows: pagination.pageSize, sort: 'id', order: 'asc',
      wheres: JSON.stringify(wheres),
    });
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch { ElMessage.error('加载数据失败'); }
  finally { loading.value = false; }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['orderDetailStatusEnum']);
    detailStatusOptions.value = res?.find(item => item.dicNo === 'orderDetailStatusEnum')?.data || [];
  } catch { detailStatusOptions.value = []; }
}
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() { queryForm.materielCode = ''; queryForm.materielName = ''; queryForm.batchNo = ''; handleSearch(); }
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getDetailStatusText = (val) => detailStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.outbound-detail-page { padding: 16px; }
.search-form { margin-bottom: 12px; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/stock/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,340 @@
<template>
  <div class="stock-page">
    <!-- æœç´¢åŒºåŸŸ -->
    <el-card class="search-card" shadow="never">
      <el-form :inline="true" :model="queryForm" label-width="80px">
        <el-form-item label="托盘编号">
          <el-input v-model="queryForm.palletCode" placeholder="请输入托盘编号" clearable style="width: 180px" />
        </el-form-item>
        <el-form-item label="货位编号">
          <el-input v-model="queryForm.locationCode" placeholder="请输入货位编号" clearable style="width: 180px" />
        </el-form-item>
        <el-form-item label="仓库">
          <el-select v-model="queryForm.warehouseId" placeholder="请选择仓库" clearable style="width: 160px">
            <el-option v-for="item in warehouseOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="库存状态">
          <el-select v-model="queryForm.stockStatus" placeholder="请选择状态" clearable style="width: 140px">
            <el-option v-for="item in stockStatusOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <el-card class="table-card" shadow="never">
      <div class="toolbar">
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">批量删除</el-button>
      </div>
      <el-table
        v-loading="loading"
        :data="tableData"
        border
        stripe
        @selection-change="handleSelectionChange"
        @expand-change="handleExpandChange"
        :expand-row-keys="expandedRows"
        row-key="id"
      >
        <el-table-column type="selection" width="50" align="center" />
        <el-table-column type="expand" width="50">
          <template #default="{ row }">
            <div class="expand-panel">
              <div class="expand-header">
                <span class="expand-title">库存明细</span>
                <span class="expand-subtitle">托盘:{{ row.palletCode }} / è´§ä½ï¼š{{ row.locationCode }}</span>
              </div>
              <el-table :data="detailData[row.id] || []" border stripe size="small" max-height="400">
                <el-table-column prop="materielName" label="物料名称" min-width="160" show-overflow-tooltip />
                <el-table-column prop="serialNumber" label="电芯码" min-width="160" show-overflow-tooltip />
                <el-table-column prop="stockQuantity" label="库存数量" min-width="120" align="center" />
                <el-table-column prop="status" label="状态" min-width="120" align="center">
                  <template #default="{ row: dr }">
                    {{ getStatusText(dr.status) }}
                  </template>
                </el-table-column>
                <el-table-column prop="inboundOrderRowNo" label="通道号" min-width="120" align="center" />
              </el-table>
              <div v-if="!detailData[row.id] && !detailLoading[row.id]" class="expand-empty">暂无明细数据</div>
              <div v-if="detailLoading[row.id]" class="expand-loading">加载中...</div>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="palletCode" label="托盘编号" min-width="130" show-overflow-tooltip />
        <el-table-column prop="locationCode" label="货位编号" min-width="150" show-overflow-tooltip />
        <el-table-column prop="warehouseId" label="仓库" min-width="110" align="center">
          <template #default="{ row }">
            {{ getWarehouseText(row.warehouseId) }}
          </template>
        </el-table-column>
        <el-table-column prop="stockStatus" label="库存状态" min-width="120" align="center">
          <template #default="{ row }">
            {{ getStockStatusText(row.stockStatus) }}
          </template>
        </el-table-column>
        <el-table-column prop="outboundDate" label="出库日期" min-width="160" align="center" />
        <el-table-column prop="creater" label="创建人" min-width="100" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
        <el-table-column label="操作" width="150" align="center" fixed="right">
          <template #default="{ row }">
            <el-button link type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
    <!-- ç¼–辑弹窗 -->
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" destroy-on-close>
      <el-form :model="editForm" :rules="editRules" ref="editFormRef" label-width="100px">
        <el-form-item label="托盘编号" prop="palletCode">
          <el-input v-model="editForm.palletCode" placeholder="请输入托盘编号" />
        </el-form-item>
        <el-form-item label="货位编号" prop="locationCode">
          <el-input v-model="editForm.locationCode" placeholder="请输入货位编号" />
        </el-form-item>
        <el-form-item label="仓库" prop="warehouseId">
          <el-select v-model="editForm.warehouseId" placeholder="请选择仓库" style="width: 100%">
            <el-option v-for="item in warehouseOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="库存状态" prop="stockStatus">
          <el-select v-model="editForm.stockStatus" placeholder="请选择库存状态" style="width: 100%">
            <el-option v-for="item in stockStatusOptions" :key="item.key" :label="item.value" :value="item.key" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="editForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { stockApi } from '@/api/modules/stock';
import { client } from '@/api/client';
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9291';
// æœç´¢
const queryForm = reactive({
  palletCode: '',
  locationCode: '',
  warehouseId: undefined,
  stockStatus: undefined,
});
// è¡¨æ ¼
const loading = ref(false);
const tableData = ref([]);
const selectedRows = ref([]);
const expandedRows = ref([]);
const detailData = ref({});
const detailLoading = ref({});
// å­—å…¸
const warehouseOptions = ref([]);
const stockStatusOptions = ref([]);
// åˆ†é¡µ
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
// ç¼–辑弹窗
const dialogVisible = ref(false);
const dialogTitle = ref('新增库存');
const editFormRef = ref(null);
const submitLoading = ref(false);
const editForm = reactive({
  id: undefined,
  palletCode: '',
  locationCode: '',
  warehouseId: undefined,
  stockStatus: undefined,
  remark: '',
});
const editRules = {
  palletCode: [{ required: true, message: '请输入托盘编号', trigger: 'blur' }],
  locationCode: [{ required: true, message: '请输入货位编号', trigger: 'blur' }],
  warehouseId: [{ required: true, message: '请选择仓库', trigger: 'change' }],
};
async function loadData() {
  loading.value = true;
  try {
    const params = buildQueryParams();
    const res = await stockApi.getPageList(params);
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch {
    ElMessage.error('加载数据失败');
  } finally {
    loading.value = false;
  }
}
function buildQueryParams() {
  const wheres = [
    queryForm.palletCode ? { name: 'palletCode', value: queryForm.palletCode, displayType: 'like' } : null,
    queryForm.locationCode ? { name: 'locationCode', value: queryForm.locationCode, displayType: 'like' } : null,
    queryForm.warehouseId ? { name: 'warehouseId', value: queryForm.warehouseId, displayType: 'int' } : null,
    queryForm.stockStatus !== undefined ? { name: 'stockStatus', value: queryForm.stockStatus, displayType: 'int' } : null,
  ].filter(Boolean);
  return {
    page: pagination.page,
    rows: pagination.pageSize,
    sort: 'id',
    order: 'desc',
    wheres: JSON.stringify(wheres),
  };
}
async function loadDetailData(row) {
  if (detailData.value[row.id] || detailLoading.value[row.id]) return;
  detailLoading.value[row.id] = true;
  try {
    const res = await client.post('/api/StockInfoDetail/getPageData', {
      page: 1, rows: 200, sort: 'id', order: 'asc',
      wheres: JSON.stringify([{ name: 'stockId', value: String(row.id), displayType: 'int' }]),
    });
    detailData.value[row.id] = res?.rows || [];
  } catch {
    detailData.value[row.id] = [];
    ElMessage.error('加载明细失败');
  } finally {
    detailLoading.value[row.id] = false;
  }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['warehouseEnum', 'stockStatusEmun']);
    const wh = res?.find(item => item.dicNo === 'warehouseEnum');
    warehouseOptions.value = wh?.data || [];
    const ss = res?.find(item => item.dicNo === 'stockStatusEmun');
    stockStatusOptions.value = ss?.data || [];
  } catch {
    warehouseOptions.value = [];
    stockStatusOptions.value = [];
  }
}
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() {
  queryForm.palletCode = '';
  queryForm.locationCode = '';
  queryForm.warehouseId = undefined;
  queryForm.stockStatus = undefined;
  handleSearch();
}
function handleAdd() {
  editForm.id = undefined;
  editForm.palletCode = '';
  editForm.locationCode = '';
  editForm.warehouseId = undefined;
  editForm.stockStatus = undefined;
  editForm.remark = '';
  dialogTitle.value = '新增库存';
  dialogVisible.value = true;
}
function handleEdit(row) {
  Object.assign(editForm, { id: row.id, palletCode: row.palletCode, locationCode: row.locationCode, warehouseId: row.warehouseId, stockStatus: row.stockStatus, remark: row.remark });
  dialogTitle.value = '编辑库存';
  dialogVisible.value = true;
}
async function handleSubmit() {
  await editFormRef.value.validate();
  submitLoading.value = true;
  try {
    if (editForm.id) {
      await stockApi.updateStock(editForm);
      ElMessage.success('更新成功');
    } else {
      await stockApi.addStock(editForm);
      ElMessage.success('新增成功');
    }
    dialogVisible.value = false;
    loadData();
  } catch { ElMessage.error('操作失败'); }
  finally { submitLoading.value = false; }
}
function handleDelete(row) {
  ElMessageBox.confirm(`确定删除库存「${row.palletCode}」吗?`, '提示', { type: 'warning' })
    .then(async () => {
      await stockApi.deleteStock(row.id);
      ElMessage.success('删除成功');
      loadData();
    }).catch(() => {});
}
function handleBatchDelete() {
  const ids = selectedRows.value.map(r => r.id);
  ElMessageBox.confirm(`确定删除选中的 ${ids.length} æ¡è®°å½•吗?`, '提示', { type: 'warning' })
    .then(async () => {
      await Promise.all(ids.map(id => stockApi.deleteStock(id)));
      ElMessage.success('删除成功');
      loadData();
    }).catch(() => {});
}
function handleSelectionChange(rows) { selectedRows.value = rows; }
function handleExpandChange(row, expanded) {
  if (expanded) {
    expandedRows.value.push(row.id);
    loadDetailData(row);
  } else {
    expandedRows.value = expandedRows.value.filter(id => id !== row.id);
  }
}
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getWarehouseText = (val) => warehouseOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getStockStatusText = (val) => stockStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
const getStatusText = (val) => stockStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.stock-page { padding: 16px; }
.search-card { margin-bottom: 12px; }
.table-card { margin-bottom: 12px; }
.toolbar { margin-bottom: 12px; }
.expand-panel { margin: 8px 16px 16px; padding: 12px; background: #fafafa; border-radius: 8px; }
.expand-header { margin-bottom: 12px; }
.expand-title { font-size: 15px; font-weight: 700; color: #303133; margin-right: 12px; }
.expand-subtitle { font-size: 13px; color: #606266; }
.expand-empty, .expand-loading { padding: 14px 12px; color: #909399; text-align: center; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/src/views/stock/stockInfoDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,119 @@
<template>
  <div class="stock-detail-page">
    <el-card shadow="never">
      <template #header>
        <span>库存明细 - {{ route.query.palletCode || '' }}</span>
      </template>
      <!-- æœç´¢ -->
      <el-form :inline="true" :model="queryForm" class="search-form">
        <el-form-item label="物料名称">
          <el-input v-model="queryForm.materielName" placeholder="请输入物料名称" clearable />
        </el-form-item>
        <el-form-item label="电芯码">
          <el-input v-model="queryForm.serialNumber" placeholder="请输入电芯码" clearable />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
          <el-button @click="handleReset">重置</el-button>
        </el-form-item>
      </el-form>
      <!-- è¡¨æ ¼ -->
      <el-table v-loading="loading" :data="tableData" border stripe>
        <el-table-column prop="materielCode" label="物料编码" min-width="140" show-overflow-tooltip />
        <el-table-column prop="materielName" label="物料名称" min-width="160" show-overflow-tooltip />
        <el-table-column prop="serialNumber" label="电芯码" min-width="180" show-overflow-tooltip />
        <el-table-column prop="stockQuantity" label="库存数量" min-width="120" align="center" />
        <el-table-column prop="status" label="状态" min-width="120" align="center">
          <template #default="{ row }">
            {{ getStatusText(row.status) }}
          </template>
        </el-table-column>
        <el-table-column prop="inboundOrderRowNo" label="通道号" min-width="120" align="center" />
        <el-table-column prop="creater" label="创建人" min-width="100" align="center" />
        <el-table-column prop="createDate" label="创建时间" min-width="160" align="center" />
      </el-table>
      <el-pagination
        v-model:current-page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[10, 20, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        style="margin-top: 16px; justify-content: flex-end"
      />
    </el-card>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import { client } from '@/api/client';
const route = useRoute();
const loading = ref(false);
const tableData = ref([]);
const stockStatusOptions = ref([]);
const queryForm = reactive({
  materielName: '',
  serialNumber: '',
});
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
async function loadData() {
  loading.value = true;
  try {
    const stockId = route.query.id;
    const wheres = [{ name: 'stockId', value: String(stockId), displayType: 'int' }];
    if (queryForm.materielName) wheres.push({ name: 'materielName', value: queryForm.materielName, displayType: 'like' });
    if (queryForm.serialNumber) wheres.push({ name: 'serialNumber', value: queryForm.serialNumber, displayType: 'like' });
    const res = await client.post('/api/StockInfoDetail/getPageData', {
      page: pagination.page,
      rows: pagination.pageSize,
      sort: 'id',
      order: 'asc',
      wheres: JSON.stringify(wheres),
    });
    tableData.value = res?.rows || [];
    pagination.total = res?.total || 0;
  } catch {
    ElMessage.error('加载数据失败');
  } finally {
    loading.value = false;
  }
}
async function loadDictionary() {
  try {
    const res = await client.post('/api/Sys_Dictionary/GetVueDictionary', ['stockStatusEmun']);
    const ss = res?.find(item => item.dicNo === 'stockStatusEmun');
    stockStatusOptions.value = ss?.data || [];
  } catch {
    stockStatusOptions.value = [];
  }
}
function handleSearch() { pagination.page = 1; loadData(); }
function handleReset() {
  queryForm.materielName = '';
  queryForm.serialNumber = '';
  handleSearch();
}
function handleSizeChange() { loadData(); }
function handlePageChange() { loadData(); }
const getStatusText = (val) => stockStatusOptions.value.find(o => `${o.key}` === `${val}`)?.value || val || '-';
onMounted(() => { loadDictionary(); loadData(); });
</script>
<style scoped>
.stock-detail-page { padding: 16px; }
.search-form { margin-bottom: 12px; }
</style>
Code/WMS/WIDESEA_WMSClient_Vben/tsconfig.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
Code/WMS/WIDESEA_WMSClient_Vben/tsconfig.node.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true,
    "strict": true
  },
  "include": ["vite.config.ts"]
}
Code/WMS/WIDESEA_WMSClient_Vben/vite.config.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:9291',
        changeOrigin: true,
      },
    },
  },
});
Code/WMS/WIDESEA_WMSClient_Vben_v2
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
Subproject commit 07c4ad05f40507d7d797619814bf75a47c29a9f4
Code/WMS/WMS_Api_Design.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,203 @@
# WMS å‰ç«¯ API è®¾è®¡æ–‡æ¡£
> æœ¬æ–‡æ¡£ä¸º Vben Admin å‰ç«¯é¡¹ç›®ï¼ˆWIDESEA_WMSClient_Vben)提供 API é€‚配层设计参考。
## ç›®å½•结构
```
WIDESEA_WMSClient_Vben/
├── src/
│   â”œâ”€â”€ api/
│   â”‚   â”œâ”€â”€ client.ts          # axios å®žä¾‹å°è£…
│   â”‚   â”œâ”€â”€ modules/
│   â”‚   â”‚   â”œâ”€â”€ user.ts        # ç”¨æˆ·è®¤è¯æ¨¡å—
│   â”‚   â”‚   â”œâ”€â”€ menu.ts        # èœå•模块
│   â”‚   â”‚   â”œâ”€â”€ stock.ts       # åº“存模块
│   â”‚   â”‚   â”œâ”€â”€ inbound.ts      # å…¥åº“模块
│   â”‚   â”‚   â”œâ”€â”€ outbound.ts    # å‡ºåº“模块
│   â”‚   â”‚   â””── check.ts        # ç›˜ç‚¹æ¨¡å—
│   â”‚   â””── index.ts           # ç»Ÿä¸€å¯¼å‡º
```
## 1. axios å®¢æˆ·ç«¯å°è£… (`api/client.ts`)
```typescript
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { useUserStore } from '@/store/modules/user';
import { useAuthStore } from '@/store/modules/auth';
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9291';
const client: AxiosInstance = axios.create({
  baseURL: BASE_URL,
  timeout: 30000,
  headers: { 'Content-Type': 'application/json' },
});
// è¯·æ±‚拦截器:注入 Bearer Token
client.interceptors.request.use(
  (config) => {
    const userStore = useUserStore();
    const token = userStore.token;
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);
// å“åº”拦截器:统一错误处理 + 401 token è¿‡æœŸè·³è½¬ç™»å½•
client.interceptors.response.use(
  (response: AxiosResponse) => response.data,
  async (error) => {
    const status = error.response?.status;
    const raw = error.response?.data;
    // ä¸šåŠ¡é”™è¯¯ç ï¼ˆéž HTTP çŠ¶æ€ç ï¼‰å¯ä»Ž raw.code åˆ¤æ–­
    if (raw?.code === 401 || status === 401) {
      const authStore = useAuthStore();
      authStore.logout(true); // true = token è¿‡æœŸè¢«åŠ¨ç™»å‡º
    }
    return Promise.reject(error);
  }
);
export default client;
```
## 2. è¯·æ±‚拦截器逻辑
| åœºæ™¯ | å¤„理方式 |
|------|---------|
| æœ‰ Token | `Authorization: Bearer <token>` æ³¨å…¥è¯·æ±‚头 |
| æ—  Token | æ”¾è¡Œï¼Œè®©åŽç«¯è¿”回 401 |
| ä¸»åŠ¨ç™»å‡º | æ¸…空 token è·³è½¬ç™»å½•页 |
## 3. å“åº”拦截器逻辑
| åœºæ™¯ | å¤„理方式 |
|------|---------|
| 2xx å“åº” | è¿”回 `response.data` |
| HTTP 401 / ä¸šåŠ¡ code 401 | è°ƒç”¨ `authStore.logout(true)` è·³è½¬ç™»å½• |
| å…¶ä»–错误 | æŠ›å‡ºå¼‚常,由各模块自行处理 |
## 4. æŽ¥å£ç­¾å
### 4.1 ç”¨æˆ·æ¨¡å— (`modules/user.ts`)
```typescript
/** èŽ·å–éªŒè¯ç ï¼Œè¿”å›ž { img: string, uuid: string } */
export function getVerificationCode(): Promise<{ img: string; uuid: string }>;
/** ç™»å½• */
export function login(params: {
  userName: string;
  password: string;
  verificationCode: string;
  UUID: string;
}): Promise<{ token: string; expires: number }>;
/** å½“前用户信息 */
export function getCurrentUserInfo(): Promise<UserInfo>;
/** åˆ·æ–° Token */
export function replaceToken(): Promise<{ token: string; expires: number }>;
```
### 4.2 èœå•模块 (`modules/menu.ts`)
```typescript
/** èŽ·å–æ ‘å½¢èœå• */
export function getTreeMenu(): Promise<MenuTreeNode[]>;
interface MenuTreeNode {
  id: string;
  name: string;
  path: string;
  component?: string;
  icon?: string;
  children?: MenuTreeNode[];
}
```
### 4.3 åº“存模块 (`modules/stock.ts`)
```typescript
/** åº“存列表(分页) */
export function getStockList(params: StockQuery): Promise<PageResult<StockItem>>;
/** åº“存详情 */
export function getStockDetail(id: string): Promise<StockItem>;
```
### 4.4 å…¥åº“模块 (`modules/inbound.ts`)
```typescript
/** å…¥åº“单列表 */
export function getInboundOrderList(params: InboundQuery): Promise<PageResult<InboundOrder>>;
/** åˆ›å»ºå…¥åº“单 */
export function createInboundOrder(data: CreateInboundOrder): Promise<{ id: string }>;
/** æäº¤å…¥åº“单 */
export function submitInboundOrder(id: string): Promise<void>;
```
### 4.5 å‡ºåº“模块 (`modules/outbound.ts`)
```typescript
/** å‡ºåº“单列表 */
export function getOutboundOrderList(params: OutboundQuery): Promise<PageResult<OutboundOrder>>;
/** åˆ›å»ºå‡ºåº“单 */
export function createOutboundOrder(data: CreateOutboundOrder): Promise<{ id: string }>;
/** æäº¤å‡ºåº“单 */
export function submitOutboundOrder(id: string): Promise<void>;
```
### 4.6 ç›˜ç‚¹æ¨¡å— (`modules/check.ts`)
```typescript
/** ç›˜ç‚¹å•列表 */
export function getCheckOrderList(params: CheckQuery): Promise<PageResult<CheckOrder>>;
/** åˆ›å»ºç›˜ç‚¹å• */
export function createCheckOrder(data: CreateCheckOrder): Promise<{ id: string }>;
/** æäº¤ç›˜ç‚¹å• */
export function submitCheckOrder(id: string): Promise<void>;
```
## 5. é€šç”¨ç±»åž‹å®šä¹‰
```typescript
/** åˆ†é¡µç»“æžœ */
interface PageResult<T> {
  items: T[];
  total: number;
  page: number;
  pageSize: number;
}
/** é€šç”¨æ“ä½œç»“果(无数据返回时) */
interface OpResult {
  code: number;
  message: string;
}
```
## 6. çŽ¯å¢ƒå˜é‡
```env
# .env.development
VITE_API_BASE_URL=http://localhost:9291
# .env.production
VITE_API_BASE_URL=/api
```
> **注意**: ç”Ÿäº§çŽ¯å¢ƒä½¿ç”¨ `/api` ä»£ç†ï¼Œé¿å…è·¨åŸŸã€‚