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

View File

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