From 07d3e4aa6478fe61edb271d80cbc61d037e6f409 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 11:45:36 +0800
Subject: [PATCH] 对齐控制台时间与扩展测量响应
---
ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java | 9 ++++
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java | 17 ++++++--
ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java | 4 +-
ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml | 3 +
ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestDataRevisionAction.java | 2
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java | 1
ruoyi-admin/src/test/java/com/ruoyi/config/ConsoleTimeContractTest.java | 51 +++++++++++++++++++++++++
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java | 2
8 files changed, 80 insertions(+), 9 deletions(-)
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/config/ConsoleTimeContractTest.java b/ruoyi-admin/src/test/java/com/ruoyi/config/ConsoleTimeContractTest.java
new file mode 100644
index 0000000..1d4e812
--- /dev/null
+++ b/ruoyi-admin/src/test/java/com/ruoyi/config/ConsoleTimeContractTest.java
@@ -0,0 +1,51 @@
+package com.ruoyi.config;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import tools.jackson.databind.json.JsonMapper;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.system.domain.TTest;
+import com.ruoyi.system.domain.TTestDataRevisionAction;
+import com.ruoyi.system.service.ITestLiveService.LiveState;
+
+/** 控制台 REST/SSE 的业务时间统一为毫秒,平台响应保持原有格式。 */
+class ConsoleTimeContractTest
+{
+ private final JsonMapper json = JsonMapper.builder().findAndAddModules().build();
+ private final long time = 1788588000123L;
+
+ @Test
+ void testDetailAndRevisionExposeEpochMillis()
+ {
+ TTest test = new TTest();
+ test.setCreateTime(new Date(time));
+ test.setUpdateTime(new Date(time));
+ test.setStartedAtUtc(new Date(time));
+ test.setEndedAtUtc(new Date(time));
+ var detail = json.readTree(json.writeValueAsString(AjaxResult.success(test))).get("data");
+ for (String field : List.of("createTime", "updateTime", "startedAtUtc", "endedAtUtc"))
+ {
+ assertTrue(detail.get(field).isIntegralNumber(), field);
+ assertEquals(time, detail.get(field).longValue());
+ }
+ TTestDataRevisionAction action = new TTestDataRevisionAction();
+ action.setCreatedAtUtc(new Date(time));
+ assertEquals(time, json.readTree(json.writeValueAsString(action)).get("createdAtUtc").longValue());
+ BaseEntity platform = new BaseEntity();
+ platform.setCreateTime(new Date(time));
+ assertTrue(json.readTree(json.writeValueAsString(platform)).get("createTime").isString());
+ }
+
+ @Test
+ void snapshotAndHeartbeatExposeTheSameMillis()
+ {
+ LiveState state = new LiveState(42L, "RUNNING", "RECEIVING", time, List.of(), List.of(), null);
+ assertEquals(time, json.readTree(json.writeValueAsString(state)).get("updatedAt").longValue());
+ assertEquals(time, json.readTree(json.writeValueAsString(Map.of("at", state.updatedAt()))).get("at").longValue());
+ }
+}
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java
index 01cbf4f..dcc55fe 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java
@@ -61,6 +61,7 @@
assertEquals(new BigDecimal("3.700"), snapshot.get("voltageV"));
assertEquals(new BigDecimal("1.200"), snapshot.get("currentA"));
assertEquals(new BigDecimal("2.500"), snapshot.get("capacityAh"));
+ assertEquals(now.toEpochMilli(), snapshot.get("observedAt"));
}
@Test
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java
index 3704d5c..7ca4504 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java
@@ -36,9 +36,12 @@
private String testStatus;
private String receptionStatus;
private Integer monitorTimeoutMinutes;
+ @JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date startedAtUtc;
/** 最近一次开始或继续接收动作建立的服务器时间边界。 */
+ @JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date receptionBoundaryAtUtc;
+ @JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date endedAtUtc;
/** 是否从已运行设备的后续观测边界接入。 */
private Boolean runtimeAttach;
@@ -67,6 +70,12 @@
private String consoleDetailJson;
private TTestConsoleDetail consoleDetail;
+ /** 测试业务时间输出毫秒,平台实体仍保留原有时间格式。 */
+ @Override @JsonFormat(shape = JsonFormat.Shape.NUMBER)
+ public Date getCreateTime() { return super.getCreateTime(); }
+ @Override @JsonFormat(shape = JsonFormat.Shape.NUMBER)
+ public Date getUpdateTime() { return super.getUpdateTime(); }
+
public Long getTestId() { return testId; }
public void setTestId(Long value) { testId = value; }
public String getTestName() { return testName; }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestDataRevisionAction.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestDataRevisionAction.java
index 89497cb..16a4069 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestDataRevisionAction.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestDataRevisionAction.java
@@ -20,7 +20,7 @@
private String reason;
private Long operatorId;
private String operatorName;
- @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
+ @JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date createdAtUtc;
/** 查询展示字段:来源测试名称。 */
private String testName;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java
index 26cd372..d39ebc9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java
@@ -13,12 +13,12 @@
/** 打开实时 SSE;连接初次发送当前事实,后续只推送最新快照。 */
SseEmitter stream(Long testId);
- record LiveState(Long testId, String testStatus, String receptionStatus, Instant updatedAt,
+ record LiveState(Long testId, String testStatus, String receptionStatus, long updatedAt,
List<LiveSource> sources, List<Map<String, Object>> exceptions, TestPlanSnapshot testPlan)
{
public LiveState(Long testId, String testStatus, String receptionStatus, Instant updatedAt,
List<LiveSource> sources, List<Map<String, Object>> exceptions)
- { this(testId, testStatus, receptionStatus, updatedAt, sources, exceptions, null); }
+ { this(testId, testStatus, receptionStatus, updatedAt.toEpochMilli(), sources, exceptions, null); }
}
record TestPlanSnapshot(int currentCycleNo, int currentStepNo, int plannedCycleCount,
List<TestPlanRow> rows) { }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
index 02cd9b9..34cf5e1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
@@ -78,7 +78,7 @@
}
String testStatus = test.getTestStatus();
TestPlanSnapshot testPlan = detectorTestPlan(test);
- return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now(), sources, exceptions, testPlan);
+ return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now().toEpochMilli(), sources, exceptions, testPlan);
}
private TestPlanSnapshot detectorTestPlan(TTest test)
@@ -181,7 +181,7 @@
Map<String, Object> value = new LinkedHashMap<>();
if (channel.latestSnapshot() == null) return value;
value.put("source", "检测柜");
- value.put("observedAt", channel.latestSnapshot().receivedAt());
+ value.put("observedAt", channel.latestSnapshot().receivedAt().toEpochMilli());
// BTS 核心采样字段是快照的一等事实,不能只依赖动态 measurements 展示。
value.put("currentA", channel.latestSnapshot().currentA());
value.put("voltageV", channel.latestSnapshot().voltageV());
@@ -214,10 +214,19 @@
{
Map<String, Object> value = new LinkedHashMap<>();
value.put("source", "采集器"); value.put("sampleIntervalMs", collector.sampleIntervalMs());
- value.put("measurements", collector.latestMeasurements());
+ value.put("measurements", collector.latestMeasurements().stream().map(item -> {
+ Map<String, Object> measurement = new LinkedHashMap<>();
+ measurement.put("metricCode", item.metricCode());
+ measurement.put("channelCode", item.channelCode());
+ measurement.put("value", item.value());
+ measurement.put("unit", item.unit());
+ measurement.put("deviceTime", item.deviceTime().toEpochMilli());
+ measurement.put("serverReceivedAt", item.serverReceivedAt().toEpochMilli());
+ return measurement;
+ }).toList());
value.put("units", collector.latestMeasurements().stream().map(item -> item.unit()).distinct().toList());
collector.latestMeasurements().stream().map(item -> item.serverReceivedAt()).max(Instant::compareTo)
- .ifPresent(observedAt -> value.put("observedAt", observedAt));
+ .ifPresent(observedAt -> value.put("observedAt", observedAt.toEpochMilli()));
return new LiveSource("COLLECTOR", (long) collector.collectorId(), battery.getBatteryNo(),
collector.online() ? "ONLINE" : "OFFLINE", collector.online() ? value : Map.of());
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
index 5d28386..7cb8cd8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
@@ -78,7 +78,7 @@
{
if (rows == null) return List.of();
for (Map<String, Object> row : rows)
- for (String key : List.of("deviceTime", "recordedAt", "absoluteTime", "serverReceivedAt"))
+ for (String key : List.of("deviceTime", "collectorDeviceTime", "captureSlot", "recordedAt", "absoluteTime", "serverReceivedAt"))
{
Object value = row.get(key);
if (value instanceof Date date) row.put(key, date.getTime());
diff --git a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
index e90fc6e..3aff157 100644
--- a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
@@ -451,10 +451,11 @@
concat('RT-', r.record_id) recordNo, 'SNAPSHOT' sourceType, b.battery_no batteryNo,
r.cycle_no cycleNo, r.step_no stepNo, r.step_name stepName, r.step_type stepType,
r.cabinet_sequence_id sequenceId, r.cabinet_device_time_utc deviceTime,
+ r.collector_device_time_utc collectorDeviceTime, r.capture_slot_utc captureSlot,
r.server_received_at_utc serverReceivedAt, r.voltage_v voltage, r.current_a current,
r.capacity_ah capacity, r.energy_wh energy, r.temperature temperature,
r.positive_potential positivePotential, r.negative_potential negativePotential,
- cast(r.extension_measurements_json as char) extensionMeasurements,
+ cast(r.extension_measurements_json as char) extensionMeasurementsJson,
r.adapter_code adapterCode, r.cabinet_devtype devtype, r.cabinet_devid deviceId,
r.cabinet_subdevid subdevid, r.cabinet_chlid channelId, r.collector_id collectorId,
r.collector_channel_code channelCode, r.source_identity sourceIdentity, r.source_record_id sourceRecordId
--
Gitblit v1.7.1