Переглянути джерело

修改 营养设定计算 膳食治疗

HuRongxin 2 місяців тому
батько
коміт
2f27f19249

+ 1 - 2
ruoyi-admin/src/main/java/org/dromara/web/controller/NutritionSettingController.java

@@ -111,7 +111,6 @@ public class NutritionSettingController extends BaseController {
      */
     @PostMapping("/recalculate")
     public Map<String, String> recalculate(@Validated(EditGroup.class) @RequestBody RecalculateBo bo) {
-        Integer age = Integer.valueOf(bo.getAge().substring(0,2));
-        return nutritionSettingService.calculateEnergyRequirements(bo.getGender(), age, bo.getHeight().doubleValue(), bo.getWeight().doubleValue(), bo.getActivity(), bo.getStressType());
+        return nutritionSettingService.calculateEnergyRequirements(bo.getSettingType(),bo.getGender(), bo.getAge(), bo.getHeight().doubleValue(), bo.getWeight().doubleValue(), bo.getActivity(), bo.getStressType(),bo.getBurnArea());
     }
 }

+ 4 - 0
ruoyi-admin/src/main/java/org/dromara/web/domain/HospitalMealPlan.java

@@ -4,6 +4,8 @@ import org.dromara.common.tenant.core.TenantEntity;
 import com.baomidou.mybatisplus.annotation.*;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 
