已添加12个文件
已重命名1个文件
已删除1个文件
已修改53个文件
2290 ■■■■ 文件已修改
Code/.omc/state/last-tool-error.json 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/mission-state.json 698 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/subagent-tracking.json 423 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/index.html 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/public/webconfig.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Client/src/api/http.js 6 ●●●● 补丁 | 查看 | 原始文档 | 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_Common/Constants/StackerCraneConst.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskTypeEnum.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | 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/Properties/PublishProfiles/FolderProfile.pubxml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/RobotStateRepository.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotStateService.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Query.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotMessageRouter.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotNgLineCommandHandler.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | 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 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotStateManager.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotNgLineCommandHandler.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/SocketClientGateway.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneCommandBuilder.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/api/http.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/gridBodyExtension.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient/src/views/stock/stockInfo.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSClient_Vben_v2 @ 07c4ad 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/Database/Scripts/20260420_Dt_StockInfo_MesUploadStatus.sql 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/MesService.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/MesUploadStatusEnum.cs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_StockInfo.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Manual.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Outbound.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json 4 ●●●● 补丁 | 查看 | 原始文档 | 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",
  "tool_name": "Read",
  "tool_input_preview": "{\"file_path\":\"D:\\\\Git\\\\ShanMeiXinNengYuan\\\\Code\\\\WMS\\\\WIDESEA_WMSClient_Vben_v2\\\\apps\\\\web-ele\\\\src\\\\views\\\\dashboard\\\\index.vue\"}",
  "error": "File does not exist. Note: your current working directory is D:\\Git\\ShanMeiXinNengYuan\\Code.",
  "timestamp": "2026-04-20T01:28:36.836Z",
  "retry_count": 1
}
Code/.omc/state/mission-state.json
@@ -1,5 +1,5 @@
{
  "updatedAt": "2026-04-18T08:52:24.581Z",
  "updatedAt": "2026-04-20T02:13:36.765Z",
  "missions": [
    {
      "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none",
@@ -1268,6 +1268,702 @@
          "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"
        }
      ]
    },
    {
      "id": "session:ab8c4305-0c84-43a9-bd5d-b68d5471801b:none",
      "source": "session",
      "name": "none",
      "objective": "Session mission",
      "createdAt": "2026-04-20T01:18:33.678Z",
      "updatedAt": "2026-04-20T02:13:36.765Z",
      "status": "done",
      "workerCount": 8,
      "taskCounts": {
        "total": 8,
        "pending": 0,
        "blocked": 0,
        "inProgress": 0,
        "completed": 8,
        "failed": 0
      },
      "agents": [
        {
          "name": "general-purpose:af20345",
          "role": "general-purpose",
          "ownership": "af20345f5b7efdbb8",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T02:13:36.765Z"
        },
        {
          "name": "general-purpose:a9cc35c",
          "role": "general-purpose",
          "ownership": "a9cc35c00ad32b233",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T01:21:33.668Z"
        },
        {
          "name": "general-purpose:a3499a6",
          "role": "general-purpose",
          "ownership": "a3499a67931cba616",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T01:21:25.687Z"
        },
        {
          "name": "general-purpose:addde47",
          "role": "general-purpose",
          "ownership": "addde47ba39361d9d",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T01:34:11.276Z"
        },
        {
          "name": "general-purpose:a883f88",
          "role": "general-purpose",
          "ownership": "a883f88b2839bb064",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T02:09:43.301Z"
        },
        {
          "name": "general-purpose:a1cccc1",
          "role": "general-purpose",
          "ownership": "a1cccc11f34b62da4",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T02:09:46.017Z"
        },
        {
          "name": "general-purpose:a85bc7a",
          "role": "general-purpose",
          "ownership": "a85bc7aac2726a6fa",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T02:10:09.142Z"
        },
        {
          "name": "general-purpose:a921902",
          "role": "general-purpose",
          "ownership": "a9219020fa6ba0ef0",
          "status": "done",
          "currentStep": null,
          "latestUpdate": "completed",
          "completedSummary": null,
          "updatedAt": "2026-04-20T02:08:23.745Z"
        }
      ],
      "timeline": [
        {
          "id": "session-start:a1cccc11f34b62da4:2026-04-20T02:07:02.639Z",
          "at": "2026-04-20T02:07:02.639Z",
          "kind": "update",
          "agent": "general-purpose:a1cccc1",
          "detail": "started general-purpose:a1cccc1",
          "sourceKey": "session-start:a1cccc11f34b62da4"
        },
        {
          "id": "session-start:a85bc7aac2726a6fa:2026-04-20T02:07:02.655Z",
          "at": "2026-04-20T02:07:02.655Z",
          "kind": "update",
          "agent": "general-purpose:a85bc7a",
          "detail": "started general-purpose:a85bc7a",
          "sourceKey": "session-start:a85bc7aac2726a6fa"
        },
        {
          "id": "session-start:a9219020fa6ba0ef0:2026-04-20T02:07:02.700Z",
          "at": "2026-04-20T02:07:02.700Z",
          "kind": "update",
          "agent": "general-purpose:a921902",
          "detail": "started general-purpose:a921902",
          "sourceKey": "session-start:a9219020fa6ba0ef0"
        },
        {
          "id": "session-stop:a9219020fa6ba0ef0:2026-04-20T02:08:23.745Z",
          "at": "2026-04-20T02:08:23.745Z",
          "kind": "completion",
          "agent": "general-purpose:a921902",
          "detail": "completed",
          "sourceKey": "session-stop:a9219020fa6ba0ef0"
        },
        {
          "id": "session-stop:a883f88b2839bb064:2026-04-20T02:09:43.301Z",
          "at": "2026-04-20T02:09:43.301Z",
          "kind": "completion",
          "agent": "general-purpose:a883f88",
          "detail": "completed",
          "sourceKey": "session-stop:a883f88b2839bb064"
        },
        {
          "id": "session-stop:a1cccc11f34b62da4:2026-04-20T02:09:46.017Z",
          "at": "2026-04-20T02:09:46.017Z",
          "kind": "completion",
          "agent": "general-purpose:a1cccc1",
          "detail": "completed",
          "sourceKey": "session-stop:a1cccc11f34b62da4"
        },
        {
          "id": "session-stop:a85bc7aac2726a6fa:2026-04-20T02:10:09.142Z",
          "at": "2026-04-20T02:10:09.142Z",
          "kind": "completion",
          "agent": "general-purpose:a85bc7a",
          "detail": "completed",
          "sourceKey": "session-stop:a85bc7aac2726a6fa"
        },
        {
          "id": "session-stop:a6eae12446c31bdfe:2026-04-20T02:13:36.765Z",
          "at": "2026-04-20T02:13:36.765Z",
          "kind": "completion",
          "agent": "general-purpose:af20345",
          "detail": "completed",
          "sourceKey": "session-stop:a6eae12446c31bdfe"
        }
      ]
    }
  ]
}
Code/.omc/state/subagent-tracking.json
@@ -767,10 +767,427 @@
      "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
    },
    {
      "agent_id": "af20345f5b7efdbb8",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T01:18:33.678Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T01:20:19.477Z",
      "duration_ms": 105799
    },
    {
      "agent_id": "a9cc35c00ad32b233",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T01:18:33.716Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T01:21:33.665Z",
      "duration_ms": 179949
    },
    {
      "agent_id": "a3499a67931cba616",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T01:18:33.755Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T01:21:25.686Z",
      "duration_ms": 171931
    },
    {
      "agent_id": "addde47ba39361d9d",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T01:27:42.165Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T01:34:11.275Z",
      "duration_ms": 389110
    },
    {
      "agent_id": "a883f88b2839bb064",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T02:07:02.615Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T02:09:43.299Z",
      "duration_ms": 160684
    },
    {
      "agent_id": "a1cccc11f34b62da4",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T02:07:02.639Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T02:09:46.016Z",
      "duration_ms": 163377
    },
    {
      "agent_id": "a85bc7aac2726a6fa",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T02:07:02.655Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T02:10:09.140Z",
      "duration_ms": 186485
    },
    {
      "agent_id": "a9219020fa6ba0ef0",
      "agent_type": "general-purpose",
      "started_at": "2026-04-20T02:07:02.700Z",
      "parent_mode": "none",
      "status": "completed",
      "completed_at": "2026-04-20T02:08:23.744Z",
      "duration_ms": 81044
    }
  ],
  "total_spawned": 83,
  "total_completed": 83,
  "total_spawned": 118,
  "total_completed": 127,
  "total_failed": 0,
  "last_updated": "2026-04-18T14:41:25.052Z"
  "last_updated": "2026-04-20T02:13:36.867Z"
}
Code/WCS/WIDESEAWCS_Client/index.html
@@ -16,6 +16,7 @@
    <strong>We're sorry but WCS doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <script src="/webconfig.js"></script>
  <script type="module" src="/src/main.js"></script>
