From b698a2085fd090e90abedb1e91266ec496574b29 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期四, 16 四月 2026 23:31:35 +0800
Subject: [PATCH] 1

---
 Code/docs/superpowers/plans/2026-04-16-change-pallet-batch-command.md | 1054 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,054 insertions(+), 0 deletions(-)

diff --git a/Code/docs/superpowers/plans/2026-04-16-change-pallet-batch-command.md b/Code/docs/superpowers/plans/2026-04-16-change-pallet-batch-command.md
new file mode 100644
index 0000000..a5c7485
--- /dev/null
+++ b/Code/docs/superpowers/plans/2026-04-16-change-pallet-batch-command.md
@@ -0,0 +1,1054 @@
+# 鎹㈢洏浠诲姟鎵规鎸囦护涓庡弻娴佸悜瀹炵幇璁″垝
+
+> **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 鏂板鎵规鎸囦护鏋勫缓鏂规硶锛圔uildBatchRange, 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锛� / 鍙栧亣鐢佃姱锛堟祦鍚慉锛�
+        /// 2: 鏀炬甯哥數鑺紙娴佸悜B锛� / 鏀惧亣鐢佃姱锛堟祦鍚慉锛�
+        /// 3: 鍙栧亣鐢佃姱锛堟祦鍚態 Phase2锛�
+        /// 4: 鏀惧亣鐢佃姱鍒�5鍙蜂綅锛堟祦鍚態 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: 鍦ㄦ帴鍙d腑娣诲姞 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: 鍦ㄦ湇鍔℃帴鍙d腑娣诲姞 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` 瀛楁宸插湪涓婁竴杞凯浠d腑娣诲姞锛屾棤闇�閲嶅娉ㄥ叆銆�
+
+**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($"鍙戦�佹秷鎭細銆怱wap,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($"鍙戦�佹秷鎭細銆怱wap,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($"鍙戦�佹秷鎭細銆怗roup,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($"鍙戦�佹秷鎭細銆怗roup,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)` 鍧楋紙鐜版湁浠g爜绾﹀湪绗�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锛氭斁姝e父鐢佃姱锛岄�掑璁℃暟
+                            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)` 鍧楋紙鐜版湁浠g爜绾﹀湪绗�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;
+
+                // 鍒ゆ柇娴佸悜锛坣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;
+
+                        int pickCount = Math.Min(4, remainingNormal);
+                        var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount);
+
+                        await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end);
+
+                        // 閫掑鎵规绱㈠紩锛堝鏋滃垰濂藉彇瀹屾渶鍚庝竴涓紝绱㈠紩浼氳秴杩囩洰鏍囷紝浣唒utfinished鍥炴潵鏃朵細鍒囨崲闃舵锛�
+                        stateForUpdate.CurrentBatchIndex += pickCount;
+
+                        // 鍒囨崲鍒� Phase 2
+                        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 鎺ㄥ鎵规璧峰锛堜笌鍙栬揣缂栧彿涓�鑷达級
+                        // 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锛氭祦鍚態瀹屾垚锛屼换鍔″彿: {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;
+                    }
+                }
+            }
+```
+
+- [ ] **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>
+        /// 鏍规嵁浠诲姟绫诲瀷鍐冲畾鏀捐揣鎸囦护鏍煎紡锛�
+        /// - 鎹㈢洏浠诲姟锛圕hangePallet锛夛細浣跨敤鎵规鏍煎紡 SendPutWithBatchAsync
+        /// - 缁勭洏浠诲姟锛圙roupPallet锛夛細浣跨敤鍘熸湁鏍煎紡 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锛氭斁鍋囩數鑺埌鐩爣鎵樼洏锛圥hase 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锛氭斁姝e父鐢佃姱鍒扮洰鏍囨墭鐩�
+                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娴嬭瘯锛圧obotSourceAddressLineCode = 11001锛�**
+   - targetNormalCount = 11
+   - 棰勬湡锛歅hase1 鍙栧亣鐢佃姱锛圥ickbattery,5,{pos}锛夆啋 Phase2 鏀惧亣鐢佃姱锛圥utbattery,{鐩爣},12-15锛夆啋 寰幆鐩村埌48
+
+2. **娴佸悜B娴嬭瘯锛圧obotSourceAddressLineCode != 11001/11010锛�**
+   - targetNormalCount = 11
+   - 棰勬湡锛歅hase1 鍙栨甯革紙Pickbattery,{婧恾,1-4锛夆啋 Phase2 鏀炬甯革紙Putbattery,{鐩爣},1-4锛夆啋 寰幆 鈫� Phase3 鍙栧亣锛圥ickbattery,{婧恾,12-15锛夆啋 Phase4 鏀惧亣鍒�5鍙蜂綅锛圥utbattery,5,{pos}锛夆啋 寰幆鐩村埌鍥炴敹瀹�37涓亣鐢佃姱
+
+3. **杈圭晫鏉′欢**
+   - targetNormalCount = 48锛氳蛋鍘熸湁閫昏緫
+   - targetNormalCount = 1锛氭壒娆� 1-0 鏍煎紡
+
+---
+
+**Plan complete.**

--
Gitblit v1.9.3