From 74f55db1acd945f4860b2d0b4bae48e2b918b32b Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 02 九月 2026 11:30:30 +0800
Subject: [PATCH] 移除接收区间补采与完整性旧链路
---
ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java | 4
ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java | 3
ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java | 1
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java | 13
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TTestLiveController.java | 10
ruoyi-admin/src/test/java/com/ruoyi/config/TestDeviceBindingMapperContractTest.java | 8
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java | 32 -
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java | 39 --
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java | 1
ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml | 307 ----------------------
ruoyi-admin/src/main/resources/db/migration/V28__remove_reception_backfill_integrity_legacy.sql | 27 ++
ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java | 6
ruoyi-admin/src/test/java/com/ruoyi/config/TestPersistedDataQueryContractTest.java | 2
ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java | 130 +++++----
ruoyi-admin/src/main/java/com/ruoyi/config/TestBackfillScheduler.java | 19 -
ruoyi-system/src/main/java/com/ruoyi/system/domain/TTest.java | 12
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java | 1
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java | 33 --
ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/TTestLiveControllerContractTest.java | 9
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java | 7
ruoyi-system/src/main/java/com/ruoyi/system/service/ITestLiveService.java | 11
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java | 3
ruoyi-admin/src/test/java/com/ruoyi/config/Ticket28MigrationContractTest.java | 39 +++
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java | 34 +-
24 files changed, 199 insertions(+), 552 deletions(-)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java b/ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java
index e827d08..df944cb 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java
@@ -10,7 +10,6 @@
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.ruoyi.system.mapper.TCollectorMapper;
-import com.ruoyi.system.service.ICollectorDisconnectRecoveryService;
/** 将模拟采集器的发现写入 Redis,并同步已登记采集器的实时在线事实。 */
@Component
@@ -19,25 +18,17 @@
private final BtsDevelopmentSimulator simulator;
private final DeviceDiscoveryCandidateStore candidateStore;
private final TCollectorMapper collectorMapper;
- private final ICollectorDisconnectRecoveryService disconnectRecovery;
@Autowired
public DevelopmentCollectorStatusSynchronizer(BtsDevelopmentSimulator simulator,
- DeviceDiscoveryCandidateStore candidateStore, TCollectorMapper collectorMapper,
- ICollectorDisconnectRecoveryService disconnectRecovery)
+ DeviceDiscoveryCandidateStore candidateStore, TCollectorMapper collectorMapper)
{
this.simulator = simulator;
this.candidateStore = candidateStore;
this.collectorMapper = collectorMapper;
- this.disconnectRecovery = disconnectRecovery;
}
/** 保留单元测试及独立模拟器装配使用的旧构造入口。 */
- public DevelopmentCollectorStatusSynchronizer(BtsDevelopmentSimulator simulator,
- DeviceDiscoveryCandidateStore candidateStore, TCollectorMapper collectorMapper)
- {
- this(simulator, candidateStore, collectorMapper, (codes, at) -> { });
- }
/** 完整替换 dev-sim 采集器快照,删除配置后候选立即消失。 */
@Scheduled(fixedDelay = BtsDevelopmentSimulator.POLL_INTERVAL_MS)
@@ -54,7 +45,5 @@
candidateStore.replaceCollectors(BtsDevelopmentSimulator.ADAPTER_CODE, candidates);
candidates.forEach(candidate -> collectorMapper.updateRegisteredObservation(candidate.deviceCode(),
candidate.online() ? "ONLINE" : "OFFLINE"));
- disconnectRecovery.reconcile(simulatorState.collectors().stream()
- .filter(item -> item.online()).map(item -> item.deviceCode()).collect(java.util.stream.Collectors.toSet()), observedAt);
}
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/config/TestBackfillScheduler.java b/ruoyi-admin/src/main/java/com/ruoyi/config/TestBackfillScheduler.java
index bd6d15b..1968ab1 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/config/TestBackfillScheduler.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/config/TestBackfillScheduler.java
@@ -1,24 +1,9 @@
package com.ruoyi.config;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import com.ruoyi.system.service.ITestBackfillService;
/** 以较低优先级执行历史补采;实时设备观测由既有调度器优先完成。 */
-@Component
public class TestBackfillScheduler
{
- private final ITestBackfillService backfill;
-
- public TestBackfillScheduler(ITestBackfillService backfill)
- {
- this.backfill = backfill;
- }
-
- @Scheduled(fixedDelay = 3000)
- public void reconcileAndBackfill()
- {
- backfill.reconcileNaturalEnd();
- backfill.resumePendingBackfill();
- }
+ /** Ticket28 移除历史补采调度,保留空组件避免旧配置加载失败。 */
+ public void reconcileAndBackfill() { }
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TTestLiveController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TTestLiveController.java
index f87fa4d..020a58a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TTestLiveController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TTestLiveController.java
@@ -10,7 +10,6 @@
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.service.ITestLiveService;
-import com.ruoyi.system.service.ITestIntegrityService;
/** 测试控制台实时 REST/SSE 入口,仅负责鉴权和协议转发。 */
@RestController
@@ -18,19 +17,14 @@
public class TTestLiveController extends BaseController
{
private final ITestLiveService liveService;
- private final ITestIntegrityService integrityService;
- public TTestLiveController(ITestLiveService liveService, ITestIntegrityService integrityService)
- { this.liveService = liveService; this.integrityService = integrityService; }
+ public TTestLiveController(ITestLiveService liveService)
+ { this.liveService = liveService; }
@PreAuthorize("@ss.hasPermi('system:test:query')")
@GetMapping("/{testId}/live-state")
public AjaxResult liveState(@PathVariable Long testId) { return success(liveService.current(testId)); }
/** 查询测试完整性问题和可追溯的历史异常事实。 */
- @PreAuthorize("@ss.hasPermi('system:test:query')")
- @GetMapping("/{testId}/integrity")
- public AjaxResult integrity(@PathVariable Long testId) { return success(integrityService.selectIssues(testId)); }
-
@PreAuthorize("@ss.hasPermi('system:test:query')")
@GetMapping(value = "/{testId}/live", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter live(@PathVariable Long testId) { return liveService.stream(testId); }
diff --git a/ruoyi-admin/src/main/resources/db/migration/V28__remove_reception_backfill_integrity_legacy.sql b/ruoyi-admin/src/main/resources/db/migration/V28__remove_reception_backfill_integrity_legacy.sql
new file mode 100644
index 0000000..7acca86
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/db/migration/V28__remove_reception_backfill_integrity_legacy.sql
@@ -0,0 +1,27 @@
+-- Ticket28:撤销已废弃的接收区间、历史补采、完整性和采集器断线恢复模型。
+-- 原始 t_test_sample 仍保留,成功接收数据继续通过该表追加保存。
+SET FOREIGN_KEY_CHECKS = 0;
+
+DROP TABLE t_test_integrity_issue;
+DROP TABLE t_test_backfill_cursor;
+DROP TABLE t_test_collector_exception_interval;
+DROP TABLE t_test_reception_interval;
+DROP TABLE t_collector_channel_lease;
+DROP TABLE t_channel_lease;
+
+ALTER TABLE t_test_sample
+ DROP FOREIGN KEY fk_sample_reception_interval,
+ DROP KEY idx_sample_interval,
+ DROP COLUMN reception_interval_id;
+
+ALTER TABLE t_test_collector_sample
+ DROP FOREIGN KEY fk_collector_sample_reception_interval,
+ DROP KEY idx_collector_sample_interval,
+ DROP COLUMN reception_interval_id;
+
+ALTER TABLE t_test
+ DROP COLUMN backfill_status,
+ DROP COLUMN backfill_started_at_utc,
+ DROP COLUMN backfill_completed_at_utc;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java b/ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java
index 5473902..86631d7 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java
@@ -16,10 +16,10 @@
void productionConstructorIsExplicitlyAutowired()
{
var constructors = DevelopmentCollectorStatusSynchronizer.class.getDeclaredConstructors();
- assertEquals(2, constructors.length);
+ assertEquals(1, constructors.length);
var production = java.util.Arrays.stream(constructors)
.filter(item -> item.isAnnotationPresent(Autowired.class)).findFirst().orElseThrow();
- assertEquals(4, production.getParameterCount());
+ assertEquals(3, production.getParameterCount());
}
@Test
void synchronizesOnlyConfiguredCollectorsWithoutRegisteringThem() throws Exception
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/config/TestDeviceBindingMapperContractTest.java b/ruoyi-admin/src/test/java/com/ruoyi/config/TestDeviceBindingMapperContractTest.java
index ef35d3b..d6c3438 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/config/TestDeviceBindingMapperContractTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/config/TestDeviceBindingMapperContractTest.java
@@ -27,12 +27,14 @@
assertTrue(mapper.contains("id=\"selectReceptionChannelForUpdate\""));
assertTrue(mapper.contains("channel_fact.online_status onlineStatus"));
assertTrue(mapper.contains("channel_fact.last_seen_at_utc lastSeenAtUtc"));
- assertTrue(mapper.contains("then 'RUNNING_ABNORMAL'"));
- assertTrue(mapper.contains("exception_fact.interval_status = 'OPEN'"));
assertTrue(mapper.contains("set test_status = 'COMPLETED'"));
assertTrue(mapper.contains("set test_status = 'COMPLETED', reception_status = 'ENDED'"));
- assertTrue(mapper.contains("backfill_status = 'COMPLETED'"));
assertTrue(mapper.contains("#{testStatus} = 'COMPLETED' and t.test_status in ('COMPLETED', 'COMPLETION_PENDING', 'TERMINATED')"));
+ assertFalse(mapper.contains("t_test_reception_interval"));
+ assertFalse(mapper.contains("reception_interval_id"));
+ assertFalse(mapper.contains("t_test_integrity_issue"));
+ assertFalse(mapper.contains("t_test_backfill_cursor"));
+ assertFalse(mapper.contains("t_test_collector_exception_interval"));
assertFalse(mapper.contains("group_concat"));
}
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/config/TestPersistedDataQueryContractTest.java b/ruoyi-admin/src/test/java/com/ruoyi/config/TestPersistedDataQueryContractTest.java
index 42b1ad9..9dcc7d1 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/config/TestPersistedDataQueryContractTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/config/TestPersistedDataQueryContractTest.java
@@ -16,7 +16,7 @@
assertTrue(mapper.contains("id=\"selectPersistedRecords\""));
assertTrue(mapper.contains("id=\"selectPersistedSteps\""));
assertTrue(mapper.contains("id=\"selectPersistedCycles\""));
- assertTrue(mapper.contains("id=\"selectTestSampleContentHash\""));
+ assertTrue(mapper.contains("id=\"selectBtsSampleContentHash\""));
assertTrue(mapper.contains("sample.step_name"));
assertTrue(mapper.contains("where sample.test_id = #{testId}"));
assertTrue(mapper.contains("from t_test_sample sample"));
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/config/Ticket28MigrationContractTest.java b/ruoyi-admin/src/test/java/com/ruoyi/config/Ticket28MigrationContractTest.java
new file mode 100644
index 0000000..3c30450
--- /dev/null
+++ b/ruoyi-admin/src/test/java/com/ruoyi/config/Ticket28MigrationContractTest.java
@@ -0,0 +1,39 @@
+package com.ruoyi.config;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+
+/** Ticket28 迁移必须移除区间、租约、补采和完整性遗留模型。 */
+class Ticket28MigrationContractTest
+{
+ @Test
+ void removesLegacyTablesColumnsAndConstraints()
+ {
+ String sql = resource("db/migration/V28__remove_reception_backfill_integrity_legacy.sql");
+ assertTrue(sql.contains("DROP TABLE t_test_reception_interval"));
+ assertTrue(sql.contains("DROP TABLE t_collector_channel_lease"));
+ assertTrue(sql.contains("DROP TABLE t_channel_lease"));
+ assertTrue(sql.contains("DROP FOREIGN KEY fk_sample_reception_interval"));
+ assertTrue(sql.contains("DROP FOREIGN KEY fk_collector_sample_reception_interval"));
+ assertTrue(sql.contains("DROP COLUMN reception_interval_id"));
+ assertTrue(sql.contains("DROP COLUMN backfill_status"));
+ assertTrue(sql.contains("DROP COLUMN backfill_started_at_utc"));
+ assertTrue(sql.contains("DROP COLUMN backfill_completed_at_utc"));
+ }
+
+ private static String resource(String path)
+ {
+ try (InputStream stream = Ticket28MigrationContractTest.class.getClassLoader().getResourceAsStream(path))
+ {
+ if (stream == null) throw new AssertionError("Missing migration resource " + path);
+ return new String(stream.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ catch (Exception exception)
+ {
+ throw new AssertionError("Unable to read migration resource " + path, exception);
+ }
+ }
+}
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 f97b7f5..79d4603 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
@@ -14,7 +14,6 @@
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
-import com.ruoyi.system.mapper.TTestMapper;
import com.ruoyi.system.service.ITTestService;
import com.ruoyi.system.service.ITestLiveService.LiveState;
@@ -66,7 +65,7 @@
private TestableLiveService(RecordingEmitter emitter)
{
super(mock(ITTestService.class), mock(DeviceDiscoveryCandidateStore.class),
- mock(BtsDevelopmentSimulator.class), mock(TTestMapper.class));
+ mock(BtsDevelopmentSimulator.class));
this.emitter = emitter;
}
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
index 2198c3a..fea0c55 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
@@ -23,7 +23,6 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.dao.DuplicateKeyException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
@@ -370,7 +369,7 @@
}
@Test
- void startReceptionShouldOpenAllSourceIntervalsAtomically()
+ void startReceptionShouldPersistReceptionWithoutLegacyIntervals()
{
TTest current = validTest();
current.setTestId(10L);
@@ -388,10 +387,6 @@
when(testMapper.updateReceptionStarted(eq(10L), any(), anyBoolean(), eq("operator"))).thenReturn(1);
assertEquals(1, testService.startReception(10L, 7L, "operator"));
- verify(testMapper).insertChannelLease(eq(100L), eq(10L), eq(30L), eq(7L), any());
- verify(testMapper).insertReceptionInterval(eq(10L), eq(30L), eq("CABINET_CHANNEL"), eq(100L), isNull(), any(), eq("RECEPTION_STARTED"));
- verify(testMapper, times(3)).insertCollectorChannelLease(eq(8L), any(), eq(10L), eq(30L), eq(7L), any());
- verify(testMapper, times(3)).insertReceptionInterval(eq(10L), eq(30L), eq("COLLECTOR_CHANNEL"), eq(8L), any(), any(), eq("RECEPTION_STARTED"));
verify(testMapper).insertTestAudit(eq(10L), eq("RECEPTION_STARTED"), eq(7L), eq("operator"), isNull(), any());
}
@@ -421,7 +416,7 @@
}
@Test
- void startReceptionShouldRollbackWhenDatabaseLeaseIsTaken()
+ void startReceptionShouldNotDependOnDatabaseLease()
{
TTest current = validTest();
current.setTestId(10L);
@@ -436,15 +431,10 @@
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
when(testMapper.collectorOnline(8L)).thenReturn(true);
- when(testMapper.insertChannelLease(any(), any(), any(), any(), any()))
- .thenThrow(new DuplicateKeyException("lease already exists"));
+ when(testMapper.updateReceptionStarted(eq(10L), any(), anyBoolean(), eq("operator"))).thenReturn(1);
- ServiceException exception = assertThrows(ServiceException.class,
- () -> testService.startReception(10L, 7L, "operator"));
+ assertEquals(1, testService.startReception(10L, 7L, "operator"));
- assertEquals("数据来源已被其他测试占用,请刷新后重试", exception.getMessage());
- verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
- verify(testMapper, never()).insertTestAudit(anyLong(), any(), anyLong(), any(), any(), any());
}
@Test
@@ -463,7 +453,6 @@
() -> testService.startReception(10L, 7L, "operator"));
assertEquals("检测柜通道 100 当前离线或不可观测", exception.getMessage());
- verify(testMapper, never()).insertChannelLease(any(), any(), any(), any(), any());
verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
}
@@ -489,7 +478,6 @@
() -> testService.startReception(10L, 7L, "operator"));
assertEquals("每个电池号必须绑定主温度、正电位主通道和负电位主通道", exception.getMessage());
- verify(testMapper, never()).insertChannelLease(any(), any(), any(), any(), any());
verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
}
@@ -537,7 +525,7 @@
}
@Test
- void stopTestShouldCompleteAndReleaseLeases()
+ void stopTestShouldCompleteWithoutLegacyLeaseCleanup()
{
TTest current = validTest();
current.setTestId(10L);
@@ -547,28 +535,26 @@
assertEquals(1, testService.stopTest(10L, 7L, "operator"));
verify(testMapper).updateReceptionStopped(eq(10L), eq("operator"), any());
- verify(testMapper).closeOpenReceptionIntervals(eq(10L), any(), eq("MANUAL_END"));
- verify(testMapper).deleteChannelLeasesByTestId(10L);
- verify(testMapper).deleteCollectorChannelLeasesByTestId(10L);
+ verify(testMapper, never()).deleteChannelLeasesByTestId(anyLong());
+ verify(testMapper, never()).deleteCollectorChannelLeasesByTestId(anyLong());
verify(testMapper).insertTestAudit(eq(10L), eq("TEST_STOPPED"), eq(7L), eq("operator"), isNull(),
org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("COMPLETED")));
}
@Test
- void stopTestShouldAuditImmediateReleaseAndClosedIntervals()
+ void stopTestShouldAuditImmediateStop()
{
TTest current = validTest();
current.setTestId(10L);
current.setReceptionStatus("RECEIVING");
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
when(testMapper.updateReceptionStopped(eq(10L), eq("operator"), any())).thenReturn(1);
- when(testMapper.closeOpenReceptionIntervals(eq(10L), any(), eq("MANUAL_END"))).thenReturn(4);
testService.stopTest(10L, 7L, "operator");
verify(testMapper).insertTestAudit(eq(10L), eq("TEST_STOPPED"), eq(7L), eq("operator"), isNull(),
org.mockito.ArgumentMatchers.argThat(value -> value != null
- && value.contains("closedIntervals") && value.contains("IMMEDIATE")));
+ && value.contains("IMMEDIATE")));
}
private void mockEnabledOptions()
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/TTestLiveControllerContractTest.java b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/TTestLiveControllerContractTest.java
index a6d0133..d2fd9e9 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/TTestLiveControllerContractTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/TTestLiveControllerContractTest.java
@@ -23,15 +23,6 @@
.contains("system:test:query"));
}
- @Test
- void integrityMappingIsAuthenticatedSurface()
- {
- Method integrity = method("integrity", Long.class);
- assertArrayEquals(new String[] { "/{testId}/integrity" }, integrity.getAnnotation(GetMapping.class).value());
- assertTrue(integrity.getAnnotation(org.springframework.security.access.prepost.PreAuthorize.class).value()
- .contains("system:test:query"));
- }
-
private Method method(String name, Class<?>... types)
{
try { return TTestLiveController.class.getDeclaredMethod(name, types); }
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 58009e7..eca8f10 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
@@ -39,9 +39,6 @@
private Date endedAtUtc;
/** 是否从已运行设备的后续观测边界接入。 */
private Boolean runtimeAttach;
- private String backfillStatus;
- private Date backfillStartedAtUtc;
- private Date backfillCompletedAtUtc;
private String delFlag;
private String batteryNo;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@@ -58,7 +55,6 @@
@NotEmpty(message = "阈值配置不能为空")
private List<TTestWarningThreshold> thresholds;
private List<TTestFieldSnapshot> fieldSnapshots;
- private List<TTestReceptionInterval> receptionIntervals;
private List<TTestResult> resultSummary;
private String logicStepMappingsJson;
private List<TTestLogicStepMapping> logicStepMappings;
@@ -95,12 +91,6 @@
public void setEndedAtUtc(Date value) { endedAtUtc = value; }
public Boolean getRuntimeAttach() { return runtimeAttach; }
public void setRuntimeAttach(Boolean value) { runtimeAttach = value; }
- public String getBackfillStatus() { return backfillStatus; }
- public void setBackfillStatus(String value) { backfillStatus = value; }
- public Date getBackfillStartedAtUtc() { return backfillStartedAtUtc; }
- public void setBackfillStartedAtUtc(Date value) { backfillStartedAtUtc = value; }
- public Date getBackfillCompletedAtUtc() { return backfillCompletedAtUtc; }
- public void setBackfillCompletedAtUtc(Date value) { backfillCompletedAtUtc = value; }
public String getDelFlag() { return delFlag; }
public void setDelFlag(String value) { delFlag = value; }
public String getBatteryNo() { return batteryNo; }
@@ -119,8 +109,6 @@
public void setThresholds(List<TTestWarningThreshold> value) { thresholds = value; }
public List<TTestFieldSnapshot> getFieldSnapshots() { return fieldSnapshots; }
public void setFieldSnapshots(List<TTestFieldSnapshot> value) { fieldSnapshots = value; }
- public List<TTestReceptionInterval> getReceptionIntervals() { return receptionIntervals; }
- public void setReceptionIntervals(List<TTestReceptionInterval> value) { receptionIntervals = value; }
public List<TTestResult> getResultSummary() { return resultSummary; }
public void setResultSummary(List<TTestResult> value) { resultSummary = value; }
public String getLogicStepMappingsJson() { return logicStepMappingsJson; }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
index 25139a7..f610df5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
@@ -11,12 +11,12 @@
import com.ruoyi.system.domain.TTestPlanStep;
import com.ruoyi.system.domain.TTestResult;
import com.ruoyi.system.domain.TTestWarningThreshold;
-import com.ruoyi.system.domain.TTestCollectorSource;
import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
-import com.ruoyi.system.domain.TTestReceptionInterval;
-import com.ruoyi.system.domain.TTestLogicStepMapping;
+import com.ruoyi.system.domain.TTestCollectorSource;
import com.ruoyi.system.domain.TTestBackfillCursor;
import com.ruoyi.system.domain.TTestIntegrityIssue;
+import com.ruoyi.system.domain.TTestReceptionInterval;
+import com.ruoyi.system.domain.TTestLogicStepMapping;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.TTestDataRevisionAction;
import com.ruoyi.system.domain.TTestConsoleImportRecord;
@@ -57,7 +57,6 @@
List<TTestCollectorChannel> selectTestCollectorChannels(Long testId);
List<TTestWarningThreshold> selectTestThresholds(Long testId);
/** 按来源和起始边界顺序返回测试接收区间。 */
- List<TTestReceptionInterval> selectTestReceptionIntervals(Long testId);
/** 查询当前正在接收的测试,供接收调度绑定测试事实。 */
List<Long> selectReceivingTestIds();
List<java.util.Map<String, Object>> selectPersistedRecords(@org.apache.ibatis.annotations.Param("testId") Long testId);
@@ -86,23 +85,8 @@
/** 锁定检测柜通道的最新可观测事实,供开始接收校验使用。 */
TDetectionChannel selectReceptionChannelForUpdate(Long channelId);
/** 锁定当前检测柜通道租约;返回空表示可接入。 */
- TTestChannelBinding selectChannelLeaseForUpdate(Long channelId);
- int insertChannelLease(@Param("channelId") Long channelId, @Param("testId") Long testId,
- @Param("bindingId") Long bindingId, @Param("acquiredBy") Long acquiredBy,
- @Param("acquiredAtUtc") Date acquiredAtUtc);
- int insertCollectorChannelLease(@Param("collectorId") Long collectorId, @Param("channelCode") String channelCode,
- @Param("testId") Long testId, @Param("bindingId") Long bindingId,
- @Param("acquiredBy") Long acquiredBy, @Param("acquiredAtUtc") Date acquiredAtUtc);
/** 为每个绑定来源追加一个开放接收区间;区间关闭后仅保留历史事实。 */
- int insertReceptionInterval(@Param("testId") Long testId, @Param("bindingId") Long bindingId,
- @Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
- @Param("sourceChannelCode") String sourceChannelCode, @Param("actionAtUtc") Date actionAtUtc,
- @Param("boundaryNote") String boundaryNote);
/** 在停止动作事务内关闭该测试全部开放区间,返回实际关闭数量。 */
- int closeOpenReceptionIntervals(@Param("testId") Long testId, @Param("endBoundaryAtUtc") Date endBoundaryAtUtc,
- @Param("boundaryNote") String boundaryNote);
- int deleteChannelLeasesByTestId(Long testId);
- int deleteCollectorChannelLeasesByTestId(Long testId);
int hasReceivingTestForAdapter(@Param("adapterCode") String adapterCode);
int hasPausedOrEndedTestForAdapter(@Param("adapterCode") String adapterCode);
List<TDetectionChannel> selectReceivingChannelsForAdapter(@Param("adapterCode") String adapterCode);
@@ -117,33 +101,12 @@
@Param("endedAtUtc") Date endedAtUtc);
/** 查询仍在接收中的采集器来源。 */
- List<TTestCollectorSource> selectReceivingCollectorSources();
/** 查询来源当前开放的断线区间。 */
- TTestCollectorExceptionInterval selectOpenCollectorException(@Param("testId") Long testId,
- @Param("batteryRelationId") Long batteryRelationId, @Param("collectorId") Long collectorId,
- @Param("channelCode") String channelCode);
- int insertCollectorExceptionInterval(TTestCollectorExceptionInterval interval);
- int closeCollectorExceptionInterval(@Param("intervalId") Long intervalId,
- @Param("recoveredAtUtc") Date recoveredAtUtc, @Param("missingToUtc") Date missingToUtc);
- List<TTestCollectorExceptionInterval> selectCollectorExceptionIntervals(Long testId);
+ String selectBtsSampleContentHash(@Param("channelId") Long channelId, @Param("btsTestId") String btsTestId,
+ @Param("sequenceId") Long sequenceId);
/** 查询需要自然结束或继续补采的测试。 */
- List<TTest> selectTestsForNaturalEnd();
- List<TTest> selectTestsForBackfill();
/** 按稳定来源身份锁定补采游标,避免应用重启重复推进。 */
- TTestBackfillCursor selectBackfillCursorForUpdate(@Param("testId") Long testId,
- @Param("bindingId") Long bindingId, @Param("sourceType") String sourceType,
- @Param("sourceId") Long sourceId, @Param("sourceChannelCode") String sourceChannelCode);
- int insertBackfillCursor(TTestBackfillCursor cursor);
- int updateBackfillCursor(TTestBackfillCursor cursor);
- int updateTestBackfillStarted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
- int updateTestBackfillWaiting(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc,
- @Param("error") String error);
- int updateTestBackfillCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
- int updateTestCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
- int updateTestNaturallyEnded(@Param("testId") Long testId, @Param("endedAtUtc") Date endedAtUtc);
- String selectSampleContentHash(@Param("channelId") Long channelId, @Param("btsTestId") String btsTestId,
- @Param("sequenceId") Long sequenceId);
/** 按测试事实查询通道序号,避免补采重复写入已即时接收的采样。 */
String selectTestSampleContentHash(@Param("testId") Long testId, @Param("channelId") Long channelId,
@Param("sequenceId") Long sequenceId);
@@ -162,8 +125,8 @@
Long selectBtsSampleId(@Param("channelId") Long channelId, @Param("btsTestId") String btsTestId,
@Param("sequenceId") Long sequenceId);
int insertCollectorSample(@Param("testId") Long testId, @Param("bindingId") Long bindingId,
- @Param("intervalId") Long intervalId,
- @Param("collectorId") Long collectorId, @Param("channelCode") String channelCode,
+ @Param("intervalId") Long intervalId, @Param("collectorId") Long collectorId,
+ @Param("channelCode") String channelCode,
@Param("sequenceId") Long sequenceId, @Param("deviceTimeUtc") Date deviceTimeUtc,
@Param("deviceTimeRaw") String deviceTimeRaw, @Param("receivedAtUtc") Date receivedAtUtc,
@Param("metricCode") String metricCode, @Param("metricValue") java.math.BigDecimal metricValue,
@@ -173,6 +136,61 @@
String selectCollectorSampleContentHash(@Param("collectorId") Long collectorId,
@Param("channelCode") String channelCode, @Param("sequenceId") Long sequenceId,
@Param("metricCode") String metricCode);
+ int insertDataRevisionAction(TTestDataRevisionAction action);
+ List<TTestDataRevisionAction> selectDataRevisionActions(TTestDataRevisionAction query);
+ TTestDataRevisionAction selectDataRevisionActionById(Long actionId);
+ int upsertDataOverride(TTestDataOverride override);
+ List<TTestDataOverride> selectDataOverrides(@Param("testId") Long testId,
+ @Param("dataType") String dataType);
+ int deleteBtsSamplesByIds(@Param("testId") Long testId, @Param("sampleIds") List<Long> sampleIds);
+ int deleteBtsMeasurementsBySampleIds(@Param("sampleIds") List<Long> sampleIds);
+ int deleteCollectorSamplesByIds(@Param("testId") Long testId, @Param("sampleIds") List<Long> sampleIds);
+ Long selectBtsSampleIdByDeviceChannelSequence(@Param("testId") Long testId,
+ @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
+ @Param("sequenceId") Long sequenceId);
+ List<Long> selectBtsSampleIdsByDeviceChannelStep(@Param("testId") Long testId,
+ @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
+ @Param("cycleNo") Integer cycleNo, @Param("stepNo") Integer stepNo);
+ List<Long> selectBtsSampleIdsByDeviceChannelCycle(@Param("testId") Long testId,
+ @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
+ @Param("cycleNo") Integer cycleNo);
+ int insertConsoleImportRecord(TTestConsoleImportRecord record);
+ int insertSampleConflict(@Param("testId") Long testId, @Param("channelId") Long channelId,
+ @Param("detail") String detail);
+ int countTestBatteryNo(@Param("testId") Long testId, @Param("batteryNo") String batteryNo);
+ /** 兼容已移除的历史实现源码;当前运行链路不再调用这些方法。 */
+ TTestChannelBinding selectChannelLeaseForUpdate(Long channelId);
+ int insertChannelLease(@Param("channelId") Long channelId, @Param("testId") Long testId,
+ @Param("bindingId") Long bindingId, @Param("acquiredBy") Long acquiredBy,
+ @Param("acquiredAtUtc") Date acquiredAtUtc);
+ int insertCollectorChannelLease(@Param("collectorId") Long collectorId, @Param("channelCode") String channelCode,
+ @Param("testId") Long testId, @Param("bindingId") Long bindingId,
+ @Param("acquiredBy") Long acquiredBy, @Param("acquiredAtUtc") Date acquiredAtUtc);
+ int deleteChannelLeasesByTestId(Long testId);
+ int deleteCollectorChannelLeasesByTestId(Long testId);
+ List<TTestCollectorSource> selectReceivingCollectorSources();
+ TTestCollectorExceptionInterval selectOpenCollectorException(@Param("testId") Long testId,
+ @Param("batteryRelationId") Long batteryRelationId, @Param("collectorId") Long collectorId,
+ @Param("channelCode") String channelCode);
+ int insertCollectorExceptionInterval(TTestCollectorExceptionInterval interval);
+ int closeCollectorExceptionInterval(@Param("intervalId") Long intervalId,
+ @Param("recoveredAtUtc") Date recoveredAtUtc, @Param("missingToUtc") Date missingToUtc);
+ List<TTestCollectorExceptionInterval> selectCollectorExceptionIntervals(Long testId);
+ List<TTest> selectTestsForNaturalEnd();
+ List<TTest> selectTestsForBackfill();
+ TTestBackfillCursor selectBackfillCursorForUpdate(@Param("testId") Long testId,
+ @Param("bindingId") Long bindingId, @Param("sourceType") String sourceType,
+ @Param("sourceId") Long sourceId, @Param("sourceChannelCode") String sourceChannelCode);
+ int insertBackfillCursor(TTestBackfillCursor cursor);
+ int updateBackfillCursor(TTestBackfillCursor cursor);
+ int updateTestBackfillStarted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
+ int updateTestBackfillWaiting(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc,
+ @Param("error") String error);
+ int updateTestBackfillCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
+ int updateTestCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
+ int updateTestNaturallyEnded(@Param("testId") Long testId, @Param("endedAtUtc") Date endedAtUtc);
+ String selectSampleContentHash(@Param("channelId") Long channelId, @Param("btsTestId") String btsTestId,
+ @Param("sequenceId") Long sequenceId);
int insertBackfillConflict(@Param("testId") Long testId, @Param("channelId") Long channelId,
@Param("detail") String detail);
List<TTestIntegrityIssue> selectIntegrityIssues(Long testId);
@@ -198,25 +216,9 @@
int resolveIntegrityIssue(@Param("issueId") Long issueId, @Param("resolvedAtUtc") Date resolvedAtUtc);
int countOpenIntegrityIssues(Long testId);
int countOpenExceptions(Long testId);
+ int closeOpenReceptionIntervals(@Param("testId") Long testId, @Param("endBoundaryAtUtc") Date endBoundaryAtUtc,
+ @Param("boundaryNote") String boundaryNote);
+ List<TTestReceptionInterval> selectTestReceptionIntervals(Long testId);
- int insertDataRevisionAction(TTestDataRevisionAction action);
- List<TTestDataRevisionAction> selectDataRevisionActions(TTestDataRevisionAction query);
- TTestDataRevisionAction selectDataRevisionActionById(Long actionId);
- int upsertDataOverride(TTestDataOverride override);
- List<TTestDataOverride> selectDataOverrides(@Param("testId") Long testId,
- @Param("dataType") String dataType);
- int deleteBtsSamplesByIds(@Param("testId") Long testId, @Param("sampleIds") List<Long> sampleIds);
- int deleteBtsMeasurementsBySampleIds(@Param("sampleIds") List<Long> sampleIds);
- int deleteCollectorSamplesByIds(@Param("testId") Long testId, @Param("sampleIds") List<Long> sampleIds);
- Long selectBtsSampleIdByDeviceChannelSequence(@Param("testId") Long testId,
- @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
- @Param("sequenceId") Long sequenceId);
- List<Long> selectBtsSampleIdsByDeviceChannelStep(@Param("testId") Long testId,
- @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
- @Param("cycleNo") Integer cycleNo, @Param("stepNo") Integer stepNo);
- List<Long> selectBtsSampleIdsByDeviceChannelCycle(@Param("testId") Long testId,
- @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
- @Param("cycleNo") Integer cycleNo);
- int insertConsoleImportRecord(TTestConsoleImportRecord record);
- int countTestBatteryNo(@Param("testId") Long testId, @Param("batteryNo") String batteryNo);
+ /** ����兼容旧源码的声明;Ticket28 运行链路不再调用。 */
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java
index e75128d..8bbf49f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java
@@ -3,9 +3,10 @@
import java.time.Instant;
import java.util.Set;
+
/** 维护接收中采集器来源的断线异常与恢复边界。 */
public interface ICollectorDisconnectRecoveryService
{
- /** 根据当前模拟器在线设备编码对账所有接收中来源。 */
void reconcile(Set<String> onlineCollectorCodes, Instant observedAt);
+ /** 根据当前模拟器在线设备编码对账所有接收中来源。 */
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java
index 0c54e97..3ae4fff 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java
@@ -3,12 +3,12 @@
/** 设备自然结束后的区间历史补采与恢复协调接口。 */
public interface ITestBackfillService
{
- /** 对接收中的测试检查检测柜自然结束并关闭其接收边界。 */
void reconcileNaturalEnd();
+ void resumePendingBackfill();
+ void endNaturally(Long testId, String reason);
+ /** 对接收中的测试检查检测柜自然结束并关闭其接收边界。 */
/** 从持久化游标继续所有处于完成确认中的测试补采。 */
- void resumePendingBackfill();
/** 立即结束指定测试的接收并进入完成确认中,供自然结束协调器使用。 */
- void endNaturally(Long testId, String reason);
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java
index 9f23f87..a7b8fcc 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java
@@ -3,6 +3,7 @@
import java.util.List;
import com.ruoyi.system.domain.TTestIntegrityIssue;
+
/** 查询测试区间完整性事实。 */
public interface ITestIntegrityService
{
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 521901f..26cd372 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
@@ -3,7 +3,6 @@
import java.time.Instant;
import java.util.List;
import java.util.Map;
-import com.ruoyi.system.domain.TTestIntegrityIssue;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/** 提供测试控制台的双状态实时事实与鉴权 SSE。 */
@@ -15,17 +14,11 @@
/** 打开实时 SSE;连接初次发送当前事实,后续只推送最新快照。 */
SseEmitter stream(Long testId);
record LiveState(Long testId, String testStatus, String receptionStatus, Instant updatedAt,
- List<LiveSource> sources, List<Map<String, Object>> exceptions,
- List<TTestIntegrityIssue> integrityIssues, TestPlanSnapshot testPlan)
+ 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, List.of(), null); }
-
- public LiveState(Long testId, String testStatus, String receptionStatus, Instant updatedAt,
- List<LiveSource> sources, List<Map<String, Object>> exceptions,
- List<TTestIntegrityIssue> integrityIssues)
- { this(testId, testStatus, receptionStatus, updatedAt, sources, exceptions, integrityIssues, null); }
+ { this(testId, testStatus, receptionStatus, updatedAt, 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/CollectorDisconnectRecoveryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java
index d7b264e..4776ed4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java
@@ -13,7 +13,6 @@
import com.ruoyi.system.service.ICollectorDisconnectRecoveryService;
/** 将采集器在线事实对账为可恢复的来源级异常区间。 */
-@Service
public class CollectorDisconnectRecoveryServiceImpl implements ICollectorDisconnectRecoveryService
{
private final TTestMapper mapper;
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 fab0140..97cfc6e 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
@@ -24,8 +24,6 @@
import com.ruoyi.device.model.Measurement;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
-import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
-import com.ruoyi.system.mapper.TTestMapper;
import com.ruoyi.system.service.ITestLiveService;
import com.ruoyi.system.service.ITestLiveService.TestPlanRow;
import com.ruoyi.system.service.ITestLiveService.TestPlanSnapshot;
@@ -38,13 +36,12 @@
private final ITTestService tests;
private final DeviceDiscoveryCandidateStore candidates;
private final BtsDevelopmentSimulator simulator;
- private final TTestMapper testMapper;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
private final ConcurrentMap<String, LiveSource> lastSources = new ConcurrentHashMap<>();
public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
- BtsDevelopmentSimulator simulator, TTestMapper testMapper)
- { this.tests = tests; this.candidates = candidates; this.simulator = simulator; this.testMapper = testMapper; }
+ BtsDevelopmentSimulator simulator)
+ { this.tests = tests; this.candidates = candidates; this.simulator = simulator; }
@Override public LiveState current(Long testId)
{
@@ -60,41 +57,16 @@
if (battery.getCollectorId() != null)
sources.add(snapshotFor(testId, collectorSource(battery), freezeSnapshots));
}
- List<TTestCollectorExceptionInterval> persisted = testMapper.selectCollectorExceptionIntervals(testId);
- if (persisted == null) persisted = List.of();
- List<Map<String, Object>> exceptions = new ArrayList<>(persisted.stream().map(interval -> {
- Map<String, Object> item = new LinkedHashMap<>();
- item.put("sourceType", "COLLECTOR");
- item.put("sourceId", interval.getCollectorId());
- item.put("collectorCode", interval.getCollectorCode());
- item.put("collectorName", interval.getCollectorName());
- item.put("channelCode", interval.getCollectorChannelCode());
- item.put("measurementName", interval.getMeasurementName());
- item.put("exceptionType", interval.getExceptionType());
- item.put("status", interval.getIntervalStatus());
- item.put("openedAt", interval.getOpenedAtUtc());
- item.put("missingFrom", interval.getMissingFromUtc());
- item.put("recoveredAt", interval.getRecoveredAtUtc());
- item.put("missingTo", interval.getMissingToUtc());
- item.put("detail", interval.getDetail());
- return item;
- }).toList());
+ List<Map<String, Object>> exceptions = new ArrayList<>();
exceptions.addAll(sources.stream().filter(source -> !"COLLECTOR".equals(source.sourceType())
&& !"ONLINE".equals(source.deviceStatus())
&& !"WORKING".equals(source.deviceStatus()) && !"PAUSED".equals(source.deviceStatus()))
.map(source -> Map.<String, Object>of("sourceType", source.sourceType(), "sourceId", source.sourceId(),
"batteryNo", source.batteryNo(), "status", source.deviceStatus(), "message", "数据来源当前不可观测"))
.toList());
- boolean abnormal = persisted.stream().anyMatch(item -> "OPEN".equals(item.getIntervalStatus()));
- String testStatus = abnormal && "RUNNING".equals(test.getTestStatus()) ? "RUNNING_ABNORMAL" : test.getTestStatus();
- List<com.ruoyi.system.domain.TTestIntegrityIssue> integrity = new ArrayList<>();
- List<com.ruoyi.system.domain.TTestIntegrityIssue> persistedIntegrity = testMapper.selectIntegrityIssues(testId);
- if (persistedIntegrity != null) integrity.addAll(persistedIntegrity);
- List<com.ruoyi.system.domain.TTestIntegrityIssue> persistedExceptions = testMapper.selectTestExceptionFacts(testId);
- if (persistedExceptions != null) integrity.addAll(persistedExceptions);
+ String testStatus = test.getTestStatus();
TestPlanSnapshot testPlan = detectorTestPlan(test);
- return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now(), sources, exceptions,
- integrity == null ? List.of() : integrity, testPlan);
+ return new LiveState(testId, testStatus, test.getReceptionStatus(), Instant.now(), sources, exceptions, testPlan);
}
private TestPlanSnapshot detectorTestPlan(TTest test)
@@ -169,7 +141,6 @@
emitter.send(SseEmitter.event().name("reception-status").data(Map.of("testId", testId, "receptionStatus", state.receptionStatus())));
emitter.send(SseEmitter.event().name("test-status").data(Map.of("testId", testId, "testStatus", state.testStatus())));
emitter.send(SseEmitter.event().name("exception").data(state.exceptions()));
- emitter.send(SseEmitter.event().name("integrity").data(state.integrityIssues()));
emitter.send(SseEmitter.event().name("heartbeat").data(Map.of("at", state.updatedAt())));
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java
index 649b676..f0135c4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java
@@ -183,8 +183,6 @@
throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 当前离线或不可观测");
// 只有设备事实为运行中时才标记“运行中接入”;设备暂停属于独立设备状态。
runtimeAttach |= "WORKING".equalsIgnoreCase(channel.getWorkStatus());
- if (testMapper.selectChannelLeaseForUpdate(binding.getChannelId()) != null)
- throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 已被其他测试占用");
if (battery.getCollectorId() == null || testMapper.countCollectorEnabled(battery.getCollectorId()) == 0)
throw new ServiceException("电池号 " + battery.getBatteryNo() + " 的采集器不存在或未启用");
if (!testMapper.collectorOnline(battery.getCollectorId()))
@@ -197,20 +195,6 @@
try
{
- for (TTestBattery battery : current.getBatteries())
- {
- TTestChannelBinding binding = battery.getBinding();
- testMapper.insertChannelLease(binding.getChannelId(), testId, binding.getBindingId(), operatorId, actionAt);
- testMapper.insertReceptionInterval(testId, binding.getBindingId(), "CABINET_CHANNEL",
- binding.getChannelId(), null, actionAt, "RECEPTION_STARTED");
- for (TTestCollectorChannel mapping : mutable(battery.getCollectorChannels()))
- {
- testMapper.insertCollectorChannelLease(battery.getCollectorId(), mapping.getChannelCode(), testId,
- binding.getBindingId(), operatorId, actionAt);
- testMapper.insertReceptionInterval(testId, binding.getBindingId(), "COLLECTOR_CHANNEL",
- battery.getCollectorId(), mapping.getChannelCode(), actionAt, "RECEPTION_STARTED");
- }
- }
if (testMapper.updateReceptionStarted(testId, actionAt, runtimeAttach, updateBy) != 1)
throw new ServiceException("测试状态已变更,请刷新后重试");
testMapper.insertTestAudit(testId, "RECEPTION_STARTED", operatorId, updateBy, null,
@@ -238,7 +222,6 @@
if (testMapper.updateReceptionPaused(testId, updateBy, actionAt) != 1)
throw new ServiceException("测试状态已变更,请刷新后重试");
// 暂停边界不属于本次测试的确认接收区间,继续时由新的区间重新开始计时。
- testMapper.closeOpenReceptionIntervals(testId, actionAt, "RECEPTION_PAUSED");
testMapper.insertTestAudit(testId, "RECEPTION_PAUSED", operatorId, updateBy, null,
JSON.toJSONString(Map.of("receptionStatus", "PAUSED", "polling", "STOPPED")));
return 1;
@@ -259,15 +242,6 @@
Date actionAt = new Date();
if (testMapper.updateReceptionResumed(testId, updateBy, actionAt) != 1)
throw new ServiceException("测试状态已变更,请刷新后重试");
- for (TTestBattery battery : current.getBatteries())
- {
- TTestChannelBinding binding = battery.getBinding();
- testMapper.insertReceptionInterval(testId, binding.getBindingId(), "CABINET_CHANNEL",
- binding.getChannelId(), null, actionAt, "RECEPTION_RESUMED");
- for (TTestCollectorChannel mapping : mutable(battery.getCollectorChannels()))
- testMapper.insertReceptionInterval(testId, binding.getBindingId(), "COLLECTOR_CHANNEL",
- battery.getCollectorId(), mapping.getChannelCode(), actionAt, "RECEPTION_RESUMED");
- }
testMapper.insertTestAudit(testId, "RECEPTION_RESUMED", operatorId, updateBy, null,
JSON.toJSONString(Map.of("receptionStatus", "RECEIVING", "polling", "RESUMED")));
return 1;
@@ -286,12 +260,9 @@
Date actionAt = new Date();
if (testMapper.updateReceptionStopped(testId, updateBy, actionAt) != 1)
throw new ServiceException("测试状态已变更,请刷新后重试");
- int closedIntervals = testMapper.closeOpenReceptionIntervals(testId, actionAt, "MANUAL_END");
- testMapper.deleteChannelLeasesByTestId(testId);
- testMapper.deleteCollectorChannelLeasesByTestId(testId);
testMapper.insertTestAudit(testId, "TEST_STOPPED", operatorId, updateBy, null,
JSON.toJSONString(Map.of("testStatus", "COMPLETED", "receptionStatus", "ENDED",
- "polling", "STOPPED", "closedIntervals", closedIntervals, "release", "IMMEDIATE")));
+ "polling", "STOPPED", "release", "IMMEDIATE")));
return 1;
}
@@ -411,8 +382,6 @@
test.setBatteryNo(joinBatteryNos(batteries));
List<TTestWarningThreshold> loadedThresholds = testMapper.selectTestThresholds(testId);
test.setThresholds(loadedThresholds == null ? mutable(test.getThresholds()) : mutable(loadedThresholds));
- List<com.ruoyi.system.domain.TTestReceptionInterval> intervals = testMapper.selectTestReceptionIntervals(testId);
- test.setReceptionIntervals(intervals == null ? List.of() : intervals);
List<TTestFieldSnapshot> loadedSnapshots = sharedFieldSnapshotService.selectByTestId(testId);
test.setFieldSnapshots(loadedSnapshots == null ? mutable(test.getFieldSnapshots()) : loadedSnapshots);
String mappingJson = test.getLogicStepMappingsJson();
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java
index 7f85409..5a92d54 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java
@@ -33,7 +33,6 @@
import com.ruoyi.system.service.ITTestService;
/** 以测试动作边界筛选来源历史,并以数据库游标保证补采可恢复。 */
-@Service
public class TestBackfillServiceImpl implements ITestBackfillService
{
private static final int PAGE_SIZE = 1000;
@@ -195,14 +194,14 @@
if (testScoped != null)
{
if (!testScoped.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
- mapper.insertBackfillConflict(test.getTestId(), binding.getChannelId(),
+ mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
"测试内采样内容冲突 seqid=" + sample.sequenceId());
return;
}
String old = mapper.selectSampleContentHash(binding.getChannelId(), btsTestId, sample.sequenceId());
if (old != null && !old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
{
- mapper.insertBackfillConflict(test.getTestId(), binding.getChannelId(),
+ mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
"BTS testid=" + btsTestId + ", seqid=" + sample.sequenceId());
return;
}
@@ -255,7 +254,7 @@
record.sequenceId(), record.metricCode());
if (old != null && !old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
{
- mapper.insertBackfillConflict(test.getTestId(), null,
+ mapper.insertSampleConflict(test.getTestId(), null,
"采集器=" + record.collectorCode() + ", seqid=" + record.sequenceId());
return;
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java
index 025c217..381adfb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java
@@ -6,8 +6,6 @@
import java.util.Date;
import java.util.HexFormat;
import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
@@ -15,7 +13,6 @@
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.domain.TTestChannelBinding;
-import com.ruoyi.system.domain.TTestReceptionInterval;
import com.ruoyi.system.mapper.TTestMapper;
import com.ruoyi.system.service.ITTestService;
import com.ruoyi.system.service.ITestDataReceptionService;
@@ -43,6 +40,9 @@
if (testIds == null) return;
for (Long testId : testIds)
{
+ // 锁住测试行直到本轮采样写入完成,暂停/停止动作只能在本轮接收提交后生效。
+ TTest locked = mapper.selectTestByIdForUpdate(testId);
+ if (locked == null || !"RECEIVING".equals(locked.getReceptionStatus())) continue;
TTest test = tests.selectTestById(testId);
if (test == null || !"RECEIVING".equals(test.getReceptionStatus())) continue;
captureTest(test);
@@ -55,45 +55,43 @@
{
TTestChannelBinding binding = battery.getBinding();
if (binding == null || binding.getDevid() == null || binding.getChlid() == null) continue;
- Optional<TTestReceptionInterval> open = mapper.selectTestReceptionIntervals(test.getTestId()).stream()
- .filter(item -> Objects.equals(item.getBindingId(), binding.getBindingId())
- && "CABINET_CHANNEL".equals(item.getSourceType())
- && Objects.equals(item.getSourceId(), binding.getChannelId())
- && "OPEN".equals(item.getIntervalStatus()))
- .findFirst();
- if (open.isEmpty()) continue;
- Date start = open.get().getStartBoundaryAtUtc();
List<BtsHistoryRecord> records;
try { records = simulator.btsRecords(binding.getDevid(), binding.getChlid()); }
catch (IllegalArgumentException ignored) { continue; }
for (BtsHistoryRecord record : records)
{
- if (start != null && record.deviceTime().isBefore(start.toInstant())) continue;
- save(test, battery, binding, open.get(), record);
+ save(test, binding, record);
}
}
}
- private void save(TTest test, TTestBattery battery, TTestChannelBinding binding,
- TTestReceptionInterval interval, BtsHistoryRecord record)
+ private void save(TTest test, TTestChannelBinding binding,
+ BtsHistoryRecord record)
{
// 模拟器历史 testid 按通道固定;接收事实必须再带测试作用域,避免顺序测试共用全局幂等键。
String btsTestId = "SIM-" + binding.getDevid() + "-" + binding.getChlid() + "-T" + test.getTestId();
byte[] hash = hash(record);
- String old = mapper.selectSampleContentHash(binding.getChannelId(), btsTestId, record.sequenceId());
+ String old = mapper.selectBtsSampleContentHash(binding.getChannelId(), btsTestId, record.sequenceId());
if (old != null)
{
if (!old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
- mapper.insertBackfillConflict(test.getTestId(), binding.getChannelId(),
+ mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
"实时接收内容冲突 testid=" + btsTestId + ", seqid=" + record.sequenceId());
return;
}
- mapper.insertBtsSample(test.getTestId(), binding.getBindingId(), binding.getChannelId(), interval.getIntervalId(),
+ int inserted = mapper.insertBtsSample(test.getTestId(), binding.getBindingId(), binding.getChannelId(), null,
btsTestId, record.sequenceId(), Date.from(record.deviceTime()),
record.deviceTime().toString(), new Date(), record.cycleNo(), record.stepNo(), record.stepType(),
record.stepName(), null,
BigDecimal.valueOf(record.voltageV()), BigDecimal.valueOf(record.currentA()),
BigDecimal.valueOf(record.capacityAh()), BigDecimal.valueOf(record.energyWh()), hash);
+ if (inserted == 0)
+ {
+ String actual = mapper.selectBtsSampleContentHash(binding.getChannelId(), btsTestId, record.sequenceId());
+ if (actual != null && !actual.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
+ mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
+ "实时接收并发内容冲突 testid=" + btsTestId + ", seqid=" + record.sequenceId());
+ }
}
private byte[] hash(BtsHistoryRecord record)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java
index 59d037e..ebb44b4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java
@@ -9,7 +9,6 @@
import com.ruoyi.system.service.ITestIntegrityService;
/** 完整性查询只返回持久化问题事实,不把实时快照当作历史结果。 */
-@Service
public class TestIntegrityServiceImpl implements ITestIntegrityService
{
private final TTestMapper mapper;
diff --git a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
index 4ba5d0a..d3b21e5 100644
--- a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
@@ -19,9 +19,6 @@
<result property="startedAtUtc" column="started_at_utc" />
<result property="endedAtUtc" column="ended_at_utc" />
<result property="runtimeAttach" column="runtime_attach" />
- <result property="backfillStatus" column="backfill_status" />
- <result property="backfillStartedAtUtc" column="backfill_started_at_utc" />
- <result property="backfillCompletedAtUtc" column="backfill_completed_at_utc" />
<result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
@@ -114,54 +111,18 @@
<result property="exceptionInfo" column="exception_info" />
<result property="delFlag" column="del_flag" />
</resultMap>
- <resultMap id="TTestCollectorExceptionIntervalResultMap" type="TTestCollectorExceptionInterval">
- <id property="intervalId" column="interval_id" />
- <result property="testId" column="test_id" />
- <result property="batteryRelationId" column="battery_relation_id" />
- <result property="collectorId" column="collector_id" />
- <result property="collectorCode" column="collector_code" />
- <result property="collectorName" column="collector_name" />
- <result property="collectorChannelCode" column="collector_channel_code" />
- <result property="measurementName" column="measurement_name" />
- <result property="exceptionType" column="exception_type" />
- <result property="openedAtUtc" column="opened_at_utc" />
- <result property="missingFromUtc" column="missing_from_utc" />
- <result property="recoveredAtUtc" column="recovered_at_utc" />
- <result property="missingToUtc" column="missing_to_utc" />
- <result property="intervalStatus" column="interval_status" />
- <result property="detail" column="detail" />
- </resultMap>
- <resultMap id="TTestReceptionIntervalResultMap" type="TTestReceptionInterval">
- <id property="intervalId" column="interval_id" />
- <result property="testId" column="test_id" />
- <result property="bindingId" column="binding_id" />
- <result property="sourceType" column="source_type" />
- <result property="sourceId" column="source_id" />
- <result property="sourceChannelCode" column="source_channel_code" />
- <result property="actionAtUtc" column="action_at_utc" />
- <result property="startBoundaryAtUtc" column="start_boundary_at_utc" />
- <result property="endBoundaryAtUtc" column="end_boundary_at_utc" />
- <result property="boundaryNote" column="boundary_note" />
- <result property="intervalStatus" column="interval_status" />
- </resultMap>
<sql id="selectTestBase">
select t.test_id, t.test_name, t.creator_id, creator.nick_name creator_name,
t.principal_id, principal.nick_name principal_name,
t.test_type_id, ty.test_type_name, t.test_purpose,
- case when t.test_status = 'RUNNING'
- and exists (select 1 from t_test_collector_exception_interval exception_fact
- where exception_fact.test_id = t.test_id
- and exception_fact.interval_status = 'OPEN')
- then 'RUNNING_ABNORMAL'
- else t.test_status end test_status,
+ t.test_status,
t.reception_status, t.monitor_timeout_minutes,
t.started_at_utc, t.ended_at_utc, t.del_flag,
t.create_by, t.create_time, t.update_by, t.update_time, t.remark,
cast(t.logic_step_mappings_json as char) logic_step_mappings_json,
(select count(1) from t_test_battery b where b.test_id = t.test_id and b.del_flag = 0) battery_count,
- t.runtime_attach runtime_attach, t.backfill_status, t.backfill_started_at_utc,
- t.backfill_completed_at_utc
+ t.runtime_attach runtime_attach
from t_test t
left join sys_user creator on creator.user_id = t.creator_id and creator.del_flag = '0'
left join sys_user principal on principal.user_id = t.principal_id and principal.del_flag = '0'
@@ -178,12 +139,7 @@
<if test="batteryNo != null and batteryNo != ''">and exists (select 1 from t_test_battery fb where fb.test_id = t.test_id and fb.battery_no = #{batteryNo} and fb.del_flag = 0)</if>
<if test="testStatus != null and testStatus != ''">
and (
- (#{testStatus} = 'RUNNING_ABNORMAL' and t.test_status = 'RUNNING'
- and exists (select 1 from t_test_collector_exception_interval exception_fact
- where exception_fact.test_id = t.test_id and exception_fact.interval_status = 'OPEN'))
- or (#{testStatus} = 'RUNNING' and t.test_status = 'RUNNING'
- and not exists (select 1 from t_test_collector_exception_interval exception_fact
- where exception_fact.test_id = t.test_id and exception_fact.interval_status = 'OPEN'))
+ (#{testStatus} = 'RUNNING' and t.test_status = 'RUNNING')
or (#{testStatus} = 'COMPLETED' and t.test_status in ('COMPLETED', 'COMPLETION_PENDING', 'TERMINATED'))
or (#{testStatus} not in ('RUNNING', 'RUNNING_ABNORMAL', 'COMPLETED') and t.test_status = #{testStatus})
)
@@ -359,13 +315,6 @@
<select id="selectTestThresholds" parameterType="Long" resultMap="TTestThresholdResultMap">
select threshold_id, test_id, metric_code, min_value, max_value, unit, severity, del_flag
from t_test_warning_threshold where test_id = #{testId} and del_flag = 0 order by threshold_id
- </select>
- <select id="selectTestReceptionIntervals" parameterType="Long" resultMap="TTestReceptionIntervalResultMap">
- select interval_id, test_id, binding_id, source_type, source_id, source_channel_code,
- action_at_utc, start_boundary_at_utc, end_boundary_at_utc, boundary_note, interval_status
- from t_test_reception_interval
- where test_id = #{testId}
- order by source_type, source_id, source_channel_code, start_boundary_at_utc, interval_id
</select>
<select id="selectReceivingTestIds" resultType="long">
select test_id from t_test where del_flag = 0 and reception_status = 'RECEIVING' order by test_id
@@ -547,90 +496,21 @@
for update
</select>
- <select id="selectTestsForNaturalEnd" resultMap="TTestResultMap">
- <include refid="selectTestBase" />
- where t.del_flag = 0 and t.reception_status in ('RECEIVING', 'PAUSED')
- order by t.test_id
- </select>
- <select id="selectTestsForBackfill" resultMap="TTestResultMap">
- <include refid="selectTestBase" />
- where t.del_flag = 0 and t.reception_status = 'ENDED'
- and t.test_status in ('COMPLETION_PENDING', 'COMPLETED')
- and coalesce(t.backfill_status, 'NOT_STARTED') <> 'COMPLETED'
- order by t.ended_at_utc, t.test_id
- </select>
- <resultMap id="TTestBackfillCursorResultMap" type="com.ruoyi.system.domain.TTestBackfillCursor">
- <id property="cursorId" column="cursor_id" />
- <result property="testId" column="test_id" />
- <result property="bindingId" column="binding_id" />
- <result property="sourceType" column="source_type" />
- <result property="sourceId" column="source_id" />
- <result property="sourceChannelCode" column="source_channel_code" />
- <result property="protocolTestId" column="protocol_test_id" />
- <result property="nextPosition" column="next_position" />
- <result property="sourceStatus" column="source_status" />
- <result property="protocolMetadata" column="protocol_metadata" />
- <result property="lastError" column="last_error" />
- <result property="updatedAtUtc" column="updated_at_utc" />
- </resultMap>
- <select id="selectBackfillCursorForUpdate" resultMap="TTestBackfillCursorResultMap">
- select * from t_test_backfill_cursor
- where test_id = #{testId} and binding_id = #{bindingId}
- and source_type = #{sourceType} and source_id = #{sourceId}
- and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
- for update
- </select>
- <insert id="insertBackfillCursor" parameterType="com.ruoyi.system.domain.TTestBackfillCursor" useGeneratedKeys="true" keyProperty="cursorId">
- insert into t_test_backfill_cursor
- (test_id, binding_id, source_type, source_id, source_channel_code, protocol_test_id,
- next_position, source_status, protocol_metadata, last_error, updated_at_utc)
- values (#{testId}, #{bindingId}, #{sourceType}, #{sourceId}, #{sourceChannelCode}, #{protocolTestId},
- #{nextPosition}, #{sourceStatus}, cast(#{protocolMetadata} as json), #{lastError}, #{updatedAtUtc})
- </insert>
- <update id="updateBackfillCursor" parameterType="com.ruoyi.system.domain.TTestBackfillCursor">
- update t_test_backfill_cursor set protocol_test_id = #{protocolTestId}, next_position = #{nextPosition},
- source_status = #{sourceStatus}, protocol_metadata = cast(#{protocolMetadata} as json),
- last_error = #{lastError}, updated_at_utc = #{updatedAtUtc}
- where cursor_id = #{cursorId}
- </update>
- <update id="updateTestBackfillStarted">
- update t_test set test_status = 'COMPLETION_PENDING', backfill_status = 'RUNNING',
- backfill_started_at_utc = coalesce(backfill_started_at_utc, #{updatedAtUtc}),
- update_time = #{updatedAtUtc} where test_id = #{testId} and reception_status = 'ENDED'
- </update>
- <update id="updateTestBackfillWaiting">
- update t_test set backfill_status = 'WAITING', update_time = #{updatedAtUtc}, remark = #{error}
- where test_id = #{testId} and reception_status = 'ENDED'
- </update>
- <update id="updateTestBackfillCompleted">
- update t_test set backfill_status = 'COMPLETED', backfill_completed_at_utc = #{updatedAtUtc},
- update_time = #{updatedAtUtc} where test_id = #{testId} and reception_status = 'ENDED'
- </update>
<update id="updateTestCompleted">
- update t_test set test_status = 'COMPLETED', backfill_status = 'COMPLETED',
- backfill_completed_at_utc = #{updatedAtUtc}, update_time = #{updatedAtUtc}
+ update t_test set test_status = 'COMPLETED', update_time = #{updatedAtUtc}
where test_id = #{testId} and reception_status = 'ENDED' and test_status = 'COMPLETION_PENDING'
</update>
- <update id="updateTestNaturallyEnded">
- update t_test set test_status = 'COMPLETION_PENDING', reception_status = 'ENDED',
- ended_at_utc = #{endedAtUtc}, backfill_status = 'NOT_STARTED', update_time = #{endedAtUtc}
- where test_id = #{testId} and reception_status in ('RECEIVING', 'PAUSED')
- </update>
- <select id="selectSampleContentHash" resultType="string">
+ <select id="selectBtsSampleContentHash" resultType="string">
select hex(content_sha256) from t_test_sample
where channel_id = #{channelId} and bts_test_id = #{btsTestId} and seq_id = #{sequenceId}
- </select>
- <select id="selectTestSampleContentHash" resultType="string">
- select hex(content_sha256) from t_test_sample
- where test_id = #{testId} and channel_id = #{channelId} and seq_id = #{sequenceId}
order by sample_id limit 1
</select>
<insert id="insertBtsSample">
insert ignore into t_test_sample
- (test_id, binding_id, channel_id, reception_interval_id, bts_test_id, seq_id, device_time_utc,
+ (test_id, binding_id, channel_id, bts_test_id, seq_id, device_time_utc,
device_time_raw, received_at_utc, cycle_no, step_no, step_type, step_name, test_time_ms, voltage_v,
current_a, capacity_ah, energy_wh, content_sha256)
- values (#{testId}, #{bindingId}, #{channelId}, #{intervalId}, #{btsTestId}, #{sequenceId}, #{deviceTimeUtc},
+ values (#{testId}, #{bindingId}, #{channelId}, #{btsTestId}, #{sequenceId}, #{deviceTimeUtc},
#{deviceTimeRaw}, #{receivedAtUtc}, #{cycleNo}, #{stepNo}, #{stepType}, #{stepName}, #{testTimeMs}, #{voltageV},
#{currentA}, #{capacityAh}, #{energyWh}, #{contentSha256})
</insert>
@@ -645,88 +525,11 @@
</select>
<insert id="insertCollectorSample">
insert ignore into t_test_collector_sample
- (test_id, binding_id, reception_interval_id, collector_id, collector_channel_code, sequence_id, device_time_utc,
+ (test_id, binding_id, collector_id, collector_channel_code, sequence_id, device_time_utc,
device_time_raw, server_received_at_utc, metric_code, metric_value, unit, content_sha256)
- values (#{testId}, #{bindingId}, #{intervalId}, #{collectorId}, #{channelCode}, #{sequenceId}, #{deviceTimeUtc},
+ values (#{testId}, #{bindingId}, #{collectorId}, #{channelCode}, #{sequenceId}, #{deviceTimeUtc},
#{deviceTimeRaw}, #{receivedAtUtc}, #{metricCode}, #{metricValue}, #{unit}, #{contentSha256})
</insert>
- <resultMap id="TTestIntegrityIssueResultMap" type="com.ruoyi.system.domain.TTestIntegrityIssue">
- <id property="issueId" column="issue_id"/><result property="testId" column="test_id"/>
- <result property="intervalId" column="interval_id"/><result property="bindingId" column="binding_id"/>
- <result property="sourceType" column="source_type"/><result property="sourceId" column="source_id"/>
- <result property="sourceChannelCode" column="source_channel_code"/><result property="issueType" column="issue_type"/>
- <result property="issueStatus" column="issue_status"/><result property="missingFromSequence" column="missing_from_sequence"/>
- <result property="missingToSequence" column="missing_to_sequence"/><result property="retryCount" column="retry_count"/>
- <result property="detail" column="detail"/><result property="firstDetectedAtUtc" column="first_detected_at_utc"/>
- <result property="lastDetectedAtUtc" column="last_detected_at_utc"/><result property="resolvedAtUtc" column="resolved_at_utc"/>
- </resultMap>
- <select id="selectIntegrityIssues" resultMap="TTestIntegrityIssueResultMap">
- select * from t_test_integrity_issue where test_id = #{testId}
- order by issue_status, last_detected_at_utc desc, issue_id desc
- </select>
- <select id="selectTestExceptionFacts" resultMap="TTestIntegrityIssueResultMap">
- select exception_id issue_id, test_id, null interval_id, null binding_id,
- case when channel_id is null then 'UNKNOWN_SOURCE' else 'CABINET_CHANNEL' end source_type,
- channel_id source_id, null source_channel_code, exception_type issue_type,
- exception_status issue_status, null missing_from_sequence, null missing_to_sequence,
- occurrence_count retry_count, detail, first_occurred_at_utc first_detected_at_utc,
- last_occurred_at_utc last_detected_at_utc, handled_at_utc resolved_at_utc
- from t_test_exception where test_id = #{testId}
- order by exception_status, last_occurred_at_utc desc, exception_id desc
- </select>
- <select id="selectBtsSequencesByInterval" resultType="long">
- select seq_id from t_test_sample where reception_interval_id = #{intervalId} order by seq_id
- </select>
- <select id="selectCollectorSequencesByInterval" resultType="long">
- select distinct sequence_id from t_test_collector_sample where reception_interval_id = #{intervalId} order by sequence_id
- </select>
- <select id="selectOpenIntegrityIssue" resultMap="TTestIntegrityIssueResultMap">
- select * from t_test_integrity_issue where interval_id = #{intervalId} and issue_status = 'OPEN'
- and source_type = #{sourceType} and source_id = #{sourceId}
- and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
- and (missing_from_sequence = #{missingFrom} or (missing_from_sequence is null and #{missingFrom} is null))
- and (missing_to_sequence = #{missingTo} or (missing_to_sequence is null and #{missingTo} is null)) limit 1
- </select>
- <select id="selectOpenIntegrityIssues" resultMap="TTestIntegrityIssueResultMap">
- select * from t_test_integrity_issue where interval_id = #{intervalId} and issue_status = 'OPEN'
- and source_type = #{sourceType} and source_id = #{sourceId}
- and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
- order by issue_id
- </select>
- <insert id="insertIntegrityIssue" parameterType="com.ruoyi.system.domain.TTestIntegrityIssue" useGeneratedKeys="true" keyProperty="issueId">
- insert into t_test_integrity_issue
- (test_id, interval_id, binding_id, source_type, source_id, source_channel_code, issue_type, issue_status,
- missing_from_sequence, missing_to_sequence, retry_count, detail, first_detected_at_utc, last_detected_at_utc)
- values (#{testId}, #{intervalId}, #{bindingId}, #{sourceType}, #{sourceId}, #{sourceChannelCode}, #{issueType}, 'OPEN',
- #{missingFromSequence}, #{missingToSequence}, #{retryCount}, #{detail}, #{firstDetectedAtUtc}, #{lastDetectedAtUtc})
- </insert>
- <update id="touchIntegrityIssue">
- update t_test_integrity_issue set retry_count = #{retryCount}, detail = #{detail}, last_detected_at_utc = #{detectedAtUtc}
- where issue_id = #{issueId} and issue_status = 'OPEN'
- </update>
- <update id="rewindBackfillCursor">
- update t_test_backfill_cursor set next_position = least(next_position, #{nextPosition}),
- source_status = 'PENDING', last_error = '区间序号缺口待重试', updated_at_utc = utc_timestamp(3)
- where test_id = #{testId} and binding_id = #{bindingId} and source_type = #{sourceType}
- and source_id = #{sourceId}
- and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
- </update>
- <update id="resolveIntegrityIssues">
- update t_test_integrity_issue set issue_status = 'RESOLVED', resolved_at_utc = #{resolvedAtUtc}
- where test_id = #{testId} and interval_id = #{intervalId} and issue_status = 'OPEN'
- and source_type = #{sourceType} and source_id = #{sourceId}
- and (source_channel_code = #{sourceChannelCode} or (source_channel_code is null and #{sourceChannelCode} is null))
- </update>
- <update id="resolveIntegrityIssue">
- update t_test_integrity_issue set issue_status = 'RESOLVED', resolved_at_utc = #{resolvedAtUtc}
- where issue_id = #{issueId} and issue_status = 'OPEN'
- </update>
- <select id="countOpenIntegrityIssues" resultType="int">
- select count(1) from t_test_integrity_issue where test_id = #{testId} and issue_status = 'OPEN'
- </select>
- <select id="countOpenExceptions" resultType="int">
- select count(1) from t_test_exception where test_id = #{testId} and exception_status = 'OPEN'
- </select>
<select id="selectCollectorSampleId" resultType="long">
select sample_id from t_test_collector_sample
where collector_id = #{collectorId} and collector_channel_code = #{channelCode}
@@ -737,50 +540,15 @@
where collector_id = #{collectorId} and collector_channel_code = #{channelCode}
and sequence_id = #{sequenceId} and metric_code = #{metricCode}
</select>
- <insert id="insertBackfillConflict">
+ <insert id="insertSampleConflict">
insert into t_test_exception
(test_id, channel_id, exception_type, exception_status, severity,
first_occurred_at_utc, last_occurred_at_utc, occurrence_count, detail)
- values (#{testId}, #{channelId}, 'HISTORY_CONTENT_CONFLICT', 'OPEN', 'WARNING', utc_timestamp(3),
+ values (#{testId}, #{channelId}, 'SAMPLE_CONTENT_CONFLICT', 'OPEN', 'WARNING', utc_timestamp(3),
utc_timestamp(3), 1, #{detail})
on duplicate key update last_occurred_at_utc = utc_timestamp(3), occurrence_count = occurrence_count + 1,
detail = values(detail)
</insert>
- <select id="selectChannelLeaseForUpdate" parameterType="Long" resultMap="TTestBindingResultMap">
- select binding.binding_id, binding.test_id, binding.battery_relation_id, binding.channel_id,
- binding.claim_status
- from t_channel_lease lease
- join t_test_channel_binding binding on binding.binding_id = lease.binding_id
- where lease.channel_id = #{channelId}
- for update
- </select>
- <insert id="insertChannelLease">
- insert into t_channel_lease(channel_id, test_id, binding_id, acquired_by, acquired_at_utc)
- values(#{channelId}, #{testId}, #{bindingId}, #{acquiredBy}, #{acquiredAtUtc})
- </insert>
- <insert id="insertCollectorChannelLease">
- insert into t_collector_channel_lease(collector_id, channel_code, test_id, binding_id, acquired_by, acquired_at_utc)
- values(#{collectorId}, #{channelCode}, #{testId}, #{bindingId}, #{acquiredBy}, #{acquiredAtUtc})
- </insert>
- <insert id="insertReceptionInterval">
- insert into t_test_reception_interval
- (test_id, binding_id, source_type, source_id, source_channel_code,
- action_at_utc, start_boundary_at_utc, boundary_note, interval_status)
- values(#{testId}, #{bindingId}, #{sourceType}, #{sourceId}, #{sourceChannelCode},
- #{actionAtUtc}, #{actionAtUtc}, #{boundaryNote}, 'OPEN')
- </insert>
- <update id="closeOpenReceptionIntervals">
- update t_test_reception_interval
- set end_boundary_at_utc = #{endBoundaryAtUtc},
- boundary_note = #{boundaryNote}, interval_status = 'CLOSED'
- where test_id = #{testId} and interval_status = 'OPEN'
- </update>
- <delete id="deleteChannelLeasesByTestId">
- delete from t_channel_lease where test_id = #{testId}
- </delete>
- <delete id="deleteCollectorChannelLeasesByTestId">
- delete from t_collector_channel_lease where test_id = #{testId}
- </delete>
<select id="hasReceivingTestForAdapter" resultType="int">
select count(1)
from t_test_channel_binding binding
@@ -788,15 +556,6 @@
join t_detection_channel channel_fact on channel_fact.channel_id = binding.channel_id
where channel_fact.adapter_code = #{adapterCode}
and test_fact.reception_status = 'RECEIVING'
- and test_fact.del_flag = 0 and channel_fact.del_flag = 0
- </select>
- <select id="hasPausedOrEndedTestForAdapter" resultType="int">
- select count(1)
- from t_test_channel_binding binding
- join t_test test_fact on test_fact.test_id = binding.test_id
- join t_detection_channel channel_fact on channel_fact.channel_id = binding.channel_id
- where channel_fact.adapter_code = #{adapterCode}
- and test_fact.reception_status in ('PAUSED', 'ENDED')
and test_fact.del_flag = 0 and channel_fact.del_flag = 0
</select>
<select id="selectReceivingChannelsForAdapter" resultType="com.ruoyi.system.domain.TDetectionChannel">
@@ -838,54 +597,10 @@
<update id="updateReceptionStopped">
update t_test
set test_status = 'COMPLETED', reception_status = 'ENDED', ended_at_utc = #{endedAtUtc},
- backfill_status = 'COMPLETED',
update_by = #{updateBy}, update_time = #{endedAtUtc}
where test_id = #{testId} and reception_status in ('RECEIVING', 'PAUSED') and del_flag = 0
</update>
- <select id="selectReceivingCollectorSources" resultType="com.ruoyi.system.domain.TTestCollectorSource">
- select test_fact.test_id testId, battery.relation_id batteryRelationId, battery.battery_no batteryNo,
- collector.collector_id collectorId, collector.collector_code collectorCode,
- mapping.channel_code channelCode
- from t_test test_fact
- join t_test_battery battery on battery.test_id = test_fact.test_id and battery.del_flag = 0
- join t_collector collector on collector.collector_id = battery.collector_id
- and collector.del_flag = 0
- join t_test_collector_channel mapping on mapping.battery_relation_id = battery.relation_id
- and mapping.test_id = test_fact.test_id
- where test_fact.reception_status = 'RECEIVING' and test_fact.del_flag = 0
- order by test_fact.test_id, battery.relation_id, mapping.mapping_id
- </select>
- <select id="selectOpenCollectorException" resultMap="TTestCollectorExceptionIntervalResultMap">
- select * from t_test_collector_exception_interval
- where test_id = #{testId} and battery_relation_id = #{batteryRelationId}
- and collector_id = #{collectorId} and collector_channel_code = #{channelCode}
- and exception_type = 'COLLECTOR_DISCONNECTED' and interval_status = 'OPEN'
- order by interval_id desc limit 1
- </select>
- <insert id="insertCollectorExceptionInterval" parameterType="TTestCollectorExceptionInterval" useGeneratedKeys="true" keyProperty="intervalId">
- insert into t_test_collector_exception_interval
- (test_id, battery_relation_id, collector_id, collector_channel_code, exception_type,
- opened_at_utc, missing_from_utc, detail)
- values (#{testId}, #{batteryRelationId}, #{collectorId}, #{collectorChannelCode},
- #{exceptionType}, #{openedAtUtc}, #{missingFromUtc}, #{detail})
- </insert>
- <update id="closeCollectorExceptionInterval">
- update t_test_collector_exception_interval
- set recovered_at_utc = #{recoveredAtUtc}, missing_to_utc = #{missingToUtc}, interval_status = 'CLOSED'
- where interval_id = #{intervalId} and interval_status = 'OPEN'
- </update>
- <select id="selectCollectorExceptionIntervals" parameterType="Long" resultMap="TTestCollectorExceptionIntervalResultMap">
- select exception_fact.*, collector.collector_code, collector.collector_name,
- mapping.measurement_name
- from t_test_collector_exception_interval exception_fact
- left join t_collector collector on collector.collector_id = exception_fact.collector_id
- left join t_test_collector_channel mapping on mapping.battery_relation_id = exception_fact.battery_relation_id
- and mapping.collector_id = exception_fact.collector_id
- and mapping.channel_code = exception_fact.collector_channel_code
- where exception_fact.test_id = #{testId} and exception_fact.interval_status = 'OPEN'
- order by exception_fact.opened_at_utc, exception_fact.interval_id
- </select>
<resultMap id="TTestDataOverrideResultMap" type="com.ruoyi.system.domain.TTestDataOverride">
<id property="overrideId" column="override_id"/><result property="testId" column="test_id"/>
<result property="dataType" column="data_type"/><result property="stableIdentity" column="stable_identity"/>
--
Gitblit v1.7.1