From f7273277023f3497ac071bf98f556a569cb4dd25 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 17 九月 2026 16:24:10 +0800
Subject: [PATCH] feat(mes): 重构袋码生成与物料分类功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java |   80 ++++++++++++++++++++++++++++++++++-----
 1 files changed, 69 insertions(+), 11 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
index 110c7b1..7eafe26 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/trace/MesProTracePublicServiceImpl.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchFlowRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchProcessTraceRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchPurchaseSourceRespVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchSalesTargetRespVO;
@@ -38,6 +39,9 @@
 
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -103,7 +107,7 @@
                 throw exception(MES_TRACE_CODE_NOT_FOUND);
             }
             // 2. 鑱氬悎鍏ㄧ▼淇℃伅
-            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId);
+            MesProTracePublicRespVO result = buildRespVO(rawCode, traceCode, entry.sourceType, entry.batchId, entry.bagItemId);
             recordConsumerScan(rawCode, traceCode, entry.sourceType, entry.batchId, true);
             return result;
         } catch (RuntimeException ex) {
@@ -163,24 +167,24 @@
         // 鈶� 琚嬬爜
         MesProBagCodeDO bag = bagCodeService.getBagCodeByCode(traceCode);
         if (bag != null) {
-            return new TraceEntry("BAG", bag.getBatchId());
+            return new TraceEntry("BAG", bag.getBatchId(), bag.getItemId());
         }
         // 鈶� 鎵樼洏鐮�
         MesProPalletDO pallet = palletService.getPalletByCode(traceCode);
         if (pallet != null) {
-            return new TraceEntry("PALLET", pallet.getBatchId());
+            return new TraceEntry("PALLET", pallet.getBatchId(), null);
         }
         // 鈶� 鎵规鐮侊紙鍚复鏃舵壒娆$爜锛実etBatchByCode 鍐呴儴鍏煎锛�
         MesProBatchDO batch = batchService.getBatchByCode(traceCode);
         if (batch != null) {
-            return new TraceEntry("BATCH", batch.getId());
+            return new TraceEntry("BATCH", batch.getId(), null);
         }
-        return new TraceEntry("", null);
+        return new TraceEntry("", null, null);
     }
 
     // ==================== 鑱氬悎鏋勫缓 ====================
 
