yeg
2026-09-05 bd921b8e2db78be2178803c018f1a6f63a02525f
按当前设备状态展示控制台离线提醒

排除未处理历史离线记录对实时提醒的影响,设备恢复在线即移除提醒,仍离线时不受待办处理状态影响。补充两类设备恢复及处理状态独立的回归验证。
2个文件已修改
45 ■■■■■ 已修改文件
battery-business/src/main/java/com/battery/business/service/impl/TTestLiveServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/battery/business/service/impl/TTestLiveServiceImplTest.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-business/src/main/java/com/battery/business/service/impl/TTestLiveServiceImpl.java
@@ -59,9 +59,8 @@
        // 完成或暂停后只保留历史异常事实,实时控制台不再展示开放预警。
        if (receiving && mapper != null) {
            mapper.selectWarningExceptions(testId, "OPEN").forEach(item -> {
                boolean offline = "DEVICE_OFFLINE".equals(item.getExceptionType());
                if (offline) offlineSources.add(item.getSourceType() + ":" + item.getSourceIdentity());
                // 离线异常没有测量值,必须允许空值,不能用 Map.of 构造响应。
                // 离线待办的处理状态不代表当前设备状态,实时提醒只由下方当前来源生成。
                if ("DEVICE_OFFLINE".equals(item.getExceptionType())) return;
                Map<String, Object> warning = new LinkedHashMap<>();
                warning.put("exceptionId", item.getExceptionId());
                warning.put("exceptionType", item.getExceptionType());
@@ -71,7 +70,7 @@
                warning.put("value", item.getAbnormalValue());
                warning.put("unit", item.getUnit());
                warning.put("status", item.getExceptionStatus());
                warning.put("message", offline ? "接收期间设备离线,等待处理" : "测试预警异常");
                warning.put("message", "测试预警异常");
                exceptions.add(warning);
            });
        }
ruoyi-admin/src/test/java/com/battery/business/service/impl/TTestLiveServiceImplTest.java
@@ -38,7 +38,7 @@
class TTestLiveServiceImplTest
{
    @Test
    void persistedOfflineWarningWithoutMeasurementReplacesLiveHintAndSurvivesRefresh()
    void offlineHintIsIndependentOfHistoricalHandlingStatusAndSurvivesRefresh()
    {
        TTest test = test("RECEIVING");
        var mapper = mock(TTestMapper.class);
@@ -55,13 +55,42 @@
        for (int attempt = 0; attempt < 2; attempt++) {
            var alarms = service.current(10L).exceptions();
            assertEquals(1, alarms.size());
            assertEquals(21L, alarms.get(0).get("exceptionId"));
            assertFalse(alarms.get(0).containsKey("exceptionId"));
            assertEquals("DEVICE_OFFLINE", alarms.get(0).get("exceptionType"));
            assertFalse(alarms.get(0).get("message").toString().contains("处理"));
        }
        warning.setExceptionStatus("CLOSED");
        when(mapper.selectWarningExceptions(10L, "OPEN")).thenReturn(List.of());
        assertEquals(1, service.current(10L).exceptions().size());
        test.setReceptionStatus("PAUSED");
        assertTrue(service.current(10L).exceptions().isEmpty());
        test.setReceptionStatus("ENDED");
        assertTrue(service.current(10L).exceptions().isEmpty());
    }
    @Test
    void recoveredSourcesHideOfflineHintsEvenWhenHistoryRemainsOpen()
    {
        TTest test = test("RECEIVING");
        test.getBatteries().get(0).setCollectorId(7L);
        var mapper = mock(TTestMapper.class);
        var warnings = List.of("CABINET_CHANNEL", "COLLECTOR").stream().map(sourceType -> {
            var warning = new TTestWarningException();
            warning.setExceptionType("DEVICE_OFFLINE");
            warning.setSourceType(sourceType);
            warning.setSourceIdentity("COLLECTOR".equals(sourceType) ? "7" : "dev-sim:1:1:0:1");
            warning.setExceptionStatus("OPEN");
            return warning;
        }).toList();
        when(mapper.selectWarningExceptions(10L, "OPEN")).thenReturn(warnings);
        for (boolean online : List.of(false, true, true, false)) {
            var service = liveService(test, Instant.now(), online, DeviceWorkStatus.WORKING, mapper);
            var state = service.current(10L);
            assertTrue(state.sources().stream().allMatch(source -> (online ? "ONLINE" : "OFFLINE").equals(source.deviceStatus())));
            assertEquals(online ? 0 : 2, state.exceptions().size());
            assertTrue(warnings.stream().allMatch(warning -> "OPEN".equals(warning.getExceptionStatus())));
        }
    }
    @Test
@@ -245,6 +274,11 @@
                new DeviceDiscoveryCandidateStore.CandidateSnapshot(List.of(cabinet), List.of()));
        var plan = new TestDataObservationAdapter.TestPlan(1, 1, 1, List.of());
        when(simulator.testPlan(any(ChannelIdentity.class))).thenReturn(plan);
        if (mapper != null && test.getBatteries().get(0).getCollectorId() != null) {
            when(mapper.selectCollectorCode(7L)).thenReturn("collector-7");
            when(simulator.latestCollector("collector-7")).thenReturn(
                    new TestDataObservationAdapter.CollectorRealtime("collector-7", online, 1000, List.of(), null));
        }
        return new CurrentLiveService(tests, candidates, simulator, mapper);
    }