山东大学试卷风格制作技能
将课程重点内容自动编排为山东大学标准版式试卷,输出 HTML + PDF,可用于任意专业课期末考试复刻。
适用场景
- 现代电力电子变换技术、现代通信原理、电力系统分析等任意专业课期末试卷
- 期中/期末/补考/重修卷,支持 A/B/C 多卷
- 题型数量和分值结构完全可配置(不限于三种题型)
工作流程
步骤 1:收集试卷信息
向用户确认或从用户输入中提取:
| 字段 | 说明 | 示例 |
|---|---|---|
| school | 学校名称 | 山东大学 |
| course_name | 课程名 | 现代通信原理 |
| academic_year | 学年 | 2025-2026学年 |
| semester | 学期 | 第2学期 |
| paper_codes | 试卷编号 | ["A", "B"] |
| score_structure | 题型与分值结构 | 见下方示例 |
| exam_note | 注意事项 | 默认即可 |
| coverage_keywords | 重点覆盖词 | 从用户重点列表提取 |
| question_content | 题目与答案 | 由用户给出或按重点出题 |
步骤 2:创建输出目录与数据文件
<输出目录>/
├── exam_data.json # 结构化题库
├── sdu_exam_template.html # 从本技能 assets/ 复制
├── render_exams.py # 从本技能 scripts/ 复制
├── <课程名>期末试卷A卷.html
├── <课程名>期末试卷A卷.pdf
├── <课程名>期末试卷B卷.html
└── <课程名>期末试卷B卷.pdf
步骤 3:编写 exam_data.json
JSON 结构(分值结构完全可配置):
{
"meta": {
"school": "山东大学",
"paper_title": "课程试卷",
"course_name": "现代通信原理",
"academic_year": "2025-2026学年",
"semester": "第2学期",
"exam_note": "请考生将答案写在答题区内。",
"coverage_keywords": ["关键词1", "关键词2"],
"score_structure": [
{"key": "fill_blank", "name": "填空题", "score": 30, "count": 6, "hint": "请在横线上填写最准确的术语或公式。"},
{"key": "short_answer", "name": "简答题", "score": 40, "count": 4, "hint": "回答要条理清晰、概念准确。"},
{"key": "comprehensive", "name": "综合题", "score": 30, "count": 2, "hint": "综合分析题要求系统作答。"}
]
},
"paperA": {
"paper_code": "A",
"fill_blank": [
{
"no": 1, "score": 5,
"chapter": "第一章",
"focus": ["重点标签"],
"stem": "题干______。",
"answer": "答案。"
}
],
"short_answer": [
{
"no": 7, "score": 10,
"chapter": "第二章",
"focus": ["重点标签"],
"stem_paragraphs": ["第一段", "第二段"],
"answer_points": ["要点1", "要点2"]
}
],
"comprehensive": [
{
"no": 11, "score": 15,
"chapter": "第三章",
"focus": ["重点标签"],
"stem_paragraphs": ["题干", "(1)...", "(2)..."],
"answer_points": ["要点1", "要点2"]
}
]
},
"paperB": { "...同结构..." }
}
score_structure 说明:
| 字段 | 必填 | 说明 |
|---|---|---|
| key | 是 | 对应 paperX 中的题目数组键名 |
| name | 是 | 题型显示名称(如"填空题""计算题""论述题") |
| score | 是 | 该题型总分 |
| count | 否 | 该题型题数(用于得分栏显示) |
| hint | 否 | 该题型下方的答题提示 |
每题必须包含: no(题号)、score(分值)、chapter(章节)、focus(重点标签数组)、题干、答案。
- 填空题:用 stem(单行),答案用 answer(简短填空答案)。
- 简答/综合/计算题:用 stem_paragraphs(多段),答案用 answer_points(要点数组)。
步骤 4:运行渲染脚本
python <输出目录>/render_exams.py <输出目录>
脚本自动完成:
1. 校验每卷分值与 score_structure 中定义的各题型总分一致
2. 校验总分正确
3. 校验重点覆盖(所有 coverage_keywords 必须出现在题目的 focus 中)
4. 渲染 A/B 卷 HTML(题目页 + 答案页)
步骤 5:导出 PDF
python <math-exercise-pdf脚本路径> "<输出目录>/<课程名>期末试卷A卷.html" "<输出目录>/<课程名>期末试卷A卷.pdf" --force
python <math-exercise-pdf脚本路径> "<输出目录>/<课程名>期末试卷B卷.html" "<输出目录>/<课程名>期末试卷B卷.pdf" --force
PDF 导出统一使用 .trae\skills\math-exercise-pdf\scripts\html_to_pdf.py(依赖 Playwright Chromium)。
模板版式说明
assets/sdu_exam_template.html 提供山东大学标准试卷版式:
- A4 纵向,黑白打印友好
- 首页:学校名 + 课程试卷 + 课程号占位 + 学年学期
- 标题行:山东大学 + 课程名 + A/B卷
- 得分栏:根据
score_structure动态生成列数和分值 - 左侧装订线:姓名、学院、学号、专业(纵向排列)
- 注意事项框
- 正文分节:根据
score_structure动态生成题型标题和提示 - 答案页:独立分页,同风格边框与装订线
自定义指南
修改课程名和元信息
编辑 exam_data.json 中的 meta 字段即可。
调整分值结构
修改 meta.score_structure 数组即可,得分栏、题型标题、分值校验均自动适配。
例如:填空30 + 计算45 + 论述25 = 100 或 选择20 + 填空20 + 简答30 + 计算30 = 100。
增加/减少题型
在 score_structure 中增减条目,并在 paperX 中对应增减题目数组即可。
修改版式
编辑 assets/sdu_exam_template.html 中的 CSS 变量:
- --left-gutter:装订线宽度
- --page-width / --page-height:纸张尺寸
- --font-main:字体族
依赖要求
pip install playwright pymupdf
playwright install chromium
验证清单
- [ ] 每卷各题型分值之和与
score_structure一致 - [ ] 总分正确
- [ ] 重点覆盖关键词无遗漏
- [ ] HTML 无
{{占位符残留 - [ ] PDF 可正常打开,版式与样张高度一致
- [ ] 答案位于各卷末尾,与题目一一对应