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/RobotTaskProcessor.cs |  227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 221 insertions(+), 6 deletions(-)

diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
index 79f8073..e30d316 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
@@ -69,6 +69,14 @@
         private readonly HttpClientHelper _httpClientHelper;
 
         /// <summary>
+        /// 鍋囩數鑺钩闈㈢偣浣嶆湇鍔�
+        /// </summary>
+        /// <remarks>
+        /// 鐢ㄤ簬绠$悊鍋囩數鑺钩闈㈢偣浣嶇殑鍒嗛厤鍜岀姸鎬併��
+        /// </remarks>
+        private readonly IFakeBatteryPositionService _fakeBatteryPositionService;
+
+        /// <summary>
         /// 鏃ュ織璁板綍鍣�
         /// </summary>
         private readonly ILogger _logger;
@@ -88,7 +96,8 @@
             IRobotTaskService robotTaskService,
             ITaskService taskService,
             HttpClientHelper httpClientHelper,
-            ILogger logger)
+            ILogger logger,
+            IFakeBatteryPositionService fakeBatteryPositionService)
         {
             _socketClientGateway = socketClientGateway;
             _stateManager = stateManager;
@@ -96,6 +105,7 @@
             _taskService = taskService;
             _httpClientHelper = httpClientHelper;
             _logger = logger;
+            _fakeBatteryPositionService = fakeBatteryPositionService;
         }
 
         /// <summary>
@@ -110,6 +120,20 @@
         public Dt_RobotTask? GetTask(RobotCraneDevice robotCrane)
         {
             return _robotTaskService.QueryRobotCraneTask(robotCrane.DeviceCode);
+        }
+
+        /// <summary>
+        /// 鎸夎澶囩紪鐮佽幏鍙栧綋鍓嶆満鍣ㄤ汉鐨勬墽琛屼腑浠诲姟
+        /// </summary>
+        /// <remarks>
+        /// 浠庢暟鎹簱涓煡璇㈡寚瀹氳澶囩紪鐮佺殑鎵ц涓満鍣ㄤ汉浠诲姟銆�
+        /// 褰揜obotArmObject涓�1锛堟湁鐗╂枡锛変笖娌℃湁寰呭鐞嗕换鍔℃椂璋冪敤銆�
+        /// </remarks>
+        /// <param name="robotCrane">鏈哄櫒浜鸿澶囦俊鎭紝鍖呭惈璁惧缂栫爜</param>
+        /// <returns>鎵ц涓殑浠诲姟瀵硅薄锛屽鏋滄病鏈夊垯杩斿洖 null</returns>
+        public Dt_RobotTask? GetExecutingTask(RobotCraneDevice robotCrane)
+        {
+            return _robotTaskService.QueryRobotCraneExecutingTask(robotCrane.DeviceCode);
         }
 
         /// <summary>
@@ -176,6 +200,193 @@
         }
 
         /// <summary>
