From ff006f77f6267fc0d2c4ee810d897a85165f5b8f Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期四, 30 四月 2026 22:08:29 +0800
Subject: [PATCH] Merge branch 'xiaoyang' into dev
---
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs | 3
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs | 8
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/TaskAddressConstants.cs | 4
Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs | 9
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/OutboundTimeConstants.cs | 10
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs | 3
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs | 6
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs | 5
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs | 2
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json | 2
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs | 80 ++----
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs | 22
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs | 30 --
Code/docs/superpowers/plans/2026-04-29-outbound-task-flow-todo-implementation.md | 170 ++++++++++++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotTaskController.cs | 20
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs | 117 +++++++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs | 22 -
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json | 2
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs | 6
Code/docs/superpowers/specs/2026-04-29-outbound-task-flow-todo-design.md | 148 ++++++++++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs | 1
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs | 4
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/BaseAPI.cs | 2
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotTaskService.cs | 16 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs | 3
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs | 2
26 files changed, 558 insertions(+), 139 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/BaseAPI.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/BaseAPI.cs
index 08a0f08..89e42b5 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/BaseAPI.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/HttpEnum/BaseAPI.cs
@@ -11,7 +11,7 @@
/// <summary>
/// WMS鎺ュ彛鍩虹URL
/// </summary>
- public const string WMSBaseUrl = "http://localhost:9291/api/";
+ public const string WMSBaseUrl = "http://192.168.60.30:9291/api/";
/// <summary>
/// WCS鎺ュ彛鍩虹URL
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs
index 1e678f5..fc5ef00 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs
@@ -112,6 +112,7 @@
DataType_Char => TypeCode.Char,
DataType_UInt => TypeCode.UInt16,
DataType_UDInt => TypeCode.UInt32,
+ DataType_ByteArray => TypeCode.SByte,
_ => throw new CommunicationException($"鏁版嵁绫诲瀷閿欒:銆恵dataType}銆�", CommunicationErrorType.TypeError),
};
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs
index c2dfc11..1d72f38 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs
@@ -358,6 +358,9 @@
return Encoding.Default.GetString((byte[])GetContent(plc.Read(address, length), address)).ToArray();
return (char)GetContent(plc.ReadByte(address), address);
+ case TypeCode.SByte:
+ return Encoding.Default.GetString((byte[])GetContent(plc.Read(address, 20), address)).ToArray();
+
default:
throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, typeCode.ToString(), address), CommunicationErrorType.TypeError);
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotTaskService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotTaskService.cs
index 203bf94..87d7b3a 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotTaskService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/IRobotTaskService.cs
@@ -83,12 +83,28 @@
WebResponseContent GetWMSRobotTask(Dt_Task task);
/// <summary>
+ ///
+ /// </summary>
+ /// <param name="taskType"></param>
+ /// <param name="palletCode"></param>
+ /// <returns></returns>
+ int GetRobotTaskTotalNum(int taskType, string? palletCode);
+
+ /// <summary>
/// 鍦ㄦ湰鍦扮洿鎺ュ垱寤烘満姊版墜浠诲姟锛屼笉璋冪敤WMS鎺ュ彛
/// </summary>
/// <param name="task">鍑哄簱浠诲姟</param>
/// <returns>鎿嶄綔缁撴灉</returns>
WebResponseContent CreateLocalRobotTask(Dt_Task task);
+ /// <summary>
+ /// 妫�鏌ユ簮绾夸綋鏄惁鏈夋墭鐩樺彿锛屽苟鏍规嵁缁撴灉鍒涘缓鏈烘鎵嬩换鍔°��
+ /// 鏈夋墭鐩樺彿鏃惰皟鐢� CreateLocalRobotTask锛屾棤鎵樼洏鍙锋椂浠� WMS 鑾峰彇浠诲姟銆�
+ /// </summary>
+ /// <param name="task">鍑哄簱浠诲姟瀹炰綋</param>
+ /// <returns>鎿嶄綔缁撴灉</returns>
+ WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task);
+
int MapWarehouseIdConfigKey(string? targetAddress);
string ResolveRobotRuleValue(string? targetAddress, string addressSectionName, string? fallback);
WebResponseContent CreateRobotTaskManually(ManualRobotTaskDto request);
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs
index 6be42fe..5c795e5 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs
@@ -459,11 +459,14 @@
/// <returns></returns>
private ITrigger CreateSimpleTrigger(DispatchInfoDTO sysSchedule)
{
+ // Quartz瑕佹眰闂撮殧鑷冲皯1绉掞紝闃叉鏁版嵁搴撲腑IntervalSecond涓�0鎴栬礋鍊煎鑷碅rgumentOutOfRangeException
+ var intervalSeconds = sysSchedule.IntervalSecond <= 0 ? 1 : sysSchedule.IntervalSecond;
+
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
.StartAt(sysSchedule.BeginTime.GetValueOrDefault())
.WithSimpleSchedule(x => x
- .WithIntervalInSeconds(sysSchedule.IntervalSecond)
+ .WithIntervalInSeconds(intervalSeconds)
.RepeatForever()
)
.EndAt(sysSchedule.EndTime.GetValueOrDefault())
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs
index 8b697de..0d93b8b 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs
@@ -82,6 +82,8 @@
public IServer GetServer()
{
var endpoints = _connection.Value.GetEndPoints();
+ if (endpoints == null || endpoints.Length == 0)
+ throw new InvalidOperationException("Redis娌℃湁鍙敤鐨勭粓缁撶偣锛岃妫�鏌ヨ繛鎺ラ厤缃�");
return _connection.Value.GetServer(endpoints[0]);
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotTaskController.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotTaskController.cs
index ee7754c..af053f2 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotTaskController.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/RobotTaskController.cs
@@ -1,14 +1,9 @@
-锘縰sing Autofac.Core;
+using Autofac.Core;
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
-using System.Threading.Tasks;
-using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseController;
-using WIDESEAWCS_Core.Enums;
-using WIDESEAWCS_DTO.TaskInfo;
-using WIDESEAWCS_ISystemServices;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
@@ -20,17 +15,24 @@
{
public RobotTaskController(IRobotTaskService service) : base(service)
{
-
}
+
[HttpGet, HttpPost, Route("DeleteRobotTask"), AllowAnonymous]
public WebResponseContent DeleteRobotTask(int id)
{
- if (Service.DeleteRobotTask(id)){
+ if (Service.DeleteRobotTask(id))
+ {
return WebResponseContent.Instance.OK();
}
return WebResponseContent.Instance.Error();
}
+
+ [HttpGet, HttpPost, Route("GetRobotTaskTotalNum"), AllowAnonymous]
+ public int GetRobotTaskTotalNum( int taskType, string? palletCode)
+ {
+ return Service.GetRobotTaskTotalNum(taskType, palletCode);
+ }
// 鎵嬪姩鏈烘鎵嬩换鍔�
[HttpGet, HttpPost, Route("CreateRobotTaskManually"), AllowAnonymous]
public WebResponseContent CreateRobotTaskManually([FromBody] ManualRobotTaskDto request)
@@ -38,4 +40,4 @@
return Service.CreateRobotTaskManually(request);
}
}
-}
+}
\ No newline at end of file
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
index 8897ce4..6847c0c 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
@@ -34,7 +34,7 @@
//5.PostgreSQL
"DBType": "SqlServer",
//杩炴帴瀛楃涓�
- "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
//"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWCS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
//璺ㄥ煙
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs
index 192b2a5..e9df2c8 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs
@@ -107,13 +107,17 @@
if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
{
- return WebResponseContent.Instance.OK();
+ //return WebResponseContent.Instance.OK();
+
+ //return _robotTaskService.CheckSourceLineAndCreateRobotTask(task);
+ // Todo:鑾峰彇瀵瑰悜绾夸綋鏄惁鏈夋墭鐩樺彿锛屽鏋滄湁鎵樼洏鍙风洿鎺ョ敓鎴愭満姊版墜浠诲姟
+
return GetWMSOutboundTrayTask(task);
}
if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty)
{
- return _robotTaskService.CreateLocalRobotTask(task);
+ return _robotTaskService.CreateLocalRobotTask(task);
//if (!content.Status)
//{
// return content;
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
index 48c1bc2..915f224 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
@@ -22,10 +22,12 @@
using Masuit.Tools;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using Serilog;
using SqlSugar;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Text;
using WIDESEA_Core;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.HttpEnum;
@@ -75,6 +77,7 @@
_taskExecuteDetailService = taskExecuteDetailService;
_logger = logger;
}
+
public override WebResponseContent DeleteData(object[] keys)
{
List<int> taskKeys = new List<int>();
@@ -85,8 +88,8 @@
List<Dt_RobotTask> tasks = BaseDal.QueryData(x => taskKeys.Contains(x.RobotTaskId));
BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.浜哄伐鍒犻櫎);
return WebResponseContent.Instance.OK($"鎴愬姛鍒犻櫎{tasks.Count}鏉℃暟鎹�");
-
}
+
public bool DeleteRobotTask(int id)
{
Dt_RobotTask task = BaseDal.QueryFirst(x => x.RobotTaskId == id);
@@ -135,7 +138,7 @@
public Dt_RobotTask? QueryRobotCraneTask(string deviceCode)
{
- return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode && x.RobotTaskState != (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
+ return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode, TaskOrderBy);
}
public Dt_RobotTask? QueryRobotCraneExecutingTask(string deviceCode)
@@ -242,10 +245,108 @@
}
/// <summary>
+ /// 妫�鏌ユ簮绾夸綋鏄惁鏈夋墭鐩樺彿锛屽苟鏍规嵁缁撴灉鍒涘缓鏈烘鎵嬩换鍔°��
+ /// </summary>
+ /// <param name="task">鍑哄簱浠诲姟瀹炰綋</param>
+ /// <returns>
+ /// 鏈夋墭鐩樺彿鏃惰繑鍥� CreateLocalRobotTask 缁撴灉锛�
+ /// 鏃犳墭鐩樺彿鏃惰繑鍥� GetWMSOutboundTrayTask 缁撴灉銆�
+ /// </returns>
+ public WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task)
+ {
+ // 1. 鑾峰彇婧愮嚎浣撶紪鍙凤紙澶嶇敤宸叉湁閫昏緫锛�
+ string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
+ StockDTO stock = BuildRobotTaskStock(task, configKey);
+ string sourceLineNo = stock.SourceLineNo;
+
+ if (string.IsNullOrWhiteSpace(sourceLineNo))
+ {
+ return GetWMSOutboundTrayTaskFromWMS(task);
+ }
+
+ // 2. 閫氳繃璁惧閫氫俊璇诲彇绾夸綋鎵樼洏鍙�
+ string? palletCode = ReadLineBarcode(sourceLineNo);
+
+ if (!string.IsNullOrWhiteSpace(palletCode))
+ {
+ // 鏈夋墭鐩樺彿锛屾湰鍦板垱寤烘満姊版墜浠诲姟
+ return CreateLocalRobotTask(task);
+ }
+
+ // 鏃犳墭鐩樺彿锛屼粠 WMS 鑾峰彇浠诲姟
+ return GetWMSOutboundTrayTaskFromWMS(task);
+ }
+
+ /// <summary>
+ /// 浠嶹MS鑾峰彇绌烘墭鐩樺嚭搴撲换鍔°��
+ /// </summary>
+ /// <param name="task">浠诲姟瀹炰綋銆�</param>
+ /// <returns>璋冪敤缁撴灉銆�</returns>
+ private WebResponseContent GetWMSOutboundTrayTaskFromWMS(Dt_Task task)
+ {
+ int warehouseId = MapWarehouseIdConfigKey(task.TargetAddress);
+ string sourceLineNo = ResolveRobotRuleValue(task.TargetAddress, "AddressSourceLineNoMap", task.TargetAddress);
+ string configKey = nameof(ConfigKey.GetOutBoundTrayTaskAsync);
+ string requestParam = new CreateTaskDto { WarehouseId = warehouseId, TargetAddress = sourceLineNo }.ToJson();
+ DateTime startTime = DateTime.Now;
+
+ var result = _httpClientHelper.Post<WebResponseContent>(configKey, requestParam);
+
+ if (!result.IsSuccess || !result.Data.Status)
+ {
+ QuartzLogHelper.LogError(_logger, $"璋冪敤WMS鎺ュ彛澶辫触,鎺ュ彛:銆恵configKey}銆�,璇锋眰鍙傛暟:銆恵requestParam}銆�,閿欒淇℃伅:銆恵result.Data?.Message}銆�", "RobotTaskService");
+ return WebResponseContent.Instance.Error($"鑾峰彇WMS绯荤粺绌烘墭鐩樺嚭搴撲换鍔″け璐�,浠诲姟鍙�:銆恵task.TaskNum}銆�,鎵樼洏鍙�:銆恵task.PalletCode}銆�,閿欒淇℃伅:銆恵result.Data?.Message}銆�");
+ }
+
+ QuartzLogHelper.LogInfo(_logger, $"璋冪敤WMS鎺ュ彛鎴愬姛,鎺ュ彛:銆恵configKey}銆�,鍝嶅簲鏁版嵁:銆恵result.Data?.Data}銆�,鑰楁椂:{(DateTime.Now - startTime).TotalMilliseconds}ms", "RobotTaskService");
+
+ WMSTaskDTO? wMSTask = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data?.ToString() ?? string.Empty);
+ if (wMSTask == null)
+ return WebResponseContent.Instance.Error($"鑾峰彇WMS绯荤粺绌烘墭鐩樺嚭搴撲换鍔″け璐�,浠诲姟鍙�:銆恵task.TaskNum}銆�,鎵樼洏鍙�:銆恵task.PalletCode}銆�,閿欒淇℃伅:銆怶MS鏈繑鍥炴湁鏁堜换鍔℃暟鎹��");
+
+ // 鏋勫缓StockDTO骞惰皟鐢≧eceiveWMSTask鍒涘缓鏈湴鍏ュ簱浠诲姟
+ var stockDto = new StockDTO
+ {
+ Roadway = task.Roadway,
+ SourceLineNo = sourceLineNo,
+ TargetLineNo = task.TargetAddress,
+ SourcePalletNo = string.Empty,
+ TargetPalletNo = string.Empty
+ };
+ return ReceiveWMSTask(wMSTask, stockDto);
+ }
+
+ /// <summary>
+ /// 璇诲彇鎸囧畾绾夸綋鐨勬墭鐩樺彿銆�
+ /// </summary>
+ /// <param name="sourceLineNo">婧愮嚎浣撶紪鍙�</param>
+ /// <returns>鎵樼洏鍙凤紝濡傛湁寮傚父杩斿洖 null</returns>
+ private string? ReadLineBarcode(string sourceLineNo)
+ {
+ try
+ {
+ IDevice? device = Storage.Devices.FirstOrDefault(x =>
+ x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
+
+ if (device == null)
+ return null;
+
+ CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
+ return conveyorLine.GetValue<ConveyorLineDBNameNew, string>(
+ ConveyorLineDBNameNew.Barcode, sourceLineNo);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, $"璇诲彇绾夸綋[{sourceLineNo}]鎵樼洏鍙峰紓甯�");
+ return null;
+ }
+ }
+
+ /// <summary>
/// 鑾峰彇鏈烘鎵嬩换鍔℃�绘暟閲忋��
/// 缁勭洏浠诲姟鍥哄畾48锛屾崲鐩樺拰鎷嗙洏浠诲姟閫氳繃鎵樼洏鍙锋煡璇MS搴撳瓨鏄庣粏鏁伴噺銆�
/// </summary>
- private int GetRobotTaskTotalNum(int taskType, string? palletCode)
+ public int GetRobotTaskTotalNum(int taskType, string? palletCode)
{
if (taskType == (int)RobotTaskTypeEnum.GroupPallet)
return 48;
@@ -255,8 +356,10 @@
try
{
+ QuartzLogHelper.LogInfo(_logger, $"寮�濮嬭皟鐢╓MS鎺ュ彛鑾峰彇搴撳瓨鏄庣粏鏁伴噺,鎵樼洏鍙�:銆恵palletCode}銆�", "RobotTaskService");
string url = $"{BaseAPI.WMSBaseUrl}Stock/GetStockDetailCount?palletCode={Uri.EscapeDataString(palletCode)}";
var result = _httpClientHelper.Get(url);
+ QuartzLogHelper.LogInfo(_logger, $"璋冪敤WMS鑾峰彇搴撳瓨鏄庣粏鏁伴噺鎺ュ彛,璇锋眰URL:銆恵url}銆�,鍝嶅簲鏁版嵁:銆恵result.Content}銆�,鑰楁椂:{result.Duration}ms", "RobotTaskService");
if (!result.IsSuccess || string.IsNullOrEmpty(result.Content))
return 1;
@@ -264,8 +367,8 @@
if (response == null || !response.Status)
return 1;
- var detailCount = response.Data?.GetType().GetProperty("DetailCount")?.GetValue(response.Data);
- return detailCount is int count and > 0 ? count : 1;
+ var detailCount = (response.Data as JObject)?["detailCount"]?.Value<int>();
+ return detailCount.HasValue && detailCount.Value > 0 ? detailCount.Value : 1;
}
catch
{
@@ -370,8 +473,10 @@
CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
DeviceProDTO? devicePro = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(ConveyorLineDBNameNew.Barcode) && x.DeviceChildCode == sourceLineNo);
+ //conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
//ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(sourceLineNo); // 娴嬭瘯鐢�
- var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
+ var bytes = conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
+ var barcode = Encoding.Default.GetString(bytes).Trim();
stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode;
}
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
index 7788251..fa281cd 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -1,16 +1,11 @@
using MapsterMapper;
using Masuit.Tools;
-using Microsoft.Extensions.Configuration;
-using Newtonsoft.Json;
using Quartz;
using Serilog;
using SqlSugar;
using WIDESEA_Core;
-using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
-using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
-using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
@@ -228,7 +223,11 @@
{
// 濡傛灉 WCS_ACK 涓� 1锛屽厛娓呴櫎锛堣〃绀哄鐞嗚繃涓婁竴娆¤姹傦級
if (command.WCS_ACK == 1)
- conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)0, childDeviceCode);
+ {
+ conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (byte)0, childDeviceCode);
+ //Thread.Sleep(300);
+ //conveyorLine.SetValue(ConveyorLineDBNameNew.Target, (short)0, childDeviceCode);
+ }
// 澶勭悊鎵嬪姩鍏ュ簱浠诲姟锛堣捣鐐逛负绾夸綋鐐逛綅鐨勪换鍔★級
try
@@ -247,17 +246,36 @@
}
continue;
}
+ else
+ {
+ if (childDeviceCode == "2103" || childDeviceCode == "2101")
+ {
+ try
+ {
+ var task = _taskService.QueryManualInboundTask(childDeviceCode);
+ if (task != null)
+ {
+ QuartzLogHelper.LogInfo(_logger, $"鑾峰彇鍒拌緭閫佺嚎寮�濮嬩换鍔★紝浠诲姟鍙凤細{task.TaskNum}锛岀姸鎬�: {task.TaskStatus},褰撳墠鍦板潃锛歿conveyorLine.DeviceCode}", conveyorLine.DeviceCode);
+ var handler = new ManualInboundTaskHandler(_taskService, _logger);
+ handler.WriteTaskToPlc(conveyorLine, childDeviceCode, task);
+ }
+ }
+ catch (Exception ex)
+ {
+ QuartzLogHelper.LogError(_logger, ex, "澶勭悊鎵嬪姩鍏ュ簱浠诲姟寮傚父", $"澶勭悊鎵嬪姩鍏ュ簱浠诲姟寮傚父: {ex.Message}", "CommonConveyorLineNewJob");
+ }
+ }
+ }
- // ========== 澶勭悊鏃犳墭鐩樻潯鐮佺殑鎯呭喌 ==========
- // 鏃犳墭鐩樻潯鐮佹椂锛岃姹傚嚭搴撲换鍔�
- if (command.Barcode.IsNullOrEmpty() || command.Barcode.Replace("\0", "") == "")
+ // 濡傛灉 PLC_STB 涓� 1锛屼絾娌℃湁浠诲姟鍙凤紝鍙兘鏄柊浠诲姟鐨勫紑濮嬶紝鍏堣姹傚嚭搴撲换鍔★紙閫傜敤浜庢棤鏉$爜鐨勬儏鍐碉級
+ if (command.TaskNo == 1000)
{
_conveyorLineDispatch.RequestOutbound(conveyorLine, command, childDeviceCode);
continue;
}
// ========== 澶勭悊宸叉湁浠诲姟鍙风殑鎯呭喌 ==========
- if (command.TaskNo > 0 && !command.Barcode.IsNullOrEmpty())
+ if (command.TaskNo > 0)
{
// 鏌ヨ姝e湪鎵ц鐨勪换鍔�
Dt_Task task = _taskService.QueryExecutingConveyorLineTask(command.TaskNo, childDeviceCode);
@@ -299,48 +317,6 @@
conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode);
}
}
- //else if (!command.Barcode.IsNullOrEmpty() && (childDeviceCode == "11001" || childDeviceCode == "11010"))
- //{
- // var isWcsTask = _taskService.Db.Queryable<Dt_Task>().Any(x => x.PalletCode == command.Barcode && (x.TaskStatus == (int)TaskOutStatusEnum.OutNew || x.TaskStatus == (int)TaskInStatusEnum.InNew));
- // var isRobotTask = _robotTaskService.Db.Queryable<Dt_RobotTask>().Any(x => x.RobotTargetAddressPalletCode == command.Barcode);
- // if (isWcsTask || isRobotTask)
- // {
- // continue;
- // }
-
- // // 璋冪敤 WMS 鍒涘缓绌烘墭鐩樺叆搴撲换鍔�
- // string configKey = nameof(ConfigKey.CreateTaskInboundAsync);
- // string requestParam = new CreateTaskDto()
- // {
- // PalletCode = command.Barcode,
- // SourceAddress = childDeviceCode,
- // TargetAddress = "GWSC1", // 鐩爣鍦板潃
- // Roadway = "GWSC1", // 宸烽亾
- // WarehouseId = 1, // 浠撳簱 ID
- // PalletType = 1, // 鎵樼洏绫诲瀷锛堥粯璁や负1锛�
- // TaskType = TaskTypeEnum.InEmpty.GetHashCode() // 浠诲姟绫诲瀷锛堝叆搴�/绌烘墭鐩樺叆搴擄級
- // }.Serialize();
- // DateTime startTime = DateTime.Now;
-
- // var responseResult = _httpClientHelper.Post<WebResponseContent>(configKey, requestParam);
-
- // if (responseResult.IsSuccess && responseResult.Data.Status)
- // {
- // QuartzLogHelper.LogInfo(_logger, $"璋冪敤WMS鎺ュ彛鎴愬姛,鎺ュ彛:銆恵configKey}銆�,璇锋眰鍙傛暟:銆恵requestParam}銆�,鍝嶅簲鏁版嵁:銆恵responseResult.Data?.Data}銆�,鑰楁椂:{(DateTime.Now - startTime).TotalMilliseconds}ms", conveyorLine.DeviceCode);
- // var wmsTask = JsonConvert.DeserializeObject<WMSTaskDTO>(responseResult?.Data?.Data?.ToString());
- // List<WMSTaskDTO> taskDTOs = new List<WMSTaskDTO> { wmsTask };
- // if (wmsTask == null) continue;
-
- // if (_taskService.ReceiveWMSTask(taskDTOs).Status)
- // {
- // conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode);
- // }
- // }
- // else
- // {
- // QuartzLogHelper.LogError(_logger, $"璋冪敤WMS鎺ュ彛澶辫触,鎺ュ彛:銆恵configKey}銆�,璇锋眰鍙傛暟:銆恵requestParam}銆�,閿欒淇℃伅:銆恵responseResult.Data?.Message}銆�", conveyorLine.DeviceCode);
- // }
- //}
}
}
catch (Exception innerEx)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
index d3555a1..1b3c8d5 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
@@ -257,21 +257,21 @@
// 纭畾鐩爣鍦板潃锛氱┖鎵樼洏浠诲姟浣跨敤 "2201"锛屽叾浠栦换鍔′娇鐢� NextAddress
var isEmptyTask = task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty;
- var targetAddress = task.CurrentAddress == "2217" ? (isEmptyTask ? "2201" : task.NextAddress) : task.NextAddress;
+ var targetAddress = task.CurrentAddress == "2217" ? (isEmptyTask ? task.TargetAddress : task.NextAddress) : task.NextAddress;
// 澶勭悊鐗规畩鍦板潃 2217锛岄渶瑕佽皟鐢ㄧ洰鏍囧湴鍧�閫夋嫨鍣�
- if (task.CurrentAddress == "2217" && !_targetAddressSelector.HandleOutboundNextAddress(conveyorLine, targetAddress, childDeviceCode))
- {
- return Task.CompletedTask; ;
- }
+ //if (task.CurrentAddress == "2217" && !_targetAddressSelector.HandleOutboundNextAddress(conveyorLine, targetAddress, childDeviceCode))
+ //{
+ // return Task.CompletedTask; ;
+ //}
// 璁剧疆浠诲姟鍙枫�佹墭鐩樻潯鐮併�佺洰鏍囧湴鍧�銆乄CS_ACK
var isTaskNoSet = conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, task.TaskNum, childDeviceCode);
- Thread.Sleep(100); // 纭繚 PLC 鑳芥纭鍙栦换鍔″彿鍚庡啀鍐欏叆鏉$爜
+ Thread.Sleep(300); // 纭繚 PLC 鑳芥纭鍙栦换鍔″彿鍚庡啀鍐欏叆鏉$爜
var isPalletSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Barcode, task.PalletCode, childDeviceCode);
- Thread.Sleep(100); // 纭繚 PLC 鑳芥纭鍙栦换鍔″彿鍚庡啀鍐欏叆鏉$爜
+ Thread.Sleep(300); // 纭繚 PLC 鑳芥纭鍙栦换鍔″彿鍚庡啀鍐欏叆鏉$爜
bool isTargetSet = conveyorLine.SetValue(ConveyorLineDBNameNew.Target, targetAddress, childDeviceCode);
//if (targetAddress == "2217" && !isEmptyTask)
//{
@@ -281,16 +281,16 @@
//}
//if (!isTargetSet || !isTaskNoSet || !isPalletSet)
//{
- // QuartzLogHelper.LogError(_logger, $"RequestOutbound锛氫笅鍙戝嚭搴撲换鍔″け璐ワ紝浠诲姟鍙�: {task.TaskNum}锛屽瓙璁惧: {childDeviceCode}", conveyorLine.DeviceCode);
+ // QuartzLogHelper.LogError(_logger, $"RequestOutbound锛氫笅鍙戝嚭搴撲换鍔″け璐ワ紝浠诲姟鍙�: {task.TaskNum}锛屽瓙璁惧: {childDeviceCode}", conveyorLine.DeviceCode);
// return Task.CompletedTask;
//}
bool isWmsResult = false;
// 鏇存柊浠诲姟鐘舵�佹垨浣嶇疆
- if (isEmptyTask && task.NextAddress == "2217")
+ if (isEmptyTask && (task.TargetAddress == "2103" || task.TargetAddress == "2101"))
{
task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskOutStatusEnum>();
- task.NextAddress = "2201";
+ task.NextAddress = "2103";
isWmsResult = _taskService.Repository.UpdateData(task);
}
else
@@ -298,7 +298,7 @@
isWmsResult = _taskService.UpdateTaskStatusToNext(task).Status;
}
- if(!isWmsResult)
+ if (!isWmsResult)
{
QuartzLogHelper.LogError(_logger, $"RequestOutbound锛氭洿鏂颁换鍔$姸鎬佸け璐ワ紝浠诲姟鍙�: {task.TaskNum}锛屽瓙璁惧: {childDeviceCode}", conveyorLine.DeviceCode);
return Task.CompletedTask;
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs
index e003d18..c816827 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineTargetAddressSelector.cs
@@ -68,8 +68,11 @@
var cvState = conveyorLine.GetValue<ConveyorLineDBNameNew, byte>(ConveyorLineDBNameNew.CV_State, nextAddress);
bool isAvailable = cvState == 2;
+ WriteDebug(conveyorLine, "鍑哄簱涓嬩竴鍦板潃鐘舵��", childDeviceCode, $"CV_State={cvState}锛屽彲鐢�={isAvailable}");
if (isAvailable)
{
+ WriteDebug(conveyorLine, "鍑哄簱涓嬩竴鍦板潃鍙敤锛屽啓鍏ョ洰鏍囧湴鍧�", childDeviceCode, nextAddress);
+ Thread.Sleep(300); // 鐭殏绛夊緟锛岀‘淇濊澶囩姸鎬佺ǔ瀹氬悗鍐嶅啓鍏ョ洰鏍囧湴鍧�
return conveyorLine.SetValue(ConveyorLineDBNameNew.Target, Convert.ToInt16(nextAddress), childDeviceCode);
}
return false;
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
index 318ed17..06c1c36 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotTaskProcessor.cs
@@ -627,6 +627,12 @@
// 瑙f瀽 WMS 杩斿洖鐨勪换鍔′俊鎭�
WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data.ToJson() ?? string.Empty) ?? new WMSTaskDTO();
+ var task = await _taskService.Repository.QueryFirstAsync(x => x.PalletCode == taskDTO.PalletCode);
+ if(task != null)
+ {
+ await _taskService.Repository.DeleteDataAsync(task);
+ }
+
// 璋冪敤浠诲姟鏈嶅姟鎺ユ敹 WMS 浠诲姟
var content = _taskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
if (!content.Status)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs
index d60d160..2c7f640 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotSimpleCommandHandler.cs
@@ -197,7 +197,7 @@
// 璋冪敤鎵归噺鎷嗙洏纭鎺ュ彛
var sourcePallet = state.CurrentTask.RobotSourceAddressPalletCode;
var confirmResult = _taskProcessor.PostSplitPalletConfirmAsync(sourcePallet, state.RobotCrane?.DeviceName);
- if (!confirmResult.IsSuccess)
+ if (!confirmResult.IsSuccess && !confirmResult.Data.Status)
{
QuartzLogHelper.LogError(_logger, $"鎵归噺鎷嗙洏纭澶辫触: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown");
return false;
@@ -314,7 +314,7 @@
// 璋冪敤鎵归噺缁勭洏纭鎺ュ彛
var targetPallet = state.CurrentTask.RobotTargetAddressPalletCode;
var confirmResult = _taskProcessor.PostGroupPalletConfirmAsync(targetPallet, state.RobotCrane?.DeviceName);
- if (!confirmResult.IsSuccess)
+ if (!confirmResult.IsSuccess && !confirmResult.Data.Status)
{
QuartzLogHelper.LogError(_logger, $"鎵归噺缁勭洏纭澶辫触: {confirmResult.ErrorMessage}", state.RobotCrane?.DeviceName ?? "Unknown");
return false;
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 3d5241e..8cba5b3 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
@@ -396,10 +396,13 @@
// 鐩爣鏁伴噺涓�48锛氱洿鎺ヨ蛋鍘熸湁閫昏緫锛屼笉杩涘叆鎵规妯″紡
if (targetNormalCount + currentCompletedCount == targetTotal)
{
+ QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsync锛氱洰鏍囨暟閲忓凡杈�48锛岀洿鎺ヤ笅鍙戝彇璐ф寚浠わ紝浠诲姟鍙�: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress);
await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
return;
}
+ QuartzLogHelper.LogDebug(_logger,$"HandlePutFinishedStateAsync锛氭崲鐩樹换鍔$洰鏍囨暟閲�: {targetNormalCount}锛屽綋鍓嶅凡瀹屾垚鏁伴噺: {currentCompletedCount}锛屾祦鍚�: {(isFlowA ? "A" : "B")}锛屼换鍔″彿: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress);
+
// 鍒濆鍖栨壒娆℃ā寮�
if (stateForUpdate.ChangePalletPhase == 0)
{
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
index 15fd6f2..2c7f8f4 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/SocketServer/TcpSocketServer.Messaging.cs
@@ -3,6 +3,7 @@
using System.Text.Json;
using System.IO;
using WIDESEAWCS_Model.Models;
+using Serilog.Core;
namespace WIDESEAWCS_Tasks.SocketServer
{
@@ -64,6 +65,7 @@
//{
// if (_clientLastMessage.TryGetValue(clientId, out var prev) && message == prev)
// {
+ // QuartzLogHelper.LogInfo(Logger.None, $"鏉ヨ嚜瀹㈡埛绔� {clientId} 鐨勯噸澶嶆秷鎭紝鍐呭: {message}", clientId);
// continue;
// }
// _clientLastMessage[clientId] = message;
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
index f24aa72..4568c72 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs
@@ -121,36 +121,6 @@
}
/// <summary>
- /// 鍔犺浇閰嶇疆鏂囦欢锛堜紭鍏堢骇锛氶厤缃枃浠� > 榛樿閰嶇疆锛�
- /// </summary>
- /// <remarks>
- /// 浠庡簲鐢ㄧ▼搴忕洰褰曚笅鐨� StackerCraneJob/stackercrane-command-config.json 璇诲彇閰嶇疆銆�
- /// 濡傛灉鏂囦欢涓嶅瓨鍦ㄦ垨瑙f瀽澶辫触锛屼娇鐢ㄩ粯璁ら厤缃��
- /// </remarks>
- /// <returns>鍫嗗灈鏈哄懡浠ら厤缃�</returns>
- private static StackerCraneCommandConfig LoadConfig()
- {
- try
- {
- // 鏋勯�犻厤缃枃浠惰矾寰�
- string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StackerCraneJob", "stackercrane-command-config.json");
- if (File.Exists(configPath))
- {
- // 璇诲彇骞惰В鏋� JSON 閰嶇疆
- string json = File.ReadAllText(configPath);
- return System.Text.Json.JsonSerializer.Deserialize<StackerCraneCommandConfig>(json) ?? new StackerCraneCommandConfig();
- }
- }
- catch (Exception ex)
- {
- // 閰嶇疆鍔犺浇澶辫触锛屼娇鐢ㄩ粯璁ら厤缃�
- Console.WriteLine($"閰嶇疆鍔犺浇澶辫触: {ex.Message}锛屼娇鐢ㄩ粯璁ら厤缃�");
- }
-
- return new StackerCraneCommandConfig();
- }
-
- /// <summary>
/// Quartz Job 鐨勬墽琛屽叆鍙�
/// </summary>
/// <remarks>
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
index 712dd6c..7e4a4ea 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneTaskSelector.cs
@@ -1,7 +1,6 @@
using Newtonsoft.Json;
using Serilog;
using System.Diagnostics.CodeAnalysis;
-using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEAWCS_Common.Constants;
using WIDESEAWCS_Common.HttpEnum;
@@ -10,7 +9,6 @@
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
-using WIDESEAWCS_QuartzJob.ConveyorLine.Enum;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
@@ -208,7 +206,7 @@
{
// 鍏堣繘琛屾湰鍦扮珯鍙版鏌ワ紙PLC 璇诲彇锛屽揩閫燂級锛岄伩鍏嶄笉蹇呰鐨� WMS HTTP 璋冪敤
- if (outboundTask.TaskType != (int)TaskOutboundTypeEnum.OutEmpty && outboundTask.Roadway != "GWSC1" && outboundTask.TargetAddress != "CWSC1")
+ if (outboundTask.TaskType != (int)TaskOutboundTypeEnum.OutEmpty && outboundTask.TargetAddress != "CWSC1")
{
// 鍒ゆ柇 TargetAddress 杈撻�佺嚎绔欏彴鏄惁绌洪棽
if (!IsTargetAddressConveyorStationAvailable(outboundTask))
@@ -223,18 +221,18 @@
return null;
}
- if (outboundTask.TargetAddress != "CWSC1")
+ //if (outboundTask.TargetAddress != "CWSC1")
+ //{
+ // 妫�鏌ユ槸鍚︽湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟鍘诲線鍚屼竴 TargetAddress
+ if (_taskService.HasExecutingTaskToTarget(outboundTask.Roadway, outboundTask.TargetAddress))
{
- // 妫�鏌ユ槸鍚︽湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟鍘诲線鍚屼竴 TargetAddress
- if (_taskService.HasExecutingTaskToTarget(outboundTask.Roadway, outboundTask.TargetAddress))
- {
- QuartzLogHelper.LogInfo(_logger, "TrySelectOutboundTask锛歍argetAddress: {TargetAddress} 宸叉湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟锛屼换鍔″彿: {TaskNum}",
- $"TrySelectOutboundTask锛歍argetAddress: {outboundTask.TargetAddress} 宸叉湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟", outboundTask.Roadway, outboundTask.TargetAddress, outboundTask.TaskNum);
- return null;
- }
+ QuartzLogHelper.LogInfo(_logger, "TrySelectOutboundTask锛歍argetAddress: {TargetAddress} 宸叉湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟锛屼换鍔″彿: {TaskNum}",
+ $"TrySelectOutboundTask锛歍argetAddress: {outboundTask.TargetAddress} 宸叉湁姝e湪鎵ц鐨勮緭閫佺嚎浠诲姟", outboundTask.Roadway, outboundTask.TargetAddress, outboundTask.TaskNum);
+ return null;
}
+ //}
- if(outboundTask.Roadway != "GWSC1")
+ if (outboundTask.Roadway != "GWSC1")
{
return outboundTask;
}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
index d7aee6d..2a1433c 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_BasicService/LocationInfoService.cs
@@ -159,9 +159,12 @@
&& x.LocationType == locationType)
.CountAsync();
- // 绌洪棽璐т綅涓嶈冻鏈�浣庝繚鐣欐暟閲忔椂杩斿洖null锛岄伩鍏嶅皢宸烽亾鍒嗛厤鑰楀敖
- const int minFreeLocationThreshold = 5;
- if (freeCount < minFreeLocationThreshold) return null;
+ if(roadwayNo != "CWSC1")
+ {
+ // 绌洪棽璐т綅涓嶈冻鏈�浣庝繚鐣欐暟閲忔椂杩斿洖null锛岄伩鍏嶅皢宸烽亾鍒嗛厤鑰楀敖
+ const int minFreeLocationThreshold = 1;
+ if (freeCount < minFreeLocationThreshold) return null;
+ }
// 鏁版嵁搴撶鎺掑簭鍙栫涓�鏉★紙鍙紶杈撳崟琛屾暟鎹級
return await BaseDal.Db.Queryable<Dt_LocationInfo>()
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/OutboundTimeConstants.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/OutboundTimeConstants.cs
index b1e0174..fdd7553 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/OutboundTimeConstants.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/OutboundTimeConstants.cs
@@ -29,16 +29,16 @@
/// <summary>
/// GW_1棣栨斁鍏ュ簱鏃舵晥锛�24灏忔椂锛�
/// </summary>
- public const int OUTBOUND_HOURS_GW1_FIRST = 24;
+ public const double OUTBOUND_HOURS_GW1_FIRST = 24;
/// <summary>
- /// GW_1浜屾斁鍏ュ簱鏃舵晥锛�24灏忔椂锛�
+ /// GW_1浜屾斁鍏ュ簱鏃舵晥锛�5鍒嗛挓锛�
/// </summary>
- public const int OUTBOUND_HOURS_GW1_SECOND = 24;
+ public const double OUTBOUND_HOURS_GW1_SECOND = 0.05;
/// <summary>
- /// CW_1鍑哄簱鏃舵晥锛�12灏忔椂锛�
+ /// CW_1鍑哄簱鏃舵晥锛�3灏忔椂锛�
/// </summary>
- public const int OUTBOUND_HOURS_CW1 = 12;
+ public const double OUTBOUND_HOURS_CW1 = 3;
}
}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/TaskAddressConstants.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/TaskAddressConstants.cs
index 21577e5..ab4ed07 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/TaskAddressConstants.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/Constants/TaskAddressConstants.cs
@@ -13,7 +13,7 @@
/// <summary>
/// 楂樻俯1鍙峰嚭搴撳湴鍧�鍒楄〃锛堣疆璇級
/// </summary>
- public static readonly string[] GW1_ADDRESSES = { "11001" };
+ public static readonly string[] GW1_ADDRESSES = { "11010" };
/// <summary>
/// 楂樻俯2鍙峰嚭搴撳湴鍧�
@@ -28,7 +28,7 @@
/// <summary>
/// 鍒嗗搴撳嚭搴撳湴鍧�
/// </summary>
- public const string GRADING_OUTBOUND_ADDRESS = "2103";
+ public const string GRADING_OUTBOUND_ADDRESS = "2101";
/// <summary>
/// 鍒嗗搴撳嚭搴撳湴鍧�
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs
index f36e945..2d22bbb 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/WCS/TaskService_Inbound.cs
@@ -141,8 +141,10 @@
Creater = StockConstants.SYSTEM_USER,
Details = null,
LocationCode = location.LocationCode,
- LocationId = location.Id
+ LocationId = location.Id,
+ OutboundDate = DateTime.Now
};
+ location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
var updateStockResult = await _stockInfoService.Repository.AddDataAsync(stockInfo);
return await CompleteTaskAsync(task, "鍏ュ簱瀹屾垚");
@@ -167,6 +169,8 @@
stockInfo.StockStatus = StockStatusEmun.鍏ュ簱瀹屾垚.GetHashCode();
+ stockInfo.CreateDate = DateTime.Now;
+
location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
index fc7e7ae..56185d5 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/appsettings.json
@@ -34,7 +34,7 @@
"MainDB": "DB_WIDESEA", //褰撳墠椤圭洰鐨勪富搴擄紝鎵�瀵瑰簲鐨勮繛鎺ュ瓧绗︿覆鐨凟nabled蹇呴』涓簍rue
//杩炴帴瀛楃涓�
//"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
- "ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
+ "ConnectionString": "Data Source=192.168.60.30;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
//"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_ShanMei;User ID=sa;Password=123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
//"ConnectionString": "Data Source=10.30.4.92;Initial Catalog=WMS_TC;User ID=sa;Password=duo123456;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
//鏃MS鏁版嵁搴撹繛鎺�
diff --git a/Code/docs/superpowers/plans/2026-04-29-outbound-task-flow-todo-implementation.md b/Code/docs/superpowers/plans/2026-04-29-outbound-task-flow-todo-implementation.md
new file mode 100644
index 0000000..d3bf360
--- /dev/null
+++ b/Code/docs/superpowers/plans/2026-04-29-outbound-task-flow-todo-implementation.md
@@ -0,0 +1,170 @@
+# OutboundTaskFlowService.MoveToNextStatus TODO 瀹炵幇璁″垝
+
+> **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:** 琛ュ叏 `OutboundTaskFlowService.MoveToNextStatus` 鏂规硶涓殑 TODO锛屽疄鐜板湪鍑哄簱浠诲姟鍒拌揪 `Line_OutFinish` 鐘舵�佹椂妫�鏌ュ鍚戠嚎浣撴墭鐩樺彿锛屾湁鎵樼洏鍙峰垯鏈湴鍒涘缓鏈烘鎵嬩换鍔★紝鏃犳墭鐩樺彿鍒欎粠 WMS 鑾峰彇浠诲姟銆�
+
+**Architecture:** 鍦� `RobotTaskService` 涓柊澧� `CheckSourceLineAndCreateRobotTask` 鏂规硶锛屽鐢ㄥ凡鏈夌殑 `BuildRobotTaskStock` 鑾峰彇婧愮嚎浣撶紪鍙凤紝閫氳繃璁惧閫氫俊璇诲彇绾夸綋鎵樼洏鍙凤紝鏍规嵁缁撴灉鍐冲畾璋冪敤 `CreateLocalRobotTask` 鎴� `GetWMSOutboundTrayTask`銆�
+
+**Tech Stack:** C# / .NET 6, ASP.NET Core, SqlSugar ORM
+
+---
+
+## 娑夊強鏂囦欢
+
+| 鏂囦欢 | 鏀瑰姩 |
+|------|------|
+| `WIDESEAWCS_TaskInfoService/RobotTaskService.cs` | 鏂板 `CheckSourceLineAndCreateRobotTask` 鏂规硶 |
+| `WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs` | 鏇挎崲 TODO 浠g爜娈典负濮旀墭璋冪敤 |
+
+---
+
+## Task 1: 鍦� RobotTaskService 鏂板 CheckSourceLineAndCreateRobotTask 鏂规硶
+
+**Files:**
+- Modify: `WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs:241`锛堝湪 `CreateLocalRobotTask` 鏂规硶涔嬪悗锛�
+
+- [ ] **Step 1: 鍦� `CreateLocalRobotTask` 鏂规硶鍚庢坊鍔犳柊鏂规硶**
+
+鍦� `RobotTaskService.cs` 绗� 240 琛岋紙`CreateLocalRobotTask` 鏂规硶缁撴潫鍚庣殑浣嶇疆锛夋坊鍔犱互涓嬫柟娉曪細
+
+```csharp
+/// <summary>
+/// 妫�鏌ユ簮绾夸綋鏄惁鏈夋墭鐩樺彿锛屽苟鏍规嵁缁撴灉鍒涘缓鏈烘鎵嬩换鍔°��
+/// </summary>
+/// <param name="task">鍑哄簱浠诲姟瀹炰綋</param>
+/// <returns>
+/// 鏈夋墭鐩樺彿鏃惰繑鍥� CreateLocalRobotTask 缁撴灉锛�
+/// 鏃犳墭鐩樺彿鏃惰繑鍥� GetWMSOutboundTrayTask 缁撴灉銆�
+/// </returns>
+public WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task)
+{
+ // 1. 鑾峰彇婧愮嚎浣撶紪鍙凤紙澶嶇敤宸叉湁閫昏緫锛�
+ string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
+ StockDTO stock = BuildRobotTaskStock(task, configKey);
+ string sourceLineNo = stock.SourceLineNo;
+
+ if (string.IsNullOrWhiteSpace(sourceLineNo))
+ {
+ return GetWMSOutboundTrayTask(task);
+ }
+
+ // 2. 閫氳繃璁惧閫氫俊璇诲彇绾夸綋鎵樼洏鍙�
+ string? palletCode = ReadLineBarcode(sourceLineNo);
+
+ if (!string.IsNullOrWhiteSpace(palletCode))
+ {
+ // 鏈夋墭鐩樺彿锛屾湰鍦板垱寤烘満姊版墜浠诲姟
+ return CreateLocalRobotTask(task);
+ }
+
+ // 鏃犳墭鐩樺彿锛屼粠 WMS 鑾峰彇浠诲姟
+ return GetWMSOutboundTrayTask(task);
+}
+
+/// <summary>
+/// 璇诲彇鎸囧畾绾夸綋鐨勬墭鐩樺彿銆�
+/// </summary>
+/// <param name="sourceLineNo">婧愮嚎浣撶紪鍙�</param>
+/// <returns>鎵樼洏鍙凤紝濡傛湁寮傚父杩斿洖 null</returns>
+private string? ReadLineBarcode(string sourceLineNo)
+{
+ try
+ {
+ IDevice? device = Storage.Devices.FirstOrDefault(x =>
+ x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
+
+ if (device == null)
+ return null;
+
+ CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
+ return conveyorLine.GetValue<ConveyorLineDBNameNew, string>(
+ ConveyorLineDBNameNew.Barcode, sourceLineNo);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, $"璇诲彇绾夸綋[{sourceLineNo}]鎵樼洏鍙峰紓甯�");
+ return null;
+ }
+}
+```
+
+- [ ] **Step 2: 楠岃瘉缂栬瘧**
+
+Run: `dotnet build WIDESEAWCS_Server/WIDESEAWCS_Server.sln --no-restore`
+Expected: BUILD SUCCEEDED锛堟棤缂栬瘧閿欒锛�
+
+- [ ] **Step 3: 鎻愪氦**
+
+```bash
+git add WIDESEAWCS_TaskInfoService/RobotTaskService.cs
+git commit -m "feat(鏈烘鎵嬩换鍔�): 鏂板CheckSourceLineAndCreateRobotTask鏂规硶鏀寔妫�鏌ョ嚎浣撴墭鐩樺彿鍐崇瓥
+
+- 鏂板CheckSourceLineAndCreateRobotTask鏂规硶锛屾牴鎹簮绾夸綋鎵樼洏鍙峰喅瀹氬垱寤烘満姊版墜浠诲姟鏂瑰紡
+- 鏂板ReadLineBarcode绉佹湁鏂规硶锛岃鍙栨寚瀹氱嚎浣撶殑鎵樼洏鍙�
+- 鏈夋墭鐩樺彿鏃惰皟鐢–reateLocalRobotTask锛屾棤鎵樼洏鍙锋椂璋冪敤GetWMSOutboundTrayTask
+- 寮傚父鏃堕檷绾т负浠嶹MS鑾峰彇浠诲姟"
+```
+
+---
+
+## Task 2: 淇敼 OutboundTaskFlowService.MoveToNextStatus 璋冪敤鏂版柟娉�
+
+**Files:**
+- Modify: `WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs:107-114`
+
+- [ ] **Step 1: 鏇挎崲 TODO 浠g爜娈�**
+
+灏� `OutboundTaskFlowService.cs` 绗� 107-114 琛岋細
+
+```csharp
+if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
+{
+ return WebResponseContent.Instance.OK();
+
+ // Todo:鑾峰彇瀵瑰悜绾夸綋鏄惁鏈夋墭鐩樺彿锛屽鏋滄湁鎵樼洏鍙风洿鎺ョ敓鎴愭満姊版墜浠诲姟
+
+ return GetWMSOutboundTrayTask(task);
+}
+```
+
+鏇挎崲涓猴細
+
+```csharp
+if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
+{
+ // 鑾峰彇瀵瑰悜绾夸綋鏄惁鏈夋墭鐩樺彿锛屽鏋滄湁鎵樼洏鍙风洿鎺ョ敓鎴愭満姊版墜浠诲姟
+ return _robotTaskService.CheckSourceLineAndCreateRobotTask(task);
+}
+```
+
+- [ ] **Step 2: 楠岃瘉缂栬瘧**
+
+Run: `dotnet build WIDESEAWCS_Server/WIDESEAWCS_Server.sln --no-restore`
+Expected: BUILD SUCCEEDED锛堟棤缂栬瘧閿欒锛�
+
+- [ ] **Step 3: 鎻愪氦**
+
+```bash
+git add WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs
+git commit -m "feat(鍑哄簱浠诲姟): MoveToNextStatus璋冪敤CheckSourceLineAndCreateRobotTask鍐崇瓥鏈烘鎵嬩换鍔″垱寤烘柟寮�
+
+- 鏇挎崲TODO浠g爜娈典负_robotTaskService.CheckSourceLineAndCreateRobotTask璋冪敤
+- 鏈夋墭鐩樺彿鏃舵湰鍦板垱寤烘満姊版墜浠诲姟锛屾棤鎵樼洏鍙锋椂浠嶹MS鑾峰彇"
+```
+
+---
+
+## 楠岃瘉瑕佺偣
+
+1. 褰撹緭閫佺嚎鏈夋枡鏃讹紙瀵瑰悜绾夸綋 Barcode 鏈夊�硷級锛屾満姊版墜浠诲姟鐩存帴鏈湴鍒涘缓锛屼笉璋冪敤 WMS 鎺ュ彛
+2. 褰撹緭閫佺嚎鏃犳枡鏃讹紙瀵瑰悜绾夸綋 Barcode 涓虹┖锛夛紝闄嶇骇璋冪敤 WMS 鑾峰彇绌烘墭鐩樹换鍔�
+3. 寮傚父鍦烘櫙涓嶉樆濉炰富娴佺▼锛岄檷绾у埌 WMS 鑾峰彇
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+- `ReadLineBarcode` 鏂规硶澶嶇敤浜� `BuildRobotTaskStock` 涓鍙� Barcode 鐨勮澶囨煡璇㈤�昏緫锛堣 `RobotTaskService.cs:365-374`锛�
+- 寮傚父澶勭悊杩斿洖 null锛岃Е鍙戦檷绾ч�昏緫璋冪敤 `GetWMSOutboundTrayTask`
+- 璁捐鏂囨。浣嶇疆锛歚docs/superpowers/specs/2026-04-29-outbound-task-flow-todo-design.md`
diff --git a/Code/docs/superpowers/specs/2026-04-29-outbound-task-flow-todo-design.md b/Code/docs/superpowers/specs/2026-04-29-outbound-task-flow-todo-design.md
new file mode 100644
index 0000000..47e84da
--- /dev/null
+++ b/Code/docs/superpowers/specs/2026-04-29-outbound-task-flow-todo-design.md
@@ -0,0 +1,148 @@
+# OutboundTaskFlowService.MoveToNextStatus TODO 璁捐鏂规
+
+## 鑳屾櫙
+
+`OutboundTaskFlowService.MoveToNextStatus` 鏂规硶涓瓨鍦ㄤ竴涓� TODO锛�
+
+```csharp
+if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
+{
+ return WebResponseContent.Instance.OK();
+
+ // Todo:鑾峰彇瀵瑰悜绾夸綋鏄惁鏈夋墭鐩樺彿锛屽鏋滄湁鎵樼洏鍙风洿鎺ョ敓鎴愭満姊版墜浠诲姟
+
+ return GetWMSOutboundTrayTask(task);
+}
+```
+
+璇� TODO 闇�瑕佸湪鍑哄簱浠诲姟鍒拌揪 `Line_OutFinish` 鐘舵�佹椂锛屾鏌ュ鍚戠嚎浣撴槸鍚︽湁鎵樼洏鍙凤紝浠ュ喅瀹氬悗缁満姊版墜浠诲姟鐨勫垱寤烘柟寮忋��
+
+## 涓氬姟閫昏緫
+
+鍑哄簱浠诲姟娴佺▼涓紝褰撶墿鏂欓�氳繃杈撻�佺嚎鍒拌揪鐩爣浣嶇疆鍚庯細
+
+- **瀵瑰悜绾夸綋鏈夋墭鐩樺彿** 鈫� 鎵樼洏涓婃湁璐э紝鐩存帴鍦ㄦ湰鍦板垱寤烘満姊版墜浠诲姟鎵ц鎹㈢洏/缁勭洏/鎷嗙洏
+- **瀵瑰悜绾夸綋鏃犳墭鐩樺彿** 鈫� 闇�瑕佷粠 WMS 鑾峰彇绌烘墭鐩樺嚭搴撲换鍔�
+
+## 鏂规閫夋嫨
+
+**閲囩敤鏂规 B**锛氬湪 `RobotTaskService` 涓皝瑁呮鏌ラ�昏緫锛屽鐢ㄥ凡鏈夌殑 `BuildRobotTaskStock` 鍩虹璁炬柦銆�
+
+### 鍘熷洜
+- `RobotTaskService.BuildRobotTaskStock` 宸插疄鐜伴�氳繃 `AddressSourceLineNoMap` 瑙f瀽婧愮嚎浣撶紪鍙凤紝骞堕�氳繃璁惧閫氫俊璇诲彇 `Barcode` 鐨勫畬鏁撮�昏緫
+- 鏂板鏂规硶鑱岃矗鍗曚竴锛氭鏌� 鈫� 鍐崇瓥锛屼粎鍋氬垽鏂笉鎵ц鍓綔鐢�
+- `OutboundTaskFlowService` 淇濇寔绠�娲侊紝鍙渶璋冪敤鍗冲彲
+
+## 瀹炵幇璁捐
+
+### 1. RobotTaskService 鏂板鏂规硶
+
+```csharp
+/// <summary>
+/// 妫�鏌ユ簮绾夸綋鏄惁鏈夋墭鐩樺彿锛屽苟鏍规嵁缁撴灉鍒涘缓鏈烘鎵嬩换鍔°��
+/// </summary>
+/// <param name="task">鍑哄簱浠诲姟瀹炰綋</param>
+/// <returns>
+/// 鏈夋墭鐩樺彿鏃惰繑鍥� CreateLocalRobotTask 缁撴灉锛�
+/// 鏃犳墭鐩樺彿鏃惰繑鍥� GetWMSOutboundTrayTask 缁撴灉銆�
+/// </returns>
+public WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task)
+{
+ // 1. 鑾峰彇婧愮嚎浣撶紪鍙凤紙澶嶇敤宸叉湁閫昏緫锛�
+ string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
+ StockDTO stock = BuildRobotTaskStock(task, configKey);
+ string sourceLineNo = stock.SourceLineNo;
+
+ if (string.IsNullOrWhiteSpace(sourceLineNo))
+ {
+ return GetWMSOutboundTrayTask(task);
+ }
+
+ // 2. 閫氳繃璁惧閫氫俊璇诲彇绾夸綋鎵樼洏鍙�
+ string? palletCode = ReadLineBarcode(sourceLineNo);
+
+ if (!string.IsNullOrWhiteSpace(palletCode))
+ {
+ // 鏈夋墭鐩樺彿锛屾湰鍦板垱寤烘満姊版墜浠诲姟
+ return CreateLocalRobotTask(task);
+ }
+
+ // 鏃犳墭鐩樺彿锛屼粠 WMS 鑾峰彇浠诲姟
+ return GetWMSOutboundTrayTask(task);
+}
+
+/// <summary>
+/// 璇诲彇鎸囧畾绾夸綋鐨勬墭鐩樺彿銆�
+/// </summary>
+private string? ReadLineBarcode(string sourceLineNo)
+{
+ try
+ {
+ IDevice? device = Storage.Devices.FirstOrDefault(x =>
+ x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
+
+ if (device == null)
+ return null;
+
+ CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
+ return conveyorLine.GetValue<ConveyorLineDBNameNew, string>(
+ ConveyorLineDBNameNew.Barcode, sourceLineNo);
+ }
+ catch
+ {
+ return null;
+ }
+}
+```
+
+### 2. OutboundTaskFlowService 淇敼
+
+```csharp
+if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
+{
+ // 鑾峰彇瀵瑰悜绾夸綋鏄惁鏈夋墭鐩樺彿锛屽鏋滄湁鎵樼洏鍙风洿鎺ョ敓鎴愭満姊版墜浠诲姟
+ return _robotTaskService.CheckSourceLineAndCreateRobotTask(task);
+}
+```
+
+## 鏁版嵁娴�
+
+```
+MoveToNextStatus (OutboundTaskFlowService)
+ 鈹�
+ 鈻�
+CheckSourceLineAndCreateRobotTask (RobotTaskService)
+ 鈹�
+ 鈹溾攢鈹�鈹�鈻� BuildRobotTaskStock 鈹�鈹�鈻� ResolveRobotTaskConfigKey
+ 鈹� 鈹斺攢鈹�鈻� AddressSourceLineNoMap 鑾峰彇 sourceLineNo
+ 鈹�
+ 鈻�
+ReadLineBarcode(sourceLineNo)
+ 鈹�
+ 鈹溾攢鈹�鈹�鈻� Storage.Devices 鏌ユ壘璁惧
+ 鈹斺攢鈹�鈹�鈻� CommonConveyorLine.GetValue(Barcode)
+ 鈹�
+ 鈻�
+ 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鎵樼洏鍙锋湁鍊� 鈹� 鎵樼洏鍙蜂负绌�
+ 鈻� 鈻�
+CreateLocalRobotTask GetWMSOutboundTrayTask
+```
+
+## 閿欒澶勭悊
+
+- 璁惧鏌ユ壘澶辫触鎴栬鍙栧紓甯� 鈫� 闄嶇骇涓鸿皟鐢� `GetWMSOutboundTrayTask`锛堜粠 WMS 鑾峰彇浠诲姟锛�
+- 涓嶉樆濉炰富娴佺▼锛屽紓甯镐粎璁板綍鏃ュ織
+
+## 娑夊強鏂囦欢
+
+| 鏂囦欢 | 鏀瑰姩 |
+|------|------|
+| `WIDESEAWCS_TaskInfoService/RobotTaskService.cs` | 鏂板 `CheckSourceLineAndCreateRobotTask` 鍜� `ReadLineBarcode` 鏂规硶 |
+| `WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs` | 鏇挎崲 TODO 浠g爜娈典负濮旀墭璋冪敤 |
+
+## 楠岃瘉瑕佺偣
+
+1. 褰撹緭閫佺嚎鏈夋枡鏃讹紝鏈烘鎵嬩换鍔$洿鎺ユ湰鍦板垱寤猴紝涓嶈皟鐢� WMS 鎺ュ彛
+2. 褰撹緭閫佺嚎鏃犳枡鏃讹紝闄嶇骇璋冪敤 WMS 鑾峰彇绌烘墭鐩樹换鍔�
+3. 寮傚父鍦烘櫙涓嶉樆濉炰富娴佺▼锛岄檷绾у埌 WMS 鑾峰彇
--
Gitblit v1.9.3