using Mapster; using MapsterMapper; using Microsoft.Extensions.Configuration; using SqlSugar; using System.DirectoryServices.Protocols; using System.Text.Json; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Common.WareHouseEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Core; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.GradingMachine; using WIDESEA_DTO.MES; using WIDESEA_DTO.Stock; using WIDESEA_DTO.Task; using WIDESEA_IBasicService; using WIDESEA_IStockService; using WIDESEA_ITaskInfoService; using WIDESEA_Model.Models; namespace WIDESEA_TaskInfoService { public partial class TaskService : ServiceBase>, ITaskService { private readonly IMapper _mapper; private readonly IStockInfoService _stockInfoService; private readonly ILocationInfoService _locationInfoService; private readonly HttpClientHelper _httpClientHelper; private readonly IConfiguration _configuration; private readonly RoundRobinService _roundRobinService; private readonly IMesService _mesService; private readonly ITask_HtyService _task_HtyService; private readonly IStockInfo_HtyService _stockInfo_HtyService; private readonly IUnitOfWorkManage _unitOfWorkManage; public IRepository Repository => BaseDal; private readonly Dictionary _taskOrderBy = new() { { nameof(Dt_Task.Grade), OrderByType.Desc }, { nameof(Dt_Task.CreateDate), OrderByType.Asc }, }; public List TaskTypes => typeof(TaskTypeEnum).GetEnumIndexList(); public List TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList(); public TaskService( IRepository BaseDal, IMapper mapper, IStockInfoService stockInfoService, ILocationInfoService locationInfoService, HttpClientHelper httpClientHelper, IConfiguration configuration, RoundRobinService roundRobinService, IMesService mesService, ITask_HtyService task_HtyService, IStockInfo_HtyService stockInfo_HtyService, IUnitOfWorkManage unitOfWorkManage) : base(BaseDal) { _mapper = mapper; _stockInfoService = stockInfoService; _locationInfoService = locationInfoService; _httpClientHelper = httpClientHelper; _configuration = configuration; _roundRobinService = roundRobinService; _mesService = mesService; _task_HtyService = task_HtyService; _stockInfo_HtyService = stockInfo_HtyService; _unitOfWorkManage = unitOfWorkManage; } #region WCS逻辑处理 /// /// 创建任务(组盘入库任务、空托盘回库任务) /// public async Task CreateTaskInboundAsync(CreateTaskDto taskDto) { try { WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); if (content.Status) { return content; } if (string.IsNullOrWhiteSpace(taskDto.PalletCode) || string.IsNullOrWhiteSpace(taskDto.Roadway)) { return WebResponseContent.Instance.Error("无效的任务详情"); } if (taskDto.TaskType != TaskTypeEnum.Inbound && taskDto.TaskType != TaskTypeEnum.InEmpty) { return WebResponseContent.Instance.Error("无效的任务详情"); } // 使用 switch 表达式映射任务类型 int taskInboundType = taskDto.TaskType switch { TaskTypeEnum.Inbound => TaskInboundTypeEnum.Inbound.GetHashCode(), TaskTypeEnum.InEmpty => TaskInboundTypeEnum.InEmpty.GetHashCode(), _ => 0 // 理论上不会走到这里,因为已经验证过了 }; var task = new Dt_Task { TaskNum = await BaseDal.GetTaskNo(), PalletCode = taskDto.PalletCode, PalletType = taskDto.PalletType, Roadway = taskDto.Roadway, TaskType = taskInboundType, TaskStatus = TaskInStatusEnum.InNew.GetHashCode(), SourceAddress = taskDto.SourceAddress, TargetAddress = taskDto.TargetAddress, CurrentAddress = taskDto.SourceAddress, NextAddress = taskDto.TargetAddress, WarehouseId = taskDto.WarehouseId, Grade = 1, Creater = "system" }; var result = await Repository.AddDataAsync(task) > 0; if (!result) return WebResponseContent.Instance.Error("任务创建失败"); var wmstaskDto = _mapper.Map(task); return WebResponseContent.Instance.OK("任务创建成功", wmstaskDto); } catch (Exception ex) { return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}"); } } /// /// 根据指定的任务详情异步创建新的出库任务 /// public async Task CreateTaskOutboundAsync(CreateTaskDto taskDto) { try { var stockResult = await _stockInfoService.GetStockInfoAsync(taskDto.WarehouseId); if (stockResult == null || !stockResult.Any()) return WebResponseContent.Instance.Error("未找到库存信息"); var taskList = stockResult.Select(item => new Dt_Task { WarehouseId = item.WarehouseId, PalletCode = item.PalletCode, PalletType = item.PalletType, SourceAddress = item.LocationCode, TargetAddress = taskDto.TargetAddress, Roadway = item.LocationDetails.RoadwayNo, TaskType = TaskTypeEnum.Outbound.GetHashCode(), TaskStatus = TaskStatusEnum.New.GetHashCode(), Grade = 1, TaskNum = 0, CurrentAddress = item.LocationCode, NextAddress = taskDto.TargetAddress, Creater = "system", }).ToList(); var result = await BaseDal.AddDataAsync(taskList) > 0; var wmstaskDto = result ? _mapper.Map(taskList) : null; return WebResponseContent.Instance.OK(result ? "任务创建成功" : "任务创建失败", wmstaskDto ?? new object()); } catch (Exception ex) { return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}"); } } /// /// 获取可入库货位 /// public async Task GetTasksLocationAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var locationInfo = await _locationInfoService.GetLocationInfo(task.Roadway); if (locationInfo == null) return WebResponseContent.Instance.Error("未找到对应的货位"); return await ExecuteWithinTransactionAsync(async () => { locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode(); task.CurrentAddress = task.SourceAddress; task.NextAddress = locationInfo.LocationCode; task.TargetAddress = locationInfo.LocationCode; task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode(); var updateTaskResult = await BaseDal.UpdateDataAsync(task); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); if (!updateTaskResult || !updateLocationResult) { return WebResponseContent.Instance.Error("任务更新失败"); } return WebResponseContent.Instance.OK("任务更新成功", locationInfo.LocationCode); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"获取任务失败: {ex.Message}"); } } /// /// 入库任务完成:添加库存,修改货位状态,删除任务数据,添加历史任务数据 /// public async Task InboundFinishTaskAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位"); var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息"); // 判断是不是极卷库任务 //if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) //{ // return WebResponseContent.Instance.OK(); //} return await ExecuteWithinTransactionAsync(async () => { WebResponseContent content = new WebResponseContent(); stockInfo.LocationCode = location.LocationCode; stockInfo.LocationId = location.Id; stockInfo.OutboundDate = task.Roadway switch { var r when r.Contains("GW") => DateTime.Now.AddHours(2), var r when r.Contains("CW") => DateTime.Now.AddHours(1), _ => DateTime.Now }; stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode(); location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!updateLocationResult || !updateStockResult) return WebResponseContent.Instance.Error("任务完成失败"); // 调用MES托盘进站 var inboundRequest = new InboundInContainerRequest { EquipmentCode = "STK-GROUP-001", ResourceCode = "STK-GROUP-001", LocalTime = DateTime.Now, ContainerCode = taskDto.PalletCode }; var inboundResult = _mesService.InboundInContainer(inboundRequest); if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess) { return content.Error($"任务完成失败:MES进站失败: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "未知错误"}"); } return await CompleteTaskAsync(task, "入库完成"); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}"); } } /// /// 出库任务完成 :修改库存,修改货位状态,删除任务数据,添加历史任务数据 /// public async Task OutboundFinishTaskAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位"); var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息"); // 判断是不是极卷库任务 if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) { OutTaskCompleteDto outTaskCompleteDto = new OutTaskCompleteDto() { TaskId = task.OrderNo, DevId = task.TargetAddress, ReqTime = DateTime.Now.ToString() }; return await OutTaskComplete(outTaskCompleteDto); } WebResponseContent content = new WebResponseContent(); return await ExecuteWithinTransactionAsync(async () => { stockInfo.LocationId = 0; stockInfo.LocationCode = null; stockInfo.OutboundDate = DateTime.Now; location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!updateLocationResult || !updateStockResult) return WebResponseContent.Instance.Error("任务完成失败"); // 调用MES托盘出站 var outboundRequest = new OutboundInContainerRequest { EquipmentCode = "STK-GROUP-001", ResourceCode = "STK-GROUP-001", LocalTime = DateTime.Now, ContainerCode = taskDto.PalletCode, ParamList = new List() }; var outboundResult = _mesService.OutboundInContainer(outboundRequest); if (outboundResult == null || outboundResult.Data == null || !outboundResult.Data.IsSuccess) { return content.Error($"任务完成失败:MES出站失败: {outboundResult?.Data?.Msg ?? outboundResult?.ErrorMessage ?? "未知错误"}"); } return await CompleteTaskAsync(task, "出库完成"); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}"); } } /// /// 移库任务完成:修改库存位置与状态,修改源/目标货位状态,删除任务数据 /// public async Task RelocationFinishTaskAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode && s.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode()); if (task == null) return WebResponseContent.Instance.Error("未找到对应的移库任务"); var sourceLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); if (sourceLocation == null) return WebResponseContent.Instance.Error("未找到移库源货位"); var targetLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); if (targetLocation == null) return WebResponseContent.Instance.Error("未找到移库目标货位"); var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息"); return await ExecuteWithinTransactionAsync(async () => { stockInfo.LocationCode = targetLocation.LocationCode; stockInfo.LocationId = targetLocation.Id; stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode(); sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode(); targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation); var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!updateSourceResult || !updateTargetResult || !updateStockResult) return WebResponseContent.Instance.Error("移库任务完成失败"); return await CompleteTaskAsync(task, "移库完成"); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}"); } } /// /// 创建空托盘入库任务 /// /// /// public async Task CreateTaskInboundTrayAsync(CreateTaskDto taskDto) { try { WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); if (content.Status) { return content; } //var tasks = await BaseDal.QueryAsync(s => s.PalletCode == palletCode); //if (tasks == null || !tasks.Any()) // return WebResponseContent.Instance.Error("未找到对应的任务"); //var taskDtos = _mapper.Map>(tasks); return WebResponseContent.Instance.OK("查询成功"/*, taskDtos*/); } catch (Exception ex) { return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}"); } } /// /// 空托盘入库完成 /// public async Task InboundFinishTaskTrayAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位"); var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息"); return await ExecuteWithinTransactionAsync(async () => { stockInfo.LocationCode = location.LocationCode; stockInfo.LocationId = location.Id; stockInfo.StockStatus = StockStatusEmun.空托盘库存.GetHashCode(); location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!updateLocationResult || !updateStockResult) return WebResponseContent.Instance.Error("任务完成失败"); // 保存任务历史 var historyTask = _mapper.Map(task); historyTask.InsertTime = DateTime.Now; historyTask.OperateType = "空托盘入库完成"; if (await _task_HtyService.Repository.AddDataAsync(historyTask) <= 0) return WebResponseContent.Instance.Error("任务历史保存失败"); // 保存库存历史 var historyStock = _mapper.Map(stockInfo); historyStock.InsertTime = DateTime.Now; historyStock.OperateType = "空托盘入库完成"; if (await _stockInfo_HtyService.Repository.AddDataAsync(historyStock) <= 0) return WebResponseContent.Instance.Error("库存历史保存失败"); var deleteResult = await BaseDal.DeleteDataAsync(task); if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败"); return WebResponseContent.Instance.OK("任务完成"); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}"); } } /// /// 创建空托盘出库任务 /// /// /// public async Task GetOutBoundTrayTaskAsync(CreateTaskDto taskDto) { try { var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.空托盘库存.GetHashCode()); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应的库存信息"); var task = new Dt_Task() { WarehouseId = stockInfo.LocationDetails.WarehouseId, PalletCode = stockInfo.PalletCode, PalletType = stockInfo.PalletType, SourceAddress = stockInfo.LocationCode, CurrentAddress = stockInfo.LocationCode, NextAddress = taskDto.TargetAddress, TargetAddress = taskDto.TargetAddress, Roadway = stockInfo.LocationDetails.RoadwayNo, TaskType = TaskOutboundTypeEnum.OutEmpty.GetHashCode(), TaskStatus = TaskStatusEnum.New.GetHashCode(), Grade = 1, TaskNum = await BaseDal.GetTaskNo(), Creater = "system", }; var taskDtos = task.Adapt(); var addResult = await BaseDal.AddDataAsync(task) > 0; if (!addResult) return WebResponseContent.Instance.Error("任务创建失败"); return WebResponseContent.Instance.OK("任务创建成功", taskDtos); } catch (Exception ex) { return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}"); } } /// /// 空托盘出库完成 /// public async Task OutboundFinishTaskTrayAsync(CreateTaskDto taskDto) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位"); var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息"); return await ExecuteWithinTransactionAsync(async () => { stockInfo.LocationId = 0; stockInfo.LocationCode = null; stockInfo.StockStatus = StockStatusEmun.出库完成.GetHashCode(); location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!updateLocationResult || !updateStockResult) return WebResponseContent.Instance.Error("任务完成失败"); // 保存任务历史 var historyTask = _mapper.Map(task); historyTask.InsertTime = DateTime.Now; historyTask.OperateType = "空托盘出库完成"; if (await _task_HtyService.Repository.AddDataAsync(historyTask) <= 0) return WebResponseContent.Instance.Error("任务历史保存失败"); // 保存库存历史 var historyStock = _mapper.Map(stockInfo); historyStock.InsertTime = DateTime.Now; historyStock.OperateType = "空托盘出库完成"; if (await _stockInfo_HtyService.Repository.AddDataAsync(historyStock) <= 0) return WebResponseContent.Instance.Error("库存历史保存失败"); var deleteResult = await BaseDal.DeleteDataAsync(task); if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败"); return WebResponseContent.Instance.OK("任务完成"); }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}"); } } /// /// 修改任务状态(根据任务ID修改为指定状态) /// /// /// /// public async Task UpdateTaskByStatusAsync(int taskId, int newStatus) { try { var tasks = await BaseDal.QueryFirstAsync(s => s.TaskNum == taskId); if (tasks == null) return WebResponseContent.Instance.Error("未找到对应的任务"); tasks.TaskStatus = newStatus; await BaseDal.UpdateDataAsync(tasks); return WebResponseContent.Instance.OK("修改成功", tasks); } catch (Exception ex) { return WebResponseContent.Instance.Error($"修改失败: {ex.Message}"); } } /// /// 查找托盘是否有任务 /// /// /// private async Task GetTaskByPalletCodeAsync(string palletCode) { try { var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode); if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务"); var taskDto = _mapper.Map(task); return WebResponseContent.Instance.OK("查询成功", taskDto); } catch (Exception ex) { return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}"); } } /// /// 完成任务后统一处理(删除任务数据) /// private async Task CompleteTaskAsync(Dt_Task task, string operateType = "") { var deleteTaskResult = await BaseDal.DeleteDataAsync(task); if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败"); var historyTask = _mapper.Map(task); historyTask.InsertTime = DateTime.Now; historyTask.OperateType = operateType; var saveResult = await _task_HtyService.Repository.AddDataAsync(historyTask) > 0; if (!saveResult) return WebResponseContent.Instance.Error("任务历史保存失败"); return WebResponseContent.Instance.OK("任务完成"); } /// /// 根据巷道确定目标地址(支持多出库口轮询) /// private string DetermineTargetAddress(string roadway, Dictionary> addressMap) { if (string.IsNullOrWhiteSpace(roadway)) return "10080"; // 查找匹配的巷道前缀 string matchedPrefix = null; foreach (var kvp in addressMap) { if (roadway.Contains(kvp.Key)) { matchedPrefix = kvp.Key; break; } } if (matchedPrefix == null) return "10080"; var addresses = addressMap[matchedPrefix]; if (addresses == null || addresses.Count == 0) return "10080"; // 单个地址,直接返回 if (addresses.Count == 1) return addresses[0]; // 多个地址,使用轮询服务 return _roundRobinService.GetNextAddress(matchedPrefix, addresses); } /// /// 自动创建出库任务 - 查询到期库存并创建任务 /// public async Task CreateAutoOutboundTasksAsync() { try { // 1. 查询到期库存 var expiredStocks = await _stockInfoService.Repository .QueryDataNavAsync(s => s.OutboundDate <= DateTime.Now && s.StockStatus == StockStatusEmun.入库完成.GetHashCode()); if (expiredStocks == null || !expiredStocks.Any()) { return WebResponseContent.Instance.OK("无到期库存需要处理"); } // 过滤有位置且位置有库存的记录 expiredStocks = expiredStocks .Where(s => s.LocationDetails != null && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode()) .ToList(); if (!expiredStocks.Any()) { return WebResponseContent.Instance.OK("无符合条件的到期库存"); } // 2. 检查已存在的任务 var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList(); var existingTasks = await Repository.QueryDataAsync(t => palletCodes.Contains(t.PalletCode) && (t.TaskStatus == TaskStatusEnum.New.GetHashCode() || t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode() || t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode())); var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet(); // 3. 筛选需要处理的库存 var stocksToProcess = expiredStocks .Where(s => !processedPallets.Contains(s.PalletCode)) .ToList(); if (!stocksToProcess.Any()) { return WebResponseContent.Instance.OK("所有到期库存已存在任务"); } // 4. 获取配置的目标地址映射 var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses") .Get>>() ?? new Dictionary>(); // 5. 批量创建任务 var taskList = new List(); foreach (var stock in stocksToProcess) { // 根据巷道确定目标地址 var targetAddress = DetermineTargetAddress( stock.LocationDetails?.RoadwayNo ?? "", targetAddressMap); var task = new Dt_Task { WarehouseId = stock.WarehouseId, PalletCode = stock.PalletCode, PalletType = stock.PalletType, SourceAddress = stock.LocationCode, CurrentAddress = stock.LocationCode, NextAddress = targetAddress, TargetAddress = targetAddress, Roadway = stock.LocationDetails?.RoadwayNo ?? "", TaskType = TaskTypeEnum.Outbound.GetHashCode(), TaskStatus = TaskStatusEnum.New.GetHashCode(), Grade = 1, TaskNum = await BaseDal.GetTaskNo(), Creater = "system_auto" }; taskList.Add(task); } var transactionResult = await ExecuteWithinTransactionAsync(async () => { var addResult = await BaseDal.AddDataAsync(taskList) > 0; if (!addResult) { return WebResponseContent.Instance.Error($"批量创建任务失败,共 {taskList.Count} 个任务"); } // 任务创建成功后,同步锁定库存和货位状态,避免重复分配 var stocksToUpdate = stocksToProcess .Select(s => { s.StockStatus = StockStatusEmun.出库锁定.GetHashCode(); return s; }) .ToList(); var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate); if (!updateStockResult) { return WebResponseContent.Instance.Error($"任务创建成功,但库存状态更新失败,共 {stocksToUpdate.Count} 条"); } var locationsToUpdate = stocksToProcess .Where(s => s.LocationDetails != null) .GroupBy(s => s.LocationDetails.Id) .Select(g => { var location = g.First().LocationDetails; location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode(); return location; }) .ToList(); if (locationsToUpdate.Any()) { var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate); if (!updateLocationResult) { return WebResponseContent.Instance.Error($"任务创建成功,但货位状态更新失败,共 {locationsToUpdate.Count} 条"); } } return WebResponseContent.Instance.OK(); }); if (!transactionResult.Status) { return transactionResult; } // 6. 通知 WCS(异步,不影响主流程) _ = Task.Run(() => { try { var wmstaskDtos = _mapper.Map>(taskList); _httpClientHelper.Post( "http://localhost:9292/api/Task/ReceiveTask", wmstaskDtos.ToJson()); } catch (Exception ex) { // WCS 通知失败不影响任务创建,记录日志即可 Console.WriteLine($"WCS 批量通知失败,任务数量: {taskList.Count}, 错误: {ex.Message}"); } }); return WebResponseContent.Instance.OK($"成功创建 {taskList.Count} 个出库任务", taskList.Count); } catch (Exception ex) { return WebResponseContent.Instance.Error($"自动创建出库任务失败: {ex.Message}"); } } /// /// 创建机械手组盘任务 /// public async Task CreateRobotGroupPalletTaskAsync(StockDTO stock) { return await CreateRobotPalletTaskAsync( stock, "组盘", RobotTaskTypeEnum.GroupPallet, s => string.IsNullOrWhiteSpace(s.TargetPalletNo) ? s.SourcePalletNo : s.TargetPalletNo, requireStockWithoutLocation: false); } /// /// 创建机械手换盘任务 /// public async Task CreateRobotChangePalletTaskAsync(StockDTO stock) { return await CreateRobotPalletTaskAsync( stock, "换盘", RobotTaskTypeEnum.ChangePallet, s => s.SourcePalletNo, requireStockWithoutLocation: true, stockPalletCodeSelector: s => s.SourcePalletNo); } /// /// 创建机械手拆盘任务 /// public async Task CreateRobotSplitPalletTaskAsync(StockDTO stock) { return await CreateRobotPalletTaskAsync( stock, "拆盘", RobotTaskTypeEnum.SplitPallet, s => s.SourcePalletNo, requireStockWithoutLocation: true, stockPalletCodeSelector: s => s.SourcePalletNo); } private async Task CreateRobotPalletTaskAsync( StockDTO stock, string taskName, RobotTaskTypeEnum taskType, Func palletCodeSelector, bool requireStockWithoutLocation, Func? stockPalletCodeSelector = null) { try { if (stock == null) return WebResponseContent.Instance.Error("任务参数不能为空"); var palletCode = palletCodeSelector(stock)?.Trim(); if (string.IsNullOrWhiteSpace(palletCode)) return WebResponseContent.Instance.Error("托盘号不能为空"); var sourceLineNo = stock.SourceLineNo?.Trim(); var targetLineNo = stock.TargetLineNo?.Trim(); if (string.IsNullOrWhiteSpace(sourceLineNo) || string.IsNullOrWhiteSpace(targetLineNo)) return WebResponseContent.Instance.Error("来源线体编号和目标线体编号不能为空"); var existingTask = await BaseDal.QueryFirstAsync(t => t.PalletCode == palletCode && (t.TaskStatus == TaskRobotStatusEnum.RobotNew.GetHashCode() || t.TaskStatus == TaskRobotStatusEnum.RobotExecuting.GetHashCode() || t.TaskStatus == TaskRobotStatusEnum.RobotPickFinish.GetHashCode() || t.TaskStatus == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() || t.TaskStatus == TaskRobotStatusEnum.RobotPending.GetHashCode())); if (existingTask != null) return WebResponseContent.Instance.Error($"托盘[{palletCode}]已存在未完成任务"); Dt_StockInfo? stockInfo = null; if (requireStockWithoutLocation) { var stockPalletCode = (stockPalletCodeSelector ?? palletCodeSelector).Invoke(stock)?.Trim(); if (string.IsNullOrWhiteSpace(stockPalletCode)) return WebResponseContent.Instance.Error("源托盘号不能为空"); stockInfo = await _stockInfoService.GetStockInfoAsync(stockPalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存不存在"); if (stockInfo.LocationId > 0 || !string.IsNullOrWhiteSpace(stockInfo.LocationCode)) return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存已绑定货位,不能创建机械手{taskName}任务"); } var task = new Dt_Task { TaskNum = await BaseDal.GetTaskNo(), PalletCode = palletCode, PalletType = stockInfo?.PalletType ?? 0, Roadway = stock.Roadway, TaskType = taskType.GetHashCode(), TaskStatus = TaskRobotStatusEnum.RobotNew.GetHashCode(), SourceAddress = sourceLineNo, TargetAddress = targetLineNo, CurrentAddress = sourceLineNo, NextAddress = targetLineNo, WarehouseId = stockInfo?.WarehouseId ?? 1, Grade = 1, Remark = $"机械手{taskName}", Creater = "system" }; var result = await Repository.AddDataAsync(task) > 0; if (!result) return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败"); var wmstaskDto = _mapper.Map(task); return WebResponseContent.Instance.OK($"机械手{taskName}任务创建成功", wmstaskDto); } catch (Exception ex) { return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败: {ex.Message}"); } } #endregion WCS逻辑处理 #region 分容柜接口 /// /// 堆垛机取放货完成后物流通知化成分容柜完成信号 /// public async Task InOrOutCompletedAsync(GradingMachineInputDto input) { WebResponseContent content = new WebResponseContent(); if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode)) { return content.Error($"托盘号或者货位编号不能为空"); } try { var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode); int locationStatus; if (stockInfo == null) { var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode); locationStatus = location?.LocationStatus ?? 0; } else { locationStatus = stockInfo.LocationDetails?.LocationStatus ?? 0; } OutputDto outPutDto = new OutputDto() { LocationCode = input.LocationCode, PalletCode = input.PalletCode, IsNormalProcedure = 1, LocationStatus = locationStatus }; return content.OK(data: outPutDto); } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 化成分容柜定时向物流更新分容柜状态信息 /// /// /// public async Task SendLocationStatusAsync(GradingMachineInputDto input) { WebResponseContent content = new WebResponseContent(); if (string.IsNullOrWhiteSpace(input.LocationCode)) { return content.Error($"货位编号不能为空"); } try { var result = await _locationInfoService.Db.Updateable() .SetColumns(s => new Dt_LocationInfo { LocationStatus = input.LocationStatus }).Where(s => s.LocationCode == input.LocationCode).ExecuteCommandAsync() > 0; if (result) { content.OK("更新成功"); } else { content.Error("更新失败"); } } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 分容柜工作完成后调用此接口通知物流出库 /// /// /// public async Task RequestOutboundAsync(GradingMachineInputDto input) { WebResponseContent content = new WebResponseContent(); if (string.IsNullOrWhiteSpace(input.LocationCode) || string.IsNullOrWhiteSpace(input.PalletCode)) { return content.Error($"托盘号或者货位编号不能为空"); } try { var stock = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode); if (stock == null) { content.Error("未找到对应的托盘"); } else { var taskList = new Dt_Task { WarehouseId = stock.WarehouseId, PalletCode = stock.PalletCode, PalletType = stock.PalletType, SourceAddress = stock.LocationCode, CurrentAddress = stock.LocationCode, NextAddress = "10080", TargetAddress = "10081", Roadway = stock.LocationDetails.RoadwayNo, TaskType = TaskTypeEnum.Outbound.GetHashCode(), TaskStatus = TaskStatusEnum.New.GetHashCode(), Grade = 1, TaskNum = await BaseDal.GetTaskNo(), Creater = "system", }; var result = await BaseDal.AddDataAsync(taskList) > 0; var wmstaskDto = result ? _mapper.Map(taskList) : null; var httpResponse = _httpClientHelper.Post("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data; if (result && httpResponse != null) { content.OK("出库请求成功"); } else { content.Error("出库请求失败"); } } } catch (Exception ex) { content.Error(ex.Message); } return content; } /// /// 入库完成分容调用获取托盘上每个通道电芯 /// /// /// public async Task GetPalletCodeCellAsync(GradingMachineInputDto input) { WebResponseContent content = new WebResponseContent(); if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode)) { return content.Error($"托盘号或者货位编号不能为空"); } try { var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode); if (stockInfo == null) { return content.Error("未找到对应的托盘"); } var outPutDtos = stockInfo.Details.Select(x => new OutputDto() { LocationCode = input.LocationCode, PalletCode = input.PalletCode, IsNormalProcedure = 1, LocationStatus = stockInfo.LocationDetails.LocationStatus, CellCode = x.SerialNumber, Channel = x.InboundOrderRowNo.ToString() }).ToList(); return content.OK(data: outPutDtos); } catch (Exception ex) { return content.Error(ex.Message); } } #endregion 分容柜接口 #region 极卷库任务模块 public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"]; // 上报AGV出库输送线完成 public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"]; // WMS输送线任务下发 /// /// 出入库申请 /// /// 请求参数 /// public async Task ApplyInOutAsync(ApplyInOutDto applyInOutDto) { AGVResponse aGVResponse = new AGVResponse(); try { // 参数验证 if (applyInOutDto == null) return aGVResponse.Error("请求参数不能为空"); if (string.IsNullOrWhiteSpace(applyInOutDto.TrayNumber)) return aGVResponse.Error("托盘号不能为空"); if (string.IsNullOrWhiteSpace(applyInOutDto.TaskId)) return aGVResponse.Error("任务号不能为空"); if (string.IsNullOrWhiteSpace(applyInOutDto.MaterialType)) return aGVResponse.Error("物料类型不能为空"); if (string.IsNullOrWhiteSpace(applyInOutDto.MaterialName)) return aGVResponse.Error("物料描述不能为空"); if (string.IsNullOrWhiteSpace(applyInOutDto.ReqTime)) return aGVResponse.Error("请求时间不能为空"); if (applyInOutDto.Floor != 1 && applyInOutDto.Floor != 2) return aGVResponse.Error($"楼层段错误,必须为1(模切段)或2(卷绕段),当前值:{applyInOutDto.Floor}"); if (applyInOutDto.YinYang != 1 && applyInOutDto.YinYang != 2) return aGVResponse.Error($"阴阳极错误,必须为1(阴极)或2(阳极),当前值:{applyInOutDto.YinYang}"); if (applyInOutDto.InOut != 1 && applyInOutDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{applyInOutDto.InOut}"); if (applyInOutDto.InOut == 1) // 入库 { if (applyInOutDto.Width == null || applyInOutDto.Width <= 0) return aGVResponse.Error("入库时宽度不能为空且必须大于0"); if (string.IsNullOrWhiteSpace(applyInOutDto.Group)) return aGVResponse.Error("入库时整托组别不能为空"); } // 检查任务是否已存在 var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber); if (existingTask != null) return aGVResponse.Error($"WMS已有当前任务,不可重复下发,任务号:{applyInOutDto.TaskId}"); // 创建任务 Dt_Task task = new Dt_Task { OrderNo = applyInOutDto.TaskId, // 使用AGV的任务号 PalletCode = applyInOutDto.TrayNumber, PalletType = applyInOutDto.Floor, //WarehouseId = applyInOutDto.YinYang, Grade = 1, Creater = "AGV", CreateDate = DateTime.Now, Remark = $"物料类型:{applyInOutDto.MaterialType},物料描述:{applyInOutDto.MaterialName}" }; // 根据阴极/阳极设置巷道和站台 if (applyInOutDto.YinYang == 1) // 阴极 { // 货物到达后分配货物位 task.Roadway = WarehouseEnum.FJ1.ToString(); task.WarehouseId = (int)WarehouseEnum.FJ1; task.SourceAddress = applyInOutDto.InOut == 1 ? "D10010" : "D10020"; // 入库口/出库口 task.NextAddress = "D10080"; // 阴极公共出库口 task.TargetAddress = "阴极卷库"; } else if (applyInOutDto.YinYang == 2) // 阳极 { task.Roadway = WarehouseEnum.ZJ1.ToString(); task.WarehouseId = (int)WarehouseEnum.ZJ1; task.SourceAddress = applyInOutDto.InOut == 1 ? "D10100" : "D10090"; // 入库口/出库口 task.NextAddress = "D10160"; // 阳极公共出库口 task.TargetAddress = "正极卷库"; } // 根据出入库类型设置目标地址 if (applyInOutDto.InOut == 1) // 入库 { var stockInfo = await _stockInfoService.GetStockInfoAsync(applyInOutDto.TrayNumber); if (stockInfo != null) return aGVResponse.Error($"当前托盘{applyInOutDto.TrayNumber}已经入库了"); task.TaskType = (int)TaskInboundTypeEnum.Inbound; task.TaskStatus = (int)TaskInStatusEnum.InNew; task.CurrentAddress = task.SourceAddress; // 当前在入库口 // 保存任务 var result = await BaseDal.AddDataAsync(task); } else // 出库 { // 判断是否移库 task.TaskType = (int)TaskOutboundTypeEnum.Outbound; task.TaskStatus = (int)TaskOutStatusEnum.OutNew; task.CurrentAddress = task.SourceAddress; // 当前在入库口 // 查找库存 var stockInfo = await _stockInfoService.GetStockInfoAsync(applyInOutDto.TrayNumber); if (stockInfo == null) return aGVResponse.Error($"未找到托盘{applyInOutDto.TrayNumber}的库存信息"); // 验证库存所属是否正确 if (stockInfo.WarehouseId != applyInOutDto.YinYang) return aGVResponse.Error($"托盘{applyInOutDto.TrayNumber}不属于当前{(applyInOutDto.YinYang == 1 ? "阴极" : "阳极")}"); if (stockInfo.StockStatus != (int)StockStatusEmun.入库完成) return aGVResponse.Error($"托盘{applyInOutDto.TrayNumber}正在移动中,请稍后!"); task.SourceAddress = stockInfo.LocationCode; // 源地址为货位 task.CurrentAddress = stockInfo.LocationCode; // 当前位置在货位 task.TargetAddress = applyInOutDto.YinYang == 1 ? "D10020" : "D10090"; // 目标地址为出库口 // 保存任务 var result = await BaseDal.AddDataAsync(task); // 判断是否移库 //var transferTask = await _locationInfoService.TransferCheckAsync(result); } // 构建响应数据 AGVDataDto aGVDataDto = new AGVDataDto { DevId = applyInOutDto.InOut == 1 ? task.SourceAddress : task.TargetAddress, TrayNumber = task.PalletCode, Group = applyInOutDto.Group, Width = applyInOutDto.Width ?? 0, LabelNumber = applyInOutDto.LabelNumber, ProductNo = applyInOutDto.ProductNo, ProductName = applyInOutDto.ProductName, Quantity = applyInOutDto.Quantity, UomCode = applyInOutDto.UomCode, ProductType = applyInOutDto.ProductType, Equipment = applyInOutDto.Equipment, ProductionDate = applyInOutDto.ProductionDate, LowerLimitTime = applyInOutDto.LowerLimitTime, WarningTime = applyInOutDto.WarningTime, OverdueTime = applyInOutDto.OverdueTime }; return aGVResponse.OK(aGVDataDto); } catch (Exception ex) { return aGVResponse.Error($"WMS任务创建接口错误: {ex.Message}"); } } /// /// 手动出库完成反馈给AGV /// /// 请求参数 /// public async Task OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto) { WebResponseContent webResponse = new WebResponseContent(); try { if (outTaskCompleteDto == null) return webResponse.Error("请求参数不能为空"); if (string.IsNullOrWhiteSpace(outTaskCompleteDto.TaskId)) return webResponse.Error("任务号不能为空"); if (string.IsNullOrWhiteSpace(outTaskCompleteDto.DevId)) return webResponse.Error("出库口编号不能为空"); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == outTaskCompleteDto.TaskId); if (task == null) return webResponse.Error("未找到任务信息"); outTaskCompleteDto.ReqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var httpResponse = _httpClientHelper.Post(AGV_OutTaskComplete, outTaskCompleteDto.ToJson()).Data; // 判断远程接口返回是否成功 if (httpResponse != null && httpResponse.Data != null) { AGVResponse agvResponse = httpResponse; // 根据code字段判断,code为true表示成功 if (agvResponse.Code == true) { var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return webResponse.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return webResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) { return webResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); } locationInfo.LocationStatus = (int)LocationStatusEnum.Free; _unitOfWorkManage.BeginTran(); BaseDal.DeleteData(task); _locationInfoService.UpdateData(locationInfo); _stockInfoService.DeleteData(stockInfo); _unitOfWorkManage.CommitTran(); return webResponse.OK(agvResponse.Msg); } else { // 失败:返回AGV返回的错误信息 return webResponse.Error(string.IsNullOrWhiteSpace(agvResponse.Msg) ? "AGV接口调用失败" : agvResponse.Msg); } } else { // HTTP请求本身失败 return webResponse.Error(httpResponse?.Msg ?? "AGV接口调用异常"); } } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return webResponse.Error($"WMS任务完成接口错误:{ex.Message}"); } } ///// ///// 任务完成接口 ///// ///// ///// //public async Task TaskCompleted(WCSTaskDTO wCSTask) //{ // WebResponseContent webResponse = new WebResponseContent(); // try // { // Dt_Task task = await BaseDal.QueryFirstAsync(x => x.TaskId == wCSTask.TaskNum && x.PalletCode == wCSTask.PalletCode); // if (task == null) return webResponse.Error("未找到任务信息"); // // 出库完成反馈 // OutTaskCompleteDto outTaskCompleteDto = new OutTaskCompleteDto() // { // TaskId = task.OrderNo, // DevId = task.TargetAddress, // ReqTime = DateTime.Now.ToString() // }; // return await OutTaskComplete(outTaskCompleteDto); // } // catch (Exception ex) // { // return webResponse.Error($"WMS任务完成接口错误:{ex.Message}"); // } //} /// /// 输送线申请进入 /// /// 请求参数 /// public async Task ApplyEnterAsync(ApplyEnterDto applyEnterDto) { AGVResponse aGVResponse = new AGVResponse(); try { // 参数验证 if (applyEnterDto == null) return aGVResponse.Error("请求参数不能为空"); if (string.IsNullOrWhiteSpace(applyEnterDto.DevId)) return aGVResponse.Error("设备编号不能为空"); if (string.IsNullOrWhiteSpace(applyEnterDto.TaskId)) return aGVResponse.Error("任务号不能为空"); if (applyEnterDto.InOut != 1 && applyEnterDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{applyEnterDto.InOut}"); // 查询任务是否存在 var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == applyEnterDto.TaskId); if (task == null) return aGVResponse.Error($"未找到任务信息,任务号:{applyEnterDto.TaskId}"); if (applyEnterDto.InOut == 1 && task.TaskType == (int)TaskInboundTypeEnum.Inbound && task.TaskStatus == (int)TaskInStatusEnum.InNew) { aGVResponse.OK(); } else if (applyEnterDto.InOut == 2 && task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TaskStatus == (int)TaskStatusEnum.Line_Finish) { aGVResponse.OK(); } return aGVResponse.Error($"输送线{applyEnterDto.DevId}当前繁忙,请稍后重试"); // Dt_Task.SourceAddress询问wcs站台1-阴极入口叫D10010和D10020;2-阳极D10090和D10100是否有货物 //var httpResponse = _httpClientHelper.Post("http://127.0.0.1:9999/api/Task/ApplyInOut", JsonSerializer.Serialize(task)).Data; //if (httpResponse != null && httpResponse.Status == true) //{ // _unitOfWorkManage.BeginTran(); // task.TaskStatus = (int)TaskStatusEnum.AGV_Executing; // await BaseDal.UpdateDataAsync(task); // _unitOfWorkManage.CommitTran(); // return aGVResponse.OK(); //} //else //{ // return aGVResponse.Error($"站台{task.SourceAddress}已经载货"); //} } catch (Exception ex) { //_unitOfWorkManage.RollbackTran(); return aGVResponse.Error($"WMS输送线申请接口错误:{ex.Message}"); } } /// /// 取放货完成 /// /// 请求参数 /// public async Task TaskCompleteAsync(TaskCompleteDto taskCompleteDto) { AGVResponse aGVResponse = new AGVResponse(); try { if (taskCompleteDto == null) return aGVResponse.Error("请求参数不能为空"); if (string.IsNullOrWhiteSpace(taskCompleteDto.TaskId)) return aGVResponse.Error("任务号不能为空"); if (string.IsNullOrWhiteSpace(taskCompleteDto.DevId)) return aGVResponse.Error("设备编号不能为空"); if (taskCompleteDto.InOut != 1 && taskCompleteDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{taskCompleteDto.InOut}"); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCompleteDto.TaskId); if (task == null) return aGVResponse.Error($"未找到任务信息,任务号:{taskCompleteDto.TaskId}"); if (taskCompleteDto.InOut == 2) { var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return aGVResponse.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return aGVResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) { return aGVResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); } locationInfo.LocationStatus = (int)LocationStatusEnum.Free; task.TaskStatus = (int)TaskOutStatusEnum.OutFinish; _unitOfWorkManage.BeginTran(); _stockInfoService.DeleteData(stockInfo); await _locationInfoService.UpdateLocationInfoAsync(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); } else { //查找可用货位 var availableLocation = await _locationInfoService.GetLocationInfo(task.Roadway); if (availableLocation == null) return aGVResponse.Error("无可用的入库货位"); task.TargetAddress = availableLocation.LocationCode; // 通知WCS入库 var wcsTaskDto = _mapper.Map(task); var httpResponse = _httpClientHelper.Post(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto)); if (httpResponse == null) return aGVResponse.Error("下发WCS失败"); task.TaskStatus = (int)TaskStatusEnum.Line_Executing; task.Dispatchertime = DateTime.Now; var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); if (locationInfo == null) return aGVResponse.Error($"未找到托盘{task.TargetAddress}的货位信息"); if (locationInfo.LocationStatus != (int)LocationStatusEnum.InStock) { return aGVResponse.Error($"当前货位{locationInfo.LocationStatus}状态信息错误"); } Dt_StockInfo dt_Stock = new Dt_StockInfo() { PalletCode = task.PalletCode, StockStatus = (int)StockStatusEmun.入库确认, LocationCode = locationInfo.LocationCode, WarehouseId = task.WarehouseId, Creater = "AGV", CreateDate = DateTime.Now }; locationInfo.LocationStatus = (int)LocationStatusEnum.FreeLock; _unitOfWorkManage.BeginTran(); BaseDal.UpdateData(task); _locationInfoService.UpdateData(locationInfo); _stockInfoService.AddData(dt_Stock); _unitOfWorkManage.CommitTran(); } return aGVResponse.OK(); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return aGVResponse.Error($"WMS取放货完成接口错误:{ex.Message}"); } } /// /// 任务取消 /// /// 请求参数 /// public async Task TaskCancelAsync(TaskCancelDto taskCancelDto) { AGVResponse aGVResponse = new AGVResponse(); try { if (taskCancelDto == null) return aGVResponse.Error("请求参数不能为空"); if (string.IsNullOrWhiteSpace(taskCancelDto.TaskId)) return aGVResponse.Error("任务号不能为空"); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCancelDto.TaskId); // 没有任务强制取消 if (task == null) return aGVResponse.OK(); if (task.TaskStatus == (int)TaskInStatusEnum.InNew) { task.TaskStatus = (int)TaskInStatusEnum.InCancel; // 入库任务直接删除 _unitOfWorkManage.BeginTran(); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); return aGVResponse.OK(); } else if (task.TaskStatus == (int)TaskOutStatusEnum.OutNew) { // 出库任务恢复库存 var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return aGVResponse.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return aGVResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) { return aGVResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); } stockInfo.StockStatus = (int)StockStatusEmun.入库完成; locationInfo.LocationStatus = (int)LocationStatusEnum.InStock; task.TaskStatus = (int)TaskOutStatusEnum.OutCancel; _unitOfWorkManage.BeginTran(); _locationInfoService.UpdateData(locationInfo); _stockInfoService.UpdateData(stockInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); return aGVResponse.OK(); } return aGVResponse.Error("任务已经在执行中,不可取消"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return aGVResponse.Error($"WMS任务取消接口错误:{ex.Message}"); } } #endregion 极卷库任务模块 } }