wanshenmean
2026-03-06 aefdecd0aa3226b7d00d1dc764241b82658b3be8
添加机器人客户端;更新 WCS 缓存及任务

新增内容:

添加新的 RobotClient 项目及多个 RobotJob 组件(包括:BarcodeGenerator 条码生成器、ClientManager 客户端管理器、MessageHandler 消息处理器、SocketState 套接字状态、StateManager 状态管理器、TaskProcessor 任务处理器)

服务端更新:

更新 WIDESEAWCS 服务器:修改 TaskEnum 和 TaskType 枚举、TaskService 服务以及 RobotJob.cs 文件

缓存层重构:

修订缓存层及 Redis 集成(涉及 ICacheService 缓存接口、MemoryCacheService 内存缓存、HybridCacheService 混合缓存、RedisCacheService 缓存服务、CacheSyncBackgroundService 缓存同步后台服务、RedisOptions 配置选项)

更新 appsettings 配置文件

开发环境配置:

更新工作区元数据(.vs/DocumentLayout.json 文件)

添加 .claude 本地权限配置

其他变更:

包含各类 IDE 快照文件

若干与 WMS 任务相关的细微调整
已添加26个文件
已修改21个文件
4162 ■■■■ 文件已修改
Code/WCS/WIDESEAWCS_Server/.claude/settings.local.json 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json 431 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskTypeEnum.cs 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/CacheSyncBackgroundService.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotBarcodeGenerator.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs 616 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotMessageHandler.cs 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotStateManager.cs 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/TaskEnum/TaskStatusEnum.cs 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/TaskEnum/TaskTypeEnum.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.dockerignore 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/957CD3507E75254DAB50B67D1CAD4ABB/57E558275472B567970CA987458436D5 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/957CD3507E75254DAB50B67D1CAD4ABB/89EE95323C118AB5E5FA0B5FC9E372D8 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/BE43EC63E499EE468C0161FA83175A2D/340C5AFE3B0C2AB455087AFF43725D6E 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/BE43EC63E499EE468C0161FA83175A2D/57E558275472B567970CA987458436D5 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/C569B8B80C5D3640BC534EFC4D2E9EFE/57E558275472B567970CA987458436D5 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/C569B8B80C5D3640BC534EFC4D2E9EFE/EEF5B4E6C1E13E5E42E047DE7B74D577 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/E6DFDF72DCCF3C46ABA29988BCD5456A/57E558275472B567970CA987458436D5 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/E6DFDF72DCCF3C46ABA29988BCD5456A/F977376DB3B74CAF672118CAACA4BA95 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/state.mpack 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/RobotClient.slnx/copilot-chat/bef6627e/sessions/36c312bd-395e-4534-89ed-c65ca163a4e7 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/RobotClient.slnx/v18/DocumentLayout.backup.json 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/.vs/RobotClient.slnx/v18/DocumentLayout.json 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/CLAUDE.md 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/Dockerfile 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/Program.cs 399 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/Properties/launchSettings.json 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/RobotClient.csproj 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/机械手客户端/RobotClient/RobotClient.slnx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/.claude/settings.local.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
{
  "permissions": {
    "allow": [
      "Bash(dotnet new:*)",
      "Bash(dotnet add:*)",
      "Bash(dotnet test:*)",
      "Bash(dotnet build WIDESEAWCS_Server.sln --nologo -v q)"
    ]
  }
}
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/CodeChunks.db
Binary files differ
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/18.0.988.22099/SemanticSymbols.db
Binary files differ
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json
@@ -3,20 +3,60 @@
  "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|solutionrelative:wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robottaskprocessor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robottaskprocessor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotmessagehandler.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotmessagehandler.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\taskenum\\taskenumhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\taskenum\\taskenumhelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\robottaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\robottaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.messaging.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.messaging.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\service\\routerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\service\\routerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotstatemanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotstatemanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotclientmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotclientmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\cache\\hybridcacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\cache\\hybridcacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\connection\\redisconnectionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\connection\\redisconnectionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
@@ -27,28 +67,32 @@
      "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\extensions\\redisservicesetup.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\cache\\rediscacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\cache\\rediscacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\httpenum\\configkey.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\httpenum\\configkey.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\redis\u4F7F\u7528\u6848\u4F8B.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\redis\u4F7F\u7528\u6848\u4F8B.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\redis\\redisname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\redis\\redisname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.server.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.server.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|solutionrelative:wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_core\\http\\httprequesthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|solutionrelative:wideseawcs_core\\http\\httprequesthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinenewjob\\conveyorline\\checkpalletposition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinenewjob\\conveyorline\\checkpalletposition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\httpenum\\baseapi.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\httpenum\\baseapi.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\quartznet\\quartznetextension.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_common\\redis\\redisprefix.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}|WIDESEAWCS_Common\\WIDESEAWCS_Common.csproj|solutionrelative:wideseawcs_common\\redis\\redisprefix.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
@@ -58,7 +102,7 @@
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 14,
          "SelectedChildIndex": 10,
          "Children": [
            {
              "$type": "Bookmark",
@@ -74,156 +118,289 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "TcpSocketServer.Clients.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
              "ViewState": "AgIAAEkAAAAAAAAAAAAIwAkAAAAZAAAAAAAAAA==",
              "DocumentIndex": 6,
              "Title": "TaskEnumHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\TaskEnum\\TaskEnumHelper.cs",
              "ViewState": "AgIAABQAAAAAAAAAAAAgwDUAAAAIAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T04:08:38.428Z",
              "WhenOpened": "2026-03-05T07:09:01.343Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "RedisConnectionManager.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
              "ViewState": "AgIAAD0AAAAAAAAAAAAuwE8AAAAIAAAAAAAAAA==",
              "Title": "RobotMessageHandler.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotMessageHandler.cs",
              "ViewState": "AgIAAMgAAAAAAAAAAAAMwNIAAABHAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T03:52:53.567Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "Title": "HybridCacheService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "ViewState": "AgIAAOkAAAAAAAAAAAAqwPoAAAAjAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T03:39:18.734Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "Title": "RedisServiceSetup.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "ViewState": "AgIAADgAAAAAAAAAAAAmwCIAAAAMAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T03:33:54.548Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "Program.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Program.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Program.cs",
              "ViewState": "AgIAACQAAAAAAAAAAAAqwDYAAAAeAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T03:16:21.765Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "RedisCacheService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
              "ViewState": "AgIAABoAAAAAAAAAAAAmwCkAAAAoAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T03:06:06.952Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "Redis\u4F7F\u7528\u6848\u4F8B.md",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
              "RelativeToolTip": "WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
              "ViewState": "AgIAAAgBAAAAAAAAAAAAABcBAAAPAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
              "WhenOpened": "2026-03-02T02:59:29.028Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "HttpClientHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "RelativeToolTip": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "ViewState": "AgIAABQAAAAAAAAAAADwvygAAABLAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T02:58:50.075Z",
              "WhenOpened": "2026-03-05T03:25:13.299Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "Title": "CheckPalletPosition.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAeAAAAAAAAAA==",
              "Title": "TaskTypeEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ViewState": "AgIAACEAAAAAAAAAAADwvzwAAAAYAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-28T08:42:47.236Z",
              "WhenOpened": "2026-03-05T03:17:26.276Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "DocumentIndex": 2,
              "Title": "RobotTaskProcessor.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotTaskProcessor.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotTaskProcessor.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotTaskProcessor.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotTaskProcessor.cs",
              "ViewState": "AgIAAIgAAAAAAAAAAAD4v54AAAApAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T02:51:55.934Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 15,
              "Title": "RedisServiceSetup.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
              "ViewState": "AgIAABkAAAAAAAAAAAAtwDYAAAA5AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T07:51:50.169Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "RobotTaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\RobotTaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\RobotTaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\RobotTaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\RobotTaskService.cs",
              "ViewState": "AgIAAD0AAAAAAAAAAAAMwEcAAAAdAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T03:03:26.246Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 19,
              "Title": "HttpRequestHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HttpRequestHelper.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Core\\Http\\HttpRequestHelper.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HttpRequestHelper.cs",
              "RelativeToolTip": "WIDESEAWCS_Core\\Http\\HttpRequestHelper.cs",
              "ViewState": "AgIAAJ0AAAAAAAAAAADwv7AAAAAiAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T02:38:46.736Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "TaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAAHcBAAAAAAAAAAAMwJABAAAVAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T02:28:05.416Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 20,
              "Title": "BaseAPI.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\HttpEnum\\BaseAPI.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\HttpEnum\\BaseAPI.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\HttpEnum\\BaseAPI.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\HttpEnum\\BaseAPI.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAABoAAAAWAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T02:22:49.339Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 16,
              "Title": "ConfigKey.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\HttpEnum\\ConfigKey.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\HttpEnum\\ConfigKey.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\HttpEnum\\ConfigKey.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\HttpEnum\\ConfigKey.cs",
              "ViewState": "AgIAABEAAAAAAAAAAADwvwkAAAASAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T02:19:51.695Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "HttpClientHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "RelativeToolTip": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
              "ViewState": "AgIAAFgAAAAAAAAAAAD4v1sAAAAtAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T02:13:21.506Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 17,
              "Title": "RedisName.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\Redis\\RedisName.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\Redis\\RedisName.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\Redis\\RedisName.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\Redis\\RedisName.cs",
              "ViewState": "AgIAAAwAAAAAAAAAAAAswBwAAAAfAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T01:52:46.175Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 22,
              "Title": "RedisPrefix.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\Redis\\RedisPrefix.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Common\\Redis\\RedisPrefix.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\Redis\\RedisPrefix.cs",
              "RelativeToolTip": "WIDESEAWCS_Common\\Redis\\RedisPrefix.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAA4AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T01:50:08.45Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "RouterService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\RouterService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\Service\\RouterService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\Service\\RouterService.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\Service\\RouterService.cs",
              "ViewState": "AgIAAKoAAAAAAAAAAAAawMEAAABrAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T10:10:38.22Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "Title": "HybridCacheService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "RelativeToolTip": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
              "ViewState": "AgIAAHUCAAAAAAAAAAAswI4CAABaAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T10:04:18.563Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 21,
              "Title": "QuartzNetExtension.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\QuartzNet\\QuartzNetExtension.cs",
              "ViewState": "AgIAAHoAAAAAAAAAAAAswIgAAABBAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T09:22:53.922Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 18,
              "Title": "TcpSocketServer.Server.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Server.cs",
              "ViewState": "AgIAABEAAAAAAAAAAAAhwCMAAAAbAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T09:11:28.744Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "TcpSocketServer.Messaging.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Messaging.cs",
              "ViewState": "AgIAADMAAAAAAAAAAAAgwEgAAAAZAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-02T09:07:48.915Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "Title": "appsettings.json",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json",
              "ViewState": "AgIAACUAAAAAAAAAAAAYwCsAAAAeAAAAAAAAAA==",
              "ViewState": "AgIAADoAAAAAAAAAAAAYwE4AAAAbAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
              "WhenOpened": "2026-02-28T05:50:10.851Z",
              "EditorCaption": ""
              "WhenOpened": "2026-02-28T05:50:10.851Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "DocumentIndex": 4,
              "Title": "CommonConveyorLineNewJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
              "ViewState": "AgIAAEoAAAAAAAAAAAAAwGAAAABTAAAAAAAAAA==",
              "ViewState": "AgIAAEAAAAAAAAAAAAAswHgAAAAcAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-28T05:48:06.526Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "DocumentIndex": 11,
              "Title": "RobotStateManager.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotStateManager.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotStateManager.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotStateManager.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotStateManager.cs",
              "ViewState": "AgIAAFoAAAAAAAAAAAAmwAAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T02:50:08.257Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 12,
              "Title": "RobotClientManager.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotClientManager.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotClientManager.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotClientManager.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotClientManager.cs",
              "ViewState": "AgIAADYAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T01:55:28.903Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "Title": "RobotJob.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
              "ViewState": "AgIAADgAAAAAAAAAAAAtwEIAAAAPAAAAAAAAAA==",
              "ViewState": "AgIAAGMAAAAAAAAAAAAcwHYAAABVAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-05T05:38:04.031Z",
              "EditorCaption": ""
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskEnumHelper.cs
@@ -32,7 +32,7 @@
                return TaskTypeGroup.OutbondGroup;
            }
            // å°è¯•将任务类型转换为TaskInStatusEnum枚举类型,如果成功,返回InboundGroup
            else if (!int.TryParse(Enum.Parse<TaskOutboundTypeEnum>(taskTypeStr).ToString(), out result))
            else if (!int.TryParse(Enum.Parse<TaskInStatusEnum>(taskTypeStr).ToString(), out result))
            {
                return TaskTypeGroup.InboundGroup;
            }
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/TaskEnum/TaskTypeEnum.cs
@@ -28,7 +28,13 @@
        /// è´¨æ£€å…¥åº“
        /// </summary>
        [Description("质检入库")]
        InQuality = 203
        InQuality = 203,
        /// <summary>
        /// ç©ºç®±å…¥åº“
        /// </summary>
        [Description("空箱入库")]
        InEmpty = 600,
    }
    public enum TaskOutboundTypeEnum
@@ -53,6 +59,12 @@
        /// </summary>
        [Description("质检出库")]
        OutQuality = 103,
        /// <summary>
        /// ç©ºç®±å‡ºåº“
        /// </summary>
        [Description("空箱出库")]
        OutEmpty = 140,
    }
    public enum TaskRelocationTypeEnum
