From 8de35e85c2d86711f36d71b765feebd7ec5bf6eb Mon Sep 17 00:00:00 2001 From: jacobxu666 Date: Thu, 20 Aug 2026 13:38:46 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=BB=93=E6=9E=84=E5=8C=96=E9=A2=98?= =?UTF-8?q?=E7=9B=AE=E7=BC=96=E8=BE=91=E5=99=A8+=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E9=A2=98=E7=AD=94=E6=A1=88=E5=88=A4=E5=88=86=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 题型联动表单替代 JSON 文本域(首发 judge/choice/fill/solve); 应用题新增 judgeMode=answer(最终答案数组+归一化匹配秒判),rubric AI 判分共存。 Co-Authored-By: Claude Haiku 4.5 --- ...08-20-structured-question-editor-design.md | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-20-structured-question-editor-design.md diff --git a/docs/superpowers/specs/2026-08-20-structured-question-editor-design.md b/docs/superpowers/specs/2026-08-20-structured-question-editor-design.md new file mode 100644 index 0000000..aeecfe2 --- /dev/null +++ b/docs/superpowers/specs/2026-08-20-structured-question-editor-design.md @@ -0,0 +1,92 @@ +# 结构化题目编辑器 + 应用题答案判分模式 - 设计文档 + +日期:2026-08-20 +状态:已批准 + +## 背景 + +`/parent/exams/[paperId]` 编辑页目前用**裸 JSON 文本域**录入题目,家长需手写 quiz JSON 数组(曾明确拒绝结构化表单,现转向)。同时用户对应用题判分提出新模式:孩子拍照上传解题过程 + 填写最终答案来判定对错(替代/补充现有 AI 逐评分点判分)。 + +现状事实(grilling 确认): + +- 现有 86 道种子题 = choice 48 + fill 30 + solve 8,**judge/order/match 零数据**。 +- solve 题现状:孩子拍照 → 百炼 Qwen-VL 按 rubric 评分点逐点判分(ai-grade.ts,无 key 演示回退),照片与逐点判定进错题本。 +- 孩子端 QuizBlock 已支持全部 6 题型答题 + 对错反馈;fill 题的参考答案本身是**数组**(answers)。 +- 现有 svaeEqxamPaper 的 validateQuestionsJson 已做形状校验。 + +## 需求(已与用户确认) + +1. **结构化编辑器**:试卷题目改为逐题表单(题型联动字段),不再手写 JSON。题目卡片流:新增/编辑/删除/上移/下移。 +2. **首发四种题型**:判断题/选择题/填空题/应用题(judge/order/match 暂不做,有数据时后置)。 +3. **应用题新增判定模式** `judgeMode: "answer"`:家长只填**最终答案数组**(复用 fill 的 answers 语义)+ 分值;孩子拍照解题过程 + 填最终答案,**归一化匹配秒级判对错**,不调 AI。 +4. **共存**:现有 rubric 模式(AI 逐点评分)保留,存量 8 道题零改动(`judgeMode` 缺省 = rubric)。 +5. 孩子端此模式下:拍照必填(进错题本),最终答案判对错;对 = 满分,错 = 0 分(不做部分给分,可解释)。 + +## 方案选择 + +- **方案 A(采用):结构化表单产出仍是 QuizQ JSON,存储/孩子端渲染零schema改动** + - 编辑 UI 从 JSON textarea 换成题型联动表单;服务端校验扩展 judgeMode 分支;判分在现有 child 提交链路内按 judgeMode 分流。 +- 方案 B(弃):引入独立"题目表"(questions 拆表)→ 迁移 86 题、错题本/组卷/判分全部重写,收益为零。 +- 方案 C(弃):AI 判最终答案(取代归一化)→ 有延迟、依赖 key、判定无法对孩子解释;归一化数组对家庭场景足够。 + +## 设计 + +### 1. QuizQ 扩展(src/lib/quiz-parse.ts) + +```ts +// solve 新增可选字段(缺省即 rubric 老模式,向后兼容): +judgeMode?: "rubric" | "answer"; +// judgeMode==="answer" 时复用: +answers?: string[]; // 最终答案数组(与 fill 同字段语义,等价答法都填) +// points 两种模式下都必须(分值);reference 为展示用参考解答 +``` + +### 2. 归一化判定 lib(新建 src/lib/answer-match.ts) + +```ts +// xuchao: 答案等价判定——数值类归一化(分数/小数/百分数互转),文本类去空格/全角/大小写 +export function normalizeAnswer(s: string): string; +export function answersMatch(expected: string[], given: string): boolean; // 任一期望答案等价即中 +``` + +- 纯数字语义(`1/2`→`0.5`、`50%`→`0.5`、`0.50`→`0.5`,去尾零)互转比较。 +- 含字母/单位词(如 `10个`、`across`)按文本归一(去空白、全角→半角、小写)严格比较;等价形式靠家长在答案数组里补填。 +- **fill 现有判分不动**(grammar.ts `gradeOne`:trim+小写精确匹配)——归一化仅用于 judgeMode==="answer" 的应用题,避免改变既有周测/记录判分行为。 + +### 3. 孩子端判分流(exam/actions.ts takeExam + QuizBlock) + +- `takeExam` 中 solve 题分流: + - `judgeMode==="answer"`:`answersMatch(q.answers, 孩子填的答案)` → score=points(对)/0(错);判定与照片写 `solveSnap`(`hits:[{ point:"最终答案", score, hit, reason }]`),照片 OSS 照常上传。 + - 缺省/`rubric`:走现有 ai-grade 逐点评分,零改动。 +- QuizBlock solve 分支:answer 模式下拍照必填 + 显示最终答案 Input;rubric 模式现状不变。 +- 错题本:**零改动**(solveSnap 结构兼容;answerText 已对 solve 显示拍照与得分)。 + +### 4. 家长端结构化编辑器(/parent/exams/[paperId] 重构) + +- PaperForm 拆为:试卷 MetaForm(现有字段,不动)+ `QuestionList`(题目卡片区)。 +- QuestionList: + - 每题卡片:题型徽标 + 题干摘要 + 操作(编辑/上移/下移/删除)。 + - 「+ 新增题目」按钮;题型下拉(judge/choice/fill/solve 四项)。 + - QuestionForm 按 type 联动: + - **judge**:题干 + 解析 + 对/错单选 + - **choice**:题干 + 选项列表(增/删/编辑,单选正确答案)+ 解析 + - **fill**:题干 + 参考答案数组(增/删/编辑)+ 解析 + - **solve**:题干 + 分值 + judgeMode 开关(rubric → 评分点列表(point/score)+ 参考解答;/ answer → 最终答案数组 + 参考解答可选)+ 解析 + - 非法时客户端给出对应提示(与服务端同文案);保存仍走现有 `saveExamPaper`(JSON 序列化 QuizQ 数组)。 +- 服务端 validateQuestionsJson 扩展: + - solve:rubric 模式沿用现行(reference + points 必填);answer 模式要求 `answers` 非空数组 + points 必填,reference 可选;answer 模式不得带 rubric。 + - 其余题型校验不变。 + +### 5. 不改动 + +- DB schema(quiz JSON 存储不变)、ai-grade.ts、错题本 WrongRow、积分/达标规则、周测组卷。 +- 孩子端之外:seed、overview、记录管理全不动。 + +## 测试清单(手工,项目无自动化测试框架) + +1. 编辑页:JSON 文本域消失,题目卡片流可新增/编辑/删除/上下移/保存。 +2. 四种题型表单字段联动正确;应用题的 rubric/answer 开关切换字段正确。 +3. 新建 answer 应用题(答案 0.5 与 1/2 都填):孩子端拍照 + 填 `1/2` → 判对满分;填 `2/3` → 判错 0 分,错题本含照片与判定。 +4. 存量 rubric 题:孩子照旧拍照 AI 逐点评分,进错题本逐点判定。 +5. 服务端校验:answer 模式缺 answers / rubric 模式缺 reference → 对应报错不保存。 +6. 部署 jump.hn12301.net 后线上复验。 \ No newline at end of file