From dd1af98f7e679290e5280e2aff58d7ff5237c5fb Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 11:17:11 +0800
Subject: [PATCH] 实现测试数据物理删除修订

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java           |    7 +++
 ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml                            |   12 ++++++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java                      |   12 ++++++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestConsoleDataServiceImpl.java |   35 ++++++++++++++++-
 4 files changed, 64 insertions(+), 2 deletions(-)

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 d0e401b..930905e 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
@@ -176,6 +176,18 @@
     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);
+    int deleteRealtimeRecordsByIds(@Param("testId") Long testId, @Param("recordIds") List<Long> recordIds);
+    int deleteRealtimeSnapshotsByIds(@Param("testId") Long testId, @Param("snapshotIds") List<Long> snapshotIds);
+    int deleteStepRecordsByIds(@Param("testId") Long testId, @Param("recordIds") List<Long> recordIds);
+    int deleteCycleRecordsByIds(@Param("testId") Long testId, @Param("recordIds") List<Long> recordIds);
+    int deleteCollectorSamplesByIdentities(@Param("testId") Long testId, @Param("identities") List<String> identities);
+    int deleteTestRealtimeRecordsByTestId(Long testId);
+    int deleteTestRealtimeSnapshotsByTestId(Long testId);
+    int deleteTestStepRecordsByTestId(Long testId);
+    int deleteTestCycleRecordsByTestId(Long testId);
+    int deleteTestDataRevisionActionsByTestId(Long testId);
+    int deleteTestDataOverridesByTestId(Long testId);
+    int deleteTestConsoleImportRecordsByTestId(Long testId);
     Long selectBtsSampleIdByDeviceChannelSequence(@Param("testId") Long testId,
             @Param("deviceId") Long deviceId, @Param("channelNo") Long channelNo,
             @Param("sequenceId") Long sequenceId);
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 22077cd..a6e59f1 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
@@ -278,6 +278,13 @@
             if (!stateMatches(current, WAITING, NOT_STARTED)) throw new ServiceException("开始接收后不能删除测试");
             loadConfiguration(current);
             // 测试整体删除是无痕例外:先清理全部测试绑定和阈值,再删除主记录,不写审计。
+            testMapper.deleteTestRealtimeRecordsByTestId(testId);
+            testMapper.deleteTestRealtimeSnapshotsByTestId(testId);
+            testMapper.deleteTestStepRecordsByTestId(testId);
+            testMapper.deleteTestCycleRecordsByTestId(testId);
+            testMapper.deleteTestDataRevisionActionsByTestId(testId);
+            testMapper.deleteTestDataOverridesByTestId(testId);
+            testMapper.deleteTestConsoleImportRecordsByTestId(testId);
             testMapper.deleteTestCollectorChannelsByTestId(testId);
             testMapper.deleteTestBindingsByTestId(testId);
             testMapper.deleteTestThresholdRowsByTestId(testId);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestConsoleDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestConsoleDataServiceImpl.java
index 78ee125..b2ca305 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestConsoleDataServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestConsoleDataServiceImpl.java
@@ -71,6 +71,10 @@
         if (action.getOperatorName() == null || action.getOperatorName().trim().isEmpty()) action.setOperatorName("未知用户");
         action.setReason(action.getReason().trim());
         action.setCreatedAtUtc(new Date());
+        if ("DELETE".equals(action.getOperationType())) {
+            applyPhysicalDelete(action);
+            return action.getActionId();
+        }
         mapper.insertDataRevisionAction(action);
         if ("IMPORT".equals(action.getOperationType()) && action.getChangesSummary() != null)
         {
@@ -113,11 +117,38 @@
                 mapper.upsertDataOverride(item);
             }
         }
-        // 删除仅写入 deleted 覆盖,保留设备原始采样和采集器事实供追溯。
-        // btsSampleIds/collectorSampleIds 保留在接口中兼容旧调用方,但不再执行物理删除。
         return action.getActionId();
     }
 
