From 1515ffa15c11e106f35e1447bc990b7867c449bb Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期四, 16 四月 2026 16:07:14 +0800
Subject: [PATCH] feat(Robot): 机械手换盘任务特殊处理

---
 Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 251 insertions(+), 12 deletions(-)

diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
index f5c193d..4414558 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
@@ -152,7 +152,7 @@
         /// </summary>
         /// <remarks>
         /// 褰撳彇璐у畬鎴愬悗锛屽悜鏈哄櫒浜哄彂閫佹斁璐ф寚浠わ紙Putbattery锛夈��
-        /// 鏈哄櫒浜烘敹鍒版寚浠ゅ悗浼氬皢璐х墿鏀剧疆鍒扮洰鏍囧湴鍧�銆�
+        /// 鎹㈢洏浠诲姟浣跨敤鎵规鏍煎紡 SendPutWithBatchAsync銆�
         ///
         /// 鎸囦护鏍煎紡锛歅utbattery,{鐩爣鍦板潃}
         /// 渚嬪锛歅utbattery,B01 琛ㄧず灏嗚揣鐗╂斁缃埌 B01 浣嶇疆
@@ -161,38 +161,99 @@
         /// <param name="ipAddress">鏈哄櫒浜� IP 鍦板潃</param>
         private async Task HandlePickFinishedStateAsync(Dt_RobotTask task, string ipAddress)
         {
-            // 鏋勫缓鏀捐揣鎸囦护锛屾牸寮忥細Putbattery,{鐩爣鍦板潃}
-            string taskString = $"Putbattery,{task.RobotTargetAddress}";
+            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;
+
+                    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锛氭斁姝e父鐢佃姱鍒扮洰鏍囨墭鐩�
+                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
+            {
+                // 闈炴崲鐩樹换鍔★細浣跨敤鍘熸湁鏍煎紡
+                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);
             }
@@ -237,13 +298,13 @@
                     || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
             }
 
-            // 濡傛灉鏄粍鐩樹换鍔★紙鍖呮嫭鎹㈢洏锛�
+            // 濡傛灉鏄粍鐩樹换鍔�
             if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
             {
                 // 鐢熸垚鎵樼洏鏉$爜鍓嶇紑
                 const string prefix = "TRAY";
 
-                // 鐢熸垚涓や釜鎵樼洏鏉$爜锛堢敤浜庣粍鐩樻搷浣滐級
+                // 鐢熸垚涓や釜鎵樼洏鏉$爜锛堢敤浜庣粍鐩樻搷浣滐級锛堟祴璇曠敤锛屽悗缁鍙栫嚎浣撴潯鐮侊級
                 string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
                 string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
 
@@ -282,6 +343,184 @@
                     QuartzLogger.Error($"鐢熸垚鎵樼洏鏉$爜澶辫触", stateForUpdate.RobotCrane.DeviceName);
                 }
             }
+            else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
+            {
+                const int targetTotal = 48;
+                int targetNormalCount = task.RobotTaskTotalNum;
+                int currentCompletedCount = stateForUpdate.RobotTaskTotalNum;
+
+                // 鍒ゆ柇娴佸悜锛坣ull-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锛氭祦鍚慉瀹屾垚锛屼换鍔″彿: {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锛氭祦鍚慉瀹屾垚锛屼换鍔″彿: {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锛氬彇姝e父鐢佃姱 + 鍥炴敹鍋囩數鑺� ====================
+                else
+                {
+                    // Phase 1: 鍙栨甯哥數鑺紙浠庢簮鍦板潃锛屼粠1寮�濮嬮�掑锛�
+                    if (stateForUpdate.ChangePalletPhase == 1)
+                    {
+                        int remainingNormal = targetNormalCount - currentCompletedCount;
+                        if (remainingNormal <= 0)
+                        {
+                            // 姝e父鐢佃姱鍙栧畬锛屽垏鎹㈠埌 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)
+                        {
+                            // 姝e父鐢佃姱鏀惧畬锛屽垏鎹㈠埌 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锛氭祦鍚態瀹屾垚锛屼换鍔″彿: {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锛氭祦鍚態瀹屾垚锛屼换鍔″彿: {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
             {
                 // 闈炵粍鐩樹换鍔★紝鐩存帴鍙戦�佸彇璐ф寚浠�

--
Gitblit v1.9.3