@@ -98,4 +110,98 @@
        [Description("换盘任务")]
        SplitPallet = 520
    }
    public enum TaskTypeEnum
    {
        /// <summary>
        /// é¢†æ–™å‡ºåº“
        /// </summary>
        [Description("领料出库")]
        Outbound = 100,
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“
        /// </summary>
        [Description("盘点出库")]
        OutInventory = 110,
        /// <summary>
        /// åˆ†æ‹£å‡ºåº“
        /// </summary>
        [Description("分拣出库")]
        OutPick = 120,
        /// <summary>
        /// è´¨æ£€å‡ºåº“
        /// </summary>
        [Description("质检出库")]
        OutQuality = 130,
        /// <summary>
        /// ç©ºç®±å‡ºåº“
        /// </summary>
        [Description("空箱出库")]
        OutEmpty = 140,
        /// <summary>
        /// MES出库
        /// </summary>
        [Description("MES出库")]
        MesOutbound = 200,
        /// <summary>
        /// MES手动出库
        /// </summary>
        [Description("MES手动出库")]
        MesHandOutbound = 210,
        /// <summary>
        /// MES手动拣选出库
        /// </summary>
        [Description("MES手动拣选出库")]
        MesHandPickOutbound = 220,
        /// <summary>
        /// é‡‡è´­å…¥åº“
        /// </summary>
        [Description("采购入库")]
        Inbound = 510,
        /// <summary>
        /// ç›˜ç‚¹å…¥åº“
        /// </summary>
        [Description("盘点入库")]
        InInventory = 520,
        /// <summary>
        /// åˆ†æ‹£å…¥åº“
        /// </summary>
        [Description("分拣入库")]
        InPick = 530,
        /// <summary>
        /// è´¨æ£€å…¥åº“
        /// </summary>
        [Description("质检入库")]
        InQuality = 540,
        /// <summary>
        /// ç”Ÿäº§é€€æ–™
        /// </summary>
        [Description("生产退料")]
        ProductionReturn = 550,
        /// <summary>
        /// MES退料
        /// </summary>
        [Description("MES退料")]
        MesMatReturn = 560,
        /// <summary>
        /// ç©ºç®±å…¥åº“
        /// </summary>
        [Description("空箱入库")]
        InEmpty = 600,
        /// <summary>
        /// å··é“内移库
        /// </summary>
        [Description("巷道内移库")]
        Relocation = 900
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs
@@ -247,6 +247,24 @@
        bool TryUpdateIfChanged<T>(string key, T newValue, int expireSeconds = -1) where T : class;
        /// <summary>
        /// å®‰å…¨æ›´æ–°ï¼šä»…当内存缓存中的值与expectedVersion匹配时才更新
        /// é˜²æ­¢å¹¶å‘写入时旧值覆盖新值(适用于多线程/多进程场景)
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="newValue">新值</param>
        /// <param name="expectedVersion">期望的版本(通常是旧对象的某个属性值,如时间戳)</param>
        /// <param name="versionExtractor">从对象提取版本号的函数</param>
        /// <param name="expireSeconds">过期时间(秒)</param>
        /// <returns>是否更新成功</returns>
        bool TrySafeUpdate<T>(
            string key,
            T newValue,
            object? expectedVersion,
            Func<T, object?> versionExtractor,
            int expireSeconds = -1) where T : class;
        /// <summary>
        /// èŽ·å–æˆ–æ·»åŠ ï¼šKey存在则返回现有值,不存在则添加并返回新值
        /// </summary>
        string GetOrAdd(string key, string value, int expireSeconds = -1);
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs
@@ -392,6 +392,28 @@
            return true;
        }
        public bool TrySafeUpdate<T>(
            string key,
            T newValue,
            object? expectedVersion,
            Func<T, object?> versionExtractor,
            int expireSeconds = -1) where T : class
        {
            var existing = Get<T>(key);
            if (existing == null) return false;
            // æ£€æŸ¥ç‰ˆæœ¬æ˜¯å¦åŒ¹é…
            var currentVersion = versionExtractor(existing);
            if (!Equals(currentVersion, expectedVersion))
            {
                return false; // ç‰ˆæœ¬ä¸åŒ¹é…ï¼Œæ‹’绝更新
            }
            Remove(key);
            AddObject(key, newValue, expireSeconds);
            return true;
        }
        public string GetOrAdd(string key, string value, int expireSeconds = -1)
        {
            var existing = _cache.Get(key)?.ToString();
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/CacheSyncBackgroundService.cs
@@ -132,6 +132,15 @@
                    try
                    {
                        var keyStr = redisKey.ToString();
                        // è·³è¿‡æŽ’除的key前缀(如设备状态等频繁变动的数据)
                        if (_options.SyncExcludePrefixes.Any(prefix => keyStr.StartsWith(prefix, StringComparison.Ordinal)))
                        {
                            _logger.LogTrace("跳过排除的key: {Key}", keyStr);
                            skippedCount++;
                            continue;
                        }
                        _trackedKeys.AddOrUpdate(keyStr, true, (_, _) => true);
                        // èŽ·å–Redis中的值
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs
@@ -573,6 +573,104 @@
            }
        }
        /// <summary>
        /// å®‰å…¨æ›´æ–°ï¼šä»…当内存缓存中的值与expectedVersion匹配时才更新
        /// é˜²æ­¢å¹¶å‘写入时旧值覆盖新值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="newValue">新值</param>
        /// <param name="expectedVersion">期望的版本(通常是旧对象的哈希值或时间戳)</param>
        /// <param name="versionExtractor">从对象提取版本号的函数</param>
        /// <param name="expireSeconds">过期时间</param>
        /// <returns>是否更新成功</returns>
        public bool TrySafeUpdate<T>(
            string key,
            T newValue,
            object? expectedVersion,
            Func<T, object?> versionExtractor,
            int expireSeconds = -1) where T : class
        {
            var fullKey = BuildKey(key);
            // ä»ŽRedis获取当前值
            string? existingJson = null;
            T? existingValue = default;
            if (RedisAvailable)
            {
                try
                {
                    var value = _connectionManager.GetDatabase().StringGet(fullKey);
                    if (!value.IsNullOrEmpty)
                    {
                        existingJson = value.ToString();
                        existingValue = _serializer.Deserialize<T>(existingJson);
                    }
                }
                catch { }
            }
            // å¦‚æžœRedis不可用,从内存缓存获取
            if (existingValue == null && _options.EnableL1Cache)
            {
                if (_memoryCache.TryGetValue(fullKey, out string? cached) && cached != null)
                {
                    existingValue = _serializer.Deserialize<T>(cached);
                    existingJson = cached;
                }
                else
                {
                    return false;
                }
            }
            // æ£€æŸ¥ç‰ˆæœ¬æ˜¯å¦åŒ¹é…
            if (existingValue != null)
            {
                var currentVersion = versionExtractor(existingValue);
                if (!Equals(currentVersion, expectedVersion))
                {
                    _logger.LogWarning("TrySafeUpdate版本不匹配, key={Key}, expected={Expected}, current={Current}",
                        key, expectedVersion, currentVersion);
                    return false; // ç‰ˆæœ¬ä¸åŒ¹é…ï¼Œæ‹’绝更新
                }
            }
            // ç‰ˆæœ¬åŒ¹é…ï¼Œæ‰§è¡Œæ›´æ–°
            var newJson = _serializer.Serialize(newValue);
            // å…ˆå†™å…¥Redis
            if (RedisAvailable)
            {
                try
                {
                    var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
                    if (!_connectionManager.GetDatabase().StringSet(fullKey, newJson, expiry))
                    {
                        _logger.LogWarning("Redis TrySafeUpdate写入失败, key={Key}", key);
                        return _options.FallbackToMemory && _options.EnableL1Cache;
                    }
                    else
                    {
                        _logger.LogInformation("Redis TrySafeUpdate写入成功, key={Key}", key);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Redis TrySafeUpdate写入失败, key={Key}", key);
                    return _options.FallbackToMemory && _options.EnableL1Cache;
                }
            }
            // æ›´æ–°å†…存缓存
            if (_options.EnableL1Cache)
            {
                SetMemoryCache(fullKey, newJson, expireSeconds, false);
            }
            return true;
        }
        public object? Get(Type type, string key)
        {
            var fullKey = BuildKey(key);
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs
@@ -365,6 +365,34 @@
            return Db.StringSet(fullKey, newJson, expiry, When.Exists);
        }
        public bool TrySafeUpdate<T>(
            string key,
            T newValue,
            object? expectedVersion,
            Func<T, object?> versionExtractor,
            int expireSeconds = -1) where T : class
        {
            var fullKey = BuildKey(key);
            var existing = Db.StringGet(fullKey);
            if (existing.IsNullOrEmpty) return false;
            // ååºåˆ—化现有值
            var existingValue = _serializer.Deserialize<T>(existing.ToString()!);
            if (existingValue == null) return false;
            // æ£€æŸ¥ç‰ˆæœ¬æ˜¯å¦åŒ¹é…
            var currentVersion = versionExtractor(existingValue);
            if (!Equals(currentVersion, expectedVersion))
            {
                return false; // ç‰ˆæœ¬ä¸åŒ¹é…ï¼Œæ‹’绝更新
            }
            // ç‰ˆæœ¬åŒ¹é…ï¼Œæ‰§è¡Œæ›´æ–°
            var newJson = _serializer.Serialize(newValue);
            var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
            return Db.StringSet(fullKey, newJson, expiry, When.Exists);
        }
        public string GetOrAdd(string key, string value, int expireSeconds = -1)
        {
            var fullKey = BuildKey(key);
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs
@@ -46,6 +46,12 @@
        /// </summary>
        public int SyncBatchSize { get; set; } = 1000;
        /// <summary>
        /// è‡ªåŠ¨åŒæ­¥æŽ’é™¤çš„key前缀列表(这些key不会被自动同步覆盖)
        /// ä¾‹å¦‚:["wcs:SocketDevices:"] è¡¨ç¤ºè®¾å¤‡çŠ¶æ€ä¸ä¼šè¢«è‡ªåŠ¨åŒæ­¥
        /// </summary>
        public List<string> SyncExcludePrefixes { get; set; } = new();
        public MonitoringOptions Monitoring { get; set; } = new();
        public EvictionOptions Eviction { get; set; } = new();
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
@@ -75,10 +75,11 @@
    "SerializerType": "Newtonsoft", //序列化方式:Newtonsoft
    "FallbackToMemory": true, //Redis不可用时是否降级到内存缓存
    "KeyPrefix": "wcs:", //全局Key前缀,用于隔离不同系统的数据
    "EnableL1Cache": true, //是否启用L1内存缓存层。禁用后只使用Redis,适用于需要外部修改Redis数据的场景
    "EnableAutoSync": true, //是否启用Redis到内存缓存的自动同步
    "EnableL1Cache": false, //是否启用L1内存缓存层。禁用后只使用Redis,适用于需要外部修改Redis数据的场景
    "EnableAutoSync": false, //是否启用Redis到内存缓存的自动同步
    "SyncIntervalSeconds": 30, //自动同步间隔时间(秒),建议30-60秒
    "SyncBatchSize": 1000, //同步时单次批量获取的Redis key数量上限
    "SyncExcludePrefixes": [ "wcs:Code:SocketDevices:" ], //排除设备状态key不参与自动同步(防止覆盖本地修改)
    "Monitoring": {
      "Enabled": false, //是否启用监控
      "SlowLogThresholdMs": 100, //慢查询阈值(毫秒)
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -103,13 +103,13 @@
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    {
                        List<Dt_Router> routers = _routerService.QueryNextRoutes(item.SourceAddress, item.TargetAddress);
                        Dt_Router routers = _routerService.QueryNextRoute(item.SourceAddress);
                        //暂不考虑多路径
                        if (routers.Count > 0)
                        if (!routers.IsNullOrEmpty())
                        {
                            task.TaskState = (int)TaskInStatusEnum.InNew;
                            task.CurrentAddress = item.SourceAddress;
                            task.NextAddress = routers.FirstOrDefault().ChildPosi;
                            task.NextAddress = routers.ChildPosi;
                        }
                    }
                    tasks.Add(task);
@@ -118,7 +118,7 @@
                _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "接收WMS任务");
                content = WebResponseContent.Instance.OK("成功");
                content = WebResponseContent.Instance.OK("成功", tasks);
            }
            catch (Exception ex)
            {
@@ -397,6 +397,14 @@
                        task.TargetAddress = wmsTargetAddress;
                        task.CurrentAddress = task.NextAddress;
                    }
                    else
                    {
                        //_httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.GetTasksLocation), taskDto.ToJson(), nameof(ConfigKey.GetTasksLocation));
                        //if (!result.IsSuccess && !result.Data.Status)
                        //{
                        //    return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【{content.Message}】");
                        //}
                    }
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup)
                {
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotBarcodeGenerator.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹æ¡ç ç”Ÿæˆå™¨ - è´Ÿè´£ç”Ÿæˆæ‰˜ç›˜æ¡ç 
    /// </summary>
    public static class RobotBarcodeGenerator
    {
        /// <summary>
        /// ç”Ÿæˆæ‰˜ç›˜æ¡ç 
        /// </summary>
        /// <param name="prefix">条码前缀,默认为空</param>
        /// <returns>生成的条码字符串</returns>
        public static string GenerateTrayBarcode(string prefix = "")
        {
            // å½“前日期
            string datePart = DateTime.Now.ToString("yyyyMMdd");
            // æ—¶é—´æˆ³ï¼ˆæ—¶åˆ†ç§’)
            string timePart = DateTime.Now.ToString("HHmmss");
            // éšæœºæ•°
            string randomPart = Random.Shared.Next(100, 1000).ToString();
            // ç»„合:前缀 + æ—¥æœŸ + æ—¶é—´ + éšæœºæ•°
            return prefix + datePart + timePart + randomPart;
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotClientManager.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
using System.Collections.Concurrent;
using System.Net.Sockets;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_Tasks.SocketServer;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹å®¢æˆ·ç«¯è¿žæŽ¥ç®¡ç†å™¨ - è´Ÿè´£TCP客户端连接管理和事件订阅
    /// </summary>
    public class RobotClientManager
    {
        private readonly TcpSocketServer _tcpSocket;
        private readonly RobotStateManager _stateManager;
        // è·Ÿè¸ªå·²ç»å¯åЍ HandleClientAsync çš„客户端
        private static readonly ConcurrentDictionary<string, bool> _handleClientStarted = new();
        private static int _eventSubscribedFlag;
        public event EventHandler<RobotSocketState>? OnClientDisconnected;
        public RobotClientManager(TcpSocketServer tcpSocket, RobotStateManager stateManager)
        {
            _tcpSocket = tcpSocket;
            _stateManager = stateManager;
        }
        /// <summary>
        /// ç¡®ä¿å®¢æˆ·ç«¯å·²è¿žæŽ¥å¹¶è®¢é˜…消息事件
        /// </summary>
        /// <param name="ipAddress">设备IP地址</param>
        /// <param name="robotCrane">机器人设备信息</param>
        /// <returns>客户端是否可用(已连接且消息处理已启动)</returns>
        public bool EnsureClientSubscribed(string ipAddress, RobotCraneDevice robotCrane)
        {
            // æ£€æŸ¥æ˜¯å¦æœ‰è¯¥å®¢æˆ·ç«¯è¿žæŽ¥
            var clientIds = _tcpSocket.GetClientIds();
            bool isClientConnected = clientIds.Contains(ipAddress);
            if (!isClientConnected)
            {
                // å®¢æˆ·ç«¯æœªè¿žæŽ¥ï¼Œæ¸…理 HandleClientAsync çŠ¶æ€
                _handleClientStarted.TryRemove(ipAddress, out _);
                return false;
            }
            // è®¢é˜…一次 robot äº‹ä»¶ï¼ˆå…¨å±€ä¸€æ¬¡ï¼‰- message事件由RobotJob订阅
            if (System.Threading.Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
            {
                _tcpSocket.RobotReceived += OnRobotReceived;
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] æœºå™¨äººTCP断开事件已订阅");
            }
            // èŽ·å–TcpClient
            TcpClient? tcpClient = null;
            _tcpSocket._clients.TryGetValue(ipAddress, out tcpClient);
            if (tcpClient == null)
            {
                // isClientConnected为true但无法获取tcpClient,列表可能不同步
                _handleClientStarted.TryRemove(ipAddress, out _);
                return false;
            }
            // æ£€æŸ¥æ˜¯å¦å·²ç»ä¸ºè¿™ä¸ªå®¢æˆ·ç«¯å¯åŠ¨è¿‡ HandleClientAsync
            bool alreadyStarted = _handleClientStarted.TryGetValue(ipAddress, out _);
            if (!alreadyStarted)
            {
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] å¯åŠ¨å®¢æˆ·ç«¯æ¶ˆæ¯å¤„ç†: {ipAddress}");
                // é‡æ–°èŽ·å–æœ€æ–°çš„ state å¯¹è±¡
                var latestStateForSubscribe = _stateManager.GetState(ipAddress);
                if (latestStateForSubscribe != null)
                {
                    // æ ‡è®°ä¸ºå·²å¯åЍ
                    _handleClientStarted[ipAddress] = true;
                    _ = _tcpSocket.HandleClientAsync(tcpClient, robotCrane.IPAddress, _tcpSocket._cts.Token, latestStateForSubscribe)
                        .ContinueWith(t =>
                        {
                            if (t.IsFaulted)
                            {
                                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
                                // å‘生错误时,移除启动标志,允许下次重试
                                _handleClientStarted.TryRemove(ipAddress, out _);
                            }
                        }, TaskContinuationOptions.OnlyOnFaulted);
                    // æ›´æ–° IsEventSubscribed çŠ¶æ€
                    _stateManager.TryUpdateStateSafely(ipAddress, s =>
                    {
                        s.IsEventSubscribed = true;
                        return s;
                    });
                }
            }
            return true;
        }
        /// <summary>
        /// äº‹ä»¶ï¼šå®¢æˆ·ç«¯æ–­å¼€è¿žæŽ¥æ—¶è§¦å‘
        /// </summary>
        private Task<string?> OnRobotReceived(string clientId)
        {
            // å®¢æˆ·ç«¯æ–­å¼€è¿žæŽ¥ï¼Œæ¸…理 HandleClientAsync å¯åŠ¨æ ‡å¿—
            _handleClientStarted.TryRemove(clientId, out _);
            _stateManager.TryUpdateStateSafely(clientId, state =>
            {
                state.IsEventSubscribed = false;
                state.CurrentAction = "";
                state.OperStatus = "";
                state.RobotArmObject = 0;
                state.RobotControlMode = 0;
                state.RobotRunMode = 0;
                return state;
            });
            // è§¦å‘断开连接事件
            OnClientDisconnected?.Invoke(this, _stateManager.GetState(clientId) ?? new RobotSocketState { IPAddress = clientId });
            return Task.FromResult<string?>(null);
        }
        /// <summary>
        /// æ£€æŸ¥å®¢æˆ·ç«¯æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsClientConnected(string ipAddress)
        {
            var clientIds = _tcpSocket.GetClientIds();
            return clientIds.Contains(ipAddress);
        }
        /// <summary>
        /// å‘送消息到客户端
        /// </summary>
        public async Task<bool> SendToClientAsync(string ipAddress, string message)
        {
            return await _tcpSocket.SendToClientAsync(ipAddress, message);
        }
        /// <summary>
        /// èŽ·å–TcpSocketServer引用(用于RobotJob直接访问)
        /// </summary>
        public TcpSocketServer TcpSocket => _tcpSocket;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
@@ -1,19 +1,8 @@
using HslCommunication;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
using Quartz;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
@@ -21,34 +10,55 @@
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹ä»»åŠ¡ä½œä¸š - è´Ÿè´£åè°ƒæœºæ¢°æ‰‹å®¢æˆ·ç«¯è¿žæŽ¥ã€æ¶ˆæ¯å¤„理和任务执行
    /// </summary>
    [DisallowConcurrentExecution]
    public class RobotJob : IJob
    {
        private const int MaxTaskTotalNum = 48;
        private readonly TcpSocketServer _TcpSocket;
        private static int _messageSubscribedFlag;
        //private static readonly ConcurrentDictionary<string, RobotSocketState> _socketStates = new();
        private static int _eventSubscribedFlag;
        private readonly ITaskService _taskService;
        private readonly RobotClientManager _clientManager;
        private readonly RobotStateManager _stateManager;
        private readonly RobotMessageHandler _messageHandler;
        private readonly RobotTaskProcessor _taskProcessor;
        private readonly IRobotTaskService _robotTaskService;
        private readonly ICacheService _cache;
        private readonly HttpClientHelper _httpClientHelper;
        private static IRobotTaskService _latestRobotTaskService = null!;
        private static ITaskService _latestTaskService = null!;
        public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService RobottaskService, ITaskService TaskService, ICacheService cache, HttpClientHelper httpClientHelper)
        public RobotJob(
            TcpSocketServer tcpSocket,
            IRobotTaskService robotTaskService,
            ITaskService taskService,
            ICacheService cache,
            HttpClientHelper httpClientHelper)
        {
            _TcpSocket = TcpSocket;
            _robotTaskService = RobottaskService;
            _taskService = TaskService;
            _cache = cache;
            _httpClientHelper = httpClientHelper;
            _robotTaskService = robotTaskService;
            _latestRobotTaskService = RobottaskService;
            _latestTaskService = TaskService;
            // åˆå§‹åŒ–管理器
            _stateManager = new RobotStateManager(cache);
            _taskProcessor = new RobotTaskProcessor(tcpSocket, _stateManager, robotTaskService, taskService, httpClientHelper);
            _clientManager = new RobotClientManager(tcpSocket, _stateManager);
            _messageHandler = new RobotMessageHandler(tcpSocket, _stateManager, cache, robotTaskService, _taskProcessor);
            // è®¢é˜…客户端管理器的事件
            _clientManager.OnClientDisconnected += OnClientDisconnected;
            // è®¢é˜…TCP服务器的消息事件(全局只订阅一次)
            if (System.Threading.Interlocked.CompareExchange(ref _messageSubscribedFlag, 1, 0) == 0)
            {
                tcpSocket.MessageReceived += _messageHandler.HandleMessageReceivedAsync;
                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] æœºå™¨äººTCP消息事件已订阅");
            }
        }
        /// <summary>
        /// å®¢æˆ·ç«¯æ–­å¼€è¿žæŽ¥æ—¶çš„处理
        /// </summary>
        private void OnClientDisconnected(object? sender, RobotSocketState state)
        {
            // å¯ä»¥åœ¨è¿™é‡Œæ·»åŠ æ–­å¼€è¿žæŽ¥åŽçš„å¤„ç†é€»è¾‘
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] å®¢æˆ·ç«¯å·²æ–­å¼€è¿žæŽ¥: {state.IPAddress}");
        }
        public async Task Execute(IJobExecutionContext context)
@@ -63,512 +73,118 @@
            string ipAddress = robotCrane.IPAddress;
            // èŽ·å–æˆ–åˆ›å»ºçŠ¶æ€
            RobotSocketState state = _cache.GetOrAdd($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress}", _ => new RobotSocketState
            {
                IPAddress = ipAddress,
                RobotCrane = robotCrane
            });
            // æ›´æ–°è®¾å¤‡ä¿¡æ¯
            RobotSocketState state = _stateManager.GetOrCreateState(ipAddress, robotCrane);
            state.RobotCrane = robotCrane;
            try
            {
                // æ£€æŸ¥æ˜¯å¦æœ‰è¯¥å®¢æˆ·ç«¯è¿žæŽ¥
                var clientIds = _TcpSocket.GetClientIds();
                if (!clientIds.Contains(ipAddress))
                // ç¡®ä¿å®¢æˆ·ç«¯å·²è¿žæŽ¥å¹¶è®¢é˜…消息事件
                if (!_clientManager.EnsureClientSubscribed(ipAddress, robotCrane))
                {
                    return;
                    return; // å®¢æˆ·ç«¯æœªè¿žæŽ¥æˆ–订阅失败,跳过本次执行
                }
                // è®¢é˜…一次 message äº‹ä»¶ï¼ˆå…¨å±€ä¸€æ¬¡ï¼‰
                if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
                {
                    _TcpSocket.MessageReceived += _TcpSocket_MessageReceived;
                    _TcpSocket.RobotReceived += _TcpSocket_RobotReceived;
                }
                if (!state.IsEventSubscribed)
                {
                    if (_TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client))
                    {
                        _ = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state)
                            .ContinueWith(t =>
                            {
                                if (t.IsFaulted)
                                    Console.WriteLine($"HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
                            }, TaskContinuationOptions.OnlyOnFaulted);
                        state.IsEventSubscribed = true;
                        // æ›´æ–°ç¼“存中的状态
                        _cache.TryUpdateIfChanged($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress}", state);
                    }
                }
                // èŽ·å–ä»»åŠ¡å¹¶ç¼“å­˜åˆ°çŠ¶æ€ä¸­
                Dt_RobotTask? task = GetTask(robotCrane);
                // èŽ·å–ä»»åŠ¡å¹¶å¤„ç†
                Dt_RobotTask? task = _taskProcessor.GetTask(robotCrane);
                if (task != null)
                {
                    if (task.RobotTaskTotalNum <= MaxTaskTotalNum)
                    // æ¯æ¬¡åˆ¤æ–­å‰é‡æ–°ä»Žç¼“存获取最新状态
                    var latestState = _stateManager.GetState(ipAddress);
                    if (latestState == null) return;
                    if (latestState.RobotTaskTotalNum < MaxTaskTotalNum)
                    {
                        // å¤„理正在执行的任务
                        if (state.RobotRunMode == 2 && state.RobotControlMode == 1 && state.OperStatus != "Running")
                        {
                            if (state.CurrentAction == "PickFinished" && state.RobotArmObject == 1 && task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode())
                            {
                                string taskString = $"Putbattery,{task.RobotTargetAddress}";
                                bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
                                if (result)
                                {
                                    task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                                    await _robotTaskService.UpdateRobotTaskAsync(task);
                                }
                            }
                            else if (state.CurrentAction == "PutFinished" && state.RobotArmObject == 0 && task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode())
                            {
                                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                                await _robotTaskService.UpdateRobotTaskAsync(task);
                            }
                            else if (state.OperStatus == "Homed" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
                            {
                                // éšæœºç”Ÿæˆä¸¤å¤©æ‰˜ç›˜æ¡ç å­˜æ”¾åˆ°ä¸¤ä¸ªå˜é‡é‡Œé¢
                                // å®šä¹‰å‰ç¼€ï¼ˆä¾‹å¦‚:TRAY代表托盘)
                                // ç»„盘读取线体条码
                                if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
                                {
                                    string prefix = "TRAY";
                                    // ç”Ÿæˆä¸¤ä¸ªæ‰˜ç›˜æ¡ç 
                                    string trayBarcode1 = GenerateTrayBarcode(state, prefix);
                                    string trayBarcode2 = GenerateTrayBarcode(state, prefix);
                                    if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty())
                                    {
                                        await SendSocketRobotPickAsync(task, state);
                                    }
                                }
                                else // æ¢ç›˜ç›´æŽ¥å‘送取货地址
                                {
                                    await SendSocketRobotPickAsync(task, state);
                                }
                            }
                            if (state.CurrentTask.IsNullOrEmpty() && state.ToJson() != task.ToJson())
                            {
                                state.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode();
                                state.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
                                state.CurrentTask = task;
                                // æ›´æ–°ç¼“存中的状态
                                _cache.TryUpdateIfChanged($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress}", state);
                            }
                        }
                        await ProcessTaskAsync(latestState, task, ipAddress);
                    }
                }
            }
            catch (Exception)
            {
                // å¼‚常处理已在各组件中处理
            }
            finally
            {
                // å¯é€‰ï¼šåœ¨è¿™é‡Œå¤„理任何需要在任务完成后执行的清理工作
            }
        }
        //临时测试用
        private static string GenerateTrayBarcode(RobotSocketState state, string prefix = "")
        {
            // å½“前日期
            string datePart = DateTime.Now.ToString("yyyyMMdd");
            // æ—¶é—´æˆ³ï¼ˆæ—¶åˆ†ç§’)
            string timePart = DateTime.Now.ToString("HHmmss");
            // éšæœºæ•°
            string randomPart = Random.Shared.Next(100, 1000).ToString();
            // ç»„合:前缀 + æ—¥æœŸ + æ—¶é—´ + éšæœºæ•°
            var barCode = prefix + datePart + timePart + randomPart;
            state.CellBarcode.Add(barCode);
            return barCode;
        }
        /// <summary>
        ///  äº‹ä»¶ï¼šå®¢æˆ·ç«¯æ–­å¼€è¿žæŽ¥æ—¶è§¦å‘
        /// å¤„理机械手任务
        /// </summary>
        /// <param name="clientId"></param>
        /// <returns></returns>
        private Task<string?> _TcpSocket_RobotReceived(string clientId)
        private async Task ProcessTaskAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress)
        {
            var robotSocketState = _cache.Get<RobotSocketState>($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{clientId}");
            robotSocketState.IsEventSubscribed = false;
            robotSocketState.CurrentAction = "";
            robotSocketState.OperStatus = "";
            robotSocketState.RobotArmObject = 0;
            robotSocketState.RobotControlMode = 0;
            robotSocketState.RobotRunMode = 0;
            _cache.TryUpdateIfChanged($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{clientId}", robotSocketState);
            return Task.FromResult<string?>(null);
        }
        /// <summary>
        /// äº‹ä»¶ï¼šæ”¶åˆ°æ¶ˆæ¯æ—¶è§¦å‘
        /// </summary>
        /// <param name="message"></param>
        /// <param name="isJson"></param>
        /// <param name="client"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task<string?> _TcpSocket_MessageReceived(string message, bool isJson, TcpClient client, RobotSocketState state)
        {
            if (!(bool)(_cache?.TryGetValue($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{client.Client.RemoteEndPoint}", out state)))
                return null;
            string messageLower = message.ToLowerInvariant();
            if (await IsSimpleCommandAsync(messageLower, state))
            // å¤„理正在执行的任务
            if (latestState.RobotRunMode == 2 && latestState.RobotControlMode == 1 && latestState.OperStatus != "Running")
            {
                await _TcpSocket.SendMessageAsync(client, message);
            }
            else if (IsPrefixCommand(messageLower))
            {
                try
                // å–货完成状态处理
                if ((latestState.CurrentAction == "PickFinished" || latestState.CurrentAction == "AllPickFinished") && latestState.RobotArmObject == 1 &&
                    task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode())
                {
                    var parts = message.Split(',');
                    if (parts.Length >= 1 && state.CurrentTask != null)
                    {
                        var cmd = parts[0].ToLowerInvariant();
                        int[] positions = parts.Skip(1)
                           .Select(p => int.TryParse(p, out int value) ? value : (int?)null)
                           .Where(v => v.HasValue && v.Value != 0)
                           .Select(v => v!.Value)
                           .ToArray();
                        var task = await _latestRobotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId);
                        if (cmd.StartsWith("pickfinished"))
                        {
                            if (state.IsSplitPallet)
                            {
                                var stockDTO = BuildStockDTO(state, positions);
                                state.LastPickPositions = positions;
                                var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.SplitPalletAsync), stockDTO.ToJson());
                                if (result.Data.Status && result.IsSuccess)
                                {
                                    state.CurrentAction = "PickFinished";
                                }
                            }
                            else
                            {
                                state.CurrentAction = "PickFinished";
                            }
                            state.LastPickPositions = positions;
                            task.RobotTaskState = TaskRobotStatusEnum.RobotPickFinish.GetHashCode();
                            await _latestRobotTaskService.Repository.UpdateDataAsync(task);
                        }
                        else if (cmd.StartsWith("putfinished"))
                        {
                            bool putSuccess = true;
                            if (state.IsGroupPallet)
                            {
                                state.LastPutPositions = positions;
                                var stockDTO = BuildStockDTO(state, positions);
                                var configKey = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()
                                    ? nameof(ConfigKey.ChangePalletAsync) : nameof(ConfigKey.GroupPalletAsync);
                                var result = _httpClientHelper.Post<WebResponseContent>(configKey, stockDTO.ToJson());
                                putSuccess = result.Data.Status && result.IsSuccess;
                            }
                            if (putSuccess)
                            {
                                state.CurrentAction = "PutFinished";
                                state.RobotTaskTotalNum += positions.Length;
                                task.RobotTaskTotalNum += positions.Length;
                            }
                            task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode();
                            await _latestRobotTaskService.Repository.UpdateDataAsync(task);
                        }
                        await _TcpSocket.SendMessageAsync(client, message);
                    }
                    await HandlePickFinishedStateAsync(latestState, task, ipAddress);
                }
                catch (Exception ex)
                // æ”¾è´§å®ŒæˆçŠ¶æ€å¤„ç†
                else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished") && latestState.OperStatus == "Homed" &&
                    latestState.RobotArmObject == 0 &&
                    (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() ||
                    task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode()))
                {
                    Console.WriteLine($"RobotJob MessageReceived Error: {ex.Message}");
                    await HandlePutFinishedStateAsync(latestState, task, ipAddress);
                }
            }
            // æ›´æ–°ç¼“存中的状态
            _cache.TryUpdateIfChanged($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{state.IPAddress}", state);
            return null;
        }
        /// <summary>
        /// æœºæ¢°æ‰‹ç®€å•命令处理
        /// å¤„理取货完成状态
        /// </summary>
        /// <param name="message"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task<bool> IsSimpleCommandAsync(string message, RobotSocketState state)
        private async Task HandlePickFinishedStateAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress)
        {
            switch (message)
            {
                case "homing":
                    state.OperStatus = "Homing";
                    return true;
                case "homed":
                    state.OperStatus = "Homed";
                    return true;
                case "picking":
                    state.CurrentAction = "Picking";
                    return true;
                case "puting":
                    state.CurrentAction = "Putting";
                    return true;
                case "allpickfinished": // å–货完成
                    state.CurrentAction = "AllPickFinished";
                    if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode() || state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
                    {
                        await HandleInboundTaskAsync(state, useSourceAddress: true);
                    }
                    return true;
                case "allputfinished": // æ”¾è´§å®Œæˆ
                    state.CurrentAction = "AllPutFinished";
                    if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
                    {
                        await HandleInboundTaskAsync(state, useSourceAddress: false);
                    }
                    return true;
                case "running":
                    state.OperStatus = "Running";
                    return true;
                case "pausing":
                    state.OperStatus = "Pausing";
                    return true;
                case "warming":
                    state.OperStatus = "Warming";
                    return true;
                case "emstoping":
                    state.OperStatus = "Emstoping";
                    return true;
                case "runmode,1":
                    state.RobotRunMode = 1;
                    return true;
                case "runmode,2":
                    state.RobotRunMode = 2;
                    return true;
                case "controlmode,1":
                    state.RobotControlMode = 1;
                    return true;
                case "controlmode,2":
                    state.RobotControlMode = 2;
                    return true;
                case "armobject,1":
                    state.RobotArmObject = 1;
                    return true;
                case "armobject,0":
                    state.RobotArmObject = 0;
                    return true;
                default:
                    return false;
            }
        }
        private async Task HandleInboundTaskAsync(RobotSocketState state, bool useSourceAddress)
        {
            var currentTask = state.CurrentTask;
            if (currentTask == null)
            {
                return;
            }
            string roadway = currentTask.RobotRoadway == "1" ? "GWSC001" : currentTask.RobotRoadway == "2" ? "HCSC001" : "SC001";
            int warehouseId = currentTask.RobotRoadway == "1" ? 1 : currentTask.RobotRoadway == "2" ? 2 : 3;
            CreateTaskDto taskDto = new CreateTaskDto
            {
                PalletCode = currentTask.RobotTargetAddressPalletCode ?? string.Empty,
                SourceAddress = currentTask.RobotSourceAddress ?? string.Empty,
                TargetAddress = currentTask.RobotTargetAddress ?? string.Empty,
                Roadway = roadway,
                WarehouseId = warehouseId,
                PalletType = 1,
                TaskType = 4
            };
            var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.CreateTaskInboundAsync), taskDto.ToJson());
            if (!result.Data.Status && result.IsSuccess)
            {
                return;
            }
            WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.ToString() ?? string.Empty) ?? new WMSTaskDTO();
            var content = _latestTaskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
            if (!content.Status) return;
            var taskInfo = _latestTaskService.QueryByTaskNum(taskDTO.TaskNum);
            if (taskInfo == null) return;
            string targetAddress = useSourceAddress ? taskDTO.SourceAddress : taskDTO.TargetAddress;
            IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == targetAddress));
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.Target), taskInfo.NextAddress);
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.TaskNo), taskDTO.TaskNum);
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.WCS_STB), 1);
        }
        /// <summary>
        /// æœºæ¢°æ‰‹å‰ç¼€å‘½ä»¤å¤„理
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private static bool IsPrefixCommand(string message)
        {
            return message.StartsWith("pickfinished") || message.StartsWith("putfinished");
        }
        private static StockDTO BuildStockDTO(RobotSocketState state, int[] positions)
        {
            string sss = state.ToJson();
            return new StockDTO
            {
                SourceLineNo = state.CurrentTask.RobotSourceAddressLineCode,
                SourcePalletNo = state.CurrentTask.RobotSourceAddressPalletCode,
                TargetPalletNo = state.CurrentTask.RobotTargetAddressPalletCode,
                TargetLineNo = state.CurrentTask.RobotTargetAddressLineCode,
                Details = positions
                    .Where(x => x > 0)
                    .OrderBy(x => x)
                    .Select((x, idx) => new StockDetailDTO
                    {
                        Quantity = state.RobotTaskTotalNum > 0 ? state.RobotTaskTotalNum + positions.Length : positions.Length,
                        Channel = x,
                        CellBarcode = state.CellBarcode?.Count > 0 ? state.CellBarcode[x - 1] : ""
                    })
                    .ToList()
            };
        }
        private Dt_RobotTask? GetTask(RobotCraneDevice robotCrane)
        {
            return _robotTaskService.QueryRobotCraneTask(robotCrane.DeviceCode);
        }
        /// <summary>
        /// å‘送机械手取货命令
        /// </summary>
        /// <param name="task"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private async Task SendSocketRobotPickAsync(Dt_RobotTask task, RobotSocketState state)
        {
            string taskString = $"Pickbattery,{task.RobotSourceAddress}";
            // å‘送任务指令
            bool result = await _TcpSocket.SendToClientAsync(state.IPAddress, taskString);
            string taskString = $"Putbattery,{task.RobotTargetAddress}";
            bool result = await _clientManager.SendToClientAsync(ipAddress, taskString);
            if (result)
            {
                // TODO å¤„理成功发送任务指令后的逻辑
                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                result = await _robotTaskService.UpdateRobotTaskAsync(task);
                // æ›´æ–°ç¼“存中的状态
                _cache.TryUpdateIfChanged($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{state.IPAddress}", state);
                // é‡æ–°èŽ·å–æœ€æ–°çŠ¶æ€å¹¶æ›´æ–°
                var stateToUpdate = _stateManager.GetState(ipAddress);
                if (stateToUpdate != null)
                {
                    stateToUpdate.CurrentTask = task;
                    if (_stateManager.TryUpdateStateSafely(ipAddress, stateToUpdate))
                        await _robotTaskService.UpdateRobotTaskAsync(task);
                }
            }
        }
        /// <summary>
        /// å¤„理放货完成状态
        /// </summary>
        private async Task HandlePutFinishedStateAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress)
        {
            // é‡æ–°èŽ·å–æœ€æ–°çŠ¶æ€
            var stateForUpdate = _stateManager.GetState(ipAddress);
            if (stateForUpdate == null) return;
            if (!stateForUpdate.IsSplitPallet && !stateForUpdate.IsGroupPallet)
            {
                stateForUpdate.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode();
                stateForUpdate.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() ||
                    task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
            }
            if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
            {
                string prefix = "TRAY";
                // ç”Ÿæˆä¸¤ä¸ªæ‰˜ç›˜æ¡ç 
                string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
                string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
                if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty())
                {
                    stateForUpdate.CellBarcode.Add(trayBarcode1);
                    stateForUpdate.CellBarcode.Add(trayBarcode2);
                    await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
                }
            }
            else // ä»»åŠ¡å¼€å§‹æ‰§è¡Œç›´æŽ¥å‘é€å–è´§åœ°å€
            {
                await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
            }
        }
    }
    public class RobotSocketState
    {
        public string IPAddress { get; set; } = string.Empty;
        /// <summary>
        /// æ˜¯å¦å·²è®¢é˜…消息事件
        /// </summary>
        public bool IsEventSubscribed { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è¿è¡Œæ¨¡å¼
        /// </summary>
        public int? RobotRunMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æŽ§åˆ¶æ¨¡å¼
        /// </summary>
        public int? RobotControlMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æ˜¯å¦æŠ“取物料,0-无物料,1-有物料
        /// </summary>
        public int? RobotArmObject { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è®¾å¤‡ä¿¡æ¯
        /// </summary>
        public RobotCraneDevice? RobotCrane { get; set; }
        /// <summary>
        /// å½“前动作
        /// </summary>
        public string? CurrentAction { get; set; }
        /// <summary>
        /// å½“前状态
        /// </summary>
        public string? OperStatus { get; set; }
        /// <summary>
        /// å–货完成位置
        /// </summary>
        public int[]? LastPickPositions { get; set; }
        /// <summary>
        /// æ”¾è´§å®Œæˆä½ç½®
        /// </summary>
        public int[]? LastPutPositions { get; set; }
        /// <summary>
        /// æŠ“取位置条码
        /// </summary>
        public List<string> CellBarcode { get; set; }
        /// <summary>
        /// å½“前抓取任务
        /// </summary>
        public Dt_RobotTask? CurrentTask { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦æ‹†ç›˜
        /// </summary>
        public bool IsSplitPallet { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦ç»„盘
        /// </summary>
        public bool IsGroupPallet { get; set; }
        /// <summary>
        /// ä»»åŠ¡æ€»æ•°
        /// </summary>
        public int RobotTaskTotalNum { get; set; }
    }
}
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotMessageHandler.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,275 @@
using System.Net.Sockets;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Tasks.SocketServer;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹æ¶ˆæ¯å¤„理器 - è´Ÿè´£å¤„理来自TCP客户端的消息
    /// </summary>
    public class RobotMessageHandler
    {
        private readonly TcpSocketServer _tcpSocket;
        private readonly RobotStateManager _stateManager;
        private readonly ICacheService _cache;
        private readonly IRobotTaskService _robotTaskService;
        private readonly RobotTaskProcessor _taskProcessor;
        public RobotMessageHandler(
            TcpSocketServer tcpSocket,
            RobotStateManager stateManager,
            ICacheService cache,
            IRobotTaskService robotTaskService,
            RobotTaskProcessor taskProcessor)
        {
            _tcpSocket = tcpSocket;
            _stateManager = stateManager;
            _cache = cache;
            _robotTaskService = robotTaskService;
            _taskProcessor = taskProcessor;
        }
        /// <summary>
        /// å¤„理接收到的消息
        /// </summary>
        public async Task<string?> HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state)
        {
            if (!(_cache?.TryGetValue($"{RedisPrefix.Code}:{RedisName.SocketDevices}:{client.Client.RemoteEndPoint}", out state)) ?? false)
                return null;
            string messageLower = message.ToLowerInvariant();
            if (await IsSimpleCommandAsync(messageLower, state))
            {
                await _tcpSocket.SendMessageAsync(client, message);
                if (_stateManager.TryUpdateStateSafely(state.IPAddress, state))
                    return null;
            }
            else if (IsPrefixCommand(messageLower))
            {
                await HandlePrefixCommandAsync(message, state, client);
            }
            return null;
        }
        /// <summary>
        /// å¤„理前缀命令(pickfinished, putfinished)
        /// </summary>
        private async Task HandlePrefixCommandAsync(string message, RobotSocketState state, TcpClient client)
        {
            try
            {
                var parts = message.Split(',');
                if (parts.Length >= 1 && state.CurrentTask != null)
                {
                    var cmd = parts[0].ToLowerInvariant();
                    int[] positions = parts.Skip(1)
                       .Select(p => int.TryParse(p, out int value) ? value : (int?)null)
                       .Where(v => v.HasValue && v.Value != 0)
                       .Select(v => v!.Value)
                       .ToArray();
                    var task = await _robotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId);
                    if (cmd.StartsWith("pickfinished"))
                    {
                        await HandlePickFinishedAsync(state, positions, task, client);
                    }
                    else if (cmd.StartsWith("putfinished"))
                    {
                        await HandlePutFinishedAsync(state, positions, task, client);
                    }
                    await _tcpSocket.SendMessageAsync(client, message);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"RobotJob MessageReceived Error: {ex.Message}");
            }
        }
        /// <summary>
        /// å¤„理取货完成命令
        /// </summary>
        private async Task HandlePickFinishedAsync(RobotSocketState state, int[] positions, Dt_RobotTask? task, TcpClient client)
        {
            if (state.IsSplitPallet)
            {
                var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions);
                state.LastPickPositions = positions;
                var result = _taskProcessor.PostSplitPalletAsync(stockDTO);
                if (result.Data.Status && result.IsSuccess)
                {
                    state.CurrentAction = "PickFinished";
                }
            }
            else
            {
                state.CurrentAction = "PickFinished";
            }
            state.LastPickPositions = positions;
            if (task != null)
            {
                task.RobotTaskState = TaskRobotStatusEnum.RobotPickFinish.GetHashCode();
                if (_stateManager.TryUpdateStateSafely(state.IPAddress, state))
                    await _robotTaskService.Repository.UpdateDataAsync(task);
            }
        }
        /// <summary>
        /// å¤„理放货完成命令
        /// </summary>
        private async Task HandlePutFinishedAsync(RobotSocketState state, int[] positions, Dt_RobotTask? task, TcpClient client)
        {
            bool putSuccess = true;
            if (state.IsGroupPallet)
            {
                state.LastPutPositions = positions;
                var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions);
                var configKey = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()
                    ? nameof(ConfigKey.ChangePalletAsync) : nameof(ConfigKey.GroupPalletAsync);
                var result = _taskProcessor.PostGroupPalletAsync(configKey, stockDTO);
                putSuccess = result.Data.Status && result.IsSuccess;
            }
            if (putSuccess)
            {
                state.CurrentAction = "PutFinished";
                state.RobotTaskTotalNum += positions.Length;
                if (task != null)
                {
                    task.RobotTaskTotalNum += positions.Length;
                }
            }
            if (task != null)
            {
                task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode();
                if (_stateManager.TryUpdateStateSafely(state.IPAddress, state))
                    await _robotTaskService.Repository.UpdateDataAsync(task);
            }
        }
        /// <summary>
        /// æœºæ¢°æ‰‹ç®€å•命令处理
        /// </summary>
        private async Task<bool> IsSimpleCommandAsync(string message, RobotSocketState state)
        {
            RobotTaskTypeEnum? GetRobotTaskType() => state.CurrentTask != null ? (RobotTaskTypeEnum)state.CurrentTask.RobotTaskType : null;
            switch (message)
            {
                case "homing":
                    state.OperStatus = "Homing";
                    return true;
                case "homed":
                    state.OperStatus = "Homed";
                    return true;
                case "picking":
                    state.CurrentAction = "Picking";
                    return true;
                case "puting":
                    state.CurrentAction = "Putting";
                    return true;
                case "allpickfinished": // å–货完成
                    state.CurrentAction = "AllPickFinished";
                    var robotTaskType = GetRobotTaskType();
                    if (robotTaskType == RobotTaskTypeEnum.SplitPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet)
                    {
                        if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true))
                        {
                            _taskProcessor.DeleteTask(state.CurrentTask.RobotTaskId);
                            return true;
                        }
                    }
                    return false;
                case "allputfinished": // æ”¾è´§å®Œæˆ
                    state.CurrentAction = "AllPutFinished";
                    robotTaskType = GetRobotTaskType();
                    if (robotTaskType == RobotTaskTypeEnum.GroupPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet)
                    {
                        if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false))
                        {
                            _taskProcessor.DeleteTask(state.CurrentTask.RobotTaskId);
                            state.CurrentTask = null;
                            state.RobotTaskTotalNum = 0;
                            state.CellBarcode = new List<string>();
                            return true;
                        }
                    }
                    return false;
                case "running":
                    state.OperStatus = "Running";
                    return true;
                case "pausing":
                    state.OperStatus = "Pausing";
                    return true;
                case "warming":
                    state.OperStatus = "Warming";
                    return true;
                case "emstoping":
                    state.OperStatus = "Emstoping";
                    return true;
                case "runmode,1":
                    state.RobotRunMode = 1;
                    return true;
                case "runmode,2":
                    state.RobotRunMode = 2;
                    return true;
                case "controlmode,1":
                    state.RobotControlMode = 1;
                    return true;
                case "controlmode,2":
                    state.RobotControlMode = 2;
                    return true;
                case "armobject,1":
                    state.RobotArmObject = 1;
                    return true;
                case "armobject,0":
                    state.RobotArmObject = 0;
                    return true;
                default:
                    return false;
            }
        }
        /// <summary>
        /// åˆ¤æ–­æ˜¯å¦ä¸ºå‰ç¼€å‘½ä»¤
        /// </summary>
        private static bool IsPrefixCommand(string message)
        {
            return message.StartsWith("pickfinished") || message.StartsWith("putfinished");
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹Socket通信状态
    /// </summary>
    public class RobotSocketState
    {
        public string IPAddress { get; set; } = string.Empty;
        /// <summary>
        /// ç‰ˆæœ¬å·ï¼Œç”¨äºŽé˜²æ­¢å¹¶å‘更新时旧值覆盖新值
        /// æ¯æ¬¡ä¿®æ”¹çŠ¶æ€æ—¶éƒ½åº”è¯¥æ›´æ–°æ­¤å€¼
        /// </summary>
        public long Version { get; set; } = DateTime.UtcNow.Ticks;
        /// <summary>
        /// æ˜¯å¦å·²è®¢é˜…消息事件
        /// </summary>
        public bool IsEventSubscribed { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è¿è¡Œæ¨¡å¼
        /// </summary>
        public int? RobotRunMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æŽ§åˆ¶æ¨¡å¼
        /// </summary>
        public int? RobotControlMode { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹æ˜¯å¦æŠ“取物料,0-无物料,1-有物料
        /// </summary>
        public int? RobotArmObject { get; set; }
        /// <summary>
        /// æœºæ¢°æ‰‹è®¾å¤‡ä¿¡æ¯
        /// </summary>
        public RobotCraneDevice? RobotCrane { get; set; }
        /// <summary>
        /// å½“前动作
        /// </summary>
        public string? CurrentAction { get; set; }
        /// <summary>
        /// å½“前状态
        /// </summary>
        public string? OperStatus { get; set; }
        /// <summary>
        /// å–货完成位置
        /// </summary>
        public int[]? LastPickPositions { get; set; }
        /// <summary>
        /// æ”¾è´§å®Œæˆä½ç½®
        /// </summary>
        public int[]? LastPutPositions { get; set; }
        /// <summary>
        /// æŠ“取位置条码
        /// </summary>
        public List<string> CellBarcode { get; set; } = new List<string>();
        /// <summary>
        /// å½“前抓取任务
        /// </summary>
        public Dt_RobotTask? CurrentTask { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦æ‹†ç›˜
        /// </summary>
        public bool IsSplitPallet { get; set; }
        /// <summary>
        /// æ˜¯å¦éœ€è¦ç»„盘
        /// </summary>
        public bool IsGroupPallet { get; set; }
        /// <summary>
        /// ä»»åŠ¡æ€»æ•°
        /// </summary>
        public int RobotTaskTotalNum { get; set; }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotStateManager.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
using Newtonsoft.Json;
using WIDESEAWCS_Common;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_QuartzJob;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹çŠ¶æ€ç®¡ç†å™¨ - è´Ÿè´£RobotSocketState的安全更新和克隆
    /// </summary>
    public class RobotStateManager
    {
        private readonly ICacheService _cache;
        public RobotStateManager(ICacheService cache)
        {
            _cache = cache;
        }
        /// <summary>
        /// å®‰å…¨æ›´æ–°RobotSocketState缓存,防止并发覆盖
        /// </summary>
        /// <param name="ipAddress">设备IP地址</param>
        /// <param name="updateAction">更新状态的委托(传入当前状态,返回修改后的新状态)</param>
        /// <returns>是否更新成功</returns>
        public bool TryUpdateStateSafely(string ipAddress, Func<RobotSocketState, RobotSocketState> updateAction)
        {
            var cacheKey = GetCacheKey(ipAddress);
            var currentState = _cache.Get<RobotSocketState>(cacheKey);
            if (currentState == null)
            {
                return false;
            }
            // ä½¿ç”¨å½“前存储的版本号作为期望版本
            var expectedVersion = currentState.Version;
            // åˆ›å»ºçŠ¶æ€å‰¯æœ¬è¿›è¡Œä¿®æ”¹ï¼ˆé¿å…ä¿®æ”¹åŽŸå¯¹è±¡å¼•ç”¨ï¼‰
            var stateCopy = CloneState(currentState);
            var newState = updateAction(stateCopy);
            newState.Version = DateTime.UtcNow.Ticks;
            return _cache.TrySafeUpdate(
                cacheKey,
                newState,
                expectedVersion,
                s => s.Version
            );
        }
        /// <summary>
        /// å®‰å…¨æ›´æ–°RobotSocketState缓存(简单版本)
        /// </summary>
        /// <param name="ipAddress">设备IP地址</param>
        /// <param name="newState">新状态(会被更新Version字段)</param>
        /// <returns>是否更新成功</returns>
        public bool TryUpdateStateSafely(string ipAddress, RobotSocketState newState)
        {
            var cacheKey = GetCacheKey(ipAddress);
            var currentState = _cache.Get<RobotSocketState>(cacheKey);
            if (currentState == null)
            {
                // å½“前不存在,直接添加
                newState.Version = DateTime.UtcNow.Ticks;
                _cache.AddObject(cacheKey, newState);
                return true;
            }
            // ä½¿ç”¨å½“前存储的版本号作为期望版本
            var expectedVersion = currentState.Version;
            // æ›´æ–°æ–°çŠ¶æ€çš„ç‰ˆæœ¬å·ä¸ºæœ€æ–°æ—¶é—´æˆ³
            newState.Version = DateTime.UtcNow.Ticks;
            return _cache.TrySafeUpdate(
                cacheKey,
                newState,
                expectedVersion,
                s => s.Version
            );
        }
        /// <summary>
        /// å…‹éš†RobotSocketState对象(创建深拷贝)
        /// </summary>
        public RobotSocketState CloneState(RobotSocketState source)
        {
            // ä½¿ç”¨åºåˆ—化/反序列化进行深拷贝
            var json = JsonConvert.SerializeObject(source);
            return JsonConvert.DeserializeObject<RobotSocketState>(json) ?? new RobotSocketState { IPAddress = source.IPAddress };
        }
        /// <summary>
        /// èŽ·å–Redis缓存键
        /// </summary>
        public static string GetCacheKey(string ipAddress)
        {
            return $"{RedisPrefix.Code}:{RedisName.SocketDevices}:{ipAddress}";
        }
        /// <summary>
        /// ä»Žç¼“存获取状态
        /// </summary>
        public RobotSocketState? GetState(string ipAddress)
        {
            return _cache.Get<RobotSocketState>(GetCacheKey(ipAddress));
        }
        /// <summary>
        /// èŽ·å–æˆ–åˆ›å»ºçŠ¶æ€
        /// </summary>
        public RobotSocketState GetOrCreateState(string ipAddress, RobotCraneDevice robotCrane)
        {
            return _cache.GetOrAdd(GetCacheKey(ipAddress), _ => new RobotSocketState
            {
                IPAddress = ipAddress,
                RobotCrane = robotCrane
            });
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,207 @@
using Newtonsoft.Json;
using WIDESEA_Core;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_Tasks.SocketServer;
namespace WIDESEAWCS_Tasks
{
    /// <summary>
    /// æœºæ¢°æ‰‹ä»»åŠ¡å¤„ç†å™¨ - è´Ÿè´£æœºæ¢°æ‰‹ä»»åŠ¡æ‰§è¡Œå’Œå¤„ç†
    /// </summary>
    public class RobotTaskProcessor
    {
        private readonly TcpSocketServer _tcpSocket;
        private readonly RobotStateManager _stateManager;
        private readonly IRobotTaskService _robotTaskService;
        private readonly ITaskService _taskService;
        private readonly HttpClientHelper _httpClientHelper;
        public RobotTaskProcessor(
            TcpSocketServer tcpSocket,
            RobotStateManager stateManager,
            IRobotTaskService robotTaskService,
            ITaskService taskService,
            HttpClientHelper httpClientHelper)
        {
            _tcpSocket = tcpSocket;
            _stateManager = stateManager;
            _robotTaskService = robotTaskService;
            _taskService = taskService;
            _httpClientHelper = httpClientHelper;
        }
        /// <summary>
        /// èŽ·å–æœºæ¢°æ‰‹ä»»åŠ¡
        /// </summary>
        public Dt_RobotTask? GetTask(RobotCraneDevice robotCrane)
        {
            return _robotTaskService.QueryRobotCraneTask(robotCrane.DeviceCode);
        }
        /// <summary>
        /// èŽ·å–æœºæ¢°æ‰‹ä»»åŠ¡
        /// </summary>
        public bool? DeleteTask(int ID)
        {
            return _robotTaskService.Repository.DeleteDataById(ID);
        }
        /// <summary>
        /// å‘送机械手取货命令
        /// </summary>
        public async Task SendSocketRobotPickAsync(Dt_RobotTask task, RobotSocketState state)
        {
            string taskString = $"Pickbattery,{task.RobotSourceAddress}";
            // å‘送任务指令
            bool result = await _tcpSocket.SendToClientAsync(state.IPAddress, taskString);
            if (result)
            {
                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                state.CurrentTask = task;
                // æ›´æ–°ç¼“存中的状态(使用安全更新防止并发覆盖)
                if (_stateManager.TryUpdateStateSafely(state.IPAddress, state))
                    await _robotTaskService.UpdateRobotTaskAsync(task);
            }
        }
        /// <summary>
        /// å¤„理入库任务
        /// </summary>
        public async Task<bool> HandleInboundTaskAsync(RobotSocketState state, bool useSourceAddress)
        {
            var currentTask = state.CurrentTask;
            if (currentTask == null)
            {
                return false;
            }
            string roadway = currentTask.RobotSourceAddressLineCode;
            int warehouseId = currentTask.RobotRoadway == "ZYRB1" ? 1 : currentTask.RobotRoadway == "HPRB001" ? 2 : 3;
            int taskType = 0;
            string SourceAddress = currentTask.RobotTargetAddressLineCode;
            string TargetAddress = currentTask.RobotSourceAddressLineCode;
            string PalletCode = string.Empty;
            // ç›´æŽ¥è½¬æ¢ä¸ºæžšä¸¾ç±»åž‹è¿›è¡Œæ¯”较
            var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType;
            if (useSourceAddress)
            {
                switch (robotTaskType)
                {
                    case RobotTaskTypeEnum.GroupPallet:
                        return false;
                    case RobotTaskTypeEnum.ChangePallet:
                    case RobotTaskTypeEnum.SplitPallet:
                        taskType = TaskTypeEnum.InEmpty.GetHashCode();
                        PalletCode = currentTask.RobotSourceAddressPalletCode;
                        break;
                }
            }
            else
            {
                switch (robotTaskType)
                {
                    case RobotTaskTypeEnum.ChangePallet:
                    case RobotTaskTypeEnum.GroupPallet:
                        taskType = TaskTypeEnum.Inbound.GetHashCode();
                        PalletCode = currentTask.RobotTargetAddressPalletCode;
                        break;
                    case RobotTaskTypeEnum.SplitPallet:
                        return true;
                }
            }
            CreateTaskDto taskDto = new CreateTaskDto
            {
                PalletCode = PalletCode,
                SourceAddress = SourceAddress ?? string.Empty,
                TargetAddress = TargetAddress ?? string.Empty,
                Roadway = roadway,
                WarehouseId = warehouseId,
                PalletType = 1,
                TaskType = taskType
            };
            var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.CreateTaskInboundAsync), taskDto.ToJson());
            if (!result.Data.Status && result.IsSuccess)
            {
                return false;
            }
            WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data.ToJson() ?? string.Empty) ?? new WMSTaskDTO();
            var content = _taskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
            if (!content.Status) return false;
            var taskInfo = JsonConvert.DeserializeObject<Dt_Task>(content.Data.ToJson() ?? string.Empty) ?? new Dt_Task();
            string sourceAddress = taskDTO.SourceAddress;
            IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress));
            if (device != null)
            {
                CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
                conveyorLine.SetValue(ConveyorLineDBNameNew.Target, taskInfo.NextAddress, sourceAddress);
                conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress);
                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_STB, 1, sourceAddress);
                if (_taskService.UpdateTaskStatusToNext(taskInfo).Status)
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// æž„建库存DTO
        /// </summary>
        public static StockDTO BuildStockDTO(RobotSocketState state, int[] positions)
        {
            return new StockDTO
            {
                SourceLineNo = state.CurrentTask.RobotSourceAddressLineCode,
                SourcePalletNo = state.CurrentTask.RobotSourceAddressPalletCode,
                TargetPalletNo = state.CurrentTask.RobotTargetAddressPalletCode,
                TargetLineNo = state.CurrentTask.RobotTargetAddressLineCode,
                Details = positions
                    .Where(x => x > 0)
                    .OrderBy(x => x)
                    .Select((x, idx) => new StockDetailDTO
                    {
                        Quantity = state.RobotTaskTotalNum > 0 ? state.RobotTaskTotalNum + positions.Length : positions.Length,
                        Channel = x,
                        CellBarcode = state.CellBarcode?.Count > 0 ? state.CellBarcode[x - 1] : ""
                    })
                    .ToList()
            };
        }
        /// <summary>
        /// è°ƒç”¨æ‹†ç›˜API
        /// </summary>
        public HttpResponseResult<WebResponseContent> PostSplitPalletAsync(StockDTO stockDTO)
        {
            return _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.SplitPalletAsync), stockDTO.ToJson());
        }
        /// <summary>
        /// è°ƒç”¨ç»„盘或换盘API
        /// </summary>
        public HttpResponseResult<WebResponseContent> PostGroupPalletAsync(string configKey, StockDTO stockDTO)
        {
            return _httpClientHelper.Post<WebResponseContent>(configKey, stockDTO.ToJson());
        }
    }
}
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json
@@ -7,36 +7,64 @@
      "RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\iservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\iservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -45,18 +73,6 @@
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -87,10 +103,6 @@
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockviewservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\gradingmachine\\inputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\gradingmachine\\inputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
@@ -106,21 +118,8 @@
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 24,
          "SelectedChildIndex": 27,
          "Children": [
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "StockStatusEmun.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "ViewState": "AgIAACQAAAAAAAAAAAAgwDoAAAAeAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-28T06:15:43.313Z",
              "EditorCaption": ""
            },
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
@@ -135,7 +134,56 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "TaskTypeEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ViewState": "AgIAAIAAAAAAAAAAAAAYwKAAAAAXAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T06:53:48.328Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "Title": "IService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\IService.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\IService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\IService.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseServices\\IService.cs",
              "ViewState": "AgIAAAYAAAAAAAAAAAASwCoAAAAbAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T08:25:43.974Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "Title": "ServiceBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "ViewState": "AgIAAAEAAAAAAAAAAAAAANcBAAA3AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T08:32:27.552Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 15,
              "Title": "StockStatusEmun.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "ViewState": "AgIAACQAAAAAAAAAAAAgwDoAAAAeAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-28T06:15:43.313Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 17,
              "Title": "LocationStatusEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