@@ -64,6 +66,8 @@ public class HospitalMealPlan extends TenantEntity {
      */
     private String status;
 
+    private BigDecimal totalPrice;
+
     /**
      * 备注
      */

+ 3 - 0
ruoyi-admin/src/main/java/org/dromara/web/domain/TreatmentUser.java

@@ -77,6 +77,9 @@ public class TreatmentUser extends BaseEntity {
      */
     private String age;
 
+    /*床号*/
+    private String bedNo;
+
     /**
      * 身高
      */

+ 3 - 0
ruoyi-admin/src/main/java/org/dromara/web/domain/bo/HospitalMealPlanBo.java

@@ -11,6 +11,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.web.domain.HospitalMealPlan;
 import org.dromara.web.domain.HospitalMealRecipe;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 
@@ -72,6 +73,8 @@ public class HospitalMealPlanBo extends BaseEntity {
      */
     private String remark;
 
+    private BigDecimal totalPrice;
+
     private List<Date> dateRange;
 
     @NotEmpty(message = "日常膳食明细不能为空", groups = {AddGroup.class, EditGroup.class})

+ 4 - 0
ruoyi-admin/src/main/java/org/dromara/web/domain/bo/RecalculateBo.java

@@ -8,6 +8,10 @@ import java.math.BigDecimal;
 @Data
 public class RecalculateBo implements Serializable {
 
+    /*设定方式*/
+
+    private Integer settingType;
+
     /**
      * 身高
      */

+ 4 - 0
ruoyi-admin/src/main/java/org/dromara/web/domain/vo/DailyMealPlanVo.java

@@ -5,11 +5,13 @@ import cn.idev.excel.annotation.ExcelProperty;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 import org.dromara.web.domain.DailyMealPlan;
+import org.dromara.web.domain.DailyMealRecipe;
 import org.dromara.web.domain.HospitalMealPlan;
 
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
+import java.util.List;
 
 
 /**
@@ -86,5 +88,7 @@ public class DailyMealPlanVo implements Serializable {
 
     private String createByUser;
 
+    private List<DailyMealRecipeVo> mealRecipeList;
+
 
 }

+ 8 - 1
ruoyi-admin/src/main/java/org/dromara/web/domain/vo/HospitalMealPlanVo.java

@@ -1,5 +1,6 @@
 package org.dromara.web.domain.vo;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
@@ -8,11 +9,13 @@ import cn.idev.excel.annotation.ExcelProperty;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 import org.dromara.web.domain.HospitalMealPlan;
+import org.dromara.web.domain.HospitalMealRecipe;
+import org.dromara.web.domain.bo.HospitalMealRecipeBo;
 
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
-
+import java.util.List;
 
 
 /**
@@ -83,11 +86,15 @@ public class HospitalMealPlanVo implements Serializable {
     @ExcelProperty(value = "备注")
     private String remark;
 
+    private BigDecimal totalPrice;
+
     private Date createTime;
 
     private Long createBy;
 
     private String createByUser;
 
+    private List<HospitalMealRecipeVo> mealRecipeList;
+
 
 }

+ 4 - 3
ruoyi-admin/src/main/java/org/dromara/web/service/INutritionSettingService.java

@@ -6,6 +6,7 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.web.domain.bo.NutritionSettingBo;
 import org.dromara.web.domain.vo.NutritionSettingVo;
 
+import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -68,7 +69,7 @@ public interface INutritionSettingService {
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
-    Map<String, String> calculateEnergyRequirements(
-        String gender, int age, double height, double weight,
-        Integer activityLevel, Integer stressLevel);
+    Map<String, String> calculateEnergyRequirements(Integer settingType,
+                                                    String gender, String age, double height, double weight,
+                                                    Integer activityLevel, Integer stressLevel, BigDecimal burnArea);
 }

+ 160 - 0
ruoyi-admin/src/main/java/org/dromara/web/service/MetabolicCalculator.java

@@ -0,0 +1,160 @@
+package org.dromara.web.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MetabolicCalculator {
+
+    // 工具方法:活动系数转换
+    private static double getActivityFactor(String activityLevel) {
+        return switch (activityLevel) {
+            case "轻" -> 1.375;
+            case "中" -> 1.55;
+            case "重" -> 1.725;
+            default -> 1.2; // 默认静态
+        };
+    }
+
+    // 工具方法:格式化结果
+    private static Map<String, String> formatResults(double tdeeKcal, double weight) {
+        double tdeeKj = tdeeKcal * 4.184;
+        double kcalPerKg = tdeeKcal / weight;
+
+        Map<String, String> results = new HashMap<>();
+        results.put("kcal/d", String.format("%.2f", tdeeKcal));
+        results.put("kJ/d", String.format("%.2f", tdeeKj));
+        results.put("kcal/kg*d", String.format("%.2f", kcalPerKg));
+        return results;
+    }
+
+    /************************ BEE 计算方法 ************************/
+    public static Map<String, String> calculateByBEE(
+        String gender, int age, double height, double weight,
+        String activityLevel, String stressLevel) {
+
+        // 毛德倩公式(中国人群)
+        double bee;
+        if ("男".equals(gender)) {
+            bee = 48.5 * weight + 2954.7;
+        } else {
+            bee = 41.9 * weight + 2869.1;
+        }
+
+        double activityFactor = getActivityFactor(activityLevel);
+
+        // 应激系数转换
+        double stressFactor = switch (stressLevel) {
+            case "低级" -> 1.1;
+            case "中级" -> 1.2;
+            case "严重" -> 1.3;
+            case "恶性肿瘤" -> 1.4;
+            default -> 1.0; // 基础状态
+        };
+
+        double tdeeKcal = bee * activityFactor * stressFactor;
+        return formatResults(tdeeKcal, weight);
+    }
+
+    /************************ DRIS 计算方法 ************************/
+    public static Map<String, String> calculateByDRIS(
+        String gender, int age, double height, double weight,
+        String activityLevel) {
+
+        // 根据年龄和性别确定基础代谢系数
+        double baseFactor;
+        if (age < 30) {
+            baseFactor = "男".equals(gender) ? 38.5 : 35.0;
+        } else if (age < 50) {
+            baseFactor = "男".equals(gender) ? 36.0 : 33.0;
+        } else {
+            baseFactor = "男".equals(gender) ? 34.0 : 30.5;
+        }
+
+        // 根据活动强度调整
+        double activityBonus = switch (activityLevel) {
+            case "低" -> 1.0;
+            case "中" -> 3.5;
+            case "重" -> 7.0;
+            default -> 0; // 静态
+        };
+
+        double kcalPerKg = baseFactor + activityBonus;
+        double tdeeKcal = weight * kcalPerKg;
+
+        return formatResults(tdeeKcal, weight);
+    }
+
+    /************************ 拇指测法 ************************/
+    public static Map<String, String> calculateByThumb(
+        String gender, int age, double height, double weight,
+        String activityLevel) {
+
+        // 根据活动水平确定系数范围
+        double minFactor, maxFactor;
+        switch (activityLevel) {
+            case "轻" -> { minFactor = 25; maxFactor = 30; }
+            case "中" -> { minFactor = 30; maxFactor = 35; }
+            case "重" -> { minFactor = 35; maxFactor = 40; }
+            default -> { minFactor = 20; maxFactor = 25; }  // 静态
+        }
+
+        // 在范围内取中间值
+        double factor = (minFactor + maxFactor) / 2.0;
+
+        // 性别调整(男性通常略高)
+        if ("男".equals(gender)) factor *= 1.05;
+
+        // 年龄调整(30岁以下代谢较高)
+        if (age < 30) factor *= 1.08;
+
+        double tdeeKcal = weight * factor;
+
+        return formatResults(tdeeKcal, weight);
+    }
+
+    /************************ 烧伤公式 ************************/
+    public static Map<String, String> calculateByBurnFormula(
+        String gender, int age, double height, double weight,
+        String activityLevel, double burnAreaPercent) {
+
+        // 基于Harris-Benedict公式计算基础代谢
+        double bee;
+        if ("男".equals(gender)) {
+            bee = 66.5 + (13.75 * weight) + (5.003 * height) - (6.775 * age);
+        } else {
+            bee = 655.1 + (9.563 * weight) + (1.850 * height) - (4.676 * age);
+        }
+
+        // 活动系数
+        double activityFactor = getActivityFactor(activityLevel);
+
+        // Curreri公式:基础代谢 + 烧伤增量
+        double burnCalories = 40 * burnAreaPercent;
+        double tdeeKcal = (bee + burnCalories) * activityFactor;
+
+        return formatResults(tdeeKcal, weight);
+    }
+
+    /************************ 测试方法 ************************/
+    public static void main(String[] args) {
+        // BEE测试用例: 35岁男性,175cm,70kg,中度活动,低级应激
+        System.out.println("BEE计算方法:");
+        Map<String, String> beeResult = calculateByBEE("男", 35, 175, 70, "中", "低级");
+        beeResult.forEach((k, v) -> System.out.println(k + ": " + v));
+
+        // DRIS测试用例: 30岁女性,165cm,60kg,中度活动
+        System.out.println("\nDRIS计算方法:");
+        Map<String, String> drisResult = calculateByDRIS("女", 30, 165, 60, "中");
+        drisResult.forEach((k, v) -> System.out.println(k + ": " + v));
+
+        // 拇指测法测试用例: 25岁男性,180cm,80kg,重度活动
+        System.out.println("\n拇指测法:");
+        Map<String, String> thumbResult = calculateByThumb("男", 25, 180, 80, "重");
+        thumbResult.forEach((k, v) -> System.out.println(k + ": " + v));
+
+        // 烧伤公式测试用例: 40岁女性,160cm,55kg,轻度活动,烧伤面积30%
+        System.out.println("\n烧伤公式:");
+        Map<String, String> burnResult = calculateByBurnFormula("女", 40, 160, 55, "轻", 30.0);
+        burnResult.forEach((k, v) -> System.out.println(k + ": " + v));
+    }
+}

+ 14 - 5
ruoyi-admin/src/main/java/org/dromara/web/service/impl/DailyMealPlanServiceImpl.java

@@ -1,6 +1,7 @@
 package org.dromara.web.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -14,8 +15,12 @@ import org.dromara.system.domain.SysUser;
 import org.dromara.system.mapper.SysUserMapper;
 import org.dromara.web.domain.DailyMealPlan;
 import org.dromara.web.domain.DailyMealRecipe;
+import org.dromara.web.domain.HospitalMealRecipe;
 import org.dromara.web.domain.bo.DailyMealPlanBo;
 import org.dromara.web.domain.vo.DailyMealPlanVo;
+import org.dromara.web.domain.vo.DailyMealRecipeVo;
+import org.dromara.web.domain.vo.HospitalMealPlanVo;
+import org.dromara.web.domain.vo.HospitalMealRecipeVo;
 import org.dromara.web.mapper.DailyMealPlanMapper;
 import org.dromara.web.mapper.DailyMealRecipeMapper;
 import org.dromara.web.service.IDailyMealPlanService;
@@ -53,7 +58,12 @@ public class DailyMealPlanServiceImpl implements IDailyMealPlanService {
      */
     @Override
     public DailyMealPlanVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
+        DailyMealPlanVo dailyMealPlanVo = baseMapper.selectVoById(id);
+        if (ObjUtil.isNotNull(dailyMealPlanVo)) {
+            List<DailyMealRecipeVo> voList = mealRecipeMapper.selectVoList(Wrappers.lambdaQuery(DailyMealRecipe.class).eq(DailyMealRecipe::getPlanId, dailyMealPlanVo.getId()));
+            dailyMealPlanVo.setMealRecipeList(voList);
+        }
+        return dailyMealPlanVo;
     }
 
     /**
@@ -70,10 +80,9 @@ public class DailyMealPlanServiceImpl implements IDailyMealPlanService {
         LambdaQueryWrapper<DailyMealPlan> lqw = buildQueryWrapper(bo);
         Page<DailyMealPlanVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
         List<DailyMealPlanVo> records = result.getRecords();
-        if (CollUtil.isNotEmpty(records))
-            for (DailyMealPlanVo record : records) {
-                record.setCreateByUser(userMap.get(record.getCreateBy()));
-            }
+        if (CollUtil.isNotEmpty(records)) for (DailyMealPlanVo record : records) {
+            record.setCreateByUser(userMap.get(record.getCreateBy()));
+        }
         return TableDataInfo.build(result);
     }
 

+ 10 - 1
ruoyi-admin/src/main/java/org/dromara/web/service/impl/HospitalMealPlanServiceImpl.java

@@ -13,7 +13,9 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.system.domain.SysRecipeFoodIngredient;
+import org.dromara.system.domain.SysScreeningAssessmentQuestion;
 import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysScreeningAssessmentQuestionVo;
 import org.dromara.system.mapper.SysUserMapper;
 import org.dromara.web.domain.HospitalMealPlan;
 import org.dromara.web.domain.HospitalMealRecipe;
@@ -21,6 +23,7 @@ import org.dromara.web.domain.NutritionSetting;
 import org.dromara.web.domain.bo.HospitalMealPlanBo;
 import org.dromara.web.domain.bo.HospitalMealRecipeBo;
 import org.dromara.web.domain.vo.HospitalMealPlanVo;
+import org.dromara.web.domain.vo.HospitalMealRecipeVo;
 import org.dromara.web.domain.vo.NutritionSettingVo;
 import org.dromara.web.mapper.HospitalMealPlanMapper;
 import org.dromara.web.mapper.HospitalMealRecipeMapper;
@@ -60,7 +63,13 @@ public class HospitalMealPlanServiceImpl implements IHospitalMealPlanService {
      */
     @Override
     public HospitalMealPlanVo queryById(Long id) {
-        return baseMapper.selectVoById(id);
+        HospitalMealPlanVo hospitalMealPlanVo = baseMapper.selectVoById(id);
+        if (ObjUtil.isNotNull(hospitalMealPlanVo)) {
+            List<HospitalMealRecipeVo> voList = mealRecipeMapper.selectVoList(Wrappers.lambdaQuery(HospitalMealRecipe.class)
+                .eq(HospitalMealRecipe::getPlanId, hospitalMealPlanVo.getId()));
+            hospitalMealPlanVo.setMealRecipeList(voList);
+        }
+        return hospitalMealPlanVo;
     }
 
     /**

+ 48 - 39
ruoyi-admin/src/main/java/org/dromara/web/service/impl/NutritionSettingServiceImpl.java

@@ -20,9 +20,11 @@ import org.dromara.web.domain.bo.NutritionSettingBo;
 import org.dromara.web.domain.vo.NutritionSettingVo;
 import org.dromara.web.mapper.NutritionSettingMapper;
 import org.dromara.web.service.INutritionSettingService;
+import org.dromara.web.service.MetabolicCalculator;
 import org.dromara.web.service.NutritionDataUtil;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -169,9 +171,16 @@ public class NutritionSettingServiceImpl implements INutritionSettingService {
         return baseMapper.deleteByIds(ids) > 0;
     }
 
-    public Map<String, String> calculateEnergyRequirements(
-        String gender, int age, double height, double weight,
-        Integer activity, Integer stressType) {
+    public Map<String, String> calculateEnergyRequirements(Integer settingType,
+                                                           String gender, String ageStr, double height, double weight,
+                                                           Integer activity, Integer stressType, BigDecimal burnArea) {
+        Map<String, String> settingTypeMap = Optional.ofNullable(dictDataService.selectMapByType("nutrition_setting_type").getData())
+            .orElseGet(MapUtil::newHashMap)
+            .entrySet().stream()
+            .collect(Collectors.toMap(
+                Map.Entry::getKey,
+                entry -> entry.getValue().getDictLabel()
+            ));
 
         Map<String, String> activityMap = Optional.ofNullable(dictDataService.selectMapByType("physical_activity").getData())
             .orElseGet(MapUtil::newHashMap)
@@ -191,6 +200,11 @@ public class NutritionSettingServiceImpl implements INutritionSettingService {
             ));
         String activityLevel = null;
         String stressLevel = null;
+        Integer age = null;
+        if (null != ageStr) {
+            age = Integer.valueOf(ageStr.substring(0, 2));
+
+        }
         if (null != activity) {
             activityLevel = activityMap.get(Integer.toString(activity));
         }
@@ -199,67 +213,63 @@ public class NutritionSettingServiceImpl implements INutritionSettingService {
 
         }
 
-        Map<String, String> results = new HashMap<>();
-
-        // 1. 计算基础代谢率 (BEE) - 使用毛德倩公式
-        double bee;
-        if ("男".equals(gender)) {
-            bee = 48.5 * weight + 2954.7;
-        } else {
-            bee = 41.9 * weight + 2869.1;
-        }
-
-        // 2. 活动系数转换
-        double activityFactor = 1.2; // 默认静态
         if (null != activityLevel) {
             if (activityLevel.contains("低")) {
-                activityFactor = 1.375;
+                activityLevel = "低";
             } else if (activityLevel.contains("中")) {
-                activityFactor = 1.55;
+                activityLevel = "中";
             } else if (activityLevel.contains("重")) {
-                activityFactor = 1.725;
+                activityLevel = "重";
             }
         }
 
         // 3. 应激系数转换
-        double stressFactor = 1.0; // 默认基础状态
         if (null != stressLevel) {
-            if (stressLevel.contains("低")) {
-                stressFactor = 1.1;
-            } else if (stressLevel.contains("中")) {
-                stressFactor = 1.2;
+            if (stressLevel.contains("低")) {
+                stressLevel = "低级";
+            } else if (stressLevel.contains("中")) {
+                stressLevel = "中级";
             } else if (stressLevel.contains("严重")) {
-                stressFactor = 1.3;
+                stressLevel = "严重";
             } else if (stressLevel.contains("恶性")) {
-                stressFactor = 1.4;
+                stressLevel = "恶性肿瘤";
             }
         }
 
-        // 4. 计算总热量需求 (TDEE)
-        double tdeeKcal = bee * activityFactor * stressFactor;
-        double tdeeKj = tdeeKcal * 4.184; // 1 kcal = 4.184 kJ
-        double kcalPerKg = tdeeKcal / weight;
+        Map<String, String> map = null;
+        if ("BEE".equals(settingTypeMap.get(Integer.toString(settingType)))) {
+            map = MetabolicCalculator.calculateByBEE(gender, age, height, weight, activityLevel, stressLevel);
+        } else if ("DRIS".equals(settingTypeMap.get(Integer.toString(settingType)))) {
+            map = MetabolicCalculator.calculateByDRIS(gender, age, height, weight, activityLevel);
+        } else if ("拇指测法".equals(settingTypeMap.get(Integer.toString(settingType)))) {
+            map = MetabolicCalculator.calculateByThumb(gender, age, height, weight, activityLevel);
+        } else if ("烧伤公式".equals(settingTypeMap.get(Integer.toString(settingType)))) {
+            map = MetabolicCalculator.calculateByBurnFormula(gender, age, height, age, activityLevel, burnArea.doubleValue());
+        }
+
+        Map<String, String> results = new HashMap<>();
+
 
         double proteinCaloriePercentage = 20;
         double fatCaloriePercentage = 20;
         double carbohydrateCaloriePercentage = 50;
 
         // 5. 设置计算结果
-        results.put("caloriesKcalPerDay", String.format("%.2f", tdeeKcal));
-        results.put("caloriesKjPerDay", String.format("%.2f", tdeeKj));
-        results.put("caloriesKcalPerKgDay", String.format("%.2f", kcalPerKg));
+        results.put("caloriesKcalPerDay", map.get("kcal/d"));
+        results.put("caloriesKjPerDay", map.get("kJ/d"));
+        results.put("caloriesKcalPerKgDay", map.get("kcal/kg*d"));
 
         results.put("proteinCaloriePercentage", String.format("%.2f", proteinCaloriePercentage));//蛋白质热量占比
-        results.put("proteinGPerKgDay", String.format("%.2f", tdeeKj));
-        results.put("proteinGPerDay", String.format("%.2f", kcalPerKg));
+        results.put("proteinGPerKgDay", map.get("kcal/d"));
+        results.put("proteinGPerDay", map.get("kJ/d"));
 
         results.put("fatCaloriePercentage", String.format("%.2f", fatCaloriePercentage));//脂肪热量占比
-        results.put("fatGPerKgDay", String.format("%.2f", kcalPerKg));
-        results.put("fatGPerDay", String.format("%.2f", tdeeKj));
+        results.put("fatGPerKgDay", map.get("kJ/d"));
+        results.put("fatGPerDay", map.get("kcal/d"));
 
         results.put("carbohydrateCaloriePercentage", String.format("%.2f", carbohydrateCaloriePercentage));//碳水化合物占比
-        results.put("carbohydrateGPerKgDay", String.format("%.2f", kcalPerKg));
-        results.put("carbohydrateGPerDay", String.format("%.2f", tdeeKj));
+        results.put("carbohydrateGPerKgDay", map.get("kcal/d"));
+        results.put("carbohydrateGPerDay", map.get("kJ/d"));
 
         results.put("calcium", NutritionDataUtil.getValueByAge("钙", null, age));
         results.put("potassium", NutritionDataUtil.getValueByAge("钾", null, age));
@@ -292,7 +302,6 @@ public class NutritionSettingServiceImpl implements INutritionSettingService {
         results.put("pantothenicAcid", NutritionDataUtil.getValueByAge("泛酸", null, age));
         results.put("dietaryFiber", NutritionDataUtil.getValueByAge("膳食纤维", null, age));
 
-
         return results;
     }
 }