Просмотр исходного кода

feat(food): 报告审核确认时将食材推荐入库

- HealthReportService.auditConfirm() 新增 saveFoodSuitability()
- saveFoodSuitability() 将 FoodItem 写入 report_food_suitability 表
- 自动匹配 foodId(精确+模糊匹配 foods 表)
- schema.sql 同步 report_food_suitability 表定义
liaoxg 1 месяц назад
Родитель
Сommit
01c94b5b54

+ 62 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/HealthReportService.java

@@ -15,6 +15,7 @@ import com.etotem.cfc.mapper.HealthReportMapper;
 import com.etotem.cfc.mapper.HealthReportPermissionMapper;
 import com.etotem.cfc.mapper.HealthReportPermissionMapper;
 import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.mapper.UserMapper;
 import com.etotem.cfc.mapper.FoodMapper;
 import com.etotem.cfc.mapper.FoodMapper;
+import com.etotem.cfc.mapper.ReportFoodSuitabilityMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.dao.DuplicateKeyException;
@@ -81,6 +82,12 @@ public class HealthReportService {
     @Resource
     @Resource
     private ReportBlockAssembler reportBlockAssembler;
     private ReportBlockAssembler reportBlockAssembler;
 
 
+    @Resource
+    private ReportFoodSuitabilityMapper reportFoodSuitabilityMapper;
+
+    @Resource
+    private FoodMapper foodMapper;
+
     /**
     /**
      * 创建健康报告(含指标列表)
      * 创建健康报告(含指标列表)
      */
      */
@@ -965,6 +972,9 @@ public class HealthReportService {
                 bindReportToMember(created.getId(), matchedMemberId);
                 bindReportToMember(created.getId(), matchedMemberId);
             }
             }
 
 
+            // 保存食材推荐数据
+            saveFoodSuitability(created.getId(), payload.getFoods());
+
             markDraftConfirmed(draftId, created.getId());
             markDraftConfirmed(draftId, created.getId());
 
 
             Map<String, Object> result = new HashMap<>();
             Map<String, Object> result = new HashMap<>();
@@ -1165,6 +1175,58 @@ public class HealthReportService {
         return risks;
         return risks;
     }
     }
 
 
+    /**
+     * 从 Payload 构建食材推荐数据并入库
+     * 查找 foodId(匹配 foods 表),未匹配时留空
+     */
+    @Transactional
+    public void saveFoodSuitability(Long reportId, List<ParsedReportPayload.FoodItem> foods) {
+        if (foods == null || foods.isEmpty()) {
+            log.info("报告{}无食材推荐数据,跳过入库", reportId);
+            return;
+        }
+
+        // 批量查询所有食材名称→ID映射
+        Map<String, Long> foodNameIdMap = new HashMap<>();
+        List<Food> allFoods = foodMapper.selectList(null);
+        for (Food f : allFoods) {
+            if (f.getName() != null) {
+                foodNameIdMap.put(f.getName().trim(), f.getId());
+            }
+        }
+
+        Date now = new Date();
+        int saved = 0;
+        for (ParsedReportPayload.FoodItem item : foods) {
+            if (item.getName() == null || item.getName().trim().isEmpty()) continue;
+
+            ReportFoodSuitability suit = new ReportFoodSuitability();
+            suit.setReportId(reportId);
+            suit.setFoodName(item.getName().trim());
+            suit.setCategory(item.getCategory());
+            suit.setScore(item.getScore());
+            suit.setCreatedAt(now);
+
+            // 匹配 foodId
+            Long foodId = foodNameIdMap.get(item.getName().trim());
+            if (foodId == null) {
+                // 模糊匹配:尝试包含匹配
+                for (Map.Entry<String, Long> entry : foodNameIdMap.entrySet()) {
+                    if (entry.getKey().contains(item.getName().trim()) ||
+                        item.getName().trim().contains(entry.getKey())) {
+                        foodId = entry.getValue();
+                        break;
+                    }
+                }
+            }
+            suit.setFoodId(foodId);
+
+            reportFoodSuitabilityMapper.insert(suit);
+            saved++;
+        }
+        log.info("已保存{}条食材推荐到报告{}", saved, reportId);
+    }
+
     /**
     /**
      * 更新已发布报告的编辑数据
      * 更新已发布报告的编辑数据
      * 逻辑: 只更新已有字段的值,不增删条目(全量替换)
      * 逻辑: 只更新已有字段的值,不增删条目(全量替换)

+ 14 - 0
cfc-backend/src/main/resources/schema.sql

@@ -3807,6 +3807,20 @@ CREATE TABLE IF NOT EXISTS food_recommend_idx (
     INDEX idx_report (health_report_id)
     INDEX idx_report (health_report_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食推荐指数';
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食推荐指数';
 
 
+-- 报告食材适宜度
+CREATE TABLE IF NOT EXISTS report_food_suitability (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    report_id BIGINT NOT NULL COMMENT '健康报告ID',
+    food_id BIGINT COMMENT '食材ID',
+    food_name VARCHAR(100) NOT NULL COMMENT '食材名称',
+    category VARCHAR(50) COMMENT '分类',
+    score INT NOT NULL COMMENT '适宜度评分',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_report (report_id),
+    INDEX idx_food (food_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告食材适宜度';
+
+
 -- ============================================================
 -- ============================================================
 -- 积分兑换商品表(迁移124)
 -- 积分兑换商品表(迁移124)
 -- ============================================================
 -- ============================================================