From 7281e0552fa3abd9ad08b9fb0f71f8c1ec0b92cc Mon Sep 17 00:00:00 2001 From: fengyuan_yang <1976974459@qq.com> Date: Tue, 19 May 2026 18:33:23 +0800 Subject: [PATCH] =?UTF-8?q?2026-05-19=20=E3=80=90=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E3=80=91=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/QuoteDetailBomTreeMapper.java | 10 +++ .../impl/QuoteDetailBomTreeServiceImpl.java | 90 ++++++++++++++++--- .../mapper/quote/QuoteDetailBomTreeMapper.xml | 43 +++++++++ .../mapper/quote/QuoteDetailRoutingMapper.xml | 5 +- 4 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/spring/modules/quote/mapper/QuoteDetailBomTreeMapper.java b/src/main/java/com/spring/modules/quote/mapper/QuoteDetailBomTreeMapper.java index 40d39aa8..65d99061 100644 --- a/src/main/java/com/spring/modules/quote/mapper/QuoteDetailBomTreeMapper.java +++ b/src/main/java/com/spring/modules/quote/mapper/QuoteDetailBomTreeMapper.java @@ -26,8 +26,18 @@ public interface QuoteDetailBomTreeMapper extends BaseMapper QuoteDetailRouting queryPartBomRouting(QuoteDetail detail); + /** + * 查询 Routing 组件行(用于事务外预加载,事务内直接写入报价 Routing) + */ + List queryRoutingRowsForSave(QuoteDetailRouting routing); + BigDecimal getPartCost(@Param("site") String site,@Param("partNo") String partNo); + /** + * 查询加工中心成本(对 dbo.get_workCenter_cost 做单次缓存调用) + */ + BigDecimal queryWorkCenterCost(@Param("site") String site, @Param("workCenterNo") String workCenterNo); + PartInformationEntity queryPart(@Param("site") String site,@Param("partNo") String partNo); PartInformationEntity queryPLMPart(@Param("site") String site,@Param("partNo") String partNo); diff --git a/src/main/java/com/spring/modules/quote/service/impl/QuoteDetailBomTreeServiceImpl.java b/src/main/java/com/spring/modules/quote/service/impl/QuoteDetailBomTreeServiceImpl.java index 59d436ab..809011e0 100644 --- a/src/main/java/com/spring/modules/quote/service/impl/QuoteDetailBomTreeServiceImpl.java +++ b/src/main/java/com/spring/modules/quote/service/impl/QuoteDetailBomTreeServiceImpl.java @@ -79,7 +79,10 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl routingRows = new ArrayList<>(); /** 当前节点下的子物料列表(已填充好成本价格) */ List components = new ArrayList<>(); /** 是否顶级节点(决定是否触发 handleTool) */ @@ -105,7 +108,8 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl ifsConFactory = resolveIfsConFactory(); Map costCache = new ConcurrentHashMap<>(); - BomNodeData rootNode = collectBomData(detail, parentId, level, ifsConFactory, costCache); + Map workCenterCostCache = new ConcurrentHashMap<>(); + BomNodeData rootNode = collectBomData(detail, parentId, level, ifsConFactory, costCache, workCenterCostCache); if (rootNode == null) { return 0; } @@ -129,7 +133,7 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl ifsConFactory, Map costCache) { + private BomNodeData collectBomData(QuoteDetail detail, Long parentId, Integer level, Supplier ifsConFactory, Map costCache, Map workCenterCostCache) { // 统一先尝试将临时料映射到正式料,保证新建与“切换版本刷新”取数来源一致 PartInformationEntity mappedPart = baseMapper.queryPart(detail.getSite(), detail.getPartNo()); if (Objects.nonNull(mappedPart) && "Y".equals(mappedPart.getStatus())) { @@ -178,8 +182,17 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl routingRows = baseMapper.queryRoutingRowsForSave(routing); + for (QuoteDetailRouting routingRow : routingRows) { + BigDecimal workCenterCost = resolveWorkCenterCost(routingRow.getSite(), routingRow.getWorkCenterNo(), workCenterCostCache); + routingRow.setWorkCenterCost(workCenterCost); + routingRow.setManuCost(workCenterCost); + } + nodeData.routingRows = routingRows; + } // ── 串行阶段:构建 BOM 层级结构(递归,有顺序依赖,不可并行)──────────────── for (QuoteDetailBom component : componentParts) { @@ -192,7 +205,7 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl costCache = new ConcurrentHashMap<>(); - nodeData = collectBomData(detail, newParentId, newLevel, ifsConFactory, costCache); + Map workCenterCostCache = new ConcurrentHashMap<>(); + nodeData = collectBomData(detail, newParentId, newLevel, ifsConFactory, costCache, workCenterCostCache); log.info("[PERF_LOG] Phase 1: collectBomData (including IFS calls) took {} ms", (System.currentTimeMillis() - collectStartTime)); } else { detail = new QuoteDetail(); @@ -387,7 +400,8 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl ifsConFactory = resolveIfsConFactory(); Map costCache = new ConcurrentHashMap<>(); - nodeData = collectBomData(detail, 0L, 0, ifsConFactory, costCache); + Map workCenterCostCache = new ConcurrentHashMap<>(); + nodeData = collectBomData(detail, 0L, 0, ifsConFactory, costCache, workCenterCostCache); log.info("[PERF_LOG] Phase 1: collectBomData (including IFS calls) took {} ms", (System.currentTimeMillis() - collectStartTime)); } @@ -684,6 +698,60 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl workCenterCostCache) { + if (!StringUtils.hasText(site) || !StringUtils.hasText(workCenterNo)) { + return BigDecimal.ZERO; + } + String cacheKey = site + "_" + workCenterNo; + return workCenterCostCache.computeIfAbsent(cacheKey, key -> { + BigDecimal cost = baseMapper.queryWorkCenterCost(site, workCenterNo); + return Objects.nonNull(cost) ? cost : BigDecimal.ZERO; + }); + } + private QuoteDetailBom getPurchaseComponentPart(QuoteDetail detail, QuoteDetailBomTree bom, Integer lineSequence) { QuoteDetailBom purchase = new QuoteDetailBom(); purchase.setQuoteDetailId(detail.getId()); diff --git a/src/main/resources/mapper/quote/QuoteDetailBomTreeMapper.xml b/src/main/resources/mapper/quote/QuoteDetailBomTreeMapper.xml index d959e472..fa5c6d3f 100644 --- a/src/main/resources/mapper/quote/QuoteDetailBomTreeMapper.xml +++ b/src/main/resources/mapper/quote/QuoteDetailBomTreeMapper.xml @@ -177,10 +177,53 @@ order by rh.phase_in_date desc, rh.create_date desc + + + +