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 |  254 ++++++++++++++++++++++++++++----------------------
 1 files changed, 141 insertions(+), 113 deletions(-)

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 3bfb6fd..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
@@ -23,13 +23,13 @@
 import com.ruoyi.system.domain.TTestCollectorChannel;
 import com.ruoyi.system.domain.TTestPlanStep;
 import com.ruoyi.system.domain.TTestResult;
-import com.ruoyi.system.domain.TTestFieldSnapshot;
 import com.ruoyi.system.domain.TTestWarningThreshold;
+import com.ruoyi.system.domain.TTestLogicStepMapping;
+import com.ruoyi.system.domain.TTestConsoleDetail;
 import com.ruoyi.system.domain.TDetectionChannel;
 import com.ruoyi.system.domain.vo.TestConfigurationOptionsVo;
 import com.ruoyi.system.mapper.TTestMapper;
 import com.ruoyi.system.service.ITTestService;
-import com.ruoyi.system.service.ISharedFieldSnapshotService;
 
 /** 测试配置服务,负责状态边界、关系校验、事务写入和只追加审计。 */
 @Service
@@ -37,8 +37,8 @@
 {
     private static final String WAITING = "WAITING";
     private static final String NOT_STARTED = "NOT_STARTED";
-    private static final Set<String> TEST_STATUSES = Set.of(
-            WAITING, "RUNNING", "PAUSED", "RUNNING_ABNORMAL", "COMPLETION_PENDING", "COMPLETED", "TERMINATED");
+    /** 新流程只允许四种测试状态;历史状态仅在旧数据展示层做兼容映射。 */
+    private static final Set<String> TEST_STATUSES = Set.of(WAITING, "RUNNING", "PAUSED", "COMPLETED");
     private static final Set<String> RECEPTION_STATUSES = Set.of(NOT_STARTED, "RECEIVING", "PAUSED", "ENDED");
     private static final Set<String> THRESHOLD_UNITS = Set.of("A", "V", "Ah", "Wh", "℃");
     private static final Set<String> REQUIRED_COLLECTOR_MEASUREMENTS = Set.of(
@@ -46,9 +46,6 @@
 
     @Autowired
     private TTestMapper testMapper;
-
-    @Autowired
-    private ISharedFieldSnapshotService sharedFieldSnapshotService;
 
     @Override
     public TTest selectTestById(Long testId)
@@ -96,14 +93,11 @@
         validateConfiguration(test);
         test.setTestStatus(WAITING);
         test.setReceptionStatus(NOT_STARTED);
-        test.setFieldSnapshots(sharedFieldSnapshotService.createForBatteryGroup(
-                test.getBatteries().get(0).getGroupId()));
         test.setDelFlag("0");
         test.setCreateTime(new Date());
         testMapper.insertTest(test);
         saveConfiguration(test);
-        testMapper.insertTestAudit(test.getTestId(), "TEST_CREATED", test.getOperatorId(), test.getCreateBy(),
-                null, JSON.toJSONString(test));
+        // 最终基线移除了 t_test_audit;Controller 的 @Log 负责记录创建操作,业务表只保存配置事实。
         return test.getTestId();
     }
 
@@ -115,7 +109,7 @@
         TTest current = testMapper.selectTestByIdForUpdate(test.getTestId());
         if (current == null) throw new ServiceException("测试不存在");
         loadConfiguration(current);
-        if (!NOT_STARTED.equals(current.getReceptionStatus()))
+        if (!stateMatches(current, WAITING, NOT_STARTED))
             throw new ServiceException("开始接收后不能修改测试配置");
 
         test.setCreatorId(current.getCreatorId());
@@ -125,25 +119,16 @@
             test.setMonitorTimeoutMinutes(current.getMonitorTimeoutMinutes());
         validateBase(test, true);
         validateConfiguration(test);
-        Long currentGroupId = current.getBatteries().isEmpty() ? null : current.getBatteries().get(0).getGroupId();
-        Long nextGroupId = test.getBatteries().get(0).getGroupId();
-        test.setFieldSnapshots(sharedFieldSnapshotService.resolveForUpdate(
-                currentGroupId, nextGroupId, current.getFieldSnapshots()));
         test.setUpdateTime(new Date());
         int rows = testMapper.updateTest(test);
         if (rows != 1) throw new ServiceException("测试配置已变更,请刷新后重试");
 
-        // 开始接收前没有数据归属事实,配置关系可在同一事务内整体替换,审计记录仍只追加。
+        // 开始接收前没有数据归属事实,配置关系可在同一事务内整体替换;操作审计由 Controller @Log 追加。
         testMapper.deleteTestCollectorChannelsByTestId(test.getTestId());
         testMapper.deleteTestBindingsByTestId(test.getTestId());
-        testMapper.deleteTestPlanStepsByTestId(test.getTestId());
-        testMapper.deleteTestFieldsByTestId(test.getTestId());
         testMapper.deleteTestBatteriesByTestId(test.getTestId());
         testMapper.deleteTestThresholdsByTestId(test.getTestId());
-        sharedFieldSnapshotService.deleteByTestId(test.getTestId());
         saveConfiguration(test);
-        testMapper.insertTestAudit(test.getTestId(), "TEST_CONFIGURATION_UPDATED", test.getOperatorId(),
-                test.getUpdateBy(), JSON.toJSONString(current), JSON.toJSONString(test));
         return rows;
     }
 