</body>
Code/WCS/WIDESEAWCS_Client/public/webconfig.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
window.webConfig = {
    "webApiBaseUrl": "http://localhost:9292/",
    "webApiProduction":"http://192.168.60.30:9292/"
}
Code/WCS/WIDESEAWCS_Client/src/api/http.js
@@ -12,14 +12,14 @@
let loadingInstance;
let loadingStatus = false;
if (process.env.NODE_ENV == 'development') {
    axios.defaults.baseURL = 'http://127.0.0.1:9292/';
    axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
}
else if (process.env.NODE_ENV == 'debug') {
    axios.defaults.baseURL = 'http://127.0.0.1:9292/';
    axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
}
else if (process.env.NODE_ENV == 'production') {
    axios.defaults.baseURL = 'http://192.168.60.30:9292/';
    axios.defaults.baseURL = window.webConfig.webApiProduction;
}
if (!axios.defaults.baseURL.endsWith('/')) {
    axios.defaults.baseURL+="/";
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: [{ key: 1, value: "手动模式" },{ key: 2, value: "自动模式" }] }, align: "center" },
      { field: "robotControlMode", title: "控制模式", type: "int", width: 100, bind: { key: "robotControlMode", data: [{ key: 1, value: "客户端控制" },{ key: 2, value: "其他" }] }, align: "center" },
      { field: "robotArmObject", title: "手臂状态", type: "int", width: 90, bind: { key: "robotArmObject", data: [{ key: 0, value: "空闲"}, { key: 1, value: "有物料" }] }, 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_Common/Constants/StackerCraneConst.cs
@@ -15,6 +15,15 @@
        public const int EmptyPalletTaskType = 100;
        /// <summary>
        /// ç©ºæ‰˜ç›˜ä»»åŠ¡ç±»åž‹
        /// </summary>
        /// <remarks>
        /// å½“任务类型为空托盘出库/入库时,使用此特殊类型值代替原任务类型。
        /// ç”¨äºŽä¸Žç«™å°è·¯ç”±é…ç½®åŒ¹é…ã€‚
        /// </remarks>
        public const int EmptyInPalletTaskType = 200;
        /// <summary>
        /// ç«è­¦çŠ¶æ€æ­£å¸¸
        /// </summary>
        /// <remarks>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs
@@ -32,7 +32,7 @@
                return TaskTypeGroup.OutbondGroup;
            }
            // å°è¯•将任务类型转换为TaskInStatusEnum枚举类型,如果成功,返回InboundGroup
            else if (!int.TryParse(Enum.Parse<TaskInStatusEnum>(taskTypeStr).ToString(), out result))
            else if (!int.TryParse(Enum.Parse<TaskInboundTypeEnum>(taskTypeStr).ToString(), out result))
            {
                return TaskTypeGroup.InboundGroup;
            }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskTypeEnum.cs
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace WIDESEAWCS_Common.TaskEnum
{
@@ -14,16 +9,19 @@
        /// </summary>
        [Description("入库")]
        Inbound = 200,
        /// <summary>
        /// ç›˜ç‚¹å…¥åº“
        /// </summary>
        [Description("盘点入库")]
        InInventory = 201,
        /// <summary>
        /// åˆ†æ‹£å…¥åº“
        /// </summary>
        [Description("分拣入库")]
        InPick = 202,
        /// <summary>
        /// è´¨æ£€å…¥åº“
        /// </summary>
@@ -34,7 +32,7 @@
        /// ç©ºç®±å…¥åº“
        /// </summary>
        [Description("空箱入库")]
        InEmpty = 600,
        InEmpty = 204,
    }
    public enum TaskOutboundTypeEnum
@@ -44,16 +42,19 @@
        /// </summary>
        [Description("出库")]
        Outbound = 100,
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“
        /// </summary>
        [Description("盘点出库")]
        OutInventory = 101,
        /// <summary>
        /// åˆ†æ‹£å‡ºåº“
        /// </summary>
        [Description("分拣出库")]
        OutPick = 102,
        /// <summary>
        /// è´¨æ£€å‡ºåº“
        /// </summary>
@@ -74,6 +75,7 @@
        /// </summary>
        [Description("库内移库")]
        Relocation = 300,
        /// <summary>
        /// åº“外移库
        /// </summary>
@@ -118,16 +120,19 @@
        /// </summary>
        [Description("领料出库")]
        Outbound = 100,
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“
        /// </summary>
        [Description("盘点出库")]
        OutInventory = 110,
        /// <summary>
        /// åˆ†æ‹£å‡ºåº“
        /// </summary>
        [Description("分拣出库")]
        OutPick = 120,
        /// <summary>
        /// è´¨æ£€å‡ºåº“
        /// </summary>
