using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HslCommunication.WebSocket; using Quartz; using WIDESEAWCS_Common; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_IBasicInfoRepository; using WIDESEAWCS_IBasicInfoService; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.DTO; namespace WIDESEAWCS_Tasks { /// /// 龙门架任务处理类,继承自JobBase并实现IJob接口
/// 特性[DisallowConcurrentExecution]表示禁止并发执行 ///
/// /// 主要功能:
/// 1. 检查龙门吊状态(自动状态/工作状态)
/// 2. 处理取货/放货任务:
/// - 验证位置坐标格式
/// - 获取板材尺寸信息
/// - 校验工位和容器信息
/// - 计算并校验坐标范围
/// - 更新PLC控制参数
/// 3. 处理任务完成状态:
/// - 更新任务状态
/// - 通知MES系统
/// - 重置工位状态
/// 4. 错误处理:记录各种校验失败的异常情况
/// 依赖多个仓储和服务接口进行数据操作 ///
[DisallowConcurrentExecution] public class GantryJob : JobBase, IJob { private readonly ITaskRepository _taskRepository; private readonly ITaskService _taskService; private readonly IContainerItemRepository _containerItemRepository; private readonly WebSocketServer _webSocketServer; private readonly IOrderDetailsService _orderDetailsService; private readonly IContainerRepository _containerRepository; private readonly IOrderContainerRepository _orderContainerRepository; public GantryJob(ITaskRepository taskRepository, ITaskService taskService, IContainerItemRepository containerItemRepository, WebSocketServer webSocketServer, IOrderDetailsService orderDetailsService, IContainerRepository containerRepository, IOrderContainerRepository orderContainerRepository) { _taskRepository = taskRepository; _taskService = taskService; _containerItemRepository = containerItemRepository; _webSocketServer = webSocketServer; _orderDetailsService = orderDetailsService; _containerRepository = containerRepository; _orderContainerRepository = orderContainerRepository; } public Task Execute(IJobExecutionContext context) { bool flag = context.JobDetail.JobDataMap.TryGetValue("JobParams", out object? value); if (flag && value is OtherDevice otherDevice) { try { byte gantryStatus = otherDevice.GetValue(GantryDBName.GantryStatus); byte gantryAutoStatus = otherDevice.GetValue(GantryDBName.GantryAutoStatus); byte gantryWorkStatus = otherDevice.GetValue(GantryDBName.GantryWorkStatus); if (gantryStatus == 1 && gantryAutoStatus == 3 && gantryWorkStatus == 0) { Dt_Task? task = _taskService.QueryAGantryUnExecuteTask(otherDevice.DeviceCode); if (task != null) { #region 取货位置判断 string[] takePositions = task.CurrentAddress.Split("*"); if (takePositions.Length != 5) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "取货位置错误"); if (task.ExceptionMessage?.Contains("取货位置错误") ?? true) { task.ExceptionMessage = "取货位置错误"; _taskRepository.UpdateData(task); } return Task.CompletedTask; } #endregion #region 放货位置判断 string[] putPositions = task.NextAddress.Split("*"); if (putPositions.Length != 5) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "放货位置错误"); if (task.ExceptionMessage?.Contains("放货位置错误") ?? true) { task.ExceptionMessage = "放货位置错误"; _taskRepository.UpdateData(task); } return Task.CompletedTask; } #endregion #region 板材尺寸获取 Dt_ContainerItem containerItem = _containerItemRepository.QueryFirst(x => x.ItemCode == task.PalletCode); if (containerItem == null) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "板材尺寸获取错误"); if (task.ExceptionMessage?.Contains("板材尺寸获取错误") ?? true) { task.ExceptionMessage = "板材尺寸获取错误"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 放货工位判断 Dt_Container container = _containerRepository.QueryFirst(x => x.ContainerCode == putPositions[0]); if (container == null) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", $"放货工位【{takePositions[0]}】未找到"); if (task.ExceptionMessage?.Contains($"放货工位【{takePositions[0]}】未找到") ?? true) { task.ExceptionMessage = $"放货工位【{takePositions[0]}】未找到"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 工位订单信息判断 Dt_OrderContainer orderContainer = _orderContainerRepository.QueryFirst(x => x.ContainerCode == putPositions[0] && x.ContainerId == container.Id); if (orderContainer == null && container.ContainerType != ContainerTypeEnum.ExceptionContainer.ObjToInt()) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", $"放货工位【{takePositions[0]}】未找到订单信息"); if (task.ExceptionMessage?.Contains($"放货工位【{takePositions[0]}】未找到订单信息") ?? true) { task.ExceptionMessage = $"放货工位【{takePositions[0]}】未找到订单信息"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 工位垫板读取数据判断 if (!LightStatusStorage.StationStautsDic.TryGetValue(putPositions[0], out bool stationStatus)) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", $"工位【{putPositions[0]}】有无垫板数据错误,{LightStatusStorage.StationStautsDic.Serialize()}"); if (task.ExceptionMessage?.Contains($"工位【{putPositions[0]}】有无垫板数据错误") ?? true) { task.ExceptionMessage = $"工位【{putPositions[0]}】有无垫板数据错误"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 工位垫板状态判断 if (!stationStatus) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", $"工位【{putPositions[0]}】无垫板,{LightStatusStorage.StationStautsDic.Serialize()}"); if (task.ExceptionMessage?.Contains($"工位【{putPositions[0]}】无垫板") ?? true) { task.ExceptionMessage = $"工位【{putPositions[0]}】无垫板"; _taskRepository.UpdateData(task); } return Task.CompletedTask; } #endregion #region 取货Z坐标判断 if (OPositions.HPositions[takePositions[0]].PositionZ == 0) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "读取取货Z坐标读取为0"); if (task.ExceptionMessage?.Contains($"读取取货Z坐标读取为0") ?? true) { task.ExceptionMessage = $"读取取货Z坐标读取为0"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 放货Z坐标判断 if (OPositions.HPositions[putPositions[0]].PositionZ == 0) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "读取放货Z坐标读取为0"); if (task.ExceptionMessage?.Contains($"读取放货Z坐标读取为0") ?? true) { task.ExceptionMessage = $"读取放货Z坐标读取为0"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 任务实体参数转换处理 int takePoX = Convert.ToInt32(takePositions[1]); int takePoY = Convert.ToInt32(takePositions[2]); int takePoZ = OPositions.HPositions[takePositions[0]].PositionZ + 30 * 1000 - Convert.ToInt32(takePositions[3]) * 1000; int takePoR = 0; int putPoX = Convert.ToInt32(putPositions[1]); int putPoY = Convert.ToInt32(putPositions[2]); int putPoZ = OPositions.HPositions[putPositions[0]].PositionZ - Convert.ToInt32(putPositions[3]) * 1000; int putPoR = 0; #endregion #region 坐标乘以1000处理,2#龙门架取反(乘以-1000) int temp = 1000; if (otherDevice.DeviceCode == "GT02") { temp = -1000; } #endregion #region 坐标计算 if (Convert.ToInt32(takePositions[4]) == 1 || Convert.ToInt32(takePositions[4]) == 2) { takePoX = takePoX * temp + OPositions.HPositions[takePositions[0]].PositionX; takePoY = takePoY * temp + OPositions.HPositions[takePositions[0]].PositionY; putPoX = putPoX * temp + OPositions.HPositions[putPositions[0]].PositionX; putPoY = putPoY * temp + OPositions.HPositions[putPositions[0]].PositionY; takePoR = OPositions.HPositions[takePositions[0]].PositionR; if (Convert.ToInt32(takePositions[4]) == 1) putPoR = OPositions.HPositions[putPositions[0]].PositionR; else { if (otherDevice.DeviceCode == "GT03") putPoR = otherDevice.Communicator.Read("DB10.840"); else if (otherDevice.DeviceCode == "GT02") putPoR = otherDevice.Communicator.Read("DB10.836"); else if (otherDevice.DeviceCode == "GT01") putPoR = otherDevice.Communicator.Read("DB10.832"); else { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "R坐标错误"); if (task.ExceptionMessage?.Contains($"R坐标错误") ?? true) { task.ExceptionMessage = $"R坐标错误"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } } } else { takePoX = takePoX * temp + OPositions.ZPositions[takePositions[0]].PositionX; takePoY = takePoY * temp + OPositions.ZPositions[takePositions[0]].PositionY; putPoX = putPoX * temp + OPositions.ZPositions[putPositions[0]].PositionX; putPoY = putPoY * temp + OPositions.ZPositions[putPositions[0]].PositionY; takePoR = OPositions.ZPositions[takePositions[0]].PositionR; putPoR = OPositions.ZPositions[putPositions[0]].PositionR; } #endregion #region Debug日志记录,记录取货和放货坐标信息 WriteDebug($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"取货位:{takePositions[0]},放货位:{putPositions[0]}{Environment.NewLine}取货坐标:X:{takePoX} Y:{takePoY} Z:{takePoZ} R:{takePoR}{Environment.NewLine}放货坐标:X:{putPoX} Y:{putPoY} Z:{putPoZ} R:{putPoR}{Environment.NewLine}读取PLC取货坐标:X:{OPositions.HPositions[takePositions[0]].PositionX} Y:{OPositions.HPositions[takePositions[0]].PositionY} Z:{OPositions.HPositions[takePositions[0]].PositionZ} R:{OPositions.HPositions[takePositions[0]].PositionR}{Environment.NewLine}读取PLC放货坐标:X:{OPositions.HPositions[putPositions[0]].PositionX} Y:{OPositions.HPositions[putPositions[0]].PositionY} Z:{OPositions.HPositions[putPositions[0]].PositionZ} R:{OPositions.HPositions[putPositions[0]].PositionR}"); #endregion #region 超过容器宽度处理 bool isMoreWidth = orderContainer == null ? false : orderContainer.MaxWidth > container.ContainerWidth; if (isMoreWidth) { putPoX = putPoX - (orderContainer.MaxWidth - container.ContainerWidth) / 2 * temp; } #endregion #region 坐标范围判断 List devicePros = otherDevice.DeviceProDTOs.Where(x => x.DeviceProParamType == "MaxPosition").ToList(); DeviceProDTO? devicePro = devicePros.OrderBy(x => x.DeviceProOffset).FirstOrDefault(); if (devicePro == null) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", "设备协议参数错误,未找到最大最小坐标地址"); if (task.ExceptionMessage?.Contains($"设备协议参数错误,未找到最大最小坐标地址") ?? true) { task.ExceptionMessage = $"设备协议参数错误,未找到最大最小坐标地址"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } int[] data = otherDevice.Communicator.Read(devicePro.DeviceProAddress, (ushort)(devicePros.Count)); int maxX = data[0]; int minX = data[1]; int maxY = data[2]; int minY = data[3]; int maxZ = data[4]; int minZ = data[5]; int maxR = data[6]; int minR = data[7]; if (takePoX < minX || takePoX > maxX) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"X取货坐标超出范围,取货坐标:{takePoX},最大值:{maxX},最小值:{minX}"); if (task.ExceptionMessage?.Contains($"X取货坐标超出范围,取货坐标:{takePoX},最大值:{maxX},最小值:{minX}") ?? true) { task.ExceptionMessage = $"X取货坐标超出范围,取货坐标:{takePoX},最大值:{maxX},最小值:{minX}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (putPoX < minX || putPoX > maxX) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"X放货坐标超出范围,取货坐标:{putPoX},最大值:{maxX},最小值:{minX}"); if (task.ExceptionMessage?.Contains($"X放货坐标超出范围,取货坐标:{putPoX},最大值:{maxX},最小值:{minX}") ?? true) { task.ExceptionMessage = $"X放货坐标超出范围,取货坐标:{putPoX},最大值:{maxX},最小值:{minX}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (takePoY < minY || takePoY > maxY) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"Y取货坐标超出范围,取货坐标:{takePoY},最大值:{maxY},最小值:{minY}"); if (task.ExceptionMessage?.Contains($"Y取货坐标超出范围,取货坐标:{takePoY},最大值:{maxY},最小值:{minY}") ?? true) { task.ExceptionMessage = $"Y取货坐标超出范围,取货坐标:{takePoY},最大值:{maxY},最小值:{minY}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (putPoY < minY || putPoY > maxY) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"Y放货坐标超出范围,取货坐标:{putPoY},最大值:{maxY},最小值:{minY}"); if (task.ExceptionMessage?.Contains($"Y放货坐标超出范围,取货坐标:{putPoY},最大值:{maxY},最小值:{minY}") ?? true) { task.ExceptionMessage = $"Y放货坐标超出范围,取货坐标:{putPoY},最大值:{maxY},最小值:{minY}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (takePoZ < minZ || takePoZ > maxZ) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"Z取货坐标超出范围,取货坐标:{takePoZ},最大值:{maxZ},最小值:{minZ}"); if (task.ExceptionMessage?.Contains($"Z取货坐标超出范围,取货坐标:{takePoZ},最大值:{maxZ},最小值:{minZ}") ?? true) { task.ExceptionMessage = $"Z取货坐标超出范围,取货坐标:{takePoZ},最大值:{maxZ},最小值:{minZ}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (putPoZ < minZ || putPoZ > maxZ) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"Z放货坐标超出范围,取货坐标:{putPoZ},最大值:{maxZ},最小值:{minZ}"); if (task.ExceptionMessage?.Contains($"Z放货坐标超出范围,取货坐标:{putPoZ},最大值:{maxZ},最小值:{minZ}") ?? true) { task.ExceptionMessage = $"Z放货坐标超出范围,取货坐标:{putPoZ},最大值:{maxZ},最小值:{minZ}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (takePoR < minR || takePoR > maxR) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"R取货坐标超出范围,取货坐标:{takePoR},最大值:{maxR},最小值:{minR}"); if (task.ExceptionMessage?.Contains($"R取货坐标超出范围,取货坐标:{takePoR},最大值:{maxR},最小值:{minR}") ?? true) { task.ExceptionMessage = $"R取货坐标超出范围,取货坐标:{takePoR},最大值:{maxR},最小值:{minR}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } if (putPoR < minR || putPoR > maxR) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}-坐标", $"R放货坐标超出范围,取货坐标:{putPoR},最大值:{maxR},最小值:{minR}"); if (task.ExceptionMessage?.Contains($"R放货坐标超出范围,取货坐标:{putPoR},最大值:{maxR},最小值:{minR}") ?? true) { task.ExceptionMessage = $"R放货坐标超出范围,取货坐标:{putPoR},最大值:{maxR},最小值:{minR}"; _taskRepository.UpdateData(task); } if (LightStatusStorage.LightStatusDic.ContainsKey(putPositions[0])) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightError; } return Task.CompletedTask; } #endregion #region 任务发送 otherDevice.SetValue(GantryDBName.TwoHand, true); otherDevice.SetValue(GantryDBName.TaskNum, task.TaskNum); otherDevice.SetValue(GantryDBName.TakePositionX, takePoX); otherDevice.SetValue(GantryDBName.TakePositionY, takePoY); otherDevice.SetValue(GantryDBName.TakePositionZ, takePoZ); otherDevice.SetValue(GantryDBName.TakePositionR, takePoR); otherDevice.SetValue(GantryDBName.PutPositionX, putPoX); otherDevice.SetValue(GantryDBName.PutPositionY, putPoY); otherDevice.SetValue(GantryDBName.PutPositionZ, putPoZ); otherDevice.SetValue(GantryDBName.PutPositionR, putPoR); otherDevice.SetValue(GantryDBName.Length, containerItem.ItemLength); otherDevice.SetValue(GantryDBName.Width, containerItem.ItemWidth); otherDevice.SetValue(GantryDBName.Height, containerItem.ItemHeight); otherDevice.SetValue(GantryDBName.WorkType, 1); otherDevice.SetValue(GantryDBName.StartCommand, 1); #endregion #region 任务状态更新 task.TaskState = TaskStatusEnum.Gantry_Executing.ObjToInt(); _taskRepository.UpdateData(task); #endregion #region 三色灯状态更新 if (LightStatusStorage.LightStatusDic.TryGetValue(putPositions[0], out LightStatusEnum lightStatusDic)) { if (lightStatusDic != LightStatusEnum.LightWorking) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.LightWorking; } } #endregion } } else if (gantryWorkStatus == 5) { int currentTaskNum = otherDevice.GetValue(GantryDBName.TaskNum); if (currentTaskNum > 0) { Dt_Task task = _taskRepository.QueryFirst(x => x.TaskNum == currentTaskNum); if (task != null) { _taskService.TaskComplete(task); Task.Run(() => { _orderDetailsService.ToMes(task.PalletCode, 4); }); string[] putPositions = task.NextAddress.Split("*"); if (putPositions.Length != 5) { return Task.CompletedTask; } if (LightStatusStorage.LightStatusDic.TryGetValue(putPositions[0], out LightStatusEnum lightStatusDic)) { if (lightStatusDic != LightStatusEnum.Ready) { LightStatusStorage.LightStatusDic[putPositions[0]] = LightStatusEnum.Ready; } } } } otherDevice.SetValue(GantryDBName.WorkType, 5); } } catch (Exception ex) { WriteError($"{otherDevice.DeviceCode}-{otherDevice.DeviceName}", ex.Message, ex); } } else { WriteError(nameof(GantryJob), "参数错误,未传递设备参数或设备类型错误"); } return Task.CompletedTask; } } }