@@ -147,31 +195,31 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "DocumentIndex": 12,
              "Title": "IStockService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
              "RelativeToolTip": "WIDESEA_IStockService\\IStockService.cs",
              "ViewState": "AgIAAAkAAAAAAAAAAAAAABUAAAA0AAAAAAAAAA==",
              "ViewState": "AgIAAAcAAAAAAAAAAAAewBkAAAAfAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-26T06:24:13.287Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 12,
              "DocumentIndex": 8,
              "Title": "StockController.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "ViewState": "AgIAADQAAAAAAAAAAAAIwDwAAAA5AAAAAAAAAA==",
              "ViewState": "AgIAABwAAAAAAAAAAAAAACoAAAAJAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-26T06:16:05.674Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 15,
              "DocumentIndex": 19,
              "Title": "Program.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs",
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs",
@@ -183,7 +231,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 18,
              "DocumentIndex": 22,
              "Title": "HttpResponseResult.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
@@ -195,7 +243,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 17,
              "DocumentIndex": 21,
              "Title": "HttpRequestConfig.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
@@ -207,7 +255,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 16,
              "DocumentIndex": 20,
              "Title": "HttpClientHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
@@ -219,7 +267,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 23,
              "DocumentIndex": 26,
              "Title": "OutPutDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
@@ -231,7 +279,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 22,
              "DocumentIndex": 25,
              "Title": "InputDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\InputDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\InputDto.cs",