@@ -163,16 +168,19 @@
        /// </summary>
        [Description("采购入库")]
        Inbound = 510,
        /// <summary>
        /// ç›˜ç‚¹å…¥åº“
        /// </summary>
        [Description("盘点入库")]
        InInventory = 520,
        /// <summary>
        /// åˆ†æ‹£å…¥åº“
        /// </summary>
        [Description("分拣入库")]
        InPick = 530,
        /// <summary>
        /// è´¨æ£€å…¥åº“
        /// </summary>
@@ -202,6 +210,5 @@
        /// </summary>
        [Description("巷道内移库")]
        Relocation = 900
    }
}
}
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/Properties/PublishProfiles/FolderProfile.pubxml
@@ -4,13 +4,13 @@
-->
<Project>
  <PropertyGroup>
    <DeleteExistingFiles>true</DeleteExistingFiles>
    <DeleteExistingFiles>false</DeleteExistingFiles>
    <ExcludeApp_Data>false</ExcludeApp_Data>
    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
    <LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <PublishProvider>FileSystem</PublishProvider>
    <PublishUrl>bin\Debug\net6.0\publish\</PublishUrl>
    <PublishUrl>E:\IISText\HuanAn\WCS</PublishUrl>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <_TargetId>Folder</_TargetId>
    <SiteUrlToLaunchAfterPublish />
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
@@ -32,7 +32,7 @@
  //5.PostgreSQL
  "DBType": "SqlServer",
  //连接字符串
  "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //跨域
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/RobotStateRepository.cs
@@ -1,7 +1,7 @@
using Newtonsoft.Json;
using SqlSugar;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.UnitOfWork;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_Model.Models;
@@ -10,20 +10,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 +34,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 IPAddress = @ip AND Version = @expectedVersion,版本匹配才更新
            var affectedRows = Db.Updateable<Dt_RobotState>(newState)
                .Where(x => x.IPAddress == ipAddress)
                .WhereRowVersion(x => x.RowVersion, expectedRowVersion)
                .ExecuteCommand();
            return affectedRows > 0;
@@ -65,7 +61,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,
@@ -131,7 +127,11 @@
                CurrentBatchIndex = state.CurrentBatchIndex,
                ChangePalletPhase = state.ChangePalletPhase,
                IsScanNG = state.IsScanNG,
                BatteryArrived = state.BatteryArrived
                BatteryArrived = state.BatteryArrived,
                CellBarcodeJson = state.CellBarcode.ToJson(),
                LastPickPositionsJson = state.LastPickPositions.ToJson(),
                CurrentTaskJson = state.CurrentTask.ToJson(),
                LastPutPositionsJson = state.LastPutPositions.ToJson(),
            };
            // åºåˆ—化复杂对象为 JSON
@@ -162,13 +162,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_TaskInfoService/TaskService/TaskService.Query.cs
@@ -149,7 +149,7 @@
    public Dt_Task QueryManualInboundTask(string sourceAddress)
    {
        return BaseDal.QueryFirst(x =>
            x.TaskType == (int)TaskInboundTypeEnum.Inbound &&
            (x.TaskType == (int)TaskInboundTypeEnum.Inbound || x.TaskType == (int)TaskInboundTypeEnum.InEmpty) &&
            x.TaskStatus == (int)TaskInStatusEnum.InNew &&
            x.SourceAddress == sourceAddress);
    }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -188,7 +188,7 @@
                                    {
                                        // æ²¡æœ‰ä»»åŠ¡ï¼Œå‘ WMS è¯·æ±‚出库托盘任务
                                        var position = checkPalletPositions.FirstOrDefault(x => x.Code == childDeviceCode);
                                        QuartzLogHelper.LogInfo(_logger, "Execute:检查托盘位置 {ChildDeviceCode},请求WMS出库托盘任务", $"检查托盘位置 {childDeviceCode},请求WMS出库托盘任务", conveyorLine.DeviceCode, childDeviceCode);
                                        //QuartzLogHelper.LogInfo(_logger, "Execute:检查托盘位置 {ChildDeviceCode},请求WMS出库托盘任务", $"检查托盘位置 {childDeviceCode},请求WMS出库托盘任务", conveyorLine.DeviceCode, childDeviceCode);
                                        var responseResult = _httpClientHelper.Post<WebResponseContent>("GetOutBoundTrayTaskAsync", new CreateTaskDto()
                                        {
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs
@@ -50,6 +50,8 @@
                conveyorLine.SetValue(ConveyorLineDBNameNew.Source, short.Parse(task.SourceAddress ?? "0"), childDeviceCode);
                // å†™å…¥ç›®æ ‡åœ°å€
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, short.Parse(task.NextAddress ?? "0"), childDeviceCode);
                // å†™å…¥æ‰˜ç›˜å·
                conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode);
                // æ›´æ–°ä»»åŠ¡çŠ¶æ€åˆ°ä¸‹ä¸€é˜¶æ®µ
                var updateResult = _taskService.UpdateTaskStatusToNext(task);
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
{
@@ -15,6 +16,6 @@
        /// <param name="client">TCP å®¢æˆ·ç«¯è¿žæŽ¥</param>
        /// <param name="state">机器人当前状态</param>
        /// <returns>响应消息,如果无需回复则返回 null</returns>
        Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state);
        Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Abstractions/IRobotNgLineCommandHandler.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_Tasks.Workflow.Abstractions
{
    public interface IRobotNgLineCommandHandler
    {
        Task<bool> HandleAsync(string message, RobotSocketState state);
    }
}
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>
@@ -112,49 +88,43 @@
        /// <param name="client">TCP å®¢æˆ·ç«¯è¿žæŽ¥</param>
        /// <param name="state">机器人当前状态</param>
        /// <returns>响应消息,如果无需回复则返回 null</returns>
        public async Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state)
        public async Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client)
        {
            var state = _stateManager.GetState(client.Client.RemoteEndPoint.ToString());
            if(state.OperStatus == message)
            {
                // å¤„理成功后,将原消息回写到客户端(保持原有行为)
                await _socketClientGateway.SendMessageAsync(client, message);
            }
            // è®°å½•接收到的消息日志
            _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);
                if(messageLower != "batteryarrived")
                {
                    // å¤„理成功后,将原消息回写到客户端(保持原有行为)
                    await _socketClientGateway.SendMessageAsync(client, message);
                    QuartzLogger.Info($"发送消息:【{message}】", state.RobotCrane?.DeviceName);
                }
                // å®‰å…¨æ›´æ–°çŠ¶æ€åˆ° Redis
                _stateManager.TryUpdateStateSafely(activeState.IPAddress, activeState);
                // å®‰å…¨æ›´æ–°çŠ¶æ€åˆ°æ•°æ®åº“
                _stateManager.TryUpdateStateSafely(state.IPAddress, state);
                return null;
            }
