From ec3308617909c8d6280e0d00ffb18350e372fbdf Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期日, 30 八月 2026 17:36:29 +0800
Subject: [PATCH] 实现采集器断线恢复与来源异常持久化

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java |   35 ++++++++++++++++++++++++++++++-----
 1 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
index 02f04cf..1765131 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
@@ -24,6 +24,8 @@
 import com.ruoyi.device.model.Measurement;
 import com.ruoyi.system.domain.TTest;
 import com.ruoyi.system.domain.TTestBattery;
+import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
+import com.ruoyi.system.mapper.TTestMapper;
 import com.ruoyi.system.service.ITestLiveService;
 import com.ruoyi.system.service.ITTestService;
 
@@ -34,12 +36,13 @@
     private final ITTestService tests;
     private final DeviceDiscoveryCandidateStore candidates;
     private final BtsDevelopmentSimulator simulator;
+    private final TTestMapper testMapper;
     private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
     private final ConcurrentMap<String, LiveSource> lastSources = new ConcurrentHashMap<>();
 
     public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
-            BtsDevelopmentSimulator simulator)
-    { this.tests = tests; this.candidates = candidates; this.simulator = simulator; }
+            BtsDevelopmentSimulator simulator, TTestMapper testMapper)
+    { this.tests = tests; this.candidates = candidates; this.simulator = simulator; this.testMapper = testMapper; }
 
     @Override public LiveState current(Long testId)
     {
@@ -55,12 +58,34 @@
             if (battery.getCollectorId() != null)
                 sources.add(snapshotFor(testId, collectorSource(battery), freezeSnapshots));
         }
-        List<Map<String, Object>> exceptions = sources.stream().filter(source -> !"ONLINE".equals(source.deviceStatus())
+        List<TTestCollectorExceptionInterval> persisted = testMapper.selectCollectorExceptionIntervals(testId);
+        if (persisted == null) persisted = List.of();
+        List<Map<String, Object>> exceptions = new ArrayList<>(persisted.stream().map(interval -> {
+            Map<String, Object> item = new LinkedHashMap<>();
+            item.put("sourceType", "COLLECTOR");
+            item.put("sourceId", interval.getCollectorId());
+            item.put("collectorCode", interval.getCollectorCode());
+            item.put("collectorName", interval.getCollectorName());
+            item.put("channelCode", interval.getCollectorChannelCode());
+            item.put("measurementName", interval.getMeasurementName());
+            item.put("exceptionType", interval.getExceptionType());
+            item.put("status", interval.getIntervalStatus());
+            item.put("openedAt", interval.getOpenedAtUtc());
+            item.put("missingFrom", interval.getMissingFromUtc());
+            item.put("recoveredAt", interval.getRecoveredAtUtc());
+            item.put("missingTo", interval.getMissingToUtc());
+            item.put("detail", interval.getDetail());
+            return item;
+        }).toList());
+        exceptions.addAll(sources.stream().filter(source -> !"COLLECTOR".equals(source.sourceType())
+                && !"ONLINE".equals(source.deviceStatus())
                 && !"WORKING".equals(source.deviceStatus()) && !"PAUSED".equals(source.deviceStatus()))
                 .map(source -> Map.<String, Object>of("sourceType", source.sourceType(), "sourceId", source.sourceId(),
                         "batteryNo", source.batteryNo(), "status", source.deviceStatus(), "message", "数据来源当前不可观测"))
-                .toList();
-        return new LiveState(testId, test.getTestStatus(), test.getReceptionStatus(), Instant.now(), sources, exceptions);
+                .toList());
+        boolean abnormal = persisted.stream().anyMatch(item -> "OPEN".equals(item.getIntervalStatus()));
+        String testStatus = abnormal && "RUNNING".equals(test.getTestStatus()) ? "RUNNING_ABNORMAL" : test.getTestStatus();
+        return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now(), sources, exceptions);
     }
 
     private LiveSource snapshotFor(Long testId, LiveSource fresh, boolean freeze)

--
Gitblit v1.7.1