已添加12个文件
已删除1个文件
已修改24个文件
| | |
| | | # Git worktrees (isolated workspaces) |
| | | .worktrees/ |
| | | worktrees/ |
| | | .omc/ |
| | | |
| | | # Nuget packages directory |
| | | packages/ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"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":"ae1b992","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ae1b992","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":38937} |
| | | {"t":0,"agent":"a13c6d6","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a13c6d6","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":22242} |
| | | {"t":0,"agent":"ae5f507","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ae5f507","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":21126} |
| | | {"t":0,"agent":"ab64c32","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ab64c32","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":24981} |
| | | {"t":0,"agent":"aa35de1","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aa35de1","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":16562} |
| | | {"t":0,"agent":"abc7829","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"abc7829","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":19081} |
| | | {"t":0,"agent":"aa920a6","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aa920a6","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":42219} |
| | | {"t":0,"agent":"a1432d1","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a1432d1","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":18827} |
| | | {"t":0,"agent":"a7fa0a6","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a7fa0a6","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":21618} |
| | | {"t":0,"agent":"a15c777","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a15c777","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":94170} |
| | | {"t":0,"agent":"ad4599d","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ad4599d","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":21240} |
| | | {"t":0,"agent":"ad3da31","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ad3da31","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":82778} |
| | | {"t":0,"agent":"abb3857","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"abb3857","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":146432} |
| | | {"t":0,"agent":"a7103e2","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a7103e2","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":55971} |
| | | {"t":0,"agent":"a06ff50","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a06ff50","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":33830} |
| | | {"t":0,"agent":"a82ce3a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a82ce3a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":46724} |
| | | {"t":0,"agent":"aae2ba6","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aae2ba6","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":20220} |
| | | {"t":0,"agent":"a06945f","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a06945f","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":70377} |
| | | {"t":0,"agent":"aaa0767","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aaa0767","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":21965} |
| | | {"t":0,"agent":"a93b1a0","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a93b1a0","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":16241} |
| | | {"t":0,"agent":"a2f4b0e","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a2f4b0e","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":242121} |
| | | {"t":0,"agent":"a9268a7","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a9268a7","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":15757} |
| | | {"t":0,"agent":"a19a767","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a19a767","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":16955} |
| | | {"t":0,"agent":"ac74c0a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ac74c0a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":115622} |
| | | {"t":0,"agent":"afe8178","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"afe8178","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":33425} |
| | | {"t":0,"agent":"a278b04","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a278b04","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":148353} |
| | | {"t":0,"agent":"a93149b","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a93149b","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":111569} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:finishing-a-development-branch"} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:brainstorming"} |
| | | {"t":0,"agent":"aab4d29","agent_type":"code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aab4d29","agent_type":"code-reviewer","event":"agent_stop","success":true,"duration_ms":301448} |
| | | {"t":0,"agent":"a3ca65d","agent_type":"code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a3ca65d","agent_type":"code-reviewer","event":"agent_stop","success":true,"duration_ms":110707} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:writing-plans"} |
| | | {"t":0,"agent":"a8078d8","agent_type":"code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a8078d8","agent_type":"code-reviewer","event":"agent_stop","success":true,"duration_ms":48817} |
| | | {"t":0,"agent":"a789651","agent_type":"code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a789651","agent_type":"code-reviewer","event":"agent_stop","success":true,"duration_ms":363405} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:subagent-driven-development"} |
| | | {"t":0,"agent":"a9cfe1f","agent_type":"unknown","event":"agent_stop","success":true} |
| | | {"t":0,"agent":"a089308","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a089308","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":171986} |
| | | {"t":0,"agent":"a4b1abc","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ab8096e","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"adc57d5","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "created_at": "2026-04-16T05:56:05.018Z", |
| | | "trigger": "auto", |
| | | "active_modes": {}, |
| | | "todo_summary": { |
| | | "pending": 0, |
| | | "in_progress": 0, |
| | | "completed": 0 |
| | | }, |
| | | "wisdom_exported": false, |
| | | "background_jobs": { |
| | | "active": [], |
| | | "recent": [], |
| | | "stats": null |
| | | } |
| | | } |
| | |
| | | { |
| | | "lastSentAt": "2026-04-15T14:42:46.838Z" |
| | | "lastSentAt": "2026-04-16T15:29:53.609Z" |
| | | } |
| | |
| | | { |
| | | "tool_name": "Bash", |
| | | "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 |
| | | "tool_name": "Read", |
| | | "tool_input_preview": "{\"file_path\":\"D:\\\\Git\\\\ShanMeiXinNengYuan\\\\Code\\\\WCS\\\\WIDESEAWCS_Server\\\\WIDESEA_DTO\\\\Stock\\\\StockDTO.cs\"}", |
| | | "error": "File does not exist. Note: your current working directory is D:\\Git\\ShanMeiXinNengYuan\\Code.", |
| | | "timestamp": "2026-04-16T15:04:27.059Z", |
| | | "retry_count": 2 |
| | | } |
| | |
| | | { |
| | | "updatedAt": "2026-04-15T14:16:41.286Z", |
| | | "updatedAt": "2026-04-16T13:59:54.835Z", |
| | | "missions": [ |
| | | { |
| | | "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none", |
| | |
| | | "sourceKey": "session-stop:a991ee262522932f5" |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "session:358cfb75-d493-40fb-94ed-f795f943182b:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-16T02:59:26.042Z", |
| | | "updatedAt": "2026-04-16T06:05:51.361Z", |
| | | "status": "running", |
| | | "workerCount": 8, |
| | | "taskCounts": { |
| | | "total": 8, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 3, |
| | | "completed": 5, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "code-reviewer:aab4d29", |
| | | "role": "code-reviewer", |
| | | "ownership": "aab4d29faa1a3cd33", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T05:57:18.762Z" |
| | | }, |
| | | { |
| | | "name": "code-reviewer:a3ca65d", |
| | | "role": "code-reviewer", |
| | | "ownership": "a3ca65d5e9e566acc", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T03:21:01.279Z" |
| | | }, |
| | | { |
| | | "name": "code-reviewer:a8078d8", |
| | | "role": "code-reviewer", |
| | | "ownership": "a8078d862c25a2973", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T05:40:16.461Z" |
| | | }, |
| | | { |
| | | "name": "code-reviewer:a789651", |
| | | "role": "code-reviewer", |
| | | "ownership": "a78965129a4ecaee2", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T05:50:59.155Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a089308", |
| | | "role": "general-purpose", |
| | | "ownership": "a089308fce13261b6", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T06:00:35.344Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a4b1abc", |
| | | "role": "general-purpose", |
| | | "ownership": "a4b1abcbbe45f220a", |
| | | "status": "running", |
| | | "currentStep": null, |
| | | "latestUpdate": null, |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T06:00:51.582Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ab8096e", |
| | | "role": "general-purpose", |
| | | "ownership": "ab8096ee80268e720", |
| | | "status": "running", |
| | | "currentStep": null, |
| | | "latestUpdate": null, |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T06:05:29.655Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:adc57d5", |
| | | "role": "general-purpose", |
| | | "ownership": "adc57d5ba6bbc20c1", |
| | | "status": "running", |
| | | "currentStep": null, |
| | | "latestUpdate": null, |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T06:05:51.361Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:a4b1abcbbe45f220a:2026-04-16T06:00:51.582Z", |
| | | "at": "2026-04-16T06:00:51.582Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a4b1abc", |
| | | "detail": "started general-purpose:a4b1abc", |
| | | "sourceKey": "session-start:a4b1abcbbe45f220a" |
| | | }, |
| | | { |
| | | "id": "session-start:ab8096ee80268e720:2026-04-16T06:05:29.655Z", |
| | | "at": "2026-04-16T06:05:29.655Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:ab8096e", |
| | | "detail": "started general-purpose:ab8096e", |
| | | "sourceKey": "session-start:ab8096ee80268e720" |
| | | }, |
| | | { |
| | | "id": "session-start:adc57d5ba6bbc20c1:2026-04-16T06:05:51.361Z", |
| | | "at": "2026-04-16T06:05:51.361Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:adc57d5", |
| | | "detail": "started general-purpose:adc57d5", |
| | | "sourceKey": "session-start:adc57d5ba6bbc20c1" |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "session:2b26e0d1-aaf0-4052-80ce-6ac16773aa04:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-16T13:29:32.117Z", |
| | | "updatedAt": "2026-04-16T13:59:54.835Z", |
| | | "status": "done", |
| | | "workerCount": 27, |
| | | "taskCounts": { |
| | | "total": 27, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 0, |
| | | "completed": 27, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "general-purpose:ae1b992", |
| | | "role": "general-purpose", |
| | | "ownership": "ae1b9928fed053dab", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:30:11.054Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a13c6d6", |
| | | "role": "general-purpose", |
| | | "ownership": "a13c6d6fa489cf43f", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:30:47.127Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ae5f507", |
| | | "role": "general-purpose", |
| | | "ownership": "ae5f507bce27980a7", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:31:14.414Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ab64c32", |
| | | "role": "general-purpose", |
| | | "ownership": "ab64c32ded08f4496", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:31:54.680Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:aa35de1", |
| | | "role": "general-purpose", |
| | | "ownership": "aa35de1f9a3a458f8", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:32:17.868Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:abc7829", |
| | | "role": "general-purpose", |
| | | "ownership": "abc782903e12397e0", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:32:42.368Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:aa920a6", |
| | | "role": "general-purpose", |
| | | "ownership": "aa920a67ffd9738ad", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:33:38.081Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a1432d1", |
| | | "role": "general-purpose", |
| | | "ownership": "a1432d1eaad43f135", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:34:03.851Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a7fa0a6", |
| | | "role": "general-purpose", |
| | | "ownership": "a7fa0a68a3e22dc75", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:34:33.092Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a15c777", |
| | | "role": "general-purpose", |
| | | "ownership": "a15c777f2ea430420", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:36:49.197Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ad4599d", |
| | | "role": "general-purpose", |
| | | "ownership": "ad4599d8f93863a39", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:37:20.551Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ad3da31", |
| | | "role": "general-purpose", |
| | | "ownership": "ad3da315642eaf667", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:38:51.689Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:abb3857", |
| | | "role": "general-purpose", |
| | | "ownership": "abb3857c0a5fbcf61", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:41:33.360Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a7103e2", |
| | | "role": "general-purpose", |
| | | "ownership": "a7103e22eb25f9483", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:42:39.118Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a06ff50", |
| | | "role": "general-purpose", |
| | | "ownership": "a06ff508885a4867e", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:43:32.081Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a82ce3a", |
| | | "role": "general-purpose", |
| | | "ownership": "a82ce3a41dd1c1400", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:44:25.819Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:aae2ba6", |
| | | "role": "general-purpose", |
| | | "ownership": "aae2ba6f974a382f2", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:44:53.801Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a06945f", |
| | | "role": "general-purpose", |
| | | "ownership": "a06945f987220703d", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:46:20.822Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:aaa0767", |
| | | "role": "general-purpose", |
| | | "ownership": "aaa07676e0c05c622", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:46:49.019Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a93b1a0", |
| | | "role": "general-purpose", |
| | | "ownership": "a93b1a0c14459720b", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:47:10.678Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a2f4b0e", |
| | | "role": "general-purpose", |
| | | "ownership": "a2f4b0e1c77c785b0", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:51:26.670Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a9268a7", |
| | | "role": "general-purpose", |
| | | "ownership": "a9268a79714555bc6", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:51:52.517Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a19a767", |
| | | "role": "general-purpose", |
| | | "ownership": "a19a76743c10df1a1", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:52:15.500Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ac74c0a", |
| | | "role": "general-purpose", |
| | | "ownership": "ac74c0af0952387a3", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:54:22.962Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:afe8178", |
| | | "role": "general-purpose", |
| | | "ownership": "afe8178d0a09a72ff", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:55:15.934Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a278b04", |
| | | "role": "general-purpose", |
| | | "ownership": "a278b0417e3bfb390", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:57:54.276Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a93149b", |
| | | "role": "general-purpose", |
| | | "ownership": "a93149b10e8b430e7", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-16T13:59:54.835Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:a278b0417e3bfb390:2026-04-16T13:55:25.923Z", |
| | | "at": "2026-04-16T13:55:25.923Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a278b04", |
| | | "detail": "started general-purpose:a278b04", |
| | | "sourceKey": "session-start:a278b0417e3bfb390" |
| | | }, |
| | | { |
| | | "id": "session-stop:a278b0417e3bfb390:2026-04-16T13:57:54.276Z", |
| | | "at": "2026-04-16T13:57:54.276Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:a278b04", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a278b0417e3bfb390" |
| | | }, |
| | | { |
| | | "id": "session-start:a93149b10e8b430e7:2026-04-16T13:58:03.266Z", |
| | | "at": "2026-04-16T13:58:03.266Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a93149b", |
| | | "detail": "started general-purpose:a93149b", |
| | | "sourceKey": "session-start:a93149b10e8b430e7" |
| | | }, |
| | | { |
| | | "id": "session-stop:a93149b10e8b430e7:2026-04-16T13:59:54.835Z", |
| | | "at": "2026-04-16T13:59:54.835Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:a93149b", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a93149b10e8b430e7" |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | |
| | | "status": "completed", |
| | | "completed_at": "2026-04-15T14:16:41.286Z", |
| | | "duration_ms": 246360 |
| | | }, |
| | | { |
| | | "agent_id": "aab4d29faa1a3cd33", |
| | | "agent_type": "code-reviewer", |
| | | "started_at": "2026-04-16T02:59:26.042Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T03:04:27.490Z", |
| | | "duration_ms": 301448 |
| | | }, |
| | | { |
| | | "agent_id": "a3ca65d5e9e566acc", |
| | | "agent_type": "code-reviewer", |
| | | "started_at": "2026-04-16T03:19:10.572Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T03:21:01.279Z", |
| | | "duration_ms": 110707 |
| | | }, |
| | | { |
| | | "agent_id": "a8078d862c25a2973", |
| | | "agent_type": "code-reviewer", |
| | | "started_at": "2026-04-16T05:39:27.644Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T05:40:16.461Z", |
| | | "duration_ms": 48817 |
| | | }, |
| | | { |
| | | "agent_id": "a78965129a4ecaee2", |
| | | "agent_type": "code-reviewer", |
| | | "started_at": "2026-04-16T05:44:55.750Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T05:50:59.155Z", |
| | | "duration_ms": 363405 |
| | | }, |
| | | { |
| | | "agent_id": "a089308fce13261b6", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T05:57:43.358Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T06:00:35.344Z", |
| | | "duration_ms": 171986 |
| | | }, |
| | | { |
| | | "agent_id": "a4b1abcbbe45f220a", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T06:00:51.582Z", |
| | | "parent_mode": "none", |
| | | "status": "running" |
| | | }, |
| | | { |
| | | "agent_id": "ab8096ee80268e720", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T06:05:29.655Z", |
| | | "parent_mode": "none", |
| | | "status": "running" |
| | | }, |
| | | { |
| | | "agent_id": "adc57d5ba6bbc20c1", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T06:05:51.361Z", |
| | | "parent_mode": "none", |
| | | "status": "running" |
| | | }, |
| | | { |
| | | "agent_id": "ae1b9928fed053dab", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:29:32.117Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:30:11.054Z", |
| | | "duration_ms": 38937 |
| | | }, |
| | | { |
| | | "agent_id": "a13c6d6fa489cf43f", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:30:24.885Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:30:47.127Z", |
| | | "duration_ms": 22242 |
| | | }, |
| | | { |
| | | "agent_id": "ae5f507bce27980a7", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:30:53.288Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:31:14.414Z", |
| | | "duration_ms": 21126 |
| | | }, |
| | | { |
| | | "agent_id": "ab64c32ded08f4496", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:31:29.699Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:31:54.680Z", |
| | | "duration_ms": 24981 |
| | | }, |
| | | { |
| | | "agent_id": "aa35de1f9a3a458f8", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:32:01.306Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:32:17.868Z", |
| | | "duration_ms": 16562 |
| | | }, |
| | | { |
| | | "agent_id": "abc782903e12397e0", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:32:23.287Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:32:42.368Z", |
| | | "duration_ms": 19081 |
| | | }, |
| | | { |
| | | "agent_id": "aa920a67ffd9738ad", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:32:55.862Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:33:38.081Z", |
| | | "duration_ms": 42219 |
| | | }, |
| | | { |
| | | "agent_id": "a1432d1eaad43f135", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:33:45.024Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:34:03.851Z", |
| | | "duration_ms": 18827 |
| | | }, |
| | | { |
| | | "agent_id": "a7fa0a68a3e22dc75", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:34:11.474Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:34:33.092Z", |
| | | "duration_ms": 21618 |
| | | }, |
| | | { |
| | | "agent_id": "a15c777f2ea430420", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:35:15.027Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:36:49.197Z", |
| | | "duration_ms": 94170 |
| | | }, |
| | | { |
| | | "agent_id": "ad4599d8f93863a39", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:36:59.311Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:37:20.551Z", |
| | | "duration_ms": 21240 |
| | | }, |
| | | { |
| | | "agent_id": "ad3da315642eaf667", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:37:28.911Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:38:51.689Z", |
| | | "duration_ms": 82778 |
| | | }, |
| | | { |
| | | "agent_id": "abb3857c0a5fbcf61", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:39:06.928Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:41:33.360Z", |
| | | "duration_ms": 146432 |
| | | }, |
| | | { |
| | | "agent_id": "a7103e22eb25f9483", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:41:43.147Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:42:39.118Z", |
| | | "duration_ms": 55971 |
| | | }, |
| | | { |
| | | "agent_id": "a06ff508885a4867e", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:42:58.251Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:43:32.081Z", |
| | | "duration_ms": 33830 |
| | | }, |
| | | { |
| | | "agent_id": "a82ce3a41dd1c1400", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:43:39.095Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:44:25.819Z", |
| | | "duration_ms": 46724 |
| | | }, |
| | | { |
| | | "agent_id": "aae2ba6f974a382f2", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:44:33.581Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:44:53.801Z", |
| | | "duration_ms": 20220 |
| | | }, |
| | | { |
| | | "agent_id": "a06945f987220703d", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:45:10.445Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:46:20.822Z", |
| | | "duration_ms": 70377 |
| | | }, |
| | | { |
| | | "agent_id": "aaa07676e0c05c622", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:46:27.054Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:46:49.019Z", |
| | | "duration_ms": 21965 |
| | | }, |
| | | { |
| | | "agent_id": "a93b1a0c14459720b", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:46:54.437Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:47:10.678Z", |
| | | "duration_ms": 16241 |
| | | }, |
| | | { |
| | | "agent_id": "a2f4b0e1c77c785b0", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:47:24.549Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:51:26.670Z", |
| | | "duration_ms": 242121 |
| | | }, |
| | | { |
| | | "agent_id": "a9268a79714555bc6", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:51:36.760Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:51:52.517Z", |
| | | "duration_ms": 15757 |
| | | }, |
| | | { |
| | | "agent_id": "a19a76743c10df1a1", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:51:58.545Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:52:15.500Z", |
| | | "duration_ms": 16955 |
| | | }, |
| | | { |
| | | "agent_id": "ac74c0af0952387a3", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:52:27.340Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:54:22.962Z", |
| | | "duration_ms": 115622 |
| | | }, |
| | | { |
| | | "agent_id": "afe8178d0a09a72ff", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:54:42.509Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:55:15.934Z", |
| | | "duration_ms": 33425 |
| | | }, |
| | | { |
| | | "agent_id": "a278b0417e3bfb390", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:55:25.923Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:57:54.276Z", |
| | | "duration_ms": 148353 |
| | | }, |
| | | { |
| | | "agent_id": "a93149b10e8b430e7", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-16T13:58:03.266Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-16T13:59:54.835Z", |
| | | "duration_ms": 111569 |
| | | } |
| | | ], |
| | | "total_spawned": 42, |
| | | "total_completed": 42, |
| | | "total_spawned": 77, |
| | | "total_completed": 74, |
| | | "total_failed": 0, |
| | | "last_updated": "2026-04-15T14:16:41.394Z" |
| | | "last_updated": "2026-04-16T13:59:54.939Z" |
| | | } |
| | |
| | | /// <summary> |
| | | /// 空æçåºåºå®æï¼æ ¹æ®ä»»å¡å·åæçå·éç¥WMS空æçåºåºå®æï¼ |
| | | /// </summary> |
| | | OutboundFinishTaskTray |
| | | OutboundFinishTaskTray, |
| | | |
| | | /// <summary> |
| | | /// æ¹éæç确认 |
| | | /// </summary> |
| | | SplitPalletConfirm, |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 |
| | | /// </summary> |
| | | GroupPalletConfirm |
| | | |
| | | #endregion WMSæ¥å£ |
| | | } |
| | |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå¯ç¨ï¼éæ¾ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsAvailable(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | |
| | | bool MarkAsUsed(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå¯ç¨ï¼éæ¾ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsAvailable(List<int> positions); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¡ååè·åç¹ä½ç´¢å¼ |
| | | /// </summary> |
| | | /// <param name="row">è¡ï¼1-3ï¼</param> |
| | |
| | | (nameof(ConfigKey.CreateRobotGroupPalletTask), "Task/CreateRobotGroupPalletTask"), |
| | | (nameof(ConfigKey.CreateRobotChangePalletTask), "Task/CreateRobotChangePalletTask"), |
| | | (nameof(ConfigKey.CreateRobotSplitPalletTask), "Task/CreateRobotSplitPalletTask"), |
| | | (nameof(ConfigKey.OutboundFinishTaskTray), "Task/OutboundFinishTaskTray") |
| | | (nameof(ConfigKey.OutboundFinishTaskTray), "Task/OutboundFinishTaskTray"), |
| | | (nameof(ConfigKey.SplitPalletConfirm), "Stock/SplitPalletConfirm"), |
| | | (nameof(ConfigKey.GroupPalletConfirm), "Stock/GroupPalletConfirm") |
| | | }; |
| | | |
| | | private readonly ICacheService _cache; |
| | |
| | | warmedCount++; |
| | | } |
| | | |
| | | _logger.LogInformation("ï¼APIè·¯ç±ç¼åé¢ç宿ã计æ°={Count}", warmedCount); |
| | | _logger.LogInformation("��API·�ɻ���Ԥ����ɡ�����={Count}", warmedCount); |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsAvailable(List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | return true; |
| | | |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, false) |
| | | .Where(x => positions.Contains(x.PositionIndex)) |
| | | .ExecuteCommand() > 0; |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | var entity = Db.Queryable<Dt_FakeBatteryPosition>() |
| | |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public bool MarkAsAvailable(List<int> positions) |
| | | { |
| | | return BaseDal.MarkAsAvailable(positions); |
| | | } |
| | | |
| | | /// <inheritdoc/> |
| | | public int? GetPositionIndex(int row, int col) |
| | | { |
| | | return BaseDal.GetPositionIndex(row, col); |
| | |
| | | using Masuit.Tools; |
| | | using WIDESEAWCS_QuartzJob; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// æºæ¢°ææ¡ç çæå¨ - è´è´£çææçæ¡ç |
| | | /// æºæ¢°ææ¡ç 读åå¨ - è´è´£è¯»åçµè¯æ¡ç |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ¡ç æ ¼å¼ï¼åç¼ï¼å¯éï¼+ æ¥æï¼yyyyMMddï¼+ æ¶é´ï¼HHmmssï¼+ éæºæ°ï¼100-999ï¼ |
| | | /// ä¾å¦ï¼TRAY20260326093045123 |
| | | /// </remarks> |
| | | public static class RobotBarcodeGenerator |
| | | { |
| | | /// <summary> |
| | | /// çææçæ¡ç |
| | | /// 读åçº¿ä½æ¡ç |
| | | /// </summary> |
| | | /// <param name="prefix">æ¡ç åç¼ï¼é»è®¤ä¸ºç©ºå符串ï¼ä¾å¦ "TRAY"</param> |
| | | /// <returns>çæçæ¡ç åç¬¦ä¸²ï¼æ ¼å¼ï¼åç¼+æ¥æ+æ¶é´+éæºæ°</returns> |
| | | /// <param name="prefix">DBç¹ä½ï¼ä¾å¦ "DB40.990"</param> |
| | | /// <returns>读åå°ççµè¯æ¡ç </returns> |
| | | public static string GenerateTrayBarcode(string prefix = "") |
| | | { |
| | | // è·åå½åæ¥æï¼æ ¼å¼å为 yyyyMMddï¼8使°åï¼ |
| | | // ä¾å¦ï¼20260326 |
| | | string datePart = DateTime.Now.ToString("yyyyMMdd"); |
| | | |
| | | // è·åå½åæ¶é´ï¼æ¶åç§ï¼ï¼æ ¼å¼å为 HHmmssï¼6使°åï¼ |
| | | // ä¾å¦ï¼093045 表示 09:30:45 |
| | | string timePart = DateTime.Now.ToString("HHmmss"); |
| | | |
| | | // çæ3ä½éæºæ°ï¼èå´ 100-999ï¼ç¡®ä¿æ¡ç å¯ä¸æ§ |
| | | // ä½¿ç¨ Random.Shared è·å线ç¨å®å
¨çéæºæ°çæå¨ |
| | | string randomPart = Random.Shared.Next(100, 1000).ToString(); |
| | | |
| | | // ç»åææé¨åï¼åç¼ + æ¥æ + æ¶é´ + éæºæ° |
| | | // 妿åç¼ä¸ºç©ºï¼åç´æ¥è¿åæ¥æ+æ¶é´+éæºæ°çç»å |
| | | return prefix + datePart + timePart + randomPart; |
| | | var device = Storage.Devices.Where(d => d.DeviceName == "Aåº_䏿³¨è¾é线").FirstOrDefault(); |
| | | if (!device.IsNullOrEmpty() && device != null && device.Communicator.IsConnected) |
| | | { |
| | | var trayBarcode = device.Communicator.Read<string>(prefix); |
| | | return trayBarcode; |
| | | } |
| | | return ""; |
| | | } |
| | | } |
| | | } |
| | |
| | | // ç®åå½ä»¤å¤çå¨ï¼å¤çç¶ææ´æ°çç®åå½ä»¤ |
| | | var simpleCommandHandler = new RobotSimpleCommandHandler(_taskProcessor, socketGateway); |
| | | // åç¼å½ä»¤å¤çå¨ï¼å¤ç pickfinishedãputfinished ç另忰çå½ä»¤ |
| | | var prefixCommandHandler = new RobotPrefixCommandHandler(robotTaskService, _taskProcessor, _stateManager, socketGateway); |
| | | var prefixCommandHandler = new RobotPrefixCommandHandler(robotTaskService, _taskProcessor, _stateManager, socketGateway, fakeBatteryPositionService); |
| | | |
| | | // åå§åæ¶æ¯è·¯ç±å¨ |
| | | _messageRouter = new RobotMessageHandler(socketGateway, _stateManager, cache, simpleCommandHandler, prefixCommandHandler, logger); |
| | |
| | | /// 彿£å¸¸çµè¯ä»»å¡å®æå设为 trueï¼æºå¨äººä»åçµè¯ä½ç½®è¡¥å
çµè¯è³48个ã |
| | | /// </remarks> |
| | | public bool IsInFakeBatteryMode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åæ¹æ¬¡èµ·å§ç¼å·ï¼ç¨äºéå¢è®¡ç®åè´§/æ¾è´§ç¼å·ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 卿¹æ¬¡æ¨¡å¼ä¸ï¼æ¯æ¹åè´§/æ¾è´§çèµ·å§ç¼å·ä»1å¼å§éå¢ã |
| | | /// ç¨äºè®¡ç® {start}-{end} æ ¼å¼ä¸ç start å¼ã |
| | | /// </remarks> |
| | | public int CurrentBatchIndex { get; set; } = 1; |
| | | |
| | | /// <summary> |
| | | /// æ¢çä»»å¡å½åé¶æ®µ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// é¶æ®µå®ä¹ï¼ |
| | | /// 0: æªå¼å§ |
| | | /// 1: 忣叏çµè¯ï¼æµåBï¼ / ååçµè¯ï¼æµåAï¼ |
| | | /// 2: æ¾æ£å¸¸çµè¯ï¼æµåBï¼ / æ¾åçµè¯ï¼æµåAï¼ |
| | | /// 3: ååçµè¯ï¼æµåB Phase2ï¼ |
| | | /// 4: æ¾åçµè¯å°5å·ä½ï¼æµåB Phase2ï¼ |
| | | /// </remarks> |
| | | public int ChangePalletPhase { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æ«ç NG |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æå¸¦çº¿ä¸çµè¯æ«ç æ¯å¦NGã |
| | | /// </remarks> |
| | | public bool IsScanNG { get; set; } = false; |
| | | } |
| | | } |
| | |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | public async Task SendSocketRobotPickAsync(Dt_RobotTask task, RobotSocketState state) |
| | | /// <param name="isScanNG">æ¯å¦æ«ç NG</param> |
| | | public async Task SendSocketRobotPickAsync(Dt_RobotTask task, RobotSocketState state, bool isScanNG) |
| | | { |
| | | // æå»ºåè´§æä»¤ï¼æ ¼å¼ï¼Pickbattery,{æºå°å} |
| | | string taskString = $"Pickbattery,{task.RobotSourceAddress}"; |
| | |
| | | |
| | | // å°ä»»å¡å
³èå°ç¶æå¯¹è±¡ |
| | | state.CurrentTask = task; |
| | | |
| | | if(isScanNG) |
| | | { |
| | | state.IsScanNG = true; |
| | | } |
| | | |
| | | // ä¿æåè¯ä¹ï¼ä»
å¨ç¶æå®å
¨åå
¥æåååæ´æ°ä»»å¡ç¶æ |
| | | // è¿æ ·å¯ä»¥ç¡®ä¿ç¶æåä»»å¡è®°å½çä¸è´æ§ |
| | |
| | | public List<int> GetNextAvailableFakeBatteryPositions(int count) |
| | | { |
| | | return _fakeBatteryPositionService.GetNextAvailable(count); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è®¡ç®æ¹æ¬¡ç¼å·èå´ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¿åæ ¼å¼ï¼(start, end) |
| | | /// - remaining >= 4: (currentIndex, currentIndex + 3) |
| | | /// - remaining > 1: (currentIndex, currentIndex + remaining - 1) |
| | | /// - remaining == 1: (currentIndex, 0) -- å个ç©åç¨ 0 表示 end |
| | | /// </remarks> |
| | | /// <param name="currentIndex">å½åæ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="remaining">å©ä½æ°é</param> |
| | | /// <returns>(start, end) å
ç»</returns> |
| | | public (int Start, int End) BuildBatchRange(int currentIndex, int remaining) |
| | | { |
| | | if (remaining >= 4) |
| | | return (currentIndex, currentIndex + 3); |
| | | else if (remaining > 1) |
| | | return (currentIndex, currentIndex + remaining - 1); |
| | | else // remaining == 1 |
| | | return (currentIndex, 0); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä¸ååè´§æä»¤ï¼å¸¦æ¹æ¬¡æ ¼å¼åæ»æ°ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åé顺åºï¼ |
| | | /// 1. PickTotalNum,{N} -- çå®çµè¯æ»æ° |
| | | /// 2. Pickbattery,{ä½ç½®},{start}-{end} -- æ¹æ¬¡åè´§æä»¤ |
| | | /// |
| | | /// ä¸åæååæ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸"ã |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="position">åè´§ä½ç½®</param> |
| | | /// <param name="batchStart">æ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="batchEnd">æ¹æ¬¡ç»æç¼å·</param> |
| | | public async Task SendPickWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // å
åéæ»æ°æä»¤ |
| | | string totalNumCmd = $"PickTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // ååéæ¹æ¬¡åè´§æä»¤ |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Pickbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸åæ¹æ¬¡åè´§æä»¤æåï¼æä»¤: {TaskString}ï¼æ¹æ¬¡: {Range}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸åæ¹æ¬¡åè´§æä»¤æåï¼æä»¤: {taskString}ï¼æ¹æ¬¡: {range}", 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> |
| | | /// ä¸åæ¾è´§æä»¤ï¼å¸¦æ¹æ¬¡æ ¼å¼åæ»æ°ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åé顺åºï¼ |
| | | /// 1. PutTotalNum,{N} -- çå®çµè¯æ»æ° |
| | | /// 2. Putbattery,{ä½ç½®},{start}-{end} -- æ¹æ¬¡æ¾è´§æä»¤ |
| | | /// |
| | | /// ä¸åæååæ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸"ã |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="position">æ¾è´§ä½ç½®</param> |
| | | /// <param name="batchStart">æ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="batchEnd">æ¹æ¬¡ç»æç¼å·</param> |
| | | public async Task SendPutWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // å
åéæ»æ°æä»¤ |
| | | string totalNumCmd = $"PutTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // ååéæ¹æ¬¡æ¾è´§æä»¤ |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Putbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸åæ¾è´§æä»¤æåï¼æä»¤: {TaskString}ï¼æ¹æ¬¡: {Range}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸åæ¾è´§æä»¤æåï¼æä»¤: {taskString}ï¼æ¹æ¬¡: {range}", 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> |
| | |
| | | } |
| | | |
| | | // è§£æè¿åçä»»å¡ä¿¡æ¯ |
| | | var taskInfos = JsonConvert.DeserializeObject<List<Dt_Task>>(content.Data.ToJson() ?? string.Empty) ?? new List<Dt_Task>(); |
| | | var taskInfo = taskInfos.FirstOrDefault(); |
| | | //var taskInfos = JsonConvert.DeserializeObject<List<Dt_Task>>(content.Data.ToJson() ?? string.Empty) ?? new List<Dt_Task>(); |
| | | //var taskInfo = taskInfos.FirstOrDefault(); |
| | | |
| | | // è·åæºå°å |
| | | string sourceAddress = taskDTO.SourceAddress; |
| | | //// è·åæºå°å |
| | | //string sourceAddress = taskDTO.SourceAddress; |
| | | |
| | | // æ¥æ¾æºå°å对åºçè¾éçº¿è®¾å¤ |
| | | IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress)); |
| | | //// æ¥æ¾æºå°å对åºçè¾éçº¿è®¾å¤ |
| | | //IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress)); |
| | | |
| | | if (device != null) |
| | | { |
| | | // å°è®¾å¤è½¬æ¢ä¸ºè¾é线类å |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | //if (device != null) |
| | | //{ |
| | | // // å°è®¾å¤è½¬æ¢ä¸ºè¾é线类å |
| | | // CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | |
| | | // 设置è¾é线çç®æ å°å |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, taskInfo.NextAddress, sourceAddress); |
| | | // // 设置è¾é线çç®æ å°å |
| | | // conveyorLine.SetValue(ConveyorLineDBNameNew.Target, taskInfo.NextAddress, sourceAddress); |
| | | |
| | | // 设置è¾é线çä»»å¡å· |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress); |
| | | // // 设置è¾é线çä»»å¡å· |
| | | // conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress); |
| | | |
| | | // 触åè¾é线å¼å§æ§è¡ï¼åå
¥ WCS_ACK = 1ï¼ |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, sourceAddress); |
| | | // // 触åè¾é线å¼å§æ§è¡ï¼åå
¥ WCS_ACK = 1ï¼ |
| | | // conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, sourceAddress); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µ |
| | | if (_taskService.UpdateTaskStatusToNext(taskInfo).Status) |
| | | { |
| | | _logger.LogInformation("HandleInboundTaskAsyncï¼å
¥åºä»»å¡å¤çæåï¼ä»»å¡å·: {TaskNum}", taskInfo.TaskNum); |
| | | QuartzLogger.Info($"HandleInboundTaskAsyncï¼å
¥åºä»»å¡å¤çæåï¼ä»»å¡å·: {taskInfo.TaskNum}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | return true; |
| | | } |
| | | } |
| | | // // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µ |
| | | // if (_taskService.UpdateTaskStatusToNext(taskInfo).Status) |
| | | // { |
| | | // _logger.LogInformation("HandleInboundTaskAsyncï¼å
¥åºä»»å¡å¤çæåï¼ä»»å¡å·: {TaskNum}", taskInfo.TaskNum); |
| | | // QuartzLogger.Info($"HandleInboundTaskAsyncï¼å
¥åºä»»å¡å¤çæåï¼ä»»å¡å·: {taskInfo.TaskNum}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | // return true; |
| | | // } |
| | | //} |
| | | |
| | | return false; |
| | | } |
| | |
| | | { |
| | | return _httpClientHelper.Post<WebResponseContent>(configKey, stockDTO.ToJson()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è°ç¨æ¹éæç确认 API |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 彿çä»»å¡å
¨é¨å宿¶è°ç¨ï¼ä¸æ¬¡æ§ä¸ä¼ æ´ä¸ªæççè§£ç»æ°æ®å° MESã |
| | | /// </remarks> |
| | | /// <param name="palletCode">æºæçå·</param> |
| | | /// <returns>HTTP ååºç»æ</returns> |
| | | public HttpResponseResult<WebResponseContent> PostSplitPalletConfirmAsync(string palletCode) |
| | | { |
| | | var request = new { PalletCode = palletCode }; |
| | | return _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.SplitPalletConfirm), request.ToJson()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è°ç¨æ¹éç»ç确认 API |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½ç»çä»»å¡å
¨é¨æ¾å®æ¶è°ç¨ï¼ä¸æ¬¡æ§ä¸ä¼ æ´ä¸ªæççç»å®æ°æ®å° MESã |
| | | /// </remarks> |
| | | /// <param name="palletCode">ç®æ æçå·</param> |
| | | /// <returns>HTTP ååºç»æ</returns> |
| | | public HttpResponseResult<WebResponseContent> PostGroupPalletConfirmAsync(string palletCode) |
| | | { |
| | | var request = new { PalletCode = palletCode }; |
| | | return _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.GroupPalletConfirm), request.ToJson()); |
| | | } |
| | | } |
| | | } |
| | |
| | | private readonly ISocketClientGateway _socketClientGateway; |
| | | |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// ç¨äºéæ¾åçµè¯ç¹ä½ã |
| | | /// </remarks> |
| | | private readonly IFakeBatteryPositionService _fakeBatteryPositionService; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="robotTaskService">任塿å¡</param> |
| | | /// <param name="taskProcessor">ä»»å¡å¤çå¨</param> |
| | | /// <param name="stateManager">ç¶æç®¡çå¨</param> |
| | | /// <param name="socketClientGateway">Socket ç½å
³</param> |
| | | /// <param name="fakeBatteryPositionService">åçµè¯ä½ç½®æå¡</param> |
| | | public RobotPrefixCommandHandler( |
| | | IRobotTaskService robotTaskService, |
| | | RobotTaskProcessor taskProcessor, |
| | | RobotStateManager stateManager, |
| | | ISocketClientGateway socketClientGateway) |
| | | ISocketClientGateway socketClientGateway, |
| | | IFakeBatteryPositionService fakeBatteryPositionService) |
| | | { |
| | | _robotTaskService = robotTaskService; |
| | | _taskProcessor = taskProcessor; |
| | | _stateManager = stateManager; |
| | | _socketClientGateway = socketClientGateway; |
| | | _fakeBatteryPositionService = fakeBatteryPositionService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | // 仿°æ®åºéæ°æ¥è¯¢å½åä»»å¡ï¼ç¡®ä¿è·åææ°ç¶æï¼ |
| | | var task = await _robotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId); |
| | | |
| | | // æ ¹æ®å½ä»¤åç¼ååå¤ç |
| | | if (cmd.StartsWith("pickfinished")) |
| | | if (task != null) |
| | | { |
| | | // å¤çåè´§å®æ |
| | | await HandlePickFinishedAsync(state, positions, task); |
| | | } |
| | | else if (cmd.StartsWith("putfinished")) |
| | | { |
| | | // å¤çæ¾è´§å®æ |
| | | await HandlePutFinishedAsync(state, positions, task); |
| | | } |
| | | // æ ¹æ®å½ä»¤åç¼ååå¤ç |
| | | if (cmd.StartsWith("pickfinished")) |
| | | { |
| | | // å¤çåè´§å®æ |
| | | await HandlePickFinishedAsync(state, positions, task); |
| | | } |
| | | else if (cmd.StartsWith("putfinished")) |
| | | { |
| | | // å¤çæ¾è´§å®æ |
| | | await HandlePutFinishedAsync(state, positions, task); |
| | | } |
| | | |
| | | // åååæ¶æ¯å°å®¢æ·ç«¯ï¼ä¿æåæè¡ä¸ºï¼ |
| | | await _socketClientGateway.SendMessageAsync(client, message); |
| | | // åååæ¶æ¯å°å®¢æ·ç«¯ï¼ä¿æåæè¡ä¸ºï¼ |
| | | await _socketClientGateway.SendMessageAsync(client, message); |
| | | } |
| | | else |
| | | { |
| | | Console.WriteLine($"RobotJob HandleAsync Warning: Current task not found for RobotTaskId {state.CurrentTask.RobotTaskId}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | |
| | | /// <remarks> |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. å¦ææ¯æçä»»å¡ï¼æå»ºåºå DTO å¹¶è°ç¨æç API |
| | | /// 2. æ´æ°å½åå¨ä½ä¸º"åè´§å®æ" |
| | | /// 3. è®°å½åè´§å®æçä½ç½® |
| | | /// 4. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººåè´§å®æ" |
| | | /// 5. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// 2. æ¢çä»»å¡ Phase3 ååçµè¯æ¶ä¸è°ç¨æç API |
| | | /// 3. æ´æ°å½åå¨ä½ä¸º"åè´§å®æ" |
| | | /// 4. è®°å½åè´§å®æçä½ç½® |
| | | /// 5. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººåè´§å®æ" |
| | | /// 6. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">åè´§å®æçä½ç½®ç¼å·æ°ç»</param> |
| | | /// <param name="task">æºå¨äººä»»å¡è®°å½</param> |
| | | private async Task HandlePickFinishedAsync(RobotSocketState state, int[] positions, Dt_RobotTask? task) |
| | | { |
| | | // å¦ææ¯æçä»»å¡ |
| | | if (state.IsSplitPallet) |
| | | // è®°å½åè´§å®æçä½ç½® |
| | | state.LastPickPositions = positions; |
| | | |
| | | // æ¢çä»»å¡ Phase3 ååçµè¯ï¼ä¸è°ç¨æç API |
| | | if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode() |
| | | && state.ChangePalletPhase == 3) |
| | | { |
| | | state.CurrentAction = "PickFinished"; |
| | | } |
| | | // æçä»»å¡ |
| | | else if (state.IsSplitPallet) |
| | | { |
| | | // æå»ºåºå DTOï¼å
å«ä½ç½®ä¿¡æ¯åæçæ¡ç |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | |
| | | // è®°å½åè´§å®æçä½ç½® |
| | | state.LastPickPositions = positions; |
| | | |
| | | // è°ç¨æç API |
| | | var result = _taskProcessor.PostSplitPalletAsync(stockDTO); |
| | |
| | | // 妿 API è°ç¨æå |
| | | if (result.Data.Status && result.IsSuccess) |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"åè´§å®æ" |
| | | state.CurrentAction = "PickFinished"; |
| | | } |
| | | } |
| | |
| | | // éæçä»»å¡ï¼ç´æ¥æ´æ°å¨ä½ |
| | | state.CurrentAction = "PickFinished"; |
| | | } |
| | | |
| | | // è®°å½åè´§å®æçä½ç½®ï¼æ 论æ¯å¦æçé½è®°å½ï¼ |
| | | state.LastPickPositions = positions; |
| | | |
| | | // 妿任å¡åå¨ |
| | | if (task != null) |
| | |
| | | /// <remarks> |
| | | /// å¤çé»è¾ï¼ |
| | | /// 1. 妿æ¯ç»çä»»å¡ï¼æå»ºåºå DTO å¹¶è°ç¨ç»ç/æ¢ç API |
| | | /// 2. 妿ç»çæåï¼å¢å ä»»å¡è®¡æ° |
| | | /// 3. æ´æ°å½åå¨ä½ä¸º"æ¾è´§å®æ" |
| | | /// 4. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | /// 5. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// 2. æ¢ç任塿 ¹æ®é¶æ®µåºåå¤çï¼æµåA Phase2 ä¸è°ç¨ APIï¼æµåB Phase2 æ£å¸¸è°ç¨ï¼Phase4 è°ç¨ MarkAsAvailable |
| | | /// 3. 妿ç»çæåï¼å¢å ä»»å¡è®¡æ° |
| | | /// 4. æ´æ°å½åå¨ä½ä¸º"æ¾è´§å®æ" |
| | | /// 5. æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | /// 6. å®å
¨æ´æ°ç¶æå° Redis |
| | | /// </remarks> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="positions">æ¾è´§å®æçä½ç½®ç¼å·æ°ç»</param> |
| | |
| | | // è®°å½æ¾è´§å®æçä½ç½® |
| | | state.LastPutPositions = positions; |
| | | |
| | | // æå»ºåºå DTO |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | // 夿æ¯å¦ä¸ºæ¢çä»»å¡ |
| | | var isChangePallet = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode(); |
| | | var isFlowA = state.CurrentTask?.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // æ ¹æ®ä»»å¡ç±»åå³å®è°ç¨åªä¸ª API |
| | | // æ¢çä»»å¡è°ç¨ ChangePalletAsyncï¼ç»çä»»å¡è°ç¨ GroupPalletAsync |
| | | var configKey = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode() |
| | | ? nameof(ConfigKey.ChangePalletAsync) |
| | | : nameof(ConfigKey.GroupPalletAsync); |
| | | if (isChangePallet) |
| | | { |
| | | // æ¢çä»»å¡ï¼æ ¹æ®é¶æ®µåºåå¤ç |
| | | if (state.ChangePalletPhase == 2) |
| | | { |
| | | if (isFlowA) |
| | | { |
| | | // æµåA Phase2ï¼æ¾åçµè¯å°ç®æ æçï¼ä¸è°ç¨ APIï¼ä¸éå¢è®¡æ° |
| | | // ä»
æ´æ°ç¶æ |
| | | } |
| | | else |
| | | { |
| | | // æµåB Phase2ï¼æ¾æ£å¸¸çµè¯ï¼éå¢è®¡æ° |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | |
| | | // è°ç¨ç»ç/æ¢ç API |
| | | var result = _taskProcessor.PostGroupPalletAsync(configKey, stockDTO); |
| | | // æå»ºåºå DTO å¹¶è°ç¨ ChangePalletAsync API |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | var result = _taskProcessor.PostGroupPalletAsync(nameof(ConfigKey.ChangePalletAsync), stockDTO); |
| | | putSuccess = result.Data.Status && result.IsSuccess; |
| | | } |
| | | } |
| | | else if (state.ChangePalletPhase == 4) |
| | | { |
| | | // æµåB Phase4ï¼æ¾åçµè¯å°5å·ä½ï¼ä¸è°ç¨ APIï¼ä¸éå¢è®¡æ°ï¼éæ¾ç¹ä½ |
| | | _fakeBatteryPositionService.MarkAsAvailable(positions.ToList()); |
| | | } |
| | | else |
| | | { |
| | | // éæ¹æ¬¡æ¨¡å¼ï¼æ£å¸¸éå¢è®¡æ°å¹¶è°ç¨ API |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | |
| | | // æ£æ¥ API è¿åç¶æ |
| | | putSuccess = result.Data.Status && result.IsSuccess; |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | var result = _taskProcessor.PostGroupPalletAsync(nameof(ConfigKey.GroupPalletAsync), stockDTO); |
| | | putSuccess = result.Data.Status && result.IsSuccess; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // ç»çä»»å¡ï¼åæé»è¾ |
| | | var stockDTO = RobotTaskProcessor.BuildStockDTO(state, positions); |
| | | var result = _taskProcessor.PostGroupPalletAsync(nameof(ConfigKey.GroupPalletAsync), stockDTO); |
| | | putSuccess = result.Data.Status && result.IsSuccess; |
| | | |
| | | // å¢å ä»»å¡è®¡æ° |
| | | if (!state.IsScanNG) |
| | | { |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 妿æ¾è´§æå |
| | |
| | | { |
| | | // æ´æ°å½åå¨ä½ä¸º"æ¾è´§å®æ" |
| | | state.CurrentAction = "PutFinished"; |
| | | state.IsScanNG = false; |
| | | |
| | | // å¢å ä»»å¡è®¡æ°ï¼ç´¯å æ¬æ¬¡å®æçæ°éï¼ |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | // éç»ç任塿¶å¢å 计æ°ï¼ç»çä»»å¡å·²å¨ä¸é¢éå¢ï¼ |
| | | if (!state.IsGroupPallet) |
| | | { |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | |
| | | // 妿任å¡åå¨ï¼åæ¥æ´æ°ä»»å¡çè®¡æ° |
| | | // 妿任å¡åå¨ |
| | | if (task != null) |
| | | { |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | } |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode(); |
| | | |
| | | // 妿任å¡åå¨ |
| | | if (task != null) |
| | | { |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ¾è´§å®æ" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode(); |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.Repository.UpdateDataAsync(task); |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.Repository.UpdateDataAsync(task); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | // 夿任å¡ç±»å |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // åªææçææ¢çä»»å¡éè¦å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.SplitPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | // æ¢çä»»å¡ï¼ä»
彿æé¶æ®µå®ææ¶æå¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | // å¤çå
¥åºä»»å¡åä¼ |
| | | // useSourceAddress: true è¡¨ç¤ºä½¿ç¨æºå°åï¼æç/æ¢çåºæ¯ï¼ |
| | | if (state.ChangePalletPhase == 0) |
| | | { |
| | | // è°ç¨æ¹éæç确认æ¥å£ï¼æ¢çåå®é¶æ®µï¼ |
| | | var sourcePallet = state.CurrentTask.RobotSourceAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostSplitPalletConfirmAsync(sourcePallet); |
| | | if (!confirmResult.IsSuccess) |
| | | { |
| | | QuartzLogger.Error($"æ¹éæç确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | } |
| | | |
| | | // ææé¶æ®µå®æï¼å¤çå
¥åº |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Swap,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãSwap,diskFinishedã", state.RobotCrane.DeviceName); |
| | | |
| | | // éç½®æ¹æ¬¡ç¶æ |
| | | state.ChangePalletPhase = 0; |
| | | state.CurrentBatchIndex = 1; |
| | | state.IsInFakeBatteryMode = false; |
| | | return true; |
| | | } |
| | | } |
| | | // ä¸é´é¶æ®µä¸å¤çï¼ä»
æ´æ°ç¶æ |
| | | return true; |
| | | } |
| | | |
| | | // æçä»»å¡ï¼ç´æ¥å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.SplitPallet) |
| | | { |
| | | // è°ç¨æ¹éæç确认æ¥å£ |
| | | var sourcePallet = state.CurrentTask.RobotSourceAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostSplitPalletConfirmAsync(sourcePallet); |
| | | if (!confirmResult.IsSuccess) |
| | | { |
| | | QuartzLogger.Error($"æ¹éæç确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | } |
| | | |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | |
| | | // 夿任å¡ç±»å |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // åªæç»çææ¢çä»»å¡éè¦å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.GroupPallet || robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | // æ¢çä»»å¡ï¼ä»
彿æé¶æ®µå®ææ¶æå¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | if (state.ChangePalletPhase == 0) |
| | | { |
| | | // è°ç¨æ¹éç»ç确认æ¥å£ï¼æ¢çæ¾å®é¶æ®µï¼ |
| | | var targetPallet = state.CurrentTask.RobotTargetAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostGroupPalletConfirmAsync(targetPallet); |
| | | if (!confirmResult.IsSuccess) |
| | | { |
| | | QuartzLogger.Error($"æ¹éç»ç确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | } |
| | | |
| | | // ææé¶æ®µå®æï¼å¤çå
¥åº |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | |
| | | // æ¸
çç¶æï¼ä¸ºä¸ä¸ä¸ªä»»å¡ååå¤ |
| | | state.CurrentTask = null; // æ¸
é¤å½åä»»å¡ |
| | | state.RobotTaskTotalNum = 0; // é置任å¡è®¡æ° |
| | | state.CellBarcode = new List<string>(); // æ¸
空æ¡ç å表 |
| | | |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Group,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãGroup,diskFinishedã", state.RobotCrane.DeviceName); |
| | | |
| | | // éç½®æ¹æ¬¡ç¶æ |
| | | state.ChangePalletPhase = 0; |
| | | state.CurrentBatchIndex = 1; |
| | | state.IsInFakeBatteryMode = false; |
| | | return true; |
| | | } |
| | | } |
| | | // ä¸é´é¶æ®µä¸å¤çï¼ä»
æ´æ°ç¶æ |
| | | return true; |
| | | } |
| | | |
| | | // ç»çä»»å¡ï¼ç´æ¥å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.GroupPallet) |
| | | { |
| | | // è°ç¨æ¹éç»ç确认æ¥å£ |
| | | var targetPallet = state.CurrentTask.RobotTargetAddressPalletCode; |
| | | var confirmResult = _taskProcessor.PostGroupPalletConfirmAsync(targetPallet); |
| | | if (!confirmResult.IsSuccess) |
| | | { |
| | | QuartzLogger.Error($"æ¹éç»ç确认失败: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown"); |
| | | } |
| | | |
| | | // å¤çå
¥åºä»»å¡åä¼ |
| | | // useSourceAddress: false 表示使ç¨ç®æ å°åï¼ç»ç/æ¢çåºæ¯ï¼ |
| | | // useSourceAddress: false 表示使ç¨ç®æ å°åï¼ç»çåºæ¯ï¼ |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false)) |
| | | { |
| | | // å
¥åºæåï¼å é¤ä»»å¡è®°å½ |
| | |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_Tasks.SocketServer; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | |
| | | namespace WIDESEAWCS_Tasks.Workflow |
| | |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// å½åè´§å®æåï¼åæºå¨äººåéæ¾è´§æä»¤ï¼Putbatteryï¼ã |
| | | /// æºå¨äººæ¶å°æä»¤åä¼å°è´§ç©æ¾ç½®å°ç®æ å°åã |
| | | /// æ¢çä»»å¡ä½¿ç¨æ¹æ¬¡æ ¼å¼ SendPutWithBatchAsyncã |
| | | /// |
| | | /// æä»¤æ ¼å¼ï¼Putbattery,{ç®æ å°å} |
| | | /// ä¾å¦ï¼Putbattery,B01 表示å°è´§ç©æ¾ç½®å° B01 ä½ç½® |
| | |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | private async Task HandlePickFinishedStateAsync(Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // æå»ºæ¾è´§æä»¤ï¼æ ¼å¼ï¼Putbattery,{ç®æ å°å} |
| | | string taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | string taskString; |
| | | |
| | | // éè¿å®¢æ·ç«¯ç®¡çå¨åéæä»¤å°æºå¨äºº |
| | | var state = _stateManager.GetState(ipAddress); |
| | | |
| | | // æ¢çä»»å¡ä½¿ç¨æ¹æ¬¡æ ¼å¼ |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | int targetNormalCount = task.RobotTaskTotalNum; |
| | | int currentCompletedCount = state?.RobotTaskTotalNum ?? 0; |
| | | |
| | | bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // æµåA Phase 2ï¼æ¾åçµè¯å°ç®æ æç |
| | | if (isFlowA && state?.ChangePalletPhase == 2) |
| | | { |
| | | int remaining = 48 - currentCompletedCount; |
| | | if (remaining <= 0) return; |
| | | |
| | | int batchStart = targetNormalCount + 1 + (state.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remaining); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | return; |
| | | } |
| | | |
| | | // æµåB Phase 4ï¼æ¾åçµè¯å°5å·ä½ |
| | | if (!isFlowA && state?.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = 48 - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) return; |
| | | |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePickFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end); |
| | | return; |
| | | } |
| | | |
| | | // æµåB Phase 2ï¼æ¾æ£å¸¸çµè¯å°ç®æ æç |
| | | if (!isFlowA && state?.ChangePalletPhase == 2) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) return; |
| | | |
| | | int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | return; |
| | | } |
| | | |
| | | // é»è®¤ï¼ä½¿ç¨åææ ¼å¼ |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | else |
| | | { |
| | | // 鿢çä»»å¡ï¼ä½¿ç¨åææ ¼å¼ |
| | | if (state != null && state.IsGroupPallet && task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | // ç»çä»»å¡ï¼æ¾è´§é夿æ¯å¦NGï¼å¦æNGåæ¾å°NGå£ |
| | | if (state.IsScanNG) |
| | | { |
| | | taskString = $"Putbattery,NG"; |
| | | } |
| | | else |
| | | { |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | } |
| | | else |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | |
| | | bool result = await _clientManager.SendToClientAsync(ipAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | // åéæåï¼è®°å½ Info æ¥å¿ |
| | | _logger.LogInformation("HandlePickFinishedStateAsyncï¼ä¸åæ¾è´§æä»¤æåï¼æä»¤: {TaskString}ï¼ä»»å¡å·: {TaskNum}", taskString, task.RobotTaskNum); |
| | | QuartzLogger.Info($"ä¸åæ¾è´§æä»¤æåï¼æä»¤: {taskString}", task.RobotRoadway); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // è·åææ°ç¶æå¹¶æ´æ°ä»»å¡å
³è |
| | | var stateToUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateToUpdate != null) |
| | | { |
| | | stateToUpdate.CurrentTask = task; |
| | | |
| | | // å®å
¨æ´æ°ç¶æå° Redis |
| | | if (_stateManager.TryUpdateStateSafely(ipAddress, stateToUpdate)) |
| | | { |
| | | // ç¶ææ´æ°æååï¼æ´æ°ä»»å¡è®°å½ |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // åé失败ï¼è®°å½ Error æ¥å¿ |
| | | _logger.LogError("HandlePickFinishedStateAsyncï¼ä¸åæ¾è´§æä»¤å¤±è´¥ï¼æä»¤: {TaskString}ï¼ä»»å¡å·: {TaskNum}", taskString, task.RobotTaskNum); |
| | | QuartzLogger.Error($"ä¸åæ¾è´§æä»¤å¤±è´¥ï¼æä»¤: {taskString}", task.RobotRoadway); |
| | | } |
| | |
| | | // 妿æ¯ç»çä»»å¡ |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | // çææçæ¡ç åç¼ |
| | | const string prefix = "TRAY"; |
| | | |
| | | // çæä¸¤ä¸ªæçæ¡ç ï¼ç¨äºç»çæä½ï¼ï¼æµè¯ç¨ï¼åç»è¯»åçº¿ä½æ¡ç ï¼ |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | // 读å线ä½çµè¯æ¡ç |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode("DB40.990"); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode("DB40.1020"); |
| | | |
| | | // 妿æ¡ç çææå |
| | | if (!string.IsNullOrEmpty(trayBarcode1) && !string.IsNullOrEmpty(trayBarcode2)) |
| | | { |
| | | if(stateForUpdate.CellBarcode.Contains(trayBarcode1)|| stateForUpdate.CellBarcode.Contains(trayBarcode2)) |
| | | if (stateForUpdate.CellBarcode.Contains(trayBarcode1) || stateForUpdate.CellBarcode.Contains(trayBarcode2)) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼çæçæçæ¡ç å·²åå¨ï¼å¯è½åå¨éå¤ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"çæçæçæ¡ç å·²åå¨ï¼å¯è½åå¨éå¤", stateForUpdate.RobotCrane.DeviceName); |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼è¯»åçæçæ¡ç å·²åå¨ï¼å¯è½åå¨éå¤ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"读åçæçæ¡ç å·²åå¨ï¼å¯è½åå¨éå¤", stateForUpdate.RobotCrane.DeviceName); |
| | | |
| | | // æ¡ç éå¤ï¼è®°å½é误æ¥å¿å¹¶åæ¢åç»æä½(åç»æ¾è´§æ¶ä¼ç¨å°è¿äºæ¡ç ä¿¡æ¯ï¼ä¾åç»æ¾è´§æ¶ä½¿ç¨ï¼è°è¯åå¯è½ä¼åæ¶æ¤é»è¾) |
| | | return; |
| | | |
| | | // åéåè´§æä»¤ æ è®°æ«ç NGï¼æ¾è´§æ¶ä¸ä½¿ç¨è¿äºæ¡ç ï¼å¹¶æ¾å
¥NGå£ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼çæçæçæ¡ç å¯ä¸ï¼ç»§ç»æ§è¡ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"çæçæçæ¡ç å¯ä¸ï¼ç»§ç»æ§è¡", stateForUpdate.RobotCrane.DeviceName); |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼è¯»åçæçæ¡ç å¯ä¸ï¼ç»§ç»æ§è¡ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"读åçæçæ¡ç å¯ä¸ï¼ç»§ç»æ§è¡", stateForUpdate.RobotCrane.DeviceName); |
| | | // å°æ¡ç æ·»å å°ç¶æä¸ï¼ä¾åç»æ¾è´§æ¶ä½¿ç¨ |
| | | stateForUpdate.CellBarcode.Add(trayBarcode1); |
| | | stateForUpdate.CellBarcode.Add(trayBarcode2); |
| | | } |
| | | |
| | | |
| | | // è®°å½æ¥å¿ï¼çææçæ¡ç æå |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼çææçæ¡ç æå: {Barcode1}+{Barcode2}ï¼ä»»å¡å·: {TaskNum}", trayBarcode1, trayBarcode2, task.RobotTaskNum); |
| | | QuartzLogger.Info($"çææçæ¡ç æå: {trayBarcode1}+{trayBarcode2}", stateForUpdate.RobotCrane.DeviceName); |
| | | // è®°å½æ¥å¿ï¼è¯»åæçæ¡ç æå |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼è¯»åæçæ¡ç æå: {Barcode1}+{Barcode2}ï¼ä»»å¡å·: {TaskNum}", trayBarcode1, trayBarcode2, task.RobotTaskNum); |
| | | QuartzLogger.Info($"读åæçæ¡ç æå: {trayBarcode1}+{trayBarcode2}", stateForUpdate.RobotCrane.DeviceName); |
| | | |
| | | // åéåè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, false); |
| | | } |
| | | else |
| | | { |
| | | // æ¡ç çæå¤±è´¥ï¼è®°å½é误æ¥å¿ |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼çææçæ¡ç 失败ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"çææçæ¡ç 失败", stateForUpdate.RobotCrane.DeviceName); |
| | | // æ¡ç 读å失败ï¼è®°å½é误æ¥å¿ |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼è¯»åæçæ¡ç 失败ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Error($"读åæçæ¡ç 失败", stateForUpdate.RobotCrane.DeviceName); |
| | | |
| | | |
| | | // åéåè´§æä»¤ æ è®°æ«ç NGï¼æ¾è´§æ¶ä¸ä½¿ç¨è¿äºæ¡ç ï¼å¹¶æ¾å
¥NGå£ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | } |
| | | } |
| | | 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; |
| | | |
| | | int targetNormalCount = task.RobotTaskTotalNum; // æ£å¸¸çµè¯ç®æ æ°é |
| | | int currentCompletedCount = stateForUpdate.RobotTaskTotalNum; // 已宿æ°é |
| | | // 夿æµåï¼null-safeï¼ |
| | | bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // å¦æç®æ æ°é为48ï¼ç´æ¥ä¸åæ£å¸¸ä»»å¡ |
| | | // ç®æ æ°é为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); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, false); |
| | | return; |
| | | } |
| | | |
| | | // 妿å¤äºåçµè¯è¡¥å
模å¼ï¼è®¡ç®å¹¶ä¸åè¡¥æ°ä»»å¡ |
| | | if (stateForUpdate.IsInFakeBatteryMode) |
| | | // åå§åæ¹æ¬¡æ¨¡å¼ |
| | | if (stateForUpdate.ChangePalletPhase == 0) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining > 0) |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ¢çä»»å¡è¿å
¥æ¹æ¬¡æ¨¡å¼ï¼ä»»å¡å·: {TaskNum}ï¼æµå: {Flow}", |
| | | task.RobotTaskNum, isFlowA ? "A" : "B"); |
| | | } |
| | | |
| | | // ==================== æµåAï¼è¡¥åçµè¯å°ç®æ æç ==================== |
| | | if (isFlowA) |
| | | { |
| | | // Phase 1: ååçµè¯ï¼ä»5å·ä½ï¼ä½¿ç¨ PositionIndexï¼ |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | { |
| | | // è®¡ç®æ¯æ¬¡æåçæ°éï¼æå¤4ä¸ªï¼ |
| | | int pickCount = Math.Min(pickCountPerExecution, remaining); |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåA宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // è·åå¯ç¨çåçµè¯å¹³é¢ç¹ä½ |
| | | int pickCount = Math.Min(4, 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); |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | } |
| | | else |
| | | // Phase 2: æ¾åçµè¯å°ç®æ æçï¼ä» targetNormalCount+1 å¼å§éå¢ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | { |
| | | // åçµè¯è¡¥å
宿ï¼éç½®æ å¿ |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ¢çä»»å¡å®æï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"æ¢çä»»å¡å®æ", stateForUpdate.RobotCrane?.DeviceName); |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåA宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // è®¡ç®æ¾è´§æ¹æ¬¡ç¼å·ï¼ä» targetNormalCount + 1 å¼å§ |
| | | int batchStart = targetNormalCount + 1 + (stateForUpdate.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remaining); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += putCount; |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | } |
| | | // ==================== æµåBï¼åæ£å¸¸çµè¯ + åæ¶åçµè¯ ==================== |
| | | else |
| | | { |
| | | // Phase 1: 忣叏çµè¯ï¼ä»æºå°åï¼ä»1å¼å§éå¢ï¼ |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // æ£å¸¸çµè¯åå®ï¼åæ¢å° Phase 3 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = targetNormalCount + 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ£å¸¸çµè¯å
¨é¨åå®ï¼è¿å
¥Phase 3åæ¶åçµè¯ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | } |
| | | // Phase 2: æ¾æ£å¸¸çµè¯å°ç®æ æçï¼æ¾è´§ç¼å·ä¸åè´§ç¼å·ä¸è´ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // æ£å¸¸çµè¯æ¾å®ï¼åæ¢å° Phase 3 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = targetNormalCount + 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ£å¸¸çµè¯å
¨é¨æ¾å®ï¼è¿å
¥Phase 3åæ¶åçµè¯ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // è®¡ç®æ¬æ¹æ¾è´§ç¼å·ï¼åºäº currentCompletedCount æ¨å¯¼æ¹æ¬¡èµ·å§ |
| | | int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | // Phase 3: ååçµè¯ï¼ä»æºå°åï¼ä» targetNormalCount+1 å¼å§éå¢ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 3) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåB宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remainingFake); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | stateForUpdate.ChangePalletPhase = 4; |
| | | } |
| | | // Phase 4: æ¾åçµè¯å°5å·ä½ï¼ä½¿ç¨ PositionIndexï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåB宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, "5", start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // éç»çä»»å¡ï¼ç´æ¥åéåè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, false); |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- æç临æ¶è¡¨ï¼ç¨äºæåæçä»»å¡çµè¯å表ï¼ä¾æ¹é确认æ¶ä½¿ç¨ |
| | | IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Dt_SplitTemp]') AND type in (N'U')) |
| | | BEGIN |
| | | CREATE TABLE [dbo].[Dt_SplitTemp]( |
| | | [Id] [int] IDENTITY(1,1) NOT NULL, |
| | | [PalletCode] [nvarchar](50) NOT NULL, |
| | | [SfcList] [nvarchar](max) NOT NULL, |
| | | [CreateTime] [datetime] NOT NULL DEFAULT GETDATE(), |
| | | CONSTRAINT [PK_Dt_SplitTemp] PRIMARY KEY CLUSTERED ([Id] ASC) |
| | | ); |
| | | |
| | | -- å¯ä¸ç´¢å¼é²æ¢å䏿çéå¤åå
¥ |
| | | CREATE UNIQUE NONCLUSTERED INDEX [IX_Dt_SplitTemp_PalletCode] ON [dbo].[Dt_SplitTemp]([PalletCode] ASC); |
| | | END |
| | | GO |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEA_DTO.Stock |
| | | { |
| | | /// <summary> |
| | | /// æ¹éç»ç确认请æ±DTO |
| | | /// </summary> |
| | | public class GroupPalletConfirmRequestDto |
| | | { |
| | | /// <summary> |
| | | /// ç®æ æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEA_DTO.Stock |
| | | { |
| | | /// <summary> |
| | | /// æ¹éæç确认请æ±DTO |
| | | /// </summary> |
| | | public class SplitPalletConfirmRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æºæçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | } |
| | |
| | | /// <param name="stock">åºåä¿¡æ¯æ°æ®ä¼ è¾å¯¹è±¡</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | Task<WebResponseContent> UpdateStockInfoAsync(StockInfoDTO stock); |
| | | |
| | | /// <summary> |
| | | /// æ¹éæç确认 - 䏿¬¡æ§è°ç¨MESè§£ç»æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">æºæçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | Task<WebResponseContent> SplitPalletConfirmAsync(string palletCode); |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - 䏿¬¡æ§è°ç¨MESç»å®æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">ç®æ æçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using SqlSugar; |
| | | using WIDESEA_Core.DB.Models; |
| | | |
| | | namespace WIDESEA_Model.Models |
| | | { |
| | | /// <summary> |
| | | /// æç临æ¶è¡¨ - ç¨äºæåæçä»»å¡çµè¯å表ï¼ä¾æ¹é确认æ¶ä½¿ç¨ |
| | | /// </summary> |
| | | [SugarTable(nameof(Dt_SplitTemp), "æç临æ¶è¡¨")] |
| | | public class Dt_SplitTemp |
| | | { |
| | | /// <summary> |
| | | /// ä¸»é® |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®")] |
| | | public int Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "æçå·")] |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯æ¡ç å表ï¼JSONæ ¼å¼ï¼ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, Length = -1, ColumnDescription = "çµè¯æ¡ç å表JSON")] |
| | | public string SfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建æ¶é´ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, ColumnDescription = "å建æ¶é´")] |
| | | public DateTime CreateTime { get; set; } = DateTime.Now; |
| | | } |
| | | } |
| | |
| | | using SqlSugar; |
| | | using Newtonsoft.Json; |
| | | using SqlSugar; |
| | | using WIDESEA_Common.Constants; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core; |
| | |
| | | public IWarehouseService _warehouseService { get; } |
| | | |
| | | /// <summary> |
| | | /// SqlSugar客æ·ç«¯ï¼ç¨äºä¸´æ¶è¡¨æä½ï¼ |
| | | /// </summary> |
| | | public ISqlSugarClient SqlSugarClient { get; } |
| | | |
| | | /// <summary> |
| | | /// Mesæ¥å£æå¡ |
| | | /// </summary> |
| | | public IMesService _mesService { get; } |
| | |
| | | IStockInfoDetail_HtyService stockInfoDetail_HtyService, |
| | | IStockInfo_HtyService stockInfo_HtyService, |
| | | IMesService mesService, |
| | | IWarehouseService warehouseService) |
| | | IWarehouseService warehouseService, |
| | | ISqlSugarClient sqlSugarClient) |
| | | { |
| | | StockInfoDetailService = stockInfoDetailService; |
| | | StockInfoService = stockInfoService; |
| | |
| | | StockInfo_HtyService = stockInfo_HtyService; |
| | | _mesService = mesService; |
| | | _warehouseService = warehouseService; |
| | | SqlSugarClient = sqlSugarClient; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | Status = StockStatusEmun.ç»çæå.GetHashCode(), |
| | | }).ToList(); |
| | | |
| | | var bindRequest = new BindContainerRequest |
| | | { |
| | | ContainerCode = stock?.TargetPalletNo, |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = now, |
| | | OperationType = StockConstants.MES_BIND_OPERATION_TYPE, |
| | | ContainerSfcList = details.Select(d => new ContainerSfcItem |
| | | { |
| | | Sfc = d.SerialNumber, |
| | | Location = d.InboundOrderRowNo.ToString(), |
| | | }).ToList() |
| | | }; |
| | | |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | |
| | | result = StockInfoService.Repository.AddData(entity, x => x.Details); |
| | | if (!result) return content.Error("ç»ç失败"); |
| | | |
| | | //var mesResult = _mesService.BindContainer(bindRequest); |
| | | //if (mesResult == null || mesResult.Data == null || !mesResult.Data.IsSuccess) |
| | | //{ |
| | | // return content.Error($"ç»çæåï¼ä½MESç»å®å¤±è´¥: {mesResult?.Data?.Msg ?? mesResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | //} |
| | | return content.OK("ç»çæå"); |
| | | }); |
| | | } |
| | |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock, targetStock }, "æ¢ç")) <= 0) |
| | | return content.Error("æ¢çåå²è®°å½ä¿å失败"); |
| | | |
| | | // è°ç¨MESè§£ç»æºæççµè¯ |
| | | var unbindRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = stock.SourcePalletNo, |
| | | SfcList = detailEntities.Select(d => d.SerialNumber).ToList() |
| | | }; |
| | | var unbindResult = _mesService.UnBindContainer(unbindRequest); |
| | | if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"æ¢çæåï¼ä½MESè§£ç»å¤±è´¥: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | detailEntities.ForEach(d => d.StockId = targetStock.Id); |
| | | var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | if (!result) return content.Error("æ¢ç失败"); |
| | | |
| | | // è°ç¨MESç»å®ç®æ æççµè¯ |
| | | var bindRequest = new BindContainerRequest |
| | | { |
| | | ContainerCode = stock.TargetPalletNo, |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | OperationType = StockConstants.MES_BIND_OPERATION_TYPE, |
| | | ContainerSfcList = detailEntities.Select(d => new ContainerSfcItem |
| | | { |
| | | Sfc = d.SerialNumber, |
| | | Location = d.InboundOrderRowNo.ToString() |
| | | }).ToList() |
| | | }; |
| | | var bindResult = _mesService.BindContainer(bindRequest); |
| | | if (bindResult == null || bindResult.Data == null || !bindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"æ¢çæåï¼ä½MESç»å®å¤±è´¥: {bindResult?.Data?.Msg ?? bindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | return content.OK("æ¢çæå"); |
| | | }); |
| | |
| | | { |
| | | if (stock == null || string.IsNullOrWhiteSpace(stock.SourcePalletNo)) |
| | | return content.Error("æºæçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | // å¹çåå
¥ï¼æ£æ¥ä¸´æ¶è¡¨æ¯å¦å·²æè¯¥æçè®°å½ï¼æ ååå
¥ |
| | | var existingTemp = SqlSugarClient.Queryable<Dt_SplitTemp>() |
| | | .Where(t => t.PalletCode == stock.SourcePalletNo) |
| | | .First(); |
| | | if (existingTemp == null) |
| | | { |
| | | // æ¥è¯¢è¯¥æçå½åææçµè¯ï¼åå
¥ä¸´æ¶è¡¨ |
| | | var sourceStockForTemp = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStockForTemp != null) |
| | | { |
| | | var allDetails = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStockForTemp.Id); |
| | | if (allDetails != null && allDetails.Any()) |
| | | { |
| | | var sfcListJson = JsonConvert.SerializeObject(allDetails.Select(d => d.SerialNumber).ToList()); |
| | | await SqlSugarClient.Insertable(new Dt_SplitTemp |
| | | { |
| | | PalletCode = stock.SourcePalletNo, |
| | | SfcList = sfcListJson, |
| | | CreateTime = DateTime.Now |
| | | }).ExecuteCommandAsync(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | |
| | | // è°ç¨MESè§£ç»çµè¯ |
| | | var unbindRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = stock.SourcePalletNo, |
| | | SfcList = detailEntities.Select(d => d.SerialNumber).ToList() |
| | | }; |
| | | var unbindResult = _mesService.UnBindContainer(unbindRequest); |
| | | if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"æçæåï¼ä½MESè§£ç»å¤±è´¥: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | var result = await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); |
| | | if (!result) return content.Error("æç失败"); |
| | | return content.OK("æçæå"); |
| | | }); |
| | | } |
| | |
| | | OutboundDate = s.OutboundDate |
| | | }).ToList(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éæç确认 - 䏿¬¡æ§è°ç¨MESè§£ç»æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">æºæçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | public async Task<WebResponseContent> SplitPalletConfirmAsync(string palletCode) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (string.IsNullOrWhiteSpace(palletCode)) |
| | | return content.Error("æçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | // 1. ä»ä¸´æ¶è¡¨è¯»åçµè¯å表 |
| | | var tempRecord = SqlSugarClient.Queryable<Dt_SplitTemp>() |
| | | .Where(t => t.PalletCode == palletCode) |
| | | .First(); |
| | | if (tempRecord == null) |
| | | return content.Error("æªæ¾å°æç临æ¶è®°å½ï¼è¯·å
æ§è¡æçæä½"); |
| | | |
| | | var sfcList = JsonConvert.DeserializeObject<List<string>>(tempRecord.SfcList); |
| | | if (sfcList == null || !sfcList.Any()) |
| | | return content.Error("临æ¶è¡¨ä¸çµè¯å表为空"); |
| | | |
| | | // 2. è°ç¨MESè§£ç» |
| | | var unbindRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = palletCode, |
| | | SfcList = sfcList |
| | | }; |
| | | var unbindResult = _mesService.UnBindContainer(unbindRequest); |
| | | if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"MESè§£ç»å¤±è´¥: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | // 3. å é¤ä¸´æ¶è¡¨è®°å½ |
| | | await SqlSugarClient.Deleteable<Dt_SplitTemp>().Where(t => t.PalletCode == palletCode).ExecuteCommandAsync(); |
| | | |
| | | return content.OK("æ¹éæç确认æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error($"æ¹éæç确认失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - 䏿¬¡æ§è°ç¨MESç»å®æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">ç®æ æçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | public async Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (string.IsNullOrWhiteSpace(palletCode)) |
| | | return content.Error("æçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | // 1. æ¥è¯¢è¯¥æçä¸çææçµè¯æç» |
| | | var stockInfo = StockInfoService.Repository.QueryFirst(s => s.PalletCode == palletCode); |
| | | if (stockInfo == null) |
| | | return content.Error("æçä¸åå¨"); |
| | | |
| | | var details = StockInfoDetailService.Repository.QueryData(d => d.StockId == stockInfo.Id); |
| | | if (details == null || !details.Any()) |
| | | return content.Error("æç䏿 çµè¯æ°æ®"); |
| | | |
| | | // 2. è°ç¨MESç»å® |
| | | var bindRequest = new BindContainerRequest |
| | | { |
| | | ContainerCode = palletCode, |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | OperationType = StockConstants.MES_BIND_OPERATION_TYPE, |
| | | ContainerSfcList = details.Select(d => new ContainerSfcItem |
| | | { |
| | | Sfc = d.SerialNumber, |
| | | Location = d.InboundOrderRowNo.ToString() |
| | | }).ToList() |
| | | }; |
| | | var bindResult = _mesService.BindContainer(bindRequest); |
| | | if (bindResult == null || bindResult.Data == null || !bindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"MESç»å®å¤±è´¥: {bindResult?.Data?.Msg ?? bindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | return content.OK("æ¹éç»ç确认æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error($"æ¹éç»ç确认失败: {ex.Message}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | return await Service.UpdateStockInfoAsync(stock); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éæç确认 - WCSæçä»»å¡å
¨é¨å宿¶è°ç¨ |
| | | /// </summary> |
| | | /// <param name="dto">æç确认请æ±</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("SplitPalletConfirm"), AllowAnonymous] |
| | | public async Task<WebResponseContent> SplitPalletConfirm([FromBody] SplitPalletConfirmRequestDto dto) |
| | | { |
| | | return await Service.SplitPalletConfirmAsync(dto.PalletCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - WCSç»çä»»å¡å
¨é¨æ¾å®æ¶è°ç¨ |
| | | /// </summary> |
| | | /// <param name="dto">ç»ç确认请æ±</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("GroupPalletConfirm"), AllowAnonymous] |
| | | public async Task<WebResponseContent> GroupPalletConfirm([FromBody] GroupPalletConfirmRequestDto dto) |
| | | { |
| | | return await Service.GroupPalletConfirmAsync(dto.PalletCode); |
| | | } |
| | | } |
| | | } |
| | |
| | | "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjMwMTcyNzM5Mzk5NzYxOTIwIiwibmFtZSI6IlBBQ0voo4XphY3lt6XkvY0wMSIsIkZhY3RvcnlJZCI6IjEyMzQ1NiIsIlNpdGVJZCI6IjEyMzQ1NiIsIkNvZGUiOiJYWExQQUNLMDRBRTAzMiIsIm5iZiI6MTcwNDE4NzY5MCwiZXhwIjoyMTQ1NjkxNjkwLCJpc3MiOiJodHRwczovL3d3dy5oeW1zb24uY29tIiwiYXVkIjoiaHR0cHM6Ly93d3cuaHltc29uLmNvbSJ9.An1BE7UgfcSP--LtTOmmmWVE2RQFPDahLkDg1xy5KqY" |
| | | }, |
| | | "RobotTaskAddressRules": { |
| | | "11068": [ "1", "2" ] |
| | | "11068": [ "1", "2" ], |
| | | "11001": [ "3", "1" ], |
| | | "11010": [ "4", "2" ], |
| | | "2101": [ "1", "3" ], |
| | | "2103": [ "2", "4" ] |
| | | }, |
| | | |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¹é MES ç»å®ä¸è§£ç»æ¥å£å®æ½è®¡å |
| | | |
| | | > **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:** æ°å¢ä¸¤ä¸ª WMS æ¥å£ï¼SplitPalletConfirmãGroupPalletConfirmï¼ï¼ä¾ WCS å¨ä»»å¡é¶æ®µå®ææ¶ä¸æ¬¡æ§ä¸ä¼ æç级å«ç MES ç»å®/è§£ç»æ°æ®ï¼åå° MES è°ç¨æ¬¡æ°ã |
| | | |
| | | **Architecture:** |
| | | - `Dt_SplitTemp` 临æ¶è¡¨ï¼æçå¼å§æ¶å¹çåå
¥æççµè¯å表ï¼Confirm æ¶è¯»åå¹¶å é¤ |
| | | - `SplitPalletAsync` æ¹é ï¼æ¯æ¬¡è°ç¨æ¶æ£æ¥ä¸´æ¶è¡¨ï¼æ è®°å½ååå
¥ï¼æè®°å½åè·³è¿ |
| | | - `SplitPalletConfirm`ï¼ä»ä¸´æ¶è¡¨è¯»åçµè¯ â è°ç¨ MES UnBindContainer â å é¤ä¸´æ¶è¡¨è®°å½ |
| | | - `GroupPalletConfirm`ï¼ææçå·æ¥ Dt_StockInfoDetail â è°ç¨ MES BindContainer |
| | | |
| | | **Tech Stack:** .NET 6/8, C#, SqlSugar ORM, ASP.NET Core WebAPI |
| | | |
| | | --- |
| | | |
| | | ## æä»¶åæ´æ¦è§ |
| | | |
| | | | æä½ | æä»¶ | |
| | | |------|------| |
| | | | æ°å¢ | `WIDESEA_Model/Models/Stock/Dt_SplitTemp.cs` | |
| | | | æ°å¢ | `WIDESEA_DTO/Stock/SplitPalletConfirmRequestDto.cs` | |
| | | | æ°å¢ | `WIDESEA_DTO/Stock/GroupPalletConfirmRequestDto.cs` | |
| | | | ä¿®æ¹ | `WIDESEA_IStockService/IStockService.cs` | |
| | | | ä¿®æ¹ | `WIDESEA_StockService/StockService.cs` | |
| | | | ä¿®æ¹ | `WIDESEA_WMSServer/Controllers/Stock/StockController.cs` | |
| | | | ä¿®æ¹ | æ°æ®åºï¼æ°å¢ `Dt_SplitTemp` 表 | |
| | | |
| | | --- |
| | | |
| | | ## Task 1: æ°å»ºä¸´æ¶è¡¨å®ä½ Dt_SplitTemp |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_SplitTemp.cs` |
| | | |
| | | - [ ] **Step 1: å建 Dt_SplitTemp å®ä½** |
| | | |
| | | ```csharp |
| | | using SqlSugar; |
| | | using WIDESEA_Core.DB.Models; |
| | | |
| | | namespace WIDESEA_Model.Models |
| | | { |
| | | /// <summary> |
| | | /// æç临æ¶è¡¨ - ç¨äºæåæçä»»å¡çµè¯å表ï¼ä¾æ¹é确认æ¶ä½¿ç¨ |
| | | /// </summary> |
| | | [SugarTable(nameof(Dt_SplitTemp), "æç临æ¶è¡¨")] |
| | | public class Dt_SplitTemp |
| | | { |
| | | /// <summary> |
| | | /// ä¸»é® |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主é®")] |
| | | public int Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "æçå·")] |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯æ¡ç å表ï¼JSONæ ¼å¼ï¼ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, Length = -1, ColumnDescription = "çµè¯æ¡ç å表JSON")] |
| | | public string SfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建æ¶é´ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false, ColumnDescription = "å建æ¶é´")] |
| | | public DateTime CreateTime { get; set; } = DateTime.Now; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Stock/Dt_SplitTemp.cs |
| | | git commit -m "feat(Stock): æ°å¢Dt_SplitTempæç临æ¶è¡¨å®ä½ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 2: æ°å»ºè¯·æ± DTO |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Stock/SplitPalletConfirmRequestDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Stock/GroupPalletConfirmRequestDto.cs` |
| | | |
| | | - [ ] **Step 1: å建 SplitPalletConfirmRequestDto** |
| | | |
| | | ```csharp |
| | | namespace WIDESEA_DTO.Stock |
| | | { |
| | | /// <summary> |
| | | /// æ¹éæç确认请æ±DTO |
| | | /// </summary> |
| | | public class SplitPalletConfirmRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æºæçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å建 GroupPalletConfirmRequestDto** |
| | | |
| | | ```csharp |
| | | namespace WIDESEA_DTO.Stock |
| | | { |
| | | /// <summary> |
| | | /// æ¹éç»ç确认请æ±DTO |
| | | /// </summary> |
| | | public class GroupPalletConfirmRequestDto |
| | | { |
| | | /// <summary> |
| | | /// ç®æ æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/Stock/SplitPalletConfirmRequestDto.cs WMS/WIDESEA_WMSServer/WIDESEA_DTO/Stock/GroupPalletConfirmRequestDto.cs |
| | | git commit -m "feat(DTO): æ°å¢æ¹éç»çæç确认请æ±DTO |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 3: ä¿®æ¹ IStockService æ¥å£ |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockService.cs`ï¼å¨æ¥å£æ«å°¾æ·»å ä¸¤ä¸ªæ°æ¹æ³ï¼ |
| | | |
| | | - [ ] **Step 1: å¨ IStockService æ¥å£æ·»å ä¸¤ä¸ªæ°æ¹æ³å£°æ** |
| | | |
| | | å¨ `UpdateStockInfoAsync` æ¹æ³å£°æä¹åãæ¥å£ç»æ `}` ä¹åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ¹éæç确认 - 䏿¬¡æ§è°ç¨MESè§£ç»æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">æºæçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | Task<WebResponseContent> SplitPalletConfirmAsync(string palletCode); |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - 䏿¬¡æ§è°ç¨MESç»å®æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">ç®æ æçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode); |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IStockService.cs |
| | | git commit -m "feat(IStockService): æ°å¢SplitPalletConfirmAsyncåGroupPalletConfirmAsyncæ¥å£ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 4: ä¿®æ¹ StockService å®ç° - SplitPalletConfirmAsync å GroupPalletConfirmAsync |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockService.cs` |
| | | |
| | | - [ ] **Step 1: æ·»å ISqlSugarClient 注å
¥å Dt_SplitTemp å®ä½** |
| | | |
| | | å¨ `StockService` ç±»ä¸æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | using SqlSugar; |
| | | using WIDESEA_Model.Models; |
| | | using Newtonsoft.Json; |
| | | ``` |
| | | |
| | | å¨ç±»ä¸æ·»å 屿§ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// SqlSugar客æ·ç«¯ï¼ç¨äºä¸´æ¶è¡¨æä½ï¼ |
| | | /// </summary> |
| | | public ISqlSugarClient SqlSugarClient { get; } |
| | | ``` |
| | | |
| | | æé 彿°ä¸æ³¨å
¥ï¼ |
| | | |
| | | ```csharp |
| | | public StockService( |
| | | ..., |
| | | ISqlSugarClient sqlSugarClient) // æ·»å å°åæ°æ«å°¾ |
| | | { |
| | | ... |
| | | SqlSugarClient = sqlSugarClient; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å®ç° SplitPalletConfirmAsync æ¹æ³** |
| | | |
| | | å¨ç±»æ«å°¾ï¼`UpdateStockInfoAsync` æ¹æ³ä¹åã`CreateDetailHistory` ä¹åï¼æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ¹éæç确认 - 䏿¬¡æ§è°ç¨MESè§£ç»æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">æºæçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | public async Task<WebResponseContent> SplitPalletConfirmAsync(string palletCode) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (string.IsNullOrWhiteSpace(palletCode)) |
| | | return content.Error("æçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | // 1. ä»ä¸´æ¶è¡¨è¯»åçµè¯å表 |
| | | var tempRecord = SqlSugarClient.Queryable<Dt_SplitTemp>() |
| | | .Where(t => t.PalletCode == palletCode) |
| | | .First(); |
| | | if (tempRecord == null) |
| | | return content.Error("æªæ¾å°æç临æ¶è®°å½ï¼è¯·å
æ§è¡æçæä½"); |
| | | |
| | | var sfcList = JsonConvert.DeserializeObject<List<string>>(tempRecord.SfcList); |
| | | if (sfcList == null || !sfcList.Any()) |
| | | return content.Error("临æ¶è¡¨ä¸çµè¯å表为空"); |
| | | |
| | | // 2. è°ç¨MESè§£ç» |
| | | var unbindRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = palletCode, |
| | | SfcList = sfcList |
| | | }; |
| | | var unbindResult = _mesService.UnBindContainer(unbindRequest); |
| | | if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"MESè§£ç»å¤±è´¥: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | // 3. å é¤ä¸´æ¶è¡¨è®°å½ |
| | | SqlSugarClient.Deleteable<Dt_SplitTemp>().Where(t => t.PalletCode == palletCode).ExecuteCommand(); |
| | | |
| | | return content.OK("æ¹éæç确认æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error($"æ¹éæç确认失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - 䏿¬¡æ§è°ç¨MESç»å®æ´ä¸ªæç |
| | | /// </summary> |
| | | /// <param name="palletCode">ç®æ æçå·</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | public async Task<WebResponseContent> GroupPalletConfirmAsync(string palletCode) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | if (string.IsNullOrWhiteSpace(palletCode)) |
| | | return content.Error("æçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | // 1. æ¥è¯¢è¯¥æçä¸çææçµè¯æç» |
| | | var stockInfo = StockInfoService.Repository.QueryFirst(s => s.PalletCode == palletCode); |
| | | if (stockInfo == null) |
| | | return content.Error("æçä¸åå¨"); |
| | | |
| | | var details = StockInfoDetailService.Repository.QueryData(d => d.StockId == stockInfo.Id); |
| | | if (!details.Any()) |
| | | return content.Error("æç䏿 çµè¯æ°æ®"); |
| | | |
| | | // 2. è°ç¨MESç»å® |
| | | var bindRequest = new BindContainerRequest |
| | | { |
| | | ContainerCode = palletCode, |
| | | EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, |
| | | ResourceCode = StockConstants.MES_RESOURCE_CODE, |
| | | LocalTime = DateTime.Now, |
| | | OperationType = StockConstants.MES_BIND_OPERATION_TYPE, |
| | | ContainerSfcList = details.Select(d => new ContainerSfcItem |
| | | { |
| | | Sfc = d.SerialNumber, |
| | | Location = d.InboundOrderRowNo.ToString() |
| | | }).ToList() |
| | | }; |
| | | var bindResult = _mesService.BindContainer(bindRequest); |
| | | if (bindResult == null || bindResult.Data == null || !bindResult.Data.IsSuccess) |
| | | { |
| | | return content.Error($"MESç»å®å¤±è´¥: {bindResult?.Data?.Msg ?? bindResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | } |
| | | |
| | | return content.OK("æ¹éç»ç确认æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return content.Error($"æ¹éç»ç确认失败: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockService.cs |
| | | git commit -m "feat(StockService): å®ç°SplitPalletConfirmAsyncåGroupPalletConfirmAsync |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 5: ä¿®æ¹ SplitPalletAsync - æ·»å 临æ¶è¡¨å¹çåå
¥é»è¾ |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockService.cs` |
| | | |
| | | - [ ] **Step 1: å¨ SplitPalletAsync æ¹æ³å¼å¤´æ·»å 临æ¶è¡¨åå
¥é»è¾** |
| | | |
| | | å¨ `SplitPalletAsync` æ¹æ³ç `try` åå¼å¤´ï¼`if (stock == null ...` ä¹åï¼ãå¨äºå¡ `ExecuteWithinTransactionAsync` è°ç¨ä¹åï¼æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | // å¹çåå
¥ï¼æ£æ¥ä¸´æ¶è¡¨æ¯å¦å·²æè¯¥æçè®°å½ï¼æ ååå
¥ |
| | | var existingTemp = SqlSugarClient.Queryable<Dt_SplitTemp>() |
| | | .Where(t => t.PalletCode == stock.SourcePalletNo) |
| | | .First(); |
| | | if (existingTemp == null) |
| | | { |
| | | // æ¥è¯¢è¯¥æçå½åææçµè¯ï¼åå
¥ä¸´æ¶è¡¨ |
| | | var sourceStockForTemp = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStockForTemp != null) |
| | | { |
| | | var allDetails = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStockForTemp.Id); |
| | | if (allDetails.Any()) |
| | | { |
| | | var sfcListJson = JsonConvert.SerializeObject(allDetails.Select(d => d.SerialNumber).ToList()); |
| | | SqlSugarClient.Insertable(new Dt_SplitTemp |
| | | { |
| | | PalletCode = stock.SourcePalletNo, |
| | | SfcList = sfcListJson, |
| | | CreateTime = DateTime.Now |
| | | }).ExecuteCommand(); |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 注æï¼è¿æ®µä»£ç å¨ `return await ExecuteWithinTransactionAsync(...)` ä¹åæ§è¡ï¼ä¸å¨äºå¡å
ã |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_StockService/StockService.cs |
| | | git commit -m "feat(SplitPalletAsync): æ·»å 临æ¶è¡¨å¹çåå
¥é»è¾ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 6: ä¿®æ¹ StockController - æ·»å æ°è·¯ç± |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockController.cs` |
| | | |
| | | - [ ] **Step 1: å¨ StockController æ·»å 两个æ°è·¯ç±** |
| | | |
| | | å¨ `UpdateStockInfoAsync` æ¹æ³ä¹åãç±»ç»æ `}` ä¹åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ¹éæç确认 - WCSæçä»»å¡å
¨é¨å宿¶è°ç¨ |
| | | /// </summary> |
| | | /// <param name="dto">æç确认请æ±</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("SplitPalletConfirm"), AllowAnonymous] |
| | | public async Task<WebResponseContent> SplitPalletConfirm([FromBody] SplitPalletConfirmRequestDto dto) |
| | | { |
| | | return await Service.SplitPalletConfirmAsync(dto.PalletCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éç»ç确认 - WCSç»çä»»å¡å
¨é¨æ¾å®æ¶è°ç¨ |
| | | /// </summary> |
| | | /// <param name="dto">ç»ç确认请æ±</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("GroupPalletConfirm"), AllowAnonymous] |
| | | public async Task<WebResponseContent> GroupPalletConfirm([FromBody] GroupPalletConfirmRequestDto dto) |
| | | { |
| | | return await Service.GroupPalletConfirmAsync(dto.PalletCode); |
| | | } |
| | | ``` |
| | | |
| | | 忶卿件顶鍿·»å usingï¼ |
| | | |
| | | ```csharp |
| | | using WIDESEA_DTO.Stock; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockController.cs |
| | | git commit -m "feat(StockController): æ°å¢SplitPalletConfirmåGroupPalletConfirmæ¥å£è·¯ç± |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 7: æ°æ®åºåæ´èæ¬ |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/Database/Scripts/20260416_Dt_SplitTemp.sql` |
| | | |
| | | - [ ] **Step 1: å建临æ¶è¡¨ DDL èæ¬** |
| | | |
| | | ```sql |
| | | -- æç临æ¶è¡¨ï¼ç¨äºæåæçä»»å¡çµè¯å表ï¼ä¾æ¹é确认æ¶ä½¿ç¨ |
| | | IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Dt_SplitTemp]') AND type in (N'U')) |
| | | BEGIN |
| | | CREATE TABLE [dbo].[Dt_SplitTemp]( |
| | | [Id] [int] IDENTITY(1,1) NOT NULL, |
| | | [PalletCode] [nvarchar](50) NOT NULL, |
| | | [SfcList] [nvarchar](max) NOT NULL, |
| | | [CreateTime] [datetime] NOT NULL DEFAULT GETDATE(), |
| | | CONSTRAINT [PK_Dt_SplitTemp] PRIMARY KEY CLUSTERED ([Id] ASC) |
| | | ); |
| | | |
| | | -- å¯éï¼æ·»å å¯ä¸ç´¢å¼é²æ¢å䏿çéå¤åå
¥ |
| | | CREATE UNIQUE NONCLUSTERED INDEX [IX_Dt_SplitTemp_PalletCode] ON [dbo].[Dt_SplitTemp]([PalletCode] ASC); |
| | | END |
| | | GO |
| | | ``` |
| | | |
| | | - [ ] **Step 2: Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/Database/Scripts/20260416_Dt_SplitTemp.sql |
| | | git commit -m "feat(db): æ°å¢Dt_SplitTempæç临æ¶è¡¨ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 8: æå»ºéªè¯ |
| | | |
| | | - [ ] **Step 1: è¿è¡ dotnet build éªè¯ç¼è¯éè¿** |
| | | |
| | | ```bash |
| | | cd D:\Git\ShanMeiXinNengYuan\Code\WMS\WIDESEA_WMSServer |
| | | dotnet build WIDESEA_WMSServer.sln |
| | | ``` |
| | | |
| | | Expected: Build succeeded with no errors. |
| | | |
| | | --- |
| | | |
| | | ## èªæ£æ¸
å |
| | | |
| | | - [ ] ææ public æ¹æ³åæ XML ææ¡£æ³¨é |
| | | - [ ] `Dt_SplitTemp.SfcList` ä½¿ç¨ `nvarchar(max)` åå¨ JSON |
| | | - [ ] `SplitPalletConfirmAsync` 读å临æ¶è¡¨åå é¤è®°å½ |
| | | - [ ] `SplitPalletAsync` ä¸ç临æ¶è¡¨åå
¥å¨äºå¡å¤æ§è¡ |
| | | - [ ] `GroupPalletConfirmAsync` ä» `Dt_StockInfoDetail` æ¥çµè¯ï¼ä¸æ¥ä¸´æ¶è¡¨ |
| | | - [ ] ä¸¤ä¸ªæ° Controller æ¹æ³åæ è®° `[AllowAnonymous]` |
| | | - [ ] æ°æ®åºèæ¬å« IF NOT EXISTS 鲿¢éå¤å建 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¢ç任塿¹æ¬¡æä»¤ä¸åæµåå®ç°è®¡å |
| | | |
| | | > **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:** å级æ¢çä»»å¡åè´§/æ¾è´§æä»¤æ ¼å¼ä¸ºæ¹æ¬¡æ¨¡å¼ï¼æ¯æ PickTotalNum/PutTotalNumï¼å¹¶æ ¹æ® RobotSourceAddressLineCode åºåä¸¤ç§æµå |
| | | |
| | | **Architecture:** |
| | | - RobotSocketState æ°å¢æ¹æ¬¡ç¶æå段ï¼CurrentBatchIndex, ChangePalletPhaseï¼ |
| | | - RobotTaskProcessor æ°å¢æ¹æ¬¡æä»¤æå»ºæ¹æ³ï¼BuildBatchRange, SendPickWithBatchAsync, SendPutWithBatchAsyncï¼ |
| | | - RobotWorkflowOrchestrator éå HandlePutFinishedStateAsync å HandlePickFinishedStateAsync å®ç°ä¸¤ç§æµåçç¶ææº |
| | | - RobotPrefixCommandHandler å RobotSimpleCommandHandler æ ¹æ®é¶æ®µåºåå¤çé»è¾ |
| | | - åçµè¯æå¡å±æ°å¢ MarkAsAvailable æ¹æ³ç¨äºéæ¾ç¹ä½ |
| | | |
| | | **Tech Stack:** C# / .NET 8, SqlSugar ORM, Redisç¼å |
| | | |
| | | --- |
| | | |
| | | ## File Structure |
| | | |
| | | ``` |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/ |
| | | = RobotSocketState.cs # +CurrentBatchIndex, +ChangePalletPhase |
| | | = RobotTaskProcessor.cs # +BuildBatchRange, +SendPickWithBatchAsync, +SendPutWithBatchAsync |
| | | = Workflow/RobotWorkflowOrchestrator.cs # éå HandlePutFinishedStateAsync + HandlePickFinishedStateAsync |
| | | = Workflow/RobotPrefixCommandHandler.cs # putfinished/pickfinished é¶æ®µå¤æ |
| | | = Workflow/RobotSimpleCommandHandler.cs # allpickfinished/allputfinished é¶æ®µå®å« |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ |
| | | = IFakeBatteryPositionService.cs # +MarkAsAvailable |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/ |
| | | = FakeBatteryPositionService.cs # +MarkAsAvailable |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/ |
| | | = IFakeBatteryPositionRepository.cs # +MarkAsAvailable |
| | | |
| | | WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/ |
| | | = FakeBatteryPositionRepository.cs # +MarkAsAvailable |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 1: RobotSocketState æ°å¢æ¹æ¬¡ç¶æå段 |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs` |
| | | |
| | | - [ ] **Step 1: æ·»å CurrentBatchIndex å ChangePalletPhase 屿§** |
| | | |
| | | å¨ `IsInFakeBatteryMode` 屿§åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ¯å¦å¤äºåçµè¯è¡¥å
æ¨¡å¼ |
| | | /// </summary> |
| | | public bool IsInFakeBatteryMode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åæ¹æ¬¡èµ·å§ç¼å·ï¼ç¨äºéå¢è®¡ç®åè´§/æ¾è´§ç¼å·ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 卿¹æ¬¡æ¨¡å¼ä¸ï¼æ¯æ¹åè´§/æ¾è´§çèµ·å§ç¼å·ä»1å¼å§éå¢ã |
| | | /// ç¨äºè®¡ç® {start}-{end} æ ¼å¼ä¸ç start å¼ã |
| | | /// </remarks> |
| | | public int CurrentBatchIndex { get; set; } = 1; |
| | | |
| | | /// <summary> |
| | | /// æ¢çä»»å¡å½åé¶æ®µ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// é¶æ®µå®ä¹ï¼ |
| | | /// 0: æªå¼å§ |
| | | /// 1: 忣叏çµè¯ï¼æµåBï¼ / ååçµè¯ï¼æµåAï¼ |
| | | /// 2: æ¾æ£å¸¸çµè¯ï¼æµåBï¼ / æ¾åçµè¯ï¼æµåAï¼ |
| | | /// 3: ååçµè¯ï¼æµåB Phase2ï¼ |
| | | /// 4: æ¾åçµè¯å°5å·ä½ï¼æµåB Phase2ï¼ |
| | | /// </remarks> |
| | | public int ChangePalletPhase { get; set; } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | cd D:\Git\ShanMeiXinNengYuan\Code\WCS\WIDESEAWCS_Server |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotSocketState.cs |
| | | git commit -m "feat(Robot): RobotSocketState æ°å¢ CurrentBatchIndex å ChangePalletPhase" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 2: åçµè¯ä»å¨å±æ°å¢ MarkAsAvailable æ¹æ³ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/IFakeBatteryPositionRepository.cs` |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/FakeBatteryPositionRepository.cs` |
| | | |
| | | - [ ] **Step 1: 卿¥å£ä¸æ·»å MarkAsAvailable æ¹æ³å£°æï¼å¨ MarkAsUsed æ¹æ³åï¼** |
| | | |
| | | å¨ `IFakeBatteryPositionRepository.cs` ç `MarkAsUsed` æ¹æ³åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå¯ç¨ï¼éæ¾ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsAvailable(List<int> positions); |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å¨ä»å¨å®ç°ä¸æ·»å MarkAsAvailable æ¹æ³ï¼å¨ MarkAsUsed æ¹æ³åï¼** |
| | | |
| | | å¨ `FakeBatteryPositionRepository.cs` ç `MarkAsUsed` æ¹æ³åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <inheritdoc/> |
| | | public bool MarkAsAvailable(List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | return true; |
| | | |
| | | return Db.Updateable<Dt_FakeBatteryPosition>() |
| | | .SetColumns(x => x.IsUsed, false) |
| | | .Where(x => positions.Contains(x.PositionIndex)) |
| | | .ExecuteCommand() > 0; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Server.sln |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 4: 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): åçµè¯ä»å¨å±æ°å¢ MarkAsAvailable æ¹æ³" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 3: åçµè¯æå¡å±æ°å¢ MarkAsAvailable æ¹æ³ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IFakeBatteryPositionService.cs` |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/FakeBatteryPositionService.cs` |
| | | |
| | | - [ ] **Step 1: 卿塿¥å£ä¸æ·»å MarkAsAvailable æ¹æ³å£°æï¼å¨ MarkAsUsed åï¼** |
| | | |
| | | å¨ `IFakeBatteryPositionService.cs` ç `MarkAsUsed` æ¹æ³åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æ è®°æå®ç¹ä½ä¸ºå¯ç¨ï¼éæ¾ç¹ä½ï¼ |
| | | /// </summary> |
| | | /// <param name="positions">ç¹ä½ç´¢å¼å表</param> |
| | | /// <returns>æ¯å¦æå</returns> |
| | | bool MarkAsAvailable(List<int> positions); |
| | | ``` |
| | | |
| | | - [ ] **Step 2: 卿å¡å®ç°ä¸æ·»å MarkAsAvailable æ¹æ³** |
| | | |
| | | ```csharp |
| | | /// <inheritdoc/> |
| | | public bool MarkAsAvailable(List<int> positions) |
| | | { |
| | | return BaseDal.MarkAsAvailable(positions); |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Server.sln |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 4: 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): åçµè¯æå¡å±æ°å¢ MarkAsAvailable æ¹æ³" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 4: RobotTaskProcessor æ°å¢æ¹æ¬¡æä»¤è¾
婿¹æ³ |
| | | |
| | | **注æï¼** `_fakeBatteryPositionService` åæ®µå·²å¨ä¸ä¸è½®è¿ä»£ä¸æ·»å ï¼æ éé夿³¨å
¥ã |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs` |
| | | |
| | | - [ ] **Step 1: æ·»å BuildBatchRange è¾
婿¹æ³** |
| | | |
| | | å¨ `GetNextAvailableFakeBatteryPositions` æ¹æ³åæ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// è®¡ç®æ¹æ¬¡ç¼å·èå´ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è¿åæ ¼å¼ï¼(start, end) |
| | | /// - remaining >= 4: (currentIndex, currentIndex + 3) |
| | | /// - remaining > 1: (currentIndex, currentIndex + remaining - 1) |
| | | /// - remaining == 1: (currentIndex, 0) -- å个ç©åç¨ 0 表示 end |
| | | /// </remarks> |
| | | /// <param name="currentIndex">å½åæ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="remaining">å©ä½æ°é</param> |
| | | /// <returns>(start, end) å
ç»</returns> |
| | | public (int Start, int End) BuildBatchRange(int currentIndex, int remaining) |
| | | { |
| | | if (remaining >= 4) |
| | | return (currentIndex, currentIndex + 3); |
| | | else if (remaining > 1) |
| | | return (currentIndex, currentIndex + remaining - 1); |
| | | else // remaining == 1 |
| | | return (currentIndex, 0); |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ·»å SendPickWithBatchAsync æ¹æ³** |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// ä¸ååè´§æä»¤ï¼å¸¦æ¹æ¬¡æ ¼å¼åæ»æ°ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åé顺åºï¼ |
| | | /// 1. PickTotalNum,{N} -- çå®çµè¯æ»æ° |
| | | /// 2. Pickbattery,{ä½ç½®},{start}-{end} -- æ¹æ¬¡åè´§æä»¤ |
| | | /// |
| | | /// ä¸åæååæ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸"ã |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="position">åè´§ä½ç½®</param> |
| | | /// <param name="batchStart">æ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="batchEnd">æ¹æ¬¡ç»æç¼å·</param> |
| | | public async Task SendPickWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // å
åéæ»æ°æä»¤ |
| | | string totalNumCmd = $"PickTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // ååéæ¹æ¬¡åè´§æä»¤ |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Pickbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸åæ¹æ¬¡åè´§æä»¤æåï¼æä»¤: {TaskString}ï¼æ¹æ¬¡: {Range}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸åæ¹æ¬¡åè´§æä»¤æåï¼æä»¤: {taskString}ï¼æ¹æ¬¡: {range}", 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: æ·»å SendPutWithBatchAsync æ¹æ³** |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// ä¸åæ¾è´§æä»¤ï¼å¸¦æ¹æ¬¡æ ¼å¼åæ»æ°ï¼ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// åé顺åºï¼ |
| | | /// 1. PutTotalNum,{N} -- çå®çµè¯æ»æ° |
| | | /// 2. Putbattery,{ä½ç½®},{start}-{end} -- æ¹æ¬¡æ¾è´§æä»¤ |
| | | /// |
| | | /// ä¸åæååæ´æ°ä»»å¡ç¶æä¸º"æºå¨äººæ§è¡ä¸"ã |
| | | /// </remarks> |
| | | /// <param name="task">è¦ä¸åçä»»å¡å¯¹è±¡</param> |
| | | /// <param name="state">æºå¨äººå½åç¶æ</param> |
| | | /// <param name="position">æ¾è´§ä½ç½®</param> |
| | | /// <param name="batchStart">æ¹æ¬¡èµ·å§ç¼å·</param> |
| | | /// <param name="batchEnd">æ¹æ¬¡ç»æç¼å·</param> |
| | | public async Task SendPutWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // å
åéæ»æ°æä»¤ |
| | | string totalNumCmd = $"PutTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // ååéæ¹æ¬¡æ¾è´§æä»¤ |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Putbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("ä¸åæ¾è´§æä»¤æåï¼æä»¤: {TaskString}ï¼æ¹æ¬¡: {Range}ï¼è®¾å¤: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"ä¸åæ¾è´§æä»¤æåï¼æä»¤: {taskString}ï¼æ¹æ¬¡: {range}", 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 4: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 5: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs |
| | | git commit -m "feat(Robot): RobotTaskProcessor æ°å¢æ¹æ¬¡æä»¤è¾
婿¹æ³" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 5: RobotSimpleCommandHandler æ·»å é¶æ®µå®å« |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs` |
| | | |
| | | - [ ] **Step 1: ä¿®æ¹ allpickfinished 忝** |
| | | |
| | | æ¾å° `case "allpickfinished":` åæ¯ï¼æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | // å
¨é¨åè´§å®æ |
| | | case "allpickfinished": |
| | | { |
| | | state.CurrentAction = "AllPickFinished"; |
| | | |
| | | var currentTask = state.CurrentTask; |
| | | if (currentTask == null) |
| | | return false; |
| | | |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // æ¢çä»»å¡ï¼ä»
彿æé¶æ®µå®ææ¶æå¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | if (state.ChangePalletPhase == 0) |
| | | { |
| | | // ææé¶æ®µå®æï¼å¤çå
¥åº |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true)) |
| | | { |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Swap,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãSwap,diskFinishedã", state.RobotCrane.DeviceName); |
| | | |
| | | // éç½®æ¹æ¬¡ç¶æ |
| | | state.ChangePalletPhase = 0; |
| | | state.CurrentBatchIndex = 1; |
| | | state.IsInFakeBatteryMode = false; |
| | | return true; |
| | | } |
| | | } |
| | | // ä¸é´é¶æ®µä¸å¤çï¼ä»
æ´æ°ç¶æ |
| | | return true; |
| | | } |
| | | |
| | | // æçä»»å¡ï¼ç´æ¥å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.SplitPallet) |
| | | { |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: true)) |
| | | { |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Swap,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãSwap,diskFinishedã", state.RobotCrane.DeviceName); |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: ä¿®æ¹ allputfinished 忝** |
| | | |
| | | æ¾å° `case "allputfinished":` åæ¯ï¼æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | // å
¨é¨æ¾è´§å®æ |
| | | case "allputfinished": |
| | | { |
| | | state.CurrentAction = "AllPutFinished"; |
| | | |
| | | var currentTask = state.CurrentTask; |
| | | if (currentTask == null) |
| | | return false; |
| | | |
| | | var robotTaskType = (RobotTaskTypeEnum)currentTask.RobotTaskType; |
| | | |
| | | // æ¢çä»»å¡ï¼ä»
彿æé¶æ®µå®ææ¶æå¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.ChangePallet) |
| | | { |
| | | if (state.ChangePalletPhase == 0) |
| | | { |
| | | // ææé¶æ®µå®æï¼å¤çå
¥åº |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false)) |
| | | { |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | state.CurrentTask = null; |
| | | state.RobotTaskTotalNum = 0; |
| | | state.CellBarcode = new List<string>(); |
| | | |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Group,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãGroup,diskFinishedã", state.RobotCrane.DeviceName); |
| | | |
| | | // éç½®æ¹æ¬¡ç¶æ |
| | | state.ChangePalletPhase = 0; |
| | | state.CurrentBatchIndex = 1; |
| | | state.IsInFakeBatteryMode = false; |
| | | return true; |
| | | } |
| | | } |
| | | // ä¸é´é¶æ®µä¸å¤çï¼ä»
æ´æ°ç¶æ |
| | | return true; |
| | | } |
| | | |
| | | // ç»çä»»å¡ï¼ç´æ¥å¤çå
¥åº |
| | | if (robotTaskType == RobotTaskTypeEnum.GroupPallet) |
| | | { |
| | | if (await _taskProcessor.HandleInboundTaskAsync(state, useSourceAddress: false)) |
| | | { |
| | | _taskProcessor.DeleteTask(currentTask.RobotTaskId); |
| | | state.CurrentTask = null; |
| | | state.RobotTaskTotalNum = 0; |
| | | state.CellBarcode = new List<string>(); |
| | | |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, $"Group,diskFinished"); |
| | | QuartzLogger.Info($"åéæ¶æ¯ï¼ãGroup,diskFinishedã", state.RobotCrane.DeviceName); |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 4: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs |
| | | git commit -m "feat(Robot): RobotSimpleCommandHandler æ¢ç任塿·»å ChangePalletPhase é¶æ®µå®å«" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 6: RobotPrefixCommandHandler ä¿®æ¹ putfinished/pickfinished å¤çé»è¾ |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs` |
| | | |
| | | - [ ] **Step 1: æ·»å IFakeBatteryPositionService ä¾èµ** |
| | | |
| | | å¨ç±»é¡¶é¨æ·»å åæ®µåæé 彿°åæ°ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// åçµè¯ä½ç½®æå¡ |
| | | /// </summary> |
| | | private readonly IFakeBatteryPositionService _fakeBatteryPositionService; |
| | | |
| | | public RobotPrefixCommandHandler( |
| | | IRobotTaskService robotTaskService, |
| | | RobotTaskProcessor taskProcessor, |
| | | RobotStateManager stateManager, |
| | | ISocketClientGateway socketClientGateway, |
| | | IFakeBatteryPositionService fakeBatteryPositionService) |
| | | { |
| | | _robotTaskService = robotTaskService; |
| | | _taskProcessor = taskProcessor; |
| | | _stateManager = stateManager; |
| | | _socketClientGateway = socketClientGateway; |
| | | _fakeBatteryPositionService = fakeBatteryPositionService; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: ä¿®æ¹ HandlePutFinishedAsync æ¹æ³ä¸çæ¾è´§å¤çé»è¾** |
| | | |
| | | æ¾å° `if (putSuccess)` åï¼ç°æä»£ç 约å¨ç¬¬258è¡éè¿ï¼ï¼æ¿æ¢å
¶ä¸çæ¾è´§æåå¤çé»è¾ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | // 妿æ¾è´§æå |
| | | if (putSuccess) |
| | | { |
| | | state.CurrentAction = "PutFinished"; |
| | | |
| | | // 夿æ¯å¦ä¸ºæ¢çä»»å¡ä¸å¤äºæ¹æ¬¡æ¨¡å¼ |
| | | var isChangePallet = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode(); |
| | | var isFlowA = state.CurrentTask?.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | if (isChangePallet) |
| | | { |
| | | if (state.ChangePalletPhase == 2) |
| | | { |
| | | if (isFlowA) |
| | | { |
| | | // æµåA Phase 2ï¼æ¾åçµè¯å°ç®æ æçï¼ä¸è°ç¨ APIï¼ä¸éå¢è®¡æ° |
| | | // ä¸åä»»ä½é¢å¤å¤çï¼ä»
æ´æ°ç¶æ |
| | | } |
| | | else |
| | | { |
| | | // æµåB Phase 2ï¼æ¾æ£å¸¸çµè¯ï¼éå¢è®¡æ° |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | } |
| | | else if (state.ChangePalletPhase == 4) |
| | | { |
| | | // æµåB Phase 4ï¼æ¾åçµè¯å°5å·ä½ï¼ä¸è°ç¨ APIï¼ä¸éå¢è®¡æ°ï¼éæ¾ç¹ä½ |
| | | _fakeBatteryPositionService.MarkAsAvailable(positions.ToList()); |
| | | } |
| | | else |
| | | { |
| | | // éæ¹æ¬¡æ¨¡å¼æéæ¢çä»»å¡ï¼éå¢è®¡æ° |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 鿢çä»»å¡ï¼åæé»è¾ |
| | | state.RobotTaskTotalNum += positions.Length; |
| | | if (task != null) |
| | | task.RobotTaskTotalNum -= positions.Length; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: ä¿®æ¹ HandlePickFinishedAsync æ¹æ³** |
| | | |
| | | æ¾å° `if (state.IsSplitPallet)` åï¼ç°æä»£ç 约å¨ç¬¬173-198è¡ï¼ï¼æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | // å¦ææ¯æçä»»å¡ |
| | | 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"; |
| | | } |
| | | } |
| | | // æ¢çä»»å¡ååçµè¯æ¶ï¼Phase 3ï¼ä¸è°ç¨æç API |
| | | else if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode() |
| | | && state.ChangePalletPhase == 3) |
| | | { |
| | | state.CurrentAction = "PickFinished"; |
| | | state.LastPickPositions = positions; |
| | | } |
| | | else |
| | | { |
| | | state.CurrentAction = "PickFinished"; |
| | | state.LastPickPositions = positions; |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 4: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 5: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs |
| | | git commit -m "feat(Robot): RobotPrefixCommandHandler æ¢ç任塿 ¹æ®é¶æ®µåºåå¤çé»è¾" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 7: RobotWorkflowOrchestrator éå HandlePutFinishedStateAsync ç ChangePallet 忝 |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs` |
| | | |
| | | - [ ] **Step 1: æ¿æ¢ ChangePallet 忝é»è¾** |
| | | |
| | | æ¾å° `else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())` 忝ï¼å°å
¶å®æ´æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | const int targetTotal = 48; |
| | | int targetNormalCount = task.RobotTaskTotalNum; |
| | | int currentCompletedCount = stateForUpdate.RobotTaskTotalNum; |
| | | |
| | | // 夿æµåï¼null-safeï¼ |
| | | bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // ç®æ æ°é为48ï¼ç´æ¥èµ°åæé»è¾ï¼ä¸è¿å
¥æ¹æ¬¡æ¨¡å¼ |
| | | if (targetNormalCount == targetTotal) |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | return; |
| | | } |
| | | |
| | | // åå§åæ¹æ¬¡æ¨¡å¼ |
| | | if (stateForUpdate.ChangePalletPhase == 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ¢çä»»å¡è¿å
¥æ¹æ¬¡æ¨¡å¼ï¼ä»»å¡å·: {TaskNum}ï¼æµå: {Flow}", |
| | | task.RobotTaskNum, isFlowA ? "A" : "B"); |
| | | } |
| | | |
| | | // ==================== æµåAï¼è¡¥åçµè¯å°ç®æ æç ==================== |
| | | if (isFlowA) |
| | | { |
| | | // Phase 1: ååçµè¯ï¼ä»5å·ä½ï¼ä½¿ç¨ PositionIndexï¼ |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåA宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remaining); |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions); |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | } |
| | | // Phase 2: æ¾åçµè¯å°ç®æ æçï¼ä» targetNormalCount+1 å¼å§éå¢ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåA宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // è®¡ç®æ¾è´§æ¹æ¬¡ç¼å·ï¼ä» targetNormalCount + 1 å¼å§ |
| | | int batchStart = targetNormalCount + 1 + (stateForUpdate.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remaining); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += putCount; |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | } |
| | | // ==================== æµåBï¼åæ£å¸¸çµè¯ + åæ¶åçµè¯ ==================== |
| | | else |
| | | { |
| | | // Phase 1: 忣叏çµè¯ï¼ä»æºå°åï¼ä»1å¼å§éå¢ï¼ |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | |
| | | int pickCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | // é墿¹æ¬¡ç´¢å¼ï¼å¦æå好å宿åä¸ä¸ªï¼ç´¢å¼ä¼è¶
è¿ç®æ ï¼ä½putfinished忥æ¶ä¼åæ¢é¶æ®µï¼ |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | |
| | | // åæ¢å° Phase 2 |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | } |
| | | // Phase 2: æ¾æ£å¸¸çµè¯å°ç®æ æçï¼æ¾è´§ç¼å·ä¸åè´§ç¼å·ä¸è´ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // æ£å¸¸çµè¯æ¾å®ï¼åæ¢å° Phase 3 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = targetNormalCount + 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æ£å¸¸çµè¯å
¨é¨æ¾å®ï¼è¿å
¥Phase 3åæ¶åçµè¯ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // è®¡ç®æ¬æ¹æ¾è´§ç¼å·ï¼åºäº currentCompletedCount æ¨å¯¼æ¹æ¬¡èµ·å§ï¼ä¸åè´§ç¼å·ä¸è´ï¼ |
| | | // batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1 |
| | | int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | // Phase 3: ååçµè¯ï¼ä»æºå°åï¼ä» targetNormalCount+1 å¼å§éå¢ï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 3) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåB宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remainingFake); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | stateForUpdate.ChangePalletPhase = 4; |
| | | } |
| | | // Phase 4: æ¾åçµè¯å°5å·ä½ï¼ä½¿ç¨ PositionIndexï¼ |
| | | else if (stateForUpdate.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsyncï¼æµåB宿ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, "5", start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs |
| | | git commit -m "feat(Robot): RobotWorkflowOrchestrator éå HandlePutFinishedStateAsync å®ç°æ¹æ¬¡æä»¤ä¸åæµå" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 8: RobotWorkflowOrchestrator éå HandlePickFinishedStateAsync ç ChangePallet 忝 |
| | | |
| | | **Files:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs` |
| | | |
| | | - [ ] **Step 1: ä¿®æ¹ HandlePickFinishedStateAsync æ¹æ³** |
| | | |
| | | æ¾å° `HandlePickFinishedStateAsync` æ¹æ³ï¼ç°æä»£ç 约第162-199è¡ï¼ï¼å°æ´ä¸ªæ¹æ³æ¿æ¢ä¸ºï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// å¤çåè´§å®æåçæ¾è´§æä»¤ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// æ ¹æ®ä»»å¡ç±»åå³å®æ¾è´§æä»¤æ ¼å¼ï¼ |
| | | /// - æ¢çä»»å¡ï¼ChangePalletï¼ï¼ä½¿ç¨æ¹æ¬¡æ ¼å¼ SendPutWithBatchAsync |
| | | /// - ç»çä»»å¡ï¼GroupPalletï¼ï¼ä½¿ç¨åææ ¼å¼ Putbattery,{ç®æ å°å} |
| | | /// - å
¶ä»ä»»å¡ï¼ä½¿ç¨åææ ¼å¼ |
| | | /// </remarks> |
| | | /// <param name="task">å½åä»»å¡</param> |
| | | /// <param name="ipAddress">æºå¨äºº IP å°å</param> |
| | | private async Task HandlePickFinishedStateAsync(Dt_RobotTask task, string ipAddress) |
| | | { |
| | | string taskString; |
| | | |
| | | // æ¢çä»»å¡ä½¿ç¨æ¹æ¬¡æ ¼å¼ |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | int targetNormalCount = task.RobotTaskTotalNum; |
| | | var state = _stateManager.GetState(ipAddress); |
| | | int currentCompletedCount = state?.RobotTaskTotalNum ?? 0; |
| | | |
| | | bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // æµåAï¼æ¾åçµè¯å°ç®æ æçï¼Phase 2ï¼ |
| | | if (isFlowA && state?.ChangePalletPhase == 2) |
| | | { |
| | | int remaining = 48 - currentCompletedCount; |
| | | if (remaining <= 0) return; |
| | | |
| | | // è®¡ç®æ¹æ¬¡ç¼å·ï¼ä» targetNormalCount + 1 å¼å§ |
| | | int batchStart = targetNormalCount + 1; |
| | | int putCount = Math.Min(4, remaining); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | return; |
| | | } |
| | | |
| | | // æµåB Phase 4ï¼æ¾åçµè¯å°5å·ä½ |
| | | if (!isFlowA && state?.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = 48 - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) return; |
| | | |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePickFinishedStateAsyncï¼æ å¯ç¨åçµè¯ç¹ä½ï¼ä»»å¡å·: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end); |
| | | return; |
| | | } |
| | | |
| | | // æµåB Phase 2ï¼æ¾æ£å¸¸çµè¯å°ç®æ æç |
| | | if (!isFlowA && state?.ChangePalletPhase == 2) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) return; |
| | | |
| | | int batchStart = state.CurrentBatchIndex - (state.CurrentBatchIndex - 1) / 4 * 4; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | return; |
| | | } |
| | | |
| | | // é»è®¤ï¼ä½¿ç¨åææ ¼å¼ |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | else |
| | | { |
| | | // 鿢çä»»å¡ï¼ä½¿ç¨åææ ¼å¼ |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | |
| | | bool result = await _clientManager.SendToClientAsync(ipAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("HandlePickFinishedStateAsyncï¼ä¸åæ¾è´§æä»¤æåï¼æä»¤: {TaskString}ï¼ä»»å¡å·: {TaskNum}", taskString, task.RobotTaskNum); |
| | | QuartzLogger.Info($"ä¸åæ¾è´§æä»¤æåï¼æä»¤: {taskString}", task.RobotRoadway); |
| | | |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | var stateToUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateToUpdate != null) |
| | | { |
| | | stateToUpdate.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(ipAddress, stateToUpdate)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("HandlePickFinishedStateAsyncï¼ä¸åæ¾è´§æä»¤å¤±è´¥ï¼æä»¤: {TaskString}ï¼ä»»å¡å·: {TaskNum}", taskString, task.RobotTaskNum); |
| | | QuartzLogger.Error($"ä¸åæ¾è´§æä»¤å¤±è´¥ï¼æä»¤: {taskString}", task.RobotRoadway); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 3: Commit** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs |
| | | git commit -m "feat(Robot): RobotWorkflowOrchestrator éå HandlePickFinishedStateAsync æ¯ææ¹æ¬¡æä»¤" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 9: 注åä¾èµæ³¨å
¥ |
| | | |
| | | **Files:** |
| | | - Modify: AutofacModuleRegister.cs ææ£æ¥ç°ææ³¨å |
| | | |
| | | - [ ] **Step 1: æ£æ¥ FakeBatteryPositionService æ¯å¦å·²èªå¨æ³¨å** |
| | | |
| | | ```bash |
| | | grep -r "FakeBatteryPositionService" D:\Git\ShanMeiXinNengYuan\Code\WCS\WIDESEAWCS_Server\WIDESEAWCS_Core --include="*.cs" |
| | | ``` |
| | | |
| | | Expected: 妿项ç®ä½¿ç¨ `AsImplementedInterfaces()` èªå¨æ«æï¼è¯¥æå¡å·²èªå¨æ³¨åã |
| | | |
| | | - [ ] **Step 2: æ£æ¥ RobotPrefixCommandHandler æé 彿°åæ´åæ¯å¦éè¦é¢å¤æ³¨å** |
| | | |
| | | ç±äºä»
æ°å¢äºä¾èµåæ°ï¼å¦æé¡¹ç®ä½¿ç¨ Autofac èªå¨è£
é
ï¼åæ°èªå¨æ³¨å
¥ï¼ï¼åæ éä¿®æ¹ã妿éè¦æå¨æ³¨åï¼æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | // ç¡®ä¿ IFakeBatteryPositionService 已被注åï¼é常éè¿ AsImplementedInterfaces èªå¨å®æï¼ |
| | | // RobotPrefixCommandHandler çæ°æé 彿°åæ°ä¼èªå¨è£
é
|
| | | ``` |
| | | |
| | | - [ ] **Step 3: éªè¯ç¼è¯** |
| | | |
| | | ```bash |
| | | dotnet build WIDESEAWCS_Server.sln |
| | | ``` |
| | | |
| | | Expected: 0 errors |
| | | |
| | | - [ ] **Step 4: Commit**ï¼ä»
彿å®é
æ¹å¨æ¶ææäº¤ï¼ |
| | | |
| | | ```bash |
| | | git add <ä¿®æ¹çæä»¶> |
| | | git commit -m "feat(Robot): 注åä¾èµæ³¨å
¥ï¼å¦ææ¹å¨ï¼" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 10: éªè¯æ´ä½æå»º |
| | | |
| | | - [ ] **Step 1: 宿´æå»º** |
| | | |
| | | ```bash |
| | | cd D:\Git\ShanMeiXinNengYuan\Code |
| | | dotnet build WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln |
| | | ``` |
| | | |
| | | Expected: 0 errors, 0 warnings |
| | | |
| | | - [ ] **Step 2: æ£æ¥æµè¯** |
| | | |
| | | ```bash |
| | | dotnet test WCS/WIDESEAWCS_Tests/WIDESEAWCS_Tests.csproj |
| | | ``` |
| | | |
| | | Expected: ç°ææµè¯éè¿ |
| | | |
| | | - [ ] **Step 3: æäº¤å®ææ è®°** |
| | | |
| | | ```bash |
| | | git commit --allow-empty -m "feat(Robot): æ¢ç任塿¹æ¬¡æä»¤ä¸åæµåå®ç°å®æ" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## éå½ï¼æµè¯éªè¯æ¥éª¤ |
| | | |
| | | ### æå¨éªè¯æµç¨ |
| | | |
| | | 1. **æµåAæµè¯ï¼RobotSourceAddressLineCode = 11001ï¼** |
| | | - targetNormalCount = 11 |
| | | - 颿ï¼Phase1 ååçµè¯ï¼Pickbattery,5,{pos}ï¼â Phase2 æ¾åçµè¯ï¼Putbattery,{ç®æ },12-15ï¼â 循ç¯ç´å°48 |
| | | |
| | | 2. **æµåBæµè¯ï¼RobotSourceAddressLineCode != 11001/11010ï¼** |
| | | - targetNormalCount = 11 |
| | | - 颿ï¼Phase1 忣叏ï¼Pickbattery,{æº},1-4ï¼â Phase2 æ¾æ£å¸¸ï¼Putbattery,{ç®æ },1-4ï¼â å¾ªç¯ â Phase3 ååï¼Pickbattery,{æº},12-15ï¼â Phase4 æ¾åå°5å·ä½ï¼Putbattery,5,{pos}ï¼â 循ç¯ç´å°åæ¶å®37个åçµè¯ |
| | | |
| | | 3. **è¾¹çæ¡ä»¶** |
| | | - targetNormalCount = 48ï¼èµ°åæé»è¾ |
| | | - targetNormalCount = 1ï¼æ¹æ¬¡ 1-0 æ ¼å¼ |
| | | |
| | | --- |
| | | |
| | | **Plan complete.** |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¹é MES ç»å®ä¸è§£ç»æ¥å£è®¾è®¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | å½å `StockSerivce` ä¸ `GroupPalletAsync`ã`ChangePalletAsync`ã`SplitPalletAsync` æ¯æ¬¡è°ç¨é½ä¼è§¦å䏿¬¡ MES æ¥å£ã |
| | | |
| | | WCS æºå¨äººä»»å¡ææ¹æ¬¡åæ¾ï¼ä¸ä¸ªæçå¯è½éè¦å¤æ¬¡ MES è°ç¨ï¼å¦æ¢çéè¦å
è§£ç»åç»å®ï¼ã为åå° MES è°ç¨æ¬¡æ°ï¼æ°å¢ä¸¤ä¸ªæ¹é确认æ¥å£ä¾ WCS å¨ä»»å¡é¶æ®µå®ææ¶ä¸æ¬¡æ§ä¸ä¼ æç级å«çç»å®/è§£ç»æ°æ®ã |
| | | |
| | | ## æ°å¢æ¥å£ |
| | | |
| | | ### 1. SplitPalletConfirm â æ¹éæç确认 |
| | | |
| | | **è§¦åæ¶æº**ï¼WCS æçä»»å¡/æ¢çä»»å¡å
¨é¨åå® |
| | | |
| | | **WCS è°ç¨æ¹å¼**ï¼`POST /api/Stock/SplitPalletConfirm` |
| | | |
| | | **请æ±åæ°**ï¼ |
| | | ```csharp |
| | | public class SplitPalletConfirmRequest |
| | | { |
| | | /// <summary> |
| | | /// æºæçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | **å¤çæµç¨**ï¼ |
| | | 1. WMS æ ¹æ® `PalletCode` ä»ä¸´æ¶è¡¨ `Dt_SplitTemp` 读åé¢åçµè¯å表 |
| | | 2. è°ç¨ MES `UnBindContainer`ï¼ä¸æ¬¡æ§ä¸ä¼ æ´æçµè¯ï¼ |
| | | 3. å é¤ä¸´æ¶è¡¨ `Dt_SplitTemp` ä¸å¯¹åºè®°å½ |
| | | |
| | | **临æ¶è¡¨åå
¥æ¶æº**ï¼`SplitPalletAsync` æ¯æ¬¡è¢«è°ç¨æ¶ï¼å
æ£æ¥ `Dt_SplitTemp` 䏿¯å¦åå¨è¯¥æçè®°å½ï¼ä¸åå¨åå°å½åæç对åºçææçµè¯æ¡ç åå
¥ä¸´æ¶è¡¨ï¼å·²åå¨åè·³è¿åå
¥ã |
| | | |
| | | **临æ¶è¡¨ç»æ**ï¼`Dt_SplitTemp`ï¼ï¼ |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | Id | int | ä¸»é® | |
| | | | PalletCode | string | æçå· | |
| | | | SfcList | string | çµè¯æ¡ç å表ï¼JSONæ°ç»ï¼ | |
| | | | CreateTime | DateTime | å建æ¶é´ | |
| | | |
| | | --- |
| | | |
| | | ### 2. GroupPalletConfirm â æ¹éç»ç确认 |
| | | |
| | | **è§¦åæ¶æº**ï¼WCS ç»çä»»å¡/æ¢çä»»å¡å
¨é¨æ¾å® |
| | | |
| | | **WCS è°ç¨æ¹å¼**ï¼`POST /api/Stock/GroupPalletConfirm` |
| | | |
| | | **请æ±åæ°**ï¼ |
| | | ```csharp |
| | | public class GroupPalletConfirmRequest |
| | | { |
| | | /// <summary> |
| | | /// ç®æ æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | **å¤çæµç¨**ï¼ |
| | | 1. WMS æ ¹æ® `PalletCode` æ¥è¯¢ `Dt_StockInfoDetail` ä¸è¯¥æçä¸çææçµè¯æç» |
| | | 2. è°ç¨ MES `BindContainer`ï¼ä¸æ¬¡æ§ä¸ä¼ æ´æçµè¯ç»å®ï¼ |
| | | 3. è¿åç»æ |
| | | |
| | | **注æ**ï¼çµè¯æ°æ®å¨ç»ç任塿¾è´§è¿ç¨ä¸å·²ç± WCS éè¿å
¶ä»æ¥å£åå
¥ `Dt_StockInfoDetail`ï¼WMS ä¸éè¦é¢å¤åå¨ |
| | | |
| | | --- |
| | | |
| | | ## æ¢çä»»å¡å®æ´æµç¨ |
| | | |
| | | ``` |
| | | æ¢çä»»å¡ï¼ |
| | | å
¨é¨åå® â SplitPalletConfirm(æºæç) â MES UnBindContainer |
| | | å
¨é¨æ¾å® â GroupPalletConfirm(ç®æ æç) â MES BindContainer |
| | | ``` |
| | | |
| | | ## ç°ææ¥å£å¤ç |
| | | |
| | | - `GroupPalletAsync`ã`ChangePalletAsync`ã`SplitPalletAsync` ä¿ç |
| | | - æ°æ¥å£ä¸ç°ææ¥å£å¹¶åï¼WCS æ ¹æ®ä»»å¡åºæ¯éæ©è°ç¨ |
| | | - ç°ææ¥å£ç»§ç»æ¿æ
忬¡/éæ¹éåºæ¯ç MES è°ç¨ |
| | | |
| | | ## WCS ä¾§æ¹é è¦ç¹ |
| | | |
| | | - æç/æ¢çä»»å¡å¼å§æ¶ï¼WCS è°ç¨ç°æ `SplitPalletAsync` æ¥å£ï¼WMS å¨ `SplitPalletAsync` å
é¨å
æ£æ¥ `Dt_SplitTemp` æ¯å¦å·²æè¯¥æçè®°å½ï¼æ ååå
¥ï¼æåè·³è¿ï¼å¹çåå
¥ï¼ |
| | | - ç»çä»»å¡å
¨é¨æ¾å®æ¶è°ç¨ `GroupPalletConfirm` |
| | | - æ¢çä»»å¡å
¨é¨å宿¶è°ç¨ `SplitPalletConfirm`ï¼å
¨é¨æ¾å®æ¶è°ç¨ `GroupPalletConfirm` |
| | | |
| | | ## æä»¶åæ´ |
| | | |
| | | | æä½ | æä»¶ | |
| | | |------|------| |
| | | | æ°å¢ | `WIDESEA_DTO/Stock/SplitPalletConfirmRequestDto.cs` | |
| | | | æ°å¢ | `WIDESEA_DTO/Stock/GroupPalletConfirmRequestDto.cs` | |
| | | | æ°å¢ | `WIDESEA_Model/Models/Dt_SplitTemp.cs` | |
| | | | ä¿®æ¹ | `WIDESEA_IStockService/IStockService.cs`ï¼æ°å¢æ¥å£å®ä¹ï¼ | |
| | | | ä¿®æ¹ | `WIDESEA_StockService/StockService.cs`ï¼å®ç°æ¹é确认é»è¾ï¼ | |
| | | | ä¿®æ¹ | `WIDESEA_WMSServer/Controllers/Stock/StockInfoDetailController.cs`ï¼æ°å¢ API è·¯ç±ï¼ | |
| | | | ä¿®æ¹ | æ°æ®åºï¼æ°å¢ `Dt_SplitTemp` 表 | |
| | | |
| | | ## é£é©ä¸çº¦æ |
| | | |
| | | - 临æ¶è¡¨ `Dt_SplitTemp` éè¦ææ¸
çæºå¶ï¼é²æ¢å¼å¸¸æ
åµä¸æ°æ®æ®ç |
| | | - MES æ¥å£è°ç¨å¤±è´¥æ¶ï¼ä¸´æ¶è¡¨æ°æ®ä¸åæ»ï¼ä¸æ¬¡éè¯æ¶å¯è½éå¤è§£ç»ï¼é MES ä¾§å¹çæ¯æ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¢ç任塿¹æ¬¡æä»¤ä¸åæµå设计 |
| | | |
| | | ## æ¦è¿° |
| | | |
| | | 对æ¢çä»»å¡ï¼ChangePalletï¼çåè´§/æ¾è´§æä»¤æ ¼å¼è¿è¡åçº§ï¼æ¯ææ¹æ¬¡ç¼å·åæ»æ°æä»¤ï¼å¹¶æ ¹æ® `RobotSourceAddressLineCode` åºåä¸¤ç§æµåã |
| | | |
| | | ## èæ¯ |
| | | |
| | | å½åæ¢çä»»å¡å®ç°ï¼ä¸ä¸è½®è¿ä»£ï¼ä»
å¤çäº `HandlePutFinishedStateAsync` ä¸çåçµè¯è¡¥å
é»è¾ï¼æä»¤æ ¼å¼ä¸ºç®åç `Pickbattery,{å°å}` å `Pickbattery,5,{start}-{end}`ãç°éè¦ï¼ |
| | | |
| | | 1. æææ¢çåè´§/æ¾è´§æä»¤ç»ä¸ä¸ºæ¹æ¬¡æ ¼å¼ `{Command},{ä½ç½®},{start}-{end}` |
| | | 2. æ¯æ¹ååéæ»æ°æä»¤ `PickTotalNum,{N}` / `PutTotalNum,{N}` |
| | | 3. æ ¹æ®æºå°å线ä½ç¼ç åºå两ç§å®å
¨ä¸åçæä½æµå |
| | | |
| | | ## æä»¤æ ¼å¼ |
| | | |
| | | ### æ¹æ¬¡æä»¤ |
| | | |
| | | | æä»¤ç±»å | æ ¼å¼ | ç¤ºä¾ | |
| | | |----------|------|------| |
| | | | åè´§æ»æ° | `PickTotalNum,{N}` | `PickTotalNum,11` | |
| | | | æ¾è´§æ»æ° | `PutTotalNum,{N}` | `PutTotalNum,11` | |
| | | | åè´§æ¹æ¬¡ | `Pickbattery,{ä½ç½®},{start}-{end}` | `Pickbattery,3,1-4` | |
| | | | æ¾è´§æ¹æ¬¡ | `Putbattery,{ä½ç½®},{start}-{end}` | `Putbattery,6,5-8` | |
| | | | åè´§å个 | `Pickbattery,{ä½ç½®},{n}-0` | `Pickbattery,3,11-0` | |
| | | | æ¾è´§å个 | `Putbattery,{ä½ç½®},{n}-0` | `Putbattery,6,11-0` | |
| | | |
| | | - `PickTotalNum/PutTotalNum` ä»
æ¢çä»»å¡åéï¼æ¯æ¹å/æ¾ä¹åé½å |
| | | - `N` = çå®çµè¯æ°éï¼å³ `task.RobotTaskTotalNum`ï¼ï¼æºå¨äººåºä»¶ç¨æ¤å¼å¤ææç䏿£å¸¸çµè¯æ»æ°ï¼ä¸¤ç§æµåååéç¸åç N å¼ |
| | | - æ¯æ¹æå¤4个ï¼ä¸æ»¡4个æå®é
æ°åï¼å©1ä¸ªæ¶ end=0 |
| | | |
| | | ### æ¹æ¬¡ç¼å·è®¡ç® |
| | | |
| | | `BuildBatchRange(currentIndex, remaining)` â `(start, end)`: |
| | | - `remaining >= 4` â `(currentIndex, currentIndex + 3)` |
| | | - `remaining > 1` â `(currentIndex, currentIndex + remaining - 1)` |
| | | - `remaining == 1` â `(currentIndex, 0)` |
| | | |
| | | 示ä¾ï¼targetNormalCount=11ï¼ï¼ç¬¬1æ¹ 1-4ï¼ç¬¬2æ¹ 5-8ï¼ç¬¬3æ¹ 9-11 |
| | | 示ä¾ï¼targetNormalCount=9ï¼ï¼ç¬¬1æ¹ 1-4ï¼ç¬¬2æ¹ 5-8ï¼ç¬¬3æ¹ 9-0ï¼å个ï¼end=0ï¼ |
| | | |
| | | ## ä¸¤ç§æµå |
| | | |
| | | ### æµåAï¼è¡¥åçµè¯å°ç®æ æç |
| | | |
| | | **æ¡ä»¶ï¼** `RobotSourceAddressLineCode == "11001" || "11010"` |
| | | |
| | | **åºæ¯ï¼** ç®æ æçæ N 个æ£å¸¸çµè¯ï¼N < 48ï¼ï¼éä»5å·ä½åçµè¯æçååçµè¯è¡¥æ»¡48个ã |
| | | |
| | | **é¶æ®µæµè½¬ï¼** |
| | | |
| | | ``` |
| | | [ååçµè¯] Pickbattery,5,{positionIndex} â ä»5å·ä½åï¼ç¼å·ç¨å¹³é¢ç¹ä½è¡¨PositionIndex |
| | | â |
| | | [æ¾åçµè¯] Putbattery,{ç®æ å°å},{N+1}-{N+4} â æ¾å°ç®æ æçï¼ç¼å·ä»æ£å¸¸æ°+1éå¢ |
| | | â |
| | | éå¤ç´å°è¡¥æ»¡48个 |
| | | ``` |
| | | |
| | | åçµè¯æ°é = `48 - task.RobotTaskTotalNum` |
| | | |
| | | ### æµåBï¼åæ£å¸¸çµè¯ + åæ¶åçµè¯ |
| | | |
| | | **æ¡ä»¶ï¼** `RobotSourceAddressLineCode != "11001" && != "11010"` |
| | | |
| | | **åºæ¯ï¼** æºæçåæ¬æ»¡48ä¸ªï¼æ£å¸¸çµè¯ + åçµè¯æ··åï¼ï¼å
åèµ°æ£å¸¸çµè¯æ¾å°ç®æ æçï¼åææºæçä¸å©ä½çåçµè¯ååºæ¾å5å·ä½ã |
| | | |
| | | **é¶æ®µæµè½¬ï¼** |
| | | |
| | | ``` |
| | | Phase 1 - 忣叏çµè¯: |
| | | [忣叏] Pickbattery,{æºå°å},{1}-{4} â ç¼å·ä»1éå¢ |
| | | â |
| | | [æ¾æ£å¸¸] Putbattery,{ç®æ å°å},{1}-{4} â ç¼å·ä»1éå¢ |
| | | â |
| | | éå¤ç´å° N 个æ£å¸¸çµè¯å
¨é¨åå® |
| | | |
| | | Phase 2 - åæ¶åçµè¯: |
| | | [ååçµè¯] Pickbattery,{æºå°å},{N+1}-{N+4} â ç¼å·ä»æ£å¸¸æ°+1ç»§ç»éå¢ |
| | | â |
| | | [æ¾åçµè¯] Putbattery,5,{positionIndex} â æ¾å5å·ä½ï¼ç¼å·ç¨å¹³é¢ç¹ä½è¡¨PositionIndex |
| | | â |
| | | éå¤ç´å°åçµè¯å
¨é¨åæ¶ï¼48-N ä¸ªï¼ |
| | | ``` |
| | | |
| | | ## ç¶æç®¡ç |
| | | |
| | | ### RobotSocketState æ°å¢å段 |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// å½åæ¹æ¬¡èµ·å§ç¼å·ï¼ç¨äºéå¢è®¡ç®åè´§/æ¾è´§ç¼å·ï¼ |
| | | /// </summary> |
| | | public int CurrentBatchIndex { get; set; } = 1; |
| | | |
| | | /// <summary> |
| | | /// æ¢çä»»å¡å½åé¶æ®µ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 0: æªå¼å§ |
| | | /// 1: 忣叏çµè¯ / ååçµè¯ï¼æµåAï¼ |
| | | /// 2: æ¾æ£å¸¸çµè¯ / æ¾åçµè¯ï¼æµåAï¼ |
| | | /// 3: ååçµè¯ï¼æµåB Phase2ï¼ |
| | | /// 4: æ¾åçµè¯å°5å·ä½ï¼æµåB Phase2ï¼ |
| | | /// </remarks> |
| | | public int ChangePalletPhase { get; set; } |
| | | ``` |
| | | |
| | | ### CurrentBatchIndex çå½å¨æ |
| | | |
| | | **æµåAï¼** |
| | | - Phase 0â1ï¼`CurrentBatchIndex = 1`ï¼åå§åï¼ç¨äº PositionIndex æ¥è¯¢èµ·ç¹ï¼ |
| | | - Phase 1â2ï¼ä¸éç½®ï¼æ¾è´§ç¼å·ä» `targetNormalCount + 1` å¼å§ï¼ç± Orchestrator 计ç®ï¼ |
| | | - Phase 2â1ï¼`CurrentBatchIndex += æ¬æ¹æ°é`ï¼éå¢ï¼ä¸ä¸æ¹ç»§ç»ï¼ |
| | | - 宿â0ï¼`CurrentBatchIndex = 1`ï¼éç½®ï¼ |
| | | |
| | | **æµåBï¼** |
| | | - Phase 0â1ï¼`CurrentBatchIndex = 1`ï¼åæ£å¸¸çµè¯ä»1å¼å§ï¼ |
| | | - Phase 1â2ï¼ä¸éç½®ï¼æ¾è´§ç¼å·ä¸åè´§ç¼å·ä¸è´ï¼ |
| | | - Phase 2â1ï¼`CurrentBatchIndex += æ¬æ¹æ°é`ï¼éå¢ï¼ |
| | | - Phase 2â3ï¼æ£å¸¸çµè¯åå®ï¼å³ `state.RobotTaskTotalNum >= targetNormalCount` æ¶ putfinished 宿å触åï¼ï¼`CurrentBatchIndex = targetNormalCount + 1`ï¼åçµè¯ä»æ£å¸¸æ°+1å¼å§ï¼ |
| | | - Phase 3â4ï¼ä¸éç½®ï¼æ¾åçµè¯ç¨ PositionIndexï¼ç± Orchestrator 计ç®ï¼ |
| | | - Phase 4â3ï¼`CurrentBatchIndex += æ¬æ¹æ°é`ï¼éå¢ï¼ |
| | | - 宿â0ï¼`CurrentBatchIndex = 1`ï¼éç½®ï¼ |
| | | |
| | | ### é¶æ®µæµè½¬ç¶ææº |
| | | |
| | | **æµåAï¼** |
| | | ``` |
| | | Phase 0 â Phase 1ï¼ååçµè¯from 5å·ä½ï¼â Phase 2ï¼æ¾åçµè¯to ç®æ ï¼â Phase 1 â ... â Phase 0ï¼å®æï¼ |
| | | ``` |
| | | |
| | | **æµåBï¼** |
| | | ``` |
| | | Phase 0 â Phase 1ï¼åæ£å¸¸from æºï¼â Phase 2ï¼æ¾æ£å¸¸to ç®æ ï¼â Phase 1 â ... |
| | | â Phase 3ï¼ååçµè¯from æºï¼â Phase 4ï¼æ¾åçµè¯to 5å·ä½ï¼â Phase 3 â ... â Phase 0ï¼å®æï¼ |
| | | ``` |
| | | |
| | | ## ä»£ç æ¹å¨èå´ |
| | | |
| | | | æä»¶ | æ¹å¨ | |
| | | |------|------| |
| | | | `RobotSocketState.cs` | +`CurrentBatchIndex`, +`ChangePalletPhase` | |
| | | | `RobotTaskProcessor.cs` | +`BuildBatchRange()`, +`SendPickWithBatchAsync()`, +`SendPutWithBatchAsync()`, ä¿®æ¹ç°æåçµè¯æ¹æ³ | |
| | | | `RobotWorkflowOrchestrator.cs` | éå ChangePallet 忝ï¼HandlePutFinishedStateAsync + HandlePickFinishedStateAsyncï¼ | |
| | | | `RobotPrefixCommandHandler.cs` | HandlePutFinishedAsync ä¸åºåæ¢çé¶æ®µï¼åçµè¯æ¾è´§ä¸è°ç¨ ChangePalletAsync APIï¼ä¸éå¢ `RobotTaskTotalNum`ï¼HandlePickFinishedAsync ä¸åçµè¯åè´§ä¸è°ç¨æç API | |
| | | | `RobotSimpleCommandHandler.cs` | allpickfinished/allputfinished ä¸å¢å `ChangePalletPhase` å®å«ï¼ä»
å½ Phase==0ï¼ææé¶æ®µå®æï¼æ¶æè§¦åå
¥åºåå é¤ä»»å¡ï¼ä¸é´é¶æ®µä¸å¤ç | |
| | | | `IFakeBatteryPositionService.cs` | +`MarkAsAvailable(List<int> positions)` æ¹æ³ | |
| | | | `FakeBatteryPositionService.cs` | +`MarkAsAvailable` å®ç° | |
| | | | `IFakeBatteryPositionRepository.cs` | +`MarkAsAvailable(List<int> positions)` æ¹æ³ | |
| | | | `FakeBatteryPositionRepository.cs` | +`MarkAsAvailable` å®ç°ï¼å°æå®ç¹ä½ IsUsed 设为 falseï¼ | |
| | | |
| | | ## å½ä»¤å¤çå¨äº¤äº |
| | | |
| | | ### RobotPrefixCommandHandler åæ´ |
| | | |
| | | **pickfinished å¤çï¼** |
| | | - å½ `ChangePalletPhase == 3`ï¼æµåBååçµè¯ï¼æ¶ï¼ä¸è°ç¨æç APIï¼ä»
æ´æ°ç¶æ |
| | | - å
¶ä»é¶æ®µä¿æç°æé»è¾ |
| | | |
| | | **putfinished å¤çï¼** |
| | | - 夿æµåï¼éè¿ `state.CurrentTask.RobotSourceAddressLineCode` å¤ææ¯æµåAè¿æ¯æµåB |
| | | - å½ `ChangePalletPhase == 2` 䏿µåBï¼æ¾æ£å¸¸çµè¯ï¼æ¶ï¼æ£å¸¸è°ç¨ ChangePalletAsync APIï¼`state.RobotTaskTotalNum += positions.Length` |
| | | - å½ `ChangePalletPhase == 4`ï¼æµåBæ¾åçµè¯å°5å·ä½ï¼æ¶ï¼ä¸è°ç¨ APIï¼ä¸éå¢ `RobotTaskTotalNum`ï¼è°ç¨ `MarkAsAvailable(positions)` éæ¾ç¹ä½ |
| | | - å½ `ChangePalletPhase == 2` 䏿µåAï¼æ¾åçµè¯å°ç®æ ï¼æ¶ï¼ä¸è°ç¨ APIï¼ä¸éå¢ `RobotTaskTotalNum` |
| | | |
| | | ### RobotSimpleCommandHandler åæ´ |
| | | |
| | | **allpickfinished / allputfinishedï¼** |
| | | - å¢å å®å«æ¡ä»¶ï¼ä»
å½ `state.ChangePalletPhase == 0`ï¼ææé¶æ®µå®æï¼æ¶ï¼ææ§è¡å
¥åºåä¼ åä»»å¡å é¤ |
| | | - ä¸é´é¶æ®µæ¶å° allpickfinished/allputfinished æ¶ï¼ä»
æ´æ° `state.CurrentAction`ï¼ä¸è§¦åå
¥åºé»è¾ |
| | | - ä»»å¡å®ææ¶é¢å¤éç½®ï¼`state.ChangePalletPhase = 0`, `state.CurrentBatchIndex = 1`, `state.IsInFakeBatteryMode = false` |
| | | |
| | | ## è¾¹çæ¡ä»¶ |
| | | |
| | | - `task.RobotTaskTotalNum == 48`ï¼ç´æ¥èµ°åæé»è¾ï¼ä¸è¿å
¥æ¹æ¬¡æ¨¡å¼ |
| | | - `task.RobotTaskTotalNum == 0`ï¼æµåA 补满48个åçµè¯ï¼æµåB è·³è¿ Phase 1/2ï¼ç´æ¥è¿å
¥ Phase 3/4 åæ¶48个åçµè¯ |
| | | - åçµè¯å¹³é¢ç¹ä½ä¸è¶³ï¼è®°å½é误æ¥å¿ï¼ä¸æ¢å½åæ¹æ¬¡ |
| | | - åçµè¯ç¹ä½ç¢çåï¼`GetNextAvailable` è¦æ±åè¡è¿ç»ï¼å¦æè¯·æ±4个æ¾ä¸å°ï¼ä¾æ¬¡å°è¯3ã2ã1个 |
| | | - æ¹æ¬¡ç¼å·æº¢åºï¼è¶
è¿48ï¼ï¼ä¸åºåçï¼ä½éé²å¾¡æ§æ£æ¥ |