# 任务 10 检查记录:模考分析 日期:2026-09-01 ## 交付内容 ### 后端(Handler + Schema + Routes) - `server/src/handlers/mock.ts`(重写): - `analysis`:返回记录列表(新→旧)、目标分、最近成绩 `latest`、目标分差 `targetGap`(目标分 − 最近成绩)、较上次变化 `changeVsPrevious`(最近 − 上一场)、总分趋势 `trend` 与五个行测模块均分 `moduleAverages`。 - `record`:录入持久化到 `mock-exams.json`(`updateData` 原子写,生成 UUID + createdAt),不再返回未落库的临时对象。 - `update`(新增):按 id 修改记录,保留 id/createdAt,其余字段覆盖。 - `remove`(新增):按 id 删除记录,分析随数据文件同步更新。 - `server/src/schemas/api.ts`:新增 `MockExamIdParamsSchema`、`MockExamUpdateBodySchema`、`MockExamRecordResponseSchema`、`MockExamDeleteResponseSchema`;`MockExamAnalysisResponseSchema` 增加 `latest` / `targetGap` / `changeVsPrevious`。 - `server/src/routes.ts`:新增 `POST /api/mock-exams/:id/update`、`DELETE /api/mock-exams/:id`(模考分析 tag)。 - `server/src/server.ts`:修复 CORS 预检方法白名单(原默认仅 GET/HEAD/POST,导致浏览器端 DELETE/PATCH 被拦;现显式允许 GET/HEAD/POST/PATCH/DELETE,同时修复题库删除与计划切换的浏览器调用)。 ### 前端(View + API) - `client/src/views/mock/MockView.vue`(替换 ComingSoon 占位): - 顶部「录入成绩」入口;加载/错误/空数据三态。 - 空态:标题「还没有模考成绩」+ 描述 + 「录入第一场模考」CTA。 - 统计卡:最近成绩(名称 + 日期)、目标分差(达标显示「已达目标」)、较上次变化(±分)。 - 行测成绩趋势(`AppLineChart`,虚线为目标分)。 - 模块均分对比(五模块横向进度条)。 - 模考记录列表(名称、日期、总分徽章、五模块小分、备注)+ 编辑 / 删除(删除弹确认框,二次确认)。 - `client/src/views/mock/MockFormView.vue`(新增):成绩录入/修改共用表单。 - 字段:模考名称、日期、五个模块分数(0–100)、备注;总分由五模块自动汇总展示。 - 校验:名称必填、日期必填、模块合计 ≤ 100(超限给出中文提示)。 - 创建走 `POST /api/mock-exams/record`,编辑走 `POST /api/mock-exams/:id/update`,保存成功 toast 后返回分析页。 - `client/src/api/index.ts`:`mockApi.update` / `mockApi.remove`;导出 `MockExamRecord` / `MockExamAnalysis` / `MockExamListItem` 类型。 - `client/src/router/index.ts`:新增 `/mock/new`(录入)、`/mock/:id/edit`(修改)。 - `client/src/components/base/icons.ts`:新增 `line`(趋势线)图标。 ## 接口实测(curl,演示数据) | 接口 | 结果 | |---|---| | `GET /api/mock-exams/analysis` | 5 条记录;latest=67;targetGap=5(目标 72);changeVsPrevious=+3;trend 5 点;五模块均分正确 | | `POST /api/mock-exams/record` | 新增记录持久化,analysis 变为 6 条、latest=70、gap=2 | | `POST /api/mock-exams/:id/update` | 名称/分数/备注覆盖,保留 id/createdAt | | `DELETE /api/mock-exams/:id` | 删除后 analysis 回到 5 条、latest 回 67 | | 空数据 analysis | `records:[]`、latest/targetGap/changeVsPrevious 为 null、trend 空 | | 非法输入 | 缺 name / 分数 120 → 统一 `VALIDATION_ERROR`;不存在记录 update/delete → `NOT_FOUND` | | 重启持久化 | 新增记录重启后仍存在,分析正确(6 条 / latest=69 / gap=3 / +2) | ## 浏览器检查(Chrome headless + CDP) | 场景 | 结果 | |---|---| | 桌面 1440 模考分析 | 统计卡(最近 67 / 还差 5 分 / +3 分)、趋势图、模块对比、5 条记录、录入成绩按钮 | | 录入流程 | 填名称/日期/五模块 → 总分自动汇总 70 → 保存 → 回分析页显示 6 条、最近 70 分 | | 编辑流程 | 点击「编辑」→ 表单回填 → 改名称/分数 → 保存 → 列表同步更新 | | 删除流程 | 点击「删除」→ 确认弹窗 → 「确认删除」→ 列表回 5 条、最近成绩回 67 | | 空态 | 「还没有模考成绩」+「录入第一场模考」CTA 正常展示与跳转 | | 表单校验 | 空名称提示「请填写模考名称」;五模块合计超 100 提示不能超过 100 分 | | 移动 390 | 模考分析页与录入页均无横向溢出(390/390) | | 首页回归 | 数据中枢「最近模考」卡与趋势联动正常(67 分 / +3 / 还差 5 分) | 截图:`deliverables/checks/task10-mock-desktop.png`、`task10-entry-desktop.png`、`task10-mock-mobile.png`、`task10-entry-mobile.png`、`task10-mock-empty-mobile.png`。 ## 完成标准核对(开发计划任务10) - ✅ 行测模考录入(record 持久化 + 录入页)。 - ✅ 列表(模考记录,含编辑/删除)。 - ✅ 趋势(≥2 条记录生成折线趋势,含目标参考线)。 - ✅ 模块分数(五模块录入与均分对比,仅行测字段)。 - ✅ 目标分差(targetGap)与较上次变化(changeVsPrevious)。 - ✅ 无数据空状态(后端 null 字段 + 前端空态 CTA)。 - ✅ 删除或修改记录后分析同步更新(实测录入→6 条、删除→5 条、编辑同步)。 - ✅ 类型检查(vue-tsc / tsc)与生产构建(135 模块)通过;`api:generate` 与 OpenAPI 一致。 ## 边界说明 - 总分由前端按五模块自动汇总(演示数据 total = 模块和,保持一致);后端仅做 0–100 范围校验,不强制模块和等于 total。 - CORS 方法白名单修复属于本任务联调发现的前置缺陷(浏览器端 DELETE/PATCH 预检被拒),一并修复并回归题库删除、计划切换。 ## 当前结论 任务 10 完成:行测模考录入、列表、趋势、模块分数、目标分差、较上次变化、空状态与删除/修改联动全部实测通过;桌面与移动双端可操作;测试数据已恢复演示基线。