|
@@ -313,12 +313,24 @@ public class HealthReportService {
|
|
|
* 先通过 family_members 表归一该成员的两种 id,再用 IN 匹配 subject_id/user_id
|
|
* 先通过 family_members 表归一该成员的两种 id,再用 IN 匹配 subject_id/user_id
|
|
|
*/
|
|
*/
|
|
|
public List<HealthReport> getMemberReports(Long memberId) {
|
|
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) {
|
|
if (memberId == null) {
|
|
|
return Collections.emptyList();
|
|
return Collections.emptyList();
|
|
|
}
|
|
}
|
|
|
Set<Long> ids = new HashSet<>();
|
|
Set<Long> ids = new HashSet<>();
|
|
|
ids.add(memberId);
|
|
ids.add(memberId);
|
|
|
- Long familyId = null;
|
|
|
|
|
|
|
+ Long memberFamilyId = null;
|
|
|
try {
|
|
try {
|
|
|
FamilyMember fm = familyMemberMapper.selectById(memberId);
|
|
FamilyMember fm = familyMemberMapper.selectById(memberId);
|
|
|
if (fm != null) {
|
|
if (fm != null) {
|
|
@@ -326,28 +338,28 @@ public class HealthReportService {
|
|
|
if (fm.getUserId() != null) {
|
|
if (fm.getUserId() != null) {
|
|
|
ids.add(fm.getUserId());
|
|
ids.add(fm.getUserId());
|
|
|
}
|
|
}
|
|
|
- familyId = fm.getFamilyId();
|
|
|
|
|
|
|
+ memberFamilyId = fm.getFamilyId();
|
|
|
}
|
|
}
|
|
|
// memberId 可能是 users.id,反查其关联的 family_members 行
|
|
// memberId 可能是 users.id,反查其关联的 family_members 行
|
|
|
List<FamilyMember> linked = familyMemberMapper.selectList(
|
|
List<FamilyMember> linked = familyMemberMapper.selectList(
|
|
|
new LambdaQueryWrapper<FamilyMember>().eq(FamilyMember::getUserId, memberId));
|
|
new LambdaQueryWrapper<FamilyMember>().eq(FamilyMember::getUserId, memberId));
|
|
|
for (FamilyMember item : linked) {
|
|
for (FamilyMember item : linked) {
|
|
|
ids.add(item.getId());
|
|
ids.add(item.getId());
|
|
|
- if (familyId == null) {
|
|
|
|
|
- familyId = item.getFamilyId();
|
|
|
|
|
|
|
+ if (memberFamilyId == null) {
|
|
|
|
|
+ memberFamilyId = item.getFamilyId();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.warn("归一家庭成员ID失败 memberId={}: {}", memberId, e.getMessage());
|
|
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();
|
|
return Collections.emptyList();
|
|
|
}
|
|
}
|
|
|
// 严格绑定:经 reassignReport 取消归属(subject_id 被清空)的报告不在此列出,
|
|
// 严格绑定:经 reassignReport 取消归属(subject_id 被清空)的报告不在此列出,
|
|
@@ -355,7 +367,7 @@ public class HealthReportService {
|
|
|
return healthReportMapper.selectList(
|
|
return healthReportMapper.selectList(
|
|
|
new LambdaQueryWrapper<HealthReport>()
|
|
new LambdaQueryWrapper<HealthReport>()
|
|
|
.in(HealthReport::getSubjectId, ids)
|
|
.in(HealthReport::getSubjectId, ids)
|
|
|
- .eq(HealthReport::getFamilyId, familyId)
|
|
|
|
|
|
|
+ .eq(HealthReport::getFamilyId, boundaryFamilyId)
|
|
|
.eq(HealthReport::getStatus, "active")
|
|
.eq(HealthReport::getStatus, "active")
|
|
|
.orderByDesc(HealthReport::getCreatedAt)
|
|
.orderByDesc(HealthReport::getCreatedAt)
|
|
|
);
|
|
);
|