小学数学试卷生成
用途
把「出数学卷」做成可复现的流程:确定考点边界 → 命题 → 排版 → 几何校验 → 导出 PDF → 附答案与评卷建议。
不靠临时重写代码。版式、分页、护眼字号、填空线和校验全部由 scripts/ 里三个脚本保证,改卷子只需改内容数据。
工作流
第 1 步:确认 5 个参数
不明确就问,不要替用户拍板:
- 年级 + 学期(一上 / 四下 / 六上)
- 教材版本(默认人教版;北师大、苏教单元顺序不同)
- 范围(单元卷 / 期中 / 期末 / 专项:计算、应用题、几何)
- 套数(1 套 / 3 套平行卷 / A·B·C 分层)
- 交付(PDF 打印 / 是否需要答案页)
用户已说清楚的不重复问。都没说时用默认:人教版、当册全部单元、3 套平行卷、PDF + 答案页。
第 2 步:定位考点边界(先读再写题)
打开 references/curriculum.md,按年级找到对应册次,确认三件事:
- 该册的计算范围(首表列出各年级数值边界,是防超纲的第一道闸)
- 该册的题型池(哪些题型可以出)
- 该册的易错点(埋坑用)
禁止跨册出题。一年级不出现乘除,二年级不出现分数,四年级不出现分数乘除。
第 3 步:命题
按 references/exam-design.md 的板块配比定分值,然后写内容数据。
做多套平行卷时,结构、题量、分值必须完全一致,只改内容和难度,不改骨架——否则无法横向比较。
难度分层改三个维度:计算复杂度、情境步数、附加题引导程度。
第 4 步:写生成脚本
在输出目录建一个 build.py,import wstemplate 后拼内容。组件清单:
| 组件 | 用途 | 适用年级 |
|---|---|---|
header(tag, title, time, full) |
卷头 | 全 |
sec(no, title, score) |
大题标题 | 全 |
oral_grid([(a, op, b)]) |
口算四列网格 | 全 |
fenhe(top, left, right) |
数的分合式 | 一 |
brace(total) |
大括号总数图 | 一~三 |
choice_items([(题干, [选项])]) |
选择题(自动单列/三列) | 全 |
pic_items([(图, 空行)]) |
看图列式,两列 | 一~三 |
solve_items([题干]) |
解决问题 | 全 |
tf_items([题干]) |
判断题 | 三以上 |
blank_items([(题干, 分值)]) |
填空题 | 全 |
vertical_box([算式]) |
竖式计算 | 三以上 |
mixed_calc([算式]) |
脱式计算 | 四以上 |
equation_box([方程]) |
解方程 | 五以上 |
op_box(要求, 高mm) |
操作题方格纸 | 三以上 |
table_stat(表头, 行) |
统计表 | 三以上 |
page(内容, 页码, 总页) |
分包一页 | 全 |
answer_page(内容, ...) |
包答案页 | 全 |
以上全部来自 scripts/wstemplate.py(版式引擎,含 CSS 常量与组件),from wstemplate import * 后即可用。
最小示例(一年级):
import sys
sys.path.insert(0, r"<skill目录>/scripts")
from wstemplate import *
p1 = (header("A 卷 · 基础巩固", "一年级数学上册 《1~5的认识和加减法》单元测试", "40 分钟", "100 分")
+ sec("一", "直接写出得数", "每题1分,共20分")
+ oral_grid([(2, '+', 2), (5, '-', 2), (1, '+', 2), (0, '+', 3)])
+ sec("二", "填一填", "共32分")
+ '<div class="q"><span class="lb">1.</span>(4分)照样子,填一填。</div>'
+ '<div class="row" style="margin-left:4mm">' + fenhe(5, '2', '( )') + fenhe(4, '( )', '1') + '</div>')
write_html("A卷.html", page(p1, 1, 3), title="一年级数学 A 卷")
第 5 步:校验并导出(必做,不可跳)
python scripts/render_pdf.py A卷.html --check-only # 先只校验,改版式时反复跑
python scripts/render_pdf.py A卷.html --heights # 逐块看占高,规划分页
python scripts/render_pdf.py A卷.html # 通过后导出 PDF
校验会报:纵向溢出、横向截断、块重叠、SVG 字太小、填空线异常。
为什么必须校验:页高固定 275mm 加 overflow:hidden,内容超了会被静默裁掉,PDF 看上去正常但题目缺一半。肉眼扫 PDF 极易漏掉,只能靠几何测量。
导出时会自动比对「PDF 页数 = HTML 页数」,不一致说明有页被挤爆。
页面可用高度 1039px(275mm)。写内容前先查 references/layout-metrics.md 的实测占高表,能省掉大量来回调版的时间——最典型的一条:vertical_box 的占高由行数决定而不是题数,2 列 4 题和 3 列 6 题占高一样,要省高度就加列。
第 6 步:多套合并(可选)
python scripts/merge_pdf.py -o 合集.pdf --scan ./输出目录
按卷面内容排序:先按年级(一年级→六年级),同年级内再按 A/B/C 卷,不按文件名——文件名可能被改过导致串页。合并后自动校验页尺寸一致性,并提示同年级同套次是否出现重复文件。
硬性要求
- 答案页必须写:完整列式 + 单位 + 答语;多解题注明「答案不唯一」并给可接受答案;易错点解释;部分分规则
- 低年级必须给引导话术:分步提问,不直接给答案。超纲知识点(如一年级遇到乘法)换成直观经验,不要求规范算法
- 附加题 10 分不计入总分,多套卷的引导强度递减(给示范 → 给一半 → 全自主)
- 正文字号 ≥ 12pt,一年级尤其不能小
- 题目数值自洽:单价 × 数量 = 总价、统计表合计 = 各项和、应用题能整除
- 不超纲:写完逐题对照 curriculum.md 的数值边界表
交付后
把 HTML 和 PDF 都留在输出目录,build.py 一并保留,方便用户改题重跑。告诉用户答案页在第几页、打印时是否要剔除。