|
|
@@ -0,0 +1,196 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.etotem.cfc.dto.ParsedReportPayload;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 报告通用展示块组装器 — 解析结果 → blocks JSON 结构
|
|
|
+ * 前端只消费 blocks,不接触实体字段名。
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ReportBlockAssembler {
|
|
|
+
|
|
|
+ private static final java.util.Set<String> IMPORTANT_LEVELS =
|
|
|
+ new java.util.HashSet<>(java.util.Arrays.asList("需注意", "注意", "高风险", "异常"));
|
|
|
+
|
|
|
+ /** 判断是否重要风险(需注意/注意/高风险/异常 → 重要;低风险/其余 → 其它) */
|
|
|
+ public boolean isImportantRisk(String level) {
|
|
|
+ return level != null && IMPORTANT_LEVELS.contains(level);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 编辑链路:第一套键 Map → 标准 Payload(第二套键) */
|
|
|
+ public ParsedReportPayload.Payload fromMap(Map<String, Object> map) {
|
|
|
+ ParsedReportPayload.Payload p = new ParsedReportPayload.Payload();
|
|
|
+ if (map == null || map.isEmpty()) return p;
|
|
|
+ ParsedReportPayload.Summary s = new ParsedReportPayload.Summary();
|
|
|
+ s.setOverallScore(toInt(map.get("overallScore")));
|
|
|
+ s.setGutHealthScore(toInt(map.get("gutHealthScore")));
|
|
|
+ s.setChronicDiseaseScore(toInt(map.get("chronicDiseaseScore")));
|
|
|
+ s.setNutritionScore(toInt(map.get("nutritionScore")));
|
|
|
+ s.setBalanceScore(toInt(map.get("gutBalanceScore")));
|
|
|
+ s.setDiversityScore(toInt(map.get("gutDiversityScore")));
|
|
|
+ s.setBeneficialScore(toInt(map.get("beneficialBacteriaScore")));
|
|
|
+ s.setHarmfulScore(toInt(map.get("harmfulBacteriaScore")));
|
|
|
+ s.setCoreGenusScore(toInt(map.get("coreSpeciesScore")));
|
|
|
+ s.setGutAge(str(map.get("gutAge")));
|
|
|
+ s.setGutType(str(map.get("gutType")));
|
|
|
+ p.setSummary(s);
|
|
|
+ return p;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 肠道菌群报告 → blocks */
|
|
|
+ public List<Map<String, Object>> assembleGutFlora(ParsedReportPayload.Payload payload) {
|
|
|
+ List<Map<String, Object>> blocks = new ArrayList<>();
|
|
|
+ if (payload == null) return blocks;
|
|
|
+
|
|
|
+ // 1. score 块:9 项评分(null 跳过)
|
|
|
+ ParsedReportPayload.Summary s = payload.getSummary();
|
|
|
+ if (s != null) {
|
|
|
+ List<Map<String, Object>> items = new ArrayList<>();
|
|
|
+ addScore(items, "综合", s.getOverallScore());
|
|
|
+ addScore(items, "菌群健康", s.getGutHealthScore());
|
|
|
+ addScore(items, "慢病控制", s.getChronicDiseaseScore());
|
|
|
+ addScore(items, "营养均衡", s.getNutritionScore());
|
|
|
+ addScore(items, "平衡", s.getBalanceScore());
|
|
|
+ addScore(items, "多样性", s.getDiversityScore());
|
|
|
+ addScore(items, "有益菌", s.getBeneficialScore());
|
|
|
+ addScore(items, "有害菌", s.getHarmfulScore());
|
|
|
+ addScore(items, "核心菌属", s.getCoreGenusScore());
|
|
|
+ if (!items.isEmpty()) {
|
|
|
+ Map<String, Object> block = new LinkedHashMap<>();
|
|
|
+ block.put("type", "score");
|
|
|
+ block.put("title", "健康评分");
|
|
|
+ block.put("items", items);
|
|
|
+ blocks.add(block);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. risk_group 块:按风险等级分两组
|
|
|
+ List<ParsedReportPayload.DiseaseRisk> risks = payload.getDiseaseRisks();
|
|
|
+ if (risks != null && !risks.isEmpty()) {
|
|
|
+ List<Map<String, Object>> important = new ArrayList<>();
|
|
|
+ List<Map<String, Object>> normal = new ArrayList<>();
|
|
|
+ for (ParsedReportPayload.DiseaseRisk r : risks) {
|
|
|
+ Map<String, Object> m = new LinkedHashMap<>();
|
|
|
+ m.put("name", r.getDiseaseName());
|
|
|
+ m.put("value", r.getRiskValue());
|
|
|
+ m.put("level", r.getRiskLevel());
|
|
|
+ if (isImportantRisk(r.getRiskLevel())) important.add(m);
|
|
|
+ else normal.add(m);
|
|
|
+ }
|
|
|
+ if (!important.isEmpty()) blocks.add(riskBlock("重要风险", important));
|
|
|
+ if (!normal.isEmpty()) blocks.add(riskBlock("其它风险", normal));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. indicator 块:indicators 按 category 分组
|
|
|
+ List<ParsedReportPayload.Indicator> inds = payload.getIndicators();
|
|
|
+ if (inds != null && !inds.isEmpty()) {
|
|
|
+ Map<String, List<Map<String, Object>>> byCategory = new LinkedHashMap<>();
|
|
|
+ for (ParsedReportPayload.Indicator ind : inds) {
|
|
|
+ String cat = ind.getCategory() == null ? "其他指标" : ind.getCategory();
|
|
|
+ byCategory.computeIfAbsent(cat, k -> new ArrayList<>()).add(indicatorItem(ind));
|
|
|
+ }
|
|
|
+ for (Map.Entry<String, List<Map<String, Object>>> e : byCategory.entrySet()) {
|
|
|
+ Map<String, Object> block = new LinkedHashMap<>();
|
|
|
+ block.put("type", "indicator");
|
|
|
+ block.put("title", e.getKey());
|
|
|
+ block.put("items", e.getValue());
|
|
|
+ blocks.add(block);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. list 块:菌种列表(gutFlora + 病原菌)与食物推荐
|
|
|
+ List<Map<String, Object>> floraItems = new ArrayList<>();
|
|
|
+ addFloraItems(floraItems, payload.getGutFlora());
|
|
|
+ addFloraItems(floraItems, payload.getPathogenGenus());
|
|
|
+ addFloraItems(floraItems, payload.getPathogenDetection());
|
|
|
+ if (!floraItems.isEmpty()) {
|
|
|
+ Map<String, Object> block = new LinkedHashMap<>();
|
|
|
+ block.put("type", "list");
|
|
|
+ block.put("title", "菌种详情");
|
|
|
+ block.put("columns", java.util.Arrays.asList(
|
|
|
+ col("name", "菌种"), col("value", "数值"), col("range", "正常范围"), col("status", "状态")));
|
|
|
+ block.put("items", floraItems);
|
|
|
+ blocks.add(block);
|
|
|
+ }
|
|
|
+ List<ParsedReportPayload.FoodItem> foods = payload.getFoods();
|
|
|
+ if (foods != null && !foods.isEmpty()) {
|
|
|
+ List<Map<String, Object>> foodItems = new ArrayList<>();
|
|
|
+ for (ParsedReportPayload.FoodItem f : foods) {
|
|
|
+ Map<String, Object> m = new LinkedHashMap<>();
|
|
|
+ m.put("name", f.getName());
|
|
|
+ m.put("category", f.getCategory());
|
|
|
+ m.put("score", f.getScore());
|
|
|
+ foodItems.add(m);
|
|
|
+ }
|
|
|
+ Map<String, Object> block = new LinkedHashMap<>();
|
|
|
+ block.put("type", "list");
|
|
|
+ block.put("title", "食物推荐");
|
|
|
+ block.put("columns", java.util.Arrays.asList(
|
|
|
+ col("name", "食材"), col("category", "类别"), col("score", "推荐指数")));
|
|
|
+ block.put("items", foodItems);
|
|
|
+ blocks.add(block);
|
|
|
+ }
|
|
|
+ return blocks;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> riskBlock(String title, List<Map<String, Object>> items) {
|
|
|
+ Map<String, Object> block = new LinkedHashMap<>();
|
|
|
+ block.put("type", "risk_group");
|
|
|
+ block.put("title", title);
|
|
|
+ block.put("items", items);
|
|
|
+ return block;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> indicatorItem(ParsedReportPayload.Indicator ind) {
|
|
|
+ Map<String, Object> m = new LinkedHashMap<>();
|
|
|
+ m.put("name", ind.getIndicatorName());
|
|
|
+ m.put("value", ind.getIndicatorValue());
|
|
|
+ m.put("unit", ind.getUnit());
|
|
|
+ m.put("refRange", ind.getRefRange());
|
|
|
+ m.put("status", ind.getStatus());
|
|
|
+ return m;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addFloraItems(List<Map<String, Object>> items, List<ParsedReportPayload.Flora> list) {
|
|
|
+ if (list == null) return;
|
|
|
+ for (ParsedReportPayload.Flora f : list) {
|
|
|
+ Map<String, Object> m = new LinkedHashMap<>();
|
|
|
+ m.put("name", f.getBacteriaName());
|
|
|
+ m.put("value", f.getBacteriaValue());
|
|
|
+ m.put("range", f.getNormalRange());
|
|
|
+ m.put("status", f.getPopulationLevel() != null ? f.getPopulationLevel() : f.getLevel());
|
|
|
+ items.add(m);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addScore(List<Map<String, Object>> items, String label, Integer value) {
|
|
|
+ if (value == null) return;
|
|
|
+ Map<String, Object> m = new LinkedHashMap<>();
|
|
|
+ m.put("label", label);
|
|
|
+ m.put("value", value);
|
|
|
+ m.put("max", 100);
|
|
|
+ items.add(m);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> col(String key, String label) {
|
|
|
+ Map<String, Object> c = new LinkedHashMap<>();
|
|
|
+ c.put("key", key);
|
|
|
+ c.put("label", label);
|
|
|
+ return c;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer toInt(Object v) {
|
|
|
+ if (v == null) return null;
|
|
|
+ try { return Integer.valueOf(v.toString()); } catch (Exception e) { return null; }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String str(Object v) {
|
|
|
+ return v == null ? null : v.toString();
|
|
|
+ }
|
|
|
+}
|