@@ -163,11 +133,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/RobotTaskProcessor.cs
@@ -632,7 +632,7 @@
            //    }
            //}
            return false;
            return true;
        }
        /// <summary>
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotNgLineCommandHandler.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
namespace WIDESEAWCS_Tasks.Workflow
{
    public class RobotNgLineCommandHandler : IRobotNgLineCommandHandler
    {
        public Task<bool> HandleAsync(string message, RobotSocketState state)
        {
            // ä½¿ç”¨ switch è¡¨è¾¾å¼è¿›è¡Œæ¨¡å¼åŒ¹é…ï¼Œæé«˜å¯è¯»æ€§å’Œæ€§èƒ½
            switch (message)
            {
                case "PutNGFinished1":
                    return Task.FromResult(true);
                case "PutNGFinished2":
                    return Task.FromResult(true);
                case "PickNGFinished1":
                    return Task.FromResult(true);
                case "PickNGFinished2":
                    return Task.FromResult(true);
                default:
                    return Task.FromResult(true);
            }
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs
@@ -126,7 +126,7 @@
                var parts = message.Split(',');
                // æ£€æŸ¥æ¶ˆæ¯æ ¼å¼æ˜¯å¦æœ‰æ•ˆï¼šè‡³å°‘要有命令前缀,且状态中有当前任务
                if (parts.Length < 1 || state.CurrentTask == null)
                if (parts.Length < 1)
                {
                    return;
                }
@@ -143,7 +143,7 @@
                    .ToArray();
                // ä»Žæ•°æ®åº“重新查询当前任务(确保获取最新状态)
                var task = await _robotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId);
                var task = await _robotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskState == TaskRobotStatusEnum.RobotExecuting.GetHashCode() && x.RobotRoadway == state.RobotCrane.DeviceName);
                if (task != null)
                {
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
@@ -124,6 +125,11 @@
                    state.BatteryArrived = true;
                    return true;
                // æ˜¯å¦ç”µèŠ¯åˆ°ä½
                case "batteryarrivedno":
                    state.BatteryArrived = false;
                    return true;
                // ==================== å…¨éƒ¨å®Œæˆå‘½ä»¤ ====================
                // å…¨éƒ¨å–货完成
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
@@ -112,7 +112,7 @@
            // 1. è¿è¡Œæ¨¡å¼ä¸ºè‡ªåŠ¨ï¼ˆ2)
            // 2. æŽ§åˆ¶æ¨¡å¼ä¸ºå®¢æˆ·ç«¯æŽ§åˆ¶ï¼ˆ1)
            // 3. è¿è¡ŒçŠ¶æ€æ˜¯ Running
            if (latestState.RobotRunMode == 2 /*&& latestState.RobotControlMode == 1*/ && latestState.OperStatus == "Running" && (latestState.Homed == "Homed" || latestState.Homed.IsNullOrEmpty()))
            if (latestState.RobotRunMode == 2 /*&& latestState.RobotControlMode == 1*/ /*&& latestState.OperStatus == "Running"*/ && (latestState.Homed == "Homed" || latestState.Homed.IsNullOrEmpty()))
            {
                // ========== å–货完成后的放货处理 ==========
                // æ¡ä»¶ï¼š
@@ -137,8 +137,8 @@
                // - ä»»åŠ¡çŠ¶æ€ä¸º RobotPutFinish æˆ–不是 RobotExecuting
                else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction.IsNullOrEmpty())
                    && (latestState.RobotArmObject.IsNullOrEmpty() || latestState.RobotArmObject == 0)
                    && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode()
                    || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode()))
                    && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
                    && latestState.BatteryArrived)
                {
                    _logger.LogInformation("ExecuteAsync:满足取货条件,开始下发取货任务,任务号: {TaskNum}", task.RobotTaskNum);
                    QuartzLogger.Info($"ExecuteAsync:满足取货条件,开始下发取货任务", latestState.RobotCrane?.DeviceName ?? ipAddress);
@@ -312,7 +312,7 @@
        private async Task HandlePutFinishedStateAsync(Dt_RobotTask task, string ipAddress)
        {
            // èŽ·å–æœ€æ–°çŠ¶æ€
            var stateForUpdate = _stateManager.GetState(ipAddress);
            RobotSocketState? stateForUpdate = _stateManager.GetState(ipAddress);
            if (stateForUpdate == null)
            {
                _logger.LogWarning("HandlePutFinishedStateAsync:获取状态失败,IP: {IpAddress}", ipAddress);
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
{
@@ -83,7 +84,7 @@
                            {
                                // åˆ¤æ–­æ˜¯å¦ä¸º JSON æ ¼å¼
                                bool isJsonFormat = TryParseJsonSilent(message);
                                _ = MessageReceived.Invoke(message, isJsonFormat, client, robotCrane);
                                _ = MessageReceived.Invoke(message, isJsonFormat, client);
                            }
                            catch { }
                        }
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
@@ -147,7 +148,7 @@
        /// å½“服务器接收到消息时触发。
        /// å‚数:消息内容、是否 JSON æ ¼å¼ã€TCP å®¢æˆ·ç«¯ã€æœºå™¨äººçŠ¶æ€
        /// </remarks>
        public event Func<string, bool, TcpClient, RobotSocketState, Task<string?>>? MessageReceived;
        public event Func<string, bool, TcpClient, Task<string?>>? MessageReceived;
        /// <summary>
        /// æœºå™¨äººè¿žæŽ¥æ–­å¼€äº‹ä»¶
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneCommandBuilder.cs
@@ -205,6 +205,10 @@
            {
                taskType = StackerCraneConst.EmptyPalletTaskType;
            }
            else if(task.TaskType == (int)TaskInboundTypeEnum.InEmpty)
            {
                taskType = StackerCraneConst.EmptyInPalletTaskType;
            }
            else
                taskType = task.TaskType;
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
@@ -109,7 +109,7 @@
            {
                // æ²¡æœ‰ä¸Šä¸€ä»»åŠ¡ç±»åž‹ï¼ŒæŸ¥è¯¢æ™®é€šä»»åŠ¡
                candidateTask = _taskService.QueryStackerCraneTask(deviceCode);
                QuartzLogHelper.LogDebug(_logger, "SelectTask:查询普通任务,设备: {DeviceCode},结果: {TaskNum}", $"查询普通任务,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:查询普通任务,设备: {DeviceCode},结果: {TaskNum}", $"查询普通任务,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
            }
            else if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
            {
@@ -117,19 +117,19 @@
                candidateTask = _taskService.QueryStackerCraneInTask(deviceCode);
                // å¦‚果没有入库任务,再查一下出库任务
                candidateTask ??= _taskService.QueryStackerCraneOutTask(deviceCode);
                QuartzLogHelper.LogDebug(_logger, "SelectTask:出库后优先查入库,设备: {DeviceCode},结果: {TaskNum}", $"出库后优先查入库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:出库后优先查入库,设备: {DeviceCode},结果: {TaskNum}", $"出库后优先查入库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
            }
            else
            {
                // ä¸Šä¸€ä»»åŠ¡æ˜¯å…¥åº“ï¼ˆéžå‡ºåº“ï¼‰ï¼Œä¼˜å…ˆæŸ¥å‡ºåº“ä»»åŠ¡
                candidateTask = _taskService.QueryStackerCraneOutTask(deviceCode);
                QuartzLogHelper.LogDebug(_logger, "SelectTask:入库后优先查出库,设备: {DeviceCode},结果: {TaskNum}", $"入库后优先查出库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:入库后优先查出库,设备: {DeviceCode},结果: {TaskNum}", $"入库后优先查出库,设备: {deviceCode},结果: {candidateTask?.TaskNum}", deviceCode, deviceCode, candidateTask?.TaskNum);
            }
            // å¦‚果没有候选任务,返回 null
            if (candidateTask == null)
            {
                QuartzLogHelper.LogDebug(_logger, "SelectTask:没有候选任务,设备: {DeviceCode}", $"没有候选任务,设备: {deviceCode}", deviceCode, deviceCode);
                //QuartzLogHelper.LogDebug(_logger, "SelectTask:没有候选任务,设备: {DeviceCode}", $"没有候选任务,设备: {deviceCode}", deviceCode, deviceCode);
                return null;
            }
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/src/api/http.js
@@ -12,7 +12,7 @@
let loadingInstance;
let loadingStatus = false;
if (process.env.NODE_ENV == 'development') {
    axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
    axios.defaults.baseURL = 'http://127.0.0.1:9291/';
}
else if (process.env.NODE_ENV == 'debug') {
    axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue
@@ -1,16 +1,11 @@
<template>
  <div>
    <vol-box
      v-model="showBox"
      :lazy="true"
      width="500px"
      :padding="15"
      title="手动创建任务"
    >
    <vol-box v-model="showBox" :lazy="true" width="500px" :padding="15" title="手动创建任务">
      <el-form :model="formData" ref="form" label-width="100px">
        <el-form-item label="任务类型" prop="taskType" required>
          <el-select v-model="formData.taskType" placeholder="请选择任务类型">
            <el-option label="入库" value="入库"></el-option>
            <el-option label="空箱入库" value="空箱入库"></el-option>
            <el-option label="出库" value="出库"></el-option>
            <el-option label="移库" value="移库"></el-option>
          </el-select>
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/gridBodyExtension.vue
@@ -6,6 +6,7 @@
        <el-form-item label="任务类型" prop="taskType" required>
          <el-select v-model="manualFormData.taskType" placeholder="请选择任务类型">
            <el-option label="入库" value="入库"></el-option>
            <el-option label="空箱入库" value="空箱入库"></el-option>
            <el-option label="出库" value="出库"></el-option>
            <el-option label="移库" value="移库"></el-option>
          </el-select>
Code/WMS/WIDESEA_WMSClient/src/views/stock/stockInfo.vue
@@ -28,6 +28,7 @@
const TEXT = {
  pageName: "库存信息",
  palletCode: "托盘编号",
  stockStatus: "库存状态",
  locationCode: "货位编号",
  warehouse: "仓库",
  creator: "创建人",
@@ -104,6 +105,22 @@
        type: "string",
        width: 120,
        align: "left",
      },
      {
        field: "stockStatus",
        title: TEXT.stockStatus,
        type: "int",
        width: 120,
        align: "left",
        bind: { key: "stockStatusEmun", data: [] },
      },
      {
        field: "mesUploadStatus",
        title: "MES状态",
        type: "int",
        width: 120,
        align: "left",
        bind: { key: "mesUploadStatusEnum", data: [] },
      },
      {
        field: "locationCode",
@@ -223,7 +240,7 @@
    const loadStockStatusOptions = async () => {
      try {
        const result = await proxy.http.post("/api/Sys_Dictionary/GetVueDictionary", ["stockStatusEmun"]);
        const result = await proxy.http.post("/api/Sys_Dictionary/GetVueDictionary", ["stockStatusEmun", "mesUploadStatusEnum"]);
        const matched = (result || []).find((item) => item.dicNo === "stockStatusEmun");
        stockStatusOptions.value = matched ? matched.data || [] : [];
      } catch (error) {
Code/WMS/WIDESEA_WMSClient_Vben_v2
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
Subproject commit 07c4ad05f40507d7d797619814bf75a47c29a9f4
Code/WMS/WIDESEA_WMSServer/Database/Scripts/20260420_Dt_StockInfo_MesUploadStatus.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
-- Dt_StockInfo è¡¨æ–°å¢ž MesUploadStatus å­—段
IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('[dbo].[Dt_StockInfo]') AND name = 'MesUploadStatus')
BEGIN
    ALTER TABLE [dbo].[Dt_StockInfo] ADD [MesUploadStatus] TINYINT NOT NULL DEFAULT 0;
END
GO
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/MesService.cs
@@ -35,7 +35,7 @@
            {
                Headers = new Dictionary<string, string>
                {
                    { "Authorization", _authorization }
                    { "Authorization","Bearer "+ _authorization }
                },
                TimeoutMs = 30000,
                MaxRetryCount = 0,
@@ -49,7 +49,7 @@
            {
                Headers = new Dictionary<string, string>
                {
                    { "Authorization", token }
                    { "Authorization","Bearer "+ token }
                },
                TimeoutMs = 30000,
                MaxRetryCount = 0,
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/MesUploadStatusEnum.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
using System.ComponentModel;
namespace WIDESEA_Common.StockEnum
{
    /// <summary>
    /// MES上传状态枚举
    /// </summary>
    public enum MesUploadStatusEnum
    {
        /// <summary>
        /// æœªä¸Šä¼ ï¼ˆä»Žæœªè°ƒç”¨è¿‡MES)
        /// </summary>
        [Description("未上传")]
        æœªä¸Šä¼  = 0,
        /// <summary>
        /// ç»„盘上传成功
        /// </summary>
        [Description("组盘上传成功")]
        ç»„盘上传成功 = 1,
        /// <summary>
        /// ç»„盘上传失败
        /// </summary>
        [Description("组盘上传失败")]
        ç»„盘上传失败 = 2,
        /// <summary>
        /// æ‹†ç›˜ä¸Šä¼ æˆåŠŸ
        /// </summary>
        [Description("拆盘上传成功")]
        æ‹†ç›˜ä¸Šä¼ æˆåŠŸ = 3,
        /// <summary>
        /// æ‹†ç›˜ä¸Šä¼ å¤±è´¥
        /// </summary>
        [Description("拆盘上传失败")]
        æ‹†ç›˜ä¸Šä¼ å¤±è´¥ = 4,
        /// <summary>
        /// è¿›ç«™ä¸Šä¼ æˆåŠŸ
        /// </summary>
        [Description("进站上传成功")]
        è¿›ç«™ä¸Šä¼ æˆåŠŸ = 5,
        /// <summary>
        /// è¿›ç«™ä¸Šä¼ å¤±è´¥
        /// </summary>
        [Description("进站上传失败")]
        è¿›ç«™ä¸Šä¼ å¤±è´¥ = 6,
        /// <summary>
        /// å‡ºç«™ä¸Šä¼ æˆåŠŸ
        /// </summary>
        [Description("出站上传成功")]
        å‡ºç«™ä¸Šä¼ æˆåŠŸ = 7,
        /// <summary>
        /// å‡ºç«™ä¸Šä¼ å¤±è´¥
        /// </summary>
        [Description("出站上传失败")]
        å‡ºç«™ä¸Šä¼ å¤±è´¥ = 8,
        /// <summary>
        /// NG上报成功
        /// </summary>
        [Description("NG上报成功")]
        NG上报成功 = 9,
        /// <summary>
        /// NG上报失败
        /// </summary>
        [Description("NG上报失败")]
        NG上报失败 = 10
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockInfoService.cs
@@ -56,13 +56,21 @@
        /// </summary>
        /// <param name="warehouseId">仓库ID</param>
        /// <returns>3D布局DTO</returns>
        Task<Stock3DLayoutDTO> Get3DLayoutAsync(int warehouseId);
        Task<Stock3DLayoutDTO> Get3DLayoutAsync(int warehouseId);
        /// <summary>
        /// ä½¿ç”¨äº‹åŠ¡åˆ é™¤åº“å­˜å’Œæ˜Žç»†ä¿¡æ¯ï¼ˆå…ˆæŸ¥è¯¢å†åˆ é™¤ï¼‰
        /// </summary>
        /// <param name="stockId">库存ID</param>
        /// <returns>删除结果</returns>
        Task<WebResponseContent> DeleteStockWithDetailsAsync(int stockId);
        /// <summary>
        /// æ›´æ–°MES上传状态
        /// </summary>
        /// <param name="palletCode">托盘号</param>
        /// <param name="status">MES上传状态值</param>
        /// <returns>更新是否成功</returns>
        Task<bool> UpdateMesUploadStatusAsync(string palletCode, int status);
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_StockInfo.cs
@@ -64,6 +64,12 @@
        public string Remark { get; set; }
        /// <summary>
        /// MES上传状态:0=未上传,1=组盘成功,2=组盘失败,3=拆盘成功,4=拆盘失败,5=进站成功,6=进站失败,7=出站成功,8=出站失败,9=NG上报成功,10=NG上报失败
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "MES上传状态")]
        public int MesUploadStatus { get; set; } = 0;
        /// <summary>
        /// å‡ºåº“日期
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "出库日期")]
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockInfoService.cs
@@ -381,5 +381,27 @@
                return WebResponseContent.Instance.Error($"删除库存和明细时发生异常: {ex.Message}");
            }
        }
        /// <summary>
        /// æ›´æ–°MES上传状态
        /// </summary>
        /// <param name="palletCode">托盘号</param>
        /// <param name="status">MES上传状态值</param>
        /// <returns>更新是否成功</returns>
        public async Task<bool> UpdateMesUploadStatusAsync(string palletCode, int status)
        {
            try
            {
                var stockInfo = await BaseDal.QueryDataFirstAsync(x => x.PalletCode == palletCode);
                if (stockInfo == null)
                    return false;
                stockInfo.MesUploadStatus = status;
                return await BaseDal.UpdateDataAsync(stockInfo);
            }
            catch
            {
                return false;
            }
        }
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockSerivce.cs
@@ -1,8 +1,10 @@
using Newtonsoft.Json;
using SqlSugar;
using System.Diagnostics;
using WIDESEA_Common.Constants;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Stock;
using WIDESEA_IBasicService;
@@ -51,6 +53,8 @@
        /// </summary>
        public IMesService _mesService { get; }
        private readonly IMesLogService _mesLogService;
        /// <summary>
        /// æž„造函数
        /// </summary>
@@ -65,7 +69,8 @@
            IStockInfo_HtyService stockInfo_HtyService,
            IMesService mesService,
            IWarehouseService warehouseService,
            ISqlSugarClient sqlSugarClient)
            ISqlSugarClient sqlSugarClient,
            IMesLogService mesLogService)
        {
            StockInfoDetailService = stockInfoDetailService;
            StockInfoService = stockInfoService;
@@ -74,6 +79,7 @@
            _mesService = mesService;
            _warehouseService = warehouseService;
            SqlSugarClient = sqlSugarClient;
            _mesLogService = mesLogService;
        }
        /// <summary>
@@ -466,6 +472,7 @@
        public async Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode, string deviceName)
        {
            WebResponseContent content = new WebResponseContent();
            var stopwatch = Stopwatch.StartNew();
            try
            {
                if (string.IsNullOrWhiteSpace(palletCode))
@@ -510,9 +517,21 @@
                        Location = d.InboundOrderRowNo.ToString()
                    }).ToList()
                };
                string requestJson = bindRequest.ToJson();
                var bindResult = string.IsNullOrWhiteSpace(token)
                    ? _mesService.BindContainer(bindRequest)
                    : _mesService.BindContainer(bindRequest, token);
                stopwatch.Stop();
                await _mesLogService.LogAsync(new MesApiLogDto
                {
                    ApiType = "BindContainer",
                    RequestJson = requestJson,
                    ResponseJson = System.Text.Json.JsonSerializer.Serialize(bindResult),
                    IsSuccess = bindResult.IsSuccess,
                    ErrorMessage = bindResult.ErrorMessage,
                    ElapsedMs = (int)stopwatch.ElapsedMilliseconds,
                    Creator = "systeam"
                });
                if (bindResult == null || bindResult.Data == null || !bindResult.Data.IsSuccess)
                {
                    return content.Error($"MES绑定失败: {bindResult?.Data?.Msg ?? bindResult?.ErrorMessage ?? "未知错误"}");
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -19,6 +19,8 @@
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Stock;
using WIDESEA_DTO.Task;
using Newtonsoft.Json;
using System.Diagnostics;
using WIDESEA_IBasicService;
using WIDESEA_IRecordService;
using WIDESEA_IStockService;
@@ -41,6 +43,7 @@
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IRecordService _recordService;
        private readonly IMESDeviceConfigService _mesDeviceConfigService;
        private readonly IMesLogService _mesLogService;
        public IRepository<Dt_Task> Repository => BaseDal;
@@ -66,7 +69,8 @@
            IStockInfo_HtyService stockInfo_HtyService,
            IUnitOfWorkManage unitOfWorkManage,
            IRecordService recordService,
            IMESDeviceConfigService mesDeviceConfigService) : base(BaseDal)
            IMESDeviceConfigService mesDeviceConfigService,
            IMesLogService mesLogService) : base(BaseDal)
        {
            _mapper = mapper;
            _stockInfoService = stockInfoService;
@@ -80,6 +84,7 @@
            _unitOfWorkManage = unitOfWorkManage;
            _recordService = recordService;
            _mesDeviceConfigService = mesDeviceConfigService;
            _mesLogService = mesLogService;
        }
        /// <summary>
@@ -194,5 +199,81 @@
            // Remark ä¸ºç©ºæ—¶ï¼Œå›žé€€åˆ°å··é“配置
            return DetermineTargetAddress(roadway, addressMap);
        }
        /// <summary>
        /// å¼‚步执行MES上传 - ä¸é˜»å¡žä¸»ä¸šåŠ¡é€»è¾‘
        /// </summary>
        /// <param name="palletCode">托盘号</param>
        /// <param name="successStatus">成功时的状态枚举值(奇数)</param>
        /// <param name="uploadFunc">具体的MES调用函数</param>
        private async Task MesUploadAsync(string palletCode, MesUploadStatusEnum successStatus, Func<Task<HttpResponseResult<MesResponse>>> uploadFunc)
        {
            var stopwatch = Stopwatch.StartNew();
            string requestJson = "";
            string responseJson = "";
            bool isSuccess = false;
            string errorMessage = "";
            try
            {
                // è°ƒç”¨MES
                var result = await uploadFunc();
                stopwatch.Stop();
                isSuccess = result?.Data?.IsSuccess ?? false;
                errorMessage = result?.Data?.Msg ?? result?.ErrorMessage ?? "未知错误";
                responseJson = JsonConvert.SerializeObject(result);
                // æ ¹æ®æˆåŠŸ/失败决定状态值:奇数=成功,偶数=失败
                var uploadStatus = isSuccess ? (int)successStatus : (int)successStatus + 1;
                // æ›´æ–°åº“存表状态(不等待)
                _ = _stockInfoService.UpdateMesUploadStatusAsync(palletCode, uploadStatus);
                // è®°å½•MES日志
                await LogMesCallAsync(palletCode, successStatus.ToString(), requestJson, responseJson,
                    stopwatch.ElapsedMilliseconds, isSuccess ? "成功" : "失败", errorMessage);
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                errorMessage = ex.Message;
                // æ›´æ–°çŠ¶æ€ä¸ºå¤±è´¥ï¼ˆsuccessStatus+1 å³ä¸ºå¤±è´¥çŠ¶æ€ï¼‰
                var uploadStatus = (int)successStatus + 1;
                _ = _stockInfoService.UpdateMesUploadStatusAsync(palletCode, uploadStatus);
                // è®°å½•异常日志
                await LogMesCallAsync(palletCode, successStatus.ToString(), requestJson, responseJson,
                    stopwatch.ElapsedMilliseconds, "失败", errorMessage);
            }
        }
        /// <summary>
        /// è®°å½•MES接口调用日志
        /// </summary>
        private async Task LogMesCallAsync(string palletCode, string apiType, string requestJson,
            string responseJson, long durationMs, string status, string errorMessage)
        {
            try
            {
                var mesLog = new MesApiLogDto
                {
                    PalletCode = palletCode,
                    ApiType = apiType,
                    RequestJson = requestJson,
                    ResponseJson = responseJson,
                    IsSuccess = status == "成功",
                    ErrorMessage = errorMessage,
                    ElapsedMs = (int)durationMs,
                    Creator = "System"
                };
                await _mesLogService.LogAsync(mesLog);
            }
            catch
            {
                // æ—¥å¿—记录失败不影响主流程
            }
        }
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs
@@ -1,9 +1,13 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Newtonsoft.Json;
using System.Diagnostics;
using WIDESEA_Common.Constants;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Common.WareHouseEnum;
using WIDESEA_Core;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
@@ -118,6 +122,7 @@
        /// </summary>
        public async Task<WebResponseContent> InboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
