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; namespace WIDESEA_BasicService { public partial class LocationInfoService : ServiceBase>, ILocationInfoService { public IRepository Repository => BaseDal; public IRepository _taskRepository { get; } public IRepository _stockInfoRepository { get; set; } public LocationInfoService(IRepository BaseDal, IRepository taskRepository, IRepository stockInfoRepository) : base(BaseDal) { _taskRepository = taskRepository; _stockInfoRepository = stockInfoRepository; } /// /// 批量启用货位 /// 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); } } 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}", //$"{roadwayNo}-{row:D3}-{col:D3}-{layer:D3}-{depth:D2}" LocationName = $"{roadwayNo}巷道{row:D3}行{col:D3}列{layer:D3}层{depth:D2}深" }; } /// /// 获取空闲货位信息(根据巷道查询) /// 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(); } /// /// 获取货位信息(根据巷道和货位编码查询) /// 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) { WebResponseContent content = new WebResponseContent(); try { // 根据任务号获取任务 var outboundTask = await _taskRepository.QueryFirstAsync(x => x.TaskNum == taskNum); if (outboundTask == null) return null; var location = await BaseDal.QueryFirstAsync(x => x.LocationCode == outboundTask.SourceAddress); // 检查是否需要进行移库 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 /// 相对的库位ID private 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; } else { // 如果有库存,生成移库任务 var emptyLocation = await GetTransferLocationEmptyAsync(outboundTask.Roadway); var taskNo = await _taskRepository.GetTaskNo(); Dt_Task 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(); } } /// /// 根据货位是否需要移库 /// /// 货位ID /// 是否需要移库 private bool CheckForInternalTransfer(Dt_LocationInfo location) { return location.Depth == 2 ? true : false; } /// /// 根据巷道获取二深位的空库位 /// /// 巷道 /// 货位对象 private async Task GetTransferLocationEmptyAsync(string roadway) { return await BaseDal.QueryFirstAsync(x => x.Depth == 2 && x.LocationStatus == (LocationStatusEnum.Free.GetHashCode()) && 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 移库方法 } }