#region << 版 本 注 释 >> /*---------------------------------------------------------------- * 命名空间:WIDESEAWCS_TaskInfoService * 创建者:胡童庆 * 创建时间:2024/8/2 16:13:36 * 版本:V1.0.0 * 描述: * * ---------------------------------------------------------------- * 修改人: * 修改时间: * 版本:V1.0.1 * 修改说明: * *----------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using AutoMapper; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using RYB_PTL_API; using SqlSugar; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.DirectoryServices.Protocols; using System.Linq; using System.Net.Http.Headers; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using WIDESEA_DTO.Agv; using WIDESEA_External.Model; using WIDESEAWCS_BasicInfoService; using WIDESEAWCS_Common; using WIDESEAWCS_Common.APIEnum; using WIDESEAWCS_Common.Helper; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.BaseRepository; using WIDESEAWCS_Core.BaseServices; using WIDESEAWCS_Core.Enums; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_Core.LogHelper; using WIDESEAWCS_DTO; using WIDESEAWCS_DTO.Agv; using WIDESEAWCS_DTO.TaskInfo; using WIDESEAWCS_IBasicInfoRepository; using WIDESEAWCS_IBasicInfoService; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Repository; using WIDESEAWCS_QuartzJob.Service; using ICacheService = WIDESEAWCS_Core.Caches.ICacheService; namespace WIDESEAWCS_TaskInfoService { public partial class TaskService : ServiceBase, ITaskService { private readonly IMapper _mapper; private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly ICacheService _cacheService; private readonly IRouterService _routerService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository; private readonly IStationMangerRepository _stationMangerRepository; private readonly IRouterRepository _routerRepository; private readonly IApiInfoRepository _apiInfoRepository; private readonly ILocationInfoRepository _locationInfoRepository; private readonly ILocationInfoService _locationInfoService; private readonly ILocationStatusChangeRecordService _locationStatusChangeRecordService; private readonly IErrorInfoRepository _errorInfoRepository; private Dictionary _taskOrderBy = new() { {nameof(Dt_Task.Grade),OrderByType.Desc }, {nameof(Dt_Task.TaskNum),OrderByType.Asc}, {nameof(Dt_Task.CreateDate),OrderByType.Asc}, }; public Dictionary TaskOrderBy { get { return _taskOrderBy; } set { _taskOrderBy = value; } } public List TaskInboundTypes => typeof(TaskTypeEnum).GetEnumIndexList().Where(x => x >= 500 && x < 900).ToList(); public List TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList().Where(x => x >= 100 && x < 500).ToList(); public List TaskRelocationTypes => typeof(TaskTypeEnum).GetEnumIndexList().Where(x => x >= 900 && x < 1000).ToList(); public TaskService(ITaskRepository BaseDal, IMapper mapper, ICacheService cacheService, IRouterService routerService, ITaskExecuteDetailService taskExecuteDetailService, ITaskExecuteDetailRepository taskExecuteDetailRepository, IStationMangerRepository stationMangerRepository, IRouterRepository routerRepository, IApiInfoRepository apiInfoRepository, ILocationInfoRepository locationInfoRepository, IUnitOfWorkManage unitOfWorkManage, ILocationInfoService locationInfoService, ILocationStatusChangeRecordService locationStatusChangeRecordService, IErrorInfoRepository errorInfoRepository) : base(BaseDal) { _mapper = mapper; _cacheService = cacheService; _routerService = routerService; _taskExecuteDetailService = taskExecuteDetailService; _taskExecuteDetailRepository = taskExecuteDetailRepository; _stationMangerRepository = stationMangerRepository; _routerRepository = routerRepository; _apiInfoRepository = apiInfoRepository; _locationInfoRepository = locationInfoRepository; _unitOfWorkManage = unitOfWorkManage; _locationInfoService = locationInfoService; _locationStatusChangeRecordService = locationStatusChangeRecordService; _errorInfoRepository = errorInfoRepository; } static object lock_taskReceive = new object(); /// /// 接收WMS任务信息 /// /// WMS任务对象集合 /// 返回处理结果 public WMSReceiveTaskContent ReceiveWMSTask([NotNull] WMSTaskDTO taskDTO) { WMSReceiveTaskContent content = new WMSReceiveTaskContent(); string errorMsg = ""; try { lock (lock_taskReceive) { WriteLog.Write_Log("入库任务下发", "WMS入库任务接收参数", "接收参数", $"参数:{taskDTO.ToJson()}"); List tasks = new List(); List taskOlds = BaseDal.QueryData(x => taskDTO.Tasks.Select(x => x.TaskDescribe.ContainerCode).Contains(x.PalletCode)); List locationInfos = _locationInfoRepository.GetCanOut(taskDTO.Tasks.Select(x => x.TaskDescribe.ContainerCode).ToList()); List stationMangers = _stationMangerRepository.QueryData(); ////下发任务组 //string taskGroup= taskDTO.TaskGroupCode.IsNullOrEmpty() ? Guid.NewGuid().ToString().Replace("-","") : taskDTO.TaskGroupCode; foreach (var item in taskDTO.Tasks.OrderBy(x => x.TaskDescribe.ToStationCode)) { if (item.TaskDescribe.ToStationCode.IsNullOrEmpty()) throw new Exception($"任务{item.TaskCode}出库目标操作台不能为空"); //获取操作台 Dt_StationManger? stationManger = stationMangers.FirstOrDefault(x => x.PickStationCode == item.TaskDescribe.ToStationCode); if (stationManger == null) throw new Exception($"任务{item.TaskCode}出库目标操作台{item.TaskDescribe.ToStationCode}不存在"); Dt_Task? taskOld = taskOlds.FirstOrDefault(x => x.PalletCode == item.TaskDescribe.ContainerCode); if (taskOld != null) { errorMsg += $"料箱{taskOld.PalletCode}" + (taskOld.TaskType == TaskTypeEnum.Inbound.ObjToInt() ? "入库任务已存在;" : "出库任务已存在;"); content.FailData.Add(new BinCodeObj() { Bincode = item.TaskDescribe.ContainerCode }); continue; } Dt_LocationInfo? locationInfo = locationInfos.FirstOrDefault(x => x.PalletCode == item.TaskDescribe.ContainerCode); if (locationInfo == null) { errorMsg += $"料箱{item.TaskDescribe.ContainerCode}不存在;"; content.FailData.Add(new BinCodeObj() { Bincode = item.TaskDescribe.ContainerCode }); continue; } Dt_LocationInfo? noOutLocation = locationInfos.FirstOrDefault(x => (x.LocationStatus != LocationStatusEnum.InStock.ObjToInt() || x.EnableStatus != EnableStatusEnum.Normal.ObjToInt()) && x.PalletCode == item.TaskDescribe.ContainerCode); if (noOutLocation != null) { errorMsg += $"料箱{noOutLocation.PalletCode}货位{noOutLocation.LocationCode}状态不可出库"; content.FailData.Add(new BinCodeObj() { Bincode = noOutLocation.PalletCode }); continue; } Dt_Task task = _mapper.Map(item); task.SourceAddress = locationInfo.LocationCode; task.CurrentAddress = locationInfo.LocationCode; task.NextAddress = stationManger.PickStationCode; task.TargetAddress = stationManger.PickStationCode; //task.GroupId = taskGroup; task.TaskType = TaskTypeEnum.Outbound.ObjToInt(); task.Roadway = locationInfo.RoadwayNo; task.DeviceCode = stationManger.CraneCode; task.TaskState = TaskStatusEnum.AGV_Execute.ObjToInt(); tasks.Add(task); content.SucessData.Add(new BinCodeObj() { Bincode = item.TaskDescribe.ContainerCode }); } locationInfos.ForEach(x => { x.LocationStatus = LocationStatusEnum.Lock.ObjToInt(); }); //添加任务更新货位数据 _unitOfWorkManage.BeginTran(); BaseDal.AddData(tasks); _locationInfoRepository.UpdateData(locationInfos); _unitOfWorkManage.CommitTran(); _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "接收WMS任务"); if (tasks.Count > 0) { _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfos, LocationStatusEnum.InStock, LocationStatusEnum.Lock, LocationChangeType.OutboundAssignLocation, tasks); } content.OK(errorMsg.IsNullOrEmpty() ? "成功" : errorMsg); } } catch (Exception ex) { content.Error($"任务接收错误,错误信息:{ex.Message}"); } return content; } /// /// 容器入库创建任务 /// /// public WebResponseContent ContainerFlow(ContainerFlowDTO containerFlowDTO, string deviceCode, string stationCode, int type = 0) { WebResponseContent content = new WebResponseContent(); try { List locationInfos = _locationInfoRepository.QueryData(); Dt_LocationInfo? locationInfo = locationInfos.FirstOrDefault(x => x.PalletCode == containerFlowDTO.ContainerCode); if (locationInfo != null) throw new Exception($"库位料箱号{containerFlowDTO.ContainerCode}已存在"); Dt_Task taskOld = BaseDal.QueryFirst(x => x.PalletCode == containerFlowDTO.ContainerCode); if (taskOld != null && taskOld.PalletCode == containerFlowDTO.ContainerCode && taskOld.TaskType == TaskTypeEnum.Inbound.ObjToInt() && taskOld.TaskState == TaskStatusEnum.CL_Executing.ObjToInt() && taskOld.DeviceCode == deviceCode) { Thread.Sleep(500); return content.OK(); } if (taskOld != null && taskOld.PalletCode == containerFlowDTO.ContainerCode && taskOld.TaskType == TaskTypeEnum.Inbound.ObjToInt() && taskOld.TaskState == TaskStatusEnum.CL_Executing.ObjToInt() && taskOld.DeviceCode != deviceCode) { Dt_StationManger stationOld = _stationMangerRepository.QueryFirst(x => x.StationType == StationTypeEnum.StationType_OnlyInbound.ObjToInt() && x.StationDeviceCode == deviceCode); string oldSlotCode = taskOld.SourceAddress; taskOld.SourceAddress = containerFlowDTO.SlotCode; taskOld.CurrentAddress = containerFlowDTO.SlotCode; taskOld.NextAddress = stationOld.StationCode; taskOld.DeviceCode = stationOld.StationDeviceCode; //更新任务 BaseDal.UpdateData(taskOld); _taskExecuteDetailService.AddTaskExecuteDetail(new List() { taskOld.TaskNum }, $"{oldSlotCode}换至{containerFlowDTO.SlotCode}入库"); return content.OK(); } else if (taskOld != null) { throw new Exception($"料箱号{containerFlowDTO.ContainerCode}" + (taskOld.TaskType == TaskTypeEnum.Inbound.ObjToInt() ? "入库AGV执行中" : "出库AGV执行中")); } Dt_LocationInfo? noInLocation = locationInfos.FirstOrDefault(x => x.LocationStatus == LocationStatusEnum.Free.ObjToInt() && x.EnableStatus == EnableStatusEnum.Normal.ObjToInt()); if (noInLocation == null) throw new Exception($"可用货位不足!"); Dt_StationManger stationManger = _stationMangerRepository.QueryFirst(x => x.StationType == StationTypeEnum.StationType_OnlyInbound.ObjToInt() && x.StationDeviceCode == deviceCode); //创建任务 Dt_Task task = new Dt_Task(); task.PalletCode = containerFlowDTO.ContainerCode; task.SourceAddress = containerFlowDTO.SlotCode; task.CurrentAddress = containerFlowDTO.SlotCode; task.NextAddress = stationManger.StationCode; task.TargetAddress = ""; task.WMSId = ""; task.TaskType = TaskTypeEnum.Inbound.ObjToInt(); task.Roadway = noInLocation.RoadwayNo; task.DeviceCode = stationManger.StationDeviceCode; task.TaskState = TaskStatusEnum.CL_Executing.ObjToInt(); //添加任务 int taskId = BaseDal.AddData(task); if (type > 0) { _taskExecuteDetailService.AddTaskExecuteDetail(new List() { task.TaskNum }, "手动按钮入库"); } else { _taskExecuteDetailService.AddTaskExecuteDetail(new List() { task.TaskNum }, "创建入库任务"); } WriteLog.Write_Log("入库任务下发", "容器入库任务添加任务", "添加任务", $"任务:{task.ToJson()}"); content.OK("成功"); } catch (Exception ex) { content.Error($"错误信息:{ex.Message}"); } return content; } /// /// 播种墙初始化 /// /// public WebResponseContent InitLight() { WebResponseContent content = new WebResponseContent(); try { EPLightContent lightContent = INITIALIZATION(); if (lightContent.Result != "0") throw new Exception($"{lightContent.Msg}"); content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 结束作业 /// /// public WebResponseContent EndLight() { WebResponseContent content = new WebResponseContent(); try { EPLightContent lightContent = ENDWORK(); if (lightContent.Result != "0") throw new Exception($"{lightContent.Msg}"); content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 一期播种墙下发 /// /// public EPLightContent Phase1PickOrderInfoRequest(List lightSendDTOs) { EPLightContent content = new EPLightContent(); try { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.Phase1PickOrderInfoRequest.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { return content.Error("未找到播种墙下发接口,请检查接口配置"); } bool allSuccess = true; StringBuilder errorMessages = new StringBuilder(); foreach (EPLightSendDTO lightSendDTO in lightSendDTOs) { try { bool operationResult; // 处理灯光类型转换 if (!int.TryParse(lightSendDTO.LIGHTTYPE, out int lightType)) { allSuccess = false; errorMessages.AppendLine($"位置 {lightSendDTO.LOCATION} 错误: 无效的灯光类型 '{lightSendDTO.LIGHTTYPE}'"); continue; } // 处理关闭灯光请求 if (lightType == 2) { operationResult = RYB_PTL.RYB_PTL_CloseDigit5(url, lightSendDTO.LOCATION); // TODO: 关闭灯光回调处理 //List lightBackDTOs = new List(); //List taskBackLights = lightSendDTOs.Select(x => new TaskBackLight() //{ // TagNo = "B1", // TagCode = x.LOCATION, //}).ToList(); //content = WMSLightBack(taskBackLights); } // 处理显示灯光请求 else { // 处理灯光颜色转换 if (!int.TryParse(lightSendDTO.LIGHTCOLOR, out int lightColor)) { allSuccess = false; errorMessages.AppendLine($"位置 {lightSendDTO.LOCATION} 错误: 无效的灯光颜色 '{lightSendDTO.LIGHTCOLOR}'"); continue; } operationResult = RYB_PTL.RYB_PTL_DspDigit5( url, lightSendDTO.LOCATION, lightSendDTO.QUANTITY, lightType, lightColor); } if (!operationResult) { allSuccess = false; errorMessages.AppendLine($"位置 {lightSendDTO.LOCATION} 操作失败"); } } catch (Exception ex) { allSuccess = false; errorMessages.AppendLine($"位置 {lightSendDTO.LOCATION} 处理异常: {ex.Message}"); } } return allSuccess ? content.OK("所有播种墙下发操作成功") : content.Error(errorMessages.ToString()); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 播种墙亮灯 /// /// public WebResponseContent SendLight(TaskSendLight taskSendLight) { WebResponseContent content = new WebResponseContent(); try { if (taskSendLight.TagNo == "B1") { List lightSendDTOs = new List() { new EPLightSendDTO { DOCNO = taskSendLight.DocNo, TASKNO= taskSendLight.TaskNo, LOCATION=taskSendLight.TagCode, QUANTITY=taskSendLight.TagQunity, LIGHTCOLOR=taskSendLight.Color switch { "Blue" => "4", "Green" => "2", "Red" => "1", _ => throw new Exception($"未找到颜色定义") }, ORDERTYPE="1", LIGHTTYPE=taskSendLight.Mode.ToString(), } }; EPLightContent pLightContent = Phase1PickOrderInfoRequest(lightSendDTOs); if (pLightContent.Result != "0") throw new Exception($"{pLightContent.Msg}"); content.OK(); } else if (taskSendLight.TagNo == "B2") { List lightSendDTOs = new List() { new EPLightSendDTO { DOCNO = taskSendLight.DocNo, TASKNO= taskSendLight.TaskNo, LOCATION=taskSendLight.TagCode, QUANTITY=taskSendLight.TagQunity, LIGHTCOLOR=taskSendLight.Color switch { "Blue" => "1", "Green" => "2", "Red" => "4", _ => throw new Exception($"未找到颜色定义") }, ORDERTYPE="1", LIGHTTYPE=taskSendLight.Mode.ToString(), } }; EPLightContent pLightContent = PickOrderInfoRequest(lightSendDTOs); if (pLightContent.Result != "0") throw new Exception($"{pLightContent.Msg}"); content.OK(); } else { content.OK(); } } catch (Exception ex) { content.Error(ex.Message); } return content; } static object lock_requestInTask = new object(); /// /// 申请入库 /// /// public WebResponseContent RequestInTask(string stationCode, string barCode) { WebResponseContent content = new WebResponseContent(); try { lock (lock_requestInTask) { Dt_Task task = BaseDal.QueryFirst(x => x.PalletCode == barCode && x.TaskType == TaskTypeEnum.Inbound.ObjToInt() && x.NextAddress == stationCode && x.TaskState == TaskStatusEnum.CL_Executing.ObjToInt()); if (task == null) throw new Exception($"{barCode}料箱未找到任务!"); Dt_LocationInfo? locationInfo = _locationInfoService.AssignLocation(); if (locationInfo == null) throw new Exception($"可用货位不足!"); task.NextAddress = locationInfo.LocationCode; task.TargetAddress = locationInfo.LocationCode; task.CurrentAddress = stationCode; task.DeviceCode = "AGV"; task.TaskState = TaskStatusEnum.AGV_Execute.ObjToInt(); locationInfo.LocationStatus = LocationStatusEnum.Lock.ObjToInt(); //更新任务和货位数据 _unitOfWorkManage.BeginTran(); BaseDal.UpdateData(task); _locationInfoRepository.UpdateData(locationInfo); _unitOfWorkManage.CommitTran(); _taskExecuteDetailService.AddTaskExecuteDetail(new List() { task.TaskNum }, $"分配货位{locationInfo.LocationCode}"); _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, LocationStatusEnum.Free, LocationStatusEnum.Lock, LocationChangeType.InboundAssignLocation, task.TaskNum); WriteLog.Write_Log("入库任务下发", "申请入库接口", "更新任务", $"任务:{task.ToJson()}"); content.OK("成功"); } } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error($"错误信息:{ex.Message}"); } return content; } public static string Post(string serviceAddress, string requestJson = "", string contentType = "application/json", Dictionary? headers = null) { string result = string.Empty; DateTime beginDate = DateTime.Now; try { using (HttpContent httpContent = new StringContent(string.Empty)) { httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); using HttpClient httpClient = new HttpClient(); httpClient.Timeout = new TimeSpan(0, 0, 30); HttpResponseMessage responseMessage = httpClient.PostAsync(serviceAddress, httpContent).Result; result = responseMessage.Content.ReadAsStringAsync().Result; } return result; } catch (Exception e) { throw new Exception(e.Message); } finally { Logger.Add(serviceAddress, requestJson == null ? "" : requestJson, result, beginDate); } } /// /// 更新任务异常信息显示 /// /// 任务号 /// 异常信息 public WebResponseContent UpdateTaskExceptionMessage(int taskNum, string message) { WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); task.TaskState = (int)TaskStatusEnum.Pending; task.ExceptionMessage = message; task.ModifyDate = DateTime.Now; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task, task.ExceptionMessage); WriteLog.Write_Log("更新任务异常信息", "更新任务接口", "更新任务", $"任务:{task.ToJson()}"); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 恢复挂起任务 /// /// 任务号 /// 返回处理结果 public WebResponseContent TaskStatusRecovery(int taskNum) { WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); if (task.TaskState != (int)TaskStatusEnum.Pending) { return content = WebResponseContent.Instance.Error($"该任务状态不可恢复,任务号:【{taskNum}】,任务状态:【{task.TaskState}】"); } Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.IsNormal, new Dictionary { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } }); if (taskExecuteDetail != null) { task.TaskState = taskExecuteDetail.TaskState; } else { task.TaskState = (int)TaskStatusEnum.New; } task.ExceptionMessage = string.Empty; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task, $"人工恢复挂起任务,恢复挂起时任务状态【{task.TaskState}】"); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 回滚任务状态 /// /// 任务号 /// 返回处理结果 public WebResponseContent RollbackTaskStatusToLast(int taskNum) { WebResponseContent content = new(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); int oldState = task.TaskState; Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.TaskState < task.TaskState && x.TaskState > 0, new Dictionary { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } }); if (taskExecuteDetail != null) { task.TaskState = taskExecuteDetail.TaskState; task.CurrentAddress = taskExecuteDetail.CurrentAddress; task.NextAddress = taskExecuteDetail.NextAddress; } else { return content = WebResponseContent.Instance.Error($"未找到任务明细信息,该任务状态不可回滚到上一步,任务号:【{taskNum}】,任务状态:【{task.TaskState}】"); } task.ExceptionMessage = string.Empty; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task, $"人工将任务状态从【{oldState}】回滚到【{task.TaskState}】"); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 接受WMS手动完成任务 /// /// /// public WebResponseContent RecWMSTaskCompleted(int taskNum) { try { WriteLog.Write_Log("接受WMS手动完成任务", "接受WMS手动完成任务接口", "任务号", $"任务号:{taskNum}"); Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task != null) { task.TaskState = TaskStatusEnum.Finish.ObjToInt(); BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工完成); } return WebResponseContent.Instance.OK(); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// AGV任务放行 /// /// public WebResponseContent AgvTaskFlow(string code) { WebResponseContent content = new WebResponseContent(); try { WriteLog.Write_Log("AGV任务放行", "AGV任务放行接口", "料箱号", $"料箱:{code}"); string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.AgvTaskFlow.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) throw new Exception($"{code},未找到AGV任务放行接口,请检查接口配置"); AgvTaskFlowDTO agvTaskFlowDTO = new AgvTaskFlowDTO() { RequestId = Guid.NewGuid().ToString().Replace("-", ""), MissionCode = code }; string request = JsonConvert.SerializeObject(agvTaskFlowDTO, settings); string response = HttpHelper.Post(url, request); WriteLog.Write_Log("AGV任务放行接口请求AGV", "AGV任务放行接口", $"请求:{request},回传:{response}"); AgvResponseContent agvResponse = JsonConvert.DeserializeObject(response) ?? throw new Exception($"{code},未接收到AGV任务放行返回值"); if (!agvResponse.Success) throw new Exception($"料箱{code},AGV任务放行错误,信息:{agvResponse.Message}"); content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// WMS料箱到达拣选位上报 /// /// public WebResponseContent WMSPickUp(string stationCode, string pickCode) { WebResponseContent content = new WebResponseContent(); try { WriteLog.Write_Log("WMS料箱到达拣选位上报", "WMS料箱到达拣选位上报成接口", "信息", $"拣选位:{stationCode},料箱:{pickCode}"); string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMSPickArrivedUp.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) throw new Exception($"未找到WMS料箱到达拣选位上报接口,请检查接口配置"); ContainerArriveDTO containerArriveDTO = new ContainerArriveDTO() { SlotCode = stationCode, ContainerCode = pickCode }; string request = JsonConvert.SerializeObject(containerArriveDTO, settings); string response = HttpHelper.Post(url, request); WriteLog.Write_Log("上报WMS料箱到达", "上报WMS料箱到达", "信息", $"请求:{request},回传:{response}"); WMSResponseContent wMSResponse = JsonConvert.DeserializeObject(response) ?? throw new Exception($"{pickCode},未接收到WMS料箱到达拣选位上报返回值"); if (wMSResponse.Code != "0") throw new Exception($"料箱{pickCode}WMS料箱到达拣选位上报错误,信息:{wMSResponse.Msg}"); content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 任务完成 /// /// /// public WebResponseContent TaskCompleted(int taskNum) { WebResponseContent content = new WebResponseContent(); try { WriteLog.Write_Log("任务完成", "任务完成接口", "任务号", $"任务:{taskNum}"); Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)//出库任务完成逻辑 { Dt_LocationInfo locationInfo = _locationInfoRepository.QueryFirst(x => x.PalletCode == task.PalletCode); if (locationInfo.LocationStatus != LocationStatusEnum.Lock.ObjToInt()) { return content.Error($"{locationInfo.LocationCode}货位状态不正确"); } task.TaskState = TaskStatusEnum.Finish.ObjToInt(); locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); locationInfo.PalletCode = ""; //料箱出库完成上报给WMS string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMSInOutBoundBack.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { _taskExecuteDetailService.AddTaskExecuteDetail(task, $"未找到WMS出库上报接口,请检查接口配置"); UpdateTaskExceptionMessage(taskNum, $"未找到WMS出库上报接口,请检查接口配置"); return content.Error($"{taskNum},未找到WMS出库上报接口,请检查接口配置"); } ContainerInFinishDTO containerInFinishDTO = new ContainerInFinishDTO() { TaskCode = task.TaskNum.ToString(), ContainerCode = task.PalletCode, StationCode = task.TargetAddress, LocationCode = task.SourceAddress, CompleteType = 1 }; string request = JsonConvert.SerializeObject(containerInFinishDTO, settings); _unitOfWorkManage.BeginTran(); _locationInfoRepository.UpdateData(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User?.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, LocationStatusEnum.Lock, LocationStatusEnum.Free, LocationChangeType.OutboundCompleted, task.TaskNum); //调用接口 string response = HttpHelper.Post(url, request); WriteLog.Write_Log("WMS出库任务完成回传", "任务完成接口", "任务信息", $"请求:{request},回传:{response}"); WMSResponseContent wMSResponse = JsonConvert.DeserializeObject(response) ?? throw new Exception($"{taskNum},未接收到WMS出库上报返回值"); if (wMSResponse.Code != "0") content.Message = $"出库任务{task.TaskNum}WMS出库上报错误,信息:{wMSResponse.Msg}"; } else if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)//入库任务完成逻辑 { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMSInOutBoundBack.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { _taskExecuteDetailService.AddTaskExecuteDetail(task, $"未找到WMS入库上报接口,请检查接口配置"); UpdateTaskExceptionMessage(taskNum, $"未找到WMS入库上报接口,请检查接口配置"); return content.Error($"{taskNum},未找到WMS入库上报接口,请检查接口配置"); } ContainerInFinishDTO containerInFinishDTO = new ContainerInFinishDTO() { TaskCode = task.TaskNum.ToString(), ContainerCode = task.PalletCode, StationCode = task.SourceAddress, LocationCode = task.TargetAddress, CompleteType = 2 }; string request = JsonConvert.SerializeObject(containerInFinishDTO, settings); Dt_LocationInfo locationInfo = _locationInfoRepository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo.LocationStatus != LocationStatusEnum.Lock.ObjToInt()) { return content.Error($"{locationInfo.LocationCode}货位状态不正确"); } task.TaskState = TaskStatusEnum.Finish.ObjToInt(); locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); locationInfo.PalletCode = task.PalletCode; _unitOfWorkManage.BeginTran(); _locationInfoRepository.UpdateData(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User?.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, LocationStatusEnum.Lock, LocationStatusEnum.InStock, LocationChangeType.InboundCompleted, task.TaskNum); //调用接口 string response = HttpHelper.Post(url, request); WriteLog.Write_Log("WMS入库任务完成回传", "任务完成接口", "任务信息", $"请求:{request},回传:{response}"); WMSResponseContent wMSResponse = JsonConvert.DeserializeObject(response) ?? throw new Exception($"{taskNum},未接收到WMS入库上报返回值"); if (wMSResponse.Code != "0") content.Message = $"入库任务{task.TaskNum}WMS入库上报错误,信息:{wMSResponse.Msg}"; } content.OK("任务完成"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error(ex.Message); } return content; } /// /// 人工手动取消指定任务 /// /// 任务编号 /// 操作结果 public WebResponseContent ManualTaskCancellation(int taskNum) { WebResponseContent content = new WebResponseContent(); try { WriteLog.Write_Log("任务取消接收", "人工手动取消指定任务", "任务号", $"任务:{taskNum}"); // 1. 获取任务信息 Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return content.Error($"任务{taskNum}不存在"); TaskTypeGroup group = task.TaskType.GetTaskTypeGroup(); if (group == TaskTypeGroup.InboundGroup)// 入库任务取消 { // 获取目标货位 Dt_LocationInfo locationInfo = _locationInfoRepository.QueryFirst(x => x.LocationCode == task.TargetAddress); if (locationInfo == null) return content.Error($"目标货位{task.TargetAddress}不存在"); // 验证货位状态 if (locationInfo.LocationStatus != LocationStatusEnum.Lock.ObjToInt()) return content.Error($"{task.TargetAddress}货位状态异常,无法取消"); // 恢复货位状态 locationInfo.LocationStatus = LocationStatusEnum.Free.ObjToInt(); // 恢复为空闲状态 locationInfo.PalletCode = ""; // 清空托盘号 // 更新数据库 _unitOfWorkManage.BeginTran(); _locationInfoRepository.UpdateData(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); _unitOfWorkManage.CommitTran(); // 记录状态变更 _locationStatusChangeRecordService.AddLocationStatusChangeRecord( locationInfo, LocationStatusEnum.Lock, LocationStatusEnum.Free, LocationChangeType.InboundCancelled, task.TaskNum ); content.OK("任务取消成功"); } else { content.Error("只能入库任务取消!"); } } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error($"取消失败: {ex.Message}"); // 记录详细错误 _taskExecuteDetailService.AddTaskExecuteDetail( new Dt_Task { TaskNum = taskNum }, $"任务取消异常: {ex.Message}" ); } return content; } /// /// 任务取消 /// /// public WebResponseContent TaskCancelCompleted(int taskNum) { WebResponseContent content = new WebResponseContent(); try { WriteLog.Write_Log("任务取消接收", "任务取消接口", "任务号", $"任务:{taskNum}"); Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task != null && task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)//出库任务完成逻辑 { Dt_LocationInfo locationInfo = _locationInfoRepository.QueryFirst(x => x.PalletCode == task.PalletCode); if (locationInfo.LocationStatus != LocationStatusEnum.Lock.ObjToInt()) { return content.Error($"{locationInfo.LocationCode}货位状态不正确"); } task.TaskState = TaskStatusEnum.Cancel.ObjToInt(); locationInfo.LocationStatus = LocationStatusEnum.InStock.ObjToInt(); _unitOfWorkManage.BeginTran(); _locationInfoRepository.UpdateData(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User?.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); _locationStatusChangeRecordService.AddLocationStatusChangeRecord(locationInfo, LocationStatusEnum.Lock, LocationStatusEnum.InStock, LocationChangeType.InboundCompleted, task.TaskNum); content.OK(); } else { content.Error($"未找到出库任务{taskNum}"); } } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 任务取消 /// /// public WebResponseContent TaskCancel(List taskCancels) { WebResponseContent content = new WebResponseContent(); try { // 参数验证 if (taskCancels == null || taskCancels.Count == 0) { return content.Error("传入参数不能为空"); } WriteLog.Write_Log("任务取消接收", "任务取消接口", "任务取消", $"任务:{taskCancels.ToJson()}"); // 获取所有出库任务(只查询一次) List outTasks = BaseDal.QueryData(x => x.TaskType == TaskTypeEnum.Outbound.ObjToInt()); if (outTasks.Count == 0) { return content.Error("未找到对应的任务"); } // 按GroupId分组处理 var tasksByGroup = outTasks.GroupBy(x => x.GroupId) .Where(g => !string.IsNullOrEmpty(g.Key)) .ToDictionary(g => g.Key, g => g.ToList()); List cancelTasks = new List(); List cancelTasksCompleted = new List(); // 收集所有需要检查的任务组 var groupsToCheck = new List>(); foreach (var taskCancel in taskCancels) { // 找到该任务所在的组 var group = tasksByGroup.Values.FirstOrDefault(g => g.Any(t => t.PalletCode == taskCancel.ContainerCode)); if (group != null && !groupsToCheck.Contains(group)) { groupsToCheck.Add(group); } } // 验证任务状态 foreach (var group in groupsToCheck) { var firstTask = group.FirstOrDefault(); if (firstTask == null) continue; // 检查组内所有任务状态 foreach (var task in group) { if (task.TaskState == TaskStatusEnum.AGV_TakeFinish.ObjToInt()) { task.IsCancel = 1; cancelTasks.Add(task); } else if (task.TaskState == TaskStatusEnum.AGV_Executing.ObjToInt()) { cancelTasksCompleted.Add(task); } else { return content.Error($"任务取消失败{task.PalletCode}任务状态不可取消!"); } } } //WriteLog.Write_Log("任务取消接收", "任务取消接口", "任务取消", $"任务:{taskCancels.ToJson()}"); //if (taskCancels==null || taskCancels.Count<=0) //{ // return content.Error("传入不能为空"); //} ////获取所有料箱 //List outTasks = BaseDal.QueryData(x=>x.TaskType==TaskTypeEnum.Outbound.ObjToInt()); //List cancelTasks = new List(); //List cancelTasksCompleted = new List(); //HashSet processedGroups = new HashSet(); ////判断是否有任务存在 //foreach (var item in taskCancels) //{ // Dt_Task? taskExist = outTasks.FirstOrDefault(x=>x.PalletCode == item.ContainerCode); // if (taskExist==null) // { // content.Message += $"{item.ContainerCode}任务不存在"; // WriteLog.Write_Log("任务取消接收", "任务取消接口", "任务不存在", $"任务:{item.ContainerCode}"); // continue; // } // if (string.IsNullOrEmpty(taskExist.GroupId)) // { // continue; // } // processedGroups.Add(taskExist.GroupId); // //if (taskExist.TaskState == TaskStatusEnum.AGV_TakeFinish.ObjToInt()) // //{ // // taskExist.IsCancel = 1; // // cancelTasks.Add(taskExist); // //} // //else if(taskExist.TaskState == TaskStatusEnum.AGV_Executing.ObjToInt()) // //{ // // cancelTasksCompleted.Add(taskExist); // //} // //else // //{ // // return content.Error($"任务取消失败{item.TaskCode}任务状态不可取消!"); // //} //} //// 取消整个组 //foreach(var processed in processedGroups) //{ // List groupTask = BaseDal.QueryData(x => x.TaskType == TaskTypeEnum.Outbound.ObjToInt() && x.GroupId == processed); // foreach (var group in groupTask) // { // if (group.TaskState == TaskStatusEnum.AGV_TakeFinish.ObjToInt()) // { // group.IsCancel = 1; // cancelTasks.Add(group); // } // else if (group.TaskState == TaskStatusEnum.AGV_Executing.ObjToInt()) // { // cancelTasksCompleted.Add(group); // } // else // { // return content.Error($"任务取消失败{group.PalletCode}任务状态不可取消!"); // } // } //} _unitOfWorkManage.BeginTran(); BaseDal.UpdateData(cancelTasks); foreach (var item in cancelTasksCompleted) { WebResponseContent responseContent = TaskCancelCompleted(item.TaskNum); if (!responseContent.Status) { throw new Exception(responseContent.Message); } } _unitOfWorkManage.CommitTran(); cancelTasks.AddRange(cancelTasksCompleted); foreach (var item in cancelTasks) { AgvTaskCancelDTO agvTaskCancel = new AgvTaskCancelDTO() { RequestId = DateTime.Now.ToString("yyMMddHHmmssfff"), MissionCode = item.GroupId, ContainerCode = item.PalletCode, Position = "", CancelMode = "CTU_REDIRECT_START", Reason = "" }; AgvCancelTask(agvTaskCancel); } content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 二期播种墙回传 /// /// public EPLightContent WMSLightBack(List taskBackLights) { EPLightContent content = new EPLightContent(); try { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMSLightBack.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { return content.Error($"未找到播种墙上报,请检查接口配置"); } string request = JsonConvert.SerializeObject(taskBackLights, settings); string response = HttpHelper.Post(url, request); WMSResponseContent wMSResponse = JsonConvert.DeserializeObject(response) ?? throw new Exception($"未接收到播种墙上报返回值"); if (wMSResponse.Code != "0") throw new Exception($"播种墙上报错误,信息:{wMSResponse.Msg}"); content.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 二期播种墙下发 /// /// public EPLightContent PickOrderInfoRequest(List lightSendDTOs) { EPLightContent content = new EPLightContent(); try { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.PickOrderInfoRequest.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { return content.Error($"未找到播种墙下发接口,请检查接口配置"); } string request = JsonConvert.SerializeObject(lightSendDTOs, settings).ToUpper(); // 调用接口 string response = HttpHelper.Post(url, request); EPLightContent lightContent = JsonConvert.DeserializeObject(response) ?? throw new Exception($"未接收到播种墙下发上报返回值"); if (lightContent.Result != "0") throw new Exception($"播种墙下发错误,信息:{lightContent.Msg}"); content.OK("成功"); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 二期播种墙初始化 /// /// /// public EPLightContent INITIALIZATION() { EPLightContent content = new EPLightContent(); try { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.INITIALIZATION.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { return content.Error($"未找到播种墙初始化接口,请检查接口配置"); } //调用接口 string response = Post(url); EPLightContent lightContent = JsonConvert.DeserializeObject(response) ?? throw new Exception($"未接收到播种墙初始化上报返回值"); if (lightContent.Result != "0") throw new Exception($"播种墙初始化错误,信息:{lightContent.Msg}"); content.OK("成功"); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 二期播种墙结束作业 /// /// /// public EPLightContent ENDWORK() { EPLightContent content = new EPLightContent(); try { string? url = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.ENDWORK.ToString())?.ApiAddress; if (string.IsNullOrEmpty(url)) { return content.Error($"未找到播种墙结束作业接口,请检查接口配置"); } //调用接口 string response = Post(url); EPLightContent lightContent = JsonConvert.DeserializeObject(response) ?? throw new Exception($"未接收到播种墙结束作业上报返回值"); if (lightContent.Result != "0") throw new Exception($"播种墙结束作业错误,信息:{lightContent.Msg}"); content.OK("成功"); } catch (Exception ex) { content.Error(ex.Message); } return content; } public override WebResponseContent Export(PageDataOptions options) { WebResponseContent content = new WebResponseContent(); try { string savePath = AppDomain.CurrentDomain.BaseDirectory + "ExcelExport"; // 确保目录存在 if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath); // 获取数据 ISugarQueryable query = BaseDal.Db.Queryable(); var dataList = query.ToList(); var properties = typeof(Dt_Task).GetProperties(); string filePath = TExportHelper.GetExport(savePath, properties, dataList); return WebResponseContent.Instance.OK(data: filePath); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 重置所有异常任务 /// public WebResponseContent ResetAllExceptionTask(int taskNum) { // 获取异常任务990修改为AGV待执行300 WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); if (task.TaskState != (int)TaskStatusEnum.Exception) { return content = WebResponseContent.Instance.Error($"该任务状态不可重置,任务号:【{taskNum}】,任务状态:【{task.TaskState}】"); } task.TaskState = (int)TaskStatusEnum.AGV_Execute; BaseDal.UpdateData(task); //_taskExecuteDetailService.AddTaskExecuteDetail(task, $"人工重置异常任务,重置后任务状态【{task.TaskState}】"); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content.Error(ex.Message); } return content; } public WebResponseContent WmsRecovery() { WebResponseContent content = new WebResponseContent(); try { // 删除第一个异常 // 按创建时间升序获取第一条记录 var orderBy = new Dictionary { { "CreateDate", OrderByType.Asc } }; Dt_ErrorInfo errorInfo = _errorInfoRepository.QueryFirst(x => true, orderBy); if (errorInfo == null) { return content.Error("当前没有异常任务"); } // 获取第一个异常(按创建时间排序) _unitOfWorkManage.BeginTran(); _errorInfoRepository.DeleteData(errorInfo); _unitOfWorkManage.CommitTran(); // 上报恢复 string? apiErrorBack = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.WMSErrorBack.ToString())?.ApiAddress; if (string.IsNullOrEmpty(apiErrorBack)) throw new Exception($"未找到WMS故障上报,请检查接口配置"); TaskError taskError = new TaskError() { MsgID = errorInfo.Id, StationCode = errorInfo.StationCode, MsgCode = 0, Msg = "恢复" }; string reqErrorBack = JsonConvert.SerializeObject(taskError, settings); HttpHelper.Post(apiErrorBack, reqErrorBack); return content.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content.Error(ex.Message); throw new Exception(ex.Message); } } } }