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

feat: 戒备按报告查——报告详情入口传 reportId 返回该次检测戒备食材,foods 无数据回退 report_food_suitability

liaoxg 1 месяц назад
Родитель
Сommit
4915a7edd4

+ 12 - 2
cfc-backend/src/main/java/com/etotem/cfc/controller/FoodRecommendController.java

@@ -67,8 +67,18 @@ public class FoodRecommendController {
             @RequestBody(required = false) Map<String, Object> params) {
         if (userId == null) return Result.error("请先登录");
         Long memberId = null;
-        if (params != null && params.get("memberId") instanceof Number) {
-            memberId = ((Number) params.get("memberId")).longValue();
+        Long reportId = null;
+        if (params != null) {
+            if (params.get("memberId") instanceof Number) {
+                memberId = ((Number) params.get("memberId")).longValue();
+            }
+            if (params.get("reportId") instanceof Number) {
+                reportId = ((Number) params.get("reportId")).longValue();
+            }
+        }
+        // 传 reportId:按报告返回该次检测的戒备食材;否则维持现状(按成员/用户最新推荐指数)
+        if (reportId != null) {
+            return Result.success(foodRecommendService.getCautionFoodsByReport(reportId));
         }
         List<FoodRecommendIndex> foods = foodRecommendService.getCautionFoods(memberId != null ? memberId : userId);
         return Result.success(foods);

+ 44 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/FoodRecommendService.java

@@ -275,6 +275,50 @@ public class FoodRecommendService {
         );
     }
 
+    /**
+     * 按报告获取戒备食材(该报告当次检测的推荐指数 &lt; 0 食材)。
+     * 优先从 foods 表读取(正常确认流程按报告写入),
+     * 若 foods 表无负分数据,回退到 report_food_suitability(审核路径写入)。
+     * 返回结构与当前戒备接口一致(兼容前端 FoodRecommendIndex 映射)。
+     */
+    public List<FoodRecommendIndex> getCautionFoodsByReport(Long reportId) {
+        List<FoodRecommendIndex> result = new ArrayList<>();
+        if (reportId == null) return result;
+
+        // 优先 foods 表(确认流程写入,携带 report_id)
+        List<Food> reportFoods = foodService.listByReportId(reportId);
+        for (Food food : reportFoods) {
+            if (food.getScore() != null && food.getScore() < 0) {
+                FoodRecommendIndex idx = new FoodRecommendIndex();
+                idx.setFoodId(food.getId());
+                idx.setFoodName(food.getName());
+                idx.setIndexScore(food.getScore());
+                idx.setHealthReportId(reportId);
+                result.add(idx);
+            }
+        }
+
+        // foods 无负分数据:回退 report_food_suitability(审核路径只写这张表)
+        if (result.isEmpty()) {
+            List<ReportFoodSuitability> fallback = reportFoodSuitabilityMapper.selectList(
+                    new LambdaQueryWrapper<ReportFoodSuitability>()
+                            .eq(ReportFoodSuitability::getReportId, reportId)
+                            .lt(ReportFoodSuitability::getScore, 0)
+                            .orderByAsc(ReportFoodSuitability::getScore));
+            for (ReportFoodSuitability rfs : fallback) {
+                FoodRecommendIndex idx = new FoodRecommendIndex();
+                idx.setFoodId(rfs.getFoodId());
+                idx.setFoodName(rfs.getFoodName());
+                idx.setIndexScore(rfs.getScore());
+                idx.setHealthReportId(reportId);
+                result.add(idx);
+            }
+        }
+
+        result.sort(Comparator.comparing(FoodRecommendIndex::getIndexScore));
+        return result;
+    }
+
     /**
      * 获取戒备食材趋势数据:返回每个食材的 indexScore 历史序列(最近N条变更记录)
      * 每个元素: { foodId, foodName, currentScore, trend: [reportDate, score], changeDir: "up"|"down"|"flat" }

+ 12 - 4
cfc-frontend/pages/growth/caution-detail.vue

@@ -75,12 +75,17 @@ export default {
       nutritionCache: {},
       currentMemberId: null,
       memberList: [],
-      trendMap: {}
+      trendMap: {},
+      // 报告详情入口传入:>0 时按该报告返回戒备食材,隐藏家庭成员切换
+      reportId: null
     }
   },
   onLoad: function(options) {
+    this.reportId = options.reportId ? parseInt(options.reportId) : null
     this.currentMemberId = options.memberId ? parseInt(options.memberId) : null
-    this.loadMemberList()
+    if (!this.reportId) {
+      this.loadMemberList()
+    }
     this.loadFoods()
   },
   methods: {
@@ -108,7 +113,7 @@ export default {
     async loadFoods() {
       this.loading = true
       try {
-        var res = await getFoodCautionList(this.currentMemberId > 0 ? this.currentMemberId : null)
+        var res = await getFoodCautionList(this.currentMemberId > 0 ? this.currentMemberId : null, this.reportId)
         if (res && res.code === 200 && res.data) {
           this.foods = (res.data || []).map(function(f) {
             return {
@@ -124,7 +129,10 @@ export default {
             }
           })
           this.loadNutrition()
-          this.loadTrends()
+          // 按报告快照展示,无历史变化概念,跳过趋势查询
+          if (!this.reportId) {
+            this.loadTrends()
+          }
         } else {
           this.foods = []
         }

+ 4 - 2
cfc-frontend/pages/health/gut-flora-detail.vue

@@ -974,9 +974,11 @@ report.gutType = s.gutType || ''
       uni.navigateTo({ url: '/pages/health/gut-flora-foods-detail?reportId=' + this.reportId })
     },
     goToCaution: function() {
-      // 报告绑定主体(subjectId)即 food_recommend_idx 写入的用户维度,作为 memberId 传入戒备页
+      // 报告详情入口:传 reportId(按报告快照返回戒备食材)+ memberId(报告绑定主体 subjectId)
       var mid = (this.report && this.report.subjectId) || uni.getStorageSync('currentMemberId') || ''
-      uni.navigateTo({ url: '/pages/growth/caution-detail' + (mid ? '?memberId=' + mid : '') })
+      var url = '/pages/growth/caution-detail?reportId=' + this.reportId
+      if (mid) url += '&memberId=' + mid
+      uni.navigateTo({ url: url })
     },
     goToIndicators: function() {
       // 展开所有营养分组手风琴

+ 4 - 1
cfc-frontend/utils/api.js

@@ -2767,9 +2767,12 @@ export const getGrowthRecommendations = (category = 'health', limit = 3) =>
   request('/api/growth/recommendations', 'POST', { category, limit })
 
 // ===== 食材戒备匹配 =====
-export const getFoodCautionList = (memberId) => {
+// reportId 可选:传了则按报告返回该次检测的戒备食材(报告详情入口);
+// 不传则按成员最新推荐指数返回(成长页当前戒备入口)
+export const getFoodCautionList = (memberId, reportId) => {
   var data = {}
   if (memberId) data.memberId = memberId
+  if (reportId) data.reportId = reportId
   return request('/api/food/recommendation/caution', 'POST', data)
 }