From 8027c8e2e0b5c559da612b187031dd6fd82d9bc7 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期六, 04 四月 2026 12:03:48 +0800
Subject: [PATCH] #任务分析异常修复

---
 src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java |  243 ++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 211 insertions(+), 32 deletions(-)

diff --git a/src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java
index f647010..6eab1a5 100644
--- a/src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java
+++ b/src/main/java/com/zy/asrs/service/impl/WrkAnalysisServiceImpl.java
@@ -30,7 +30,8 @@
             WrkStsType.SETTLE_INBOUND.sts,
             WrkStsType.COMPLETE_OUTBOUND.sts,
             WrkStsType.SETTLE_OUTBOUND.sts,
-            WrkStsType.COMPLETE_LOC_MOVE.sts
+            WrkStsType.COMPLETE_LOC_MOVE.sts,
+            WrkStsType.COMPLETE_CRN_MOVE.sts
     );
     private static final String MODE_TASK = "TASK";
     private static final String MODE_TIME = "TIME";
@@ -45,6 +46,7 @@
     private final BasCrnpErrLogService basCrnpErrLogService;
     private final BasDualCrnpErrLogService basDualCrnpErrLogService;
     private final BasRgvErrLogService basRgvErrLogService;
+    private final BasStationErrLogService basStationErrLogService;
     private final BasStationService basStationService;
     private final BasWrkStatusService basWrkStatusService;
     private final WrkMastService wrkMastService;
@@ -53,6 +55,7 @@
                                   BasCrnpErrLogService basCrnpErrLogService,
                                   BasDualCrnpErrLogService basDualCrnpErrLogService,
                                   BasRgvErrLogService basRgvErrLogService,