@@ -243,32 +291,33 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "DocumentIndex": 3,
              "Title": "RepositoryBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "ViewState": "AgIAALgDAAAAAAAAAAAawMsDAAAZAAAAAAAAAA==",
              "ViewState": "AgIAALoDAAAAAAAAAAAawM0DAAA+AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-14T08:55:16.1Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 21,
              "DocumentIndex": 4,
              "Title": "IRepository.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "ViewState": "AgIAAIIBAAAAAAAAAAAWwLMBAAASAAAAAAAAAA==",
              "ViewState": "AgIAAKEBAAAAAAAAAAAewLMBAAASAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-14T08:53:36.522Z"
              "WhenOpened": "2026-02-14T08:53:36.522Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 20,
              "DocumentIndex": 24,
              "Title": "StockViewService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockViewService.cs",
@@ -280,7 +329,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "DocumentIndex": 16,
              "Title": "ILocationInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IBasicService\\ILocationInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IBasicService\\ILocationInfoService.cs",
@@ -292,7 +341,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 19,
              "DocumentIndex": 23,
              "Title": "LocationInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs",
@@ -304,20 +353,19 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "DocumentIndex": 13,
              "Title": "Dt_StockInfo.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "RelativeDocumentMoniker": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "RelativeToolTip": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAuAAAAAAAAAA==",
              "ViewState": "AgIAABYAAAAAAAAAAAAAwCcAAAArAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-11T01:38:37.887Z",
              "EditorCaption": ""
              "WhenOpened": "2026-02-11T01:38:37.887Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "DocumentIndex": 18,
              "Title": "StockInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs",
