using WIDESEA_Common; using WIDESEA_DTO; namespace WIDESEA_StorageBasicService; public class LocationInfoService : ServiceBase, ILocationInfoService { private readonly LogFactory LogFactory = new LogFactory(); private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IDt_TaskRepository _taskRepository; private readonly IStockInfoRepository _stockInfoRepository; private readonly IDt_WareAreaInfoRepository _wareAreaInfoRepository; private readonly IPointStackerRelationRepository _pointStackerRelationRepository; private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository; private readonly ILocationStatusChangeRecordRepository _locationStatusChangeRecordRepository; public LocationInfoService(ILocationInfoRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IDt_TaskRepository taskRepository, IStockInfoRepository stockInfoRepository, IDt_WareAreaInfoRepository wareAreaInfoRepository, IPointStackerRelationRepository pointStackerRelationRepository, ITaskExecuteDetailRepository taskExecuteDetailRepository, ILocationStatusChangeRecordRepository locationStatusChangeRecordRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _taskRepository = taskRepository; _stockInfoRepository = stockInfoRepository; _wareAreaInfoRepository = wareAreaInfoRepository; _pointStackerRelationRepository = pointStackerRelationRepository; _taskExecuteDetailRepository = taskExecuteDetailRepository; _locationStatusChangeRecordRepository = locationStatusChangeRecordRepository; } /// /// 检查并生成移库任务或返回出库任务 /// /// 任务号 /// 任务对象 public virtual async Task TransferCheckAsync(int taskNum) { try { // 根据任务号获取任务 var outboundTask = await _taskRepository.QueryFirstAsync(x => x.TaskNum == taskNum); if (outboundTask == null) return null; LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "根据任务号获取任务", $"任务号:{taskNum},任务数据:{outboundTask}"); var location = await BaseDal.QueryFirstAsync(x => x.LocationCode == outboundTask.SourceAddress); LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "获取指定库位的货位数据", $"货位号:{outboundTask.SourceAddress},货位数据:{location}"); // 检查是否需要进行移库 if (CheckForInternalTransfer(location)) { LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库", $"货位号:{outboundTask.SourceAddress},货位数据:{location}"); // 计算对应位置的相对库位 (奇数行的下一行或者偶数行的上一行) var newLocationID = GetRelativeLocationID(location); LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,组建需要移库货位号", $"新的库位ID:{newLocationID}"); // 获取新的库位的任务 var internalTransferTask = await _taskRepository.QueryFirstAsync(x => x.SourceAddress == newLocationID && x.Roadway == outboundTask.Roadway); LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,获取新库位的任务", $"新库位任务:{internalTransferTask}"); // 如果新的库位没有找到对应的任务 if (internalTransferTask == null) { LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,未获取到新库位任务", $""); return await HandleNoTaskAtLocation(outboundTask.SourceAddress, newLocationID, outboundTask); } LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,获取到新库位任务直接返回", $"新库位任务:{internalTransferTask}"); // 直接返回一深位出库任务 return internalTransferTask; } // 返回当前库位的出库任务 return outboundTask; } catch (Exception) { return null; } } public override WebResponseContent UpdateData(SaveModel saveModel) { int id = saveModel.MainData["id"].ObjToInt(); int status = saveModel.MainData["locationStatus"].ObjToInt(); var location = BaseDal.QueryFirst(x => x.Id == id); LocationChangeRecordDto changeRecordDto = new LocationChangeRecordDto() { AfterStatus = status, BeforeStatus = location.LocationStatus, TaskNum = 0, LocationId = id, LocationCode = location.LocationCode, ChangeType = (int)StatusChangeTypeEnum.ManualOperation }; _locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); return base.UpdateData(saveModel); } #region 创建原始货位数据 /// /// 创建原始货位数据 /// /// 行 /// 列 /// 层 /// 货位类型(1、单深,2、双深) /// 库区编码 /// public WebResponseContent CreateLocation(int x, int y, int z, int locType, int areaId) { string[] chineseNumbers = new string[] { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }; var locationList = new List(); for (int line = 1; line <= x; line++) { for (int column = 1; column <= y; column++) { for (int layer = 1; layer <= z; layer++) { locationList.Add(new DtLocationInfo() { Row = line, Column = column, Layer = layer, LocationCode = line.ToString().PadLeft(3, '0') + '-' + column.ToString().PadLeft(3, '0') + '-' + layer.ToString().PadLeft(3, '0'), LocationName = ConvertToFormattedString(line, column, layer), LocationType = locType, Remark = "", Depth = locType > 1 ? (((line - 1) % 4) + 1) == 2 || (((line - 1) % 4) + 1) == 3 ? 1 : 2 : 1, RoadwayNo = locType > 1 ? $"CHSC{((line - 1) / 4) + 1}" : $"CHSC{((line - 1) / 2) + 1}", LocationStatus = LocationEnum.Free.ObjToInt(), AreaId = areaId, Creater = "systeam", EnalbeStatus = 2, }); } } } var isResult = BaseDal.AddData(locationList) > 0; if (isResult) return new WebResponseContent().OK(); else return new WebResponseContent().Error(); } #endregion 创建原始货位数据 #region 启用禁用货位 public WebResponseContent LocationEnable(SaveModel saveModel) { WebResponseContent content = new WebResponseContent(); try { List locations = new List(); int enable = Convert.ToBoolean(saveModel.Extra) ? 0 : 4; for (int i = 0; i < saveModel.DelKeys.Count; i++) { DtLocationInfo location = BaseDal.QueryData(x => x.Id == int.Parse(saveModel.DelKeys[i].ToString())).FirstOrDefault(); location.LocationStatus = enable; locations.Add(location); } BaseDal.UpdateData(locations); content = WebResponseContent.Instance.OK(); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } finally { //日志记录 } return content; } #endregion 启用禁用货位 #region 内部方法 #region 移库方法 /// /// 计算相对的库位ID /// /// 当前库位ID /// 相对的库位ID private string GetRelativeLocationID(DtLocationInfo locationInfo) { int line = locationInfo.Row; // 计算相对的货位行值,奇数行的下一行或者偶数行的上一行 int relativeLine = line % 2 == 1 ? line + 1 : line - 1; LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,计算相对行", $"原始货位行:{line},计算相对货位行:{relativeLine}"); // 构建新的库位ID string[] newLocationParts = new string[] { relativeLine.ToString().PadLeft(3, '0'), locationInfo.Column.ToString(), locationInfo.Layer.ToString() }; return string.Join("-", newLocationParts); } /// /// 处理没有任务的库位情况 /// /// 原始库位ID /// 新的库位ID /// 出库任务 /// 生成的移库任务或原始出库任务 private async Task HandleNoTaskAtLocation(string originalLocationID, string newLocationID, Dt_Task outboundTask) { // 判断该位置是否有库存 var stockInfo = await _stockInfoRepository.QueryFirstAsync(x => x.LocationCode == newLocationID); LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,未获取到新库位任务", $"该位置是否有库存:{stockInfo}"); if (stockInfo == null) { LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,未获取到库存数据", $"直接返回原先出库任务:{outboundTask}"); // 如果没有库存,直接返回当前出库任务 return outboundTask; } else { // 如果有库存,生成移库任务 var emptyLocation = await GetTransferLocationEmptyAsync(outboundTask.Roadway); LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,查找能移库货位", $"货位数据:{emptyLocation}"); var taskNo = await _taskRepository.GetTaskNo(); Dt_Task newTransferTask = new Dt_Task() { CreateDate = DateTime.Now, Creater = App.User.UserName, CurrentAddress = originalLocationID, Grade = 99, MaterialNo = stockInfo.StockInfoDetails[0].MaterielCode, NextAddress = emptyLocation.LocationCode, PalletCode = stockInfo.PalletCode, Remark = "移库", Roadway = stockInfo.LocationInfo.RoadwayNo, SourceAddress = originalLocationID, TaskNum = taskNo, TargetAddress = emptyLocation.LocationCode, //TaskState = TaskInStatusEnum.RelocationNew.ObjToInt(), TaskType = TaskTypeEnum.RelocationIn.ObjToInt(), }; LogFactory.GetLog("检查是否需要移库").InfoFormat(true, "需要移库,新建移库任务", $"移库任务数据:{newTransferTask}"); return await _taskRepository.Create(newTransferTask); } } /// /// 根据货位是否需要移库 /// /// 货位ID /// 是否需要移库 private bool CheckForInternalTransfer(DtLocationInfo location) { return location.Depth == 2 ? true : false; } /// /// 根据巷道获取二深位的空库位 /// /// 巷道 /// 货位对象 private async Task GetTransferLocationEmptyAsync(string roadway) { return await BaseDal.QueryFirstAsync(x => x.Depth == 2 && x.LocationStatus == LocationEnum.Free.ObjToInt() && x.RoadwayNo == roadway); //Db.Queryable() //.Where(x => x.Status == LocationEnum.Free.ObjToInt()) //.Where(x => x.Depth == 2.ToString()) //.Where(x => x.Roadway == roadway) //.First(); } #endregion 移库方法 #region 创建初始货位方法 public static string ConvertToFormattedString(int line, int column, int layer) { // 将每个部分转换为目标格式 string lineString = ConvertNumberToChineseString(line); string columnString = ConvertNumberToChineseString(column); string layerString = ConvertNumberToChineseString(layer); // 格式化输出 return $"{lineString}行{columnString}列{layerString}层"; } public static string ConvertNumberToChineseString(int number) { string[] chineseNumbers = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" }; if (number <= 10) { return chineseNumbers[number]; } // 处理大于10的数字 string result = string.Empty; if (number / 10 > 1) { result += chineseNumbers[number / 10] + "十"; } else { result += "十"; } if (number % 10 > 0) { result += chineseNumbers[number % 10]; } return result; } #endregion 创建初始货位方法 #endregion 内部方法 }