@@ -153,6 +138,9 @@
         throw new ServiceException("旧开始入口已停用,请使用原子开始接收接口并提供操作人");
     }
 
+    /**
+     * 建立测试接收边界;来源离线不阻断状态流转,只有成功观测数据才会写入测试事实。
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int startReception(Long testId, Long operatorId, String updateBy)
@@ -161,7 +149,7 @@
         if (operatorId == null) throw new ServiceException("操作人不能为空");
         TTest current = testMapper.selectTestByIdForUpdate(testId);
         if (current == null) throw new ServiceException("测试不存在");
-        if (!NOT_STARTED.equals(current.getReceptionStatus()))
+        if (!stateMatches(current, WAITING, NOT_STARTED))
             throw new ServiceException("当前测试不是未开始接收状态");
         loadConfiguration(current);
         if (current.getBatteries().isEmpty()) throw new ServiceException("测试未配置电池号");
@@ -178,16 +166,13 @@
             if (!channelIds.add(binding.getChannelId()))
                 throw new ServiceException("检测柜通道重复绑定,无法开始接收");
             TDetectionChannel channel = testMapper.selectReceptionChannelForUpdate(binding.getChannelId());
-            if (channel == null || !isEnabled(channel.getStatus()) || !isOnline(channel.getOnlineStatus()))
-                throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 当前离线或不可观测");
+            if (channel == null || !isEnabled(channel.getStatus()))
+                throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 不存在或未启用");
             // 只有设备事实为运行中时才标记“运行中接入”;设备暂停属于独立设备状态。
-            runtimeAttach |= "WORKING".equalsIgnoreCase(channel.getWorkStatus());
-            if (testMapper.selectChannelLeaseForUpdate(binding.getChannelId()) != null)
-                throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 已被其他测试占用");
+            runtimeAttach |= "WORKING".equalsIgnoreCase(channel.getWorkStatus())
+                    || "RUNNING".equalsIgnoreCase(channel.getWorkStatus());
             if (battery.getCollectorId() == null || testMapper.countCollectorEnabled(battery.getCollectorId()) == 0)
                 throw new ServiceException("电池号 " + battery.getBatteryNo() + " 的采集器不存在或未启用");
-            if (!testMapper.collectorOnline(battery.getCollectorId()))
-                throw new ServiceException("采集器 " + battery.getCollectorId() + " 当前离线或不可观测");
             Integer collectorChannelCount = testMapper.selectCollectorChannelCount(battery.getCollectorId());
             validateCollectorChannels(battery.getCollectorId(), collectorChannelCount == null ? 0 : collectorChannelCount,
                     battery.getCollectorChannels(), collectorChannels);
@@ -196,20 +181,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,
@@ -230,14 +201,13 @@
         if (operatorId == null) throw new ServiceException("操作人不能为空");
         TTest current = testMapper.selectTestByIdForUpdate(testId);
         if (current == null) throw new ServiceException("测试不存在");
-        if (!"RECEIVING".equals(current.getReceptionStatus()))
+        if (!stateMatches(current, "RUNNING", "RECEIVING"))
             throw new ServiceException("当前测试不是接收中状态");
 
         Date actionAt = new Date();
         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;
@@ -251,22 +221,13 @@
         if (operatorId == null) throw new ServiceException("操作人不能为空");
         TTest current = testMapper.selectTestByIdForUpdate(testId);
         if (current == null) throw new ServiceException("测试不存在");
-        if (!"PAUSED".equals(current.getReceptionStatus()))
+        if (!stateMatches(current, "PAUSED", "PAUSED"))
             throw new ServiceException("当前测试不是暂停接收状态");
-        // 加锁查询只返回测试主表,继续接收需要完整绑定配置来重建各来源接收区间。
+        // 加锁查询只返回测试主表,继续接收前重新加载绑定配置以校验来源仍可用。
         loadConfiguration(current);
         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;
@@ -280,28 +241,28 @@
         if (operatorId == null) throw new ServiceException("操作人不能为空");
         TTest current = testMapper.selectTestByIdForUpdate(testId);
         if (current == null) throw new ServiceException("测试不存在");
-        if (NOT_STARTED.equals(current.getReceptionStatus()) || "ENDED".equals(current.getReceptionStatus()))
+        if (!(stateMatches(current, "RUNNING", "RECEIVING")
+                || stateMatches(current, "PAUSED", "PAUSED")))
             throw new ServiceException("当前测试不能停止");
         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", "COMPLETION_PENDING", "receptionStatus", "ENDED",
-                        "polling", "STOPPED", "closedIntervals", closedIntervals, "release", "IMMEDIATE")));
+                JSON.toJSONString(Map.of("testStatus", "COMPLETED", "receptionStatus", "ENDED",
+                        "polling", "STOPPED", "release", "IMMEDIATE")));
         return 1;
-    }
-
-    private boolean isOnline(String status)
-    {
-        return status != null && ("ONLINE".equalsIgnoreCase(status) || "0".equals(status));
     }
 
     private boolean isEnabled(String status)
     {
         return status == null || "0".equals(status);
+    }
+
+    /** 生命周期动作必须同时匹配测试状态和接收状态,避免并发请求后两个状态字段互相矛盾。 */
+    private boolean stateMatches(TTest test, String expectedTestStatus, String expectedReceptionStatus)
+    {
+        return expectedReceptionStatus.equals(test.getReceptionStatus())
+                && expectedTestStatus.equals(test.getTestStatus());
     }
 
     @Override