@@ -329,45 +377,45 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "DocumentIndex": 9,
              "Title": "IStockInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockInfoService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
              "RelativeToolTip": "WIDESEA_IStockService\\IStockInfoService.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAACsAAAAzAAAAAAAAAA==",
              "ViewState": "AgIAAAAAAAAAAAAAAAAuwAgAAAAiAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-11T01:21:54.522Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "DocumentIndex": 5,
              "Title": "TaskController.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "ViewState": "AgIAAD0AAAAAAAAAAAAUwFUAAABJAAAAAAAAAA==",
              "ViewState": "AgIAABAAAAAAAAAAAAAgwCIAAAAIAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-09T01:23:19.844Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "DocumentIndex": 2,
              "Title": "CreateTaskDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "RelativeToolTip": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "ViewState": "AgIAABsAAAAAAAAAAAAywA4AAAARAAAAAAAAAA==",
              "ViewState": "AgIAAC0AAAAAAAAAAAAUwDwAAAAcAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T07:58:13.932Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "DocumentIndex": 14,
              "Title": "ITaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
              "RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs",
@@ -375,8 +423,7 @@
              "RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs",
              "ViewState": "AgIAAEAAAAAAAAAAAAAUwFEAAAAVAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T07:00:19.697Z",
              "EditorCaption": ""
              "WhenOpened": "2026-02-06T07:00:19.697Z"
            },
            {
              "$type": "Document",
@@ -386,14 +433,14 @@
              "RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAAAEBAAAAAAAAAAAxwPABAAAAAAAAAAAAAA==",
              "ViewState": "AgIAADoAAAAAAAAAAAAgwEMAAAARAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T06:34:59.734Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "DocumentIndex": 7,
              "Title": "StockDTO.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs",
@@ -406,13 +453,13 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "DocumentIndex": 6,
              "Title": "StockSerivce.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
              "RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAD8AAAApAAAAAAAAAA==",
              "ViewState": "AgIAADAAAAAAAAAAAAAawC4AAAA7AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T01:53:49.077Z",
              "EditorCaption": ""
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json
@@ -3,40 +3,76 @@
  "WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\taskenum\\tasktypeenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\servicebase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baseservices\\iservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baseservices\\iservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -45,22 +81,6 @@
    {
      "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\stock\\stockcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{49716D78-720D-475D-948C-0FC6C5F079E5}|WIDESEA_IStockService\\WIDESEA_IStockService.csproj|solutionrelative:widesea_istockservice\\istockservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -87,10 +107,6 @@
      "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockviewservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\irepository.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\gradingmachine\\inputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\gradingmachine\\inputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
@@ -106,8 +122,21 @@
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 24,
          "SelectedChildIndex": 25,
          "Children": [
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "TaskStatusEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs",
              "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskStatusEnum.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAALgAAAAhAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T09:14:24.547Z",
              "EditorCaption": ""
            },
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
@@ -123,6 +152,43 @@
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "TaskTypeEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "RelativeToolTip": "WIDESEA_Common\\TaskEnum\\TaskTypeEnum.cs",
              "ViewState": "AgIAAIAAAAAAAAAAAAAYwKAAAAAXAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-05T06:53:48.328Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "Title": "IService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\IService.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\IService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\IService.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseServices\\IService.cs",
              "ViewState": "AgIAAAYAAAAAAAAAAAASwCoAAAAbAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T08:25:43.974Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "Title": "ServiceBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseServices\\ServiceBase.cs",
              "ViewState": "AgIAAAEAAAAAAAAAAAAAANcBAAA3AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-03-03T08:32:27.552Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 17,
              "Title": "StockStatusEmun.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
@@ -134,7 +200,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "DocumentIndex": 19,
              "Title": "LocationStatusEnum.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
@@ -146,13 +212,13 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "DocumentIndex": 15,
              "Title": "IStockService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
              "RelativeToolTip": "WIDESEA_IStockService\\IStockService.cs",
              "ViewState": "AgIAAAkAAAAAAAAAAAAAABUAAAA0AAAAAAAAAA==",
              "ViewState": "AgIAAAcAAAAAAAAAAAAewBkAAAAfAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-26T06:24:13.287Z"
            },
@@ -164,13 +230,13 @@
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
              "ViewState": "AgIAADQAAAAAAAAAAAAIwDwAAAA5AAAAAAAAAA==",
              "ViewState": "AgIAABwAAAAAAAAAAAAAACoAAAAJAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-26T06:16:05.674Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 15,
              "DocumentIndex": 20,
              "Title": "Program.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs",
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs",
@@ -182,7 +248,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 18,
              "DocumentIndex": 23,
              "Title": "HttpResponseResult.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
@@ -194,7 +260,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 17,
              "DocumentIndex": 22,
              "Title": "HttpRequestConfig.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
@@ -206,7 +272,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 16,
              "DocumentIndex": 21,
              "Title": "HttpClientHelper.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
@@ -218,7 +284,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 23,
              "DocumentIndex": 27,
              "Title": "OutPutDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
@@ -230,7 +296,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 22,
              "DocumentIndex": 26,
              "Title": "InputDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\InputDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\InputDto.cs",
@@ -242,31 +308,33 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "DocumentIndex": 8,
              "Title": "RepositoryBase.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
              "ViewState": "AgIAALgDAAAAAAAAAAAawMsDAAAZAAAAAAAAAA==",
              "ViewState": "AgIAALoDAAAAAAAAAAAawM0DAAA+AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-14T08:55:16.1Z"
              "WhenOpened": "2026-02-14T08:55:16.1Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 21,
              "DocumentIndex": 9,
              "Title": "IRepository.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "RelativeToolTip": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
              "ViewState": "AgIAAIIBAAAAAAAAAAAWwLMBAAASAAAAAAAAAA==",
              "ViewState": "AgIAAKEBAAAAAAAAAAAewLMBAAASAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-14T08:53:36.522Z"
              "WhenOpened": "2026-02-14T08:53:36.522Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 20,
              "DocumentIndex": 25,
              "Title": "StockViewService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockViewService.cs",
@@ -278,7 +346,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "DocumentIndex": 18,
              "Title": "ILocationInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IBasicService\\ILocationInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IBasicService\\ILocationInfoService.cs",
@@ -290,7 +358,7 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 19,
              "DocumentIndex": 24,
              "Title": "LocationInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs",
@@ -302,92 +370,97 @@
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "DocumentIndex": 16,
              "Title": "Dt_StockInfo.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "RelativeDocumentMoniker": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "RelativeToolTip": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
              "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAuAAAAAAAAAA==",
              "ViewState": "AgIAABYAAAAAAAAAAAAAwCcAAAArAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-11T01:38:37.887Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "DocumentIndex": 4,
              "Title": "StockInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs",
              "RelativeToolTip": "WIDESEA_StockService\\StockInfoService.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAABUAAAA0AAAAAAAAAA==",
              "ViewState": "AgIAAAsAAAAAAAAAAAAMwB0AAAAuAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-11T01:23:56.94Z"
              "WhenOpened": "2026-02-11T01:23:56.94Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "DocumentIndex": 5,
              "Title": "IStockInfoService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
              "RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockInfoService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
              "RelativeToolTip": "WIDESEA_IStockService\\IStockInfoService.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAACsAAAAzAAAAAAAAAA==",
              "ViewState": "AgIAAAMAAAAAAAAAAAAMwAgAAAAiAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-11T01:21:54.522Z"
              "WhenOpened": "2026-02-11T01:21:54.522Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "DocumentIndex": 0,
              "Title": "TaskController.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
              "ViewState": "AgIAAD0AAAAAAAAAAAAUwFUAAABJAAAAAAAAAA==",
              "ViewState": "AgIAAFMAAAAAAAAAAAAcwGQAAAAJAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-09T01:23:19.844Z"
              "WhenOpened": "2026-02-09T01:23:19.844Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "DocumentIndex": 7,
              "Title": "CreateTaskDto.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "RelativeToolTip": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
              "ViewState": "AgIAABsAAAAAAAAAAAAywA4AAAARAAAAAAAAAA==",
              "ViewState": "AgIAAC0AAAAAAAAAAAAUwDwAAAAcAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T07:58:13.932Z"
              "WhenOpened": "2026-02-06T07:58:13.932Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "DocumentIndex": 2,
              "Title": "ITaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
              "RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
              "RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs",
              "ViewState": "AgIAAEAAAAAAAAAAAAAUwFEAAAAVAAAAAAAAAA==",
              "ViewState": "AgIAAE8AAAAAAAAAAAAgwFwAAAAfAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T07:00:19.697Z"
              "WhenOpened": "2026-02-06T07:00:19.697Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "DocumentIndex": 1,
              "Title": "TaskService.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
              "RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAANcAAAAAAAAAAAAgwBYBAABGAAAAAAAAAA==",
              "ViewState": "AgIAACIBAAAAAAAAAAAuwGMBAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T06:34:59.734Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "DocumentIndex": 11,
              "Title": "StockDTO.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
              "RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs",
@@ -395,19 +468,21 @@
              "RelativeToolTip": "WIDESEA_DTO\\Stock\\StockDTO.cs",
              "ViewState": "AgIAACMAAAAAAAAAAAAAADYAAAAuAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T02:56:51.397Z"
              "WhenOpened": "2026-02-06T02:56:51.397Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "DocumentIndex": 10,
              "Title": "StockSerivce.cs",
              "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
              "RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs",
              "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
              "RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAD8AAAApAAAAAAAAAA==",
              "ViewState": "AgIAADAAAAAAAAAAAAAawC4AAAA7AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-06T01:53:49.077Z"
              "WhenOpened": "2026-02-06T01:53:49.077Z",
              "EditorCaption": ""
            }
          ]
        }
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/TaskEnum/TaskStatusEnum.cs
@@ -112,4 +112,143 @@
        [Description("提升机执行中")]
        HT_Executing = 110,
    }
    public enum TaskInStatusEnum
    {
        /// <summary>
        /// æ–°å»ºå…¥åº“任务
        /// </summary>
        [Description("新建入库任务")]
        InNew = 200,
        ///// <summary>
        ///// AGV入库执行中
        ///// </summary>
        //[Description("AGV入库执行中")]
        //AGV_InExecuting = 210,
        ///// <summary>
        ///// AGV入库完成
        ///// </summary>
        //[Description("AGV搬运完成")]
        //AGV_InFinish = 215,
        /// <summary>
        /// è¾“送线入库执行中
        /// </summary>
        [Description("输送线入库执行中")]
        Line_InExecuting = 220,
        /// <summary>
        /// è¾“送线入库完成
        /// </summary>
        [Description("输送线输送完成")]
        Line_InFinish = 225,
        /// <summary>
        /// å †åž›æœºå…¥åº“执行中
        /// </summary>
        [Description("堆垛机入库执行中")]
        SC_InExecuting = 230,
        /// <summary>
        /// å †åž›æœºå…¥åº“完成
        /// </summary>
        [Description("堆垛机入库完成")]
        SC_InFinish = 235,
        /// <summary>
        /// å…¥åº“任务完成
        /// </summary>
        [Description("入库任务完成")]
        InFinish = 290,
        /// <summary>
        /// å…¥åº“任务挂起
        /// </summary>
        [Description("入库任务挂起")]
        InPending = 297,
        /// <summary>
        /// å…¥åº“任务取消
        /// </summary>
        [Description("入库任务取消")]
        InCancel = 298,
        /// <summary>
        /// å…¥åº“任务异常
        /// </summary>
        [Description("入库任务异常")]
        InException = 299,
    }
    public enum TaskOutStatusEnum
    {
        /// <summary>
        /// æ–°å»ºå‡ºåº“任务
        /// </summary>
        [Description("新建出库任务")]
        OutNew = 100,
        /// <summary>
        /// å †åž›æœºå‡ºåº“执行中
        /// </summary>
        [Description("堆垛机出库执行中")]
        SC_OutExecuting = 110,
        /// <summary>
        /// å †åž›æœºå‡ºåº“完成
        /// </summary>
        [Description("堆垛机出库完成")]
        SC_OutFinish = 115,
        /// <summary>
        /// è¾“送线出库执行中
        /// </summary>
        [Description("输送线出库执行中")]
        Line_OutExecuting = 120,
        /// <summary>
        /// è¾“送线出库完成
        /// </summary>
        [Description("输送线输送完成")]
        Line_OutFinish = 125,
        ///// <summary>
        ///// AGV出库执行中
        ///// </summary>
        //[Description("AGV出库执行中")]
        //AGV_OutExecuting = 130,
        ///// <summary>
        ///// AGV出库完成
        ///// </summary>
        //[Description("AGV搬运完成")]
        //AGV_OutFinish = 135,
        /// <summary>
        /// å‡ºåº“任务完成
        /// </summary>
        [Description("出库任务完成")]
        OutFinish = 190,
        /// <summary>
        /// å‡ºåº“任务挂起
        /// </summary>
        [Description("出库任务挂起")]
        OutPending = 197,
        /// <summary>
        /// å‡ºåº“任务取消
        /// </summary>
        [Description("出库任务取消")]
        OutCancel = 198,
        /// <summary>
        /// å‡ºåº“任务异常
        /// </summary>
        [Description("出库任务异常")]
        OutException = 199,
    }
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/TaskEnum/TaskTypeEnum.cs
@@ -101,6 +101,80 @@
        
    }
    public enum TaskInboundTypeEnum
    {
        /// <summary>
        /// å…¥åº“
        /// </summary>
        [Description("入库")]
        Inbound = 200,
        /// <summary>
        /// ç›˜ç‚¹å…¥åº“
        /// </summary>
        [Description("盘点入库")]
        InInventory = 201,
        /// <summary>
        /// åˆ†æ‹£å…¥åº“
        /// </summary>
        [Description("分拣入库")]
        InPick = 202,
        /// <summary>
        /// è´¨æ£€å…¥åº“
        /// </summary>
        [Description("质检入库")]
        InQuality = 203,
        /// <summary>
        /// ç©ºç®±å…¥åº“
        /// </summary>
        [Description("空箱入库")]
        InEmpty = 600,
    }
    public enum TaskOutboundTypeEnum
    {
        /// <summary>
        /// å‡ºåº“
        /// </summary>
        [Description("出库")]
        Outbound = 100,
        /// <summary>
        /// ç›˜ç‚¹å‡ºåº“
        /// </summary>
        [Description("盘点出库")]
        OutInventory = 101,
        /// <summary>
        /// åˆ†æ‹£å‡ºåº“
        /// </summary>
        [Description("分拣出库")]
        OutPick = 102,
        /// <summary>
        /// è´¨æ£€å‡ºåº“
        /// </summary>
        [Description("质检出库")]
        OutQuality = 103,
        /// <summary>
        /// ç©ºç®±å‡ºåº“
        /// </summary>
        [Description("空箱出库")]
        OutEmpty = 140,
    }
    public enum TaskRelocationTypeEnum
    {
        /// <summary>
        /// åº“内移库
        /// </summary>
        [Description("库内移库")]
        Relocation = 300,
        /// <summary>
        /// åº“外移库
        /// </summary>
        [Description("库外移库")]
        RelocationIn = 301
    }
    public enum TaskTypeGroup
    {
        /// <summary>
Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
@@ -86,6 +86,14 @@
        Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto);
        /// <summary>
        /// ä¿®æ”¹ä»»åŠ¡çŠ¶æ€ï¼ˆæ ¹æ®ä»»åŠ¡ID修改为指定状态)
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="newStatus"></param>
        /// <returns></returns>
        Task<WebResponseContent> UpdateTaskByStatusAsync(int taskId, int newStatus);
        /// <summary>
        /// å †åž›æœºå–放货完成后物流通知化成分容柜完成信号
        /// </summary>
        /// <param name="input"></param>
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -1,5 +1,4 @@
using AutoMapper;
using Microsoft.AspNetCore.Components.Forms;
using SqlSugar;
using System.Text.Json;
using WIDESEA_Common.LocationEnum;
@@ -8,7 +7,6 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Helper;
using WIDESEA_DTO;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
@@ -49,6 +47,8 @@
            _httpClientHelper = httpClientHelper;
        }
        #region WCS逻辑处理
        /// <summary>
        /// åˆ›å»ºä»»åŠ¡ï¼ˆç»„ç›˜å…¥åº“ä»»åŠ¡ã€ç©ºæ‰˜ç›˜å›žåº“ä»»åŠ¡ï¼‰
        /// </summary>