@@ -127,56 +132,91 @@
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                // åˆ¤æ–­æ˜¯ä¸æ˜¯æžå·åº“任务
                if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1)
                if (stockInfo == null)
                {
                    return await CompleteAgvInboundTaskAsync(taskDto);
                    return await _unitOfWorkManage.BeginTranAsync(async () =>
                    {
                        stockInfo = new Dt_StockInfo
                        {
                            PalletCode = taskDto.PalletCode,
                            WarehouseId = task.WarehouseId,
                            StockStatus = StockStatusEmun.空托盘库存.GetHashCode(),
                            Creater = StockConstants.SYSTEM_USER,
                            Details = null,
                            LocationCode = location.LocationCode,
                            LocationId = location.Id
                        };
                        var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                        var updateStockResult = await _stockInfoService.Repository.AddDataAsync(stockInfo);
                        return await CompleteTaskAsync(task, "入库完成");
                    });
                }
                return await _unitOfWorkManage.BeginTranAsync(async () =>
                else
                {
                    WebResponseContent content = new WebResponseContent();
                    stockInfo.LocationCode = location.LocationCode;
                    stockInfo.LocationId = location.Id;
                    SetOutboundDateByRoadway(task, stockInfo);
                    stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                    location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("任务完成失败");
                    // æ ¹æ®åº“å­˜Remark选择静置设备,查MES动态凭证
                    string deviceName = stockInfo.Remark == "GW_1" ? "高温静置1"
                        : stockInfo.Remark == "GW_2" ? "高温静置2"
                        : "常温静置1";
                    var mesConfig = _mesDeviceConfigService.GetByDeviceName(deviceName);
                    string equipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE;
                    string resourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE;
                    string token = mesConfig?.Token;
                    // è°ƒç”¨MES托盘进站
                    var inboundRequest = new InboundInContainerRequest
                    // åˆ¤æ–­æ˜¯ä¸æ˜¯æžå·åº“任务
                    if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1)
                    {
                        EquipmentCode = equipmentCode,
                        ResourceCode = resourceCode,
                        LocalTime = DateTime.Now,
                        ContainerCode = taskDto.PalletCode
                    };
                    var inboundResult = string.IsNullOrWhiteSpace(token)
                        ? _mesService.InboundInContainer(inboundRequest)
                        : _mesService.InboundInContainer(inboundRequest, token);
                    if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess)
                    {
                        return content.Error($"任务完成失败:MES进站失败: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "未知错误"}");
                        return await CompleteAgvInboundTaskAsync(taskDto);
                    }
                    return await CompleteTaskAsync(task, "入库完成");
                });
                    return await _unitOfWorkManage.BeginTranAsync(async () =>
                    {
                        WebResponseContent content = new WebResponseContent();
                        stockInfo.LocationCode = location.LocationCode;
                        stockInfo.LocationId = location.Id;
                        SetOutboundDateByRoadway(task, stockInfo);
                        stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                        location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                        var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                        var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                        if (!updateLocationResult || !updateStockResult)
                            return WebResponseContent.Instance.Error("任务完成失败");
                        // æ ¹æ®åº“å­˜Remark选择静置设备,查MES动态凭证
                        //string deviceName = stockInfo.Remark == "GW_1" ? "高温静置1"
                        //    : stockInfo.Remark == "GW_2" ? "高温静置2"
                        //    : "常温静置1";
                        //var mesConfig = _mesDeviceConfigService.GetByDeviceName(deviceName);
                        //string equipmentCode = mesConfig?.EquipmentCode ?? StockConstants.MES_EQUIPMENT_CODE;
                        //string resourceCode = mesConfig?.ResourceCode ?? StockConstants.MES_RESOURCE_CODE;
                        //string token = mesConfig?.Token;
                        // è°ƒç”¨MES托盘进站
                        //var inboundRequest = new InboundInContainerRequest
                        //{
                        //    EquipmentCode = equipmentCode,
                        //    ResourceCode = resourceCode,
                        //    LocalTime = DateTime.Now,
                        //    ContainerCode = taskDto.PalletCode
                        //};
                        //string requestJson = inboundRequest.ToJson();
                        //var inboundResult = string.IsNullOrWhiteSpace(token)
                        //    ? _mesService.InboundInContainer(inboundRequest)
                        //    : _mesService.InboundInContainer(inboundRequest, token);
                        //stopwatch.Stop();
                        //await _mesLogService.LogAsync(new MesApiLogDto
                        //{
                        //    ApiType = "InboundInContainer",
                        //    RequestJson = requestJson,
                        //    ResponseJson = JsonConvert.SerializeObject(inboundResult),
                        //    IsSuccess = inboundResult.IsSuccess,
                        //    ErrorMessage = inboundResult.ErrorMessage,
                        //    ElapsedMs = (int)stopwatch.ElapsedMilliseconds,
                        //    Creator = "systeam"
                        //});
                        //if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess)
                        //{
                        //    return content.Error($"任务完成失败:MES进站失败: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "未知错误"}");
                        //}
                        return await CompleteTaskAsync(task, "入库完成");
                    });
                }
            }
            catch (Exception ex)
            {
@@ -220,4 +260,4 @@
        #endregion å…¥åº“任务
    }
}
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Manual.cs
@@ -41,6 +41,11 @@
                        taskStatus = TaskRelocationStatusEnum.RelocationNew.GetHashCode();
                        break;
                    case "空箱入库":
                        taskType = TaskInboundTypeEnum.InEmpty.GetHashCode();
                        taskStatus = TaskInStatusEnum.InNew.GetHashCode();
                        break;
                    default:
                        return WebResponseContent.Instance.Error($"不支持的任务类型: {dto.TaskType}");
                }
