yeg
2026-09-08 942674ec8a3fd45986f1bf82d353d322bf416362
修复拼接来源详情与模板的独立冻结
1个文件已修改
35 ■■■■■ 已修改文件
battery-business/src/main/java/com/battery/business/report/SpliceReportService.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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;