using Quartz; using System.Diagnostics.CodeAnalysis; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Service; using WIDESEAWCS_QuartzJob.StackerCrane.Enum; using WIDESEAWCS_Tasks.StackerCraneJob; namespace WIDESEAWCS_Tasks { [DisallowConcurrentExecution] public class FormationCommonStackerCraneJob : IJob { private readonly ITaskService _taskService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskRepository _taskRepository; private readonly IRouterService _routerService; public FormationCommonStackerCraneJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService) { _taskService = taskService; _taskExecuteDetailService = taskExecuteDetailService; _taskRepository = taskRepository; _routerService = routerService; } public Task Execute(IJobExecutionContext context) { try { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " FormationCommonStackerCraneJob Start"); bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value); if (!flag || value is not SpeFormationStackerCrane commonStackerCrane) { return Task.CompletedTask; } if (!commonStackerCrane.IsEventSubscribed) { commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler; } if (commonStackerCrane.StackerCraneStatusValue != FormationStackerCraneRunStatus.Standby) { return Task.CompletedTask; } commonStackerCrane.CheckStackerCraneTaskCompleted(); if (commonStackerCrane.StackerCraneWorkStatusValue == FormationStackerCraneOperationStatus.Idle) { Dt_Task? task = GetTask(commonStackerCrane); if (task != null) { FormationStackerCraneTaskCommand? stackerCraneTaskCommand = ConvertToStackerCraneTaskCommand(task); if (stackerCraneTaskCommand != null) { bool sendFlag = commonStackerCrane.SendCommand(stackerCraneTaskCommand); if (sendFlag) { commonStackerCrane.LastTaskType = task.TaskType; _taskService.UpdateTaskStatusToNext(task.TaskNum); } } } } } catch (Exception ex) { Console.WriteLine($"FormationCommonStackerCraneJob Error: {ex.Message}"); } return Task.CompletedTask; } /// /// 任务完成事件订阅的方法 /// /// /// private void CommonStackerCrane_StackerCraneTaskCompletedEventHandler(object? sender, WIDESEAWCS_QuartzJob.StackerCrane.StackerCraneTaskCompletedEventArgs e) { SpeFormationStackerCrane? commonStackerCrane = sender as SpeFormationStackerCrane; if (commonStackerCrane != null) { if (commonStackerCrane.GetValue(FormationStackerCraneDBName.WorkType) != 7) { Console.Out.WriteLine("TaskCompleted" + e.TaskNum); _taskService.StackCraneTaskCompleted(e.TaskNum); commonStackerCrane.SetValue(FormationStackerCraneDBName.WorkType, 4); } } } /// /// 获取任务 /// /// 堆垛机对象 /// private Dt_Task? GetTask(SpeFormationStackerCrane commonStackerCrane) { Dt_Task? task = null; if (commonStackerCrane.LastTaskType == null) { task = _taskService.QueryStackerCraneTask(commonStackerCrane.DeviceCode); } else { if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); task ??= _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); } else { task = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); } } if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { if (IsOutTaskStationAvailable(task)) { return task; } List otherOutStationCodes = _routerService.QueryNextRoutes(commonStackerCrane.DeviceCode, task.NextAddress, task.TaskType) .Select(x => x.ChildPosi).ToList(); List tasks = _taskService.QueryStackerCraneOutTasks(commonStackerCrane.DeviceCode, otherOutStationCodes); foreach (var alternativeTask in tasks) { if (IsOutTaskStationAvailable(alternativeTask)) { return alternativeTask; } } task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); } return task; } /// /// 检查出库任务的出库站台是否可用 /// /// 任务实体 /// 如果站台可用返回true,否则返回false private bool IsOutTaskStationAvailable([NotNull] Dt_Task task) { Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.NextAddress, task.TaskType); if (router == null) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到站台【{task.NextAddress}】信息,无法校验站台"); return false; } IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == router.ChildPosiDeviceCode); if (device == null) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{router.ChildPosiDeviceCode}】对应的通讯对象,无法判断出库站台是否被占用"); return false; } CommonConveyorLine conveyorLine = (CommonConveyorLine)device; return conveyorLine.IsOccupied(router.ChildPosi); } /// /// 任务实体转换成命令Model /// /// 任务实体 /// public FormationStackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) { FormationStackerCraneTaskCommand stackerCraneTaskCommand = new FormationStackerCraneTaskCommand { Barcode = task.PalletCode, TaskNum = task.TaskNum, WorkType = 4, WorkAction = 1, FireAlarm = 0, FieldName = "" }; TaskTypeGroup taskTypeGroup = task.TaskType.GetTaskTypeGroup(); return taskTypeGroup switch { TaskTypeGroup.InboundGroup => BuildInboundCommand(task, stackerCraneTaskCommand), TaskTypeGroup.OutbondGroup => BuildOutboundCommand(task, stackerCraneTaskCommand), TaskTypeGroup.RelocationGroup => BuildRelocationCommand(task, stackerCraneTaskCommand), _ => stackerCraneTaskCommand }; } /// /// 构建入库命令 /// private FormationStackerCraneTaskCommand? BuildInboundCommand(Dt_Task task, FormationStackerCraneTaskCommand command) { Dt_Router? router = _routerService.QueryNextRoute(task.CurrentAddress, task.Roadway, task.TaskType); if (router == null) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到站台【{task.CurrentAddress}】信息,无法获取对应的堆垛机取货站台信息"); return null; } command.StartRow = Convert.ToInt16(router.SrmRow); command.StartColumn = Convert.ToInt16(router.SrmColumn); command.StartLayer = Convert.ToInt16(router.SrmLayer); if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer)) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库任务终点错误,终点:【{task.NextAddress}】"); return null; } command.EndRow = endRow; command.EndColumn = endColumn; command.EndLayer = endLayer; return command; } /// /// 构建出库命令 /// private FormationStackerCraneTaskCommand? BuildOutboundCommand(Dt_Task task, FormationStackerCraneTaskCommand command) { Dt_Router? router = _routerService.QueryNextRoute(task.Roadway, task.TargetAddress, task.TaskType); if (router == null) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到站台【{task.TargetAddress}】信息,无法获取对应的堆垛机放货站台信息"); return null; } command.EndRow = Convert.ToInt16(router.SrmRow); command.EndColumn = Convert.ToInt16(router.SrmColumn); command.EndLayer = Convert.ToInt16(router.SrmLayer); if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer)) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务起点错误,起点:【{task.CurrentAddress}】"); return null; } command.StartRow = startRow; command.StartColumn = startColumn; command.StartLayer = startLayer; return command; } /// /// 构建移库命令 /// private FormationStackerCraneTaskCommand? BuildRelocationCommand(Dt_Task task, FormationStackerCraneTaskCommand command) { if (!TryParseAddress(task.NextAddress, out short endRow, out short endColumn, out short endLayer)) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库任务终点错误,终点:【{task.NextAddress}】"); return null; } command.EndRow = endRow; command.EndColumn = endColumn; command.EndLayer = endLayer; if (!TryParseAddress(task.CurrentAddress, out short startRow, out short startColumn, out short startLayer)) { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库任务起点错误,起点:【{task.CurrentAddress}】"); return null; } command.StartRow = startRow; command.StartColumn = startColumn; command.StartLayer = startLayer; return command; } /// /// 解析地址字符串(格式:行-列-层) /// private bool TryParseAddress(string address, out short row, out short column, out short layer) { row = column = layer = 0; string[] parts = address.Split("-"); if (parts.Length != 3) { return false; } return short.TryParse(parts[0], out row) && short.TryParse(parts[1], out column) && short.TryParse(parts[2], out layer); } } }