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

fix: 恢复仅不可登录成员可切换视角(业务规则确认:可登录成员不允许切换)

- listMembers 成员段 isSwitchable 恢复 openid 判断(撤销 17a6dde35 的'非自己即可'加宽)
- listMembers / updateParentMember 家长段 isSwitchable 恒 false(家长均为可登录用户)
- switchToMember 恢复 openid 校验:可登录成员 throw '该成员可通过微信登录,不能切换为TA的身份';source='parent' 分支同样拒绝
- toFamilyMemberVO 恢复原签名与 openid 判定(撤销 601bcf083 的加宽)
- 前端 store 切换守卫文案与 ProfileHeader 注释同步恢复原语义
liaoxg 1 месяц назад
Родитель
Сommit
68e44ad2a8

+ 33 - 19
cfc-backend/src/main/java/com/etotem/cfc/service/FamilyMemberService.java

@@ -210,7 +210,7 @@ public class FamilyMemberService {
             membershipService.syncMembershipForNewMember(memberUserId, familyId);
         }
 
-        return toFamilyMemberVO(member, userId);
+        return toFamilyMemberVO(member);
     }
 
     /**
@@ -290,9 +290,15 @@ public class FamilyMemberService {
             vo.setTrustScore(fm.getTrustScore());
             vo.setIntimacyScore(fm.getIntimacyScore());
             vo.setCommunicationScore(fm.getCommunicationScore());
-            vo.setIsSelf(viewerMember != null && viewerMember.getId().equals(fm.getId()));
-            // 设置 isSwitchable:同家庭非自己成员均可切换视角(含被邀请的能登录成员)
-            vo.setIsSwitchable(!(viewerMember != null && viewerMember.getId().equals(fm.getId())));
+vo.setIsSelf(viewerMember != null && viewerMember.getId().equals(fm.getId()));
+            // 设置 isSwitchable:仅无 openid 的不可登录成员可被切换(可登录成员不允许切换视角)
+            if (fm.getUserId() != null) {
+                User memberUser = userMapper.selectById(fm.getUserId());
+                String openid = memberUser != null ? memberUser.getOpenid() : null;
+                vo.setIsSwitchable(openid == null || openid.isEmpty());
+            } else {
+                vo.setIsSwitchable(true);
+            }
             vo.setLastInteractionAt(fm.getLastInteractionAt());
             vo.setStreakDays(fm.getStreakDays());
             // 兼容旧前端字段
@@ -337,7 +343,8 @@ public class FamilyMemberService {
             vo.setGeneration(0);
             vo.setIsAdmin(isAdmin);
             vo.setIsSelf(p.getId().equals(userId));
-            vo.setIsSwitchable(!p.getId().equals(userId)); // 非自己即可切换(含 source='parent' 段)
+            // 家长账号均为可登录用户,不允许切换视角(与成员段"仅不可登录可切换"一致)
+            vo.setIsSwitchable(false); // 含 source='parent' 段
             vo.setShowToFamily(p.getShowToFamily() != null ? p.getShowToFamily() : 1);
             vo.setIsSpouse(false);
             vo.setTotalPoints(p.getTotalPoints());
@@ -363,6 +370,13 @@ public class FamilyMemberService {
             if (member.getUserId() != null && member.getUserId().equals(userId)) {
                 throw new RuntimeException("不能切换到自己");
             }
+            // 仅不可登录成员可被切换:可登录成员(有 openid,可通过微信登录)不允许切换视角
+            User memberUser = member.getUserId() != null ? userMapper.selectById(member.getUserId()) : null;
+            String openid = memberUser != null ? memberUser.getOpenid() : null;
+            boolean canLogin = openid != null && !openid.isEmpty();
+            if (canLogin) {
+                throw new RuntimeException("该成员可通过微信登录,不能切换为TA的身份");
+            }
             String effectiveRole = computeEffectiveRole(member);
             // 直接登录的孩子端不能切换到家长端
             if ("child".equals(user.getRole()) && "parent".equals(effectiveRole)) {
@@ -390,13 +404,8 @@ public class FamilyMemberService {
             if ("child".equals(user.getRole())) {
                 throw new RuntimeException("孩子账号不能切换到家长视角");
             }
-            SwitchMemberVO vo = new SwitchMemberVO();
-            vo.setMemberId(targetParent.getId());
-            vo.setSource("parent");
-            vo.setEffectiveRole("parent");
-            vo.setNickname(targetParent.getNickname());
-            vo.setIsSwitchable(true);
-            return vo;
+            // source='parent' 的家长账号均为可登录用户,不允许切换视角
+            throw new RuntimeException("该成员可通过微信登录,不能切换为TA的身份");
         }
 
         throw new RuntimeException("成员不存在或不属于您的家庭");
@@ -870,7 +879,7 @@ public class FamilyMemberService {
         member.setUpdatedAt(new Date());
         familyMemberMapper.updateById(member);
         logMemberAction(member.getFamilyId(), member.getId(), "update", oldNickname, member.getNickname(), userId);
-        return toFamilyMemberVO(member, userId);
+        return toFamilyMemberVO(member);
     }
 
     /**
@@ -935,7 +944,8 @@ public class FamilyMemberService {
         vo.setGeneration(0);
         vo.setIsAdmin(true);
         vo.setIsSelf(parent.getId().equals(operator.getId()));
-        vo.setIsSwitchable(!parent.getId().equals(operator.getId()));
+        // 家长账号均为可登录用户,不允许切换视角(与成员段"仅不可登录可切换"一致)
+        vo.setIsSwitchable(false); // source='parent' 段(updateParentMember 返回 VO)
         vo.setShowToFamily(parent.getShowToFamily() != null ? parent.getShowToFamily() : 1);
         vo.setIsSpouse(false);
         vo.setTotalPoints(parent.getTotalPoints());
@@ -959,7 +969,7 @@ public class FamilyMemberService {
         return fm.getNickname();
     }
 
-    private FamilyMemberVO toFamilyMemberVO(FamilyMember member, Long operatorUserId) {
+    private FamilyMemberVO toFamilyMemberVO(FamilyMember member) {
         FamilyMemberVO vo = new FamilyMemberVO();
         vo.setId(member.getId());
         vo.setSource("family_member");
@@ -976,10 +986,14 @@ public class FamilyMemberService {
         if (member.getBirthday() != null) {
             vo.setAge(calculateAge(member.getBirthday()));
         }
-        // 设置 isSwitchable:非操作者本人即可切换视角(含可登录成员),与 listMembers 口径一致
-        boolean switchableIsSelf = operatorUserId != null && member.getUserId() != null
-                && operatorUserId.equals(member.getUserId());
-        vo.setIsSwitchable(!switchableIsSelf);
+        // 设置 isSwitchable:仅无 openid 的不可登录成员可被切换(可登录成员不允许切换视角)
+        if (member.getUserId() != null) {
+            User memberUser = userMapper.selectById(member.getUserId());
+            String openid = memberUser != null ? memberUser.getOpenid() : null;
+            vo.setIsSwitchable(openid == null || openid.isEmpty());
+        } else {
+            vo.setIsSwitchable(true);
+        }
         return vo;
     }
 

+ 1 - 1
cfc-frontend/components/ProfileHeader.vue

@@ -94,7 +94,7 @@ export default {
           return
         }
       }
-      // 优先显示可切换成员(isSwitchable 由后端计算:非本人即可切换,含可登录成员)
+      // 优先显示可切换成员(不可登录成员),过滤掉可通过微信登录的成员
       var switchable = this.children.filter(function(m) { return m.isSwitchable })
       if (switchable.length === 0) {
         uni.showToast({ title: '暂无可切换成员', icon: 'none' })

+ 2 - 2
cfc-frontend/store/index.js

@@ -195,11 +195,11 @@ const store = new Vuex.Store({
       commit('switchToChild', memberId)
       return true
     },
-    // 切换到家庭成员前检查(isSwitchable 由后端统一计算:非本人即可切换,含可登录成员)
+    // 切换到家庭成员前检查(仅不可登录成员可切换)
     switchToMemberWithCheck({ commit }, payload) {
       var member = payload.member || {}
       if (member.isSwitchable === false) {
-        uni.showToast({ title: '该成员暂不可切换', icon: 'none' })
+        uni.showToast({ title: '该成员可通过微信登录,不能切换为TA的身份', icon: 'none' })
         return false
       }
       commit('switchToMember', payload)