using WIDESEA_Common.LocationEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Utilities; using WIDESEA_DTO.Basic; using WIDESEA_IBasicService; using WIDESEA_Model.Models; using WIDESEA_Common.CommonEnum; namespace WIDESEA_BasicService { /// /// 货位信息服务实现类 /// public partial class LocationInfoService : ServiceBase>, ILocationInfoService { private readonly IRepository _taskRepository; private readonly IRepository _stockInfoRepository; /// /// 构造函数 /// /// 基础数据访问对象 /// 任务仓储 /// 库存信息仓储 public LocationInfoService( IRepository baseDal, IRepository taskRepository, IRepository stockInfoRepository) : base(baseDal) { _taskRepository = taskRepository; _stockInfoRepository = stockInfoRepository; } /// /// 获取货位信息仓储 /// public IRepository Repository => BaseDal; /// /// 批量启用货位 /// /// 货位主键数组 /// 操作结果 public WebResponseContent LocationEnableStatus(int[] keys) { var locationInfos = Repository.QueryData(x => keys.Contains(x.Id)); locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Normal.GetHashCode()); Repository.UpdateData(locationInfos); return WebResponseContent.Instance.OK(); } /// /// 批量禁用货位 /// /// 货位主键数组 /// 操作结果 public WebResponseContent LocationDisableStatus(int[] keys) { var locationInfos = Repository.QueryData(x => keys.Contains(x.Id)); locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Disable.GetHashCode()); Repository.UpdateData(locationInfos); return WebResponseContent.Instance.OK(); } /// /// 单个启用货位 /// /// 货位主键 /// 操作结果 public WebResponseContent LocationEnableStatus(int key) => LocationEnableStatus(new[] { key }); /// /// 单个禁用货位 /// /// 货位主键 /// 操作结果 public WebResponseContent LocationDisableStatus(int key) => LocationDisableStatus(new[] { key }); /// /// 初始化货位 /// /// 初始化货位数据传输对象 /// 操作结果 public WebResponseContent InitializationLocation(InitializationLocationDTO dto) { try { var (isValid, errorMsg, _) = ModelValidate.ValidateModelData(dto); if (!isValid) return WebResponseContent.Instance.Error(errorMsg); var locationInfos = new List(); int depth = dto.Depth; for (int row = 1; row <= dto.MaxRow; row++) { depth = CalculateDepth(row, dto.MaxRow, dto.Depth, depth); for (int col = 1; col <= dto.MaxColumn; col++) { for (int layer = 1; layer <= dto.MaxLayer; layer++) { var location = CreateLocationInfo(dto.Roadway, row, col, layer, depth); locationInfos.Add(location); } } } BaseDal.AddData(locationInfos); return WebResponseContent.Instance.OK(); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// 根据巷道获取空闲货位信息 /// /// 巷道编号 /// 空闲货位信息,如果未找到则返回null public async Task GetLocationInfo(string roadwayNo) { var locations = await BaseDal.QueryDataAsync(x => x.EnableStatus == EnableStatusEnum.Normal.GetHashCode() && x.RoadwayNo == roadwayNo && x.LocationStatus == LocationStatusEnum.Free.GetHashCode()); return locations? .OrderBy(x => x.Layer) .ThenByDescending(x => x.Depth) .ThenBy(x => x.Column) .ThenBy(x => x.Row) .FirstOrDefault(); } /// /// 根据巷道和货位编码获取空闲货位信息 /// /// 巷道编号 /// 货位编码 /// 货位信息,如果未找到则返回null public async Task GetLocationInfo(string roadwayNo, string locationCode) { return await BaseDal.QueryFirstAsync(x => x.RoadwayNo == roadwayNo && x.LocationCode == locationCode); } /// /// 根据货位编码获取货位信息 /// /// 货位编码 /// 货位信息 public async Task GetLocationInfoAsync(string locationCode) { return await BaseDal.QueryFirstAsync(x => x.LocationCode == locationCode); } /// /// 更新货位信息 /// /// 货位信息对象 /// 更新是否成功 public async Task UpdateLocationInfoAsync(Dt_LocationInfo locationInfo) { return await BaseDal.UpdateDataAsync(locationInfo); } /// /// 检查并生成移库任务或返回出库任务 /// /// 任务号 /// 任务信息 public async Task TransferCheckAsync(int taskNum) { var content = new WebResponseContent(); try { // 根据任务号获取任务 var outboundTask = await _taskRepository.QueryFirstAsync(x => x.TaskNum == taskNum); if (outboundTask == null) return content.Error("任务不存在"); var location = await BaseDal.QueryFirstAsync(x => x.LocationCode == outboundTask.SourceAddress && x.RoadwayNo == outboundTask.Roadway); // 检查是否需要进行移库 if (CheckForInternalTransfer(location)) { // 计算对应位置的相对库位(奇数行的下一行或者偶数行的上一行) var newLocationID = GetRelativeLocationID(location); // 获取新的库位的任务 var internalTransferTask = await _taskRepository.QueryFirstAsync(x => x.SourceAddress == newLocationID && x.Roadway == outboundTask.Roadway); // 如果新的库位没有找到对应的任务 if (internalTransferTask == null) { return content.OK("获取到移库任务", await HandleNoTaskAtLocation(outboundTask.SourceAddress, newLocationID, outboundTask)); } // 直接返回一深位出库任务 return content.OK("获取到一深位出库任务", internalTransferTask); } // 返回当前库位的出库任务 return content.OK("当前出库任务", outboundTask); } catch (Exception ex) { return content.Error($"发生错误:{ex.Message}"); } } #region 私有方法 /// /// 计算相对的库位ID /// /// 货位信息 /// 相对的库位ID private static string GetRelativeLocationID(Dt_LocationInfo locationInfo) { int line = locationInfo.Row; // 计算相对的货位行值,奇数行的下一行或者偶数行的上一行 int relativeLine = line % 2 == 1 ? line + 1 : line - 1; // 构建新的库位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); if (stockInfo == null) { // 如果没有库存,直接返回当前出库任务 return outboundTask; } if (stockInfo == null) { // 如果没有库存,直接返回当前出库任务 return outboundTask; } // 如果有库存,生成移库任务 var emptyLocation = await GetTransferLocationEmptyAsync(outboundTask.Roadway); var taskNo = await _taskRepository.GetTaskNo(); var newTransferTask = new Dt_Task { CreateDate = DateTime.Now, Creater = App.User.UserName, CurrentAddress = originalLocationID, Grade = 99, NextAddress = emptyLocation.LocationCode, PalletCode = stockInfo.PalletCode, Remark = "移库", Roadway = stockInfo.LocationDetails.RoadwayNo, SourceAddress = originalLocationID, TaskNum = taskNo, TargetAddress = emptyLocation.LocationCode, TaskType = TaskTypeEnum.Relocation.GetHashCode() }; return await _taskRepository.Db.Insertable(newTransferTask).ExecuteReturnEntityAsync(); } /// /// 检查货位是否需要移库 /// /// 货位信息 /// 是否需要移库 private static bool CheckForInternalTransfer(Dt_LocationInfo location) { return location.Depth == 2; } /// /// 根据巷道获取二深位的空库位 /// /// 巷道编号 /// 货位对象 private async Task GetTransferLocationEmptyAsync(string roadway) { return await BaseDal.QueryFirstAsync(x => x.Depth == 2 && x.LocationStatus == LocationStatusEnum.Free.GetHashCode() && x.RoadwayNo == roadway); } /// /// 计算深度 /// /// 行号 /// 最大行数 /// 最大深度 /// 当前深度 /// 计算后的深度 private static int CalculateDepth(int row, int maxRow, int maxDepth, int currentDepth) { int mod = row % maxRow; if (mod == 1) return maxDepth; if (mod == maxDepth + 1) return 1; if (mod > 1 && mod <= maxDepth) return currentDepth - 1; return currentDepth + 1; } /// /// 创建货位信息 /// /// 巷道编号 /// 行号 /// 列号 /// 层数 /// 深度 /// 货位信息对象 private static Dt_LocationInfo CreateLocationInfo(string roadwayNo, int row, int col, int layer, int depth) { return new Dt_LocationInfo { WarehouseId = 0, Row = row, Column = col, Layer = layer, Depth = depth, RoadwayNo = roadwayNo, EnableStatus = EnableStatusEnum.Normal.GetHashCode(), LocationStatus = LocationStatusEnum.Free.GetHashCode(), LocationType = LocationTypeEnum.Undefined.GetHashCode(), LocationCode = $"{row:D3}-{col:D3}-{layer:D3}", LocationName = $"{roadwayNo}巷道{row:D3}行{col:D3}列{layer:D3}层{depth:D2}深" }; } #endregion 私有方法 } }