-    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId) {
+    private MesProTracePublicRespVO buildRespVO(String requestCode, String traceCode, String sourceType, Long batchId, Long bagItemId) {
         MesProBatchDO batch = batchService.getBatch(batchId);
         if (batch == null) {
             throw exception(MES_TRACE_CODE_NOT_FOUND);
@@ -189,7 +193,7 @@
         resp.setSourceType(sourceType);
         resp.setRequestCode(requestCode);
         // 鍝佺鍖哄潡
-        fillItem(resp, batch);
+        fillItem(resp, batch, bagItemId);
         // 鎵规鍖哄潡
         resp.setBatchCode(batch.getCode()).setTempCode(batch.getTempCode())
                 .setBatchStatus(batch.getStatus()).setBatchStatusName(batchStatusName(batch.getStatus()))
@@ -212,14 +216,24 @@
         fillAntiFake(resp, traceCode);
         // 鍙�夋墿灞曞尯鍧楋紙鏈夋暟鎹墠杩斿洖锛�
         fillOptionalModules(resp, batch);
+        fillTimelineAndDecision(resp);
         return resp;
     }
 
-    private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch) {
-        if (batch.getItemId() == null) {
+    /**
+     * 鍝佺宸蹭笅娌夊埌琚嬬爜鏁版嵁鍖咃細浼樺厛鍙栨壂鐮佽鐮佸搧绉嶏紝鍘嗗彶鎵规鍥為��鎵规鍝佺锛屾壒娆�/鎵樼洏鍏ュ彛鍙栨壒鍐呬换涓�琚嬬爜鍝佺
+     */
+    private void fillItem(MesProTracePublicRespVO resp, MesProBatchDO batch, Long bagItemId) {
+        Long itemId = bagItemId != null ? bagItemId : batch.getItemId();
+        if (itemId == null) {
+            List<MesProBagCodeDO> bags = bagCodeService.getBagCodeListByBatchId(batch.getId());
+            itemId = bags == null ? null : bags.stream().map(MesProBagCodeDO::getItemId)
+                    .filter(id -> id != null).findFirst().orElse(null);
+        }
+        if (itemId == null) {
             return;
         }
-        MesMdmItemDO item = mdmItemService.getItem(batch.getItemId());
+        MesMdmItemDO item = mdmItemService.getItem(itemId);
         if (item == null) {
             return;
         }
@@ -329,13 +343,57 @@
             resp.setPurchaseSources(CollUtil.isNotEmpty(purchaseSources) ? purchaseSources : List.of());
             resp.setSalesTargets(CollUtil.isNotEmpty(salesTargets) ? salesTargets : List.of());
             resp.setProcessTraces(CollUtil.isNotEmpty(processTraces) ? processTraces : List.of());
+            List<MesWmBatchFlowRespVO> seedFlows = mesWmBatchService.getBatchFlowList(batch.getCode());
+            resp.setSeedFlows(CollUtil.isNotEmpty(seedFlows) ? seedFlows : List.of());
         } catch (Exception ex) {
             // 浠撳簱鎵规浣撶郴锛堥噰璐�/閿�鍞�/娴佽浆锛夋湭鍚敤鏃跺閿欙紝涓嶅奖鍝嶆牳蹇冭拷婧�
             log.warn("[fillOptionalModules][鎵规 {} 鎵╁睍妯″潡鏌ヨ澶辫触: {}]", batch.getCode(), ex.getMessage());
             resp.setPurchaseSources(List.of());
             resp.setSalesTargets(List.of());
             resp.setProcessTraces(List.of());
+            resp.setSeedFlows(List.of());
         }
+    }
+
+    private void fillTimelineAndDecision(MesProTracePublicRespVO resp) {
+        List<MesProTracePublicRespVO.TimelineVO> timeline = new ArrayList<>();
+        if (resp.getProduceDate() != null) {
+            timeline.add(timeline("鐢熶骇", "BATCH_CREATED", "鐢熶骇鎵规寤虹珛", resp.getProduceDate(), null,
+                    resp.getBatchStatusName()));
+        }
+        if (resp.getProcessTraces() != null) {
+            resp.getProcessTraces().forEach(item -> timeline.add(timeline("鍔犲伐", item.getEventType(),
+                    item.getEventType() == null ? "宸ュ簭娴佽浆" : ("IN".equals(item.getEventType()) ? "宸ュ簭鎶曞叆" : "宸ュ簭浜у嚭"),
+                    item.getEventTime(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+        }
+        if (resp.getInbound() != null) {
+            timeline.add(timeline("浠撳偍", "INBOUND", "浠撳偍鍏ュ簱", resp.getInbound().getEventTime(),
+                    resp.getInbound().getQuantity(), resp.getInbound().getStatus()));
+        }
+        if (resp.getSalesTargets() != null) {
+            resp.getSalesTargets().forEach(item -> timeline.add(timeline("閿�鍞�", "OUTBOUND", "閿�鍞嚭搴�",
+                    item.getSalesDate(), item.getQuantity(), item.getQualityStatus() == null ? null : String.valueOf(item.getQualityStatus()))));
+        }
+        timeline.sort(Comparator.comparing(MesProTracePublicRespVO.TimelineVO::getEventTime,
+                Comparator.nullsLast(Comparator.naturalOrder())));
+        resp.setTimeline(timeline);
+
+        MesProTracePublicRespVO.DecisionVO decision = new MesProTracePublicRespVO.DecisionVO();
+        decision.setQualityRisk(resp.getQuality() != null && Integer.valueOf(2).equals(resp.getQuality().getResult()));
+        decision.setInboundQuantity(resp.getInbound() == null ? null : resp.getInbound().getQuantity());
+        decision.setSalesTargetCount(resp.getSalesTargets() == null ? 0 : resp.getSalesTargets().size());
+        decision.setConsumerScanCount(resp.getAntiFake() == null ? 0L : resp.getAntiFake().getScanCount());
+        decision.setRiskLevel(Boolean.TRUE.equals(decision.getQualityRisk()) ? "HIGH" : "NORMAL");
+        resp.setDecision(decision);
+    }
+
+    private MesProTracePublicRespVO.TimelineVO timeline(String stage, String eventType, String eventName,
+                                                         java.time.LocalDateTime eventTime, BigDecimal quantity,
+                                                         String status) {
+        MesProTracePublicRespVO.TimelineVO vo = new MesProTracePublicRespVO.TimelineVO();
+        vo.setStage(stage).setEventType(eventType).setEventName(eventName).setEventTime(eventTime)
+                .setQuantity(quantity).setStatus(status);
+        return vo;
     }
 
     // ==================== 鍚嶇О鏄犲皠 ====================
@@ -409,7 +467,7 @@
         };
     }
 
-    private record TraceEntry(String sourceType, Long batchId) {
+    private record TraceEntry(String sourceType, Long batchId, Long bagItemId) {
     }
 
 }

--
Gitblit v1.9.3