| using AutoMapper; | 
| using Microsoft.AspNetCore.Components.Routing; | 
| using Newtonsoft.Json; | 
| using Quartz; | 
| using System; | 
| using System.Collections.Generic; | 
| using System.Diagnostics.CodeAnalysis; | 
| using System.Linq; | 
| using System.Reflection; | 
| using System.Text; | 
| using System.Threading.Tasks; | 
| using WIDESEAWCS_Common.APIEnum; | 
| using WIDESEAWCS_Common.TaskEnum; | 
| using WIDESEAWCS_Core; | 
| using WIDESEAWCS_Core.Caches; | 
| using WIDESEAWCS_Core.Enums; | 
| using WIDESEAWCS_Core.Helper; | 
| using WIDESEAWCS_DTO.TaskInfo; | 
| using WIDESEAWCS_IBasicInfoRepository; | 
| 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.HoisterJob; | 
| using WIDESEAWCS_Tasks.StackerCraneJob; | 
|   | 
| namespace WIDESEAWCS_Tasks | 
| { | 
|     [DisallowConcurrentExecution] | 
|     public class StackerCraneJob_CSJ : JobBase, IJob | 
|     { | 
|         private readonly IMapper _mapper; | 
|         private readonly ICacheService _cacheService; | 
|         private readonly ITaskService _taskService; | 
|         private readonly ITaskExecuteDetailService _taskExecuteDetailService; | 
|         private readonly ITaskRepository _taskRepository; | 
|         private readonly IRouterService _routerService; | 
|         private readonly IStationMangerRepository _stationMangerRepository; | 
|         private List<Dt_ApiInfo> apiInfos; | 
|   | 
|         public StackerCraneJob_CSJ(ITaskService taskService, ICacheService cacheService, ITaskExecuteDetailService taskExecuteDetailService, ITaskRepository taskRepository, IRouterService routerService, IStationMangerRepository stationMangerRepository, IMapper mapper) | 
|         { | 
|             _taskService = taskService; | 
|             _taskExecuteDetailService = taskExecuteDetailService; | 
|             _taskRepository = taskRepository; | 
|             _routerService = routerService; | 
|             _stationMangerRepository = stationMangerRepository; | 
|             _cacheService = cacheService; | 
|             _mapper = mapper; | 
|   | 
|             string? apiInfoStr = _cacheService.Get("apiInfos"); | 
|             if (!string.IsNullOrEmpty(apiInfoStr)) | 
|             { | 
|                 List<Dt_ApiInfo>? infos = JsonConvert.DeserializeObject<List<Dt_ApiInfo>>(apiInfoStr); | 
|                 if (infos == null || infos.Count == 0) | 
|                 { | 
|                     apiInfos = new List<Dt_ApiInfo>(); | 
|                 } | 
|                 else | 
|                 { | 
|                     apiInfos = infos; | 
|                 } | 
|             } | 
|         } | 
|   | 
|         public Task Execute(IJobExecutionContext context) | 
|         { | 
|             try | 
|             { | 
|                 CommonStackerCrane commonStackerCrane = (CommonStackerCrane)context.JobDetail.JobDataMap.Get("JobParams"); | 
|                 if (commonStackerCrane != null) | 
|                 { | 
|                     if (!commonStackerCrane.IsEventSubscribed) | 
|                     { | 
|                         commonStackerCrane.StackerCraneTaskCompletedEventHandler += CommonStackerCrane_StackerCraneTaskCompletedEventHandler;//订阅任务完成事件 | 
|                     } | 
|                     commonStackerCrane.CheckStackerCraneTaskCompleted();//防止任务完成事件监测超时,再手动触发一次 | 
|                     if (commonStackerCrane.StackerCraneAutoStatusValue == StackerCraneAutoStatus.Automatic && commonStackerCrane.StackerCraneStatusValue == StackerCraneStatus.Normal && commonStackerCrane.StackerCraneWorkStatusValue == StackerCraneWorkStatus.Standby) | 
|                     { | 
|                         Thread.Sleep(1000); | 
|                         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; | 
|                                     task.Dispatchertime = DateTime.Now; | 
|                                     task.ExceptionMessage = ""; | 
|                                     _taskService.UpdateTask(task, TaskStatusEnum.SC_Executing); | 
|                                     //延时1s | 
|                                     Thread.Sleep(1000); | 
|                                 } | 
|                             } | 
|                         } | 
|                     } | 
|                 } | 
|             } | 
|             catch (Exception ex) | 
|             { | 
|                 WriteError(nameof(CommonStackerCraneJob), ex.Message, ex); | 
|             } | 
|             return Task.CompletedTask; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// 任务完成事件订阅的方法 | 
|         /// </summary> | 
|         /// <param name="sender"></param> | 
|         /// <param name="e"></param> | 
|         private void CommonStackerCrane_StackerCraneTaskCompletedEventHandler(object? sender, WIDESEAWCS_QuartzJob.StackerCrane.StackerCraneTaskCompletedEventArgs e) | 
|         { | 
|             CommonStackerCrane? commonStackerCrane = sender as CommonStackerCrane; | 
|             if (commonStackerCrane != null) | 
|             { | 
|                 if (e.TaskNum != 0) | 
|                 { | 
|                     WriteDebug(commonStackerCrane.DeviceCode, $"读取到任务完成,任务号:{e.TaskNum}"); | 
|                     StackerCraneTaskCompleted(e.TaskNum, commonStackerCrane.DeviceCode); | 
|                     commonStackerCrane.SetValue(StackerCraneDBName.WorkType, 5); | 
|                 } | 
|             } | 
|         } | 
|   | 
|         public WebResponseContent StackerCraneTaskCompleted(int taskNum, string deviceCode) | 
|         { | 
|             try | 
|             { | 
|                 Dt_Task task = _taskRepository.QueryFirst(x => x.TaskNum == taskNum); | 
|                 if (task != null) | 
|                 { | 
|                     if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) | 
|                     { | 
|                         Dt_StationManger stationManger = _stationMangerRepository.QueryFirst(x => x.StackerCraneStationCode == task.NextAddress); | 
|                         if(stationManger == null) | 
|                         { | 
|                             _taskExecuteDetailService.AddTaskExecuteDetail(taskNum, $"AGV站点未配置,{task.NextAddress}"); | 
|                             _taskService.UpdateTaskExceptionMessage(taskNum, $"AGV站点未配置,{task.NextAddress}"); | 
|                             return WebResponseContent.Instance.Error($"AGV站点未配置,{task.NextAddress}"); | 
|                         } | 
|   | 
|                         _taskService.UpdateTask(task, TaskStatusEnum.AGV_Execute, deviceCode: "AGV_CSJ", currentAddress: stationManger.AGVStationCode ?? throw new Exception($"agv站点错误"), nextAddress: task.TargetAddress); | 
|                     } | 
|                     else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup || task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup) | 
|                     { | 
|                         _taskService.TaskCompleted(taskNum); | 
|                     } | 
|                     else | 
|                     { | 
|                         WriteError(deviceCode, $"未找到该任务类型回调WMS任务完成接口,{task.TaskType}"); | 
|                         _taskExecuteDetailService.AddTaskExecuteDetail(taskNum, $"未找到该任务类型回调WMS任务完成接口,{task.TaskType}"); | 
|                         _taskService.UpdateTaskExceptionMessage(taskNum, $"未找到该任务类型回调WMS任务完成接口,{task.TaskType}"); | 
|                     } | 
|                 } | 
|                 else | 
|                 { | 
|                     WriteError(deviceCode, $"未找到任务信息,任务号:{taskNum}"); | 
|                     return WebResponseContent.Instance.Error($"未找到任务信息,任务号:{taskNum}"); | 
|                 } | 
|   | 
|                 return WebResponseContent.Instance.OK(); | 
|             } | 
|             catch (Exception ex) | 
|             { | 
|                 WriteError(deviceCode, $"任务完成错误", ex); | 
|                 return WebResponseContent.Instance.Error(ex.Message); | 
|             } | 
|         } | 
|   | 
|         /// <summary> | 
|         /// 获取任务 | 
|         /// </summary> | 
|         /// <param name="commonStackerCrane">堆垛机对象</param> | 
|         /// <returns></returns> | 
|         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 = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); | 
|                     } | 
|                 } | 
|             } | 
|             //判断移库 | 
|             if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) | 
|             { | 
|                 if (OutTaskStationIsOccupied(task) == null) | 
|                 { | 
|                     bool flag = false; | 
|                     List<string> otherOutStaionCodes = _routerService.QueryNextRoutes(commonStackerCrane.DeviceCode, task.NextAddress,task.TaskType).Select(x => x.ChildPosi).ToList(); | 
|                     List<Dt_Task> tasks = _taskService.QueryStackerCraneOutTasks(commonStackerCrane.DeviceCode, otherOutStaionCodes); | 
|                     foreach (var item in tasks) | 
|                     { | 
|                         if (OutTaskStationIsOccupied(task) != null) | 
|                         { | 
|                             flag = true; | 
|                             break; | 
|                         } | 
|                     } | 
|                     if (!flag) | 
|                     { | 
|                         task = _taskService.QueryStackerCraneInTask(commonStackerCrane.DeviceCode); | 
|                     } | 
|                 } | 
|             } | 
|   | 
|             if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) | 
|             { | 
|                 string? url = apiInfos.FirstOrDefault(x => x.ApiCode == APIEnum.WMSIsReloaction.ToString())?.ApiAddress; | 
|                 if (string.IsNullOrEmpty(url)) | 
|                 { | 
|                     _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskNum, $"未找到WMS移库判断接口"); | 
|                     WriteError(commonStackerCrane.DeviceCode, $"未找到WMS移库判断接口"); | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到WMS移库判断接口"); | 
|                     return null; | 
|                 } | 
|                 string response = HttpHelper.Post($"{url}?taskNum={task.TaskNum}&locationCode={task.CurrentAddress}", "");//todo 调用WMS任务完成方法 | 
|                 if (string.IsNullOrEmpty(response)) | 
|                 { | 
|                     _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskNum, $"移库接口调用错误"); | 
|                     WriteError(commonStackerCrane.DeviceCode, $"移库接口调用错误"); | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库接口调用错误"); | 
|                     return null; | 
|                 } | 
|                 WebResponseContent? responseContent = JsonConvert.DeserializeObject<WebResponseContent>(response); | 
|                 if (responseContent == null || !responseContent.Status) | 
|                 { | 
|                     _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskNum, $"移库接口调用错误"); | 
|                     WriteError(commonStackerCrane.DeviceCode, $"移库接口调用错误"); | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库接口调用错误"); | 
|                     return null; | 
|                 } | 
|                 WMSTaskDTO? taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(responseContent.Data.Serialize()); | 
|                 if (taskDTO == null) | 
|                 { | 
|                     _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskNum, $"移库接口调用错误"); | 
|                     WriteError(commonStackerCrane.DeviceCode, $"移库接口调用错误"); | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"移库接口调用错误"); | 
|                     return null; | 
|   | 
|                 } | 
|                 if (task.TaskNum == taskDTO.TaskNum) | 
|                 { | 
|                     return task; | 
|                 } | 
|                 else | 
|                 { | 
|                     Dt_Task reloTask = _mapper.Map<Dt_Task>(taskDTO); | 
|                     //判断移库货位任务是否已存在,如存在先执行 | 
|                     Dt_Task existTask = _taskService.QueryStackerExistTask(reloTask.PalletCode, reloTask.SourceAddress); | 
|                     if (existTask != null && existTask.TaskState == (int)TaskStatusEnum.SC_Execute) | 
|                     { | 
|                         return existTask; | 
|                     } | 
|                     else if (existTask != null && existTask.TaskState != (int)TaskStatusEnum.SC_Execute) | 
|                     { | 
|                         WriteError(commonStackerCrane.DeviceCode, $"任务{task.TaskNum}浅货位任务{existTask.TaskNum}任务状态不为堆垛待执行"); | 
|                         _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"任务{task.TaskNum}浅货位任务{existTask.TaskNum}任务状态不为堆垛待执行"); | 
|                         return null; | 
|                     } | 
|                     else | 
|                     { | 
|                         reloTask.TaskState = TaskStatusEnum.SC_Execute.ObjToInt(); | 
|                         reloTask.CurrentAddress = taskDTO.SourceAddress; | 
|                         reloTask.NextAddress = taskDTO.TargetAddress; | 
|                         reloTask.DeviceCode = task.DeviceCode; | 
|                         reloTask.TaskType = TaskTypeEnum.Relocation.ObjToInt(); | 
|                         int taskId = _taskRepository.AddData(reloTask); | 
|                         reloTask.TaskId = taskId; | 
|                     } | 
|                     return reloTask; | 
|   | 
|                 } | 
|             } | 
|   | 
|             return task; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// 出库任务判断出库站台是否被占用 | 
|         /// </summary> | 
|         /// <param name="task">任务实体</param> | 
|         /// <returns>如果未被占用,返回传入的任务信息,否则,返回null</returns> | 
|         private Dt_Task? OutTaskStationIsOccupied([NotNull] Dt_Task task) | 
|         { | 
|             Dt_StationManger? stationManger = _stationMangerRepository.QueryFirst(x => (x.StationCode == task.NextAddress || x.StackerCraneStationCode == task.NextAddress) && x.StackerCraneCode == task.DeviceCode); | 
|             if (stationManger != null) | 
|             { | 
|                 IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceCode == stationManger.StationDeviceCode); | 
|                 if (device != null) | 
|                 { | 
|                     OtherDevice client = (OtherDevice)device; | 
|                     if (client.GetValue<GroundStationDBName, bool>(GroundStationDBName.R_IsCanPut, stationManger.StationCode))//出库站台未被占用 | 
|                     { | 
|                         task.NextAddress = stationManger.StackerCraneStationCode; | 
|                         _taskRepository.UpdateData(task); | 
|                         client.SetValue(GroundStationDBName.R_IsCanPut, true, stationManger.StationCode); | 
|                         return task; | 
|                     } | 
|                 } | 
|                 else | 
|                 { | 
|                     WriteError(task.DeviceCode, $"未找到出库站台【{stationManger.StationDeviceCode}】对应的通讯对象,无法判断出库站台是否被占用"); | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到出库站台【{stationManger.StationDeviceCode}】对应的通讯对象,无法判断出库站台是否被占用"); | 
|                 } | 
|             } | 
|             else | 
|             { | 
|                 WriteError(task.DeviceCode, $"未找到站台【{task.NextAddress}】信息,无法校验站台"); | 
|                 _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"未找到站台【{task.NextAddress}】信息,无法校验站台"); | 
|             } | 
|             return null; | 
|         } | 
|   | 
|         /// <summary> | 
|         /// 任务实体转换成命令Model | 
|         /// </summary> | 
|         /// <param name="task">任务实体</param> | 
|         /// <returns></returns> | 
|         /// <exception cref="Exception"></exception> | 
|         public StackerCraneTaskCommand? ConvertToStackerCraneTaskCommand([NotNull] Dt_Task task) | 
|         { | 
|             StackerCraneTaskCommand stackerCraneTaskCommand = new StackerCraneTaskCommand(); | 
|   | 
|             stackerCraneTaskCommand.Barcode = task.PalletCode; | 
|             stackerCraneTaskCommand.TaskNum = task.TaskNum; | 
|             stackerCraneTaskCommand.WorkType = 1; | 
|             stackerCraneTaskCommand.TrayType = (Int16)task.PalletType; | 
|             if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)//判断是否是入库任务 | 
|             { | 
|                 string[] startCodes = task.CurrentAddress.Split("-"); | 
|                 if (startCodes.Length == 3) | 
|                 { | 
|                     stackerCraneTaskCommand.StartRow = Convert.ToInt16(startCodes[0]); | 
|                     stackerCraneTaskCommand.StartColumn = Convert.ToInt16(startCodes[1]); | 
|                     stackerCraneTaskCommand.StartLayer = Convert.ToInt16(startCodes[2]); | 
|                 } | 
|                 else | 
|                 { | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"入库任务起点错误,起点:【{task.CurrentAddress}】"); | 
|                     WriteError(task.DeviceCode, $"入库任务起点错误,起点:【{task.CurrentAddress}】"); | 
|                     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}】"); | 
|                     WriteError(task.DeviceCode, $"入库任务终点错误,终点:【{task.NextAddress}】"); | 
|                     return null; | 
|                 } | 
|             } | 
|             else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) | 
|             { | 
|                 string[] targetCodes = task.NextAddress.Split("-"); | 
|   | 
|                 if (targetCodes.Length == 3) | 
|                 { | 
|                     stackerCraneTaskCommand.EndRow = Convert.ToInt16(targetCodes[0]); | 
|                     stackerCraneTaskCommand.EndColumn = Convert.ToInt16(targetCodes[1]); | 
|                     stackerCraneTaskCommand.EndLayer = Convert.ToInt16(targetCodes[2]); | 
|                 } | 
|                 else | 
|                 { | 
|                     //数据配置错误 | 
|                     _taskService.UpdateTaskExceptionMessage(task.TaskNum, $"出库任务终点错误,终点:【{task.NextAddress}】"); | 
|                     WriteError(task.DeviceCode, $"出库任务终点错误,终点:【{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}】"); | 
|                     WriteError(task.DeviceCode, $"出库任务起点错误,起点:【{task.CurrentAddress}】"); | 
|                     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}】"); | 
|                     WriteError(task.DeviceCode, $"移库任务终点错误,终点:【{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}】"); | 
|                     WriteError(task.DeviceCode, $"移库任务起点错误,起点:【{task.CurrentAddress}】"); | 
|                     return null; | 
|                 } | 
|             } | 
|             return stackerCraneTaskCommand; | 
|         } | 
|     } | 
| } |