refactor(mat): 优化物料库存查询性能并移除冗余VO类
- 移除 MatMaterialWithInventoryVo 类,将库存相关字段直接添加到 MatMaterialVo 中 - 重构 queryPageListWithInventory 和 queryListWithInventory 方法,使用批量查询替代 N+1 查询 - 实现 batchQueryMaterialInventory 方法以提高库存信息查询效率 - 更新控制器中的返回类型从 MatMaterialWithInventoryVo 到 MatMaterialVo - 修改 Excel 导出功能以使用新的数据结构
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,5 +71,19 @@ public class MatMaterialVo {
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 在途数量(未完成入库的采购数量)
|
||||
*/
|
||||
private transient BigDecimal inTransitNum;
|
||||
|
||||
/**
|
||||
* 计划采购总数量
|
||||
*/
|
||||
private transient BigDecimal planNum;
|
||||
|
||||
/**
|
||||
* 已入库数量
|
||||
*/
|
||||
private transient BigDecimal receivedNum;
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -124,139 +124,156 @@ 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);
|
||||
if (materialList.isEmpty()) {
|
||||
return materialTable;
|
||||
}
|
||||
|
||||
// 查询该物料的库存信息
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
if (materialList.isEmpty()) {
|
||||
return materialList;
|
||||
}
|
||||
|
||||
// 查询该物料的库存信息
|
||||
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());
|
||||
}
|
||||
|
||||
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
|
||||
MaterialInventoryVo inventory = new MaterialInventoryVo();
|
||||
inventory.setMaterialId(materialId);
|
||||
if (material != null) {
|
||||
inventory.setMaterialName(material.getMaterialName());
|
||||
inventory.setSpec(material.getSpec());
|
||||
inventory.setModel(material.getModel());
|
||||
inventory.setUnit(material.getUnit());
|
||||
inventory.setCurrentStock(material.getCurrentStock());
|
||||
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));
|
||||
}
|
||||
|
||||
// 3. 计算该物料的计划总数、已入库总数、在途总数
|
||||
BigDecimal planTotal = BigDecimal.ZERO;
|
||||
BigDecimal receivedTotal = BigDecimal.ZERO;
|
||||
BigDecimal inTransitTotal = BigDecimal.ZERO;
|
||||
// 计算每个物料的库存信息
|
||||
for (Long materialId : materialIds) {
|
||||
MaterialInventoryVo inventory = new MaterialInventoryVo();
|
||||
inventory.setMaterialId(materialId);
|
||||
|
||||
for (MatPurchaseVo purchase : purchaseList) {
|
||||
// 累加计划总数
|
||||
BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO);
|
||||
planTotal = planTotal.add(planNum);
|
||||
// 填充物料基本信息
|
||||
MatMaterialVo material = materialInfoMap.get(materialId);
|
||||
if (material != null) {
|
||||
inventory.setMaterialName(material.getMaterialName());
|
||||
inventory.setSpec(material.getSpec());
|
||||
inventory.setModel(material.getModel());
|
||||
inventory.setUnit(material.getUnit());
|
||||
inventory.setCurrentStock(material.getCurrentStock());
|
||||
}
|
||||
|
||||
// 查询该采购单下的入库详情
|
||||
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
|
||||
detailBo.setPurchaseId(purchase.getPurchaseId());
|
||||
List<MatPurchaseInDetailVo> details = matPurchaseInDetailService.queryList(detailBo);
|
||||
// 计算采购相关数据
|
||||
List<MatPurchase> purchases = purchaseByMaterial.getOrDefault(materialId, Collections.emptyList());
|
||||
BigDecimal planTotal = BigDecimal.ZERO;
|
||||
BigDecimal receivedTotal = BigDecimal.ZERO;
|
||||
BigDecimal inTransitTotal = BigDecimal.ZERO;
|
||||
|
||||
// 计算该采购单的已入库数量
|
||||
BigDecimal receivedInPurchase = details.stream()
|
||||
.map(MatPurchaseInDetailVo::getInNum)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
receivedTotal = receivedTotal.add(receivedInPurchase);
|
||||
for (MatPurchase purchase : purchases) {
|
||||
BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO);
|
||||
planTotal = planTotal.add(planNum);
|
||||
|
||||
// 计算该采购单的在途数量
|
||||
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);
|
||||
// 计算该采购单的已入库数量
|
||||
List<MatPurchaseInDetailVo> details = detailsByPurchaseId.getOrDefault(purchase.getPurchaseId(), Collections.emptyList());
|
||||
BigDecimal receivedInPurchase = details.stream()
|
||||
.map(MatPurchaseInDetailVo::getInNum)
|
||||
.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的数值字段
|
||||
inventory.setPlanNum(planTotal);
|
||||
inventory.setReceivedNum(receivedTotal);
|
||||
inventory.setInTransitNum(inTransitTotal);
|
||||
|
||||
// 5. 添加到结果列表
|
||||
result.add(inventory);
|
||||
|
||||
return result;
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user