|
@@ -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);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 更新已发布报告的编辑数据
|
|
* 更新已发布报告的编辑数据
|
|
|
* 逻辑: 只更新已有字段的值,不增删条目(全量替换)
|
|
* 逻辑: 只更新已有字段的值,不增删条目(全量替换)
|