using AutoMapper; using MailKit.Search; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Reflection.Metadata; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.Log; using WIDESEA_Common.OtherEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.Inbound; using WIDESEA_DTO.Stock; using WIDESEA_DTO.Task; using WIDESEA_IBasicService; using WIDESEA_IStockService; using WIDESEA_ITaskInfoService; using WIDESEA_Model.Models; using static WIDESEA_ITaskInfoService.ITaskService; namespace WIDESEA_TaskInfoService { public partial class WMSCruJob : IHostedService, IDisposable { private readonly ILogger _logger; private Timer _timer; private readonly ITaskService _taskService; private readonly ILocationInfoService _locationInfoService; private readonly IStockInfoService _stockInfoService; private readonly IUnitOfWorkManage _unitOfWorkManage; public WMSCruJob(ILogger logger, IUnitOfWorkManage unitOfWorkManage, IStockInfoService stockInfoService, ILocationInfoService locationInfoService, ITaskService taskService) { _logger = logger; _unitOfWorkManage = unitOfWorkManage; _stockInfoService = stockInfoService; _locationInfoService = locationInfoService; _taskService=taskService; } private static readonly object _taskProcessLock = new object(); private const int TASK_PROCESS_TIMEOUT = 3000; // 3秒超时 public Task StartAsync(CancellationToken cancellationToken) { _timer = new Timer(DoWorkWheel, null, TimeSpan.Zero, TimeSpan.FromSeconds(3)); return Task.CompletedTask; } public static List InStationareaList = new List() { "1113", "1114", "1115", "1116", "1117", "1118", "1119", "1120", "1121", "1122" }; private void DoWorkWheel(object state) { if (!Monitor.TryEnter(_taskProcessLock, TASK_PROCESS_TIMEOUT)) { return; } try { // 定义状态常量,避免魔法数字 const int PLC_IN_FINISH = (int)InTaskStatusEnum.PLC_InFinish; const int PLC_IN_InNew = (int)InTaskStatusEnum.InNew; const int OUT_NEW = (int)OutTaskStatusEnum.OutNew; const int SC_OUT_FINISH = (int)OutTaskStatusEnum.SC_OutFinish; const int SC_IN_EXECUTING = (int)InTaskStatusEnum.SC_IntExecuting; const int SC_OUT_EXECUTING = (int)OutTaskStatusEnum.SC_OutExecuting; const int RELOCATION_EXECUTING = (int)RelocationTaskStatusEnum.RelocationExecuting; const int PLC_OUT_EXECUTING = (int)OutTaskStatusEnum.PLC_OutExecuting; // 获取当前任务数据 List allTasks = _taskService.Repository.QueryData(); // 获取巷道超过3个任务的路段 HashSet excludedRoadways = allTasks .Where(x => x.NumberSsuances > 3) .Select(x => x.Roadway) .Distinct() .ToHashSet(); // 过滤需要处理的任务 List tasksToProcess = allTasks .Where(x => (x.TaskStatus == PLC_IN_FINISH || x.TaskStatus == OUT_NEW || x.TaskStatus == SC_OUT_FINISH || (x.TaskStatus == PLC_IN_InNew && InStationareaList.Contains(x.SourceAddress))) && !excludedRoadways.Contains(x.Roadway)) .ToList(); // 按状态分组处理,减少重复查询 ProcessInAndNewTasks(tasksToProcess, allTasks, excludedRoadways); //下发堆垛机 ProcessOutFinishTasks(tasksToProcess, allTasks); //下发输送线任务 ProcessInPalltask(tasksToProcess, allTasks); } catch (Exception ex) { Console.WriteLine($"任务处理异常:{ex.Message}"); } finally { // 必须释放锁,否则会导致死锁 Monitor.Exit(_taskProcessLock); } } private void ProcessInAndNewTasks(List tasksToProcess, List allTasks, HashSet excludedRoadways) { const int PLC_IN_FINISH = (int)InTaskStatusEnum.PLC_InFinish; const int OUT_NEW = (int)OutTaskStatusEnum.OutNew; const int SC_IN_EXECUTING = (int)InTaskStatusEnum.SC_IntExecuting; const int SC_OUT_EXECUTING = (int)OutTaskStatusEnum.SC_OutExecuting; const int RELOCATION_EXECUTING = (int)RelocationTaskStatusEnum.RelocationExecuting; const int RELOCCATION_NEW = (int)RelocationTaskStatusEnum.RelocationNew; var inAndNewTasks = tasksToProcess .Where(x => x.TaskStatus == PLC_IN_FINISH || x.TaskStatus == OUT_NEW).OrderBy(x=>x.CreateDate) .ToList(); if(inAndNewTasks.Count > 0) { foreach (var task in inAndNewTasks) { // 检查同一巷道是否有正在执行的任务 bool hasExecutingTask = allTasks.Any(x => x.TaskId != task.TaskId && x.Roadway == task.Roadway && (x.TaskStatus == SC_IN_EXECUTING || x.TaskStatus == SC_OUT_EXECUTING || x.TaskStatus == RELOCATION_EXECUTING)); if (hasExecutingTask) continue; if (task.TaskStatus == OUT_NEW) { bool SCNewTasks = allTasks.Any(x => x.TaskStatus != OUT_NEW && x.TargetAddress == task.TargetAddress); if (SCNewTasks) continue; } //判断是否需要移库 WebResponseContent webResponse = JudgmentIsRelocations(task); if (!webResponse.Status) continue; // 下发堆垛机任务 WCSginseng result = _taskService.SC_IssueTasks( task.TaskId, int.Parse(task.Roadway), task.TaskNum, task.PalletCode, int.Parse(task.PalletType), task.CurrentAddress, task.NextAddress, task.TargetAddress); UpdateTaskStatus(task, result, successStatus: task.TaskStatus == PLC_IN_FINISH ? SC_IN_EXECUTING : SC_OUT_EXECUTING, 1); } } } private void ProcessOutFinishTasks(List tasksToProcess, List allTasks) { const int SC_OUT_FINISH = (int)OutTaskStatusEnum.SC_OutFinish; const int PLC_OUT_EXECUTING = (int)OutTaskStatusEnum.PLC_OutExecuting; var outFinishTasks = tasksToProcess .Where(x => x.TaskStatus == SC_OUT_FINISH) .ToList(); if(outFinishTasks.Count > 0) { foreach (var task in outFinishTasks) { // 检查同一巷道是否有其他已完成的任务 bool hasOtherFinishTask = allTasks.Any(x => x.Roadway == task.Roadway && x.TaskStatus == SC_OUT_FINISH && x.TaskId != task.TaskId); if (hasOtherFinishTask) continue; // 下发PLC任务 WCSginseng result = _taskService.PLC_IssueTasks( task.TaskId, int.Parse(task.Roadway), task.TaskNum, task.PalletCode, int.Parse(task.PalletType), task.CurrentAddress, task.NextAddress, ""); UpdateTaskStatus(task, result, PLC_OUT_EXECUTING, 2); } } } private void ProcessInPalltask(List tasksToProcess, List allTasks) { const int PLC_IN_InNew = (int)InTaskStatusEnum.InNew; const int PLC_PLC_INEXECUTING = (int)InTaskStatusEnum.PLC_InExecuting; var outFinishTasks = tasksToProcess .Where(x => x.TaskStatus == PLC_IN_InNew && InStationareaList.Contains(x.SourceAddress)) .ToList(); if(outFinishTasks.Count > 0) { foreach (var task in outFinishTasks) { // 下发PLC任务 WCSginseng result = _taskService.PLC_IssueTasks( task.TaskId, int.Parse(task.Roadway), task.TaskNum, task.PalletCode, int.Parse(task.PalletType), task.CurrentAddress, task.NextAddress, ""); UpdateTaskStatus(task, result, PLC_PLC_INEXECUTING, 2); } } } private void UpdateTaskStatus(Dt_Task task, WCSginseng result, int successStatus,int statype) { if (result.IsSuccess) { task.TaskStatus = successStatus; if(task.TaskStatus== (int)OutTaskStatusEnum.SC_OutExecuting) { string Result = MesOutTaskStatusEnum.Start.GetDescription(); //调取上游系统反馈开始任务 _taskService.OutStoreDocCallback(task.TaskNum,Result, "操作成功"); }else if(task.TaskStatus == (int)InTaskStatusEnum.PLC_InExecuting) { string Result = MesInTaskStatusEnum.Start.GetDescription(); //调取上游系统反馈开始任务 _taskService.InStoreDocCallback(task.TaskNum, Result, "操作成功",task.PalletCode,""); } } else { task.Remark = result.Message; task.NumberSsuances++; } _taskService.Repository.UpdateData(task); } public Task StopAsync(CancellationToken cancellationToken) { _timer?.Dispose(); return Task.CompletedTask; } public void Dispose() { throw new NotImplementedException(); } /// /// 判断巷道内移库 /// /// /// /// public WebResponseContent JudgmentIsRelocations(Dt_Task dt_Task) { const int PLC_IN_FINISH = (int)InTaskStatusEnum.PLC_InFinish; const int SC_IN_EXECUTING = (int)InTaskStatusEnum.SC_IntExecuting; const int SC_OUT_EXECUTING = (int)OutTaskStatusEnum.SC_OutExecuting; WebResponseContent content = new WebResponseContent(); try { string Locationcodeadd = dt_Task.TaskType == (int)TaskTypeEnum.Inbound ? dt_Task.NextAddress: dt_Task.CurrentAddress ; Dt_LocationInfo dt_Location = _locationInfoService.Repository.QueryData(x => x.LocationCode == Locationcodeadd).FirstOrDefault(); if (dt_Location.Depth == 1 || dt_Location.RoadwayNo == "5") return content.OK(); int locrow = judgmentRow(dt_Location.RoadwayNo, dt_Location.Row); Dt_LocationInfo shallowLocation = _locationInfoService.Repository.QueryData(x => x.RoadwayNo == dt_Location.RoadwayNo && x.Row == locrow && x.Layer == dt_Location.Layer && x.Column == dt_Location.Column).FirstOrDefault(); if (shallowLocation.LocationStatus == (int)LocationStatusEnum.Free) return content.OK(); //判断是否有移库任务 var TransferTask = _taskService.Repository.QueryData(x=>x.TaskStatus== (int)RelocationTaskStatusEnum.RelocationNew && x.CurrentAddress== shallowLocation.LocationCode).FirstOrDefault(); if(TransferTask != null) { //进行下发给堆垛机任务 WCSginseng result = _taskService.SC_IssueTasks( TransferTask.TaskId, int.Parse(TransferTask.Roadway), TransferTask.TaskNum, TransferTask.PalletCode, int.Parse(TransferTask.PalletType), TransferTask.CurrentAddress, TransferTask.NextAddress, dt_Task.TargetAddress); if (result.IsSuccess) { TransferTask.TaskStatus = (int)RelocationTaskStatusEnum.RelocationExecuting; _taskService.UpdateData(TransferTask); return content.OK(); } else { UpdateTaskStatus(dt_Task, result, successStatus: dt_Task.TaskStatus == PLC_IN_FINISH ? SC_IN_EXECUTING : SC_OUT_EXECUTING, 1); WriteLog.GetLog("判断巷道内移库").Write($"下发堆垛机任务失败,原因:{result.Message}", $"生成移库任务:GenerateTransferTask"); return content.Error(); } } var CuttTransferTask = _taskService.Repository.QueryData(x => x.TaskStatus == (int)RelocationTaskStatusEnum.RelocationNew).FirstOrDefault(); //判断当前是否有移库任务 if (CuttTransferTask!=null) return content.Error(); if (shallowLocation.LocationStatus != (int)LocationStatusEnum.InStock) return content.Error(); //生成移库任务,进行下发 return content =GenerateTransferTask(shallowLocation.LocationCode); } catch (Exception ex) { WriteLog.GetLog("判断巷道内移库").Write($"判断移库失败,原因:{ex.Message}", $"判断巷道内移库方法:JudgmentIsRelocations"); return content.Error(); } } private int judgmentRow(string RoadwayNo,int locrow) { if (RoadwayNo == "1" || RoadwayNo == "3") { return locrow == 1 ? 2 : 3; } else if (RoadwayNo == "2" || RoadwayNo == "4") { return locrow == 5 ? 6 : 7; } else { return 0; } } public WebResponseContent GenerateTransferTask(string shallowLocation) { WebResponseContent webResponse=new WebResponseContent(); try { Dt_LocationInfo OriginalLocation = _locationInfoService.Repository.QueryData(x => x.LocationCode == shallowLocation).FirstOrDefault(); Dt_StockInfo dt_StockInfo = _stockInfoService.Repository.QueryData(x => x.LocationCode == shallowLocation).FirstOrDefault(); Dt_LocationInfo newLocation = _locationInfoService.GetLocation(OriginalLocation.RoadwayNo, OriginalLocation.LocationType); List dt_Locations = new List(); MES_parameter mES_Parame = _taskService.ApplicationChangeStorageLocation(dt_StockInfo.PalletCode, OriginalLocation.LocationCode, newLocation.LocationCode); if (mES_Parame != null) { if (mES_Parame.Result == "Y") { //进行生成任务,下发任务至MES Dt_Task task = new Dt_Task(); task.TaskNum = "0"; task.PalletCode = dt_StockInfo.PalletCode; task.PalletType = dt_StockInfo.PalletType; task.Roadway = OriginalLocation.RoadwayNo; task.TaskType = (int)TaskTypeEnum.Relocation; task.TaskStatus = (int)RelocationTaskStatusEnum.RelocationNew; task.SourceAddress = OriginalLocation.LocationCode; task.TargetAddress = newLocation.LocationCode; task.CurrentAddress = OriginalLocation.LocationCode; task.NextAddress = newLocation.LocationCode; task.WarehouseId = OriginalLocation.WarehouseId; task.OrderNo = ""; task.Grade = 1; task.Creater = "MES"; task.CreateDate = DateTime.Now; OriginalLocation.LocationStatus = (int)LocationStatusEnum.Lock; newLocation.LocationStatus = (int)LocationStatusEnum.Lock; dt_StockInfo.StockStatus = (int)StockStatusEmun.移库锁定; dt_Locations.Add(OriginalLocation); dt_Locations.Add(newLocation); _unitOfWorkManage.BeginTran(); _taskService.AddData(task); _locationInfoService.UpdateData(dt_Locations); _stockInfoService.UpdateData(dt_StockInfo); _unitOfWorkManage.CommitTran(); return webResponse.Error("已生成移库任务"); //进行下发给堆垛机任务 /*WCSginseng result = _taskService.SC_IssueTasks( task.TaskId, int.Parse(task.Roadway), task.TaskNum, task.PalletCode, int.Parse(task.PalletType), task.CurrentAddress, task.NextAddress, task.TargetAddress); if (result.IsSuccess) { task.TaskStatus = (int)RelocationTaskStatusEnum.RelocationExecuting; _taskService.UpdateData(task); return webResponse.OK(); } else { WriteLog.GetLog("判断巷道内移库").Write($"下发堆垛机任务失败,原因:{result.Message}", $"生成移库任务:GenerateTransferTask"); return webResponse.Error(); }*/ } else { WriteLog.GetLog("判断巷道内移库").Write($"申请储位异动,MES不允许移动", $"生成移库任务:GenerateTransferTask"); return webResponse.Error(); } } else { WriteLog.GetLog("判断巷道内移库").Write($"申请储位异动,MES返回为空", $"生成移库任务:GenerateTransferTask"); return webResponse.Error(); } } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); WriteLog.GetLog("判断巷道内移库").Write($"生成移库任务失败:{ex.Message}", $"生成移库任务:GenerateTransferTask"); return webResponse.Error(); } } } }