Parcourir la source

fix(tasks): 任务列表页默认展示本人任务,与首页「我的任务」同口径

根因:FamilyMemberVO.setId 将 id 同步给 familyMemberId,source='parent'
(users 表家长账号、无 family_members 行)的本人行 id 为 users.id,不属于
family_members 主键空间。任务列表页把它当 memberId 传给 getTodayTasks,后端
按 family_member_id = users.id 过滤,恰好命中同 id 的其他家庭成员任务。

修复(仅 pages/tasks/tasks.vue,后端不动):
- resolveSelfMemberId:source='parent' 时 selfMemberId 置 null,改由后端 JWT
  currentMemberId 兜底
- loadInitialData:默认视图不再预设 selectedMemberId,loadTodayTasks() 不带
  memberId,与首页「我的任务」走完全相同的路径
- onMemberSelect:任何 isSelf 一律 selectMember(null),「本人」chip 由
  self-active="!selectedMemberId" 保持高亮
- isOwnTask:改为按当前查看对象判断,查看其他成员且 selfMemberId 不可解析时
  视为他人任务,保留「仅能完成自己的」护栏(后端 completeTask 成员不匹配时
  仍幂等返回、不改数据不发奖)
zxyj-web il y a 2 semaines
Parent
commit
55f1856fad
1 fichiers modifiés avec 24 ajouts et 10 suppressions
  1. 24 10
      cfc-frontend/pages/tasks/tasks.vue

+ 24 - 10
cfc-frontend/pages/tasks/tasks.vue

@@ -323,7 +323,15 @@ export default {
       for (var i = 0; i < members.length; i++) {
         if (members[i] && members[i].isSelf) {
           // 统一身份键:familyMemberId(family_members.id),不再用 userId
-          this.selfMemberId = memberIdOf(members[i])
+          // 注意:source='parent' 的本人(users 表家长账号,无 family_members 行)其 id/memberId 是
+          // users.id,不属于 family_members 主键空间,直接把 users.id 当 memberId 传给 getTodayTasks
+          // 会命中「恰好同 id」的其他家庭成员任务(默认列表显示成别人的任务)。
+          // 与 onMemberSelect 的「本人」分支保持同一口径:置 null 交由后端 JWT currentMemberId 兜底。
+          if (members[i].source === 'parent') {
+            this.selfMemberId = null
+          } else {
+            this.selfMemberId = memberIdOf(members[i])
+          }
           return
         }
       }
@@ -332,9 +340,11 @@ export default {
     // 统一组件选中回调:member 已由 memberNormalize 规范化,携带 canonical memberId
     onMemberSelect(member) {
       if (!member) return
-      // 「本人」且来源为 users 表家长账号(无 family_members 行)时,memberId 不属于
-      // family_members 主键空间,传 null 让后端按 JWT currentMemberId 兜底(保持原行为)
-      if (member.isSelf && member.source === 'parent') {
+      // 选中「本人」统一走后端 JWT currentMemberId 兜底,与首页「我的任务」同口径:
+      // · source='parent' 的本人(users 表家长账号,无 family_members 行)其 id 是 users.id,
+      //   不属于 family_members 主键空间,直接传会造成 task.family_member_id=users.id 误匹配他人任务
+      // · source='family_member' 的本人传显式 id 与 JWT 解析同值,统一置 null 更稳(双击成员表头同步高亮)
+      if (member.isSelf) {
         this.selectMember(null)
         return
       }
@@ -346,9 +356,14 @@ export default {
       this.activeTab = 'today'
       this.loadTodayTasks(this.selectedMemberId)
     },
-    // 是否本人的任务:兜底防呆(列表本身已按本人拉取,防御脏数据)
+    // 是否本人的任务:兜底防呆(列表本身已按归属过滤,防御脏数据/越权完成)
     isOwnTask(task) {
-      if (!task || this.selfMemberId == null || task.familyMemberId == null) return true
+      if (!task) return true
+      // 「本人」视图(未选中其他成员):列表由后端按 JWT currentMemberId 过滤,均为本人任务
+      if (this.selectedMemberId == null) return true
+      // 查看其他成员视角:可解析 selfMemberId 时精确比对;
+      // source='parent'(无 family_members 行)解析不出自身 memberId → 一律视为他人任务
+      if (this.selfMemberId == null || task.familyMemberId == null) return false
       return String(this.selfMemberId) === String(task.familyMemberId)
     },
     // 方案来源标签装饰:加载后预计算(小程序模板禁止在 :class 内做方法调用)
@@ -402,10 +417,9 @@ export default {
         var normalized = normalizeMembers(raw, { userId: this.currentUserId })
         this.familyMembers = Array.isArray(normalized) ? normalized : []
         this.resolveSelfMemberId()
-        // 「本人」行默认激活(未选成员时由后端按 JWT currentMemberId 兜底)
-        if (!this.selectedMemberId && this.selfMemberId != null) {
-          this.selectedMemberId = this.selfMemberId
-        }
+        // 默认「本人」视图:不显式传 memberId,交由后端按 JWT currentMemberId 兜底,
+        // 与首页「我的任务」完全同一口径(避免把 users.id(source='parent' 家长行)
+        // 或重复 family_members 行的 id 误当过滤条件 → 拉到别人任务)
         this.loadTodayTasks()
         this.loadPendingTasks()
         this.loadCreatedTasks()