@@ -92,7 +97,7 @@
                        wmsTaskDtos.ToJson());
                    if (!wcsResult.IsSuccess || !wcsResult.Data.Status)
                        return WebResponseContent.Instance.Error($"任务已创建但发送给WCS失败: {wcsResult.Data?.Message}");
                        return WebResponseContent.Instance.Error($"任务已创建但发送给WCS失败:{wcsResult.ErrorMessage}\r\n {wcsResult.Data?.Message}");
                    return WebResponseContent.Instance.OK($"手动创建任务成功,任务号: {taskNum}");
                });
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Outbound.cs
@@ -1,9 +1,11 @@
using System.Diagnostics;
using WIDESEA_Common.Constants;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Common.WareHouseEnum;
using WIDESEA_Core;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
@@ -58,6 +60,7 @@
        /// </summary>
        public async Task<WebResponseContent> OutboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            var stopwatch = Stopwatch.StartNew();
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
@@ -135,9 +138,21 @@
                        LocalTime = DateTime.Now,
                        ContainerCode = taskDto.PalletCode
                    };
                    string requestJson = outboundRequest.ToJson();
                    var outboundResult = string.IsNullOrWhiteSpace(token)
                        ? _mesService.OutboundInContainer(outboundRequest)
                        : _mesService.OutboundInContainer(outboundRequest, token);
                    stopwatch.Stop();
                    await _mesLogService.LogAsync(new MesApiLogDto
                    {
                        ApiType = "UnbindContainer",
                        RequestJson = requestJson,
                        ResponseJson = System.Text.Json.JsonSerializer.Serialize(outboundResult),
                        IsSuccess = outboundResult.IsSuccess,
                        ErrorMessage = outboundResult.ErrorMessage,
                        ElapsedMs = (int)stopwatch.ElapsedMilliseconds,
                        Creator = "systeam"
                    });
                    if (outboundResult == null || outboundResult.Data == null || !outboundResult.Data.IsSuccess)
                    {
                        return content.Error($"出库完成失败:MES出站失败: {outboundResult?.Data?.Msg ?? outboundResult?.ErrorMessage ?? "未知错误"}");
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
@@ -348,8 +348,8 @@
                    var occupiedLocations = occupiedLocationGroups.FirstOrDefault(og => og.WarehouseId == w.WarehouseId)?.OccupiedLocations ?? 0;
                    var emptyLocations = totalLocations - occupiedLocations;
                    var occupiedPercentage = totalLocations > 0 ? Math.Round((double)occupiedLocations / totalLocations * 100, 2) : 0.0;
                    var emptyPercentage = totalLocations > 0 ? Math.Round((double)emptyLocations / totalLocations * 100, 2) : 0.0;
                    var occupiedPercentage = totalLocations > 0 ? Math.Round((double)occupiedLocations / totalLocations * 100, 0) : 0.0;
                    var emptyPercentage = totalLocations > 0 ? Math.Round((double)emptyLocations / totalLocations * 100, 0) : 0.0;
                    return new
                    {
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
@@ -34,7 +34,7 @@
  "MainDB": "DB_WIDESEA", //当前项目的主库,所对应的连接字符串的Enabled必须为true
  //连接字符串
  //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
  "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
  //旧WMS数据库连接
@@ -71,7 +71,7 @@
    }
  },
  "MES": {
    "BaseUrl": "http://localhost:5000",
    "BaseUrl": "http://192.168.98.11:20033",
    "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjMwMTcyNzM5Mzk5NzYxOTIwIiwibmFtZSI6IlBBQ0voo4XphY3lt6XkvY0wMSIsIkZhY3RvcnlJZCI6IjEyMzQ1NiIsIlNpdGVJZCI6IjEyMzQ1NiIsIkNvZGUiOiJYWExQQUNLMDRBRTAzMiIsIm5iZiI6MTcwNDE4NzY5MCwiZXhwIjoyMTQ1NjkxNjkwLCJpc3MiOiJodHRwczovL3d3dy5oeW1zb24uY29tIiwiYXVkIjoiaHR0cHM6Ly93d3cuaHltc29uLmNvbSJ9.An1BE7UgfcSP--LtTOmmmWVE2RQFPDahLkDg1xy5KqY"
  },
  "RobotTaskAddressRules": {