refactor(mat): 优化物料库存查询性能并移除冗余VO类

- 移除 MatMaterialWithInventoryVo 类,将库存相关字段直接添加到 MatMaterialVo 中
- 重构 queryPageListWithInventory 和 queryListWithInventory 方法,使用批量查询替代 N+1 查询
- 实现 batchQueryMaterialInventory 方法以提高库存信息查询效率
- 更新控制器中的返回类型从 MatMaterialWithInventoryVo 到 MatMaterialVo
- 修改 Excel 导出功能以使用新的数据结构
This commit is contained in:
2026-01-31 13:12:07 +08:00
parent 6a223fb82a
commit f385188684
4 changed files with 134 additions and 105 deletions

View File

@@ -21,7 +21,6 @@ import com.gear.common.core.validate.QueryGroup;
import com.gear.common.enums.BusinessType; import com.gear.common.enums.BusinessType;
import com.gear.common.utils.poi.ExcelUtil; import com.gear.common.utils.poi.ExcelUtil;
import com.gear.mat.domain.vo.MatMaterialVo; import com.gear.mat.domain.vo.MatMaterialVo;
import com.gear.mat.domain.vo.MatMaterialWithInventoryVo;
import com.gear.mat.domain.bo.MatMaterialBo; import com.gear.mat.domain.bo.MatMaterialBo;
import com.gear.mat.service.IMatMaterialService; import com.gear.mat.service.IMatMaterialService;
import com.gear.common.core.page.TableDataInfo; import com.gear.common.core.page.TableDataInfo;
@@ -44,7 +43,7 @@ public class MatMaterialController extends BaseController {
* 查询配料配件基础信息列表 * 查询配料配件基础信息列表
*/ */
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo<MatMaterialWithInventoryVo> list(MatMaterialBo bo, PageQuery pageQuery) { public TableDataInfo<MatMaterialVo> list(MatMaterialBo bo, PageQuery pageQuery) {
return iMatMaterialService.queryPageListWithInventory(bo, pageQuery); return iMatMaterialService.queryPageListWithInventory(bo, pageQuery);
} }
@@ -55,8 +54,8 @@ public class MatMaterialController extends BaseController {
@PostMapping("/export") @PostMapping("/export")
public void export(MatMaterialBo bo, HttpServletResponse response) { public void export(MatMaterialBo bo, HttpServletResponse response) {
// 使用增强的服务方法获取带库存信息的物料列表 // 使用增强的服务方法获取带库存信息的物料列表
List<MatMaterialWithInventoryVo> list = iMatMaterialService.queryListWithInventory(bo); List<MatMaterialVo> list = iMatMaterialService.queryListWithInventory(bo);
ExcelUtil.exportExcel(list, "配料配件基础信息", MatMaterialWithInventoryVo.class, response); ExcelUtil.exportExcel(list, "配料配件基础信息", MatMaterialVo.class, response);
} }
/** /**

View File

@@ -71,5 +71,19 @@ public class MatMaterialVo {
@ExcelProperty(value = "备注") @ExcelProperty(value = "备注")
private String remark; private String remark;
/**
* 在途数量(未完成入库的采购数量)
*/
private transient BigDecimal inTransitNum;
/**
* 计划采购总数量
*/
private transient BigDecimal planNum;
/**
* 已入库数量
*/
private transient BigDecimal receivedNum;
} }

View File

@@ -2,7 +2,6 @@ package com.gear.mat.service;
import com.gear.mat.domain.MatMaterial; import com.gear.mat.domain.MatMaterial;
import com.gear.mat.domain.vo.MatMaterialVo; import com.gear.mat.domain.vo.MatMaterialVo;
import com.gear.mat.domain.vo.MatMaterialWithInventoryVo;
import com.gear.mat.domain.bo.MatMaterialBo; import com.gear.mat.domain.bo.MatMaterialBo;
import com.gear.common.core.page.TableDataInfo; import com.gear.common.core.page.TableDataInfo;
import com.gear.common.core.domain.PageQuery; import com.gear.common.core.domain.PageQuery;
@@ -36,7 +35,7 @@ public interface IMatMaterialService {
/** /**
* 查询配料配件基础信息列表(包含库存信息) * 查询配料配件基础信息列表(包含库存信息)
*/ */
List<MatMaterialWithInventoryVo> queryListWithInventory(MatMaterialBo bo); List<MatMaterialVo> queryListWithInventory(MatMaterialBo bo);
/** /**
* 新增配料配件基础信息 * 新增配料配件基础信息
@@ -56,5 +55,5 @@ public interface IMatMaterialService {
/** /**
* 查询配料配件基础信息列表(包含库存信息) * 查询配料配件基础信息列表(包含库存信息)
*/ */
TableDataInfo<MatMaterialWithInventoryVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery); TableDataInfo<MatMaterialVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery);
} }

View File

