feat(calculator): 营养计算结果返回校验规则集(test-0415 反馈2-1)
- NutritionCalculateResponse 新增 validations: List<ValidationRule>
- ValidationRule = { name, value, targetRange, status, reference }
- 当前覆盖 4 条核心规则:
· BMI(WS/T 428-2013)
· eGFR(KDIGO 2012 CKD 评估指南)
· 蛋白质摄入量(KDOQI 2020,按是否透析切换 0.6-0.8 / 1.0-1.2 g/kg)
· 能量摄入量(KDOQI 2020,30-35 kcal/kg)
- status: normal / below / above / unknown,前端可在结果页给徽标提示
- 用户/医生可据此核对推荐数值是否落在临床指南区间内
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,9 @@ public class NutritionCalculateResponse implements Serializable {
|
||||
@ApiModelProperty(value = "重要提示列表")
|
||||
private List<String> importantTips;
|
||||
|
||||
@ApiModelProperty(value = "校验规则集(test-0415 反馈2-1):暴露推荐计算所依据的临床指南范围,方便用户与医生核验")
|
||||
private List<ValidationRule> validations;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@@ -120,6 +123,31 @@ public class NutritionCalculateResponse implements Serializable {
|
||||
private List<Dish> dinner;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验规则项(test-0415 反馈2-1)
|
||||
* 让用户/医生可以一眼看出每个推荐数值落在哪个临床指南区间,是否「在范围内 / 偏低 / 偏高」
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(description = "校验规则项")
|
||||
public static class ValidationRule implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "指标名称", example = "蛋白质摄入量")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "当前推荐值", example = "0.8 g/kg")
|
||||
private String value;
|
||||
|
||||
@ApiModelProperty(value = "目标范围", example = "0.6-0.8 g/kg")
|
||||
private String targetRange;
|
||||
|
||||
@ApiModelProperty(value = "状态:normal / below / above / unknown", example = "normal")
|
||||
private String status;
|
||||
|
||||
@ApiModelProperty(value = "参考依据", example = "KDOQI 2020 营养指南")
|
||||
private String reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜品信息
|
||||
*/
|
||||
|
||||
@@ -644,10 +644,83 @@ public class ToolCalculatorServiceImpl extends ServiceImpl<V2CalculatorResultDao
|
||||
// 重要提示
|
||||
response.setImportantTips(importantTips);
|
||||
|
||||
// test-0415 反馈2-1:校验规则集——暴露每项推荐数值的临床指南范围与依据
|
||||
response.setValidations(buildValidationRules(entity));
|
||||
|
||||
// 创建时间
|
||||
response.setCreatedAt(entity.getCreatedAt());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建校验规则集
|
||||
* 让用户/医生可以在结果页直接核对推荐数值与临床指南的对应关系
|
||||
*/
|
||||
private List<NutritionCalculateResponse.ValidationRule> buildValidationRules(V2CalculatorResult e) {
|
||||
List<NutritionCalculateResponse.ValidationRule> list = new ArrayList<>();
|
||||
|
||||
// 1) BMI:18.5–23.9 为正常(中国成人)
|
||||
list.add(rule("BMI",
|
||||
e.getBmi().toString(),
|
||||
"18.5-23.9",
|
||||
bmiStatus(e.getBmi()),
|
||||
"中国成人 BMI 分类标准(WS/T 428-2013)"));
|
||||
|
||||
// 2) eGFR:CKD 分期参考 KDIGO 2012
|
||||
list.add(rule("eGFR",
|
||||
e.getEgfr().toString() + " ml/min/1.73m²",
|
||||
">90 (G1) / 60-89 (G2) / 30-59 (G3) / 15-29 (G4) / <15 (G5)",
|
||||
"normal", // eGFR 本身不存在「越界」概念,由分期解释
|
||||
"KDIGO 2012 CKD 评估和管理临床实践指南"));
|
||||
|
||||
// 3) 蛋白质摄入量:根据是否透析与 CKD 分期
|
||||
BigDecimal proteinPerKg = e.getProteinIntake().divide(e.getStandardWeight(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
boolean isDialysis = e.getHasDialysis() != null && e.getHasDialysis() == 1;
|
||||
String pTarget = isDialysis ? "1.0-1.2 g/kg" : "0.6-0.8 g/kg";
|
||||
BigDecimal pMin = isDialysis ? new BigDecimal("1.0") : new BigDecimal("0.6");
|
||||
BigDecimal pMax = isDialysis ? new BigDecimal("1.2") : new BigDecimal("0.8");
|
||||
list.add(rule("蛋白质摄入量",
|
||||
proteinPerKg + " g/kg(共 " + e.getProteinIntake() + " g)",
|
||||
pTarget,
|
||||
rangeStatus(proteinPerKg, pMin, pMax),
|
||||
isDialysis ? "KDOQI 2020 透析患者营养指南" : "KDOQI 2020 非透析 CKD 营养指南"));
|
||||
|
||||
// 4) 能量摄入量:30-35 kcal/kg/day
|
||||
BigDecimal energyPerKg = new BigDecimal(e.getEnergyIntake())
|
||||
.divide(e.getStandardWeight(), 2, BigDecimal.ROUND_HALF_UP);
|
||||
list.add(rule("能量摄入量",
|
||||
energyPerKg + " kcal/kg(共 " + e.getEnergyIntake() + " kcal)",
|
||||
"30-35 kcal/kg",
|
||||
rangeStatus(energyPerKg, new BigDecimal("30"), new BigDecimal("35")),
|
||||
"KDOQI 2020 营养指南"));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private NutritionCalculateResponse.ValidationRule rule(String name, String value, String targetRange,
|
||||
String status, String reference) {
|
||||
NutritionCalculateResponse.ValidationRule r = new NutritionCalculateResponse.ValidationRule();
|
||||
r.setName(name);
|
||||
r.setValue(value);
|
||||
r.setTargetRange(targetRange);
|
||||
r.setStatus(status);
|
||||
r.setReference(reference);
|
||||
return r;
|
||||
}
|
||||
|
||||
private String bmiStatus(BigDecimal bmi) {
|
||||
if (bmi == null) return "unknown";
|
||||
if (bmi.compareTo(new BigDecimal("18.5")) < 0) return "below";
|
||||
if (bmi.compareTo(new BigDecimal("23.9")) > 0) return "above";
|
||||
return "normal";
|
||||
}
|
||||
|
||||
private String rangeStatus(BigDecimal value, BigDecimal min, BigDecimal max) {
|
||||
if (value == null) return "unknown";
|
||||
if (value.compareTo(min) < 0) return "below";
|
||||
if (value.compareTo(max) > 0) return "above";
|
||||
return "normal";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user