+                                  BasStationErrLogService basStationErrLogService,
                                   BasStationService basStationService,
                                   BasWrkStatusService basWrkStatusService,
                                   WrkMastService wrkMastService) {
@@ -60,6 +63,7 @@
         this.basCrnpErrLogService = basCrnpErrLogService;
         this.basDualCrnpErrLogService = basDualCrnpErrLogService;
         this.basRgvErrLogService = basRgvErrLogService;
+        this.basStationErrLogService = basStationErrLogService;
         this.basStationService = basStationService;
         this.basWrkStatusService = basWrkStatusService;
         this.wrkMastService = wrkMastService;
@@ -71,7 +75,7 @@
         if (wrkMast == null || wrkMast.getWrkNo() == null) {
             return;
         }
-        WrkAnalysis entity = this.getById(wrkMast.getWrkNo());
+        WrkAnalysis entity = findActiveRecord(wrkMast.getWrkNo());
         Date now = new Date();
         if (entity == null) {
             entity = new WrkAnalysis();
@@ -88,9 +92,15 @@
         entity.setDualCrnFaultDurationMs(defaultLong(entity.getDualCrnFaultDurationMs()));
         entity.setRgvFaultCount(defaultInt(entity.getRgvFaultCount()));
         entity.setRgvFaultDurationMs(defaultLong(entity.getRgvFaultDurationMs()));
+        entity.setStationFaultCount(defaultInt(entity.getStationFaultCount()));
+        entity.setStationFaultDurationMs(defaultLong(entity.getStationFaultDurationMs()));
         entity.setMetricCompleteness(METRIC_PARTIAL);
         entity.setUpdateTime(now);
-        this.saveOrUpdate(entity);
+        if (entity.getId() == null) {
+            this.save(entity);
+        } else {
+            this.updateById(entity);
+        }
     }
 
     @Override
@@ -186,7 +196,9 @@
         entity.setRgvNo(wrkMast.getRgvNo());
         entity.setFinalWrkSts(wrkMast.getWrkSts());
         entity.setUpdateTime(time);
-        if (Objects.equals(wrkMast.getIoType(), WrkIoType.LOC_MOVE.id) && entity.getStationDurationMs() == null) {
+        if ((Objects.equals(wrkMast.getIoType(), WrkIoType.LOC_MOVE.id)
+                || Objects.equals(wrkMast.getIoType(), WrkIoType.CRN_MOVE.id))
+                && entity.getStationDurationMs() == null) {
             entity.setStationDurationMs(0L);
         }
         this.updateById(entity);
@@ -212,6 +224,12 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void finishTask(WrkMast wrkMast, Date finishTime) {
+        finishTask(wrkMast, finishTime, null);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void finishTask(WrkMast wrkMast, Date finishTime, Long wrkLogId) {
         if (wrkMast == null || wrkMast.getWrkNo() == null) {
             return;
         }
@@ -225,10 +243,13 @@
         if (entity.getAppeTime() != null) {
             entity.setTotalDurationMs(durationMs(entity.getAppeTime(), time));
         }
-        if (Objects.equals(wrkMast.getIoType(), WrkIoType.LOC_MOVE.id) && entity.getStationDurationMs() == null) {
+        if ((Objects.equals(wrkMast.getIoType(), WrkIoType.LOC_MOVE.id)
+                || Objects.equals(wrkMast.getIoType(), WrkIoType.CRN_MOVE.id))
+                && entity.getStationDurationMs() == null) {
             entity.setStationDurationMs(0L);
         }
-        FaultSummary faultSummary = buildFaultSummary(wrkMast.getWrkNo(), time);
+        entity.setWrkLogId(wrkLogId);
+        FaultSummary faultSummary = buildFaultSummary(wrkMast.getWrkNo(), entity.getAppeTime(), time);
         entity.setHasFault(faultSummary.hasFault);
         entity.setFaultCount(faultSummary.totalCount);
         entity.setFaultDurationMs(faultSummary.totalDurationMs);
@@ -238,21 +259,25 @@
         entity.setDualCrnFaultDurationMs(faultSummary.dualDurationMs);
         entity.setRgvFaultCount(faultSummary.rgvCount);
         entity.setRgvFaultDurationMs(faultSummary.rgvDurationMs);
+        entity.setStationFaultCount(faultSummary.stationCount);
+        entity.setStationFaultDurationMs(faultSummary.stationDurationMs);
         entity.setMetricCompleteness(resolveMetricCompleteness(wrkMast, entity));
         entity.setUpdateTime(time);
-        this.saveOrUpdate(entity);
+        this.updateById(entity);
     }
 
     @Override
-    public Map<Integer, WrkAnalysis> mapByWrkNos(Collection<Integer> wrkNos) {
-        Map<Integer, WrkAnalysis> result = new LinkedHashMap<>();
-        if (wrkNos == null || wrkNos.isEmpty()) {
+    public Map<Long, WrkAnalysis> mapByWrkLogIds(Collection<Long> wrkLogIds) {
+        Map<Long, WrkAnalysis> result = new LinkedHashMap<>();
+        if (wrkLogIds == null || wrkLogIds.isEmpty()) {
             return result;
         }
-        List<WrkAnalysis> list = this.listByIds(new LinkedHashSet<>(wrkNos));
+        List<WrkAnalysis> list = this.list(new QueryWrapper<WrkAnalysis>()
+                .in("wrk_log_id", new LinkedHashSet<>(wrkLogIds))
+                .orderByAsc("wrk_log_id", "id"));
         for (WrkAnalysis item : list) {
-            if (item != null && item.getWrkNo() != null) {
-                result.put(item.getWrkNo(), item);
+            if (item != null && item.getWrkLogId() != null) {
+                result.put(item.getWrkLogId(), item);
             }
         }
         return result;
@@ -265,6 +290,7 @@
         ioTypes.add(option("1", "IN", "鍏ュ簱", WrkIoType.IN.id));
         ioTypes.add(option("2", "OUT", "鍑哄簱", WrkIoType.OUT.id));
         ioTypes.add(option("3", "LOC_MOVE", "绉诲簱", WrkIoType.LOC_MOVE.id));
+        ioTypes.add(option("4", "CRN_MOVE", "鍫嗗灈鏈虹Щ鍔�", WrkIoType.CRN_MOVE.id));
         List<Map<String, Object>> timeFields = new ArrayList<>();
         timeFields.add(option(TIME_FIELD_FINISH, TIME_FIELD_FINISH, "瀹屾垚鏃堕棿", TIME_FIELD_FINISH));
         timeFields.add(option(TIME_FIELD_APPE, TIME_FIELD_APPE, "鍒涘缓鏃堕棿", TIME_FIELD_APPE));
@@ -303,11 +329,11 @@
         QueryWrapper<WrkMastLog> wrapper = buildHistoryLogWrapper(param);
         Page<WrkMastLog> page = wrkMastLogService.page(new Page<>(pageNo, pageSize), wrapper);
         List<WrkMastLog> logList = page.getRecords();
-        List<Integer> wrkNos = logList.stream().map(WrkMastLog::getWrkNo).filter(Objects::nonNull).collect(Collectors.toList());
-        Map<Integer, WrkAnalysis> analysisMap = mapByWrkNos(wrkNos);
+        List<Long> logIds = logList.stream().map(WrkMastLog::getId).filter(Objects::nonNull).collect(Collectors.toList());
+        Map<Long, WrkAnalysis> analysisMap = mapByWrkLogIds(logIds);
         List<Map<String, Object>> records = new ArrayList<>();
         for (WrkMastLog log : logList) {
-            records.add(toListItem(log, analysisMap.get(log.getWrkNo())));
+            records.add(toListItem(log, analysisMap.get(log.getId())));
         }
         Map<String, Object> data = new LinkedHashMap<>();
         data.put("records", records);
@@ -327,7 +353,8 @@
         QueryWrapper<WrkAnalysis> wrapper = buildAnalysisWrapper(request, mode);
         List<WrkAnalysis> list = this.list(wrapper);
         list.sort(Comparator.comparing(WrkAnalysis::getFinishTime, Comparator.nullsLast(Date::compareTo))
-                .thenComparing(WrkAnalysis::getWrkNo, Comparator.nullsLast(Integer::compareTo)));
+                .thenComparing(WrkAnalysis::getWrkLogId, Comparator.nullsLast(Long::compareTo))
+                .thenComparing(WrkAnalysis::getId, Comparator.nullsLast(Long::compareTo)));
         Collections.reverse(list);
         String timeField = TIME_FIELD_FINISH;
         if (TIME_FIELD_APPE.equalsIgnoreCase(request.getString("timeField"))) {
@@ -367,7 +394,7 @@
         applyDeviceTypeFilter(wrapper, upperTrim(stringValue(param.get("deviceType"))));
         applyRange(wrapper, "appe_time", stringValue(param.get("appeTimeRange")));
         applyRange(wrapper, "modi_time", stringValue(param.get("finishTimeRange")));
-        wrapper.orderByDesc("modi_time", "wrk_no");
+        wrapper.orderByDesc("modi_time", "id");
         return wrapper;
     }
 
@@ -400,6 +427,11 @@
             wrapper.isNotNull("rgv_no");
         }
         if (MODE_TASK.equals(mode)) {
+            List<Long> wrkLogIds = parseLongIds(request.get("wrkLogIds"));
+            if (!wrkLogIds.isEmpty()) {
+                wrapper.in("wrk_log_id", wrkLogIds);
+                return wrapper;
+            }
             List<Integer> wrkNos = parseWrkNos(request.get("wrkNos"));
             if (wrkNos.isEmpty()) {
                 wrapper.eq("wrk_no", -1);
@@ -426,7 +458,7 @@
             return;
         }
         QueryWrapper<WrkAnalysis> analysisWrapper = new QueryWrapper<>();
-        analysisWrapper.select("wrk_no");
+        analysisWrapper.select("wrk_log_id");
         if (DEVICE_TYPE_CRN.equals(deviceType)) {
             analysisWrapper.isNotNull("crn_no");
         } else if (DEVICE_TYPE_DUAL_CRN.equals(deviceType)) {
@@ -436,15 +468,15 @@
         } else {
             return;
         }
-        List<Integer> wrkNos = this.list(analysisWrapper).stream()
-                .map(WrkAnalysis::getWrkNo)
+        List<Long> wrkLogIds = this.list(analysisWrapper).stream()
+                .map(WrkAnalysis::getWrkLogId)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
-        if (wrkNos.isEmpty()) {
-            wrapper.eq("wrk_no", -1);
+        if (wrkLogIds.isEmpty()) {
+            wrapper.eq("id", -1);
             return;
         }
-        wrapper.in("wrk_no", wrkNos);
+        wrapper.in("id", wrkLogIds);
     }
 
     private Map<String, Object> buildAnalysisResult(List<WrkAnalysis> list, String timeField) {
@@ -604,6 +636,7 @@
             addDeviceFaultDuration(durationMap, "鍗曞爢鍨涙満", item.getCrnNo(), item.getCrnFaultDurationMs());
             addDeviceFaultDuration(durationMap, "鍙屽伐浣嶅爢鍨涙満", item.getDualCrnNo(), item.getDualCrnFaultDurationMs());
             addDeviceFaultDuration(durationMap, "RGV", item.getRgvNo(), item.getRgvFaultDurationMs());
+            addDeviceFaultDuration(durationMap, "杈撻�佺珯鐐�", null, item.getStationFaultDurationMs());
         }
         List<Map<String, Object>> result = new ArrayList<>();
         durationMap.forEach((name, durationMs) -> result.add(slice(name, durationMs)));
@@ -625,6 +658,7 @@
 
     private Map<String, Object> toListItem(WrkMastLog log, WrkAnalysis analysis) {
         Map<String, Object> item = new LinkedHashMap<>();
+        item.put("logId", log.getId());
         item.put("wrkNo", log.getWrkNo());
         item.put("wmsWrkNo", log.getWmsWrkNo());
         item.put("wrkSts", log.getWrkSts());
@@ -646,6 +680,9 @@
 
     private Map<String, Object> toDetailItem(WrkAnalysis item) {
         Map<String, Object> result = new LinkedHashMap<>();
+        result.put("id", item.getId());
+        result.put("wrkLogId", item.getWrkLogId());
+        result.put("rowKey", buildRowKey(item));
         result.put("wrkNo", item.getWrkNo());
         result.put("wmsWrkNo", item.getWmsWrkNo());
         result.put("ioType", item.getIoType());
@@ -674,25 +711,45 @@
         target.put("crnFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getCrnFaultDurationMs()));
         target.put("dualCrnFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getDualCrnFaultDurationMs()));
         target.put("rgvFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getRgvFaultDurationMs()));
+        target.put("stationFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getStationFaultDurationMs()));
         target.put("metricCompleteness", analysis == null ? METRIC_PARTIAL : analysis.getMetricCompleteness());
     }
 
-    private FaultSummary buildFaultSummary(Integer wrkNo, Date finishTime) {
+    private FaultSummary buildFaultSummary(Integer wrkNo, Date taskStartTime, Date finishTime) {
         FaultSummary summary = new FaultSummary();
         if (wrkNo == null) {
             return summary;
         }
-        List<BasCrnpErrLog> crnList = basCrnpErrLogService.list(new QueryWrapper<BasCrnpErrLog>().eq("wrk_no", wrkNo));
-        List<BasDualCrnpErrLog> dualList = basDualCrnpErrLogService.list(new QueryWrapper<BasDualCrnpErrLog>().eq("wrk_no", wrkNo));
-        List<BasRgvErrLog> rgvList = basRgvErrLogService.list(new QueryWrapper<BasRgvErrLog>().eq("task_no", wrkNo));
+        List<BasCrnpErrLog> crnList = filterTaskFaultLogs(
+                basCrnpErrLogService.list(new QueryWrapper<BasCrnpErrLog>().eq("wrk_no", wrkNo)),
+                taskStartTime,
+                finishTime
+        );
+        List<BasDualCrnpErrLog> dualList = filterTaskFaultLogs(
+                basDualCrnpErrLogService.list(new QueryWrapper<BasDualCrnpErrLog>().eq("wrk_no", wrkNo)),
+                taskStartTime,
+                finishTime
+        );
+        List<BasRgvErrLog> rgvList = filterTaskFaultLogs(
+                basRgvErrLogService.list(new QueryWrapper<BasRgvErrLog>().eq("task_no", wrkNo)),
+                taskStartTime,
+                finishTime
+        );
+        List<BasStationErrLog> stationList = filterTaskFaultLogs(
+                basStationErrLogService.list(new QueryWrapper<BasStationErrLog>().eq("wrk_no", wrkNo)),
+                taskStartTime,
+                finishTime
+        );
         summary.crnCount = crnList.size();
         summary.crnDurationMs = durationMs(crnList, finishTime);
         summary.dualCount = dualList.size();
         summary.dualDurationMs = durationMs(dualList, finishTime);
         summary.rgvCount = rgvList.size();
         summary.rgvDurationMs = durationMs(rgvList, finishTime);
-        summary.totalCount = summary.crnCount + summary.dualCount + summary.rgvCount;
-        summary.totalDurationMs = summary.crnDurationMs + summary.dualDurationMs + summary.rgvDurationMs;
+        summary.stationCount = stationList.size();
+        summary.stationDurationMs = durationMs(stationList, finishTime);
+        summary.totalCount = summary.crnCount + summary.dualCount + summary.rgvCount + summary.stationCount;
+        summary.totalDurationMs = summary.crnDurationMs + summary.dualDurationMs + summary.rgvDurationMs + summary.stationDurationMs;
         summary.hasFault = summary.totalCount > 0 ? 1 : 0;
         return summary;
     }
@@ -711,6 +768,9 @@
             } else if (item instanceof BasRgvErrLog) {
                 startTime = ((BasRgvErrLog) item).getStartTime();
                 endTime = ((BasRgvErrLog) item).getEndTime();
+            } else if (item instanceof BasStationErrLog) {
+                startTime = ((BasStationErrLog) item).getStartTime();
+                endTime = ((BasStationErrLog) item).getEndTime();
             }
             if (startTime == null) {
                 continue;
@@ -737,13 +797,13 @@
         if (wrkMast == null || wrkMast.getWrkNo() == null) {
             return null;
         }
-        WrkAnalysis entity = this.getById(wrkMast.getWrkNo());
+        WrkAnalysis entity = findActiveRecord(wrkMast.getWrkNo());
         if (entity != null) {
             syncBaseFields(entity, wrkMast);
             return entity;
         }
         initForTask(wrkMast);
-        return this.getById(wrkMast.getWrkNo());
+        return findActiveRecord(wrkMast.getWrkNo());
     }
 
     private void syncBaseFields(WrkAnalysis entity, WrkMast wrkMast) {
@@ -766,6 +826,28 @@
             return item.getAppeTime();
         }
         return item.getFinishTime();
+    }
+
+    private WrkAnalysis findActiveRecord(Integer wrkNo) {
+        if (wrkNo == null) {
+            return null;
+        }
+        return this.getOne(new QueryWrapper<WrkAnalysis>()
+                .eq("wrk_no", wrkNo)
+                .isNull("wrk_log_id")
+                .isNull("finish_time")
+                .orderByDesc("id")
+                .last("limit 1"), false);
+    }
+
+    private String buildRowKey(WrkAnalysis item) {
+        if (item.getWrkLogId() != null) {
+            return "log-" + item.getWrkLogId();
+        }
+        if (item.getId() != null) {
+            return "analysis-" + item.getId();
+        }
+        return "wrk-" + defaultInt(item.getWrkNo()) + "-" + defaultLong(item.getAppeTime() == null ? null : item.getAppeTime().getTime());
     }
 
     private Map<String, Object> option(String key, String code, String label, Object value) {
@@ -819,6 +901,9 @@
         if (Objects.equals(ioType, WrkIoType.LOC_MOVE.id)) {
             return "绉诲簱";
         }
+        if (Objects.equals(ioType, WrkIoType.CRN_MOVE.id)) {
+            return "鍫嗗灈鏈虹Щ鍔�";
+        }
         return String.valueOf(ioType);
     }
 
@@ -870,6 +955,59 @@
         wrapper.le(column, DateUtils.convert(parts[1].trim()));
     }
 
+    private <T> List<T> filterTaskFaultLogs(List<T> source, Date taskStartTime, Date taskFinishTime) {
+        if (source == null || source.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return source.stream()
+                .filter(item -> overlapsTaskWindow(resolveFaultStartTime(item), resolveFaultEndTime(item), taskStartTime, taskFinishTime))
+                .collect(Collectors.toList());
+    }
+
+    private Date resolveFaultStartTime(Object item) {
+        if (item instanceof BasCrnpErrLog) {
+            return ((BasCrnpErrLog) item).getStartTime();
+        }
+        if (item instanceof BasDualCrnpErrLog) {
+            return ((BasDualCrnpErrLog) item).getStartTime();
+        }
+        if (item instanceof BasRgvErrLog) {
+            return ((BasRgvErrLog) item).getStartTime();
+        }
+        if (item instanceof BasStationErrLog) {
+            return ((BasStationErrLog) item).getStartTime();
+        }
+        return null;
+    }
+
+    private Date resolveFaultEndTime(Object item) {
+        if (item instanceof BasCrnpErrLog) {
+            return ((BasCrnpErrLog) item).getEndTime();
+        }
+        if (item instanceof BasDualCrnpErrLog) {
+            return ((BasDualCrnpErrLog) item).getEndTime();
+        }
+        if (item instanceof BasRgvErrLog) {
+            return ((BasRgvErrLog) item).getEndTime();
+        }
+        if (item instanceof BasStationErrLog) {
+            return ((BasStationErrLog) item).getEndTime();
+        }
+        return null;
+    }
+
+    private boolean overlapsTaskWindow(Date eventStartTime, Date eventEndTime, Date taskStartTime, Date taskFinishTime) {
+        long taskStart = taskStartTime == null ? Long.MIN_VALUE : taskStartTime.getTime();
+        long taskEnd = taskFinishTime == null ? Long.MAX_VALUE : taskFinishTime.getTime();
+        long eventStart = eventStartTime == null
+                ? (eventEndTime == null ? Long.MIN_VALUE : eventEndTime.getTime())
+                : eventStartTime.getTime();
+        long eventEnd = eventEndTime == null
+                ? (eventStartTime == null ? Long.MAX_VALUE : eventStartTime.getTime())
+                : eventEndTime.getTime();
+        return eventStart <= taskEnd && eventEnd >= taskStart;
+    }
+
     private List<Integer> parseWrkNos(Object value) {
         List<Integer> result = new ArrayList<>();
         if (value == null) {
@@ -901,6 +1039,45 @@
         if (!Cools.isEmpty(text)) {
             for (String part : text.split(",")) {
                 Integer parsed = parseInteger(part);
+                if (parsed != null) {
+                    result.add(parsed);
+                }
+            }
+        }
+        return result;
+    }
+
+    private List<Long> parseLongIds(Object value) {
+        List<Long> result = new ArrayList<>();
+        if (value == null) {
+            return result;
+        }
+        if (value instanceof JSONArray) {
+            JSONArray array = (JSONArray) value;
+            for (int i = 0; i < array.size(); i++) {
+                Long item = parseLong(array.get(i));
+                if (item != null) {
+                    result.add(item);
+                }
+            }
+            return result;
+        }
+        if (value instanceof Collection) {
+            for (Object item : (Collection<?>) value) {
+                Long parsed = parseLong(item);
+                if (parsed != null) {
+                    result.add(parsed);
+                }
+            }
+            return result;
+        }
+        String text = String.valueOf(value).trim();
+        if (text.startsWith("[") && text.endsWith("]")) {
+            return parseLongIds(JSONArray.parseArray(text));
+        }
+        if (!Cools.isEmpty(text)) {
+            for (String part : text.split(",")) {
+                Long parsed = parseLong(part);
                 if (parsed != null) {
                     result.add(parsed);
                 }
@@ -968,6 +1145,8 @@
         private long dualDurationMs;
         private int rgvCount;
         private long rgvDurationMs;
+        private int stationCount;
+        private long stationDurationMs;
     }
 
     private static class BucketAccumulator {

--
Gitblit v1.9.1