707ea09ad(修复改动全部在工作区未提交)| # | 核验项 | 结论 |
|---|---|---|
| 1 | 问题4 sleep-checkin.vue formatDate 修复(模板/方法/import 配对 + 编译) | PASS |
| 2 | 问题1/3 根因修复(三个健康 Controller 成员归属修正 + 打卡页 memberId 解析 + index-home 传参) | PASS |
| 3 | 问题2 tasks.vue 成员 chips/切换/权限提示 | PASS |
| 4 | 静默失败修复(TaskController null 分支 + 前端调用点提示) | PASS |
| 5 | 编译(后端 mvn / 前端 node --check / 模板编译) | PASS |
| 6 | 数据流推演(睡眠打卡端到端闭环) | PASS |
| 7 | 改动范围(9 个本需求文件 + 历史遗留项隔离) | PASS |
| 附 | API 错误传播形态补充确认(决定静默失败是否真的可见) | PASS |
cfc-frontend/pages/growth/sleep-checkin.vue:147 — {{ formatDate(item.createdAt) }}cfc-frontend/pages/growth/sleep-checkin.vue:321 — formatDate: function(d) { return formatDateUtil(d) }cfc-frontend/pages/growth/sleep-checkin.vue:161 — import { formatDate as formatDateUtil } from '../../utils/format.js'formatDateUtil(不再与方法名冲突),methods 的 formatDate 包装导出,三者形成 模板 → method → import 别名 的正确链条。这也解释了根因:修复前模板调用 formatDate 会在原型链上踩中 util 导出,修复前版本缺少 methods 暴露导致 _vm.formatDate is not a function。<script> 块 node --check 全部 exit 0(sleep/diet/exercise/tasks 4 个文件);vue-template-compiler 编译 5 个文件模板均 0 error(filter 掉 "side-effects/ multiple nodes" 通用性提示后为 0)。cfc-backend/src/main/java/com/etotem/cfc/controller/HealthSleepController.java:75-80cfc-backend/src/main/java/com/etotem/cfc/controller/HealthMealController.java:257-262(同 diff 位置)cfc-backend/src/main/java/com/etotem/cfc/controller/HealthExerciseController.java:97-102(同 diff 位置)条件判定完整:linkedTask != null(外层 selectById 判断)+ record.getTaskId() != null + linkedTask.getFamilyMemberId() != null + record.getMemberId() != null + !familyMemberId.equals(memberId) 五重条件齐备才 setMemberId,置于 taskService.updateCheckinTaskProgress / completeTask 调用之前,后续回写天然使用修正后的 memberId。
sleep-checkin.vue:303 / diet-checkin.vue:222 / exercise-checkin.vue:216 三处均改为:
this.memberId = options.memberId || uni.getStorageSync('currentMemberId') || null
grep 确认三文件已无 currentChildId、userId 兜底残留。cfc-frontend/pages/index-home/index.vue:1583-1592:diet/sleep/exercise 三个分支均追加 &memberId=(task.familyMemberId || task.executorId || '')。cfc-backend/.../entity/Task.java:20(familyMemberId) 与 :28(executorId) 确认存在;同文件 index.vue:1541 已有既有用法 var memberId = (task && task.familyMemberId) || null 佐证字段名非臆造。tasks.vue:11-14 v-for familyMembers + :key="member.id"(无表达式 key)+ @click="selectMember(member.id)";data selectedMemberId: null(tasks.vue:266)。tasks.vue:326-330 — 设 selectedMemberId、activeTab = 'today'、调 loadTodayTasks(this.selectedMemberId)。tasks.vue:377-386 — arguments.length > 0 ? memberId : this.selectedMemberId,显式传参生效;不传参(switchTab:345 / loadInitialData:358)回落到 selectedMemberId 再兜底 JWT。api.js:705-714 确认 body.memberId 仅在非空时写入。completeTask(tasks.vue:415-418 isOwnTask 提示 + 421-425 res.code!==200 toast + 430-432 data 兜底)+ handleTaskAction(tasks.vue:459-462)+ submitWithInput(tasks.vue:555-559 + 562-573)三处入口均有 isOwnTask 拦截;非本人任务仍渲染(列表按 targetMemberId 全量返回),仅点击按钮才提示「只能完成自己的任务」——符合"可看不可操作"要求。loadCreatedTasks(tasks.vue:387-399)走 familyWide + creatorId 过滤,逻辑未动;pending tab(368-376)未变;isOwnTask 在 selfMemberId == null 或 task.familyMemberId == null 时 return true(338行注释即说明此兜底防呆语义),未破坏既有 tab。?.、无 toLocaleString、:key 无运算符表达式。TaskController.java:118-140 — result != null → Result.success(result);result 为 null 时(service 585-593 行已确认 null 语义:任务不存在 / !Objects.equals(task.getFamilyMemberId(), memberId) / 已完成或待审核 / 需前置校验等)返回 Result.error("任务不存在、无权完成或状态已变更")。原 Result.success(null) 已替换。index-home/index.vue:1542-1557 quickCompleteTask — res.code === 200 分支保留三态 toast,else 分支 toast res.message,.catch toast「完成失败,请重试」。tasks.vue:421-425 / tasks.vue:562-565 completeTask/submitWithInput — res.code !== 200 → toast res.message,catch 内 toast。uni.showToast(res.data.message) + reject(res.data)。即后端 Result.error(code=500)必然经 toast 或 catch 落到用户可见,静默失败链条已断。res.code !== 200 分支实际主要覆盖 5001(noFamily) 等 resolve-型错误码;属双保险,无害。cd cfc-backend && mvn clean compile -DskipTests -q → MVN_EXIT=0,无 ERROR。node --check 全 exit 0;vue-template-compiler 编译 5 个文件(睡眠/饮食/运动打卡页 + tasks + index-home)模板 0 error。推演路径(家长 storage 残留 currentChildId 场景):
quickCompleteTask(index.vue:1528-1537)判定 actionType=sleep → navigateByLinkedAction → URL sleep-checkin?taskId=X&memberId=<本人成员ID>(1587-1589,task.familyMemberId 优先,已证字段存在)。sleep-checkin.vue:303 onLoad:options.memberId || currentMemberId || null → 取 URL 中的本人成员ID,currentChildId 失效。HealthSleepController.create(59-118):record.memberId=本人 → taskId 非空 → linkedTask 非空且 familyMemberId==本人 → 归属一致,无需修正 → isDailyProgress==1 → updateCheckinTaskProgress(taskId, fm.getUserId(), fm.getId(), 1)。TaskService.java:1784-1848:成员校验 member.getUserId()==userId ✅、task.getFamilyMemberId().equals(familyMemberId) ✅ → 进度累加 → 达标调 awardTaskCompletionRewards 置 completed。_refreshOnShow → loadTodayTasks(1122-1140):个人列表该任务 status=completed 不再 pending → 卡片消失;familyTodoCount = countFamilyPendingInProgress(...)(1149-1157,只数 pending/in_progress)→ 家庭任务数 -1。根因闭环说明:修复前若 storage 有 currentChildId,打卡页 memberId 取孩子成员,record 与 task 归属错配,updateCheckinTaskProgress 在 1784-1798 校验被拒返回(任务不完成、卡片不消失、计数不减);修复后 URL 传 memberId + 后端归属修正双保险,校验通过,行为符合预期。
一次性(非每日进度)睡眠任务同样闭合:走 87-95 completeTask 分支,memberId 已按 linkedTask 修正,与 service:587 的 Objects.equals(task.getFamilyMemberId(), memberId) 对齐,可正常完成。
git diff --stat HEAD 共 14 个修改文件,逐一对照:
本需求 9 个(4 后端 + 5 前端):
历史遗留未提交项(不算本需求,提交时应排除):.gitignore、cfc-backend/pom.xml、cfc-web/AGENTS.md、docs/参考资料/知识库/统一知识库.json、tools/xaf_agent_hub/tasks_backlog.json。另还有一批 untracked 历史遗留(cfc-langgraph/AGENTS.md、cfc-web/docs/、out/ 等),均与本需求 diff 无关。
未发现本需求文件内含与 4 问题无关的改动:tasks.vue 的 563 行 diff 含较大模板重构(卡片化重设计),属问题2 成员 chips UI 改造的连带样式调整,功能侧(成员选择/权限/提交链)与需求相关,视为合理。
git add 上述 9 个文件,避免把 pom.xml/AGENTS.md/tasks_backlog.json 等历史遗留项卷入本需求提交。