把 11 个模板里满篇的 × 换成一套连贯的虚构数据,让样张能看出排版效果。
虚构设定(跨模板统一):
- 数字逻辑 / 2025 秋 / 张远航 / 计算机科学与技术学院,教学日历、成绩构成
说明、试卷归档封面、试卷四份互相对得上
- 简历:张远航,1985.03,教授博导,论文/专利/项目/获奖全套虚构
- 年度考核:同一人的 2025 年度考核表,年度总结四段写满
- 执行大纲:刻意不套用上面那套(原件就是《信号与线性系统分析》的课,
强行改课程名会让章节体系、学时分配、思政案例全对不上)
假数据都留肉眼可辨标记:DOI 统一 10.9999/、专利号 ZL209999…、
软著 2024SR99999…、手机 138 0000 0000、邮箱 example.net。
签字/日期/评语栏仍然留空——编了就分不清该改哪儿。
修掉一个既有 bug(填充时才暴露):
年度考核登记表「出生年月」的值从来不显示,连字符都不在 PDF 里。
根因是 tabularray 的 cell{r}{c}={c=n} 里那个 c 是数据行的单元序号、
不是视觉列号,表头三处 c=2 要求该行吃 15 个视觉列而表只有 11 列,
超出部分静默丢弃。迷惑点:写 12 格丢值,写 9 格反而正常。
正解是表头不写 cell{},改用行内 \SetCell[c=n]{c},每行照常写满 11 格。
同时 R0 行原件本就装不下(前六字段 115.76mm,剩 42.20mm 要放
19.68mm 标签 + 17.22mm 值,但列宽被切成 15.31/1.38/25.51),
把标签折两行「出生/年月」解决,列宽一个没改。
README 同步:根 README 与 8 个模板 README 里「一律用 × 占位」的说法
已不成立,统一改为「示例内容全部虚构」,并说明哪些位置仍必须留空。
验证:12 个模板零 error,4 处基线警告未新增;干净副本重编页数一致;
PDF 正文 × 清零;真实信息零泄漏。
15 KiB
成绩构成说明 — 中国海洋大学《成绩构成说明》(LaTeX 版)
把任课教师手写的「成绩构成说明」做成 LaTeX 模板。原件是一份填过的
.doc 实例(两段话 + 标题,无表格、无签字栏),本模板在保留其信息
内容的前提下重新组织,并补齐归档必需项。
本模板不含原件任何真实数据。 课程名、学年、学期、教师姓名、 所有比例、日期均已替换,已 grep 验证零命中。
样张填的是一份完整的虚构课程:《数字逻辑》2025 秋学期、任课教师「张远航」、 理论课 80% + 实验课 20%、平时 30%(作业 20% + 点名 10%)+ 期末 70%。 这套比例是自洽的(20+10=30、30+70=100、80+20=100),正好能演示 模板的比例校验功能;与
课程教学日历/、试卷归档封面/、试卷/为同一门课。
目录
文件
| 文件 | 说明 |
|---|---|
成绩构成说明.tex |
主文件。填表只改第 1 节(10 个宏) |
oucgrade.sty |
版式包。页面/字体/表格/签字栏,附换算注释 |
成绩构成说明.pdf |
成品样张(1 页) |
编译
xelatex 成绩构成说明.tex
单页,跑一遍即可(无交叉引用,不需要 bibtex)。
⚠️ 必须在本目录下编译,不要从仓库根调用 —— fonts.tex 用的是
相对路径 ../fonts/。
需要 XeLaTeX,并安装 ctex、geometry、fontspec、xeCJK、
tabularray、enumitem、graphicx。实测环境:TeX Live 2022。
改内容
课程信息(10 个宏)
\newcommand{\grdcourse}{数字逻辑} % 课程名称
\newcommand{\grdyear}{2025} % 学年
\newcommand{\grdseason}{秋} % 季学期(春 / 秋)
\newcommand{\grdteacher}{张远航} % 任课教师
\newcommand{\grdtheory}{80} % 理论课占总成绩 %
\newcommand{\grdlab}{20} % 实验课占总成绩 %
\newcommand{\grddaily}{30} % 平时成绩占理论课 %
\newcommand{\grdfinal}{70} % 期末考试成绩占理论课 %
\newcommand{\grdhw}{20} % 作业占理论课 %
\newcommand{\grdattend}{10} % 点名占理论课 %
\newcommand{\grdlabnote}{由实验课教师根据实验报告与实验操作评定。}
上列前四项是样张实际用的虚构值。数字只填数字,不要带 % 号,百分号由模板加。
「占本类」与「占总成绩」是两回事
这是本模板最要紧的一个设计,见下节。
改写正文
- 总述:
\grdpara{...} - 分节:
\grdsec{一、成绩构成} - 列表:
\begin{grdlist} \grditem{项}{:说明} \end{grdlist} - 表格单元格:
\grdth{}(表头)/\grdtd{}(表身)
相对于原件的改动
原件全文只有这些内容(下面是脱敏摘录,原件里的真实课程名 / 学年 / 教师名
用 ×××× 盖掉了;样张 PDF 里排的是虚构的《数字逻辑》2025 秋):
成绩构成说明
×××× 20××学年 ×季学期 期末考试
理论课成绩占总成绩的80%。理论课成绩包括平时成绩、期末考试成绩。
平时成绩占30%(作业占20%,点名占10%),期末考试成绩占70%。
实验成绩占总成绩的20%。由实验课老师提供。
它的问题有四个,逐个解决:
1. 三层百分数混用不同基准,读者要心算三轮
| 句子 | 百分数 | 基准实际是 | 折总成绩 |
|---|---|---|---|
| 理论课占总成绩的 80% | 80% | 总成绩 | 80% |
| 平时成绩占 30% | 30% | 理论课 | 24% |
| 作业占 20% | 20% | 理论课 | 16% |
| 期末考试成绩占 70% | 70% | 理论课 | 56% |
「平时占 30%」看着像占总成绩三成,实际上只占 24%。教务抽查时 这里最常被挑错,学生也容易误读。
改法:表格左右并置「占本类」与「占总成绩」两列,后者由
\grdcalc{理论课\%}{分项\%} 自动算出,不给心算留余地。
2. 层级关系埋在句子里
「平时成绩占30%(作业占20%,点名占10%)」—— 括号里的两个数加起来 才是括号外的数,这种嵌套在一个句子里读起来要来回扫。
改法:改成 6 列表格,一级项目跨行合并,层级一眼可见。
3. 没有说明「怎么算」
原件说了比例,没说作业怎么平均、缺交怎么扣、点名缺几次记零。 这些是学生真正会问的,也是申诉时的依据。
改法:新增「二、分项说明」一节,用列表逐项写清(文字留占位, 任课教师按自己课程的规则填)。
4. 没有签字栏
这是用户明确要求补的。 没有任课教师签字的成绩构成说明,在教务 归档时不被认作有效文件。
改法:右下角落款,含签字线与「年 月 日」三个手写填空位。
⚠️ 「年 月 日」不印年份。成绩构成说明是学期末签署的文件,年份
由签字人当场手写;模板里预留 20×× 反而会占掉手写空间、并诱导
使用者去改占位符。所以这一行只有三个字 + 两处 \hspace 间距。
另外新增(可关闭)
「三、成绩评定与异议」一节 —— 说明总成绩如何取整、异议如何在几个 工作日内提出。原件没有,但归档材料有这一节更完整。
不要的话把 .tex 里这个开关改成 0:
\def\grdwithini{0} % 1=印这一节,0=不印
⚠️ 关掉后正文变短,签字栏会往上移。若想让它仍贴底部,把 oucgrade.sty
里签字块前的 \par\vspace{3mm} 调大即可(见坑 3)。
比例自洽校验
模板会检查三组加法:
平时 + 期末 = 100 (构成全部理论课)
作业 + 点名 = 平时 (构成全部平时成绩)
理论课 + 实验课 = 100 (构成全部总成绩)
不通过时:
.log里打出*** oucgrade: 比例不自洽 --- 作业+点名 应构成全部平时成绩: 实际 25+10, 应为 30 ***- PDF 标题正下方印一行红字警告
为什么值得做:成绩构成说明是要归档、要被抽查的文件,比例加不起来 是最常见也最难被自己发现的错误 —— 原件那句「平时 30%(作业 20%, 点名 10%)」正是靠心算才看得出 20+10=30。
已做负面测试:把 \grdhw 从 20 改成 25 重编,log 报
实际 25+10, 应为 30,PDF 第 1 页顶部出现警告;改回 20 后警告消失。
⚠️ 警告印在开头不是文末。文末的提示会被签字栏挤到第 2 页, 而第 2 页通常没人翻 —— 等于没提示。
版式参数
页面
| 项 | 值 | 来源 |
|---|---|---|
| 纸张 | A4 210×297mm | pgSz 11906×16838 twips |
| 上下边距 | 25.40mm | pgMar top/bottom 1440 |
| 左右边距 | 31.75mm | pgMar left/right 1800 |
| 版心 | 146.50 × 246.20mm | 210−2×31.75 / 297−2×25.40 |
| 页脚距 | 17.51mm | pgMar footer 992 |
换算:mm = twips / 1440 × 25.4,pt = twips / 20。
字号
| 用途 | 原件 (w:sz) | 本模板 | 实测输出 |
|---|---|---|---|
| 大标题 | 36 半磅 = 18pt | 18bp |
18.00 |
| 副标题 | 24 = 12pt | 12bp |
12.00 |
| 正文 | 28 = 14pt | 14bp |
14.00 |
| 表格/签字 | — | 12bp |
12.00 |
⚠️ 必须写 bp 不能写 pt。Word 的 pt 是 PostScript pt(1/72 in),
TeX 默认 pt 是 1/72.27 in,差 0.36%。写 14pt 实测输出 14.05。
行距
| 用途 | 值 | 说明 |
|---|---|---|
| 正文 | 21.5bp | 14pt 的 1.54 倍 |
| 表格/签字 | 17bp | 12pt 的 1.42 倍 |
原件 docGrid linePitch=312 = 15.6pt,对 14pt 字只有 1.11 倍,太挤。
本模板用 21.5bp(1.54 倍)—— 这是有意的改善,不是复刻。
21.5 是为压到一页反复试出来的值,可读下限约 1.4 倍,还有余量。
表格列宽
6 列,Σ wd = 123.64mm:
| 列 | 宽 | 内容 |
|---|---|---|
| 项目 | 22.00mm | 理论课 / 实验课 |
| 占本类 | 14.00mm | 80% |
| 细分项目 | 26.00mm | 平时成绩 / 期末 |
| 占本类 | 14.00mm | 30% |
| 占总成绩 | 17.00mm | 24% |
| 评定依据 | 29.40mm | 作业 + 出勤 |
Σwd 为什么是 123.64 而不是 146.50:Q[wd=...] 是内容区宽度,
不含 colsep。每列实际占位 = wd + 2×colsep,6 列共多占
6×2×1.905 = 22.86mm。所以
Σwd = 146.50 − 22.86 = 123.64mm。
⚠️ 画满全格线之后每列还要再扣 0.5pt。只画外框时表宽里不含内部
竖线;一旦 vline{1-Z} 把 5 条内部竖线都画上,表宽就多出
5×0.5 = 2.5pt,编译报 Overfull \hbox (2.47554pt too wide)。
所以最后一列从 30.28mm 收到 29.40mm(−2.5pt)补回来。
行高:ht 是最小值,且跨行格不会自己长高
这两点一起踩过,都表现为"字贴着格线":
ht 是否小于内容高 |
结果 |
|---|---|
是(如 ht=7.5mm < 54.73pt) |
行被内容撑到 54.73pt,上下零留白,末行墨迹底离行线只剩 0.90pt(0.32mm),其他行是 4.97pt(1.75mm)—— 一眼看出挤 |
否(ht=22mm = 62.4pt) |
行高 62.86pt,上下各留约 3.8pt,末行墨迹底离行线 4.08pt(1.44mm),与其他行同量级 |
所以 ht 给了不等于生效,必须大于内容自然高度。本例「平时成绩
(作业 20%、点名 10%)」在 26mm 列里折 3 行,自然高 54.73pt
(= 2×17bp + 盒高),要撑开就得给到 22mm。
ht 按表格行号给,不是按逻辑块:row{1} 是表头、row{2} 是
「理论课/平时成绩」那一行。抬高 row{3}(「期末」行)只会移动中间
那条线,对跨行块的高度没有影响。
五个坑
坑 1:.tex 里写带 @ 的宏名
.tex 文档中 @ 的 catcode 是 12(其他),不是 11(字母)。写
\grd@chk 会被解析成 \grd + @chk,报
! LaTeX Error: Missing \begin{document},并且连累后面所有内容
(报一串 Undefined control sequence)。
规矩:带 @ 的内部宏一律定义在 .sty 里,.tex 只调用不带 @
的公开接口(如 \grdcheck)。
坑 2:tabularray 的 hline{} 里不能用带 @ 的宏
hline{1,Z}={\grd@rulev} % ✗ 报 \l__tblr_v_tl ->\grd @rulev
hline{1,Z}={0.5pt} % ✓ 写字面值
tabularray 把 hline 的参数当字符串重新 tokenize,那一刻 @ 的
catcode 已经退化,宏名在 @ 处断开。
规矩:hline / vline 的线宽写字面值,别用宏包一层。
⚠️ 关于 1-Z 与 1,Z:
| 写法 | 含义 | 效果 |
|---|---|---|
hline{1,Z} |
第 1 条 + 最后 1 条 | 只有顶框和底框 |
hline{1-Z} |
第 1 条到末条(全部) | 每条行线都画 |
本模板用 1-Z:所有格线都画满。只画外框时,跨行格(理论课)
与单行格的分界、以及数据行之间全是空白,非常容易看错行。这是
用户明确要求改掉的点。
代价是每列要再扣 0.5pt 表宽(见上文「画满全格线之后每列还要再扣」
一节),并且暴露出一个原本被掩盖的缺陷:跨行格里的第 3 行字一直
是贴着格线的(详见上文「行高」一节)。画满格线会让所有"零留白"
的排版问题显形 —— 这是好事,但要预留调 ht 的时间。
坑 3:签字栏被挤到第 2 页
试过四种写法,只有最后一种同时满足「一页」+「不出界」:
| 写法 | 结果 |
|---|---|
\par\vspace{4mm} + minipage |
✗ 翻页(minipage 紧跟 \par 是合法断页点) |
\vfill 顶到底部 |
✗ 不翻页但出界:年月日 y=774.9,版心底只有 771.6 |
\vfill + 块内 \vspace*{5mm} |
✗ 又翻页(\vfill 与块高之和超出剩余空间时,TeX 不接受压缩 \vfill,只能整块搬迁) |
\par\vspace{3mm} + minipage |
✓ 一页,内容底 769.8,余 1.8pt |
结论:不要指望竖直胶帮你「自动贴底」。单页文档里最稳的是 固定间距 + 实测校准 —— 改正文后重编一次,看内容底距 771.6 还有多少。
坑 4:minipage 内部用 \hfill 做右对齐
\begin{minipage}{76mm}
任课教师(签字):\rule{40mm}{0.4pt}\par % 行尾没有 \parfillskip 弹性
\end{minipage}
minipage 里的行末会被拉伸到满宽,12pt 的字出现夸张字距 —— 实测「任」「课」「教」「师」被拉到 34.8pt 一字。
正解:minipage 内 \raggedright,\hfill 只放在外面:
\noindent\makebox[\textwidth][r]{\begin{minipage}{76mm}\raggedright ...\end{minipage}}
坑 5:列表引导符「·」缺字
本库 OUC Serif 子集里没有 ·(U+00B7) 和 •(U+2022),
用它们会报 Missing character: There is no · (U+00B7),印出来是空白。
实测该字体有 ●(U+25CF) 与 ○(U+25CB),且 fonts.tex 已把这两个
码位归入 CJK 字符类,可直接用。本模板用缩小 0.6 倍的 ● 作引导符。
真实数据零泄漏
原件是填过的实例(真实课程名、学年、教师姓名、全部比例)。 本模板把这些逐项换掉:课程名 / 学年 / 教师名换成虚构的《数字逻辑》2025 秋 「张远航」,原件的比例也未保留。
已 grep 确认以下关键词在 oucgrade.sty、成绩构成说明.tex 与 README.md
中零命中(含注释):原件实例的课程名、学生人数、开课号、教师姓名、
单位名称,以及原件出现过的具体年份。本 README 不列出这些原文,
避免「为了证明零泄漏而把真实信息写进来」。
关于
80/20/30:样张里这几个数不是从原件抄的,是按「理论 80 + 实验 20、平时 30(作业 20 + 点名 10)+ 期末 70」重新配的一组自洽比例, 目的是让模板的比例校验(见前文「比例自洽校验」)能演示出「三项都成立」 的状态。原件那组比例本身有对不上的地方,不适合当范例。
字体
全部来自仓库公共字体包 ../fonts.tex(唯一允许声明字体的地方):
| 用途 | 字体 | 授权 |
|---|---|---|
| 正文宋体 | OUC Serif(思源宋体 GB2312 子集) | SIL OFL 1.1 |
| 标题楷体 | OUC Kai(霞鹜文楷子集) | SIL OFL 1.1 |
| 分节黑体 | OUC Sans(思源黑体子集) | SIL OFL 1.1 |
| 西文 | TeX Gyre Termes | GUST Font License |
⚠️ 原件标题用的是方正楷体_GB2312,那是商业字体,本库不含也不能分发。 改用霞鹜文楷(同属楷书形态,开源可商用)。这是有意的替换,不是遗漏。
⚠️ 不要用 \setCJKmainfont 直接指定系统字体(SimSun / SimHei 等)——
换到 Linux / macOS 就编不出来。全部走 ../fonts.tex。