#region << 版 本 注 释 >> /*---------------------------------------------------------------- * 命名空间:WIDESEAWCS_TaskInfoService * 创建者:胡童庆 * 创建时间:2024/8/2 16:13:36 * 版本:V1.0.0 * 描述: * * ---------------------------------------------------------------- * 修改人: * 修改时间: * 版本:V1.0.1 * 修改说明: * *----------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using MapsterMapper; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using SqlSugar; using System.Diagnostics.CodeAnalysis; using WIDESEA_Core; using WIDESEAWCS_Common.HttpEnum; using WIDESEAWCS_Common.TaskEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.BaseServices; using WIDESEAWCS_Core.Enums; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_DTO; using WIDESEAWCS_DTO.Stock; using WIDESEAWCS_DTO.TaskInfo; using WIDESEAWCS_ITaskInfoRepository; using WIDESEAWCS_ITaskInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; using WIDESEAWCS_QuartzJob.Models; using WIDESEAWCS_QuartzJob.Service; namespace WIDESEAWCS_TaskInfoService { public class TaskService : ServiceBase, ITaskService { private readonly IRouterService _routerService; private readonly ITaskExecuteDetailService _taskExecuteDetailService; private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository; private readonly IMapper _mapper; private readonly HttpClientHelper _httpClientHelper; private Dictionary _taskOrderBy = new() { {nameof(Dt_Task.Grade),OrderByType.Desc }, {nameof(Dt_Task.CreateDate),OrderByType.Asc}, }; public Dictionary TaskOrderBy { get { return _taskOrderBy; } set { _taskOrderBy = value; } } public List TaskInboundTypes => typeof(TaskInboundTypeEnum).GetEnumIndexList(); public List TaskOutboundTypes => typeof(TaskOutboundTypeEnum).GetEnumIndexList(); public List TaskRelocationTypes => typeof(TaskRelocationTypeEnum).GetEnumIndexList(); public List TaskRobotTypes => typeof(TaskOtherTypeEnum).GetEnumIndexList(); public TaskService(ITaskRepository BaseDal, IRouterService routerService, ITaskExecuteDetailService taskExecuteDetailService, ITaskExecuteDetailRepository taskExecuteDetailRepository, IMapper mapper, HttpClientHelper httpClientHelper) : base(BaseDal) { _routerService = routerService; _taskExecuteDetailService = taskExecuteDetailService; _taskExecuteDetailRepository = taskExecuteDetailRepository; _mapper = mapper; _httpClientHelper = httpClientHelper; } /// /// 接收WMS任务信息 /// /// WMS任务对象集合 /// 返回处理结果 public WebResponseContent ReceiveWMSTask([NotNull] List taskDTOs) { WebResponseContent content = new WebResponseContent(); try { List tasks = new List(); foreach (var item in taskDTOs) { if (BaseDal.QueryFirst(x => x.TaskNum == item.TaskNum || x.PalletCode == item.PalletCode) != null) { continue; } Dt_Task task = _mapper.Map(item); task.Creater = "WMS"; if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { var taskType = 100; Dt_Router router = _routerService.QueryNextRoute(item.Roadway, item.TargetAddress, taskType); //暂不考虑多路径 if (router != null) { task.TaskStatus = (int)TaskOutStatusEnum.OutNew; task.CurrentAddress = item.SourceAddress; task.NextAddress = router.ChildPosi; } } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup) { Dt_Router routers = _routerService.QueryNextRoute(item.SourceAddress); //暂不考虑多路径 if (!routers.IsNullOrEmpty()) { task.TaskStatus = (int)TaskInStatusEnum.InNew; task.CurrentAddress = item.SourceAddress; task.NextAddress = routers.ChildPosi; } } tasks.Add(task); } BaseDal.AddData(tasks); _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "接收WMS任务"); content = WebResponseContent.Instance.OK("成功", tasks); } catch (Exception ex) { content = WebResponseContent.Instance.Error($"任务接收错误,错误信息:{ex.Message}"); } return content; } /// /// 根据托盘号、起始地址向WMS请求任务 /// /// 托盘号 /// 起始地址 /// public WebResponseContent RequestWMSTask(string palletCode, string sourceAddress) { WebResponseContent content = new WebResponseContent(); try { WMSTaskDTO taskDTO = new WMSTaskDTO() { TaskNum = Convert.ToInt32(DateTime.Now.ToString("HHmmss")), Grade = 1, PalletCode = palletCode, Roadway = "SC01", SourceAddress = sourceAddress, TargetAddress = "SC01", TaskState = (int)TaskInStatusEnum.InNew, Id = 0, TaskType = (int)TaskInboundTypeEnum.Inbound }; content = ReceiveWMSTask(new List { taskDTO }); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 根据设备编号、当前地址查询输送线未执行的任务 /// /// 设备编号 /// 当前地址 /// public Dt_Task QueryConveyorLineTask(string deviceNo, string currentAddress) { return BaseDal.QueryFirst(x => (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.InNew || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.SC_OutFinish) && x.CurrentAddress == currentAddress, TaskOrderBy); } /// /// 根据任务号、下一地址查询输送线执行中的任务 /// /// 任务号 /// 下一地址 /// public Dt_Task QueryExecutingConveyorLineTask(int taskNum, string nextAddress) { if (string.IsNullOrEmpty(nextAddress)) throw new ArgumentNullException(nameof(nextAddress), "下一地址不能为空"); return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.NextAddress == nextAddress && (x.TaskStatus == (int)TaskInStatusEnum.Line_InExecuting || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting), TaskOrderBy); } /// /// 根据任务号、当前地址查询输送线完成的任务 /// /// 任务号 /// 当前地址 /// public Dt_Task QueryCompletedConveyorLineTask(int taskNum, string currentAddress) { if (string.IsNullOrEmpty(currentAddress)) throw new ArgumentNullException(nameof(currentAddress), "当前地址不能为空"); return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress && (x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish), TaskOrderBy); } /// /// 根据设备编号、任务类型分组(可选)按照优先级以及创建时间排序查询任务池新增的任务 /// /// 设备编号 /// 任务类型分组(可选) /// public Dt_Task? QuertStackerCraneTask(string deviceNo, TaskTypeGroup? taskTypeGroup = null) { if (taskTypeGroup == null) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew), TaskOrderBy); if (taskTypeGroup.Value == TaskTypeGroup.InboundGroup) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy); if (taskTypeGroup.Value == TaskTypeGroup.OutbondGroup) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew, TaskOrderBy); return null; } /// /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池新增的任务 /// /// 设备编号 /// 当前地址 /// 返回任务实体对象,可能为null public Dt_Task QueryStackerCraneTask(string deviceNo, string currentAddress = "") { if (string.IsNullOrEmpty(currentAddress)) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew || TaskRelocationTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskRelocationStatusEnum.RelocationNew), TaskOrderBy); else return BaseDal.QueryFirst(x => x.Roadway == deviceNo && x.CurrentAddress == currentAddress && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew || TaskRelocationTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskRelocationStatusEnum.RelocationNew), TaskOrderBy); } /// /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池入库类型的新增的任务 /// /// 设备编号 /// 当前地址 /// 返回任务实体对象,可能为null public Dt_Task QueryStackerCraneInTask(string deviceNo, string currentAddress = "") { if (string.IsNullOrEmpty(currentAddress)) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy); else return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish && x.CurrentAddress == currentAddress, TaskOrderBy); } /// /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务 /// /// 设备编号 /// 当前地址 /// 返回任务实体对象,可能为null public Dt_Task QueryStackerCraneOutTask(string deviceNo, string currentAddress = "") { if (string.IsNullOrEmpty(currentAddress)) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew, TaskOrderBy); else return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && x.CurrentAddress == currentAddress, TaskOrderBy); } /// /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务 /// /// 设备编号 /// 当前地址 /// 返回任务实体对象集合,可能为null public List QueryStackerCraneOutTasks(string deviceNo, List outStationCodes) { return BaseDal.QueryData(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && outStationCodes.Contains(x.CurrentAddress), TaskOrderBy); } /// /// 更新任务异常信息显示 /// /// 任务号 /// 异常信息 public WebResponseContent UpdateTaskExceptionMessage(int taskNum, string message) { WebResponseContent content = new WebResponseContent(); try { if (string.IsNullOrEmpty(message)) throw new ArgumentNullException(nameof(message), "异常信息不能为空"); Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { task.TaskStatus = (int)TaskOutStatusEnum.OutPending; } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup) { task.TaskStatus = (int)TaskInStatusEnum.InPending; } task.ExceptionMessage = message; task.ModifyDate = DateTime.Now; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, task.ExceptionMessage); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 更新任务状态信息,并同步至WMS /// /// 任务号 /// 任务状态 public void UpdateTaskStatus(int taskNum, int status) { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return; task.TaskStatus = status; task.ModifyDate = DateTime.Now; BaseDal.UpdateData(task); } /// /// 将任务状态修改为下一个状态 /// /// 任务号 public WebResponseContent UpdateTaskStatusToNext(int taskNum) { WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】"); return UpdateTaskStatusToNext(task); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } /// /// 将任务状态修改为下一个状态 /// /// 任务实体对象 /// public WebResponseContent UpdateTaskStatusToNext([NotNull] Dt_Task task) { int oldState = task.TaskStatus; var result = task.TaskType.GetTaskTypeGroup() switch { TaskTypeGroup.OutbondGroup => ProcessOutboundTaskStatus(task), TaskTypeGroup.InboundGroup => ProcessInboundTaskStatus(task), TaskTypeGroup.RelocationGroup => ProcessRelocationTaskStatus(task), TaskTypeGroup.OtherGroup => ProcessRobotTaskStatus(task), _ => WebResponseContent.Instance.Error($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】") }; if (!result.Status) return result; // 更新任务数据 task.ModifyDate = DateTime.Now; task.Modifier = "System"; if(task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish) { BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动删除); } else { BaseDal.UpdateData(task); } // 记录任务执行详情 string logMessage = App.User.UserId > 0 ? $"人工手动将任务状态从【{oldState}】跳转到【{task.TaskStatus}】" : $"系统自动流程,任务状态从【{oldState}】转到【{task.TaskStatus}】"; _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, logMessage); return WebResponseContent.Instance.OK(); } /// /// 处理出库任务状态转换 /// private WebResponseContent ProcessOutboundTaskStatus(Dt_Task task) { if (task.TaskStatus >= (int)TaskOutStatusEnum.OutFinish) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus(); if (task.TaskStatus <= 0) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); // 根据状态调用不同的WMS接口 if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound) { return GetWMSOutboundTrayTask(task); } else if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty) { return GetWMSRobotTask(task); } else { // return UpdateWMSTaskStatus(task); return WebResponseContent.Instance.OK(); } } /// /// 处理入库任务状态转换 /// private WebResponseContent ProcessInboundTaskStatus(Dt_Task task) { if (task.TaskStatus >= (int)TaskInStatusEnum.InFinish) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus(); if (task.TaskStatus <= 0) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); // 根据状态调用不同的WMS接口 if (task.TaskStatus == (int)TaskInStatusEnum.Line_InFinish) { return GetWMSInboundLocation(task); } else { return UpdateWMSTaskStatus(task); } } /// /// 处理机械手任务状态转换 /// private WebResponseContent ProcessRobotTaskStatus(Dt_Task task) { if (task.TaskStatus >= (int)TaskRobotStatusEnum.RobotFinish) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus(); if (task.TaskStatus <= 0) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); return WebResponseContent.Instance.OK(); } /// /// 处理移库任务状态转换 /// private WebResponseContent ProcessRelocationTaskStatus(Dt_Task task) { if (task.TaskStatus >= (int)TaskRelocationStatusEnum.RelocationFinish) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus(); if (task.TaskStatus <= 0) return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】"); // 移库任务开始时,同步WMS任务状态 if (task.TaskStatus == (int)TaskRelocationStatusEnum.SC_RelocationExecuting) { return UpdateWMSTaskStatus(task); } // 移库任务完成时,调用WMS移库完成接口 if (task.TaskStatus == (int)TaskRelocationStatusEnum.RelocationFinish) { return NotifyWMSRelocationFinish(task); } return WebResponseContent.Instance.OK(); } /// /// 通知WMS系统出库完成 /// private WebResponseContent NotifyWMSOutboundFinish(Dt_Task task) { var result = _httpClientHelper.Post( nameof(ConfigKey.OutboundFinishTaskAsync), new StockInfoDTO { PalletCode = task.PalletCode, TaskNum = task.TaskNum }.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"通知WMS系统堆垛机出库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】"); return WebResponseContent.Instance.OK(); } /// /// 获取空托出库任务 /// private WebResponseContent GetWMSOutboundTrayTask(Dt_Task task) { var targetAddress = task.TargetAddress; var warehouseId = MapWarehouseIdConfigKey(task.TargetAddress); string sourceLineNo = ResolveRobotRuleValue(targetAddress, "AddressSourceLineNoMap", task.TargetAddress); var result = _httpClientHelper.Post( nameof(ConfigKey.GetOutBoundTrayTaskAsync), new CreateTaskDto { WarehouseId = warehouseId, TargetAddress = sourceLineNo }.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"获取WMS系统空托盘出库任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】"); var wMSTask = JsonConvert.DeserializeObject(result.Data.Data.ToString()); var tasks = new List(); tasks.Add(wMSTask); return ReceiveWMSTask(tasks); } /// /// 获取WMS系统机械手任务 /// /// /// private WebResponseContent GetWMSRobotTask(Dt_Task task) { string configKey = ResolveRobotTaskConfigKey(task.TargetAddress); StockDTO stock = BuildRobotTaskStock(task, configKey); var result = _httpClientHelper.Post(configKey, stock.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"获取WMS系统机械手任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,目标地址:【{task.TargetAddress}】,接口:【{configKey}】,错误信息:【{result.Data?.Message}】"); var tasks = JsonConvert.DeserializeObject>(result.Data.Data?.ToString() ?? string.Empty); if (tasks == null || tasks.Count == 0) return WebResponseContent.Instance.Error($"获取WMS系统机械手任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【WMS未返回有效任务数据】"); return ReceiveWMSTask(tasks); } /// /// 根据输送线目标地址解析机械手任务接口。 /// 规则: /// 1. 从配置读取精确地址映射(AddressMap) /// 2. 未命中时默认换盘 /// private string ResolveRobotTaskConfigKey(string? targetAddress) { string address = (targetAddress ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(address)) return nameof(ConfigKey.CreateRobotChangePalletTask); var section = App.Configuration.GetSection("RobotTaskAddressRules"); var addressMap = ReadRobotRuleMap(section.GetSection("AddressMap")); if (addressMap.TryGetValue(address, out string? exactTaskType)) return MapRobotTaskTypeToConfigKey(exactTaskType); return nameof(ConfigKey.CreateRobotChangePalletTask); } private int MapWarehouseIdConfigKey(string? targetAddress) { return targetAddress switch { "11068" => 1, "11001" => 3, "11010" => 3, "10010" => 1, "10030" => 1, _ => 1 }; } /// /// 将配置任务类型转换为接口配置键。 /// 支持值:Split/Group/Change(大小写不敏感) /// private string MapRobotTaskTypeToConfigKey(string? taskType) { string type = (taskType ?? string.Empty).Trim().ToLowerInvariant(); return type switch { "split" => nameof(ConfigKey.CreateRobotSplitPalletTask), "group" => nameof(ConfigKey.CreateRobotGroupPalletTask), _ => nameof(ConfigKey.CreateRobotChangePalletTask) }; } /// /// 根据接口类型构建机械手任务入参。 /// private StockDTO BuildRobotTaskStock(Dt_Task task, string configKey) { string targetAddress = task.TargetAddress ?? string.Empty; string roadway = ResolveRobotRuleValue(targetAddress, "AddressRoadwayMap", task.Roadway); string sourceLineNo = ResolveRobotRuleValue(targetAddress, "AddressSourceLineNoMap", task.SourceAddress); var stock = new StockDTO { Roadway = roadway, SourceLineNo = sourceLineNo, TargetLineNo = task.TargetAddress, SourcePalletNo = task.PalletCode, TargetPalletNo = task.PalletCode }; if (configKey == nameof(ConfigKey.CreateRobotSplitPalletTask)) { stock.TargetPalletNo = string.Empty; } else if (configKey == nameof(ConfigKey.CreateRobotGroupPalletTask)) { stock.SourcePalletNo = string.Empty; } else if (configKey == nameof(ConfigKey.CreateRobotChangePalletTask)) { IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo)); if (device != null) { CommonConveyorLine conveyorLine = (CommonConveyorLine)device; var barcode = conveyorLine.GetValue(ConveyorLineDBNameNew.Barcode, sourceLineNo); stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode; } } return stock; } /// /// 根据目标地址按「精确 > 回退值」解析规则值。 /// private string ResolveRobotRuleValue(string? targetAddress, string addressSectionName, string? fallback) { string address = (targetAddress ?? string.Empty).Trim(); string defaultValue = fallback ?? string.Empty; if (string.IsNullOrWhiteSpace(address)) return defaultValue; var section = App.Configuration.GetSection("RobotTaskAddressRules"); var addressMap = ReadRobotRuleMap(section.GetSection(addressSectionName)); if (addressMap.TryGetValue(address, out string? value)) return value; return defaultValue; } /// /// 读取规则映射段。 /// private Dictionary ReadRobotRuleMap(IConfigurationSection section) { return section .GetChildren() .Where(x => !string.IsNullOrWhiteSpace(x.Key) && !string.IsNullOrWhiteSpace(x.Value)) .ToDictionary(x => x.Key.Trim(), x => x.Value!.Trim()); } /// /// 从WMS系统获取入库目标地址 /// private WebResponseContent GetWMSInboundLocation(Dt_Task task) { var result = _httpClientHelper.Post( nameof(ConfigKey.GetTasksLocation), new CreateTaskDto { PalletCode = task.PalletCode }.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【{result.Data?.Message}】"); var nextAddress = result.Data.Data?.ToString(); if (string.IsNullOrEmpty(nextAddress)) return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【未获取到有效的目标地址】"); task.CurrentAddress = task.NextAddress; task.NextAddress = nextAddress; task.TargetAddress = nextAddress; return WebResponseContent.Instance.OK(); } /// /// 更新WMS系统任务状态 /// private WebResponseContent UpdateWMSTaskStatus(Dt_Task task) { var result = _httpClientHelper.Post( nameof(ConfigKey.UpdateTaskByStatus), new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus }.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"调用WMS接口更新任务状态失败,任务号:【{task.TaskNum}】,错误信息:【{result.Data?.Message}】"); return WebResponseContent.Instance.OK(); } /// /// 通知WMS系统移库任务完成 /// private WebResponseContent NotifyWMSRelocationFinish(Dt_Task task) { var result = _httpClientHelper.Post( nameof(ConfigKey.RelocationFinishTask), new CreateTaskDto { PalletCode = task.PalletCode, SourceAddress = task.CurrentAddress, TargetAddress = task.TargetAddress, Roadway = task.Roadway, TaskType = task.TaskType }.ToJson()); if (!result.IsSuccess || !result.Data.Status) return WebResponseContent.Instance.Error($"通知WMS系统移库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】"); return WebResponseContent.Instance.OK(); } /// /// 根据任务号、当前地址更新任务位置信息 /// /// 任务号 /// 当前地址 /// public Dt_Task? UpdatePosition(int taskNum, string currentAddress) { try { if (string.IsNullOrEmpty(currentAddress)) throw new ArgumentNullException(nameof(currentAddress), "当前地址不能为空"); Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress); if (task == null) throw new Exception($"未找到该任务信息,任务号:【{taskNum}】"); string oldCurrentPos = task.CurrentAddress; string oldNextPos = task.NextAddress; Dt_Router routers = _routerService.QueryNextRoute(task.CurrentAddress); if (routers == null) throw new Exception($"未找到设备路由信息"); task.CurrentAddress = task.NextAddress; task.NextAddress = routers.ChildPosi; task.ModifyDate = DateTime.Now; task.Modifier = "System"; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"系统自动流程,更新当前位置【{oldCurrentPos} ----> {task.CurrentAddress}】和下一位置【{oldNextPos} ----> {task.NextAddress}】"); return task; } catch (Exception ex) { Console.WriteLine($"UpdatePosition 更新任务位置失败,任务号:【{taskNum}】,错误信息:【{ex.Message}】"); } return null; } /// /// 任务完成 /// /// 任务编号 /// 返回处理结果 public WebResponseContent StackCraneTaskCompleted(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.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup && task.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting) { List routers = _routerService.QueryNextRoutes(task.NextAddress, task.TargetAddress); if (!routers.Any()) return WebResponseContent.Instance.Error($"未找到设备路由信息"); int nextStatus = task.TaskStatus.GetNextNotCompletedStatus(); task.TaskStatus = nextStatus; task.CurrentAddress = task.NextAddress; task.NextAddress = routers.FirstOrDefault().ChildPosi; task.ModifyDate = DateTime.Now; task.Modifier = "System"; content = NotifyWMSOutboundFinish(task); if (content.Status) { BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成"); return content.Error($"通知WMS系统堆垛机出库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】"); } //var result = _httpClientHelper.Post(nameof(ConfigKey.OutboundFinishTaskAsync), (new StockInfoDTO() { PalletCode = task.PalletCode, TaskNum = task.TaskNum }).ToJson()); //if (result.IsSuccess && result.Data.Status) //{ // BaseDal.UpdateData(task); // _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成"); // return content.Error($"通知WMS系统堆垛机出库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】"); //} //else //{ // return content.Error($"通知WMS系统堆垛机出库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data.Message}】"); //} } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup && task.TaskStatus == (int)TaskInStatusEnum.SC_InExecuting) { int nextStatus = task.TaskStatus.GetNextNotCompletedStatus(); task.TaskStatus = nextStatus; task.ModifyDate = DateTime.Now; task.Modifier = "System"; var result = _httpClientHelper.Post(nameof(ConfigKey.InboundFinishTaskAsync), (new CreateTaskDto() { PalletCode = task.PalletCode, }).ToJson()); if (result.IsSuccess && result.Data.Status) { BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机入库完成"); return content.Error($"通知WMS系统堆垛机入库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】"); } else { return content.Error($"通知WMS系统堆垛机入库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data.Message}】"); } } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup) { if (task.TaskStatus == (int)TaskRelocationStatusEnum.SC_RelocationExecuting) { int nextStatus = task.TaskStatus.GetNextNotCompletedStatus(); task.TaskStatus = nextStatus; task.ModifyDate = DateTime.Now; task.Modifier = "System"; WebResponseContent result = NotifyWMSRelocationFinish(task); if (result.Status) { BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机移库完成"); return content.Error($"通知WMS系统堆垛机移库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】"); } else { return content.Error($"通知WMS系统堆垛机移库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Message}】"); } } } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup) { } else { throw new Exception($"任务类型错误,未找到该任务类型,任务号:【{taskNum}】,任务类型:【{task.TaskType}】"); } content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error($"任务完成异常,任务号:【{taskNum}】"); } 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.TaskStatus != (int)TaskInStatusEnum.InPending && task.TaskStatus != (int)TaskOutStatusEnum.OutPending) { return content = WebResponseContent.Instance.Error($"该任务状态不可恢复,任务号:【{taskNum}】,任务状态:【{task.TaskStatus}】"); } Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.IsNormal, new Dictionary { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } }); if (taskExecuteDetail != null) { task.TaskStatus = taskExecuteDetail.TaskState; } else { if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { task.TaskStatus = (int)TaskOutStatusEnum.OutNew; } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup) { task.TaskStatus = (int)TaskInStatusEnum.InNew; } //todo } task.ExceptionMessage = string.Empty; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工恢复挂起任务,恢复挂起时任务状态【{task.TaskStatus}】"); 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.TaskStatus; Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.TaskState < task.TaskStatus && x.TaskState > 0, new Dictionary { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } }); if (taskExecuteDetail != null) { task.TaskStatus = taskExecuteDetail.TaskState; task.CurrentAddress = taskExecuteDetail.CurrentAddress; task.NextAddress = taskExecuteDetail.NextAddress; } else { return content = WebResponseContent.Instance.Error($"未找到任务明细信息,该任务状态不可回滚到上一步,任务号:【{taskNum}】,任务状态:【{task.TaskStatus}】"); } task.ExceptionMessage = string.Empty; BaseDal.UpdateData(task); _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工将任务状态从【{oldState}】回滚到【{task.TaskStatus}】"); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } public override WebResponseContent DeleteData(object[] keys) { List taskKeys = new List(); for (int i = 0; i < keys.Length; i++) { taskKeys.Add(Convert.ToInt32(keys[i])); } List tasks = BaseDal.QueryData(x => taskKeys.Contains(x.TaskId)); BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.人工删除); return WebResponseContent.Instance.OK($"成功删除{tasks.Count}条数据"); } /// /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池新增的任务 /// /// 设备编号 /// 当前地址 /// 返回任务实体对象,可能为null public Dt_Task QueryRobotCraneTask(string deviceNo, string currentAddress = "") { if (string.IsNullOrEmpty(currentAddress)) return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskRobotTypes.Contains(x.TaskType) && x.TaskStatus <= (int)TaskRobotStatusEnum.RobotExecuting), TaskOrderBy); else return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskRobotTypes.Contains(x.TaskType) && x.CurrentAddress == currentAddress && x.TaskStatus <= (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy); } /// /// 获取与指定任务编号关联的任务。 /// /// 要获取的任务的唯一标识符。 /// 表示指定编号任务的对象,如果不存在该任务则返回null public Dt_Task QueryByTaskNum(int taskNum) { return BaseDal.QueryFirst(x => x.TaskNum == taskNum); } } public enum ConveyorLineDBNameNew { Barcode } }