| | |
| | | { |
| | | requireTest(testId); |
| | | List<Map<String, Object>> source = new java.util.ArrayList<>(); |
| | | List<Map<String, Object>> snapshots = mapper.selectPersistedRealtimeSnapshots(testId); |
| | | List<Map<String, Object>> snapshots = mapper.selectPersistedFinalRealtimeRecords(testId); |
| | | if (snapshots != null && !snapshots.isEmpty()) source.addAll(snapshots); |
| | | else { |
| | | // 迁移完成前兼容旧数据;新采集只从统一快照读取。 |
| | |
| | | } |
| | | List<Map<String, Object>> effective = applyEffectiveData(testId, "REALTIME", source); |
| | | attachCollectorStepContext(effective); |
| | | return effective; |
| | | return normalizeApiTimes(effective); |
| | | } |
| | | |
| | | @Override public List<Map<String, Object>> steps(Long testId) |
| | | { |
| | | requireTest(testId); |
| | | return applyEffectiveData(testId, "STEP", mapper.selectPersistedSteps(testId)); |
| | | List<Map<String, Object>> source = mapper.selectPersistedFinalStepRecords(testId); |
| | | if (source == null || source.isEmpty()) { |
| | | List<Map<String, Object>> legacy = mapper.selectPersistedSteps(testId); |
| | | if (legacy != null && !legacy.isEmpty()) source = legacy; |
| | | } |
| | | return normalizeApiTimes(applyEffectiveData(testId, "STEP", source)); |
| | | } |
| | | |
| | | @Override public List<Map<String, Object>> cycles(Long testId) |
| | | { |
| | | requireTest(testId); |
| | | return applyEffectiveData(testId, "CYCLE", mapper.selectPersistedCycles(testId)); |
| | | List<Map<String, Object>> source = mapper.selectPersistedFinalCycleRecords(testId); |
| | | if (source == null || source.isEmpty()) { |
| | | List<Map<String, Object>> legacy = mapper.selectPersistedCycles(testId); |
| | | if (legacy != null && !legacy.isEmpty()) source = legacy; |
| | | } |
| | | return normalizeApiTimes(applyEffectiveData(testId, "CYCLE", source)); |
| | | } |
| | | |
| | | /** 自研业务接口统一以 Unix epoch 毫秒返回时间,避免前端依赖数据库日期格式。 */ |
| | | private List<Map<String, Object>> normalizeApiTimes(List<Map<String, Object>> rows) |
| | | { |
| | | if (rows == null) return List.of(); |
| | | for (Map<String, Object> row : rows) |
| | | for (String key : List.of("deviceTime", "recordedAt", "absoluteTime", "serverReceivedAt")) |
| | | { |
| | | Object value = row.get(key); |
| | | if (value instanceof Date date) row.put(key, date.getTime()); |
| | | else if (value instanceof Instant instant) row.put(key, instant.toEpochMilli()); |
| | | } |
| | | return rows; |
| | | } |
| | | |
| | | /** 将最新人工覆盖应用到设备事实,删除只影响当前有效视图,不抹除原始采样。 */ |