|
|
@@ -237,6 +237,315 @@ public class BeijingNutritionService {
|
|
|
return list;
|
|
|
}
|
|
|
|
|
|
+ // ============================================================
|
|
|
+ // 菌群功能分析引擎
|
|
|
+ // ============================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分析菌群报告,给出功能维度聚合、饮食模式推断、风险提示等额外分析结论
|
|
|
+ *
|
|
|
+ * @param reportId 菌群报告ID
|
|
|
+ * @return 分析结果
|
|
|
+ */
|
|
|
+ public Map<String, Object> analyzeGutFlora(Long reportId) {
|
|
|
+ Map<String, Object> result = new LinkedHashMap<>();
|
|
|
+
|
|
|
+ // 1. 获取报告菌群数据
|
|
|
+ List<HealthGutFlora> floraList = healthGutFloraMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<HealthGutFlora>()
|
|
|
+ .eq(HealthGutFlora::getReportId, reportId)
|
|
|
+ );
|
|
|
+ if (floraList.isEmpty()) {
|
|
|
+ result.put("error", "该报告无菌群数据");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建菌名→状态映射
|
|
|
+ Map<String, HealthGutFlora> floraByName = new HashMap<>();
|
|
|
+ for (HealthGutFlora f : floraList) {
|
|
|
+ if (f.getBacteriaName() != null) {
|
|
|
+ floraByName.put(f.getBacteriaName().toLowerCase(), f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 功能维度聚合
|
|
|
+ // 功能分类定义:菌名(小写) → 功能分类
|
|
|
+ Map<String, String> funcClassMap = new HashMap<>();
|
|
|
+ funcClassMap.put("faecalibacterium", "丁酸盐生产者");
|
|
|
+ funcClassMap.put("roseburia", "丁酸盐生产者");
|
|
|
+ funcClassMap.put("eubacterium", "丁酸盐生产者");
|
|
|
+ funcClassMap.put("coprococcus", "丁酸盐生产者");
|
|
|
+ funcClassMap.put("oscillospira", "丁酸盐生产者");
|
|
|
+ funcClassMap.put("akkermansia", "黏液屏障");
|
|
|
+ funcClassMap.put("alistipes", "蛋白质发酵者");
|
|
|
+ funcClassMap.put("sutterella", "蛋白质发酵者");
|
|
|
+ funcClassMap.put("parabacteroides", "蛋白质发酵者");
|
|
|
+ funcClassMap.put("blautia", "短链脂肪酸生产者");
|
|
|
+ funcClassMap.put("lachnospira", "短链脂肪酸生产者");
|
|
|
+ funcClassMap.put("lachnoclostridium", "短链脂肪酸生产者");
|
|
|
+ funcClassMap.put("phascolarctobacterium", "短链脂肪酸生产者");
|
|
|
+ funcClassMap.put("dorea", "产气菌");
|
|
|
+ funcClassMap.put("bifidobacterium", "益生菌");
|
|
|
+ funcClassMap.put("lactobacillus", "益生菌");
|
|
|
+ funcClassMap.put("ruminococcus", "纤维分解者");
|
|
|
+ funcClassMap.put("prevotella", "纤维分解者");
|
|
|
+ funcClassMap.put("megamonas", "条件致病菌");
|
|
|
+ funcClassMap.put("clostridium", "条件致病菌");
|
|
|
+ funcClassMap.put("bacteroides", "碳水化合物分解者");
|
|
|
+ funcClassMap.put("dialister", "琥珀酸生产者");
|
|
|
+
|
|
|
+ // 按功能分类聚合
|
|
|
+ Map<String, List<Map<String, Object>>> funcGroups = new LinkedHashMap<>();
|
|
|
+ for (Map.Entry<String, String> e : funcClassMap.entrySet()) {
|
|
|
+ String funcName = e.getValue();
|
|
|
+ funcGroups.putIfAbsent(funcName, new ArrayList<>());
|
|
|
+ HealthGutFlora flora = floraByName.get(e.getKey());
|
|
|
+ if (flora != null) {
|
|
|
+ Map<String, Object> item = new HashMap<>();
|
|
|
+ item.put("bacteriaName", flora.getBacteriaName());
|
|
|
+ item.put("status", flora.getStatus());
|
|
|
+ item.put("bacteriaValue", flora.getBacteriaValue());
|
|
|
+ item.put("normalRange", flora.getNormalRange());
|
|
|
+ funcGroups.get(funcName).add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算每个功能维度的健康状态
|
|
|
+ List<Map<String, Object>> functionalAnalysis = new ArrayList<>();
|
|
|
+ for (Map.Entry<String, List<Map<String, Object>>> entry : funcGroups.entrySet()) {
|
|
|
+ if (entry.getValue().isEmpty()) continue;
|
|
|
+ Map<String, Object> dim = new LinkedHashMap<>();
|
|
|
+ dim.put("name", entry.getKey());
|
|
|
+ dim.put("items", entry.getValue());
|
|
|
+
|
|
|
+ // 统计异常菌属数量
|
|
|
+ long abnormalCount = entry.getValue().stream()
|
|
|
+ .filter(m -> {
|
|
|
+ String s = (String) m.get("status");
|
|
|
+ return s != null && !"正常".equals(s);
|
|
|
+ }).count();
|
|
|
+ dim.put("abnormalCount", abnormalCount);
|
|
|
+ dim.put("totalCount", entry.getValue().size());
|
|
|
+
|
|
|
+ // 评估状态
|
|
|
+ if (abnormalCount == 0) {
|
|
|
+ dim.put("status", "良好");
|
|
|
+ dim.put("level", 85);
|
|
|
+ } else if (abnormalCount <= entry.getValue().size() / 2) {
|
|
|
+ dim.put("status", "注意");
|
|
|
+ dim.put("level", 60);
|
|
|
+ } else {
|
|
|
+ dim.put("status", "需关注");
|
|
|
+ dim.put("level", 35);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据功能分类给出摘要
|
|
|
+ dim.put("summary", getFuncSummary(entry.getKey(), dim));
|
|
|
+ functionalAnalysis.add(dim);
|
|
|
+ }
|
|
|
+ result.put("functionalAnalysis", functionalAnalysis);
|
|
|
+
|
|
|
+ // 3. P/B 比值(Prevotella / Bacteroides)
|
|
|
+ Map<String, Object> pbRatio = new LinkedHashMap<>();
|
|
|
+ HealthGutFlora prevotella = floraByName.get("prevotella");
|
|
|
+ HealthGutFlora bacteroides = floraByName.get("bacteroides");
|
|
|
+ if (prevotella != null && bacteroides != null) {
|
|
|
+ double pv = parseDouble(prevotella.getBacteriaValue(), 0);
|
|
|
+ double bv = parseDouble(bacteroides.getBacteriaValue(), 0);
|
|
|
+ double ratio = bv > 0 ? pv / bv : 0;
|
|
|
+ pbRatio.put("prevotellaValue", pv);
|
|
|
+ pbRatio.put("bacteroidesValue", bv);
|
|
|
+ pbRatio.put("ratio", Math.round(ratio * 1000.0) / 1000.0);
|
|
|
+ pbRatio.put("prevotellaStatus", prevotella.getStatus());
|
|
|
+ pbRatio.put("bacteroidesStatus", bacteroides.getStatus());
|
|
|
+ if (ratio > 0.5) {
|
|
|
+ pbRatio.put("interpretation", "植物性饮食倾向(高 Prevotella/Bacteroides 比值)");
|
|
|
+ } else if (ratio > 0.1) {
|
|
|
+ pbRatio.put("interpretation", "均衡饮食模式");
|
|
|
+ } else {
|
|
|
+ pbRatio.put("interpretation", "西式高脂高蛋白饮食倾向(低 Prevotella/Bacteroides 比值)");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ result.put("pbRatio", pbRatio);
|
|
|
+
|
|
|
+ // 4. 饮食模式推断
|
|
|
+ Map<String, Object> dietaryPattern = inferDietaryPattern(floraByName);
|
|
|
+ result.put("dietaryPattern", dietaryPattern);
|
|
|
+
|
|
|
+ // 5. 风险提示组合
|
|
|
+ List<Map<String, Object>> riskIndicators = computeRiskIndicators(floraByName);
|
|
|
+ result.put("riskIndicators", riskIndicators);
|
|
|
+
|
|
|
+ // 6. 益生菌指导
|
|
|
+ Map<String, Object> probioticAdvice = new LinkedHashMap<>();
|
|
|
+ HealthGutFlora bifido = floraByName.get("bifidobacterium");
|
|
|
+ HealthGutFlora lacto = floraByName.get("lactobacillus");
|
|
|
+ if (bifido != null) {
|
|
|
+ Map<String, Object> b = new LinkedHashMap<>();
|
|
|
+ b.put("status", bifido.getStatus());
|
|
|
+ b.put("advice", "偏低".equals(bifido.getStatus()) ? "建议增加益生元摄入(洋葱、大蒜、香蕉、燕麦)"
|
|
|
+ : "偏高".equals(bifido.getStatus()) ? "偏高通常无害,严重偏高时暂停益生菌补充剂"
|
|
|
+ : "正常水平,继续保持");
|
|
|
+ probioticAdvice.put("bifidobacterium", b);
|
|
|
+ }
|
|
|
+ if (lacto != null) {
|
|
|
+ Map<String, Object> l = new LinkedHashMap<>();
|
|
|
+ l.put("status", lacto.getStatus());
|
|
|
+ l.put("advice", "偏低".equals(lacto.getStatus()) ? "建议补充发酵食品(无糖酸奶、开菲尔、泡菜)"
|
|
|
+ : "偏高".equals(lacto.getStatus()) ? "偏高通常无害,严重偏高时暂停益生菌补充剂"
|
|
|
+ : "正常水平,继续保持");
|
|
|
+ probioticAdvice.put("lactobacillus", l);
|
|
|
+ }
|
|
|
+ result.put("probioticAdvice", probioticAdvice);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 功能维度摘要 */
|
|
|
+ private String getFuncSummary(String funcName, Map<String, Object> dim) {
|
|
|
+ String status = (String) dim.get("status");
|
|
|
+ long total = (long) dim.get("totalCount");
|
|
|
+ long abnormal = (long) dim.get("abnormalCount");
|
|
|
+
|
|
|
+ switch (funcName) {
|
|
|
+ case "丁酸盐生产者":
|
|
|
+ return status.equals("良好") ? "丁酸盐生产者菌群正常,肠道屏障修复能力良好"
|
|
|
+ : abnormal + "/" + total + "种丁酸菌异常,可能影响肠黏膜修复和抗炎能力";
|
|
|
+ case "黏液屏障":
|
|
|
+ return status.equals("良好") ? "阿克曼菌正常,肠黏液屏障完整"
|
|
|
+ : "阿克曼菌偏低,提示肠道屏障功能可能受损,建议增加多酚类食物";
|
|
|
+ case "蛋白质发酵者":
|
|
|
+ return status.equals("良好") ? "蛋白质发酵菌群正常"
|
|
|
+ : abnormal + "/" + total + "种异常,提示高动物蛋白饮食或潜在肠道炎症";
|
|
|
+ case "短链脂肪酸生产者":
|
|
|
+ return status.equals("良好") ? "短链脂肪酸生产者正常,代谢健康良好"
|
|
|
+ : abnormal + "/" + total + "种SCFA菌异常,可能影响代谢和免疫调节";
|
|
|
+ case "产气菌":
|
|
|
+ return "偏高".equals(dim.get("status")) ? "Dorea偏高,提示腹胀/肠易激风险"
|
|
|
+ : "产气菌属正常,无腹胀风险";
|
|
|
+ case "益生菌":
|
|
|
+ return status.equals("良好") ? "益生菌水平正常"
|
|
|
+ : abnormal + "/" + total + "种益生菌异常,请参考补充建议";
|
|
|
+ case "纤维分解者":
|
|
|
+ return status.equals("良好") ? "纤维分解菌群正常,膳食纤维消化能力良好"
|
|
|
+ : abnormal + "/" + total + "种纤维分解菌异常,可能影响膳食纤维消化";
|
|
|
+ case "条件致病菌":
|
|
|
+ return status.equals("良好") ? "条件致病菌在正常范围内"
|
|
|
+ : abnormal + "/" + total + "种条件致病菌异常,建议关注";
|
|
|
+ case "碳水化合物分解者":
|
|
|
+ return status.equals("良好") ? "碳水化合物分解菌正常"
|
|
|
+ : "拟杆菌属异常,可能受高脂高蛋白饮食影响";
|
|
|
+ case "琥珀酸生产者":
|
|
|
+ return status.equals("良好") ? "Dialister正常"
|
|
|
+ : "Dialister异常,可能与情绪/压力相关";
|
|
|
+ default:
|
|
|
+ return abnormal + "/" + total + "种菌属异常";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 饮食模式推断 */
|
|
|
+ private Map<String, Object> inferDietaryPattern(Map<String, HealthGutFlora> floraByName) {
|
|
|
+ Map<String, Object> pattern = new LinkedHashMap<>();
|
|
|
+ int highProtein = 0, highFiber = 0, highSugar = 0;
|
|
|
+
|
|
|
+ HealthGutFlora alistipes = floraByName.get("alistipes");
|
|
|
+ if (alistipes != null && "偏高".equals(alistipes.getStatus())) highProtein++;
|
|
|
+
|
|
|
+ HealthGutFlora sutterella = floraByName.get("sutterella");
|
|
|
+ if (sutterella != null && "偏高".equals(sutterella.getStatus())) highProtein++;
|
|
|
+
|
|
|
+ HealthGutFlora parabacteroides = floraByName.get("parabacteroides");
|
|
|
+ if (parabacteroides != null && "偏高".equals(parabacteroides.getStatus())) highProtein++;
|
|
|
+
|
|
|
+ HealthGutFlora prevotella = floraByName.get("prevotella");
|
|
|
+ if (prevotella != null && "偏高".equals(prevotella.getStatus())) highFiber++;
|
|
|
+
|
|
|
+ HealthGutFlora megamonas = floraByName.get("megamonas");
|
|
|
+ if (megamonas != null && "偏高".equals(megamonas.getStatus())) highSugar++;
|
|
|
+
|
|
|
+ HealthGutFlora dorea = floraByName.get("dorea");
|
|
|
+ if (dorea != null && "偏高".equals(dorea.getStatus())) highSugar++;
|
|
|
+
|
|
|
+ if (highProtein >= 2 && highFiber == 0) {
|
|
|
+ pattern.put("pattern", "高动物蛋白饮食");
|
|
|
+ pattern.put("detail", "蛋白质发酵菌(Alistipes/Sutterella/Parabacteroides)偏高,提示近期动物蛋白摄入较多,建议增加蔬菜水果比例");
|
|
|
+ } else if (highFiber >= 1 && highProtein == 0) {
|
|
|
+ pattern.put("pattern", "植物性饮食");
|
|
|
+ pattern.put("detail", "Prevotella 偏高,提示植物性食物摄入充足,建议继续保持均衡");
|
|
|
+ } else if (highSugar >= 2) {
|
|
|
+ pattern.put("pattern", "高糖/精制碳水饮食");
|
|
|
+ pattern.put("detail", "Megamonas/Dorea 偏高,提示精制碳水和简单糖摄入较多,建议减少含糖饮料和糕点");
|
|
|
+ } else {
|
|
|
+ pattern.put("pattern", "均衡饮食");
|
|
|
+ pattern.put("detail", "菌群特征未显示明显偏食模式,现有饮食结构较为均衡");
|
|
|
+ }
|
|
|
+ return pattern;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 风险组合模型 */
|
|
|
+ private List<Map<String, Object>> computeRiskIndicators(Map<String, HealthGutFlora> floraByName) {
|
|
|
+ List<Map<String, Object>> risks = new ArrayList<>();
|
|
|
+
|
|
|
+ // IBD 倾向
|
|
|
+ Map<String, Object> ibd = new LinkedHashMap<>();
|
|
|
+ ibd.put("name", "肠道炎症倾向");
|
|
|
+ List<String> ibdBacteria = new ArrayList<>();
|
|
|
+ addIfAbnormal(floraByName, "megamonas", ibdBacteria);
|
|
|
+ addIfAbnormal(floraByName, "ruminococcus", ibdBacteria);
|
|
|
+ ibd.put("relatedBacteria", ibdBacteria);
|
|
|
+ ibd.put("level", ibdBacteria.size() >= 2 ? "关注" : ibdBacteria.size() == 1 ? "注意" : "正常");
|
|
|
+ risks.add(ibd);
|
|
|
+
|
|
|
+ // 代谢综合征
|
|
|
+ Map<String, Object> metabolic = new LinkedHashMap<>();
|
|
|
+ metabolic.put("name", "代谢健康提示");
|
|
|
+ List<String> metaBacteria = new ArrayList<>();
|
|
|
+ addIfAbnormal(floraByName, "blautia", metaBacteria);
|
|
|
+ addIfAbnormal(floraByName, "roseburia", metaBacteria);
|
|
|
+ metabolic.put("relatedBacteria", metaBacteria);
|
|
|
+ metabolic.put("level", metaBacteria.size() >= 2 ? "关注" : metaBacteria.size() == 1 ? "注意" : "正常");
|
|
|
+ risks.add(metabolic);
|
|
|
+
|
|
|
+ // IBS/肠易激
|
|
|
+ Map<String, Object> ibs = new LinkedHashMap<>();
|
|
|
+ ibs.put("name", "肠易激/腹胀风险");
|
|
|
+ List<String> ibsBacteria = new ArrayList<>();
|
|
|
+ addIfAbnormal(floraByName, "dorea", ibsBacteria);
|
|
|
+ addIfAbnormal(floraByName, "ruminococcus", ibsBacteria);
|
|
|
+ ibs.put("relatedBacteria", ibsBacteria);
|
|
|
+ ibs.put("level", ibsBacteria.size() >= 2 ? "关注" : ibsBacteria.size() == 1 ? "注意" : "正常");
|
|
|
+ risks.add(ibs);
|
|
|
+
|
|
|
+ // 神经-肠轴
|
|
|
+ Map<String, Object> neuro = new LinkedHashMap<>();
|
|
|
+ neuro.put("name", "神经-肠轴提示");
|
|
|
+ List<String> neuroBacteria = new ArrayList<>();
|
|
|
+ addIfAbnormal(floraByName, "dialister", neuroBacteria);
|
|
|
+ addIfAbnormal(floraByName, "phascolarctobacterium", neuroBacteria);
|
|
|
+ addIfAbnormal(floraByName, "sutterella", neuroBacteria);
|
|
|
+ neuro.put("relatedBacteria", neuroBacteria);
|
|
|
+ neuro.put("level", neuroBacteria.size() >= 2 ? "关注" : neuroBacteria.size() == 1 ? "注意" : "正常");
|
|
|
+ risks.add(neuro);
|
|
|
+
|
|
|
+ return risks;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addIfAbnormal(Map<String, HealthGutFlora> floraByName, String name, List<String> list) {
|
|
|
+ HealthGutFlora f = floraByName.get(name);
|
|
|
+ if (f != null && f.getStatus() != null && !"正常".equals(f.getStatus())) {
|
|
|
+ list.add(f.getBacteriaName() + "(" + f.getStatus() + ")");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private double parseDouble(String value, double defaultValue) {
|
|
|
+ if (value == null) return defaultValue;
|
|
|
+ try {
|
|
|
+ return Double.parseDouble(value);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// ============================================================
|
|
|
// 饮食模块扩展
|
|
|
// ============================================================
|