+    /** 删除前先把完整当前记录写入修订摘要,再删除事实行。 */
+    private void applyPhysicalDelete(TTestDataRevisionAction action) {
+        List<Map<String,Object>> rows = new java.util.ArrayList<>();
+        List<Map<String,Object>> source = switch (action.getDataType()) {
+            case "REALTIME" -> mapper.selectPersistedFinalRealtimeRecords(action.getTestId());
+            case "STEP" -> mapper.selectPersistedFinalStepRecords(action.getTestId());
+            case "CYCLE" -> mapper.selectPersistedFinalCycleRecords(action.getTestId());
+            default -> List.of();
+        };
+        Set<String> wanted = new HashSet<>();
+        try { for (Object value : JSON.parseArray(action.getIdentitySummary())) wanted.add(String.valueOf(value)); }
+        catch (Exception e) { throw new ServiceException("身份摘要格式无效"); }
+        for (Map<String,Object> row : source) if (wanted.contains(String.valueOf(row.get("stableIdentity")))) rows.add(new java.util.LinkedHashMap<>(row));
+        action.setChangesSummary(JSON.toJSONString(rows));
+        mapper.insertDataRevisionAction(action);
+        List<Long> ids = new java.util.ArrayList<>();
+        for (String identity : wanted) {
+            String[] p = identity.split(":", -1);
+            try { if ("REALTIME".equals(action.getDataType()) && p.length == 2) ids.add(Long.valueOf(p[1]));
+                else if ("STEP".equals(action.getDataType()) && p.length == 2) ids.add(Long.valueOf(p[1]));
+                else if ("CYCLE".equals(action.getDataType()) && p.length == 2) ids.add(Long.valueOf(p[1]));
+            } catch (NumberFormatException ignored) { }
+        }
+        if (ids.isEmpty()) return;
+        if ("REALTIME".equals(action.getDataType())) mapper.deleteRealtimeRecordsByIds(action.getTestId(), ids);
+        if ("STEP".equals(action.getDataType())) mapper.deleteStepRecordsByIds(action.getTestId(), ids);
+        if ("CYCLE".equals(action.getDataType())) mapper.deleteCycleRecordsByIds(action.getTestId(), ids);
+    }
+
     private void validateType(Long testId, String dataType)
     {
         if (testId == null || testId < 1) throw new ServiceException("测试ID无效");
diff --git a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
index ec8d3a0..e90fc6e 100644
--- a/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/TTestMapper.xml
@@ -849,6 +849,18 @@
         delete from t_test_collector_sample where test_id = #{testId} and sample_id in
         <foreach collection="sampleIds" item="id" open="(" separator="," close=")">#{id}</foreach>
     </delete>
+    <delete id="deleteRealtimeRecordsByIds">delete from t_test_realtime_record where test_id=#{testId} and record_id in <foreach collection="recordIds" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
+    <delete id="deleteRealtimeSnapshotsByIds">delete from t_test_realtime_snapshot where test_id=#{testId} and snapshot_id in <foreach collection="snapshotIds" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
+    <delete id="deleteStepRecordsByIds">delete from t_test_step_record where test_id=#{testId} and step_record_id in <foreach collection="recordIds" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
+    <delete id="deleteCycleRecordsByIds">delete from t_test_cycle_record where test_id=#{testId} and cycle_record_id in <foreach collection="recordIds" item="id" open="(" separator="," close=")">#{id}</foreach></delete>
+    <delete id="deleteCollectorSamplesByIdentities">delete from t_test_collector_sample where test_id=#{testId} and concat('collector:', collector_id, ':', channel_code, ':', sequence_id, ':', metric_code) in <foreach collection="identities" item="identity" open="(" separator="," close=")">#{identity}</foreach></delete>
+    <delete id="deleteTestRealtimeRecordsByTestId">delete from t_test_realtime_record where test_id=#{testId}</delete>
+    <delete id="deleteTestRealtimeSnapshotsByTestId">delete from t_test_realtime_snapshot where test_id=#{testId}</delete>
+    <delete id="deleteTestStepRecordsByTestId">delete from t_test_step_record where test_id=#{testId}</delete>
+    <delete id="deleteTestCycleRecordsByTestId">delete from t_test_cycle_record where test_id=#{testId}</delete>
+    <delete id="deleteTestDataRevisionActionsByTestId">delete from t_test_data_revision_action where test_id=#{testId}</delete>
+    <delete id="deleteTestDataOverridesByTestId">delete from t_test_data_override where test_id=#{testId}</delete>
+    <delete id="deleteTestConsoleImportRecordsByTestId">delete from t_test_console_import_record where test_id=#{testId}</delete>
     <select id="selectBtsSampleIdByDeviceChannelSequence" resultType="long">
         select sample.sample_id
         from t_test_sample sample

--
Gitblit v1.7.1