feat(机器人任务): 实现换盘任务假电芯补充逻辑
feat(机器人任务): 实现换盘任务假电芯补充逻辑
添加假电芯平面点位表实体 Dt_FakeBatteryPosition 及相关仓储服务层
RobotSocketState 添加 IsInFakeBatteryMode 标志
RobotTaskProcessor 添加假电芯取货指令方法
实现 HandlePutFinishedStateAsync 中的 ChangePallet 完整逻辑
fix(Robot): GetNextAvailable按行内连续性查找可用点位
fix(Robot): GetNextAvailable改为查找连续可用的N个点位
feat(Robot): 实现换盘任务假电芯补充逻辑
feat(Robot): RobotTaskProcessor 添加假电芯取货指令方法
feat(Robot): RobotSocketState 添加 IsInFakeBatteryMode 标志
feat(Robot): 添加假电芯位置服务层
feat(Robot): 添加假电芯位置仓储层
feat(Robot): 添加假电芯平面点位表实体 Dt_FakeBatteryPosition
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:brainstorming"} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:writing-plans"} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:subagent-driven-development"} |
| | | {"t":0,"agent":"a2061bd","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a2061bd","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":44758} |
| | | {"t":0,"agent":"a33f78a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a33f78a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":81574} |
| | | {"t":0,"agent":"a9c381b","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a9c381b","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":81306} |
| | | {"t":0,"agent":"a614ea5","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a614ea5","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":72773} |
| | | {"t":0,"agent":"a3143b3","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a3143b3","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":90995} |
| | | {"t":0,"agent":"a177bc3","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a177bc3","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":88225} |
| | | {"t":0,"agent":"a550b7f","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a550b7f","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":41024} |
| | | {"t":0,"agent":"acd1aa5","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"acd1aa5","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":90649} |
| | | {"t":0,"agent":"a991ee2","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a991ee2","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":246360} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:finishing-a-development-branch"} |
| | |
| | | { |
| | | "lastSentAt": "2026-04-15T11:40:34.475Z" |
| | | "lastSentAt": "2026-04-15T14:42:46.838Z" |
| | | } |
| | |
| | | { |
| | | "tool_name": "Bash", |
| | | "tool_input_preview": "{\"command\":\"ls \\\"D:\\\\Git\\\\ShanMeiXinNengYuan\\\\Code\\\\WMS\\\\WIDESEA_WMSClient\\\\src\\\\api\\\\\\\" 2>/dev/null | head -20\",\"description\":\"Check api directory structure\"}", |
| | | "error": "Exit code 2\n/usr/bin/bash: eval: line 1: unexpected EOF while looking for matching `\"'", |
| | | "timestamp": "2026-04-13T03:27:59.200Z", |
| | | "retry_count": 6 |
| | | "tool_input_preview": "{\"command\":\"dotnet build D:/Git/ShanMeiXinNengYuan/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln\",\"timeout\":300000,\"description\":\"Build WCS solution to verify fix\"}", |
| | | "error": "Exit code 1\n æ£å¨ç¡®å®è¦è¿åç项ç®â¦\r\n ææé¡¹ç®åæ¯ææ°çï¼æ æ³è¿åã\r\n WIDESEAWCS_Common -> D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Common\\bin\\Debug\\net8.0\\WIDESEAWCS_Common.dll\r\nD:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Communicator\\AllenBrandly\\AllenBrandlyEtherNetCommunicator.cs(110,80): warning CS1570: XML 注éåºç° XML æ ¼å¼é误 --âç»ææ è®°âparamâä¸å¼å§æ è®°âTâä¸å¹é
ãâ [D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Communicator\\WIDESEAWCS_Communicator.csproj]\r\nD:\\Git\\ShanM...", |
| | | "timestamp": "2026-04-15T14:12:47.386Z", |
| | | "retry_count": 1 |
| | | } |
| | |
| | | { |
| | | "updatedAt": "2026-04-15T06:10:46.493Z", |
| | | "updatedAt": "2026-04-15T14:16:41.286Z", |
| | | "missions": [ |
| | | { |
| | | "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none", |
| | |
| | | "sourceKey": "session-stop:a48e41df38204e6dc" |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "session:d836b656-7d6b-4a00-b9ed-f46b82f58345:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-15T14:00:27.304Z", |
| | | "updatedAt": "2026-04-15T14:16:41.286Z", |
| | | "status": "done", |
| | | "workerCount": 9, |
| | | "taskCounts": { |
| | | "total": 9, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 0, |
| | | "completed": 9, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "general-purpose:a2061bd", |
| | | "role": "general-purpose", |
| | | "ownership": "a2061bd1c8b6f066e", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:01:12.062Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a33f78a", |
| | | "role": "general-purpose", |
| | | "ownership": "a33f78a441c700f07", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:03:00.165Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a9c381b", |
| | | "role": "general-purpose", |
| | | "ownership": "a9c381b5f67087dae", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:04:44.132Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a614ea5", |
| | | "role": "general-purpose", |
| | | "ownership": "a614ea573436c827d", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:06:11.349Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a3143b3", |
| | | "role": "general-purpose", |
| | | "ownership": "a3143b3511395abdc", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:08:04.129Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a177bc3", |
| | | "role": "general-purpose", |
| | | "ownership": "a177bc320ae6cc4dc", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:09:53.582Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a550b7f", |
| | | "role": "general-purpose", |
| | | "ownership": "a550b7f6cb598b4c0", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:10:46.231Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:acd1aa5", |
| | | "role": "general-purpose", |
| | | "ownership": "acd1aa52bf3dd06d4", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:12:28.373Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a991ee2", |
| | | "role": "general-purpose", |
| | | "ownership": "a991ee262522932f5", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-15T14:16:41.286Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:acd1aa52bf3dd06d4:2026-04-15T14:10:57.724Z", |
| | | "at": "2026-04-15T14:10:57.724Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:acd1aa5", |
| | | "detail": "started general-purpose:acd1aa5", |
| | | "sourceKey": "session-start:acd1aa52bf3dd06d4" |
| | | }, |
| | | { |
| | | "id": "session-stop:acd1aa52bf3dd06d4:2026-04-15T14:12:28.373Z", |
| | | "at": "2026-04-15T14:12:28.373Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:acd1aa5", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:acd1aa52bf3dd06d4" |
| | | }, |
| | | { |
| | | "id": "session-start:a991ee262522932f5:2026-04-15T14:12:34.926Z", |
| | | "at": "2026-04-15T14:12:34.926Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a991ee2", |
| | | "detail": "started general-purpose:a991ee2", |
| | | "sourceKey": "session-start:a991ee262522932f5" |
| | | }, |
| | | { |
| | | "id": "session-stop:a991ee262522932f5:2026-04-15T14:16:41.286Z", |
| | | "at": "2026-04-15T14:16:41.286Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:a991ee2", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a991ee262522932f5" |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T06:10:46.493Z", |
| | | "duration_ms": 51400 |
| | | }, |
| | | { |
| | | "agent_id": "a2061bd1c8b6f066e", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:00:27.304Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:01:12.062Z", |
| | | "duration_ms": 44758 |
| | | }, |
| | | { |
| | | "agent_id": "a33f78a441c700f07", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:01:38.591Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:03:00.165Z", |
| | | "duration_ms": 81574 |
| | | }, |
| | | { |
| | | "agent_id": "a9c381b5f67087dae", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:03:22.826Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:04:44.132Z", |
| | | "duration_ms": 81306 |
| | | }, |
| | | { |
| | | "agent_id": "a614ea573436c827d", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:04:58.576Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:06:11.349Z", |
| | | "duration_ms": 72773 |
| | | }, |
| | | { |
| | | "agent_id": "a3143b3511395abdc", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:06:33.134Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:08:04.129Z", |
| | | "duration_ms": 90995 |
| | | }, |
| | | { |
| | | "agent_id": "a177bc320ae6cc4dc", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:08:25.357Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:09:53.582Z", |
| | | "duration_ms": 88225 |
| | | }, |
| | | { |
| | | "agent_id": "a550b7f6cb598b4c0", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:10:05.207Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:10:46.231Z", |
| | | "duration_ms": 41024 |
| | | }, |
| | | { |
| | | "agent_id": "acd1aa52bf3dd06d4", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:10:57.724Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:12:28.373Z", |
| | | "duration_ms": 90649 |
| | | }, |
| | | { |
| | | "agent_id": "a991ee262522932f5", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-15T14:12:34.926Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:16:41.286Z", |
| | | "duration_ms": 246360 |
| | | } |
| | | ], |
| | | "total_spawned": 33, |
| | | "total_completed": 33, |
| | | "total_spawned": 42, |
| | | "total_completed": 42, |
| | | "total_failed": 0, |
| | | "last_updated": "2026-04-15T06:10:46.596Z" |
| | | "last_updated": "2026-04-15T14:16:41.394Z" |
| | | } |
| | |
| | | public int Grade { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 任塿°é |
| | | /// </summary> |
| | | public int TaskQuantity { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public int WarehouseId { get; set; } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEAWCS_Core.BaseRepository; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_ITaskInfoRepository |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®ä»å¨æ¥å£ |
| | | /// </summary> |
| | | public interface IFakeBatteryPositionRepository : IRepository<Dt_FakeBatteryPosition> |
| | | { |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½åè¡¨ï¼æPositionIndexååº</returns> |
| | | List<int> GetNextAvailable(int count); |
| | | |
| | | /// <summary> |
| | | /// éç½®ææç¹ä½ä¸ºæªä½¿ç¨ |
| | | /// </summary> |
| | | /// <returns>å½±åçè¡æ°</returns> |
| | | int ResetAll(); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | | /// <param name="col">åï¼1-16ï¼</param> |
| | | /// <returns>ç¹ä½ç´¢å¼ï¼1-48ï¼ï¼æ¾ä¸å°è¿ånull</returns> |
| | | int? GetPositionIndex(int row, int col); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_ITaskInfoService |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡æ¥å£ |
| | | /// </summary> |
| | | public interface IFakeBatteryPositionService : IService<Dt_FakeBatteryPosition> |
| | | { |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½åè¡¨ï¼æPositionIndexååº</returns> |
| | | List<int> GetNextAvailable(int count); |
| | | |
| | | /// <summary> |
| | | /// éç½®ææç¹ä½ä¸ºæªä½¿ç¨ |
| | | /// </summary> |
| | | /// <returns>å½±åçè¡æ°</returns> |
| | | int ResetAll(); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | | /// <param name="col">åï¼1-16ï¼</param> |
| | | /// <returns>ç¹ä½ç´¢å¼ï¼1-48ï¼ï¼æ¾ä¸å°è¿ånull</returns> |
| | | int? GetPositionIndex(int row, int col); |
| | | |
| | | /// <summary> |
| | | /// åå§ååçµè¯ç¹ä½è¡¨ï¼48个ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»
å½è¡¨ä¸ºç©ºæ¶æå
¥1-48çåå§æ°æ®ã |
| | | /// 3è¡Ã16åï¼è¡ä¼å
æåã |
| | | /// </remarks> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool InitializeIfEmpty(); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using SqlSugar; |
| | | using WIDESEAWCS_Core.DB.Models; |
| | | |
| | | namespace WIDESEAWCS_Model.Models |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯å¹³é¢ç¹ä½è¡¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºç®¡çåçµè¯æåç¹çå¹³é¢ç¹ä½ä¿¡æ¯ã |
| | | /// 3è¡Ã16åå¸å±ï¼å
±48个ç¹ä½ï¼1-48ï¼ï¼è¡ä¼å
æåã |
| | | /// 第1è¡ï¼1-16ï¼ç¬¬2è¡ï¼17-32ï¼ç¬¬3è¡ï¼33-48ã |
| | | /// </remarks> |
| | | [SugarTable(nameof(Dt_FakeBatteryPosition), "åçµè¯å¹³é¢ç¹ä½è¡¨")] |
| | | public class Dt_FakeBatteryPosition : BaseEntity |
| | | { |
| | | /// <summary> |
| | | /// 主é®ID |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®ID")] |
| | | public int Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å¹³é¢ç¹ä½ç´¢å¼ï¼1-48ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 3Ã16å¸å±ï¼è¡ä¼å
ï¼1-16为第1è¡ï¼17-32为第2è¡ï¼33-48为第3è¡ï¼ã |
| | | /// </remarks> |
| | | [SugarColumn(ColumnDescription = "å¹³é¢ç¹ä½ç´¢å¼")] |
| | | public int PositionIndex { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æå¨è¡ï¼1-3ï¼ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æå¨è¡")] |
| | | public int Row { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æå¨åï¼1-16ï¼ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æå¨å")] |
| | | public int Col { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å·²ä½¿ç¨ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æ¯å¦å·²ä½¿ç¨")] |
| | | public bool IsUsed { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEAWCS_Core.BaseRepository; |
| | | using WIDESEAWCS_ITaskInfoRepository; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_TaskInfoRepository |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®ä»å¨å®ç° |
| | | /// </summary> |
| | | public class FakeBatteryPositionRepository : RepositoryBase<Dt_FakeBatteryPosition>, IFakeBatteryPositionRepository |
| | | { |
| | | public FakeBatteryPositionRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage) |
| | | { |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public List<int> GetNextAvailable(int count) |
| | | { |
| | | // æè¡ååååºæ¥è¯¢ææç¹ä½ |
| | | var allPositions = Db.Queryable<Dt_FakeBatteryPosition>() |
| | | .OrderBy(x => x.Row) |
| | | .OrderBy(x => x.Col) |
| | | .ToList(); |
| | | |
| | | // æè¡åç»ï¼å¨æ¯è¡å
æ¥æ¾è¿ç»å¯ç¨çç¹ä½ |
| | | var rows = allPositions.GroupBy(p => p.Row).OrderBy(g => g.Key); |
| | | |
| | | foreach (var rowGroup in rows) |
| | | { |
| | | var rowPositions = rowGroup.OrderBy(p => p.Col).ToList(); |
| | | |
| | | // å¨è¿ä¸è¡å
æ¥æ¾è¿ç»çcount个æªä½¿ç¨ç¹ä½ |
| | | for (int i = 0; i <= rowPositions.Count - count; i++) |
| | | { |
| | | var candidate = rowPositions.Skip(i).Take(count).ToList(); |
| | | |
| | | // æ£æ¥è¿count个ç¹ä½æ¯å¦é½æ¯è¿ç»çåï¼Colè¿ç»ï¼ä¸æªä½¿ç¨ |
| | | bool allAvailable = candidate.All(p => !p.IsUsed); |
| | | bool allConsecutive = true; |
| | | for (int j = 1; j < candidate.Count; j++) |
| | | { |
| | | if (candidate[j].Col != candidate[j - 1].Col + 1) |
| | | { |
| | | allConsecutive = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (allAvailable && allConsecutive) |
| | | { |
| | | return candidate.Select(p => p.PositionIndex).ToList(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æ²¡ææ¾å°è¿ç»ç空ç¹ä½ï¼è¿å空å表 |
| | | return new List<int>(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int ResetAll() |
| | | { |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, false) |
| | | .ExecuteCommand(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsUsed(List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | return true; |
| | | |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, true) |
| | | .Where(x => positions.Contains(x.PositionIndex)) |
| | | .ExecuteCommand() > 0; |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | var entity = Db.Queryable<Dt_FakeBatteryPosition>() |
| | | .Where(x => x.Row == row && x.Col == col) |
| | | .Select(x => new { x.PositionIndex }) |
| | | .First(); |
| | | return entity?.PositionIndex; |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_ITaskInfoRepository; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_TaskInfoService |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡å®ç° |
| | | /// </summary> |
| | | public class FakeBatteryPositionService : ServiceBase<Dt_FakeBatteryPosition, IFakeBatteryPositionRepository>, IFakeBatteryPositionService |
| | | { |
| | | public FakeBatteryPositionService(IFakeBatteryPositionRepository BaseDal) : base(BaseDal) |
| | | { |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public List<int> GetNextAvailable(int count) |
| | | { |
| | | return BaseDal.GetNextAvailable(count); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int ResetAll() |
| | | { |
| | | return BaseDal.ResetAll(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsUsed(List<int> positions) |
| | | { |
| | | return BaseDal.MarkAsUsed(positions); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | return BaseDal.GetPositionIndex(row, col); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool InitializeIfEmpty() |
| | | { |
| | | var existing = BaseDal.QueryFirst(x => true); |
| | | if (existing != null) |
| | | return true; |
| | | |
| | | // çæ48个ç¹ä½ï¼3è¡Ã16åï¼è¡ä¼å
|
| | | var positions = new List<Dt_FakeBatteryPosition>(); |
| | | for (int row = 1; row <= 3; row++) |
| | | { |
| | | for (int col = 1; col <= 16; col++) |
| | | { |
| | | int positionIndex = (row - 1) * 16 + col; |
| | | positions.Add(new Dt_FakeBatteryPosition |
| | | { |
| | | PositionIndex = positionIndex, |
| | | Row = row, |
| | | Col = col, |
| | | IsUsed = false, |
| | | Creater = "System" |
| | | }); |
| | | } |
| | | } |
| | | |
| | | return BaseDal.AddData(positions) > 0; |
| | | } |
| | | } |
| | | } |
| | |
| | | RobotTaskState = taskDTO.TaskStatus, |
| | | RobotGrade = taskDTO.Grade, |
| | | Creater = "WMS", |
| | | RobotTaskTotalNum = 48, |
| | | RobotTaskTotalNum = taskDTO.TaskQuantity, |
| | | }; |
| | | |
| | | BaseDal.AddData(task); |
| | |
| | | ITaskService taskService, |
| | | ICacheService cache, |
| | | HttpClientHelper httpClientHelper, |
| | | ILogger<RobotJob> logger) |
| | | ILogger<RobotJob> logger, |
| | | IFakeBatteryPositionService fakeBatteryPositionService) |
| | | { |
| | | // åå§åç¶æç®¡çå¨ï¼ä¼ å
¥ç¼åæå¡ |
| | | _stateManager = new RobotStateManager(cache, _logger); |
| | |
| | | ISocketClientGateway socketGateway = new SocketClientGateway(tcpSocket); |
| | | |
| | | // åå§åä»»å¡å¤çå¨ |
| | | _taskProcessor = new RobotTaskProcessor(socketGateway, _stateManager, robotTaskService, taskService, httpClientHelper, _logger); |
| | | _taskProcessor = new RobotTaskProcessor(socketGateway, _stateManager, robotTaskService, taskService, httpClientHelper, _logger, fakeBatteryPositionService); |
| | | |
| | | // åå§å客æ·ç«¯ç®¡çå¨ |
| | | _clientManager = new RobotClientManager(tcpSocket, _stateManager, _logger); |
| | |
| | | /// å½è¾¾å° MaxTaskTotalNum (48) æ¶ï¼ä¸åä¸åæ°ä»»å¡ã |
| | | /// </remarks> |
| | | public int RobotTaskTotalNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å¤äºåçµè¯è¡¥å
æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿£å¸¸çµè¯ä»»å¡å®æå设为 trueï¼æºå¨äººä»åçµè¯ä½ç½®è¡¥å
çµè¯è³48个ã |
| | | /// </remarks> |
| | | public bool IsInFakeBatteryMode { get; set; } |
| | | } |
| | | } |
| | |
| | | private readonly HttpClientHelper _httpClientHelper; |
| | | |
| | | /// <summary> |
| | | /// åçµè¯å¹³é¢ç¹ä½æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºç®¡çåçµè¯å¹³é¢ç¹ä½çåé
åç¶æã |
| | | /// </remarks> |
| | | private readonly IFakeBatteryPositionService _fakeBatteryPositionService; |
| | | |
| | | /// <summary> |
| | | /// æ¥å¿è®°å½å¨ |
| | | /// </summary> |
| | | private readonly ILogger _logger; |
| | |
| | | IRobotTaskService robotTaskService, |
| | | ITaskService taskService, |
| | | HttpClientHelper httpClientHelper, |
| | | ILogger logger) |
| | | ILogger logger, |
| | | IFakeBatteryPositionService fakeBatteryPositionService) |
| | | { |
| | | _socketClientGateway = socketClientGateway; |
| | | _stateManager = stateManager; |
| | |
| | | _taskService = taskService; |
| | | _httpClientHelper = httpClientHelper; |
| | | _logger = logger; |
| | | _fakeBatteryPositionService = fakeBatteryPositionService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¸ååçµè¯åè´§æä»¤å°æºå¨äººå®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åéæ ¼å¼ï¼Pickbattery,5,{startPosition}-{endPosition} |
| | | /// ä¾å¦ï¼Pickbattery,5,1-3 表示ä»åçµè¯ä½ç½®5æåï¼å¹³é¢ç¹ä½1å°3 |
| | | /// |
| | | /// ä¸åæååï¼ |
| | | /// 1. æ è®°ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// 2. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | /// 3. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">è¦æåçå¹³é¢ç¹ä½å表</param> |
| | | public async Task SendSocketRobotFakeBatteryPickAsync(Dt_RobotTask task, RobotSocketState state, List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | { |
| | | _logger.LogWarning("SendSocketRobotFakeBatteryPickAsyncï¼å¹³é¢ç¹ä½å表为空ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 计ç®ç¹ä½èå´ï¼æ ¼å¼ï¼1-3 |
| | | int startPos = positions.Min(); |
| | | int endPos = positions.Max(); |
| | | string taskString = $"Pickbattery,5,{startPos}-{endPos}"; |
| | | |
| | | // æ è®°ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | _fakeBatteryPositionService.MarkAsUsed(positions); |
| | | |
| | | // éè¿ Socket ç½å
³åéæä»¤å°æºå¨äººå®¢æ·ç«¯ |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸ååçµè¯åè´§æä»¤æåï¼æä»¤: {TaskString}ï¼ç¹ä½: {Positions}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, string.Join(",", positions), state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸ååçµè¯åè´§æä»¤æåï¼æä»¤: {taskString}", state.RobotCrane?.DeviceName); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // å°ä»»å¡å
³èå°ç¶æå¯¹è±¡ |
| | | state.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("ä¸ååçµè¯åè´§æä»¤å¤±è´¥ï¼æä»¤: {TaskString}ï¼è®¾å¤: {DeviceName}", taskString, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Error($"ä¸ååçµè¯åè´§æä»¤å¤±è´¥ï¼æä»¤: {taskString}", state.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½å表</returns> |
| | | public List<int> GetNextAvailableFakeBatteryPositions(int count) |
| | | { |
| | | return _fakeBatteryPositionService.GetNextAvailable(count); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤çå
¥åºä»»å¡åä¼ ï¼æç/ç»ç/æ¢çåºæ¯ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | |
| | | || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode(); |
| | | } |
| | | |
| | | // 妿æ¯ç»çä»»å¡ï¼å
æ¬æ¢çï¼ |
| | | // 妿æ¯ç»çä»»å¡ |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | // çææçæ¡ç åç¼ |
| | | const string prefix = "TRAY"; |
| | | |
| | | // çæä¸¤ä¸ªæçæ¡ç ï¼ç¨äºç»çæä½ï¼ |
| | | // çæä¸¤ä¸ªæçæ¡ç ï¼ç¨äºç»çæä½ï¼ï¼æµè¯ç¨ï¼åç»è¯»åçº¿ä½æ¡ç ï¼ |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | |
| | |
| | | QuartzLogger.Error($"çææçæ¡ç 失败", stateForUpdate.RobotCrane.DeviceName); |
| | | } |
| | | } |
| | | else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | // æ¢çä»»å¡ |
| | | // ç®æ ï¼æ£å¸¸çµè¯æå宿åï¼è¡¥å
åçµè¯è³48个 |
| | | const int targetTotal = 48; |
| | | const int fakeBatteryPickPosition = 5; // åçµè¯æåä½ç½® |
| | | const int pickCountPerExecution = 4; // æ¯æ¬¡æåæ°é |
| | | |
| | | int targetNormalCount = task.RobotTaskTotalNum; // æ£å¸¸çµè¯ç®æ æ°é |
| | | int currentCompletedCount = stateForUpdate.RobotTaskTotalNum; // 已宿æ°é |
| | | |
| | | // å¦æç®æ æ°é为48ï¼ç´æ¥ä¸åæ£å¸¸ä»»å¡ |
| | | if (targetNormalCount == targetTotal) |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | // 妿已宿æ°éå°äºç®æ æ°éï¼ç»§ç»æåæ£å¸¸çµè¯ |
| | | else if (currentCompletedCount < targetNormalCount) |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | // æ£å¸¸çµè¯å·²å®æï¼è¿å
¥åçµè¯è¡¥å
æ¨¡å¼ |
| | | else if (currentCompletedCount == targetNormalCount && !stateForUpdate.IsInFakeBatteryMode) |
| | | { |
| | | // 馿¬¡è¿å
¥åçµè¯æ¨¡å¼ï¼è®¾ç½®æ å¿ |
| | | stateForUpdate.IsInFakeBatteryMode = true; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ£å¸¸çµè¯æå宿ï¼è¿å
¥åçµè¯è¡¥å
模å¼ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"æ£å¸¸çµè¯æå宿ï¼è¿å
¥åçµè¯è¡¥å
模å¼", stateForUpdate.RobotCrane?.DeviceName); |
| | | } |
| | | |
| | | // 妿å¤äºåçµè¯è¡¥å
模å¼ï¼è®¡ç®å¹¶ä¸åè¡¥æ°ä»»å¡ |
| | | if (stateForUpdate.IsInFakeBatteryMode) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining > 0) |
| | | { |
| | | // è®¡ç®æ¯æ¬¡æåçæ°éï¼æå¤4ä¸ªï¼ |
| | | int pickCount = Math.Min(pickCountPerExecution, remaining); |
| | | |
| | | // è·åå¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"æ å¯ç¨åçµè¯ç¹ä½", stateForUpdate.RobotCrane?.DeviceName); |
| | | return; |
| | | } |
| | | |
| | | // ä¸ååçµè¯åè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions); |
| | | } |
| | | else |
| | | { |
| | | // åçµè¯è¡¥å
宿ï¼éç½®æ å¿ |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ¢çä»»å¡å®æï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"æ¢çä»»å¡å®æ", stateForUpdate.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // éç»çä»»å¡ï¼ç´æ¥åéåè´§æä»¤ |
| | |
| | | public int Grade { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 任塿°é |
| | | /// </summary> |
| | | public int TaskQuantity { get; set; } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | public int WarehouseId { get; set; } |
| | |
| | | if (string.IsNullOrWhiteSpace(stockPalletCode)) |
| | | return WebResponseContent.Instance.Error("æºæçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | stockInfo = await _stockInfoService.GetStockInfoAsync(stockPalletCode); |
| | | stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.PalletCode == stockPalletCode); |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æç[{stockPalletCode}]åºåä¸åå¨"); |
| | | |
| | |
| | | return WebResponseContent.Instance.Error($"æºæ¢°æ{taskName}ä»»å¡å建失败"); |
| | | |
| | | var wmstaskDto = _mapper.Map<WMSTaskDTO>(task) ?? new WMSTaskDTO(); |
| | | wmstaskDto.TaskQuantity = stock.Details?.Sum(d => d.Quantity) ?? 0; |
| | | return WebResponseContent.Instance.OK($"æºæ¢°æ{taskName}ä»»å¡å建æå", wmstaskDto); |
| | | } |
| | | catch (Exception ex) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¢çä»»å¡åçµè¯è¡¥å
é»è¾ Implementation Plan |
| | | |
| | | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| | | |
| | | **Goal:** å¨ `HandlePutFinishedStateAsync` ä¸å®ç°æ¢çä»»å¡çç¹æ®é»è¾ï¼å½ `task.RobotTaskTotalNum != 48` æ¶ï¼æ£å¸¸çµè¯ä»»å¡å®æåéè¡¥å
åçµè¯è³48个ã |
| | | |
| | | **Architecture:** æ¢çä»»å¡å䏤鶿®µæ§è¡ï¼(1) æ£å¸¸çµè¯æåé¶æ®µï¼(2) åçµè¯è¡¥å
é¶æ®µãåçµè¯ä»ä½ç½®5æåï¼æä»¤æ ¼å¼ `Pickbattery,5,1-3`ãæ°å¢ `Dt_FakeBatteryPosition` 表管ç3Ã16å¹³é¢ç¹ä½çå ç¨ç¶æã |
| | | |
| | | **Tech Stack:** C# / .NET 6, SqlSugar ORM, Redisç¼å |
| | | |
| | | --- |
| | | |
| | | ## File Structure |
| | | |
| | | ``` |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/ |
| | | + Dt_FakeBatteryPosition.cs # åçµè¯å¹³é¢ç¹ä½è¡¨å®ä½ |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/ |
| | | + IFakeBatteryPositionRepository.cs # åçµè¯ä½ç½®ä»å¨æ¥å£ |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/ |
| | | + FakeBatteryPositionRepository.cs # åçµè¯ä½ç½®ä»å¨å®ç° |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ |
| | | + IFakeBatteryPositionService.cs # åçµè¯ä½ç½®æå¡æ¥å£ |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/ |
| | | + FakeBatteryPositionService.cs # åçµè¯ä½ç½®æå¡å®ç° |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/ |
| | | = RobotSocketState.cs # +IsInFakeBatteryMode æ å¿ |
| | | = RobotTaskProcessor.cs # +SendSocketRobotFakeBatteryPickAsync æ¹æ³ |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/ |
| | | = RobotWorkflowOrchestrator.cs # å®ç° ChangePallet 忝宿´é»è¾ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 1: å建åçµè¯å¹³é¢ç¹ä½è¡¨å®ä½ |
| | | |
| | | **Files:** |
| | | - Create: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_FakeBatteryPosition.cs` |
| | | |
| | | - [ ] **Step 1: å建 Dt_FakeBatteryPosition.cs** |
| | | |
| | | ```csharp |
| | | using SqlSugar; |
| | | using WIDESEAWCS_Core.DB.Models; |
| | | |
| | | namespace WIDESEAWCS_Model.Models |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯å¹³é¢ç¹ä½è¡¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºç®¡çåçµè¯æåç¹çå¹³é¢ç¹ä½ä¿¡æ¯ã |
| | | /// 3è¡Ã16åå¸å±ï¼å
±48个ç¹ä½ï¼1-48ï¼ï¼è¡ä¼å
æåã |
| | | /// 第1è¡ï¼1-16ï¼ç¬¬2è¡ï¼17-32ï¼ç¬¬3è¡ï¼33-48ã |
| | | /// </remarks> |
| | | [SugarTable(nameof(Dt_FakeBatteryPosition), "åçµè¯å¹³é¢ç¹ä½è¡¨")] |
| | | public class Dt_FakeBatteryPosition : BaseEntity |
| | | { |
| | | /// <summary> |
| | | /// 主é®ID |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®ID")] |
| | | public int Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å¹³é¢ç¹ä½ç´¢å¼ï¼1-48ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 3Ã16å¸å±ï¼è¡ä¼å
ï¼1-16为第1è¡ï¼17-32为第2è¡ï¼33-48为第3è¡ï¼ã |
| | | /// </remarks> |
| | | [SugarColumn(ColumnDescription = "å¹³é¢ç¹ä½ç´¢å¼")] |
| | | public int PositionIndex { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æå¨è¡ï¼1-3ï¼ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æå¨è¡")] |
| | | public int Row { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æå¨åï¼1-16ï¼ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æå¨å")] |
| | | public int Col { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å·²ä½¿ç¨ |
| | | /// </summary> |
| | | [SugarColumn(ColumnDescription = "æ¯å¦å·²ä½¿ç¨")] |
| | | public bool IsUsed { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_FakeBatteryPosition.cs |
| | | git commit -m "feat(Robot): æ·»å åçµè¯å¹³é¢ç¹ä½è¡¨å®ä½ Dt_FakeBatteryPosition" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 2: å建åçµè¯ä½ç½®ä»å¨å± |
| | | |
| | | **Files:** |
| | | - Create: `WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/IFakeBatteryPositionRepository.cs` |
| | | - Create: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/FakeBatteryPositionRepository.cs` |
| | | |
| | | - [ ] **Step 1: å建 IFakeBatteryPositionRepository.cs** |
| | | |
| | | ```csharp |
| | | using WIDESEAWCS_Core.BaseRepository; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_ITaskInfoRepository |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®ä»å¨æ¥å£ |
| | | /// </summary> |
| | | public interface IFakeBatteryPositionRepository : IRepository<Dt_FakeBatteryPosition> |
| | | { |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½åè¡¨ï¼æPositionIndexååº</returns> |
| | | List<int> GetNextAvailable(int count); |
| | | |
| | | /// <summary> |
| | | /// éç½®ææç¹ä½ä¸ºæªä½¿ç¨ |
| | | /// </summary> |
| | | /// <returns>å½±åçè¡æ°</returns> |
| | | int ResetAll(); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | | /// <param name="col">åï¼1-16ï¼</param> |
| | | /// <returns>ç¹ä½ç´¢å¼ï¼1-48ï¼ï¼æ¾ä¸å°è¿ånull</returns> |
| | | int? GetPositionIndex(int row, int col); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å建 FakeBatteryPositionRepository.cs** |
| | | |
| | | ```csharp |
| | | using WIDESEAWCS_Core.BaseRepository; |
| | | using WIDESEAWCS_ITaskInfoRepository; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_TaskInfoRepository |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®ä»å¨å®ç° |
| | | /// </summary> |
| | | public class FakeBatteryPositionRepository : RepositoryBase<Dt_FakeBatteryPosition>, IFakeBatteryPositionRepository |
| | | { |
| | | public FakeBatteryPositionRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage) |
| | | { |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public List<int> GetNextAvailable(int count) |
| | | { |
| | | return Db.Queryable<Dt_FakeBatteryPosition>() |
| | | .Where(x => !x.IsUsed) |
| | | .OrderBy(x => x.PositionIndex) |
| | | .Take(count) |
| | | .Select(x => x.PositionIndex) |
| | | .ToList(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int ResetAll() |
| | | { |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, false) |
| | | .ExecuteCommand(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsUsed(List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | return true; |
| | | |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, true) |
| | | .Where(x => positions.Contains(x.PositionIndex)) |
| | | .ExecuteCommand() > 0; |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | return Db.Queryable<Dt_FakeBatteryPosition>() |
| | | .Where(x => x.Row == row && x.Col == col) |
| | | .Select(x => x.PositionIndex) |
| | | .FirstOrDefault(); |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/IFakeBatteryPositionRepository.cs |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/FakeBatteryPositionRepository.cs |
| | | git commit -m "feat(Robot): æ·»å åçµè¯ä½ç½®ä»å¨å±" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 3: å建åçµè¯ä½ç½®æå¡å± |
| | | |
| | | **Files:** |
| | | - Create: `WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IFakeBatteryPositionService.cs` |
| | | - Create: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/FakeBatteryPositionService.cs` |
| | | |
| | | - [ ] **Step 1: å建 IFakeBatteryPositionService.cs** |
| | | |
| | | ```csharp |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_ITaskInfoService |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡æ¥å£ |
| | | /// </summary> |
| | | public interface IFakeBatteryPositionService : IService<Dt_FakeBatteryPosition> |
| | | { |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½åè¡¨ï¼æPositionIndexååº</returns> |
| | | List<int> GetNextAvailable(int count); |
| | | |
| | | /// <summary> |
| | | /// éç½®ææç¹ä½ä¸ºæªä½¿ç¨ |
| | | /// </summary> |
| | | /// <returns>å½±åçè¡æ°</returns> |
| | | int ResetAll(); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | | /// <param name="col">åï¼1-16ï¼</param> |
| | | /// <returns>ç¹ä½ç´¢å¼ï¼1-48ï¼ï¼æ¾ä¸å°è¿ånull</returns> |
| | | int? GetPositionIndex(int row, int col); |
| | | |
| | | /// <summary> |
| | | /// åå§ååçµè¯ç¹ä½è¡¨ï¼48个ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ä»
å½è¡¨ä¸ºç©ºæ¶æå
¥1-48çåå§æ°æ®ã |
| | | /// 3è¡Ã16åï¼è¡ä¼å
æåã |
| | | /// </remarks> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool InitializeIfEmpty(); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å建 FakeBatteryPositionService.cs** |
| | | |
| | | ```csharp |
| | | using WIDESEAWCS_Core.BaseServices; |
| | | using WIDESEAWCS_ITaskInfoRepository; |
| | | using WIDESEAWCS_Model.Models; |
| | | |
| | | namespace WIDESEAWCS_TaskInfoService |
| | | { |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡å®ç° |
| | | /// </summary> |
| | | public class FakeBatteryPositionService : ServiceBase<Dt_FakeBatteryPosition, IFakeBatteryPositionRepository>, IFakeBatteryPositionService |
| | | { |
| | | public FakeBatteryPositionService(IFakeBatteryPositionRepository BaseDal) : base(BaseDal) |
| | | { |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public List<int> GetNextAvailable(int count) |
| | | { |
| | | return BaseDal.GetNextAvailable(count); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int ResetAll() |
| | | { |
| | | return BaseDal.ResetAll(); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsUsed(List<int> positions) |
| | | { |
| | | return BaseDal.MarkAsUsed(positions); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | return BaseDal.GetPositionIndex(row, col); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool InitializeIfEmpty() |
| | | { |
| | | var existing = BaseDal.QueryFirst(x => true); |
| | | if (existing != null) |
| | | return true; |
| | | |
| | | // çæ48个ç¹ä½ï¼3è¡Ã16åï¼è¡ä¼å
|
| | | var positions = new List<Dt_FakeBatteryPosition>(); |
| | | for (int row = 1; row <= 3; row++) |
| | | { |
| | | for (int col = 1; col <= 16; col++) |
| | | { |
| | | int positionIndex = (row - 1) * 16 + col; |
| | | positions.Add(new Dt_FakeBatteryPosition |
| | | { |
| | | PositionIndex = positionIndex, |
| | | Row = row, |
| | | Col = col, |
| | | IsUsed = false, |
| | | Creater = "System" |
| | | }); |
| | | } |
| | | } |
| | | |
| | | return BaseDal.AddData(positions) > 0; |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IFakeBatteryPositionService.cs |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/FakeBatteryPositionService.cs |
| | | git commit -m "feat(Robot): æ·»å åçµè¯ä½ç½®æå¡å±" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 4: ä¿®æ¹ RobotSocketState æ·»å IsInFakeBatteryMode æ å¿ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs:175` (å¨ `RobotTaskTotalNum` 屿§åæ·»å ) |
| | | |
| | | - [ ] **Step 1: æ·»å IsInFakeBatteryMode 屿§** |
| | | |
| | | å¨ `RobotSocketState.cs` ç `RobotTaskTotalNum` 屿§åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æºå¨äººå·²å¤çç任塿»æ° |
| | | /// </summary> |
| | | public int RobotTaskTotalNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦å¤äºåçµè¯è¡¥å
æ¨¡å¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿£å¸¸çµè¯ä»»å¡å®æå设为 trueï¼æºå¨äººä»åçµè¯ä½ç½®è¡¥å
çµè¯è³48个ã |
| | | /// </remarks> |
| | | public bool IsInFakeBatteryMode { get; set; } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs |
| | | git commit -m "feat(Robot): RobotSocketState æ·»å IsInFakeBatteryMode æ å¿" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 5: ä¿®æ¹ RobotTaskProcessor æ·»å åçµè¯åè´§æä»¤æ¹æ³ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs` (å¨ `SendSocketRobotPickAsync` åæ·»å æ°æ¹æ³) |
| | | |
| | | - [ ] **Step 1: æ·»å IFakeBatteryPositionService ä¾èµ** |
| | | |
| | | å¨ `RobotTaskProcessor` æé 彿°ä¸æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | private readonly IFakeBatteryPositionService _fakeBatteryPositionService; |
| | | |
| | | // æé 彿°åæ°ä¸æ·»å ï¼ |
| | | , IFakeBatteryPositionService fakeBatteryPositionService |
| | | |
| | | // æé 彿°èµå¼ï¼ |
| | | _fakeBatteryPositionService = fakeBatteryPositionService; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ·»å SendSocketRobotFakeBatteryPickAsync æ¹æ³** |
| | | |
| | | å¨ `SendSocketRobotPickAsync` æ¹æ³åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// ä¸ååçµè¯åè´§æä»¤å°æºå¨äººå®¢æ·ç«¯ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åéæ ¼å¼ï¼Pickbattery,5,{startPosition}-{endPosition} |
| | | /// ä¾å¦ï¼Pickbattery,5,1-3 表示ä»åçµè¯ä½ç½®5æåï¼å¹³é¢ç¹ä½1å°3 |
| | | /// |
| | | /// ä¸åæååï¼ |
| | | /// 1. æ è®°ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | /// 2. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | /// 3. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">è¦æåçå¹³é¢ç¹ä½å表</param> |
| | | public async Task SendSocketRobotFakeBatteryPickAsync(Dt_RobotTask task, RobotSocketState state, List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | { |
| | | _logger.LogWarning("SendSocketRobotFakeBatteryPickAsyncï¼å¹³é¢ç¹ä½å表为空ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 计ç®ç¹ä½èå´ï¼æ ¼å¼ï¼1-3 |
| | | int startPos = positions.Min(); |
| | | int endPos = positions.Max(); |
| | | string taskString = $"Pickbattery,5,{startPos}-{endPos}"; |
| | | |
| | | // æ è®°ç¹ä½ä¸ºå·²ä½¿ç¨ |
| | | _fakeBatteryPositionService.MarkAsUsed(positions); |
| | | |
| | | // éè¿ Socket ç½å
³åéæä»¤å°æºå¨äººå®¢æ·ç«¯ |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸ååçµè¯åè´§æä»¤æåï¼æä»¤: {TaskString}ï¼ç¹ä½: {Positions}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, string.Join(",", positions), state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸ååçµè¯åè´§æä»¤æåï¼æä»¤: {taskString}", state.RobotCrane?.DeviceName); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // å°ä»»å¡å
³èå°ç¶æå¯¹è±¡ |
| | | state.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("ä¸ååçµè¯åè´§æä»¤å¤±è´¥ï¼æä»¤: {TaskString}ï¼è®¾å¤: {DeviceName}", taskString, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Error($"ä¸ååçµè¯åè´§æä»¤å¤±è´¥ï¼æä»¤: {taskString}", state.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs |
| | | git commit -m "feat(Robot): RobotTaskProcessor æ·»å åçµè¯åè´§æä»¤æ¹æ³" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 6: å®ç° HandlePutFinishedStateAsync ä¸ç ChangePallet 宿´é»è¾ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs:285-300` |
| | | |
| | | - [ ] **Step 1: å®ç° ChangePallet 忝é»è¾** |
| | | |
| | | å°ç°æçå ä½ä»£ç æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | // æ¢çä»»å¡ |
| | | // ç®æ ï¼æ£å¸¸çµè¯æå宿åï¼è¡¥å
åçµè¯è³48个 |
| | | const int targetTotal = 48; |
| | | const int fakeBatteryPickPosition = 5; // åçµè¯æåä½ç½® |
| | | const int pickCountPerExecution = 4; // æ¯æ¬¡æåæ°é |
| | | |
| | | int targetNormalCount = task.RobotTaskTotalNum; // æ£å¸¸çµè¯ç®æ æ°é |
| | | int currentCompletedCount = stateForUpdate.RobotTaskTotalNum; // 已宿æ°é |
| | | |
| | | // å¦æç®æ æ°é为48ï¼ç´æ¥ä¸åæ£å¸¸ä»»å¡ |
| | | if (targetNormalCount == targetTotal) |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | // 妿已宿æ°éå°äºç®æ æ°éï¼ç»§ç»æåæ£å¸¸çµè¯ |
| | | else if (currentCompletedCount < targetNormalCount) |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | // æ£å¸¸çµè¯å·²å®æï¼è¿å
¥åçµè¯è¡¥å
æ¨¡å¼ |
| | | else if (currentCompletedCount == targetNormalCount && !stateForUpdate.IsInFakeBatteryMode) |
| | | { |
| | | // 馿¬¡è¿å
¥åçµè¯æ¨¡å¼ï¼è®¾ç½®æ å¿ |
| | | stateForUpdate.IsInFakeBatteryMode = true; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ£å¸¸çµè¯æå宿ï¼è¿å
¥åçµè¯è¡¥å
模å¼ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"æ£å¸¸çµè¯æå宿ï¼è¿å
¥åçµè¯è¡¥å
模å¼", stateForUpdate.RobotCrane?.DeviceName); |
| | | } |
| | | |
| | | // 妿å¤äºåçµè¯è¡¥å
模å¼ï¼è®¡ç®å¹¶ä¸åè¡¥æ°ä»»å¡ |
| | | if (stateForUpdate.IsInFakeBatteryMode) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining > 0) |
| | | { |
| | | // è®¡ç®æ¯æ¬¡æåçæ°éï¼æå¤4ä¸ªï¼ |
| | | int pickCount = Math.Min(pickCountPerExecution, remaining); |
| | | |
| | | // è·åå¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"æ å¯ç¨åçµè¯ç¹ä½", stateForUpdate.RobotCrane?.DeviceName); |
| | | return; |
| | | } |
| | | |
| | | // ä¸ååçµè¯åè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions); |
| | | } |
| | | else |
| | | { |
| | | // åçµè¯è¡¥å
宿ï¼éç½®æ å¿ |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ¢çä»»å¡å®æï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"æ¢çä»»å¡å®æ", stateForUpdate.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å¨ RobotTaskProcessor 䏿·»å GetNextAvailableFakeBatteryPositions è¾
婿¹æ³** |
| | | |
| | | å¨ `RobotTaskProcessor` 䏿·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// è·åä¸N个å¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | /// </summary> |
| | | /// <param name="count">éè¦è·åçç¹ä½æ°é</param> |
| | | /// <returns>å¯ç¨ç¹ä½å表</returns> |
| | | public List<int> GetNextAvailableFakeBatteryPositions(int count) |
| | | { |
| | | return _fakeBatteryPositionService.GetNextAvailable(count); |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs |
| | | git commit -m "feat(Robot): å®ç°æ¢çä»»å¡åçµè¯è¡¥å
é»è¾" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 7: éªè¯æå»º |
| | | |
| | | - [ ] **Step 1: è¿è¡ dotnet build** |
| | | |
| | | ```bash |
| | | dotnet build WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ£æ¥æ¯å¦æç¼è¯é误** |
| | | |
| | | --- |
| | | |
| | | ## éå½ï¼æ°æ®åºåå§åSQL |
| | | |
| | | ```sql |
| | | -- åå§ååçµè¯å¹³é¢ç¹ä½è¡¨ï¼48个ç¹ä½ï¼3è¡Ã16åï¼è¡ä¼å
ï¼ |
| | | -- 第1è¡ï¼1-16ï¼ç¬¬2è¡ï¼17-32ï¼ç¬¬3è¡ï¼33-48 |
| | | IF NOT EXISTS (SELECT 1 FROM Dt_FakeBatteryPosition) |
| | | BEGIN |
| | | INSERT INTO Dt_FakeBatteryPosition (PositionIndex, Row, Col, IsUsed, Creater, CreateDate) |
| | | SELECT |
| | | ((row - 1) * 16 + col) AS PositionIndex, |
| | | row AS Row, |
| | | col AS Col, |
| | | 0 AS IsUsed, |
| | | 'System' AS Creater, |
| | | GETDATE() AS CreateDate |
| | | FROM (SELECT 1 AS row UNION SELECT 2 UNION SELECT 3) AS rows |
| | | CROSS JOIN (SELECT 1 AS col UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 |
| | | UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 |
| | | UNION SELECT 13 UNION SELECT 14 UNION SELECT 15 UNION SELECT 16) AS cols |
| | | ORDER BY row, col; |
| | | END |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | **Plan complete and saved to `docs/superpowers/plans/2026-04-15-change-pallet-fake-battery.md`. Two execution options:** |
| | | |
| | | **1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration |
| | | |
| | | **2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints |
| | | |
| | | **Which approach?** |