9.5 KiB
9.5 KiB
任务 08 检查记录:刷题与结果闭环
日期:2026-09-01
交付内容
后端(Handler + Schema + Routes)
server/src/handlers/practice.ts(重写核心闭环)modules:返回五大模块与题量(保留)。start:支持两种组卷——- 普通组卷:按模块 +
duration(5/10/15 分钟)经DURATION_TO_COUNT换算题量随机抽取;题库不足时返回全部并打乱(实测数量关系仅题 4,total=4 而非 5)。 - 自定义组卷:
body.custom指定题目 ID 列表(去重、校验存在、上限 20 题、返回首题模块),mode='custom'。
- 普通组卷:按模块 +
currentQuestion:按session.recordIndex + 1推进取当前题;已答完返回{ question: null };不返回答案与解析;新增返回answered/durationMinutes。answer:写入作答记录 + 递增recordIndex。幂等防重复(同sessionId+questionId已存在返回accepted:false, duplicate:true,不重复计入);防乱序(非当前题返回 409「题目与会话作答顺序不符」);返回correct/correctAnswer/analysis供单题即时反馈。finish:按已作答题计分(未作答不计入正确率),返回total/answered/correctCount/accuracy/durationSeconds/wrongQuestionIds/questions[];标记会话finished并写endedAt。wrongReasons(新增):最近 30 天错因聚合计数 + 占比,供刷题中心「错因分布」卡片。
server/src/schemas/entities.ts:PracticeSessionSchema新增recordIndex(默认 -1)。server/src/schemas/api.ts:PracticeStartBodySchema新增可选custom;PracticeSessionViewSchema新增total;PracticeQuestionResponseSchema的question改为.nullable()并新增answered/durationMinutes;PracticeAnswerResponseSchema新增correct/correctAnswer/analysis;PracticeFinishResponseSchema新增answered;新增PracticeWrongReasonsResponseSchema。server/src/routes.ts:新增GET /api/practice/wrong-reasons(刷题 tag),路由数 35→36。
前端(View + API)
client/src/api/index.ts:新增类型PracticeSessionStart/PracticeQuestion/PracticeAnswer/PracticeFinish/PracticeWrongReasons;practiceApi新增wrongReasons()。client/src/views/practice/PracticeView.vue(重写,原为 ComingSoon):刷题中心,含「刷题 / 错题本 / 申论」三 tab(按路由高亮)。- 刷题 tab(对照原型):选择模块(5 卡 + 掌握度 + 选中勾)、碎片组卷时长(5/10/15)、开始刷题大按钮(含模块+时长文案)、错因分布(最近 30 天横向条)、待复习错题、推荐动作。
- 错题本 tab:对接
reviewApi.list({status:'pending'}),无数据空态;完整间隔复习属任务 09。 - 申论 tab:ComingSoon 占位。
client/src/views/practice/AnswerView.vue(新增):作答 + 单题反馈 + 整卷结果。- 作答态:顶部返回 +
第X题/共Y题进度条 + 计时 + 关闭;模块/子模块/难度标签;题干;A-D 选项;提交答案。 - 单题结果态:答对/答错横幅(含正确答案 + 「已自动收录到错题本」)、解析卡、AI 讲解按钮、标记错因(可多选,本地选择)、下一题 / 查看本卷结果。
- 整卷结果态:答对题数、正确率、用时、错题回顾(你的答案 → 正确答案 + 解析)、返回刷题中心。
secondsUsed按单题计时(elapsed - questionStartElapsed)而非会话累计。
- 作答态:顶部返回 +
client/src/views/practice/CustomView.vue(新增):自定义组卷——从题库勾选题目(上限 20、已选计数、全选),底部开始练习。client/src/components/base/icons.ts:新增plus/sparkles/refresh/book-open图标。client/src/components/base/AppButton.vue:新增loadingprop(spinner)。client/src/layouts/MobileLayout.vue:/practice相关路径隐藏顶栏标题(页面自带 AppPageHeader,避免标题重复)。client/src/router/index.ts:新增/practice/session/:id(作答)、/practice/custom(自定义组卷)。
与原型图对照
- 「桌面-刷题中心-刷题态.png」:选择模块、碎片组卷时长、开始刷题大按钮、错因分布(最近30天)、待复习错题、推荐动作 —— 结构一致。
- 「移动-刷题-行测Tab.png」:模块卡 + 时长 + 开始刷题按钮 + 底部 TabBar —— 一致(含选中勾选态)。
- 「移动-刷题-作答页.png」:进度条 + 计时 + 模块标签 + 题干 + 选项 + 提交答案 —— 一致。
- 「移动-刷题-结果页.png」:回答错误横幅(正确答案 + 已收录错题本)、解析、AI 讲一讲、标记错因(可多选)、下一题 —— 一致。
接口实测(curl,演示数据)
| 接口 | 结果 |
|---|---|
GET /api/practice/modules |
5 模块题量 {言语理解4, 数量关系4, 判断推理4, 资料分析4, 常识判断2} |
POST /api/practice/start(数量关系 5 分钟) |
返回 sessionId / questionIds / total=4(题库不足 5 取全部)/ startedAt / status |
POST /api/practice/start(custom 3 题) |
「语用理解 demo-q-001/002/003」total=3,mode=custom |
POST /api/practice/start(custom 含不存在题) |
409 CONFLICT:「存在不存在的题目:nope-1」 |
GET /api/practice/:id/question |
返回当前题(无答案/解析)+ index/total/answered/durationMinutes |
POST /api/practice/:id/answer(正确) |
{accepted:true, answeredCount:1, correct:true, correctAnswer, analysis} |
POST /api/practice/:id/answer(重复提交同题) |
{accepted:false, duplicate:true},不重复计入 |
POST /api/practice/:id/answer(乱序提交非当前题) |
409 CONFLICT:「题目与会话作答顺序不符」 |
GET /api/practice/:id/question(答完全部) |
{question:null, index, total, answered} |
POST /api/practice/:id/finish |
{total, answered, correctCount, accuracy, durationSeconds, wrongQuestionIds, questions[]}(部分答错正确率 25%,错题列表正确) |
GET /api/practice/wrong-reasons |
{reasons:[{reason,count,percent}]} 按错因聚合(演示数据各错因 1 条 14%) |
GET /api/practice/wrong-reasons(无数据) |
{reasons:[]} |
浏览器检查(agent-browser)
| 场景 | 结果 |
|---|---|
| 桌面 1440 刷题中心 | 页头按钮 + 3 tab + 选择模块 + 时长 + 开始大按钮 + 错因分布 + 待复习 + 推荐动作,与原型结构对齐 |
| 桌面 1440 作答页 | 进度条 + 计时 + 模块/子模块/难度标签 + 题干 + 选项 + 提交答案,渲染正常 |
| 桌面 1440 单题结果态(答错) | 正确答案绿勾 / 错误答案红显 / 红色「回答错误」横幅(正确答案 + 已收录错题本) / 解析 / AI 讲一讲 / 标记错因(可多选) / 下一题 —— 对齐原型结果页 |
| 桌面 1440 整卷结果页 | 答对 1/4、正确率 25%、用时、错题回顾(答案对比 + 解析)、返回刷题中心 |
| 桌面 1440 自定义组卷 | 已选计数 / 全选 / 题目列表(标签 + 题干)/ 开始练习,勾选交互正常 |
| 移动 390 刷题中心 | 标题单次显示(修 topbar 重复)、模块 2 列卡片、时长、开始大按钮、底部 TabBar,无横向溢出 |
| 移动 390 作答页 | 顶部进度 + 计时、题干、选项、提交答案、底部 TabBar,无遮挡,对齐原型 |
| 计时修正 | secondsUsed 改为单题耗时(修正前误用会话累计时间导致结果页「用时 7 分 24 秒」不合理) |
截图:deliverables/checks/task-08-practice-desktop.png、task-08-practice-desktop-bottom.png、task-08-answer-desktop.png、task-08-answer-result-desktop.png、task-08-result-desktop.png、task-08-custom-desktop.png、task-08-practice-mobile.png、task-08-answer-mobile.png。
完成标准核对(开发计划任务08)
- ✅ 模块选题(5 模块卡片全选)。
- ✅ 5/10/15 分钟组卷(时长→题量)。
- ✅ 自定义组卷。
- ✅ 会话 + 计时(作答页计时,
secondsUsed单题计)。 - ✅ 作答 + 提交(单选、校验当前题)。
- ✅ 结果 + 标准解析。
- ✅ 可从刷题中心或首页开始一套题并完成提交;记录写入 JSON(practice-sessions / practice-records)。
- ✅ 中途刷新恢复(
recordIndex进度推进,currentQuestion按索引取题,刷新后question:null走 finish)。 - ✅ 提交后不能重复计入同一题(
duplicate:true幂等)。 - ✅ 答案、正确率、耗时、完成状态准确。
边界说明
- 「答错自动沉淀错题(写 wrong-questions.json)」属于任务 09。任务 08 的
answer不写错题库,整卷结果与单题结果中的「已自动收录到错题本」为提示文案;错题本 tab 当前仅对接reviewApi.list展示既有错题,完整间隔复习闭环在任务 09 完成。 - 「标记错因(可多选)」当前为前端本地交互,落库归属任务 09 的错题逻辑。
当前结论
任务 08 完成:刷题与结果闭环在前后端打通。普通组卷 + 自定义组卷、会话持久化(recordIndex 进度防重复/防乱序)、单题即时反馈(对错/正确答案/解析/AI 入口/标记错因)、整卷结果(正确率/用时/错题回顾)全部实测通过;新增「错因分布」接口供刷题中心展示;修复移动端标题重复与单题耗时统计。类型检查(vue-tsc / tsc)与生产构建(128 模块)全部通过。测试数据已清理,题库/会话/记录恢复演示基线。