@@ -124,139 +124,156 @@ public class MatMaterialServiceImpl implements IMatMaterialService {
} }
@Override @Override
public TableDataInfo<MatMaterialWithInventoryVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery) { public TableDataInfo<MatMaterialVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery) {
// 先查询物料基本信息 // 先查询物料基本信息
TableDataInfo<MatMaterialVo> materialTable = queryPageList(bo, pageQuery); TableDataInfo<MatMaterialVo> materialTable = queryPageList(bo, pageQuery);
List<MatMaterialVo> materialList = materialTable.getRows();
// 将MatMaterialVo转换为MatMaterialWithInventoryVo if (materialList.isEmpty()) {
List<MatMaterialWithInventoryVo> inventoryList = materialTable.getRows().stream() return materialTable;
.map(material -> { }
MatMaterialWithInventoryVo inventoryVo = new MatMaterialWithInventoryVo(material);
// 查询该物料的库存信息 // 批量查询所有物料的库存信息
List<MaterialInventoryVo> materialInventoryList = queryMaterialInventory(material.getMaterialId()); List<Long> materialIds = materialList.stream()
.map(MatMaterialVo::getMaterialId)
if (!materialInventoryList.isEmpty()) { .distinct()
MaterialInventoryVo inventoryInfo = materialInventoryList.get(0);
inventoryVo.setInTransitNum(inventoryInfo.getInTransitNum());
inventoryVo.setPlanNum(inventoryInfo.getPlanNum());
inventoryVo.setReceivedNum(inventoryInfo.getReceivedNum());
}
return inventoryVo;
})
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Long, MaterialInventoryVo> inventoryMap = batchQueryMaterialInventory(materialIds);
// 构建返回结果 // 填充库存信息到MatMaterialVo
Page<MatMaterialWithInventoryVo> resultPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), materialTable.getTotal()); materialList.forEach(material -> {
resultPage.setRecords(inventoryList); MaterialInventoryVo inventory = inventoryMap.get(material.getMaterialId());
if (inventory != null) {
material.setInTransitNum(inventory.getInTransitNum());
material.setPlanNum(inventory.getPlanNum());
material.setReceivedNum(inventory.getReceivedNum());
}
});
return TableDataInfo.build(resultPage); return materialTable;
} }
@Override @Override
public List<MatMaterialWithInventoryVo> queryListWithInventory(MatMaterialBo bo) { public List<MatMaterialVo> queryListWithInventory(MatMaterialBo bo) {
// 先查询物料基本信息 // 先查询物料基本信息
List<MatMaterialVo> materialList = queryList(bo); List<MatMaterialVo> materialList = queryList(bo);
// 将MatMaterialVo转换为MatMaterialWithInventoryVo if (materialList.isEmpty()) {
return materialList.stream() return materialList;
.map(material -> { }
MatMaterialWithInventoryVo inventoryVo = new MatMaterialWithInventoryVo(material);
// 查询该物料的库存信息 // 批量查询所有物料的库存信息
List<MaterialInventoryVo> materialInventoryList = queryMaterialInventory(material.getMaterialId()); List<Long> materialIds = materialList.stream()
.map(MatMaterialVo::getMaterialId)
if (!materialInventoryList.isEmpty()) { .distinct()
MaterialInventoryVo inventoryInfo = materialInventoryList.get(0);
inventoryVo.setInTransitNum(inventoryInfo.getInTransitNum());
inventoryVo.setPlanNum(inventoryInfo.getPlanNum());
inventoryVo.setReceivedNum(inventoryInfo.getReceivedNum());
}
return inventoryVo;
})
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Long, MaterialInventoryVo> inventoryMap = batchQueryMaterialInventory(materialIds);
// 填充库存信息到MatMaterialVo
materialList.forEach(material -> {
MaterialInventoryVo inventory = inventoryMap.get(material.getMaterialId());
if (inventory != null) {
material.setInTransitNum(inventory.getInTransitNum());
material.setPlanNum(inventory.getPlanNum());
material.setReceivedNum(inventory.getReceivedNum());
}
});
return materialList;
} }
public List<MaterialInventoryVo> queryMaterialInventory(Long materialId) { /**
// 创建结果列表 * 批量查询物料库存信息
List<MaterialInventoryVo> result = new ArrayList<>(); * 避免N+1查询问题
*/
// 物料ID先做非空校验 private Map<Long, MaterialInventoryVo> batchQueryMaterialInventory(List<Long> materialIds) {
if (materialId == null) { if (materialIds == null || materialIds.isEmpty()) {
return result; return Collections.emptyMap();
} }
// 构建采购单查询条件materialId + 过滤删除标记) Map<Long, MaterialInventoryVo> resultMap = new HashMap<>();
// 批量查询所有采购单按materialId过滤
QueryWrapper<MatPurchase> purchaseQw = new QueryWrapper<>(); QueryWrapper<MatPurchase> purchaseQw = new QueryWrapper<>();
purchaseQw.eq("material_id", materialId); purchaseQw.in("material_id", materialIds);
purchaseQw.eq("del_flag", 0); purchaseQw.eq("del_flag", 0);
// 直接查采购单PO
List<MatPurchase> purchaseListPo = matPurchaseMapper.selectList(purchaseQw); List<MatPurchase> purchaseListPo = matPurchaseMapper.selectList(purchaseQw);
// 将PO转换为VO // 按materialId分组
List<MatPurchaseVo> purchaseList = purchaseListPo.stream() Map<Long, List<MatPurchase>> purchaseByMaterial = purchaseListPo.stream()
.map(purchase -> { .collect(Collectors.groupingBy(MatPurchase::getMaterialId));
MatPurchaseVo vo = new MatPurchaseVo();
BeanUtils.copyProperties(purchase, vo); // 查询物料基本信息
return vo; Map<Long, MatMaterialVo> materialInfoMap = baseMapper.selectVoBatchIds(materialIds).stream()
}) .collect(Collectors.toMap(MatMaterialVo::getMaterialId, m -> m));
// 按采购单ID分组用于批量查询入库详情
List<Long> purchaseIds = purchaseListPo.stream()
.map(MatPurchase::getPurchaseId)
.distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
// 1. 查询当前物料的详细信息 Map<Long, List<MatPurchaseInDetailVo>> detailsByPurchaseId = Collections.emptyMap();
MatMaterialVo material = baseMapper.selectVoById(materialId); if (!purchaseIds.isEmpty()) {
// 2. 初始化物料库存VO MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
MaterialInventoryVo inventory = new MaterialInventoryVo(); Map<String, Object> params = new HashMap<>();
inventory.setMaterialId(materialId); params.put("purchaseIds", purchaseIds);
if (material != null) { detailBo.setParams(params);
inventory.setMaterialName(material.getMaterialName()); List<MatPurchaseInDetailVo> allDetails = matPurchaseInDetailService.queryList(detailBo);
inventory.setSpec(material.getSpec()); detailsByPurchaseId = allDetails.stream()
inventory.setModel(material.getModel()); .collect(Collectors.groupingBy(MatPurchaseInDetailVo::getPurchaseId));
inventory.setUnit(material.getUnit());
inventory.setCurrentStock(material.getCurrentStock());
} }
// 3. 计算该物料的计划总数、已入库总数、在途总数 // 计算每个物料的库存信息
BigDecimal planTotal = BigDecimal.ZERO; for (Long materialId : materialIds) {
BigDecimal receivedTotal = BigDecimal.ZERO; MaterialInventoryVo inventory = new MaterialInventoryVo();
BigDecimal inTransitTotal = BigDecimal.ZERO; inventory.setMaterialId(materialId);
for (MatPurchaseVo purchase : purchaseList) { // 填充物料基本信息
// 累加计划总数 MatMaterialVo material = materialInfoMap.get(materialId);
BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO); if (material != null) {
planTotal = planTotal.add(planNum); inventory.setMaterialName(material.getMaterialName());
inventory.setSpec(material.getSpec());
inventory.setModel(material.getModel());
inventory.setUnit(material.getUnit());
inventory.setCurrentStock(material.getCurrentStock());
}
// 查询该采购单下的入库详情 // 计算采购相关数据
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo(); List<MatPurchase> purchases = purchaseByMaterial.getOrDefault(materialId, Collections.emptyList());
detailBo.setPurchaseId(purchase.getPurchaseId()); BigDecimal planTotal = BigDecimal.ZERO;
List<MatPurchaseInDetailVo> details = matPurchaseInDetailService.queryList(detailBo); BigDecimal receivedTotal = BigDecimal.ZERO;
BigDecimal inTransitTotal = BigDecimal.ZERO;
// 计算该采购单的已入库数量 for (MatPurchase purchase : purchases) {
BigDecimal receivedInPurchase = details.stream() BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO);
.map(MatPurchaseInDetailVo::getInNum) planTotal = planTotal.add(planNum);
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
receivedTotal = receivedTotal.add(receivedInPurchase);
// 计算该采购单的在途数量 // 计算该采购单的已入库数量
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) { List<MatPurchaseInDetailVo> details = detailsByPurchaseId.getOrDefault(purchase.getPurchaseId(), Collections.emptyList());
BigDecimal pending = planNum.subtract(receivedInPurchase); BigDecimal receivedInPurchase = details.stream()
if (pending.compareTo(BigDecimal.ZERO) > 0) { .map(MatPurchaseInDetailVo::getInNum)
inTransitTotal = inTransitTotal.add(pending); .filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
receivedTotal = receivedTotal.add(receivedInPurchase);
// 计算该采购单的在途数量
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) {
BigDecimal pending = planNum.subtract(receivedInPurchase);
if (pending.compareTo(BigDecimal.ZERO) > 0) {
inTransitTotal = inTransitTotal.add(pending);
}
} }
} }
inventory.setPlanNum(planTotal);
inventory.setReceivedNum(receivedTotal);
inventory.setInTransitNum(inTransitTotal);
resultMap.put(materialId, inventory);
} }
// 4. 设置库存VO的数值字段 return resultMap;
inventory.setPlanNum(planTotal);
inventory.setReceivedNum(receivedTotal);
inventory.setInTransitNum(inTransitTotal);
// 5. 添加到结果列表
result.add(inventory);
return result;
} }
} }