yeg
2026-09-05 78f53edb9542a83d9579714cf4e1e8133fc89ee9
battery-business/src/main/java/com/battery/business/service/impl/TTestLiveServiceImpl.java
@@ -46,7 +46,7 @@
        TTest test = tests.selectTestById(testId);
        List<CabinetCandidate> cabinets = candidates.snapshot(Instant.now()).cabinets();
        List<LiveSource> sources = new ArrayList<>();
        boolean receiving = "RECEIVING".equals(test.getReceptionStatus());
        boolean receiving = "RUNNING".equals(test.getTestStatus()) && "RECEIVING".equals(test.getReceptionStatus());
        for (TTestBattery battery : test.getBatteries() == null ? List.<TTestBattery>of() : test.getBatteries())
        {
            if (battery.getBinding() != null)
@@ -55,24 +55,53 @@
                sources.add(collectorSource(battery, receiving));
        }
        List<Map<String, Object>> exceptions = new ArrayList<>();
        if (receiving)
            exceptions.addAll(sources.stream().filter(source -> !"COLLECTOR".equals(source.sourceType())
                    && "OFFLINE".equals(source.deviceStatus()))
                    .map(source -> Map.<String, Object>of("sourceType", source.sourceType(), "sourceId", source.sourceId(),
                            "batteryNo", source.batteryNo(), "status", source.deviceStatus(), "message", "数据来源当前不可观测"))
                    .toList());
        java.util.Set<String> offlineSources = new java.util.HashSet<>();
        // 完成或暂停后只保留历史异常事实,实时控制台不再展示开放预警。
        if (receiving && mapper != null) {
            mapper.selectWarningExceptions(testId, "OPEN").forEach(item -> exceptions.add(Map.of(
                    "exceptionId", item.getExceptionId(), "sourceType", item.getSourceType(),
                    "metricCode", item.getMetricCode(), "value", item.getAbnormalValue(), "unit", item.getUnit(),
                    "status", item.getExceptionStatus(), "message", "测试预警异常")));
            mapper.selectWarningExceptions(testId, "OPEN").forEach(item -> {
                boolean offline = "DEVICE_OFFLINE".equals(item.getExceptionType());
                if (offline) offlineSources.add(item.getSourceType() + ":" + item.getSourceIdentity());
                // 离线异常没有测量值,必须允许空值,不能用 Map.of 构造响应。
                Map<String, Object> warning = new LinkedHashMap<>();
                warning.put("exceptionId", item.getExceptionId());
                warning.put("exceptionType", item.getExceptionType());
                warning.put("sourceType", item.getSourceType());
                warning.put("sourceIdentity", item.getSourceIdentity());
                warning.put("metricCode", item.getMetricCode());
                warning.put("value", item.getAbnormalValue());
                warning.put("unit", item.getUnit());
                warning.put("status", item.getExceptionStatus());
                warning.put("message", offline ? "接收期间设备离线,等待处理" : "测试预警异常");
                exceptions.add(warning);
            });
        }
        if (receiving) {
            for (LiveSource source : sources) {
                if (!"OFFLINE".equals(source.deviceStatus())) continue;
                String identity = offlineIdentity(test, source);
                if (!offlineSources.add(source.sourceType() + ":" + identity)) continue;
                exceptions.add(Map.of("exceptionType", "DEVICE_OFFLINE", "sourceType", source.sourceType(),
                        "sourceId", source.sourceId(), "sourceIdentity", identity,
                        "status", "OPEN", "message", "接收中数据来源离线,当前无法取得测量数据"));
            }
        }
        String testStatus = test.getTestStatus();
        TestPlanSnapshot testPlan = detectorTestPlan(test);
        return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now().toEpochMilli(), sources, exceptions, testPlan);
    }
    private String offlineIdentity(TTest test, LiveSource source)
    {
        if ("COLLECTOR".equals(source.sourceType())) return String.valueOf(source.sourceId());
        for (TTestBattery battery : test.getBatteries()) {
            var binding = battery.getBinding();
            if (binding != null && Objects.equals(binding.getChannelId(), source.sourceId()))
                return binding.getAdapterCode() + ":" + binding.getDevtype() + ":" + binding.getDevid()
                        + ":" + binding.getSubdevid() + ":" + binding.getChlid();
        }
        return String.valueOf(source.sourceId());
    }
    private TestPlanSnapshot detectorTestPlan(TTest test)
    {
        if (adapter == null) return null;