@@ -56,9 +56,13 @@
        {
            try
            {
                WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                if (string.IsNullOrWhiteSpace(taskDto.PalletCode) ||
                    string.IsNullOrWhiteSpace(taskDto.SourceAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.TargetAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.Roadway))
                {
                    return WebResponseContent.Instance.Error("无效的任务详情");
@@ -69,14 +73,22 @@
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                // ä½¿ç”¨ switch è¡¨è¾¾å¼æ˜ å°„任务类型
                int taskInboundType = taskDto.TaskType switch
                {
                    TaskTypeEnum.Inbound => TaskInboundTypeEnum.Inbound.GetHashCode(),
                    TaskTypeEnum.InEmpty => TaskInboundTypeEnum.InEmpty.GetHashCode(),
                    _ => 0 // ç†è®ºä¸Šä¸ä¼šèµ°åˆ°è¿™é‡Œï¼Œå› ä¸ºå·²ç»éªŒè¯è¿‡äº†
                };
                var task = new Dt_Task
                {
                    TaskNum = 0,
                    TaskNum = await BaseDal.GetTaskNo(),
                    PalletCode = taskDto.PalletCode,
                    PalletType = taskDto.PalletType,
                    Roadway = taskDto.Roadway,
                    TaskType = taskDto.TaskType.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    TaskType = taskInboundType,
                    TaskStatus = TaskInStatusEnum.InNew.GetHashCode(),
                    SourceAddress = taskDto.SourceAddress,
                    TargetAddress = taskDto.TargetAddress,
                    CurrentAddress = taskDto.SourceAddress,
@@ -259,6 +271,12 @@
        {
            try
            {
                WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                //var tasks = await BaseDal.QueryAsync(s => s.PalletCode == palletCode);
                //if (tasks == null || !tasks.Any())
                //    return WebResponseContent.Instance.Error("未找到对应的任务");
@@ -280,8 +298,9 @@
        {
            try
            {
                var stockInfo = await _stockInfoService.Repository.QueryFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.空托盘库存.GetHashCode());
                if(stockInfo == null)
                if (stockInfo == null)
                    return WebResponseContent.Instance.Error("未找到对应的库存信息");
                var task = new Dt_Task()
@@ -300,7 +319,7 @@
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "system",
                };
                 var taskDtos = _mapper.Map<List<WMSTaskDTO>>(task);
                var taskDtos = _mapper.Map<List<WMSTaskDTO>>(task);
                return WebResponseContent.Instance.OK("查询成功", taskDtos);
            }
            catch (Exception ex)
@@ -308,6 +327,55 @@
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// ä¿®æ”¹ä»»åŠ¡çŠ¶æ€ï¼ˆæ ¹æ®ä»»åŠ¡ID修改为指定状态)
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="newStatus"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> UpdateTaskByStatusAsync(int taskId, int newStatus)
        {
            try
            {
                var tasks = await BaseDal.QueryFirstAsync(s => s.TaskId == taskId);
                if (tasks == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                tasks.TaskStatus = newStatus;
                await BaseDal.UpdateDataAsync(tasks);
                return WebResponseContent.Instance.OK("修改成功", tasks);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"修改失败: {ex.Message}");
            }
        }
        /// <summary>
        /// æŸ¥æ‰¾æ‰˜ç›˜æ˜¯å¦æœ‰ä»»åŠ¡
        /// </summary>
        /// <param name="palletCode"></param>
        /// <returns></returns>
        private async Task<WebResponseContent> GetTasksByPalletCodeAsync(string palletCode)
        {
            try
            {
                var tasks = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode);
                if (tasks == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks);
                return WebResponseContent.Instance.OK("查询成功", taskDtos);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        #endregion WCS逻辑处理
        #region åˆ†å®¹æŸœæŽ¥å£
@@ -436,7 +504,6 @@
                    var result = await BaseDal.AddDataAsync(taskList) > 0;
                    var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data;
                    if (result && httpResponse != null)
                    {
@@ -491,6 +558,6 @@
            }
        }
        #endregion
        #endregion åˆ†å®¹æŸœæŽ¥å£
    }
}
}
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
@@ -101,6 +101,17 @@
        }
        /// <summary>
        /// ä¿®æ”¹ä»»åŠ¡çŠ¶æ€ï¼ˆæ ¹æ®ä»»åŠ¡ID修改为指定状态)
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        [HttpGet, HttpPost, Route("UpdateTaskByStatus"), AllowAnonymous]
        public async Task<WebResponseContent?> UpdateTaskByStatusAsync([FromBody] int taskId, int newStatus)
        {
            return await Service.UpdateTaskByStatusAsync(taskId, newStatus);
        }
        /// <summary>
        /// å †åž›æœºå–放货完成后物流通知化成分容柜完成信号
        /// </summary>
        /// <param name="input"></param>
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.dockerignore
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/957CD3507E75254DAB50B67D1CAD4ABB/57E558275472B567970CA987458436D5
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    var text = $"Hello from client #{clientId}";
    var sendBuffer = Encoding.UTF8.GetBytes(text);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length > 0)
    {
        var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {response}");
    }
    client.Shutdown(SocketShutdown.Both);
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 5000;
    public int StartLocalPort { get; init; } = 6000;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 5000),
            StartLocalPort = GetInt(map, "localport", 6000)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/957CD3507E75254DAB50B67D1CAD4ABB/89EE95323C118AB5E5FA0B5FC9E372D8
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    var text = $"Hello from client #{clientId}";
    var sendBuffer = Encoding.UTF8.GetBytes(text);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length > 0)
    {
        var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {response}");
    }
    client.Shutdown(SocketShutdown.Both);
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 5000;
    public int StartLocalPort { get; init; } = 6000;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 5000),
            StartLocalPort = GetInt(map, "localport", 6000)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/BE43EC63E499EE468C0161FA83175A2D/340C5AFE3B0C2AB455087AFF43725D6E
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/BE43EC63E499EE468C0161FA83175A2D/57E558275472B567970CA987458436D5
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2 @@
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/C569B8B80C5D3640BC534EFC4D2E9EFE/57E558275472B567970CA987458436D5
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    await WriteMessageAsync(client, clientId, $"Hello from client #{clientId}");
    await ReadMessageAsync(client, clientId);
    client.Shutdown(SocketShutdown.Both);
}
static async Task WriteMessageAsync(Socket client, int clientId, string message)
{
    var framedMessage = $"<START>{message}<END>";
    var sendBuffer = Encoding.UTF8.GetBytes(framedMessage);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    Console.WriteLine($"客户端#{clientId} å‘送: {framedMessage}");
}
static async Task ReadMessageAsync(Socket client, int clientId)
{
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length <= 0)
    {
        Console.WriteLine($"客户端#{clientId} æœªæŽ¥æ”¶åˆ°æ•°æ®");
        return;
    }
    var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
    Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {response}");
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 5000;
    public int StartLocalPort { get; init; } = 6000;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 5000),
            StartLocalPort = GetInt(map, "localport", 6000)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/C569B8B80C5D3640BC534EFC4D2E9EFE/EEF5B4E6C1E13E5E42E047DE7B74D577
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    await WriteMessageAsync(client, clientId, $"Hello from client #{clientId}");
    await ReadMessageAsync(client, clientId);
    client.Shutdown(SocketShutdown.Both);
}
static async Task WriteMessageAsync(Socket client, int clientId, string message)
{
    var framedMessage = $"<START>{message}<END>";
    var sendBuffer = Encoding.UTF8.GetBytes(framedMessage);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    Console.WriteLine($"客户端#{clientId} å‘送: {framedMessage}");
}
static async Task ReadMessageAsync(Socket client, int clientId)
{
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length <= 0)
    {
        Console.WriteLine($"客户端#{clientId} æœªæŽ¥æ”¶åˆ°æ•°æ®");
        return;
    }
    var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
    Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {response}");
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 5000;
    public int StartLocalPort { get; init; } = 6000;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 5000),
            StartLocalPort = GetInt(map, "localport", 6000)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/E6DFDF72DCCF3C46ABA29988BCD5456A/57E558275472B567970CA987458436D5
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    await WriteMessageAsync(client, clientId, $"Homed");
    await WriteMessageAsync(client, clientId, $"Runmodemode,2");
    await WriteMessageAsync(client, clientId, $"Armobject,0");
    await WriteMessageAsync(client, clientId, $"Controlmode,1");
    await ReadMessageAsync(client, clientId);
    client.Shutdown(SocketShutdown.Both);
}
static async Task WriteMessageAsync(Socket client, int clientId, string message)
{
    var framedMessage = $"<START>{message}<END>";
    var sendBuffer = Encoding.UTF8.GetBytes(framedMessage);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    Console.WriteLine($"客户端#{clientId} å‘送: {framedMessage}");
}
static async Task ReadMessageAsync(Socket client, int clientId)
{
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length <= 0)
    {
        Console.WriteLine($"客户端#{clientId} æœªæŽ¥æ”¶åˆ°æ•°æ®");
        return;
    }
    var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
    if (!response.StartsWith("<START>") || !response.EndsWith("<END>"))
    {
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°æ— æ•ˆæ¶ˆæ¯ï¼ˆç¼ºå°‘消息头或消息尾),已忽略");
        return;
    }
    var content = response["<START>".Length..^"<END>".Length];
    Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {content}");
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 2000;
    public int StartLocalPort { get; init; } = 62312;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 2000),
            StartLocalPort = GetInt(map, "localport", 62312)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/E6DFDF72DCCF3C46ABA29988BCD5456A/F977376DB3B74CAF672118CAACA4BA95
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
var options = ClientOptions.FromArgs(args);
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
var tasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options))
    .ToArray();
