| | |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.ConveyorLine.Enum; |
| | | using WIDESEAWCS_QuartzJob.Models; |
| | | using WIDESEAWCS_QuartzJob.Service; |
| | | |
| | |
| | | /// <param name="httpClientHelper">HTTP 客户端帮助类</param> |
| | | /// <param name="logger">日志记录器</param> |
| | | public StackerCraneTaskSelector(ITaskService taskService, IRouterService routerService, HttpClientHelper httpClientHelper, ILogger logger) |
| | | : this(taskService, routerService, taskNum => QueryTransferTask(httpClientHelper, taskNum), logger) |
| | | : this(taskService, routerService, taskNum => QueryTransferTask(httpClientHelper, taskNum, logger), logger) |
| | | { |
| | | } |
| | | |
| | |
| | | return selectedTask; |
| | | } |
| | | |
| | | // ===== TargetAddress 不可用时,先尝试同 NextAddress 的其他任务 ===== |
| | | var sameStationTasks = _taskService |
| | | .QueryStackerCraneOutTasks(deviceCode, new List<string> { candidateTask.NextAddress }) |
| | | .Where(x => x.TaskId != candidateTask.TaskId) |
| | | .ToList(); |
| | | |
| | | foreach (var sameStationTask in sameStationTasks) |
| | | { |
| | | selectedTask = TrySelectOutboundTask(sameStationTask); |
| | | if (selectedTask != null) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"选中同站台备选出库任务,任务号: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | return selectedTask; |
| | | } |
| | | } |
| | | |
| | | // ===== 同 NextAddress 无可用任务,尝试不同 NextAddress 的任务 ===== |
| | | // 查找其他可用的出库站台 |
| | | var otherOutStationCodes = _routerService |
| | | .QueryNextRoutes(deviceCode, candidateTask.NextAddress, candidateTask.TaskType) |
| | |
| | | /// <returns>可选中的任务,或 null(站台不可用)</returns> |
| | | private Dt_Task? TrySelectOutboundTask(Dt_Task outboundTask) |
| | | { |
| | | // 对于所有出库任务,必须先调用 WMS 判断是否需要移库 |
| | | // 先进行本地站台检查(PLC 读取,快速),避免不必要的 WMS HTTP 调用 |
| | | |
| | | // 判断 TargetAddress 输送线站台是否空闲 |
| | | if (!IsTargetAddressConveyorStationAvailable(outboundTask)) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | // 判断 NextAddress 出库站台是否可用 |
| | | if (!IsOutTaskStationAvailable(outboundTask)) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | // 站台检查通过后,调用 WMS 判断是否需要移库 |
| | | var taskAfterTransferCheck = _transferCheck(outboundTask.TaskNum) ?? outboundTask; |
| | | var taskGroup = taskAfterTransferCheck.TaskType.GetTaskTypeGroup(); |
| | | |
| | |
| | | return taskAfterTransferCheck; |
| | | } |
| | | |
| | | // 判断出库站台是否可用 |
| | | return IsOutTaskStationAvailable(taskAfterTransferCheck) ? taskAfterTransferCheck : null; |
| | | return taskAfterTransferCheck; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | /// <param name="httpClientHelper">HTTP 客户端帮助类</param> |
| | | /// <param name="taskNum">任务号</param> |
| | | /// <returns>如果需要移库返回移库任务,否则返回 null</returns> |
| | | private static Dt_Task? QueryTransferTask(HttpClientHelper httpClientHelper, int taskNum) |
| | | private static Dt_Task? QueryTransferTask(HttpClientHelper httpClientHelper, int taskNum, ILogger logger) |
| | | { |
| | | // 调用 WMS 的移库检查接口 |
| | | string configKey = nameof(ConfigKey.TransferCheck); |
| | | string requestParam = taskNum.ToString(); |
| | | |
| | | var response = httpClientHelper.Post<WebResponseContent>( |
| | | nameof(ConfigKey.TransferCheck), |
| | | taskNum.ToString()); |
| | | configKey, |
| | | requestParam); |
| | | |
| | | // 检查响应是否成功 |
| | | if (response == null || !response.IsSuccess || response.Data == null || !response.Data.Status || response.Data.Data == null) |
| | | { |
| | | QuartzLogHelper.LogError(logger, $"调用WMS接口失败,接口:【{configKey}】,请求参数:【{requestParam}】,错误信息:【{(response?.Data?.Message ?? "无响应")}】", "StackerCraneTaskSelector"); |
| | | return null; |
| | | } |
| | | |
| | | QuartzLogHelper.LogInfo(logger, $"调用WMS接口成功,接口:【{configKey}】,响应数据:【{response.Data.Data}】", "StackerCraneTaskSelector"); |
| | | |
| | | // 解析返回的任务数据 |
| | | var taskJson = response.Data.Data.ToString(); |
| | |
| | | |
| | | return isOccupied; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 判断 TargetAddress 输送线站台是否空闲 |
| | | /// </summary> |
| | | /// <param name="task">出库任务</param> |
| | | /// <returns>站台空闲(CV_State == 2)返回 true</returns> |
| | | private bool IsTargetAddressConveyorStationAvailable([NotNull] Dt_Task task) |
| | | { |
| | | // 确定任务类型 |
| | | int taskType = task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty |
| | | ? StackerCraneConst.EmptyPalletTaskType |
| | | : task.TaskType; |
| | | |
| | | // 通过路由查找 TargetAddress 对应的设备信息 |
| | | Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.TargetAddress, taskType); |
| | | if (router == null) |
| | | { |
| | | QuartzLogHelper.LogWarn(_logger, "IsTargetAddressConveyorStationAvailable:未找到 TargetAddress 路由信息,TargetAddress: {TargetAddress},任务号: {TaskNum}", |
| | | $"IsTargetAddressConveyorStationAvailable:未找到 TargetAddress 路由信息,TargetAddress: {task.TargetAddress}", task.Roadway, task.TargetAddress, task.TaskNum); |
| | | return false; |
| | | } |
| | | |
| | | // 查找输送线设备 |
| | | IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == router.ChildPosiDeviceCode); |
| | | if (device == null) |
| | | { |
| | | QuartzLogHelper.LogWarn(_logger, "IsTargetAddressConveyorStationAvailable:未找到输送线设备,ChildPosiDeviceCode: {ChildPosiDeviceCode},任务号: {TaskNum}", |
| | | $"IsTargetAddressConveyorStationAvailable:未找到输送线设备,ChildPosiDeviceCode: {router.ChildPosiDeviceCode}", task.Roadway, router.ChildPosiDeviceCode, task.TaskNum); |
| | | return false; |
| | | } |
| | | |
| | | // 转换为输送线设备 |
| | | CommonConveyorLine conveyorLine = (CommonConveyorLine)device; |
| | | |
| | | // 读取 CV_State,CV_State == 2 表示空闲 |
| | | byte cvState = conveyorLine.GetValue<ConveyorLineStatus, byte>(ConveyorLineStatus.CV_State, task.TargetAddress); |
| | | bool isAvailable = cvState == 2; |
| | | QuartzLogHelper.LogInfo(_logger, "IsTargetAddressConveyorStationAvailable:TargetAddress: {TargetAddress},CV_State: {CV_State},是否空闲: {IsAvailable},任务号: {TaskNum}", |
| | | $"IsTargetAddressConveyorStationAvailable:TargetAddress: {task.TargetAddress},CV_State: {cvState},是否空闲: {isAvailable}", task.Roadway, task.TargetAddress, cvState, isAvailable, task.TaskNum); |
| | | |
| | | return isAvailable; |
| | | } |
| | | } |
| | | } |