日期:2026-08-31 状态:已获用户方案确认(方案 A) 关联:
FiveDimensionSelfCheckService/FiveDimensionSelfCheckController/five_dimension_self_checks表
| 检查项 | 结果 | 说明 |
|---|---|---|
| 占位符扫描 | ✅ 无 TODO/待定 | 无 "待定"、"TODO"、"XXX" 字段 |
| 内部一致性 | ✅ 一致 | 后端接口与数据层、前端路径、迁移编号全部对齐 |
| 范围检查 | ✅ 单一功能闭环 | 覆盖:周期判断 / 忽略记录 / 题目轮换 / 前端入口 / 中间页,范围可覆盖 |
| 模糊性 | ✅ 已消除 | 以下歧义已在正文明确:body 维度固定 3 题无法轮换(降级说明);未到期直答保守不阻断(明确决策) |
现有五维家庭自检(P0-1)提供 15 题问卷,用户可无限次重做,首页入口固定展示同一引导文案。本次需求:
totalScore /45)。已确认的决策:
FiveDimensionSelfCheckController(/api/family/self-check):
POST /questions — 返回固定 QUESTION_BANK(15 题)POST /submit — 提交答案、计分、落库POST /latest — 最近一次结果POST /history — 历史记录FiveDimensionSelfCheckService:
QUESTION_BANK:ids 1-15,每维度 3 题,A=3/B=2/C=1/D=0,维度满分 9,总分满分 45SUB_DIMENSION_QUESTION_BANK:ids 101-119,A=100/B=66/C=33/D=0(百分制),当前无任何前端/Controller 调用(死代码,合并无破坏)submitSelfCheck 中写死遍历 QUESTION_BANK 分组five_dimension_self_checks:id / user_id / family_member_id / answers_json / scores_json / total_score / advice_json / created_at| 页面 | 现状 |
|---|---|
pages/index-home/index.vue |
selfTestSub 显示沙盘综合得分(非自检总分);点击跳答题页 |
pages/home-pages/parent-index.vue |
五维家庭自检入口卡片 → 直接跳答题页 |
pages/family/self-check.vue |
答题页(15 题分组渲染) |
pages/family/self-check-result.vue |
结果页(雷达图 + 维度分 + 寻源建议 + 「重新自检」按钮) |
utils/api.js |
已有 getSelfCheckQuestions / submitSelfCheck / getSelfCheckLatest / getSelfCheckHistory |
five_dimension_self_checks 新增列ALTER TABLE five_dimension_self_checks
ADD COLUMN question_ids_json VARCHAR(255) COMMENT '本次自检使用的题号JSON: [1,5,9,101,...]';
用途:记录本次抽到的题目集合,供下次轮换排除,并供 /status 返回 lastQuestionIds。
self_check_ignoresCREATE TABLE IF NOT EXISTS self_check_ignores (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL COMMENT '用户ID',
check_id BIGINT COMMENT '忽略的哪次自检记录ID(可空)',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '忽略时间',
INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维自检忽略提醒记录';
用途:记录「忽略本次提醒」动作,作为 15 天周期重置依据。
lastDecisiveTime = max(最近一次自检.created_at, 最近一次忽略.created_at)
canCheck = (now - lastDecisiveTime) >= 15 天
daysLeft = 15 - (now - lastDecisiveTime) 天数(未到期时 >0)
hasCheck=false,直接进入答题。POST /api/family/self-check/status请求:空 body(从 JWT 取 userId)。
响应 Result<Map>:
{
"hasCheck": true,
"lastResult": { "id": 12, "totalScore": 32, "dimensions": [...], "createdAt": "..." },
"canCheck": true,
"daysLeft": 0,
"lastQuestionIds": [1, 2, 3, 101, 5, ...]
}
lastResult:最近一次 SelfCheckResultVO(无记录时为 null)lastQuestionIds:最近一次 question_ids_json 解析(无记录时为 [])POST /questions — 随机抽题逻辑:服务层新增 getQuestionsForRetake(userId):
question_ids_json → lastQuestionIds(无记录视为空集)。QUESTION_BANK + SUB_DIMENSION_QUESTION_BANK(34 题),按 dimension 分组。lastQuestionIds;若排除后不足 3 题(body 仅 3 题),允许复用上次题号补足。各维度可用题数:body=3(固定)、wisdom=4、wealth=5、action=15、mind=7。
保证:整体 15 题与上次不完全一致(body 可能重复,其余维度必然有变化;若用户上次已做过全部可用题,按随机抽取仍尽量不同)。
POST /submit — 按提交题号计分 + 落库题号QUESTION_BANK,改为从合并池按提交的 questionId 定位题目 → 取 dimension → 计分(A=3/B=2/C=1/D=0,E=跳过)。维度分组逻辑保持不变(每维度至少答 1 题,按实际答题数折算到 9 分制)。question_ids_json(= 本次提交答案中的 questionId 去重升序列表)。onboardingService.completeTask、unlockGateService.refresh*)保持不变。POST /api/family/self-check/ignore请求:{ "checkId": 12 }(可空)。
逻辑:
nextRemindAt)。self_check_ignores(user_id, check_id, created_at=now)。{ "nextRemindAt": "2026-09-15T00:00:00" }(= now + 15 天)。pages/index-home/index.vue + pages/home-pages/parent-index.vue:
getSelfCheckStatus()。最近得分 {totalScore}/45 分 · 点击查看(替代现有沙盘分或补充分数)。self-check-entry(不再直跳答题页)。pages/family/self-check-entry.vueonLoad 调 /status,按状态分流:
| 状态 | 展示 | 操作 |
|---|---|---|
hasCheck=false |
「开始自检」 | 直接跳 self-check 答题页 |
hasCheck=true && canCheck=true |
上次结果摘要(总分 + 五维分数)+ 提示「已满 15 天」 | 按钮「再次自检」→ self-check;按钮「忽略本次」→ 调 /ignore → toast「已忽略,15 天后再次提醒」→ 返回上一页 |
hasCheck=true && canCheck=false |
上次结果摘要 + 「X 天后可再次自检」 | 仅返回按钮 |
self-check-result.vue 的展示结构(简化版:总分横幅 + 五维分数条),避免整页复制。pages.json 注册(pages/family/ 分包下,navigationBarTitleText: "自检")。pages/family/self-check.vue — 保持答题页onLoad 调 /questions(后端已随机),渲染逻辑不变。pages/family/self-check-result.vueuni.navigateTo('/pages/family/self-check-entry')(先走状态判断)。utils/api.js 新增export function getSelfCheckStatus() {
return request('/api/family/self-check/status', 'POST', {})
}
export function ignoreSelfCheck(data) {
return request('/api/family/self-check/ignore', 'POST', data)
}
| 场景 | 行为 |
|---|---|
| 忽略幂等 | 15 天内重复忽略不重复插入,返回最新 nextRemindAt |
| 题目不足 | body 维度仅 3 题,排除后不足则复用,不报错 |
| 未到期直答 | 用户绕过中间页直接进 self-check 页,/questions 仍返回随机题,/submit 不阻断(保守策略,前端入口已挡) |
| 历史老记录 | 老记录 question_ids_json 为 NULL → 视为空集,首次轮换全量随机 |
| 子维度题库 | 合并仅用于主题自检抽取与计分;原 getSubDimensionQuestions / submitSubDimensionCheck 为死代码,保持不变 |
当前最大迁移编号:268(coupon.status)。本次新增 269/270,递增连续。
迁移269: five_dimension_self_checks 表添加 question_ids_json 列(ensureColumn)迁移270: 创建 self_check_ignores 表(CREATE TABLE IF NOT EXISTS)并同步更新 schema.sql:
five_dimension_self_checks 建表语句补 question_ids_json 列self_check_ignores 建表语句mvn clean compile 通过;逻辑测试覆盖(如 FiveDimensionSelfCheckService 抽题/计分变更点)。node --check 语法校验;HBuilderX 重新打包(Agent 不自行 build)。后端
entity/FiveDimensionSelfCheck.java(新增 questionIdsJson 字段)mapper/FiveDimensionSelfCheckMapper.java(不变,必要时加 ignore 查询)service/FiveDimensionSelfCheckService.java(抽题、计分改造、status/ignore)entity/SelfCheckIgnore.java + mapper/SelfCheckIgnoreMapper.javacontroller/family/FiveDimensionSelfCheckController.java(新增 status/ignore)config/DatabaseInitializer.java(迁移 269/270)resources/schema.sql(同步)前端
pages/family/self-check-entry.vue(新增)pages/index-home/index.vue、pages/home-pages/parent-index.vue(入口显示分数 + 跳中间页)pages/family/self-check-result.vue(重新自检改跳中间页)pages.json(注册中间页)utils/api.js(新增两个方法)