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 | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 301 insertions(+), 22 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 05d2381..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,11 +5,13 @@
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;
import com.alibaba.fastjson2.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
@@ -18,27 +20,36 @@
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.domain.TTestBatteryField;
import com.ruoyi.system.domain.TTestChannelBinding;
+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.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
public class TTestServiceImpl implements ITTestService
{
private static final String WAITING = "WAITING";
- private static final String NOT_MONITORED = "NOT_MONITORED";
+ 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> MONITORING_STATUSES = Set.of(
- NOT_MONITORED, "WAITING_DEVICE_START", "MONITORING", "BACKFILLING", "MONITORING_ENDED", "CANCELLED");
+ 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(
+ "PRIMARY_TEMPERATURE", "PRIMARY_POSITIVE_POTENTIAL", "PRIMARY_NEGATIVE_POTENTIAL");
@Autowired
private TTestMapper testMapper;
+
+ @Autowired
+ private ISharedFieldSnapshotService sharedFieldSnapshotService;
@Override
public TTest selectTestById(Long testId)
@@ -57,8 +68,10 @@
test.setTestName(trimToNull(test.getTestName()));
test.setBatteryNo(trimToNull(test.getBatteryNo()));
validateQueryStatus(test.getTestStatus(), TEST_STATUSES, "测试状态无效");
- validateQueryStatus(test.getMonitoringStatus(), MONITORING_STATUSES, "监测状态无效");
- return testMapper.selectTestList(test);
+ validateQueryStatus(test.getReceptionStatus(), RECEPTION_STATUSES, "接收状态无效");
+ List<TTest> tests = mutable(testMapper.selectTestList(test));
+ populateBatteryNos(tests);
+ return tests;
}
@Override
@@ -83,7 +96,9 @@
validateBase(test, false);
validateConfiguration(test);
test.setTestStatus(WAITING);
- test.setMonitoringStatus(NOT_MONITORED);
+ test.setReceptionStatus(NOT_STARTED);
+ test.setFieldSnapshots(sharedFieldSnapshotService.createForBatteryGroup(
+ test.getBatteries().get(0).getGroupId()));
test.setDelFlag("0");
test.setCreateTime(new Date());
testMapper.insertTest(test);
@@ -101,26 +116,32 @@
TTest current = testMapper.selectTestByIdForUpdate(test.getTestId());
if (current == null) throw new ServiceException("测试不存在");
loadConfiguration(current);
- if (!NOT_MONITORED.equals(current.getMonitoringStatus()))
- throw new ServiceException("开始监测后不能修改测试配置");
+ if (!NOT_STARTED.equals(current.getReceptionStatus()))
+ throw new ServiceException("开始接收后不能修改测试配置");
test.setCreatorId(current.getCreatorId());
test.setTestStatus(current.getTestStatus());
- test.setMonitoringStatus(current.getMonitoringStatus());
+ test.setReceptionStatus(current.getReceptionStatus());
if (test.getMonitorTimeoutMinutes() == null)
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("测试配置已变更,请刷新后重试");
- // 监测开始前没有原始采集事实,配置关系可在同一事务内整体替换,审计记录仍只追加。
+ // 开始接收前没有数据归属事实,配置关系可在同一事务内整体替换,审计记录仍只追加。
+ 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));
@@ -130,7 +151,129 @@
@Override
public int startTest(Long testId, String updateBy)
{
- throw new ServiceException("开始监测由后续监测动作处理");
+ throw new ServiceException("旧开始入口已停用,请使用原子开始接收接口并提供操作人");
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int startReception(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()))
+ throw new ServiceException("当前测试不是未开始接收状态");
+ loadConfiguration(current);
+ if (current.getBatteries().isEmpty()) throw new ServiceException("测试未配置电池号");
+
+ Date actionAt = new Date();
+ Set<Long> channelIds = new HashSet<>();
+ Set<String> collectorChannels = new HashSet<>();
+ boolean runtimeAttach = false;
+ for (TTestBattery battery : current.getBatteries())
+ {
+ TTestChannelBinding binding = battery.getBinding();
+ if (binding == null || binding.getChannelId() == null)
+ throw new ServiceException("电池号 " + battery.getBatteryNo() + " 未绑定检测柜通道");
+ 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() + " 当前离线或不可观测");
+ // 只有设备事实为运行中时才标记“运行中接入”;设备暂停属于独立设备状态。
+ runtimeAttach |= "WORKING".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);
+
+ }
+
+ try
+ {
+ 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", "runtimeAttach", runtimeAttach)));
+ return 1;
+ }
+ catch (DuplicateKeyException exception)
+ {
+ throw new ServiceException("数据来源已被其他测试占用,请刷新后重试");
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int pauseReception(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 (!"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)
+ {
+ return status != null && ("ONLINE".equalsIgnoreCase(status) || "0".equals(status));
+ }
+
+ private boolean isEnabled(String status)
+ {
+ return status == null || "0".equals(status);
}
@Override
@@ -143,7 +286,7 @@
{
TTest current = testMapper.selectTestByIdForUpdate(testId);
if (current == null) throw new ServiceException("测试不存在");
- if (!NOT_MONITORED.equals(current.getMonitoringStatus())) throw new ServiceException("开始监测后不能删除测试");
+ if (!NOT_STARTED.equals(current.getReceptionStatus())) throw new ServiceException("开始接收后不能删除测试");
loadConfiguration(current);
int deleted = testMapper.deleteTestById(testId, updateBy);
if (deleted != 1) throw new ServiceException("测试配置已变更,请刷新后重试");
@@ -162,10 +305,40 @@
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)
{
Long testId = test.getTestId();
- List<TTestPlanStep> planSteps = mutable(testMapper.selectTestPlanSteps(testId));
+ List<TTestPlanStep> loadedPlanSteps = testMapper.selectTestPlanSteps(testId);
+ List<TTestPlanStep> planSteps = loadedPlanSteps == null ? mutable(test.getPlanSteps()) : mutable(loadedPlanSteps);
for (TTestPlanStep step : planSteps)
{
try
@@ -178,21 +351,43 @@
}
}
- List<TTestBattery> batteries = mutable(testMapper.selectTestBatteries(testId));
- List<TTestBatteryField> fields = mutable(testMapper.selectTestBatteryFields(testId));
+ 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<TTestCollectorChannel> loadedCollectorChannels = testMapper.selectTestCollectorChannels(testId);
+ List<TTestCollectorChannel> collectorChannels = loadedCollectorChannels == null ? List.of() : mutable(loadedCollectorChannels);
Map<Long, TTestChannelBinding> bindings = new HashMap<>();
- for (TTestChannelBinding binding : mutable(testMapper.selectTestChannelBindings(testId)))
+ List<TTestChannelBinding> loadedBindings = testMapper.selectTestChannelBindings(testId);
+ if (loadedBindings == null || (loadedBindings.isEmpty() && batteries.stream().anyMatch(item -> item.getBinding() != null)))
+ for (TTestBattery battery : batteries)
+ if (battery.getBinding() != null) bindings.put(battery.getRelationId(), battery.getBinding());
+ for (TTestChannelBinding binding : mutable(loadedBindings))
bindings.put(binding.getBatteryRelationId(), binding);
for (TTestBattery battery : batteries)
{
battery.setBinding(bindings.get(battery.getRelationId()));
- battery.setFields(fields.stream()
- .filter(field -> battery.getRelationId().equals(field.getRelationId()))
- .toList());
+ if (loadedFields != null && (!loadedFields.isEmpty() || battery.getFields() == null))
+ battery.setFields(fields.stream()
+ .filter(field -> battery.getRelationId().equals(field.getRelationId()))
+ .toList());
+ 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.setThresholds(mutable(testMapper.selectTestThresholds(testId)));
+ test.setBatteryNo(joinBatteryNos(batteries));
+ List<TTestWarningThreshold> loadedThresholds = testMapper.selectTestThresholds(testId);
+ 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)
@@ -220,7 +415,7 @@
private void validateConfiguration(TTest test)
{
- // 新建测试只建立业务身份和通道关系,计划工步可在开始监测前补充。
+ // 新建测试只建立业务身份和通道关系,计划工步可在开始接收前补充。
if (test.getPlanSteps() == null) test.setPlanSteps(new ArrayList<>());
validateBatteries(test.getBatteries());
validatePlanSteps(test.getPlanSteps());
@@ -232,6 +427,8 @@
if (batteries == null || batteries.isEmpty()) throw new ServiceException("测试至少绑定一个电池号");
Set<String> batteryNos = new HashSet<>();
Set<Long> channelIds = new HashSet<>();
+ Set<String> collectorChannelIdentities = new HashSet<>();
+ Map<Long, Integer> collectorChannelCounts = new HashMap<>();
Long groupId = null;
for (TTestBattery battery : batteries)
{
@@ -252,10 +449,45 @@
binding.setExpectedBarcode(trimToNull(binding.getExpectedBarcode()));
if (binding.getExpectedBarcode() != null && binding.getExpectedBarcode().length() > 100)
throw new ServiceException("预期条码长度不能超过100个字符");
- if (battery.getCollectorId() != null && testMapper.countCollectorEnabled(battery.getCollectorId()) == 0)
+ if (battery.getCollectorId() == null) throw new ServiceException("采集器不能为空");
+ if (testMapper.countCollectorEnabled(battery.getCollectorId()) == 0)
throw new ServiceException("采集器不存在或未启用");
+ Integer channelCount = collectorChannelCounts.computeIfAbsent(battery.getCollectorId(),
+ testMapper::selectCollectorChannelCount);
+ if (channelCount == null || channelCount < 1) throw new ServiceException("采集器通道配置无效");
+ validateCollectorChannels(battery.getCollectorId(), channelCount, battery.getCollectorChannels(),
+ collectorChannelIdentities);
validateBatteryFields(battery.getFields());
}
+ }
+
+ private void validateCollectorChannels(Long collectorId, int channelCount, List<TTestCollectorChannel> mappings,
+ Set<String> collectorChannelIdentities)
+ {
+ if (mappings == null || mappings.isEmpty())
+ throw new ServiceException("每个电池号必须绑定主温度、正电位主通道和负电位主通道");
+ Set<String> measurementCodes = new HashSet<>();
+ for (TTestCollectorChannel mapping : mappings)
+ {
+ if (mapping == null) throw new ServiceException("采集器通道映射不完整");
+ mapping.setMeasurementCode(normalizeMeasurementCode(mapping.getMeasurementCode()));
+ mapping.setMeasurementName(trimToNull(mapping.getMeasurementName()));
+ mapping.setChannelCode(normalizeCollectorChannel(mapping.getChannelCode()));
+ if (mapping.getMeasurementCode() == null || mapping.getMeasurementName() == null
+ || mapping.getChannelCode() == null)
+ throw new ServiceException("采集器通道映射不完整");
+ if (mapping.getMeasurementCode().length() > 100 || mapping.getMeasurementName().length() > 100)
+ throw new ServiceException("采集器测量项长度不能超过100个字符");
+ int channelNumber = Integer.parseInt(mapping.getChannelCode().substring(2));
+ if (channelNumber < 1 || channelNumber > channelCount)
+ throw new ServiceException("采集器通道不存在或超出登记范围");
+ if (!measurementCodes.add(mapping.getMeasurementCode()))
+ throw new ServiceException("同一电池号的采集器测量项不可重复");
+ if (!collectorChannelIdentities.add(collectorId + ":" + mapping.getChannelCode()))
+ throw new ServiceException("同一采集器通道不可重复映射");
+ }
+ if (!measurementCodes.containsAll(REQUIRED_COLLECTOR_MEASUREMENTS))
+ throw new ServiceException("每个电池号必须绑定主温度、正电位主通道和负电位主通道");
}
private void validateBatteryFields(List<TTestBatteryField> fields)
@@ -269,6 +501,22 @@
if (field.getFieldName() == null || !fieldNames.add(field.getFieldName()))
throw new ServiceException("扩展属性名称不能为空且不可重复");
}
+ }
+
+ private void populateBatteryNos(List<TTest> tests)
+ {
+ if (tests.isEmpty()) return;
+ Map<Long, List<TTestBattery>> batteriesByTest = new HashMap<>();
+ List<Long> testIds = tests.stream().map(TTest::getTestId).toList();
+ for (TTestBattery battery : mutable(testMapper.selectBatteryNosByTestIds(testIds)))
+ batteriesByTest.computeIfAbsent(battery.getTestId(), ignored -> new ArrayList<>()).add(battery);
+ for (TTest item : tests)
+ item.setBatteryNo(joinBatteryNos(batteriesByTest.get(item.getTestId())));
+ }
+
+ private String joinBatteryNos(List<TTestBattery> batteries)
+ {
+ return mutable(batteries).stream().map(TTestBattery::getBatteryNo).collect(java.util.stream.Collectors.joining("、"));
}
private void validatePlanSteps(List<TTestPlanStep> planSteps)
@@ -338,7 +586,15 @@
binding.setBatteryRelationId(battery.getRelationId());
binding.setClaimStatus("PENDING");
testMapper.insertTestChannelBinding(binding);
+ for (TTestCollectorChannel mapping : battery.getCollectorChannels())
+ {
+ mapping.setTestId(test.getTestId());
+ mapping.setBatteryRelationId(battery.getRelationId());
+ mapping.setCollectorId(battery.getCollectorId());
+ testMapper.insertTestCollectorChannel(mapping);
+ }
}
+ sharedFieldSnapshotService.saveForTest(test.getTestId(), test.getFieldSnapshots());
for (TTestWarningThreshold threshold : test.getThresholds())
{
threshold.setTestId(test.getTestId());
@@ -357,6 +613,29 @@
return StringUtils.isEmpty(trimmed) ? null : trimmed;
}
+ private String normalizeCollectorChannel(String value)
+ {
+ String normalized = trimToNull(value);
+ if (normalized == null || !normalized.toUpperCase().matches("S-\\d+"))
+ throw new ServiceException("采集器通道必须使用S-01...S-N演示编码");
+ try
+ {
+ int channelNumber = Integer.parseInt(normalized.substring(2));
+ return String.format("S-%02d", channelNumber);
+ }
+ catch (NumberFormatException exception)
+ {
+ throw new ServiceException("采集器通道必须使用S-01...S-N演示编码");
+ }
+ }
+
+ /** 测量编码与数据库不区分大小写排序保持一致,避免校验通过后插入冲突。 */
+ 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