using WIDESEA_Common.StockEnum; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_DTO.Stock; using WIDESEA_IStockService; using WIDESEA_Model.Models; namespace WIDESEA_StockService { /// /// 库存信息服务实现类 /// public partial class StockInfoService : ServiceBase>, IStockInfoService { /// /// 获取库存信息仓储接口 /// public IRepository Repository => BaseDal; /// /// 构造函数 /// /// 基础数据访问对象 public StockInfoService(IRepository baseDal) : base(baseDal) { } /// /// 获取库存信息列表(出库日期小于当前时间且库存状态为入库完成的记录) /// /// 库存信息列表 public async Task> GetStockInfoAsync() { return await BaseDal.QueryDataAsync(x => x.OutboundDate < DateTime.Now && x.StockStatus == StockStatusEmun.入库完成.GetHashCode()); } /// /// 获取库存信息列表(出库日期小于当前时间且库存状态为入库完成的记录,且仓库ID匹配) /// /// 仓库ID /// 库存信息列表 public async Task> GetStockInfoAsync(int warehouseId) { return await BaseDal.QueryDataAsync(x => x.OutboundDate < DateTime.Now && x.StockStatus == StockStatusEmun.入库完成.GetHashCode() && x.WarehouseId == warehouseId); } /// /// 获取库存信息(根据托盘码查询) /// /// 托盘编码 /// 库存信息 public async Task GetStockInfoAsync(string palletCode) { return await BaseDal.QueryDataNavFirstAsync(x => x.PalletCode == palletCode); } /// /// 更新库存数据 /// /// 库存信息对象 /// 更新是否成功 public async Task UpdateStockAsync(Dt_StockInfo stockInfo) { return await BaseDal.UpdateDataAsync(stockInfo); } /// /// 检索指定托盘在给定位置的库存详细信息 /// /// 托盘编码 /// 货位编码 /// 库存信息 public async Task GetStockInfoAsync(string palletCode, string locationCode) { return await BaseDal.QueryFirstAsync(x => x.PalletCode == palletCode && x.LocationCode == locationCode); } /// /// 获取仓库3D布局数据 /// /// 仓库ID /// 3D布局DTO public async Task Get3DLayoutAsync(int warehouseId) { // 1. 查询仓库信息 var warehouse = await Repository.Change().GetFirstAsync(x => x.Id == warehouseId); // 2. 查询该仓库所有货位 var locations = await Repository.Change().GetListAsync(x => x.WarehouseId == warehouseId); // 3. 查询该仓库所有库存信息(包含Details导航属性) var stockInfos = await Repository.Change().Includes(x => x.Details).GetListAsync(x => x.WarehouseId == warehouseId); // 4. 提取物料编号和批次号列表(去重) var materielCodeList = stockInfos .SelectMany(s => s.Details) .Select(d => d.MaterielCode) .Where(c => !string.IsNullOrEmpty(c)) .Distinct() .ToList(); var batchNoList = stockInfos .SelectMany(s => s.Details) .Select(d => d.BatchNo) .Where(b => !string.IsNullOrEmpty(b)) .Distinct() .ToList(); // 5. 创建库存字典用于快速查找(以LocationId为键) var stockDict = stockInfos.ToDictionary(s => s.LocationId, s => s); // 6. 映射每个货位到Location3DItemDTO const float defaultMaxCapacity = 100f; var locationItems = locations.Select(loc => { var item = new Location3DItemDTO { LocationId = loc.Id, LocationCode = loc.LocationCode, Row = loc.Row, Column = loc.Column, Layer = loc.Layer, LocationStatus = loc.LocationStatus, MaxCapacity = defaultMaxCapacity }; // 尝试从库存字典中获取库存信息 if (stockDict.TryGetValue(loc.Id, out var stockInfo)) { item.PalletCode = stockInfo.PalletCode; item.StockQuantity = stockInfo.Details.Sum(d => d.StockQuantity); // 获取第一个明细的物料信息(如果存在) var firstDetail = stockInfo.Details.FirstOrDefault(); if (firstDetail != null) { item.MaterielCode = firstDetail.MaterielCode; item.MaterielName = firstDetail.MaterielName; item.BatchNo = firstDetail.BatchNo; } // 计算库存状态 var ratio = item.MaxCapacity > 0 ? item.StockQuantity / item.MaxCapacity : 0; if (ratio >= 0.9f) item.StockStatus = 3; // 已满 (FULL) else if (ratio >= 0.1f) item.StockStatus = 1; // 有货 (HAS_STOCK) else if (ratio > 0) item.StockStatus = 2; // 库存紧张 (LOW_STOCK) else item.StockStatus = 0; // 无货 (EMPTY) } else { item.StockStatus = 0; // 无货 (EMPTY) item.StockQuantity = 0; } return item; }).ToList(); // 7. 计算仓库尺寸 var maxRow = locations.Any() ? locations.Max(l => l.Row) : 0; var maxColumn = locations.Any() ? locations.Max(l => l.Column) : 0; var maxLayer = locations.Any() ? locations.Max(l => l.Layer) : 0; // 8. 构建返回结果 return new Stock3DLayoutDTO { WarehouseId = warehouseId, WarehouseName = warehouse?.WarehouseName ?? string.Empty, MaxRow = maxRow, MaxColumn = maxColumn, MaxLayer = maxLayer, MaterielCodeList = materielCodeList, BatchNoList = batchNoList, Locations = locationItems }; } } }