yeg
6 天以前 e38aca8134570513435c003c25dc05f1ae51c9c9
battery-business/src/main/java/com/battery/business/service/impl/TTestLiveServiceImpl.java
@@ -18,10 +18,12 @@
import com.battery.device.api.model.Measurement;
import com.battery.business.domain.TTest;
import com.battery.business.domain.TTestBattery;
import com.battery.business.domain.TDeviceAdapter;
import com.battery.business.service.ITestLiveService;
import com.battery.business.service.ITestLiveService.TestPlanRow;
import com.battery.business.service.ITestLiveService.TestPlanSnapshot;
import com.battery.business.service.ITTestService;
import com.battery.business.mapper.TDeviceAdapterMapper;
import com.battery.business.mapper.TTestMapper;
/** 将设备最新快照转换为测试视角,按测试接收状态决定是否展示采集参数。 */
@@ -32,15 +34,16 @@
    private final DeviceDiscoveryCandidateStore candidates;
    private final TestDataObservationAdapter adapter;
    private final TTestMapper mapper;
    private final TDeviceAdapterMapper adapters;
    @Autowired
    public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
            @Nullable TestDataObservationAdapter adapter, TTestMapper mapper)
    { this.tests = tests; this.candidates = candidates; this.adapter = adapter; this.mapper = mapper; }
            @Nullable TestDataObservationAdapter adapter, TTestMapper mapper, TDeviceAdapterMapper adapters)
    { this.tests = tests; this.candidates = candidates; this.adapter = adapter; this.mapper = mapper; this.adapters = adapters; }
    public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
            TestDataObservationAdapter adapter)
    { this(tests, candidates, adapter, null); }
    { this(tests, candidates, adapter, null, null); }
    /** 返回测试当前设备事实;接收中展示测量和实时提醒,历史异常处理状态不参与判定。 */
    @Override public LiveState current(Long testId)
@@ -223,25 +226,38 @@
        return value;
    }
    /**
     * 采集器来源:测量按 ADR-0064 由同一来源实例作为辅助测量提供,所以它的在线事实就是该来源的可达性
     * (ADR-0063:在线只表示来源可达),不再依赖只有开发模拟器会产出的发现候选。
     *
     * <p>来源不提供辅助测量、或来源可达但这一刻还没有任何辅助测量值时,明确标注为「无辅助数据」:
     * 这是正常取值而不是故障,主测量接收不受影响,也不因此生成离线异常。来源不可达时不标这个标记——
     * 那种情况是来源离线,由既有的离线异常路径表达。
     */
    private LiveSource collectorSource(TTestBattery battery, boolean receiving)
    {
        if (adapter == null || mapper == null) return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(),
                "OFFLINE", Map.of());
        String collectorCode = mapper.selectCollectorCode(battery.getCollectorId());
        // 非接收状态只读设备发现事实,不能先请求测量再隐藏,否则仍会产生新观测。
        String adapterCode = battery.getBinding() == null ? null : battery.getBinding().getAdapterCode();
        boolean sourceOnline = sourceOnline(adapterCode);
        // 非接收状态只读来源可达性,不能先请求测量再隐藏,否则仍会产生新观测。
        if (!receiving)
        {
            boolean online = candidates.findCollector(collectorCode, Instant.now())
                    .map(DeviceDiscoveryCandidateStore.CollectorCandidate::online).orElse(false);
            return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(),
                    online ? "ONLINE" : "OFFLINE", Map.of());
                    sourceOnline ? "ONLINE" : "OFFLINE", Map.of());
        }
        var collector = adapter.latestCollector(
                battery.getBinding() == null ? null : battery.getBinding().getAdapterCode(), collectorCode);
        if (collector != null)
        {
        var collector = adapter.latestCollector(adapterCode, collectorCode);
            Map<String, Object> value = new LinkedHashMap<>();
            value.put("source", "采集器"); value.put("sampleIntervalMs", collector.sampleIntervalMs());
        value.put("source", "采集器");
        if (collector == null)
        {
            // 该来源根本不提供辅助测量(新威实测无辅助数据;推式来源的列语义确认前同样如此)。
            if (sourceOnline) value.put("auxiliaryDataAvailable", false);
            return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(),
                    sourceOnline ? "ONLINE" : "OFFLINE", value);
        }
        value.put("sampleIntervalMs", collector.sampleIntervalMs());
            // 在业务响应边界转换毫秒时间,设备时间与服务器接收时间分别保留。
            value.put("measurements", collector.measurements().stream().filter(item -> battery.getCollectorChannels() != null
                    && battery.getCollectorChannels().stream().anyMatch(binding -> binding.getChannelCode().equals(item.channelCode())
@@ -258,10 +274,18 @@
            value.put("units", collector.measurements().stream().map(item -> item.unit()).distinct().toList());
            collector.measurements().stream().map(item -> item.serverReceivedAt()).max(Instant::compareTo)
                    .ifPresent(observedAt -> value.put("observedAt", observedAt.toEpochMilli()));
        // 来源可达但这一刻还没有任何辅助测量值:同样是"无辅助数据",按空值展示而不是占位。
        if (collector.online() && collector.measurements().isEmpty()) value.put("auxiliaryDataAvailable", false);
            return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(),
                    collector.online() ? "ONLINE" : "OFFLINE", collector.online() ? value : Map.of());
        }
        return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(), "OFFLINE", Map.of());
    /** 来源实例是否可达;来源编码缺失或查询不到时按不可达处理,不猜也不回退到其他实例。 */
    private boolean sourceOnline(String adapterCode)
    {
        if (adapters == null || adapterCode == null || adapterCode.isBlank()) return false;
        TDeviceAdapter adapter = adapters.selectDeviceAdapterByCode(adapterCode);
        return adapter != null && "ONLINE".equalsIgnoreCase(adapter.getConnectionStatus());
    }
}