@@ -314,12 +275,22 @@
         {
             TTest current = testMapper.selectTestByIdForUpdate(testId);
             if (current == null) throw new ServiceException("测试不存在");
-            if (!NOT_STARTED.equals(current.getReceptionStatus())) throw new ServiceException("开始接收后不能删除测试");
+            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);
+            testMapper.deleteTestBatteriesByTestId(testId);
             int deleted = testMapper.deleteTestById(testId, updateBy);
             if (deleted != 1) throw new ServiceException("测试配置已变更,请刷新后重试");
-            testMapper.insertTestAudit(testId, "TEST_DELETED", operatorId, updateBy,
-                    JSON.toJSONString(current), null);
             rows += deleted;
         }
         return rows;
@@ -333,28 +304,97 @@
         return testMapper.selectTestResults(result);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int saveLogicStepMappings(Long testId, List<TTestLogicStepMapping> mappings, Long operatorId, String updateBy)
+    {
+        if (testId == null || operatorId == null) throw new ServiceException("测试和操作人不能为空");
+        TTest current = testMapper.selectTestByIdForUpdate(testId);
+        if (current == null) throw new ServiceException("测试不存在");
+        List<TTestLogicStepMapping> normalized = mappings == null ? List.of() : mappings;
+        int previousEnd = 0;
+        int expectedNo = 1;
+        for (TTestLogicStepMapping mapping : normalized)
+        {
+            if (mapping == null || mapping.getLogicalNo() == null || mapping.getLogicalNo() != expectedNo
+                    || mapping.getStartStepNo() == null || mapping.getEndStepNo() == null
+                    || mapping.getStartStepNo() < 1 || mapping.getEndStepNo() < mapping.getStartStepNo()
+                    || mapping.getStartStepNo() <= previousEnd || StringUtils.isEmpty(trimToNull(mapping.getLogicalName())))
+                throw new ServiceException("逻辑工步必须按循环内连续位置升序且互不重叠");
+            mapping.setLogicalName(trimToNull(mapping.getLogicalName()));
+            previousEnd = mapping.getEndStepNo();
+            expectedNo++;
+        }
+        String oldJson = current.getLogicStepMappingsJson();
+        String newJson = JSON.toJSONString(normalized);
+        int rows = testMapper.updateLogicStepMappings(testId, newJson, updateBy, new Date());
+        if (rows != 1) throw new ServiceException("工步设置已变更,请刷新后重试");
+        testMapper.insertTestAudit(testId, "LOGIC_STEP_MAPPING_UPDATED", operatorId, updateBy, oldJson, newJson);
+        return rows;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int saveConsoleDetail(Long testId, TTestConsoleDetail detail, Long operatorId, String updateBy)
+    {
+        if (testId == null || operatorId == null || detail == null) throw new ServiceException("测试详情不能为空");
+        TTest current = testMapper.selectTestByIdForUpdate(testId);
+        if (current == null) throw new ServiceException("测试不存在");
+        String experimentName = trimToNull(detail.getExperimentName());
+        if (experimentName != null && experimentName.length() > 200) throw new ServiceException("实验名称长度不能超过200个字符");
+        detail.setExperimentName(experimentName);
+        validateConsoleFields(detail.getBatteryFields());
+        validateConsoleFields(detail.getSpecialFields());
+        validateConsoleValues(testId, detail);
+        int rows = testMapper.updateConsoleDetail(testId, JSON.toJSONString(detail), updateBy, new Date());
+        if (rows != 1) throw new ServiceException("测试详情保存失败,请刷新后重试");
+        return rows;
+    }
+
+    private void validateConsoleFields(List<String> fields)
+    {
+        if (fields == null) return;
+        Set<String> names = new HashSet<>();
+        for (String field : fields)
+        {
+            String normalized = trimToNull(field);
+            if (normalized == null || normalized.length() > 100 || !names.add(normalized))
+                throw new ServiceException("测试详情字段不能为空、长度不能超过100且不可重复");
+        }
+    }
+
+    private void validateConsoleValues(Long testId, TTestConsoleDetail detail)
+    {
+        Set<String> allowedFields = new HashSet<>();
+        if (detail.getBatteryFields() != null) allowedFields.addAll(detail.getBatteryFields());
+        if (detail.getSpecialFields() != null) allowedFields.addAll(detail.getSpecialFields());
+        Set<String> batteryNos = new HashSet<>();
+        List<TTestBattery> batteries = testMapper.selectTestBatteries(testId);
+        if (batteries != null) for (TTestBattery battery : batteries) batteryNos.add(battery.getBatteryNo());
+        if (detail.getFieldValues() == null) return;
+        for (Map.Entry<String, Map<String, String>> entry : detail.getFieldValues().entrySet())
+        {
+            if (!allowedFields.contains(entry.getKey()) || entry.getValue() == null)
+                throw new ServiceException("测试详情字段值结构无效");
+            for (Map.Entry<String, String> value : entry.getValue().entrySet())
+            {
+                if (!batteryNos.contains(value.getKey()) || (value.getValue() != null && value.getValue().length() > 500))
+                    throw new ServiceException("测试详情电池号或字段值无效");
+            }
+        }
+    }
+
     private void loadConfiguration(TTest test)
     {
         Long testId = test.getTestId();
-        List<TTestPlanStep> loadedPlanSteps = testMapper.selectTestPlanSteps(testId);
-        List<TTestPlanStep> planSteps = loadedPlanSteps == null ? mutable(test.getPlanSteps()) : mutable(loadedPlanSteps);
-        for (TTestPlanStep step : planSteps)
-        {
-            try
-            {
-                step.setParameters(JSON.parseObject(step.getParametersJson()));
-            }
-            catch (JSONException exception)
-            {
-                throw new ServiceException("计划工步参数无法解析");
-            }
-        }
-
         List<TTestBattery> loadedBatteries = testMapper.selectTestBatteries(testId);
         List<TTestBattery> batteries = loadedBatteries == null || (loadedBatteries.isEmpty() && test.getBatteries() != null
                 && !test.getBatteries().isEmpty()) ? mutable(test.getBatteries()) : mutable(loadedBatteries);
-        List<TTestBatteryField> loadedFields = testMapper.selectTestBatteryFields(testId);
-        List<TTestBatteryField> fields = loadedFields == null ? List.of() : mutable(loadedFields);
+        // 字段属于电池组当前配置;每次查询测试都重新读取,避免产生测试字段快照。
+        List<TTestBatteryField> currentFields = testMapper.selectCurrentBatteryFields(testId);
+        Map<Long, List<TTestBatteryField>> fieldsByBattery = new HashMap<>();
+        for (TTestBatteryField field : mutable(currentFields))
+            fieldsByBattery.computeIfAbsent(field.getRelationId(), ignored -> new ArrayList<>()).add(field);
         List<TTestCollectorChannel> loadedCollectorChannels = testMapper.selectTestCollectorChannels(testId);
         List<TTestCollectorChannel> collectorChannels = loadedCollectorChannels == null ? List.of() : mutable(loadedCollectorChannels);
         Map<Long, TTestChannelBinding> bindings = new HashMap<>();
@@ -367,24 +407,26 @@
         for (TTestBattery battery : batteries)
         {
             battery.setBinding(bindings.get(battery.getRelationId()));
-            if (loadedFields != null && (!loadedFields.isEmpty() || battery.getFields() == null))
-                battery.setFields(fields.stream()
-                        .filter(field -> battery.getRelationId().equals(field.getRelationId()))
-                        .toList());
+            battery.setFields(fieldsByBattery.getOrDefault(battery.getRelationId(), List.of()));
             if (loadedCollectorChannels != null && (!loadedCollectorChannels.isEmpty() || battery.getCollectorChannels() == null))
                 battery.setCollectorChannels(collectorChannels.stream()
                         .filter(mapping -> battery.getRelationId().equals(mapping.getBatteryRelationId()))
                         .toList());
         }
-        test.setPlanSteps(planSteps);
         test.setBatteries(batteries);
         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);
+        // 测试不保存字段快照;字段值始终随电池组当前配置读取。
+        test.setFieldSnapshots(new ArrayList<>());
+        String mappingJson = test.getLogicStepMappingsJson();
+        try { test.setLogicStepMappings(mappingJson == null || mappingJson.isBlank()
+                ? new ArrayList<>() : JSON.parseArray(mappingJson, TTestLogicStepMapping.class)); }
+        catch (JSONException exception) { throw new ServiceException("逻辑工步设置无法解析"); }
+        String detailJson = test.getConsoleDetailJson();
+        try { test.setConsoleDetail(detailJson == null || detailJson.isBlank()
+                ? null : JSON.parseObject(detailJson, TTestConsoleDetail.class)); }
+        catch (JSONException exception) { throw new ServiceException("测试详情无法解析"); }
     }
 
     private void validateBase(TTest test, boolean update)
