diff --git a/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs b/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs new file mode 100644 index 0000000..2a0e0bb --- /dev/null +++ b/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs @@ -0,0 +1,13 @@ +namespace Sln.Wcs.Strategy; + +/// +/// 任务执行策略接口 - 从任务队列中取出待执行任务,根据设备类型下发到对应 SDK +/// +public interface ITaskExecuteStrategy +{ + /// + /// 执行一轮任务调度:查询待执行任务,按设备类型下发 + /// + /// 本次下发的任务数量 + Task ExecuteAsync(); +} diff --git a/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj b/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj index 3a63532..428753c 100644 --- a/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj +++ b/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -6,4 +6,11 @@ enable + + + + + + + diff --git a/Sln.Wcs.Strategy/TaskExecuteStrategy.cs b/Sln.Wcs.Strategy/TaskExecuteStrategy.cs new file mode 100644 index 0000000..61f559f --- /dev/null +++ b/Sln.Wcs.Strategy/TaskExecuteStrategy.cs @@ -0,0 +1,169 @@ +using Sln.Wcs.HikRoBotSdk; +using Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask; +using Sln.Wcs.HoistSdk; +using Sln.Wcs.HoistSdk.Dto.HoistTaskExecutor; +using Sln.Wcs.Model.Domain; +using Sln.Wcs.Repository.service; + +namespace Sln.Wcs.Strategy; + +/// +/// 任务执行策略 - 轮询数据库中待执行的任务,根据设备类型调用对应 SDK 下发 +/// +public class TaskExecuteStrategy : ITaskExecuteStrategy +{ + private readonly ILiveTaskQueueService _taskQueueService; + private readonly ILiveTaskDetailService _taskDetailService; + private readonly IHIKRoBotSdk _hikRobotSdk; + private readonly IHoistSdk _hoistSdk; + + public TaskExecuteStrategy( + ILiveTaskQueueService taskQueueService, + ILiveTaskDetailService taskDetailService, + IHIKRoBotSdk hikRobotSdk, + IHoistSdk hoistSdk) + { + _taskQueueService = taskQueueService; + _taskDetailService = taskDetailService; + _hikRobotSdk = hikRobotSdk; + _hoistSdk = hoistSdk; + } + + /// + /// 执行一轮任务调度:查询所有待执行任务,按设备类型下发 + /// + public Task ExecuteAsync() + { + return Task.Run(() => + { + // 1. 查询所有待执行的任务队列(task_status = 1) + var pendingTasks = _taskQueueService.Query(x => x.taskStatus == 1); + + if (pendingTasks.Count == 0) + return 0; + + int dispatchedCount = 0; + + foreach (var task in pendingTasks) + { + try + { + // 2. 查询任务明细 + var details = _taskDetailService.Query(x => x.taskCode == task.taskCode); + + if (details.Count == 0) + continue; + + // 3. 取第一个未执行的明细步骤 + var currentDetail = details + .Where(x => x.taskStatus == 1) + .OrderBy(x => x.objId) + .FirstOrDefault(); + + if (currentDetail == null) + continue; + + // 4. 根据设备类型下发任务 + var success = DispatchByDeviceType(currentDetail); + + if (success) + { + // 5. 更新明细状态为执行中 + currentDetail.taskStatus = 2; + _taskDetailService.Update(currentDetail); + + // 6. 更新队列状态为执行中 + task.taskStatus = 2; + _taskQueueService.Update(task); + + dispatchedCount++; + } + } + catch (Exception ex) + { + Console.WriteLine($"任务 {task.taskCode} 下发失败: {ex.Message}"); + } + } + + return dispatchedCount; + }); + } + + /// + /// 根据设备类型分发到对应 SDK + /// + private bool DispatchByDeviceType(LiveTaskDetail detail) + { + return detail.deviceType switch + { + 1 => DispatchToAgv(detail), + 2 => DispatchToHoist(detail), + _ => throw new NotSupportedException($"不支持的设备类型: {detail.deviceType}") + }; + } + + /// + /// 下发 AGV 任务(海康机器人 SDK) + /// + private bool DispatchToAgv(LiveTaskDetail detail) + { + var dto = new GenAgvSchedulingTaskDto + { + reqCode = detail.taskCode, + reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + clientCode = "WCS", + taskCode = detail.taskCode, + taskTyp = detail.taskType switch + { + 1 => "1", // 入库 + 2 => "2", // 出库 + _ => "0" + }, + taskMode = detail.taskType switch + { + 1 => "2", // 入库 move + 2 => "1", // 出库 move + _ => "0" + }, + wbCode = detail.startPoint, + ctnrCode = detail.palletBarcode, + materialLot = detail.materialBarcode, + positionCodePath = new List + { + new() { positionCode = detail.startPoint, type = "00" }, + new() { positionCode = detail.endPoint, type = "00" } + } + }; + + var result = _hikRobotSdk.GenAgvSchedulingTask(dto); + return result.code == "0"; + } + + /// + /// 下发提升机任务(Hoist SDK) + /// + private bool DispatchToHoist(LiveTaskDetail detail) + { + var dto = new HoistTaskExeDto + { + hoistCode = detail.startPoint, + taskCode = detail.taskCode, + startPoint = ParseIntPoint(detail.startPoint), + endPoint = ParseIntPoint(detail.endPoint) + }; + + var result = _hoistSdk.HoistTaskExecutor(dto); + return result.code == "0"; + } + + /// + /// 将位置字符串转为整数楼层/层号 + /// + private static int ParseIntPoint(string? point) + { + if (string.IsNullOrEmpty(point)) + return 0; + + return int.TryParse(point, out var val) ? val : 0; + } +}