+        /// 涓嬪彂鍋囩數鑺彇璐ф寚浠ゅ埌鏈哄櫒浜哄鎴风
+        /// </summary>
+        /// <remarks>
+        /// 鍙戦�佹牸寮忥細Pickbattery,5,{startPosition}-{endPosition}
+        /// 渚嬪锛歅ickbattery,5,1-3 琛ㄧず浠庡亣鐢佃姱浣嶇疆5鎶撳彇锛屽钩闈㈢偣浣�1鍒�3
+        ///
+        /// 涓嬪彂鎴愬姛鍚庯細
+        /// 1. 鏍囪鐐逛綅涓哄凡浣跨敤
+        /// 2. 鏇存柊浠诲姟鐘舵�佷负"鏈哄櫒浜烘墽琛屼腑"
+        /// 3. 瀹夊叏鏇存柊鐘舵�佸埌 Redis
+        /// </remarks>
+        /// <param name="task">瑕佷笅鍙戠殑浠诲姟瀵硅薄</param>
+        /// <param name="state">鏈哄櫒浜哄綋鍓嶇姸鎬�</param>
+        /// <param name="positions">瑕佹姄鍙栫殑骞抽潰鐐逛綅鍒楄〃</param>
+        public async Task SendSocketRobotFakeBatteryPickAsync(Dt_RobotTask task, RobotSocketState state, List<int> positions)
+        {
+            if (positions == null || positions.Count == 0)
+            {
+                _logger.LogWarning("SendSocketRobotFakeBatteryPickAsync锛氬钩闈㈢偣浣嶅垪琛ㄤ负绌猴紝浠诲姟鍙�: {TaskNum}", task.RobotTaskNum);
+                return;
+            }
+
+            // 璁$畻鐐逛綅鑼冨洿锛屾牸寮忥細1-3
+            int startPos = positions.Min();
+            int endPos = positions.Max();
+            string taskString = $"Pickbattery,5,{startPos}-{endPos}";
+
+            // 鏍囪鐐逛綅涓哄凡浣跨敤
+            _fakeBatteryPositionService.MarkAsUsed(positions);
+
+            // 閫氳繃 Socket 缃戝叧鍙戦�佹寚浠ゅ埌鏈哄櫒浜哄鎴风
+            bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString);
+
+            if (result)
+            {
+                _logger.LogInformation("涓嬪彂鍋囩數鑺彇璐ф寚浠ゆ垚鍔燂紝鎸囦护: {TaskString}锛岀偣浣�: {Positions}锛岃澶�: {DeviceName}",
+                    taskString, string.Join(",", positions), state.RobotCrane?.DeviceName);
+                QuartzLogger.Info($"涓嬪彂鍋囩數鑺彇璐ф寚浠ゆ垚鍔燂紝鎸囦护: {taskString}", state.RobotCrane?.DeviceName);
+
+                // 鏇存柊浠诲姟鐘舵�佷负"鏈哄櫒浜烘墽琛屼腑"
+                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
+
+                // 灏嗕换鍔″叧鑱斿埌鐘舵�佸璞�
+                state.CurrentTask = task;
+
+                if (_stateManager.TryUpdateStateSafely(state.IPAddress, state))
+                {
+                    await _robotTaskService.UpdateRobotTaskAsync(task);
+                }
+            }
+            else
+            {
+                _logger.LogError("涓嬪彂鍋囩數鑺彇璐ф寚浠ゅけ璐ワ紝鎸囦护: {TaskString}锛岃澶�: {DeviceName}", taskString, state.RobotCrane?.DeviceName);
+                QuartzLogger.Error($"涓嬪彂鍋囩數鑺彇璐ф寚浠ゅけ璐ワ紝鎸囦护: {taskString}", state.RobotCrane?.DeviceName);
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇涓婲涓彲鐢ㄧ殑鍋囩數鑺钩闈㈢偣浣�
+        /// </summary>
+        /// <param name="count">闇�瑕佽幏鍙栫殑鐐逛綅鏁伴噺</param>
+        /// <returns>鍙敤鐐逛綅鍒楄〃</returns>
+        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>
         /// 澶勭悊鍏ュ簱浠诲姟鍥炰紶锛堟媶鐩�/缁勭洏/鎹㈢洏鍦烘櫙锛�
         /// </summary>
         /// <remarks>
@@ -208,7 +419,7 @@
 
             // 鏍规嵁宸烽亾鍚嶇О鍒ゆ柇浠撳簱 ID
             // ZYRB1 -> 1, HPRB001 -> 2, 鍏朵粬 -> 3
-            int warehouseId = currentTask.RobotRoadway == "ZYRB1" ? 1 : currentTask.RobotRoadway == "HPRB001" ? 2 : 3;
+            int warehouseId = currentTask.RobotRoadway == "娉ㄦ恫缁勭洏鏈烘鎵�" ? 1 : currentTask.RobotRoadway == "HPRB001" ? 2 : 3;
 
             // 浠诲姟绫诲瀷锛�0 琛ㄧず鏈畾涔夛紝绋嶅悗鏍规嵁浠诲姟绫诲瀷璁剧疆锛�
             int taskType = 0;
@@ -303,7 +514,8 @@
             }
 
             // 瑙f瀽杩斿洖鐨勪换鍔′俊鎭�
-            var taskInfo = JsonConvert.DeserializeObject<Dt_Task>(content.Data.ToJson() ?? string.Empty) ?? new Dt_Task();
+            var taskInfos = JsonConvert.DeserializeObject<List<Dt_Task>>(content.Data.ToJson() ?? string.Empty) ?? new List<Dt_Task>();
+            var taskInfo = taskInfos.FirstOrDefault();
 
             // 鑾峰彇婧愬湴鍧�
             string sourceAddress = taskDTO.SourceAddress;
@@ -322,8 +534,8 @@
                 // 璁剧疆杈撻�佺嚎鐨勪换鍔″彿
                 conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, taskInfo.TaskNum, sourceAddress);
 
-                // 瑙﹀彂杈撻�佺嚎寮�濮嬫墽琛岋紙鍐欏叆 WCS_STB = 1锛�
-                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_STB, 1, sourceAddress);
+                // 瑙﹀彂杈撻�佺嚎寮�濮嬫墽琛岋紙鍐欏叆 WCS_ACK = 1锛�
+                conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, sourceAddress);
 
                 // 鏇存柊浠诲姟鐘舵�佸埌涓嬩竴闃舵
                 if (_taskService.UpdateTaskStatusToNext(taskInfo).Status)
@@ -363,6 +575,9 @@
                 // 鐩爣杈撻�佺嚎缂栧彿
                 TargetLineNo = state.CurrentTask.RobotTargetAddressLineCode,
 
+                // 宸烽亾缂栧彿(鏈哄櫒浜哄悕绉�)
+                Roadway = state.CurrentTask.RobotRoadway,
+
                 // 鐢垫睜浣嶇疆璇︽儏鍒楄〃
                 // 杩囨护鎺変綅缃负 0 鎴栬礋鏁扮殑鏃犳晥鏁版嵁
                 // 鎸変綅缃紪鍙锋帓搴�
@@ -373,7 +588,7 @@
                     .Select((x, idx) => new StockDetailDTO
                     {
                         // 鏁伴噺锛氬鏋滃凡鏈変换鍔℃�绘暟锛屼娇鐢ㄤ换鍔℃�绘暟+褰撳墠浣嶇疆鏁帮紱鍚﹀垯鍙娇鐢ㄥ綋鍓嶄綅缃暟
-                        Quantity = state.RobotTaskTotalNum > 0 ? state.RobotTaskTotalNum + positions.Length : positions.Length,
+                        Quantity = 1,
 
                         // 閫氶亾/浣嶇疆缂栧彿
                         Channel = x,

--
Gitblit v1.9.3