using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Hosting; using Quartz; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection.Metadata; using System.Text; using System.Threading.Tasks; using WIDESEA_Common.Log; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.Enums; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.DeviceBase; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Service; using WIDESEAWCS_QuartzJob.StackerCrane.Enum; using WIDESEAWCS_Tasks.StackerCraneJob; namespace WIDESEAWCS_Tasks { [DisallowConcurrentExecution] public class CommonStackerCraneJob : IJob { private readonly ITaskService _taskService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskRepository _taskRepository; private readonly IRouterService _routerService; public CommonStackerCraneJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService) { _taskService = taskService; _taskExecuteDetailService = taskExecuteDetailService; _taskRepository = taskRepository; _routerService = routerService; } public Task Execute(IJobExecutionContext context) { try { CommonStackerCrane commonStackerCrane = (CommonStackerCrane)context.JobDetail.JobDataMap.Get("JobParams"); if (commonStackerCrane != null) { if (!commonStackerCrane.IsEventSubscribed) { commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler;//订阅任务完成事件 } if (commonStackerCrane.StackerCraneAutoStatusValue == StackerCraneAutoStatus.Automatic && commonStackerCrane.StackerCraneStatusValue == StackerCraneStatus.Normal) { CommonConveyorLine conveyorLine = (CommonConveyorLine)context.JobDetail.JobDataMap.Get("JobParams"); Signalinteraction(conveyorLine, commonStackerCrane); commonStackerCrane.CheckStackerCraneTaskCompleted();//防止任务完成事件监测超时,再手动触发一次 if (commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby) { Dt_Task? task = GetTask(commonStackerCrane); if (task != null) { StackerCraneTaskCommand? 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(nameof(CommonStackerCraneJob) + ":" + ex.ToString()); } return Task.CompletedTask; } /// /// 任务完成事件订阅的方法 /// /// /// private void CommonStackerCrane_StackerCraneTaskCompletedEventHandler(object? sender, WIDESEAWCS_QuartzJob.StackerCrane.StackerCraneTaskCompletedEventArgs e) { CommonStackerCrane? commonStackerCrane = sender as CommonStackerCrane; if (commonStackerCrane != null) { if (commonStackerCrane.GetValue(StackerCraneDBName.WorkType) != 5) { Console.Out.WriteLine("TaskCompleted" + e.TaskNum); _taskService.StackCraneTaskCompleted(e.TaskNum); commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5); } } } /// /// 获取任务 /// /// 堆垛机对象 /// private Dt_Task? GetTask(CommonStackerCrane commonStackerCrane) { Dt_Task task; if (commonStackerCrane.LastTaskType == null) { task = _taskService.QueryStackerCraneTask(commonStackerCrane.DeviceCode); } else { if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); if (task == null) { task = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); } } else { task = _taskService.QueryStackerCraneOutTask(commonStackerCrane.DeviceCode); } } if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { string[] targetCodes = task.SourceAddress.Split("-"); if (targetCodes[4] == "02") { task = OutTaskMovelibrary(task); if (task != null) { return task; } } if (OutTaskStationIsOccupied(task) != null) { return task; } else { List otherOutStaionCodes = _routerService.QueryNextRoutes(commonStackerCrane.DeviceCode, task.NextAddress).Select(x => x.ChildPosi).ToList(); List tasks = _taskService.QueryStackerCraneOutTasks(commonStackerCrane.DeviceCode, otherOutStaionCodes); foreach (var item in tasks) { if (OutTaskStationIsOccupied(task) != null) { return task; } } task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); } } return task; } /// /// 出库任务判断出库站台是否被占用 /// /// 任务实体 /// 如果未被占用,返回传入的任务信息,否则,返回null private Dt_Task? OutTaskStationIsOccupied([NotNull] Dt_Task task) { IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == "1002"); if (device != null) { CommonConveyorLine conveyorLine = (CommonConveyorLine)device; if (conveyorLine.IsOccupied(task.TargetAddress))//出库站台未被占用 { return task; } } else { _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{task.TargetAddress}】对应的通讯对象,无法判断出库站台是否被占用"); } return null; } /// /// 出库任务判断是否需要进行移库Move the library /// /// 任务实体 /// 如果未被占用,返回传入的任务信息,否则,返回null private Dt_Task? OutTaskMovelibrary([NotNull] Dt_Task task) { try { string[] targetCodes = task.SourceAddress.Split("-"); if (targetCodes[1] == "001") { targetCodes[1] = "002"; } else if (targetCodes[1] == "004") { targetCodes[1] = "003"; } targetCodes[4] = "01"; string SourceAddress = string.Join("-", targetCodes); //组装浅库位地址 Dt_Task? tasks = _taskService.QueryStationIsOccupiedOutTasks(task.Roadway, SourceAddress).FirstOrDefault(); if (tasks != null) { return task; } else { //向wms申请判断浅库位是否有货,是否需要进行移库 Dt_Task? taskst = _taskService.RequestWMSTaskMovelibrary(task); if (taskst != null) { return taskst; } } } catch (Exception ex) { throw; } return null; } public void Signalinteraction(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane) { //入库信号交互 int B_Event = conveyorLine.Communicator.Read("PLC_WCS_B.01_EVENT"); int B_Event2 = conveyorLine.Communicator.Read("PLC_WCS_C.03_EVENT"); if (B_Event == 1 || B_Event2 == 1) { Stackerstatic(conveyorLine,commonStackerCrane); } //出库信号交互 //Stackerstatic2(conveyorLine, commonStackerCrane); } /// /// 任务实体转换成命令Model /// /// 任务实体 /// /// public StackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) { StackerCraneTaskCommand stackerCraneTaskCommand = new StackerCraneTaskCommand(); stackerCraneTaskCommand.Barcode = task.PalletCode; stackerCraneTaskCommand.TaskNum = task.TaskNum; stackerCraneTaskCommand.WorkType = 1; stackerCraneTaskCommand.TrayType = 0; if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)//判断是否是入库任务 { string[] targetCodest = task.SourceAddress.Split("-"); if (targetCodest.Length == 5) { stackerCraneTaskCommand.EndRow = Convert.ToInt16(targetCodest[1]); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(targetCodest[2]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(targetCodest[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库起点错误,起点:【{task.SourceAddress}】"); return null; } string[] targetCodes = task.NextAddress.Split("-"); if (targetCodes.Length == 5) { stackerCraneTaskCommand.EndRow = Convert.ToInt16(targetCodes[1]); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(targetCodes[2]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(targetCodes[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库任务终点错误,起点:【{task.NextAddress}】"); return null; } } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { string[] sourceCodes = task.CurrentAddress.Split("-"); if (sourceCodes.Length == 5) { stackerCraneTaskCommand.StartRow = Convert.ToInt16(sourceCodes[1]); stackerCraneTaskCommand.StartColumn = Convert.ToInt16(sourceCodes[2]); stackerCraneTaskCommand.StartLayer = Convert.ToInt16(sourceCodes[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务起点错误,起点:【{task.CurrentAddress}】"); return null; } string[] sourceCodest = task.TargetAddress.Split("-"); if (sourceCodest.Length == 5) { stackerCraneTaskCommand.EndRow = Convert.ToInt16(sourceCodest[1]); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(sourceCodest[2]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(sourceCodest[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务终点错误,起点:【{task.TargetAddress}】"); return null; } } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup) { string[] targetCodes = task.NextAddress.Split("-"); if (targetCodes.Length == 5) { stackerCraneTaskCommand.EndRow = Convert.ToInt16(targetCodes[1]); stackerCraneTaskCommand.EndColumn = Convert.ToInt16(targetCodes[2]); stackerCraneTaskCommand.EndLayer = Convert.ToInt16(targetCodes[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库任务终点错误,起点:【{task.NextAddress}】"); return null; } string[] sourceCodes = task.CurrentAddress.Split("-"); if (sourceCodes.Length == 5) { stackerCraneTaskCommand.StartRow = Convert.ToInt16(sourceCodes[1]); stackerCraneTaskCommand.StartColumn = Convert.ToInt16(sourceCodes[2]); stackerCraneTaskCommand.StartLayer = Convert.ToInt16(sourceCodes[3]); } else { //数据配置错误 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库任务起点错误,起点:【{task.CurrentAddress}】"); return null; } } return stackerCraneTaskCommand; } /// /// 根据站台名称写入 /// /// /// public void Stackerstatic(CommonConveyorLine conveyorLine,CommonStackerCrane commonStackerCrane) { // 调用方法处理不同 SourceAddress 的任务 Dt_Task task = _taskService.IngStackerCraneTask(commonStackerCrane.DeviceName); if (task.SourceAddress == "R01-003-027-001-01") { HandleStackerCraneTask(conveyorLine,commonStackerCrane,task, StackerCraneDBName.Requestpickup.ToString(), StackerCraneDBName.toRequestpickup.ToString(), "WCS_PLC_B.01_WCS_TAKE"); } else if (task.SourceAddress == "R01-003-041-001-01") { HandleStackerCraneTask(conveyorLine, commonStackerCrane,task, StackerCraneDBName.Requestpickuptwo.ToString(), StackerCraneDBName.toRequestpickuptwo.ToString(), "WCS_PLC_C.03_WCS_TAKE"); } } /// /// 出库信息交互 /// /// /// public void Stackerstatic2(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane) { //读取堆垛机两个站台是否有放货申请 // 检查堆垛机是否请求放货信号 if (commonStackerCrane.GetValue(StackerCraneDBName.Requestpickupout)) { LogSignalStatus("读取到堆垛机申请放货信号", "R01-002-027-001-01"); Dt_Task? task = _taskService.IngStackerCraneTask(commonStackerCrane.DeviceName); WriteLogAndHandleConveyorSignal(conveyorLine, commonStackerCrane, task, StackerCraneDBName.toRequestpickupout, "R01-002-027-001-01"); } // 判断不同的站台 /*if (task.SourceAddress == "R01-002-027-001-01") { HandleStackerCraneForAddress027001(conveyorLine, commonStackerCrane, task); } else if (task.SourceAddress == "R01-002-041-001-01") { HandleStackerCraneForAddress041001(conveyorLine, commonStackerCrane, task); }*/ } // 封装入库站台 // 定义一个方法来处理重复的堆垛机与PLC交互操作 private void HandleStackerCraneTask(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane,Dt_Task task, string requestSignal, string completionSignal, string writeAddress) { // 将 completionSignal 转换为 StackerCraneDBName 枚举值 if (Enum.TryParse(completionSignal, out StackerCraneDBName completionEnum)) { // 获取堆垛机完成信号 if (commonStackerCrane.GetValue(completionEnum)) { WriteLog.GetLog("堆垛机与plc交互信号").Write($"读取到堆垛机完成信号为 true,站台编号:{task.SourceAddress}", "站台信息"); // 向输送线写入取货完成信号 if (conveyorLine.Communicator.Write(writeAddress, 1)) { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入输送线取货完成信号成功,1,站台编号:{task.SourceAddress}", "站台信息"); } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入输送线取货完成信号失败,站台编号:{task.SourceAddress}", "站台信息"); } } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"读取到堆垛机完成信号为 false,站台编号:{task.SourceAddress}", "站台信息"); } } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"无法将completionSignal字符串{completionSignal}转换为有效的枚举值", "站台信息"); } if(Enum.TryParse(requestSignal, out StackerCraneDBName completionEnum2)){ // 写入请求信号 if (commonStackerCrane.SetValue(completionEnum2, true)) { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入信号成功,{requestSignal}", "站台信息"); } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入信号失败,{requestSignal}", "站台信息"); } } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"无法将completionSignal字符串{completionSignal}转换为有效的枚举值", "站台信息"); } } private void HandleStackerCraneForAddress027001(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane, Dt_Task task) { // 检查堆垛机是否请求放货信号 if (commonStackerCrane.GetValue(StackerCraneDBName.Requestpickupout)) { WriteLogAndHandleConveyorSignal(conveyorLine, commonStackerCrane, task, StackerCraneDBName.toRequestpickupout, "R01-002-027-001-01"); } else { LogSignalStatus("未读取到堆垛机申请放货信号", task.SourceAddress); } // 检查堆垛机完成信号 if (commonStackerCrane.GetValue(StackerCraneDBName.toRequestpickup)) { WriteLogAndHandleConveyorSignal(conveyorLine, commonStackerCrane, task, StackerCraneDBName.toRequestpickup, "R01-002-027-001-01"); } else { LogSignalStatus("读取到堆垛机完成信号为,false", task.SourceAddress); } } private void HandleStackerCraneForAddress041001(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane, Dt_Task task) { if (commonStackerCrane.SetValue(StackerCraneDBName.Requestpickuptwo, true)) { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入信号成功,Requestpickup", "站台信息"); } else { WriteLog.GetLog("堆垛机与plc交互信号").Write($"写入信号失败,Requestpickup", "站台信息"); } // 检查堆垛机完成信号 if (commonStackerCrane.GetValue(StackerCraneDBName.toRequestpickuptwo)) { WriteLogAndHandleConveyorSignal(conveyorLine, commonStackerCrane, task, StackerCraneDBName.toRequestpickuptwo, "R01-002-041-001-01"); } else { LogSignalStatus("读取到堆垛机完成信号为,false", task.SourceAddress); } } private void WriteLogAndHandleConveyorSignal(CommonConveyorLine conveyorLine, CommonStackerCrane commonStackerCrane, Dt_Task task, StackerCraneDBName signalType, string sourceAddress) { // 读取输送线信号 int events = conveyorLine.Communicator.Read("PLC_WCS_B.01_EVENT"); if (events == 0) { LogSignalStatus("读取到输送线允许放货信号", sourceAddress); // 写入堆垛机信号 if (commonStackerCrane.SetValue(signalType, true)) { LogSignalStatus($"写入堆垛机允许放货信号", sourceAddress); } else { LogSignalStatus($"未写入堆垛机允许放货信号", sourceAddress); } } else { LogSignalStatus($"未读取到输送线允许放货信号", sourceAddress); } // 写入取货完成信号 if (conveyorLine.Communicator.Write("WCS_PLC_B.01_WCS_TAKE", 1)) { LogSignalStatus($"写入输送线取货完成信号成功", sourceAddress); } else { LogSignalStatus($"写入输送线取货完成信号失败", sourceAddress); } } private void LogSignalStatus(string message, string sourceAddress) { WriteLog.GetLog("堆垛机与plc交互信号").Write($"{message},站台编号:{sourceAddress}", "站台信息"); } } }