Pārlūkot izejas kodu

fix(log): 修复 age_min_month 列缺失与 reassign 家庭边界导致的日志报错

- NutritionProduct: 移除无数据库列的4个死字段 (修复 /api/product/detail BadSqlGrammar: Unknown column 'age_min_months')
- HealthReportService.getMemberReports: 新增 viewerFamilyId 重载, 按查看者家庭边界查询 (修复 /api/health/report/reassign 报告不属于该家庭)
- HealthReportController: /report/list 传入 JWT familyId
Xiaogang Liao 1 nedēļu atpakaļ
vecāks
revīzija
e0c59d19e4

+ 1 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthReportController.java

@@ -309,7 +309,7 @@ public class HealthReportController {
         Long memberId = ParamUtils.getLong(params.get("memberId"));
         List<HealthReport> reports;
         if (memberId != null) {
-            reports = healthReportService.getMemberReports(memberId);
+            reports = healthReportService.getMemberReports(memberId, familyId);
         } else if (familyId != null) {
             // 未指定 memberId 时,返回当前家庭的全部报告
             reports = healthReportService.getFamilyReports(familyId);

+ 0 - 12
cfc-backend/src/main/java/com/etotem/cfc/entity/NutritionProduct.java

@@ -68,18 +68,6 @@ public class NutritionProduct implements Serializable {
     /** 规格 */
     private String spec;
 
-    /** 适用年龄下限(月) */
-    private Integer ageMinMonths;
-
-    /** 适用年龄上限(月) */
-    private Integer ageMaxMonths;
-
-    /** 孕期/哺乳期标签(0=不适用, 1=孕期, 2=哺乳期, 3=孕期+哺乳期) */
-    private Integer pregnancyLactationTag;
-
-    /** 禁止人群标签(0=无, 1=婴幼儿禁用, 2=成人禁用, 3=特定疾病人群禁用) */
-    private Integer contraindicationTag;
-
     /** 成分功效标签(JSON数组,如 ["补钙","补锌","益生菌","维生素D"]) */
     private String efficacyTags;
 

+ 24 - 12
cfc-backend/src/main/java/com/etotem/cfc/service/HealthReportService.java

@@ -313,12 +313,24 @@ public class HealthReportService {
      * 先通过 family_members 表归一该成员的两种 id,再用 IN 匹配 subject_id/user_id
      */
     public List<HealthReport> getMemberReports(Long memberId) {
+        return getMemberReports(memberId, null);
+    }
+
+    /**
+     * 获取成员的报告列表(家庭隔离)。
+     *
+     * @param memberId       成员ID(兼容 users.id / family_members.id)
+     * @param viewerFamilyId 查看者家庭ID(来自 JWT)。非空时以其为家庭边界,
+     *                       与 reassignReport 的权限校验保持一致,避免列表展示
+     *                       的报告在「重新分配归属」时被判为「报告不属于该家庭」。
+     */
+    public List<HealthReport> getMemberReports(Long memberId, Long viewerFamilyId) {
         if (memberId == null) {
             return Collections.emptyList();
         }
         Set<Long> ids = new HashSet<>();
         ids.add(memberId);
-        Long familyId = null;
+        Long memberFamilyId = null;
         try {
             FamilyMember fm = familyMemberMapper.selectById(memberId);
             if (fm != null) {
@@ -326,28 +338,28 @@ public class HealthReportService {
                 if (fm.getUserId() != null) {
                     ids.add(fm.getUserId());
                 }
-                familyId = fm.getFamilyId();
+                memberFamilyId = fm.getFamilyId();
             }
             // memberId 可能是 users.id,反查其关联的 family_members 行
             List<FamilyMember> linked = familyMemberMapper.selectList(
                     new LambdaQueryWrapper<FamilyMember>().eq(FamilyMember::getUserId, memberId));
             for (FamilyMember item : linked) {
                 ids.add(item.getId());
-                if (familyId == null) {
-                    familyId = item.getFamilyId();
+                if (memberFamilyId == null) {
+                    memberFamilyId = item.getFamilyId();
                 }
             }
         } catch (Exception e) {
             log.warn("归一家庭成员ID失败 memberId={}: {}", memberId, e.getMessage());
         }
 
-        // 家庭隔离:报告必须归属该成员所在家庭。
-        // 此前只按 subject_id/user_id 匹配、完全不带 family_id 条件,会把其他家庭的
-        // 报告带进成员列表(实测家庭72成员返回7条中5条越界)。小程序据此显示
-        // "取消归属",点击后在 reassignReport 权限校验处抛"报告不属于该家庭"。
-        // 列表侧必须与权限侧遵守同一条家庭边界。
-        if (familyId == null) {
-            log.warn("无法解析成员所属家庭,返回空报告列表 memberId={}", memberId);
+        // 家庭隔离:报告必须归属该家庭成员。列表侧必须与权限侧(reassignReport)遵守同一条家庭边界。
+        // 查看者家庭(JWT)优先,与权限校验一致;为空时退回成员家庭。
+        // 修复:此前以成员家庭为边界,当成员为跨家庭 users.id(多家庭)时与查看者家庭不一致,
+        // 小程序列表展示后可点「取消归属」,却在 reassignReport 处抛「报告不属于该家庭」。
+        Long boundaryFamilyId = (viewerFamilyId != null) ? viewerFamilyId : memberFamilyId;
+        if (boundaryFamilyId == null) {
+            log.warn("无法解析家庭边界,返回空报告列表 memberId={}", memberId);
             return Collections.emptyList();
         }
         // 严格绑定:经 reassignReport 取消归属(subject_id 被清空)的报告不在此列出,
@@ -355,7 +367,7 @@ public class HealthReportService {
         return healthReportMapper.selectList(
                 new LambdaQueryWrapper<HealthReport>()
                         .in(HealthReport::getSubjectId, ids)
-                        .eq(HealthReport::getFamilyId, familyId)
+                        .eq(HealthReport::getFamilyId, boundaryFamilyId)
                         .eq(HealthReport::getStatus, "active")
                         .orderByDesc(HealthReport::getCreatedAt)
         );