|
|
|
|
@ -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;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务执行策略 - 轮询数据库中待执行的任务,根据设备类型调用对应 SDK 下发
|
|
|
|
|
/// </summary>
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 执行一轮任务调度:查询所有待执行任务,按设备类型下发
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Task<int> 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;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据设备类型分发到对应 SDK
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool DispatchByDeviceType(LiveTaskDetail detail)
|
|
|
|
|
{
|
|
|
|
|
return detail.deviceType switch
|
|
|
|
|
{
|
|
|
|
|
1 => DispatchToAgv(detail),
|
|
|
|
|
2 => DispatchToHoist(detail),
|
|
|
|
|
_ => throw new NotSupportedException($"不支持的设备类型: {detail.deviceType}")
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 下发 AGV 任务(海康机器人 SDK)
|
|
|
|
|
/// </summary>
|
|
|
|
|
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<Position>
|
|
|
|
|
{
|
|
|
|
|
new() { positionCode = detail.startPoint, type = "00" },
|
|
|
|
|
new() { positionCode = detail.endPoint, type = "00" }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var result = _hikRobotSdk.GenAgvSchedulingTask(dto);
|
|
|
|
|
return result.code == "0";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 下发提升机任务(Hoist SDK)
|
|
|
|
|
/// </summary>
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 将位置字符串转为整数楼层/层号
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static int ParseIntPoint(string? point)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(point))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return int.TryParse(point, out var val) ? val : 0;
|
|
|
|
|
}
|
|
|
|
|
}
|