yeg
2026-09-02 281c6afae7fbbb59a8932ae01db38eda38487fdc
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
@@ -48,14 +48,15 @@
        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 freezeSnapshots = "PAUSED".equals(test.getReceptionStatus())
                || "ENDED".equals(test.getReceptionStatus());
        for (TTestBattery battery : test.getBatteries() == null ? List.<TTestBattery>of() : test.getBatteries())
        {
            if (battery.getBinding() != null)
                sources.add(snapshotFor(testId, cabinetSource(battery, cabinets), freezeSnapshots));
                sources.add(snapshotFor(testId, cabinetSource(battery, cabinets), receiving, freezeSnapshots));
            if (battery.getCollectorId() != null)
                sources.add(snapshotFor(testId, collectorSource(battery), freezeSnapshots));
                sources.add(snapshotFor(testId, collectorSource(battery), receiving, freezeSnapshots));
        }
        List<Map<String, Object>> exceptions = new ArrayList<>();
        exceptions.addAll(sources.stream().filter(source -> !"COLLECTOR".equals(source.sourceType())
@@ -93,12 +94,18 @@
        return null;
    }
    private LiveSource snapshotFor(Long testId, LiveSource fresh, boolean freeze)
    private LiveSource snapshotFor(Long testId, LiveSource fresh, boolean receiving, boolean freeze)
    {
        String key = testId + ":" + fresh.sourceType() + ":" + fresh.sourceId() + ":" + fresh.batteryNo();
        if (freeze) return lastSources.getOrDefault(key, fresh);
        if (!receiving)
            return freeze ? lastSources.getOrDefault(key, withoutSnapshot(fresh)) : withoutSnapshot(fresh);
        lastSources.put(key, fresh);
        return fresh;
    }
    private LiveSource withoutSnapshot(LiveSource source)
    {
        return new LiveSource(source.sourceType(), source.sourceId(), source.batteryNo(), source.deviceStatus(), Map.of());
    }
    @Override public SseEmitter stream(Long testId)
@@ -163,6 +170,11 @@
        if (channel.latestSnapshot() == null) return value;
        value.put("source", "检测柜");
        value.put("observedAt", channel.latestSnapshot().receivedAt());
        // BTS 核心采样字段是快照的一等事实,不能只依赖动态 measurements 展示。
        value.put("currentA", channel.latestSnapshot().currentA());
        value.put("voltageV", channel.latestSnapshot().voltageV());
        value.put("capacityAh", channel.latestSnapshot().capacityAh());
        value.put("energyWh", channel.latestSnapshot().energyWh());
        // 实时方案需要设备当前循环和实际工步;这些字段只用于快照展示,不形成历史采集事实。
        value.put("cycleNo", channel.latestSnapshot().cycleNo());
        value.put("stepNo", channel.latestSnapshot().stepNo());
@@ -172,7 +184,13 @@
            Measurement measurement = entry.getValue();
            return Map.of("metricCode", entry.getKey(), "value", measurement.value(), "unit", measurement.unit());
        }).toList());
        value.put("units", channel.latestSnapshot().measurements().values().stream().map(Measurement::unit).distinct().toList());
        List<String> units = new ArrayList<>();
        if (channel.latestSnapshot().currentA() != null) units.add("A");
        if (channel.latestSnapshot().voltageV() != null) units.add("V");
        if (channel.latestSnapshot().capacityAh() != null) units.add("Ah");
        if (channel.latestSnapshot().energyWh() != null) units.add("Wh");
        units.addAll(channel.latestSnapshot().measurements().values().stream().map(Measurement::unit).toList());
        value.put("units", units.stream().filter(item -> item != null && !item.isBlank()).distinct().toList());
        return value;
    }