await Task.WhenAll(tasks);
static async Task RunClientAsync(int clientId, ClientOptions options)
{
    var localPort = options.StartLocalPort + clientId - 1;
    using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    client.Bind(new IPEndPoint(IPAddress.Any, localPort));
    await client.ConnectAsync(options.ServerHost, options.ServerPort);
    Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
    await WriteMessageAsync(client, clientId, $"Homed");
    await WriteMessageAsync(client, clientId, $"Runmodemode,2");
    await WriteMessageAsync(client, clientId, $"Armobject,0");
    await WriteMessageAsync(client, clientId, $"Controlmode,1");
    await ReadMessageAsync(client, clientId);
    client.Shutdown(SocketShutdown.Both);
}
static async Task WriteMessageAsync(Socket client, int clientId, string message)
{
    var framedMessage = $"<START>{message}<END>";
    var sendBuffer = Encoding.UTF8.GetBytes(framedMessage);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    Console.WriteLine($"客户端#{clientId} å‘送: {framedMessage}");
}
static async Task ReadMessageAsync(Socket client, int clientId)
{
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length <= 0)
    {
        Console.WriteLine($"客户端#{clientId} æœªæŽ¥æ”¶åˆ°æ•°æ®");
        return;
    }
    var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
    if (!response.StartsWith("<START>") || !response.EndsWith("<END>"))
    {
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°æ— æ•ˆæ¶ˆæ¯ï¼ˆç¼ºå°‘消息头或消息尾),已忽略");
        return;
    }
    var content = response["<START>".Length..^"<END>".Length];
    Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {content}");
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 2000;
    public int StartLocalPort { get; init; } = 62312;
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 2000),
            StartLocalPort = GetInt(map, "localport", 62312)
        };
    }
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/CopilotSnapshots/BD12C3365E39344589EDC65CA163A4E7/state.mpack
Binary files differ
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/RobotClient.slnx/copilot-chat/bef6627e/sessions/36c312bd-395e-4534-89ed-c65ca163a4e7
Binary files differ
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/RobotClient.slnx/v18/DocumentLayout.backup.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
{
  "Version": 1,
  "WorkspaceRootPath": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{B1C3E674-86D3-6DBD-F67F-E7F395016C7C}|RobotClient.csproj|c:\\users\\29028\\desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\robotclient\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{B1C3E674-86D3-6DBD-F67F-E7F395016C7C}|RobotClient.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
    {
      "Orientation": 0,
      "VerticalTabListWidth": 256,
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 3,
          "Children": [
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{40ea2e6b-2121-4bb8-a43e-c83c04b51041}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "Program.cs",
              "DocumentMoniker": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\Program.cs",
              "RelativeDocumentMoniker": "Program.cs",
              "ToolTip": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\Program.cs",
              "RelativeToolTip": "Program.cs",
              "ViewState": "AgIAAPwAAAAAAAAAAAAowBgBAABBAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-27T07:38:54.023Z",
              "EditorCaption": ""
            }
          ]
        }
      ]
    }
  ]
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/.vs/RobotClient.slnx/v18/DocumentLayout.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
{
  "Version": 1,
  "WorkspaceRootPath": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{B1C3E674-86D3-6DBD-F67F-E7F395016C7C}|RobotClient.csproj|c:\\users\\29028\\desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\robotclient\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{B1C3E674-86D3-6DBD-F67F-E7F395016C7C}|RobotClient.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
    {
      "Orientation": 0,
      "VerticalTabListWidth": 256,
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 3,
          "Children": [
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{40ea2e6b-2121-4bb8-a43e-c83c04b51041}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "Program.cs",
              "DocumentMoniker": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\Program.cs",
              "RelativeDocumentMoniker": "Program.cs",
              "ToolTip": "C:\\Users\\29028\\Desktop\\\u673A\u68B0\u624B\u5BA2\u6237\u7AEF\\RobotClient\\Program.cs",
              "RelativeToolTip": "Program.cs",
              "ViewState": "AgIAAPwAAAAAAAAAAAAowBgBAABBAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2026-02-27T07:38:54.023Z",
              "EditorCaption": ""
            }
          ]
        }
      ]
    }
  ]
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/CLAUDE.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
RobotClient is a .NET 8.0 TCP client simulator for a robotic arm control system. It creates multiple concurrent TCP connections to a server, simulating robotic arm clients that can send/receive control commands and status messages.
## Build and Run Commands
```bash
# Build the project
dotnet build
# Run with default settings (1 client, connects to 127.0.0.1:2000)
dotnet run
# Run with custom options (format: key=value)
dotnet run -- count=5 host=192.168.1.100 serverport=3000 localport=50000 reconnect=false
# Build Docker image
docker build -t robot-client .
# Run in Docker
docker run -it robot-client
```
### Command-Line Options
| Option | Default | Description |
|--------|---------|-------------|
| `count` | 1 | Number of client connections to create |
| `host` | 127.0.0.1 | Server host address |
| `serverport` | 2000 | Server port |
| `localport` | 62312 | Starting local port (each client uses localport + clientId) |
| `reconnect` | true | Enable automatic reconnection |
| `reconnectinterval` | 5000 | Reconnect delay in milliseconds |
| `maxreconnect` | -1 | Max reconnect attempts (-1 = infinite) |
## Architecture
The entire application is contained in `Program.cs` using C# top-level statements. The architecture follows a multi-client concurrent pattern:
### Core Components
1. **ClientOptions** (line 358-397): Configuration parser that processes command-line arguments into a strongly-typed options object.
2. **RunClientAsync** (line 23-50): Entry point for each client. Binds to a local port, establishes initial connection, spawns a background listener with reconnection logic, and sends initialization commands.
3. **ConnectAsync** (line 52-67): Low-level TCP connection using `Socket` with explicit local port binding.
4. **RunWithReconnectAsync** (line 69-134): Wrapper around the message listener that handles automatic reconnection with configurable limits and delays.
5. **ListenServerMessagesAsync** (line 181-234): Continuous receive loop that buffers incoming data and parses framed messages. Properly cleans up sockets on disconnect.
6. **TryReadFramedMessages** (line 236-293): Parses messages using `<START>content<END>` framing protocol. Handles partial messages and buffers incomplete data. Contains simulated robot commands:
   - `Pickbattery,1` â†’ Simulates picking operation (5 seconds)
   - `Putbattery,1` â†’ Simulates placing operation (5 seconds)
