| | |
| | | settings = stepSettings(settings, matrix.items(), false); |
| | | validateValues(settings, matrix.items()); validateChargeSelections(settings, matrix.items()); |
| | | var snapshot = new LinkedHashMap<String, Object>(); |
| | | snapshot.put("curveMode", "actual-steps"); |
| | | snapshot.put("name", request.name().trim()); snapshot.put("description", request.description()); |
| | | snapshot.put("items", matrix.items()); snapshot.put("cycleNos", matrix.cycleNos()); snapshot.put("settings", settings); |
| | | snapshot.put("units", Map.of("chargeCapacity", "Ah", "dischargeCapacity", "Ah", "chargeEnergy", "Wh", "dischargeEnergy", "Wh", "efficiency", "%", "energyEfficiency", "%")); |
| | |
| | | Set<String> allowed = valueKeys(settings.fields(), matrix.items()); |
| | | Map<String, String> values = new LinkedHashMap<>(); |
| | | settings.values().forEach((key, value) -> { if (allowed.contains(key)) values.put(key, value); }); |
| | | snapshot.put("items", matrix.items()); snapshot.put("cycleNos", matrix.cycleNos()); snapshot.put("settings", new Settings(validateFields(settings.fields(), false), values, |
| | | settings.chargeStepSelections() == null ? Map.of() : settings.chargeStepSelections(), settings.metrics(), settings.seriesColors(), settings.manualChargeSteps(), settings.curveStepSelections(), settings.hiddenSeriesKeys(), settings.activeCycle(), settings.sourceDetailOverrides())); |
| | | var refreshedSettings = new Settings(validateFields(settings.fields(), false), values, |
| | | settings.chargeStepSelections() == null ? Map.of() : settings.chargeStepSelections(), settings.metrics(), settings.seriesColors(), |
| | | settings.manualChargeSteps(), settings.curveStepSelections(), settings.hiddenSeriesKeys(), settings.activeCycle(), settings.sourceDetailOverrides()); |
| | | snapshot.put("curveMode", "actual-steps"); |
| | | snapshot.put("items", matrix.items()); snapshot.put("cycleNos", matrix.cycleNos()); |
| | | snapshot.put("settings", stepSettings(refreshedSettings, matrix.items(), true)); |
| | | curveUnits(snapshot); |
| | | reports.append(id, request.baseVersionNo() + 1, snapshot.getString("name"), json(snapshot), userId, userName, "按最新来源生成:" + request.changeSummary().trim()); |
| | | return get(id, null); |
| | |
| | | if (refresh) choice = new FormationReportRequest.StepSelection(choice.charge().stream().filter(chargeAllowed::contains).toList(), choice.discharge().stream().filter(dischargeAllowed::contains).toList()); |
| | | if (choice.charge() == null || choice.discharge() == null || !chargeAllowed.containsAll(choice.charge()) || !dischargeAllowed.containsAll(choice.discharge()) |
| | | || new HashSet<>(choice.charge()).size() != choice.charge().size() || new HashSet<>(choice.discharge()).size() != choice.discharge().size()) throw new ServiceException("曲线工步不属于当前测试电池、循环或充放电分组"); |
| | | if (choice.charge().stream().anyMatch(choice.discharge()::contains)) throw new ServiceException("同一实际工步不能同时指定为充电和放电"); |
| | | if (choice.charge().stream().anyMatch(choice.discharge()::contains) || requested.stream().anyMatch(choice.discharge()::contains)) |
| | | throw new ServiceException("同一实际工步不能同时指定为充电和放电"); |
| | | selected.put(key, choice); |
| | | } |
| | | if (!refresh && ((settings.manualChargeSteps() != null && !allowed.containsAll(settings.manualChargeSteps().keySet())) |
| | |
| | | // 早期版本未冻结工步时保持缺失,普通编辑不能重新读取设备事实。 |
| | | List<ChargeStep> choices = item.chargeSteps() == null ? List.of() : item.chargeSteps().getOrDefault(cycle, List.of()); |
| | | Integer selected = selections.get(key); |
| | | if (choices.stream().filter(step -> isReliableCharge(step.stepType())).count() == 1) { |
| | | int expected = choices.stream().filter(step -> isReliableCharge(step.stepType())).findFirst().get().stepNo(); |
| | | if (selected != null && selected != expected) throw new ServiceException("充电工步选择与实际工步不一致"); |
| | | } else if (!choices.isEmpty()) { |
| | | if (selected == null) throw new ServiceException("请为无法自动识别的充电工步完成选择"); |
| | | if (choices.stream().noneMatch(step -> step.stepNo() == selected)) throw new ServiceException("所选充电工步不属于当前测试、电池和循环"); |
| | | } |
| | | // 旧版保留冻结的单选事实,不用新增协议识别规则改判历史选择。 |
| | | if (selected != null && choices.stream().noneMatch(step -> step.stepNo() == selected)) |
| | | throw new ServiceException("所选充电工步不属于当前测试、电池和循环"); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | return result; |
| | | } |
| | | private boolean isReliableCharge(String type) { return directions.resolve(type) == Direction.CHARGE; } |
| | | private int number(Object value) { return value instanceof Number n ? n.intValue() : 0; } |
| | | private BigDecimal decimal(Object value) { return value instanceof Number n ? new BigDecimal(n.toString()) : null; } |
| | | |