using AngleSharp.Io; using System.Threading.Tasks; namespace WIDESEA_StorageTaskServices; public partial class Dt_TaskService : ServiceBase, IDt_TaskService { private readonly LogFactory LogFactory = new LogFactory(); private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IStockInfoRepository _stockInfoRepository; private readonly IStockInfoDetailRepository _stockInfoDetailRepository; private readonly IDt_Task_HtyRepository _task_HtyRepository; private readonly IMapper _mapper; private readonly ILocationInfoRepository _locationRepository; private readonly ILocationStatusChangeRecordRepository _locationStatusChangeRecordRepository; private readonly IBoxingInfoRepository _boxingInfoRepository; //组盘 private readonly IDt_AreaInfoRepository _areaInfoRepository; //区域 private readonly IDt_StationManagerRepository _stationManagerRepository; private readonly ISys_ConfigService _configService; private readonly IDt_WareAreaInfoRepository _wareAreaInfoRepository; public Dt_TaskService(IDt_TaskRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoRepository stockInfoRepository, IDt_Task_HtyRepository task_HtyRepository, IMapper mapper, ILocationInfoRepository locationRepository, ILocationStatusChangeRecordRepository locationStatusChangeRecordRepository, IBoxingInfoRepository boxingInfoRepository, IDt_AreaInfoRepository areaInfoRepository, IStockInfoDetailRepository stockInfoDetailRepository, IDt_StationManagerRepository stationManagerRepository, ISys_ConfigService configService, IDt_WareAreaInfoRepository wareAreaInfoRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _stockInfoRepository = stockInfoRepository; _task_HtyRepository = task_HtyRepository; _mapper = mapper; _locationRepository = locationRepository; _locationStatusChangeRecordRepository = locationStatusChangeRecordRepository; _boxingInfoRepository = boxingInfoRepository; _areaInfoRepository = areaInfoRepository; _stockInfoDetailRepository = stockInfoDetailRepository; _stationManagerRepository = stationManagerRepository; _configService = configService; _wareAreaInfoRepository = wareAreaInfoRepository; } #region 外部接口方法 #region 出库任务完成 public async Task CompleteOutboundTaskAsync(Dt_Task task, DtStockInfo stock) { WebResponseContent content = new WebResponseContent(); try { (var loc, var tas) = UpdateStockAndTaskStatus(stock, task); // 事务处理 _unitOfWorkManage.BeginTran(); checked { await UpdateLocationAsync(loc); BaseDal.DeleteAndMoveIntoHty(tas, App.User.UserName != null ? OperateTypeEnum.人工完成 : OperateTypeEnum.自动完成); _stockInfoRepository.DeleteAndMoveIntoHty(stock, App.User.UserName != null ? OperateTypeEnum.人工完成 : OperateTypeEnum.自动完成); } _unitOfWorkManage.CommitTran(); return content.OK("任务完成成功"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); task.ErrorMessage = ex.Message; await BaseDal.UpdateDataAsync(task); return content.Error(ex.Message); } } private (DtLocationInfo, Dt_Task) UpdateStockAndTaskStatus(DtStockInfo stock, Dt_Task task) { var location = _locationRepository.QueryFirst(x => x.LocationCode == task.SourceAddress && x.RoadwayNo == task.Roadway); int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.Free; task.TaskState = (int)TaskOutStatusEnum.OutFinish; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticOutbound, task.TaskNum); LogFactory.GetLog("任务完成").Info(true, "更新库存状态与任务状态"); return (location, task); } #endregion 出库任务完成 #region 入库任务完成 /// /// 完成入库任务 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteInboundTaskAsync(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { var boxinfo = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode); if (boxinfo == null) { return content.Error("未找到组盘数据"); } var stock = CreateStock(boxinfo, task); var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress && x.RoadwayNo == task.Roadway); int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.InStock; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticInbound, task.TaskNum); task.TaskState = (int)TaskInStatusEnum.InFinish; _unitOfWorkManage.BeginTran(); checked { BaseDal.DeleteAndMoveIntoHty(task, App.User.UserName != null ? OperateTypeEnum.人工完成 : OperateTypeEnum.自动完成); await _stockInfoRepository.AddDataNavAsync(stock); await _locationRepository.UpdateDataAsync(location); } _unitOfWorkManage.CommitTran(); content.OK("入库完成"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); task.ErrorMessage = ex.Message; await BaseDal.UpdateDataAsync(task); return content.Error(ex.Message); } return content; } public DtStockInfo CreateStock(DtBoxingInfo boxingInfo,Dt_Task task) { return new DtStockInfo() { PalletCode = task.PalletCode, LocationCode = task.TargetAddress, CreateDate = DateTime.Now, MaterielName = boxingInfo.MaterielName, OutboundTime = Convert.ToDateTime(DateTime.Now).AddHours(Convert.ToDouble(12)), LinedProcessFeedbackTime = DateTime.Now.ToString(), SpecialParameterDuration = 12.ToString(), Creater = "System", IsFull = boxingInfo.IsFull, StockStatus = (int)StockStateEmun.已入库 }; } #endregion 入库任务完成 #region 任务完成 /// /// 完成任务 /// /// 任务编号 /// 返回结果集 public async Task CompleteAsync(int taskNum) { // 初始化响应内容 WebResponseContent content = new WebResponseContent(); // 提取任务数据 LogFactory.GetLog("任务完成").InfoFormat(true, "提取任务数据", $"任务号:{taskNum}"); // 验证任务是否存在0 var task = await GetByTaskNum(taskNum); if (task == null) { return content.Error("任务不存在"); } LogFactory.GetLog("任务完成").InfoFormat(true, "验证任务是否存在", JsonConvert.SerializeObject(task)); // 验证库存是否存在 var stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode); if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { return await CompleteOutboundTaskAsync(task, stock); } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup) { return await CompleteInboundTaskAsync(task); } else { return content.Error("未找到任务类型"); } } #endregion 任务完成 #region 取消任务 public WebResponseContent TaskCancel(int taskNum) { WebResponseContent content = new WebResponseContent(); try { return content = WebResponseContent.Instance.Error("未找到任务类型对应业务处理逻辑"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content = WebResponseContent.Instance.Error(ex.Message); } } #endregion #region 请求任务入库 public async Task RequestInboundTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == taskDto.PalletCode); if (task != null) { return content.Error($"托盘【{taskDto.PalletCode}】存在任务"); } var boxInfo = await _boxingInfoRepository.QueryFirstAsync(x => x.PalletCode == taskDto.PalletCode); if (boxInfo == null && taskDto.IsFull) { return content.Error("未找到托盘组盘信息"); } var location = await GetEmptyLocation(taskDto.AreaId); if (location == null) { return content.Error("未找到空闲货位"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = taskDto.PalletCode, SourceAddress = taskDto.Position, TargetAddress = location.LocationCode, CurrentAddress = taskDto.Position, NextAddress = location.LocationCode, TaskType = taskDto.IsFull ? (int)TaskInboundTypeEnum.Inbound : (int)TaskInboundTypeEnum.InTray, TaskState = (int)TaskInStatusEnum.InNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = location.RoadwayNo, }; int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.Lock; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticInbound, taskNew.TaskNum); BaseDal.AddData(taskNew); _locationRepository.UpdateData(location); var taskDTO = CreateTaskDTO(taskNew); return content.OK(data: taskDTO); } catch (Exception err) { return content.Error(err.Message); } } /// /// 直接请求入库任务(直接进入GW或CW流程,不进入缓存库流程) /// /// /// public async Task RequsetInToGWOrCW(RequestTaskDto request) { WebResponseContent content = new WebResponseContent(); try { var stationManager = await _stationManagerRepository.QueryFirstAsync(x => x.stationChildCode == request.Position); if (stationManager == null) { return content.Error("未找到站台配置"); } var nextStation = _stationManagerRepository.QueryFirst(x => x.stationChildCode == request.TargetStationManager); var task = await BaseDal.QueryFirstAsync(x => x.SourceAddress == request.Position || x.TargetAddress == request.TargetAddress); if (task != null) { return content.Error($"终点地址【{request.TargetAddress}】或起点地址【{request.Position}】存在任务"); } var location = await _locationRepository.QueryFirstAsync(x => x.RoadwayNo == nextStation.stationChildCode && x.Remark == request.TargetAddress); if (location == null) { return content.Error($"未找到目标地址【{request.TargetStationManager}-{request.TargetAddress}】的货位信息"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = "", SourceAddress = request.Position, TargetAddress = request.TargetStationManager, CurrentAddress = stationManager.stationLocation, NextAddress = location.LocationCode, TaskType = (int)TaskInboundTypeEnum.Inbound, TaskState = (int)TaskInStatusEnum.InNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = stationManager.Roadway, Creater = App.User.UserName != null ? App.User.UserName : "System", CreateDate = DateTime.Now, }; BaseDal.AddData(taskNew); var taskDTO = CreateTaskDTO(taskNew); return content.OK(data: taskDTO); } catch (Exception ex) { return content.Error(ex.Message); } } public async Task PDARequestInboundTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == taskDto.PalletCode); if (task != null) { return content.Error($"托盘【{taskDto.PalletCode}】存在任务"); } var boxInfo = await _boxingInfoRepository.QueryFirstAsync(x => x.PalletCode == taskDto.PalletCode); if (boxInfo == null && taskDto.IsFull) { return content.Error("未找到托盘组盘信息"); } var location = await GetEmptyLocation(taskDto.AreaId); if (location == null) { return content.Error("未找到空闲货位"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = taskDto.PalletCode, SourceAddress = taskDto.Position, TargetAddress = location.LocationCode, CurrentAddress = taskDto.Position, NextAddress = location.LocationCode, TaskType = taskDto.IsFull ? (int)TaskInboundTypeEnum.Inbound : (int)TaskInboundTypeEnum.InTray, TaskState = (int)TaskInStatusEnum.InNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = location.RoadwayNo, }; int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.Lock; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticInbound, taskNew.TaskNum); BaseDal.AddData(taskNew); _locationRepository.UpdateData(location); var taskDTO = CreateTaskDTO(taskNew); content = await SendWCSTask(taskDTO); return content; } catch (Exception err) { return content.Error(err.Message); } } #endregion 请求任务入库 #region 更新任务状态 /// /// 更新任务货位 /// /// /// public async Task UpdateTaskStatus(int taskNum, int taskState) { WebResponseContent content = new WebResponseContent(); try { var task = await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); if (task == null) return content.Error("未找到任务"); task.TaskState = taskState; var asb = await BaseDal.UpdateDataAsync(task); if (asb) content.OK(); else content.Error(); } catch (Exception ex) { content.Error(ex.Message); } return content; } #endregion #region 请求出库(实盘&空盘) /// /// 请求出库(实盘&空盘) /// /// /// public async Task RequestOutboundTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var stationManager = await _stationManagerRepository.QueryFirstAsync(x => x.stationChildCode == taskDto.Position); if (stationManager == null) { return content.Error("未找到站台配置"); } var task = await BaseDal.QueryFirstAsync(x => x.TargetAddress == taskDto.Position); if (task != null) { return content.Error($"终点地址【{taskDto.Position}】存在任务"); } var stock = await _stockInfoRepository.QueryFirstAsync(x => x.MaterielName == stationManager.stationMaterialCode); if (stock == null) { return content.Error($"设备【{taskDto.Position}】物料编码【{stationManager.stationMaterialCode}】未找到库存数据"); } var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == stock.LocationCode); if (location == null) { return content.Error($"设备【{taskDto.Position}】物料编码【{stationManager.stationMaterialCode}】未找到货位信息"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = stock.PalletCode, SourceAddress = location.LocationCode, TargetAddress = taskDto.Position, CurrentAddress = location.LocationCode, NextAddress = stationManager.stationLocation, TaskType = taskDto.IsFull ? (int)TaskOutboundTypeEnum.Outbound : (int)TaskOutboundTypeEnum.OutTray, TaskState = (int)TaskOutStatusEnum.OutNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = location.RoadwayNo, Creater = App.User.UserName != null ? App.User.UserName : "System", CreateDate = DateTime.Now, }; int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.InStockDisable; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticInbound, taskNew.TaskNum); BaseDal.AddData(taskNew); _locationRepository.UpdateData(location); var taskDTO = CreateTaskDTO(taskNew); return content.OK(data: taskDTO); } catch (Exception ex) { return content.Error(ex.Message); } } public async Task RequestInToOutTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var stationManager = await _stationManagerRepository.QueryFirstAsync(x => x.stationChildCode == taskDto.Position); if (stationManager == null) { return content.Error("未找到站台配置"); } var nextStation = _stationManagerRepository.QueryFirst(x => x.stationProcessCode == taskDto.TargetAddress); var task = await BaseDal.QueryFirstAsync(x => x.SourceAddress == taskDto.Position || x.TargetAddress == taskDto.TargetAddress); if (task != null) { return content.Error($"终点地址【{taskDto.TargetAddress}】或起点地址【{taskDto.Position}】存在任务"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = "", SourceAddress = taskDto.Position, TargetAddress = taskDto.TargetAddress, CurrentAddress = stationManager.stationLocation, NextAddress = nextStation.stationLocation, TaskType = (int)TaskOutboundTypeEnum.InToOut, TaskState = (int)TaskOutStatusEnum.OutNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = stationManager.Roadway, Creater = App.User.UserName != null ? App.User.UserName : "System", CreateDate = DateTime.Now, }; BaseDal.AddData(taskNew); var taskDTO = CreateTaskDTO(taskNew); return content.OK(data: taskDTO); } catch (Exception ex) { return content.Error(ex.Message); } } public async Task PDARequestOutboundTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var stock = await _stockInfoRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (stock == null) { return content.Error("未找到库存信息"); } var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == stock.PalletCode); if (task != null) { return content.Error($"托盘【{stock.PalletCode}】存在任务"); } var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (location == null) { return content.Error("未找到货位信息"); } var taskNew = new Dt_Task { TaskNum = BaseDal.GetTaskNo().Result, PalletCode = stock.PalletCode, SourceAddress = taskDto.Position, TargetAddress = taskDto.TargetAddress, CurrentAddress = taskDto.Position, NextAddress = taskDto.TargetAddress, TaskType = taskDto.IsFull ? (int)TaskOutboundTypeEnum.Outbound : (int)TaskOutboundTypeEnum.OutTray, TaskState = (int)TaskOutStatusEnum.OutNew, Grade = 1, Dispatchertime = DateTime.Now, Roadway = location.RoadwayNo, Creater = App.User.UserName != null ? App.User.UserName : "System", CreateDate = DateTime.Now, }; int lastStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.InStockDisable; _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(location, lastStatus, (int)StatusChangeTypeEnum.AutomaticInbound, taskNew.TaskNum); BaseDal.AddData(taskNew); _locationRepository.UpdateData(location); var taskDTO = CreateTaskDTO(taskNew); content = await SendWCSTask(taskDTO); return content; } catch (Exception ex) { return content.Error(ex.Message); } } #endregion 请求出库(实盘&空盘) #region 获取AGV任务号 private static readonly Random _random = new Random(); public static string GenerateUniqueId() { // 获取当前毫秒级时间戳 long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); // 生成4位随机数(0000-9999) int randomNumber = _random.Next(0, 10000); string randomPart = randomNumber.ToString("D4"); // 补零到4位 return $"{timestamp}{randomPart}"; } #endregion #region 获取任务信息 public WebResponseContent GetTaskInfo() { WebResponseContent content = new WebResponseContent(); try { Expression> expression = x => true; if (!App.User.IsSuperAdmin) { expression = x => x.Creater == App.User.UserName; } var task = BaseDal.Db.Queryable().OrderByDescending(x => x.CreateDate).Take(100).Select(x => new Dt_Task { TaskNum = x.TaskNum, PalletCode = x.PalletCode, TaskType = x.TaskType, SourceAddress = x.SourceAddress, TargetAddress = x.TargetAddress }).ToList(); content = WebResponseContent.Instance.OK(data: task); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } #endregion #endregion 外部接口方法 #region 调用WCS接口 private string GetWCSIPAddress(string baseIp, string name) { var configz = _configService.GetConfigsByCategory(CateGoryConst.CONFIG_SYS_IPAddress); var wcsBasez = configz.Where(x => x.ConfigKey == baseIp).FirstOrDefault()?.ConfigValue; var address = configz.Where(x => x.ConfigKey == name).FirstOrDefault()?.ConfigValue; if (wcsBasez == null || address == null) { throw new InvalidOperationException("WMS IP 未配置"); } return wcsBasez + address; } public async Task SendWCSTask(WMSTaskDTO taskDTO) { WebResponseContent content = new WebResponseContent(); var SendTask = GetWCSIPAddress(SysConfigConst.WCSIPAddress, SysConfigConst.ReceiveTask); // 发送请求并等待响应 var result = await HttpHelper.PostAsync(SendTask, taskDTO.ToJsonString()); content = JsonConvert.DeserializeObject(result.ToString()); return content; } #endregion #region 内部调用方法 private WMSTaskDTO CreateTaskDTO(Dt_Task task) { return new WMSTaskDTO { TaskNum = task.TaskNum.Value, Grade = task.Grade.Value, PalletCode = task.PalletCode, RoadWay = task.Roadway, SourceAddress = task.SourceAddress, TargetAddress = task.TargetAddress, CurrentAddress = task.CurrentAddress, NextAddress = task.NextAddress, TaskState = task.TaskState, Id = 0, TaskType = task.TaskType, }; } private List CreateTaskDTO(List task) { List taskNews = new List(); foreach (var item in task) { taskNews.Add(new WMSTaskDTO { TaskNum = item.TaskNum.Value, Grade = item.Grade.Value, PalletCode = item.PalletCode, RoadWay = item.Roadway, SourceAddress = item.SourceAddress, CurrentAddress = item.CurrentAddress, NextAddress = item.NextAddress, TaskState = item.TaskState, Id = 0, TaskType = item.TaskType, }); } return taskNews; } private async Task UpdateLocationAsync(DtLocationInfo info) { var isStockUpdated = await _locationRepository.UpdateDataAsync(info); if (!isStockUpdated) { throw new Exception("库位信息更新失败"); } } public override WebResponseContent DeleteData(object[] key) { WebResponseContent content = new WebResponseContent(); // 创建历史任务实例模型 try { foreach (var item in key) { Dt_Task task = BaseDal.QueryFirst(x => x.TaskId == Convert.ToInt32(key)); if (task == null) { return content.Error("未找到任务信息!"); } task.TaskState = task.TaskType > 199 ? (int)TaskInStatusEnum.InFinish : (int)TaskOutStatusEnum.OutFinish; BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.人工删除); } return content.OK("删除成功!"); } catch (Exception ex) { return content.Error("删除任务异常:" + ex.Message); } } /// /// 根据任务号获取任务 /// /// /// public async Task GetByTaskNum(int taskNum) { return await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); } #endregion 内部调用方法 #region private 内部方法 #region 任务请求方法 private static readonly SemaphoreSlim _semaphoreUpdate = new SemaphoreSlim(1, 1); /// /// 获取货位号 /// /// public async Task GetEmptyLocation(int area) { List locations = await _locationRepository.QueryDataAsync(x => x.AreaId == area && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1); if (locations.Count == 0) { return null; } return locations.OrderBy(x => x.Row).OrderBy(x => x.Column).ThenBy(x => x.Layer).FirstOrDefault(); } #endregion 任务请求方法 #endregion private 内部方法 }