From 4eaa4be4d2cbd2aa49d36a313ce71ad3e743db4a Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 02 九月 2026 12:22:53 +0800
Subject: [PATCH] 彻底清理补采完整性遗留依赖
---
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestServiceImpl.java | 145 ++++++++++++++++++++++++++++++++++--------------
1 files changed, 103 insertions(+), 42 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 e2fedad..13f5179 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
@@ -5,6 +5,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import com.alibaba.fastjson2.JSON;
@@ -24,8 +25,8 @@
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.TDetectionChannel;
-import com.ruoyi.system.domain.TTestReceptionInterval;
import com.ruoyi.system.domain.vo.TestConfigurationOptionsVo;
import com.ruoyi.system.mapper.TTestMapper;
import com.ruoyi.system.service.ITTestService;
@@ -167,7 +168,6 @@
if (current.getBatteries().isEmpty()) throw new ServiceException("测试未配置电池号");
Date actionAt = new Date();
- List<TTestReceptionInterval> intervals = new ArrayList<>();
Set<Long> channelIds = new HashSet<>();
Set<String> collectorChannels = new HashSet<>();
boolean runtimeAttach = false;
@@ -181,12 +181,8 @@
TDetectionChannel channel = testMapper.selectReceptionChannelForUpdate(binding.getChannelId());
if (channel == null || !isEnabled(channel.getStatus()) || !isOnline(channel.getOnlineStatus()))
throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 当前离线或不可观测");
- if (channel.getLastSeenAtUtc() == null)
- throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 尚未取得成功观测边界");
- runtimeAttach |= "WORKING".equalsIgnoreCase(channel.getWorkStatus())
- || "PAUSED".equalsIgnoreCase(channel.getWorkStatus());
- if (testMapper.selectChannelLeaseForUpdate(binding.getChannelId()) != null)
- throw new ServiceException("检测柜通道 " + binding.getChannelId() + " 已被其他测试占用");
+ // 只有设备事实为运行中时才标记“运行中接入”;设备暂停属于独立设备状态。
+ runtimeAttach |= "WORKING".equalsIgnoreCase(channel.getWorkStatus());
if (battery.getCollectorId() == null || testMapper.countCollectorEnabled(battery.getCollectorId()) == 0)
throw new ServiceException("电池号 " + battery.getBatteryNo() + " 的采集器不存在或未启用");
if (!testMapper.collectorOnline(battery.getCollectorId()))
@@ -195,32 +191,14 @@
validateCollectorChannels(battery.getCollectorId(), collectorChannelCount == null ? 0 : collectorChannelCount,
battery.getCollectorChannels(), collectorChannels);
- intervals.add(interval(current, binding.getBindingId(), "CABINET_CHANNEL", binding.getChannelId(), null,
- actionAt, Date.from(channel.getLastSeenAtUtc()), runtimeAttach
- ? "运行中接入:采用检测柜最近成功观测边界" : "采用检测柜最近成功观测边界"));
- for (TTestCollectorChannel mapping : mutable(battery.getCollectorChannels()))
- {
- intervals.add(interval(current, binding.getBindingId(), "COLLECTOR_CHANNEL", battery.getCollectorId(),
- mapping.getChannelCode(), actionAt, actionAt, "采集器开始接收确认边界"));
- }
}
try
{
- for (TTestBattery battery : current.getBatteries())
- {
- TTestChannelBinding binding = battery.getBinding();
- testMapper.insertChannelLease(binding.getChannelId(), testId, binding.getBindingId(), operatorId, actionAt);
- for (TTestCollectorChannel mapping : mutable(battery.getCollectorChannels()))
- testMapper.insertCollectorChannelLease(battery.getCollectorId(), mapping.getChannelCode(), testId,
- binding.getBindingId(), operatorId, actionAt);
- }
- for (TTestReceptionInterval interval : intervals) testMapper.insertReceptionInterval(interval);
- if (testMapper.updateReceptionStarted(testId, actionAt, updateBy) != 1)
+ if (testMapper.updateReceptionStarted(testId, actionAt, runtimeAttach, updateBy) != 1)
throw new ServiceException("测试状态已变更,请刷新后重试");
testMapper.insertTestAudit(testId, "RECEPTION_STARTED", operatorId, updateBy, null,
- JSON.toJSONString(Map.of("receptionStatus", "RECEIVING", "intervalCount", intervals.size(),
- "runtimeAttach", runtimeAttach, "intervals", intervals)));
+ JSON.toJSONString(Map.of("receptionStatus", "RECEIVING", "runtimeAttach", runtimeAttach)));
return 1;
}
catch (DuplicateKeyException exception)
@@ -229,20 +207,63 @@
}
}
- private TTestReceptionInterval interval(TTest test, Long bindingId, String sourceType, Long sourceId,
- String sourceChannelCode, Date actionAt, Date boundaryAt, String note)
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int pauseReception(Long testId, Long operatorId, String updateBy)
{
- TTestReceptionInterval interval = new TTestReceptionInterval();
- interval.setTestId(test.getTestId());
- interval.setBindingId(bindingId);
- interval.setSourceType(sourceType);
- interval.setSourceId(sourceId);
- interval.setSourceChannelCode(sourceChannelCode);
- interval.setActionAtUtc(actionAt);
- interval.setStartBoundaryAtUtc(boundaryAt);
- interval.setBoundaryNote(note);
- interval.setIntervalStatus("OPEN");
- return interval;
+ if (testId == null) throw new ServiceException("测试ID不能为空");
+ if (operatorId == null) throw new ServiceException("操作人不能为空");
+ TTest current = testMapper.selectTestByIdForUpdate(testId);
+ if (current == null) throw new ServiceException("测试不存在");
+ if (!"RECEIVING".equals(current.getReceptionStatus()))
+ throw new ServiceException("当前测试不是接收中状态");
+
+ Date actionAt = new Date();
+ if (testMapper.updateReceptionPaused(testId, updateBy, actionAt) != 1)
+ throw new ServiceException("测试状态已变更,请刷新后重试");
+ // 暂停期间停止请求数据;继续接收后仅追加新的成功接收事实。
+ testMapper.insertTestAudit(testId, "RECEPTION_PAUSED", operatorId, updateBy, null,
+ JSON.toJSONString(Map.of("receptionStatus", "PAUSED", "polling", "STOPPED")));
+ return 1;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int resumeReception(Long testId, Long operatorId, String updateBy)
+ {
+ if (testId == null) throw new ServiceException("测试ID不能为空");
+ if (operatorId == null) throw new ServiceException("操作人不能为空");
+ TTest current = testMapper.selectTestByIdForUpdate(testId);
+ if (current == null) throw new ServiceException("测试不存在");
+ if (!"PAUSED".equals(current.getReceptionStatus()))
+ throw new ServiceException("当前测试不是暂停接收状态");
+ // 加锁查询只返回测试主表,继续接收前重新加载绑定配置以校验来源仍可用。
+ loadConfiguration(current);
+ Date actionAt = new Date();
+ if (testMapper.updateReceptionResumed(testId, updateBy, actionAt) != 1)
+ throw new ServiceException("测试状态已变更,请刷新后重试");
+ testMapper.insertTestAudit(testId, "RECEPTION_RESUMED", operatorId, updateBy, null,
+ JSON.toJSONString(Map.of("receptionStatus", "RECEIVING", "polling", "RESUMED")));
+ return 1;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int stopTest(Long testId, Long operatorId, String updateBy)
+ {
+ if (testId == null) throw new ServiceException("测试ID不能为空");
+ 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()))
+ throw new ServiceException("当前测试不能停止");
+ Date actionAt = new Date();
+ if (testMapper.updateReceptionStopped(testId, updateBy, actionAt) != 1)
+ throw new ServiceException("测试状态已变更,请刷新后重试");
+ testMapper.insertTestAudit(testId, "TEST_STOPPED", operatorId, updateBy, null,
+ JSON.toJSONString(Map.of("testStatus", "COMPLETED", "receptionStatus", "ENDED",
+ "polling", "STOPPED", "release", "IMMEDIATE")));
+ return 1;
}
private boolean isOnline(String status)
@@ -282,6 +303,35 @@
if (result == null || result.getTestId() == null) throw new ServiceException("测试ID不能为空");
selectTestById(result.getTestId());
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;
}
private void loadConfiguration(TTest test)
@@ -334,6 +384,10 @@
test.setThresholds(loadedThresholds == null ? mutable(test.getThresholds()) : mutable(loadedThresholds));
List<TTestFieldSnapshot> loadedSnapshots = sharedFieldSnapshotService.selectByTestId(testId);
test.setFieldSnapshots(loadedSnapshots == null ? mutable(test.getFieldSnapshots()) : loadedSnapshots);
+ String mappingJson = test.getLogicStepMappingsJson();
+ try { test.setLogicStepMappings(mappingJson == null || mappingJson.isBlank()
+ ? new ArrayList<>() : JSON.parseArray(mappingJson, TTestLogicStepMapping.class)); }
+ catch (JSONException exception) { throw new ServiceException("逻辑工步设置无法解析"); }
}
private void validateBase(TTest test, boolean update)
@@ -416,7 +470,7 @@
for (TTestCollectorChannel mapping : mappings)
{
if (mapping == null) throw new ServiceException("采集器通道映射不完整");
- mapping.setMeasurementCode(trimToNull(mapping.getMeasurementCode()));
+ mapping.setMeasurementCode(normalizeMeasurementCode(mapping.getMeasurementCode()));
mapping.setMeasurementName(trimToNull(mapping.getMeasurementName()));
mapping.setChannelCode(normalizeCollectorChannel(mapping.getChannelCode()));
if (mapping.getMeasurementCode() == null || mapping.getMeasurementName() == null
@@ -575,6 +629,13 @@
}
}
+ /** 测量编码与数据库不区分大小写排序保持一致,避免校验通过后插入冲突。 */
+ private String normalizeMeasurementCode(String value)
+ {
+ String normalized = trimToNull(value);
+ return normalized == null ? null : normalized.toUpperCase(Locale.ROOT);
+ }
+
private <T> List<T> mutable(List<T> values)
{
return values == null ? new ArrayList<>() : new ArrayList<>(values);
--
Gitblit v1.7.1