From 04a0f85f968b874b1b43cf88f91993024a09d880 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期二, 08 九月 2026 17:59:18 +0800
Subject: [PATCH] 独立校验拼接来源详情并保留旧版人工内容

---
 battery-business/src/main/java/com/battery/business/report/SpliceReportService.java |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/battery-business/src/main/java/com/battery/business/report/SpliceReportService.java b/battery-business/src/main/java/com/battery/business/report/SpliceReportService.java
index 3a4dc4d..c1280a3 100644
--- a/battery-business/src/main/java/com/battery/business/report/SpliceReportService.java
+++ b/battery-business/src/main/java/com/battery/business/report/SpliceReportService.java
@@ -119,8 +119,10 @@
  @Transactional
  public Map<String,Object> create(SpliceReportRequest request, long uid, String user) {
   var settings = settings(request.settings(), true);
+  settings.putIfAbsent("sourceDetailOverrides", Map.of());
   Matrix matrix = freeze(preview(request.selections()), fields(settings));
   validateStatistics(settings, matrix.segments());
+  validateSourceDetails(settings, matrix.segments());
   Map<String,Object> snapshot = new LinkedHashMap<>();
   snapshot.put("spliceMode", "battery-segments");
   snapshot.put("name", request.name().trim()); snapshot.put("description", request.description());
@@ -146,6 +148,7 @@
   var snapshot = current(id, request.baseVersionNo());
   var settings = settings(request.settings(), false);
   validateStatistics(settings, segments(snapshot));
+  validateSourceDetails(settings, segments(snapshot));
   snapshot.put("name", request.name().trim()); snapshot.put("description", request.description()); snapshot.put("settings", settings);
   reports.append(id, request.baseVersionNo() + 1, request.name().trim(), snapshot.toJSONString(), uid, user, request.changeSummary().trim());
   return get(id, null);
@@ -158,7 +161,16 @@
   var snapshot = current(id, base);
   var selections = JSON.parseArray(snapshot.getString("selections"), SpliceReportRequest.Selection.class);
   var settings = settings(snapshot.getJSONObject("settings"), false);
+  // 主动更新才启用独立来源详情;旧版本读取和普通编辑不隐式迁移。
+  if (!settings.containsKey("sourceDetailOverrides")) {
+   // 旧版实验已按来源保存,可直接保留;旧字段人工值仍留在原报表字段,不按名称改绑共享身份。
+   Map<String,Object> details = new LinkedHashMap<>();
+   var experiments = JSON.parseObject(JSON.toJSONString(settings.getOrDefault("sourceExperimentNames", Map.of())));
+   experiments.forEach((key, value) -> details.put(key, Map.of("experimentName", value)));
+   settings.put("sourceDetailOverrides", details);
+  }
   Matrix matrix = freeze(preview(selections), fields(settings));
+  validateSourceDetails(settings, matrix.segments());
   // 人工值绑定原循环身份,刷新只清理已不存在的循环,不按新的拼接循环号迁移。
   var overrides = JSON.parseObject(JSON.toJSONString(settings.getOrDefault("statisticValues", Map.of())));
   overrides.keySet().retainAll(statisticKeys(matrix.segments()));
@@ -229,6 +241,29 @@
   return allowed;
  }
 
+ private void validateSourceDetails(Map<String,Object> settings, List<Map<String,Object>> segments) {
+  Object submitted = settings.get("sourceDetailOverrides");
+  if (submitted == null) return;
+  if (!(submitted instanceof Map<?,?> overrides)) throw new ServiceException("详情调整格式无效");
+  Set<String> sources = new HashSet<>();
+  for (var segment : segments) {
+   var source = JSON.parseObject(JSON.toJSONString(segment.get("source")), Candidate.class);
+   sources.add(source.selection().testId() + "|" + source.selection().testBatteryId());
+  }
+  // 详情按测试电池归属;名称与分类不解释为共享字段身份、单位或设备事实。
+  if (!sources.containsAll(overrides.keySet())) throw new ServiceException("详情调整不属于所选测试电池");
+  for (Object value : overrides.values()) {
+   if (!(value instanceof Map<?,?> override) || !Set.of("experimentName", "fieldValues").containsAll(override.keySet())) throw new ServiceException("详情调整无效");
+   if (override.containsKey("experimentName") && (!(override.get("experimentName") instanceof String name) || name.length() > 500)) throw new ServiceException("实验名称无效");
+   if (!override.containsKey("fieldValues")) continue;
+   if (!(override.get("fieldValues") instanceof Map<?,?> values)) throw new ServiceException("详情字段格式无效");
+   for (var entry : values.entrySet()) {
+    if (!(entry.getKey() instanceof String key) || !key.matches("(?:battery|special)\\|.{1,100}")
+        || !(entry.getValue() instanceof String text) || text.length() > 500) throw new ServiceException("详情字段名称或值无效");
+   }
+  }
+ }
+
  private void validateStatistics(Map<String,Object> settings, List<Map<String,Object>> segments) {
   Object submitted = settings.get("statisticValues");
   if (submitted == null) return;

--
Gitblit v1.7.1