@@ -412,8 +454,8 @@
 
     private void validateConfiguration(TTest test)
     {
-        // 新建测试只建立业务身份和通道关系,计划工步可在开始接收前补充。
-        if (test.getPlanSteps() == null) test.setPlanSteps(new ArrayList<>());
+        // 计划工步来自设备观测,不属于测试创建配置,也不写入业务库。
+        test.setPlanSteps(new ArrayList<>());
         validateBatteries(test.getBatteries());
         validatePlanSteps(test.getPlanSteps());
         validateThresholds(test.getThresholds());
@@ -561,23 +603,10 @@
 
     private void saveConfiguration(TTest test)
     {
-        for (TTestPlanStep step : test.getPlanSteps())
-        {
-            step.setTestId(test.getTestId());
-            testMapper.insertTestPlanStep(step);
-        }
         for (TTestBattery battery : test.getBatteries())
         {
             battery.setTestId(test.getTestId());
             testMapper.insertTestBattery(battery);
-            if (battery.getFields() != null)
-            {
-                for (TTestBatteryField field : battery.getFields())
-                {
-                    field.setRelationId(battery.getRelationId());
-                    testMapper.insertTestBatteryField(field);
-                }
-            }
             TTestChannelBinding binding = battery.getBinding();
             binding.setTestId(test.getTestId());
             binding.setBatteryRelationId(battery.getRelationId());
@@ -591,7 +620,6 @@
                 testMapper.insertTestCollectorChannel(mapping);
             }
         }
-        sharedFieldSnapshotService.saveForTest(test.getTestId(), test.getFieldSnapshots());
         for (TTestWarningThreshold threshold : test.getThresholds())
         {
             threshold.setTestId(test.getTestId());

--
Gitblit v1.7.1