7. **SendLoopAsync** (line 295-356): Interactive console input loop allowing manual commands to specific clients using format `clientId:message` (e.g., `1:Status`). Type `exit` to quit.
### Initialization Sequence
Each client sends these commands on connection/startup:
1. `Homed` â†’ Wait 500ms
2. `Runmode,2` â†’ Wait 500ms
3. `Armobject,0` â†’ Wait 500ms
4. `Controlmode,1`
### Protocol
All messages use the frame format: `<START>message<END>`
- UTF-8 encoded
- Message boundaries are explicit, allowing streaming
- Invalid data before `<START>` is discarded
- Cache limits 10KB to prevent memory exhaustion
### Thread Safety
- `ConcurrentDictionary<int, Socket>` tracks active client connections
- Each client runs its own background Task for receiving messages
- Socket cleanup happens in `finally` blocks to prevent resource leaks
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/Dockerfile
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
# è¯·å‚阅 https://aka.ms/customizecontainer ä»¥äº†è§£å¦‚何自定义调试容器,以及 Visual Studio å¦‚何使用此 Dockerfile ç”Ÿæˆæ˜ åƒä»¥æ›´å¿«åœ°è¿›è¡Œè°ƒè¯•。
# æ­¤é˜¶æ®µç”¨äºŽåœ¨å¿«é€Ÿæ¨¡å¼(默认为调试配置)下从 VS è¿è¡Œæ—¶
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base
USER $APP_UID
WORKDIR /app
# æ­¤é˜¶æ®µç”¨äºŽç”ŸæˆæœåŠ¡é¡¹ç›®
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["RobotClient.csproj", "."]
RUN dotnet restore "./RobotClient.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./RobotClient.csproj" -c $BUILD_CONFIGURATION -o /app/build
# æ­¤é˜¶æ®µç”¨äºŽå‘布要复制到最终阶段的服务项目
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./RobotClient.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# æ­¤é˜¶æ®µåœ¨ç”Ÿäº§ä¸­ä½¿ç”¨ï¼Œæˆ–在常规模式下从 VS è¿è¡Œæ—¶ä½¿ç”¨(在不使用调试配置时为默认值)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RobotClient.dll"]
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/Program.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,399 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Concurrent;
var options = ClientOptions.FromArgs(args);
var cts = new CancellationTokenSource();
var clients = new ConcurrentDictionary<int, Socket>();
Console.WriteLine($"准备启动 {options.ClientCount} ä¸ªå®¢æˆ·ç«¯ï¼Œè¿žæŽ¥åˆ° {options.ServerHost}:{options.ServerPort}");
// å¯åŠ¨æ‰€æœ‰å®¢æˆ·ç«¯è¿žæŽ¥ä»»åŠ¡
var connectTasks = Enumerable.Range(0, options.ClientCount)
    .Select(i => RunClientAsync(i + 1, options, clients, cts.Token))
    .ToArray();
// ç­‰å¾…所有客户端连接完成
await Task.WhenAll(connectTasks);
// å¯åŠ¨å‘é€å¾ªçŽ¯ï¼ˆä¸Žç›‘å¬ä»»åŠ¡å¹¶è¡Œè¿è¡Œï¼‰
await SendLoopAsync(clients, cts);
static async Task RunClientAsync(int clientId, ClientOptions options, ConcurrentDictionary<int, Socket> clients, CancellationToken cancellationToken)
{
    var localPort = options.StartLocalPort + clientId - 1;
    // éªŒè¯ç«¯å£èŒƒå›´
    if (localPort > 65535)
    {
        Console.WriteLine($"错误: å®¢æˆ·ç«¯#{clientId} çš„æœ¬åœ°ç«¯å£ {localPort} è¶…出有效范围");
        return;
    }
    // é¦–次连接
    var client = await ConnectAsync(clientId, options, localPort, cancellationToken);
    if (client == null)
    {
        return;
    }
    clients[clientId] = client;
    // å¯åŠ¨å¸¦é‡è¿žåŠŸèƒ½çš„ç›‘å¬ä»»åŠ¡ï¼ˆåŽå°è¿è¡Œï¼Œä¸é˜»å¡žï¼‰
    _ = Task.Run(() => RunWithReconnectAsync(clientId, options, localPort, clients, cancellationToken), cancellationToken);
    // å‘送初始化消息
    await InitializeClientAsync(client, clientId);
    // ç«‹å³è¿”回,让主线程继续执行 SendLoopAsync
}
static async Task<Socket?> ConnectAsync(int clientId, ClientOptions options, int localPort, CancellationToken cancellationToken)
{
    try
    {
        var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        // å…è®¸é‡ç”¨æœ¬åœ°ç«¯å£ï¼Œè§£å†³é‡è¿žæ—¶ç«¯å£è¢«å ç”¨çš„问题
        client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        client.Bind(new IPEndPoint(IPAddress.Any, localPort));
        await client.ConnectAsync(options.ServerHost, options.ServerPort);
        Console.WriteLine($"客户端#{clientId} å·²è¿žæŽ¥ï¼Œæœ¬åœ°ç«¯å£: {localPort}");
        return client;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"客户端#{clientId} è¿žæŽ¥å¤±è´¥: {ex.Message}");
        return null;
    }
}
static async Task RunWithReconnectAsync(int clientId, ClientOptions options, int localPort, ConcurrentDictionary<int, Socket> clients, CancellationToken cancellationToken)
{
    var reconnectCount = 0;
    while (!cancellationToken.IsCancellationRequested)
    {
        Socket? client = null;
        try
        {
            // èŽ·å–å½“å‰è¿žæŽ¥çš„ Socket(如果存在)
            if (clients.TryGetValue(clientId, out client))
            {
                // ç›‘听消息,直到连接断开
                // ListenServerMessagesAsync çš„ finally ä¼šè‡ªåŠ¨æ¸…ç†æ–­å¼€çš„ Socket
                await ListenServerMessagesAsync(client, clientId, cancellationToken, clients);
            }
            // è¿žæŽ¥å·²æ–­å¼€ï¼Œè¿›å…¥é‡è¿žé€»è¾‘
            reconnectCount++;
            // æ£€æŸ¥æ˜¯å¦å¯ç”¨é‡è¿ž
            if (!options.EnableReconnect)
            {
                Console.WriteLine($"客户端#{clientId} é‡è¿žå·²ç¦ç”¨ï¼Œé€€å‡º");
                return;
            }
            // æ£€æŸ¥é‡è¿žæ¬¡æ•°é™åˆ¶
            if (options.MaxReconnectAttempts > 0 && reconnectCount > options.MaxReconnectAttempts)
            {
                Console.WriteLine($"客户端#{clientId} å·²è¾¾åˆ°æœ€å¤§é‡è¿žæ¬¡æ•° ({options.MaxReconnectAttempts}),退出");
                return;
            }
            // ç­‰å¾…重连间隔
            Console.WriteLine($"客户端#{clientId} ç­‰å¾… {options.ReconnectIntervalMs / 1000} ç§’后重连... (第 {reconnectCount} æ¬¡)");
            await Task.Delay(options.ReconnectIntervalMs, cancellationToken);
            // å°è¯•重新连接
            client = await ConnectAsync(clientId, options, localPort, cancellationToken);
            if (client == null)
            {
                continue;
            }
            // å°†æ–° Socket åР入字兏
            clients[clientId] = client;
            // é‡æ–°åˆå§‹åŒ–
            await InitializeClientAsync(client, clientId);
            Console.WriteLine($"客户端#{clientId} é‡è¿žæˆåŠŸï¼Œå·²é‡æ–°åˆå§‹åŒ–");
        }
        catch (OperationCanceledException)
        {
            // æ­£å¸¸å–消
            return;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"客户端#{clientId} è¿è¡Œå¼‚常: {ex.Message}");
            clients.TryRemove(clientId, out _);
            try { client?.Shutdown(SocketShutdown.Both); } catch { }
            try { client?.Dispose(); } catch { }
        }
    }
}
static async Task InitializeClientAsync(Socket client, int clientId)
{
    await Task.Delay(5000);
    await WriteMessageAsync(client, clientId, "Homed");
    await Task.Delay(500);
    await WriteMessageAsync(client, clientId, "Runmode,2");
    await Task.Delay(500);
    await WriteMessageAsync(client, clientId, "Armobject,0");
    await Task.Delay(500);
    await WriteMessageAsync(client, clientId, "Controlmode,1");
}
static async Task WriteMessageAsync(Socket client, int clientId, string message)
{
    var framedMessage = $"<START>{message}<END>";
    var sendBuffer = Encoding.UTF8.GetBytes(framedMessage);
    await client.SendAsync(sendBuffer, SocketFlags.None);
    Console.WriteLine($"客户端#{clientId} å‘送: {framedMessage}");
}
static async Task ReadMessageAsync(Socket client, int clientId)
{
    var receiveBuffer = new byte[1024];
    var length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None);
    if (length <= 0)
    {
        Console.WriteLine($"客户端#{clientId} æœªæŽ¥æ”¶åˆ°æ•°æ®");
        return;
    }
    var response = Encoding.UTF8.GetString(receiveBuffer, 0, length);
    if (!response.StartsWith("<START>") || !response.EndsWith("<END>"))
    {
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°æ— æ•ˆæ¶ˆæ¯ï¼ˆç¼ºå°‘消息头或消息尾),已忽略");
        return;
    }
    var content = response["<START>".Length..^"<END>".Length];
    Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {content}");
}
static async Task ListenServerMessagesAsync(Socket client, int clientId, CancellationToken cancellationToken, ConcurrentDictionary<int, Socket> clients)
{
    var receiveBuffer = new byte[1024];
    var cache = new StringBuilder();
    try
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            int length;
            try
            {
                length = await client.ReceiveAsync(receiveBuffer, SocketFlags.None, cancellationToken);
            }
            catch (SocketException)
            {
                Console.WriteLine($"客户端#{clientId} ä¸ŽæœåŠ¡ç«¯æ–­å¼€è¿žæŽ¥");
                return;
            }
            catch (ObjectDisposedException)
            {
                Console.WriteLine($"客户端#{clientId} Socket å·²è¢«é‡Šæ”¾");
                return;
            }
            if (length <= 0)
            {
                Console.WriteLine($"客户端#{clientId} ä¸ŽæœåŠ¡ç«¯æ–­å¼€è¿žæŽ¥");
                return;
            }
            cache.Append(Encoding.UTF8.GetString(receiveBuffer, 0, length));
            await TryReadFramedMessages(cache, clientId, client);
        }
    }
    catch (OperationCanceledException)
    {
        // æ­£å¸¸å–消,不需要记录错误
    }
    catch (Exception ex)
    {
        Console.WriteLine($"客户端#{clientId} æŽ¥æ”¶æ¶ˆæ¯å¼‚常: {ex.Message}");
    }
    finally
    {
        // è¿žæŽ¥æ–­å¼€æ—¶ï¼Œä»Žå­—典中移除这个 Socket(如果还是当前的话)
        clients.TryRemove(clientId, out var removed);
        if (removed == client)
        {
            try { client.Shutdown(SocketShutdown.Both); } catch { }
            try { client.Dispose(); } catch { }
        }
    }
}
static async Task TryReadFramedMessages(StringBuilder cache, int clientId, Socket client)
{
    const string start = "<START>";
    const string end = "<END>";
    while (true)
    {
        var text = cache.ToString();
        var startIndex = text.IndexOf(start, StringComparison.Ordinal);
        if (startIndex < 0)
        {
            // æ²¡æœ‰æ‰¾åˆ° START æ ‡è®°ï¼Œä¿ç•™ç¼“存等待更多数据
            // ä½†å¦‚果缓存太大,清空以防内存泄漏
            if (cache.Length > 10240) // 10KB é˜ˆå€¼
            {
                cache.Clear();
            }
            return;
        }
        var endIndex = text.IndexOf(end, startIndex + start.Length, StringComparison.Ordinal);
        if (endIndex < 0)
        {
            // ç§»é™¤ START ä¹‹å‰çš„æ— æ•ˆæ•°æ®
            if (startIndex > 0)
            {
                cache.Remove(0, startIndex);
            }
            return;
        }
        var contentStart = startIndex + start.Length;
        var contentLength = endIndex - contentStart;
        var content = text.Substring(contentStart, contentLength);
        Console.WriteLine($"客户端#{clientId} æ”¶åˆ°: {content}");
        cache.Remove(0, endIndex + end.Length);
        if (content == "Pickbattery,1")
        {
            await WriteMessageAsync(client, clientId, "Running");
            await Task.Delay(1000);
            await WriteMessageAsync(client, clientId, "Picking");
            //await WriteMessageAsync(client, clientId, "PickFinished,1,2,3,4");
        }
        else if (content == "Putbattery,1")
        {
            await WriteMessageAsync(client, clientId, "Running");
            await Task.Delay(500);
            await WriteMessageAsync(client, clientId, "Puting");
            await Task.Delay(5000);
            //await WriteMessageAsync(client, clientId, "PutFinished,1,2,3,4");
        }
    }
}
static async Task SendLoopAsync(ConcurrentDictionary<int, Socket> clients, CancellationTokenSource cts)
{
    Console.WriteLine("输入格式: å®¢æˆ·ç«¯ç¼–号:消息,例如 1:Status,输入 exit é€€å‡º");
    while (!cts.IsCancellationRequested)
    {
        var line = Console.ReadLine();
        if (string.IsNullOrWhiteSpace(line))
        {
            continue;
        }
        if (line.Equals("exit", StringComparison.OrdinalIgnoreCase))
        {
            cts.Cancel();
            foreach (var socket in clients.Values)
            {
                try
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Dispose();
                }
                catch { }
            }
            return;
        }
        var index = line.IndexOf(':');
        if (index <= 0 || index == line.Length - 1)
        {
            Console.WriteLine("输入不正确,请使用: å®¢æˆ·ç«¯ç¼–号:消息");
            continue;
        }
        var idText = line[..index];
        var message = line[(index + 1)..];
        if (!int.TryParse(idText, out var clientId) || !clients.TryGetValue(clientId, out var client))
        {
            Console.WriteLine($"客户端#{idText} ä¸å­˜åœ¨æˆ–未连接");
            continue;
        }
        try
        {
            await WriteMessageAsync(client, clientId, message);
        }
        catch (ObjectDisposedException)
        {
            Console.WriteLine($"客户端#{clientId} å‘送失败: Socket å·²å…³é—­ï¼ˆå¯èƒ½æ­£åœ¨é‡è¿žä¸­ï¼‰");
            clients.TryRemove(clientId, out _);
        }
        catch (SocketException ex)
        {
            Console.WriteLine($"客户端#{clientId} å‘送失败: {ex.Message}");
            clients.TryRemove(clientId, out _);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"客户端#{clientId} å‘送失败: {ex.GetType().Name} - {ex.Message}");
        }
    }
}
file sealed class ClientOptions
{
    public int ClientCount { get; init; } = 1;
    public string ServerHost { get; init; } = "127.0.0.1";
    public int ServerPort { get; init; } = 2000;
    public int StartLocalPort { get; init; } = 62312;
    public bool EnableReconnect { get; init; } = true;
    public int ReconnectIntervalMs { get; init; } = 5000;
    public int MaxReconnectAttempts { get; init; } = -1; // -1 è¡¨ç¤ºæ— é™é‡è¯•
    public static ClientOptions FromArgs(string[] args)
    {
        var map = args
            .Select(v => v.Split('=', 2, StringSplitOptions.TrimEntries))
            .Where(parts => parts.Length == 2)
            .ToDictionary(parts => parts[0].TrimStart('-', '/').ToLowerInvariant(), parts => parts[1]);
        return new ClientOptions
        {
            ClientCount = GetInt(map, "count", 1),
            ServerHost = GetString(map, "host", "127.0.0.1"),
            ServerPort = GetInt(map, "serverport", 2000),
            StartLocalPort = GetInt(map, "localport", 62312),
            EnableReconnect = GetBool(map, "reconnect", true),
            ReconnectIntervalMs = GetInt(map, "reconnectinterval", 5000),
            MaxReconnectAttempts = GetInt(map, "maxreconnect", -1)
        };
    }
    private static bool GetBool(Dictionary<string, string> map, string key, bool defaultValue)
        => map.TryGetValue(key, out var value)
        ? (bool.TryParse(value, out var result) ? result : defaultValue)
        : defaultValue;
    private static int GetInt(Dictionary<string, string> map, string key, int defaultValue)
        => map.TryGetValue(key, out var value) && int.TryParse(value, out var number) ? number : defaultValue;
    private static string GetString(Dictionary<string, string> map, string key, string defaultValue)
        => map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : defaultValue;
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/Properties/launchSettings.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
{
  "profiles": {
    "RobotClient": {
      "commandName": "Project"
    },
    "Container (Dockerfile)": {
      "commandName": "Docker"
    }
  }
}
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/RobotClient.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>.</DockerfileContext>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
  </ItemGroup>
</Project>
Code/»úеÊÖ¿Í»§¶Ë/RobotClient/RobotClient.slnx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
<Solution>
  <Project Path="RobotClient.csproj" />
</Solution>