| | |
| | | validateSettings(request.settings()); |
| | | List<Item> items = preview(request.selections()).stream().map(item -> new Item(item.source(), item.zeroTime(), item.records(), item.logicalMapping(), |
| | | item.businessFields().stream().filter(field -> selectedBusinessField(field, request.settings())).toList())).toList(); |
| | | validateSourceOverrides(request.settings(), items); |
| | | Map<String, Object> snapshot = new LinkedHashMap<>(); |
| | | snapshot.put("name", request.name().trim()); snapshot.put("description", request.description()); |
| | | snapshot.put("experimentName", request.experimentName()); snapshot.put("items", items); snapshot.put("settings", snapshotSettings(request.settings())); |
| | | snapshot.put("experimentName", request.experimentName()); snapshot.put("items", items); |
| | | var settings = snapshotSettings(request.settings()); |
| | | settings.putIfAbsent("sourceDetailOverrides", Map.of()); |
| | | snapshot.put("settings", settings); |
| | | snapshot.put("units", Map.of("voltage", "V", "current", "A", "temperature", "℃", "positiveVoltage", "V", "negativeVoltage", "V", "capacity", "Ah", "energy", "Wh")); |
| | | snapshot.put("displayUnits", Map.of("voltage", "V", "current", "mA", "temperature", "℃", "positiveVoltage", "V", "negativeVoltage", "V", "capacity", "mAh", "energy", "mWh")); |
| | | snapshot.put("timeUnit", "epoch-milliseconds"); |
| | |
| | | { |
| | | var snapshot = currentSnapshot(id, request.baseVersionNo()); |
| | | validateSettings(request.settings()); |
| | | validateSourceOverrides(request.settings(), JSON.parseArray(JSON.toJSONString(snapshot.get("items")), Item.class)); |
| | | snapshot.put("name", request.name().trim()); snapshot.put("description", request.description()); |
| | | snapshot.put("experimentName", request.experimentName()); snapshot.put("settings", snapshotSettings(request.settings())); |
| | | reports.append(id, request.baseVersionNo() + 1, request.name().trim(), JSON.toJSONString(snapshot, JSONWriter.Feature.WriteMapNullValue), |
| | |
| | | .map(item -> new Item(item.source(), item.zeroTime(), item.records(), item.logicalMapping(), |
| | | item.businessFields().stream().filter(field -> selectedBusinessField(field, settings)).toList())).toList(); |
| | | snapshot.put("items", updated); |
| | | // 旧版仅在明确更新来源时取得新详情;原有按范围保存的人工值不迁移或合并。 |
| | | snapshot.getJSONObject("settings").putIfAbsent("sourceDetailOverrides", Map.of()); |
| | | reports.append(id, request.baseVersionNo() + 1, snapshot.getString("name"), JSON.toJSONString(snapshot, JSONWriter.Feature.WriteMapNullValue), |
| | | operatorId, operatorName, "按最新来源生成:" + request.changeSummary().trim()); |
| | | return get(id); |
| | |
| | | result.put("detailFieldValues", settings.detailFieldValues()); |
| | | // 独立复制结构而非保存模板引用,重开、编辑与打印均不重新读取模板或共享定义。 |
| | | if (settings.fieldStructure() != null) result.put("fieldStructure", settings.fieldStructure()); |
| | | if (settings.sourceDetailOverrides() != null) result.put("sourceDetailOverrides", settings.sourceDetailOverrides()); |
| | | return result; |
| | | } |
| | | |
| | | private void validateSourceOverrides(CompareReportRequest.Settings settings, List<Item> items) |
| | | { |
| | | if (settings.sourceDetailOverrides() == null) return; |
| | | Set<String> identities = new HashSet<>(); |
| | | for (var item : items) identities.add(item.source().selection().testId() + "|" + item.source().selection().testBatteryId()); |
| | | for (var entry : settings.sourceDetailOverrides().entrySet()) |
| | | { |
| | | // 报表人工值只能归入已冻结的来源电池,不接受电池号或列位置作为身份。 |
| | | if (!identities.contains(entry.getKey()) || entry.getValue() == null) |
| | | throw new ServiceException("测试详情来源不属于当前报表"); |
| | | var fields = entry.getValue().fieldValues(); |
| | | if (fields != null && fields.entrySet().stream().anyMatch(field -> field.getKey() == null |
| | | || !field.getKey().matches("(?:battery|special)\\|.{1,100}") || field.getValue() == null || field.getValue().length() > 500)) |
| | | throw new ServiceException("测试详情字段或填写值无效"); |
| | | } |
| | | } |
| | | |
| | | private List<Candidate> candidates(TTest test, List<Map<String, Object>> records) |
| | |
| | | { |
| | | return new Candidate(new Selection(test.getTestId(), battery.getTestBatteryId(), cycle, step, logical), |
| | | test.getTestName(), test.getTestTypeName(), battery.getGroupId(), battery.getGroupName(), battery.getBatteryNo(), process, |
| | | test.getConsoleDetail() == null ? null : test.getConsoleDetail().getExperimentName(), test.getConsoleDetail()); |
| | | test.getConsoleDetail() == null ? null : test.getConsoleDetail().getExperimentName(), selectedConsoleDetail(test, battery)); |
| | | } |
| | | |
| | | private TTestConsoleDetail selectedConsoleDetail(TTest test, TTestBattery battery) |
| | | { |
| | | var original = test.getConsoleDetail(); |
| | | if (original == null) return null; |
| | | var detail = new TTestConsoleDetail(); |
| | | detail.setExperimentName(original.getExperimentName()); |
| | | detail.setBatteryFields(original.getBatteryFields()); |
| | | detail.setSpecialFields(original.getSpecialFields()); |
| | | // 快照只冻结所选电池的已保存字符串;不带入其他电池,也不由当前电池组值补缺。 |
| | | original.getFieldValues().forEach((field, values) -> { |
| | | if (values.containsKey(battery.getBatteryNo())) |
| | | { |
| | | var selected = new LinkedHashMap<String, String>(); |
| | | selected.put(battery.getBatteryNo(), values.get(battery.getBatteryNo())); |
| | | detail.getFieldValues().put(field, selected); |
| | | } |
| | | }); |
| | | return detail; |
| | | } |
| | | |
| | | private int number(Map<String, Object> row, String key) { return row.get(key) instanceof Number value ? value.intValue() : 0; } |