一、项目经验整块右移(简历/awesome-source-cv.cls)
\rightcolumnlength 算早了:geometry 的 1.5cm 边距要到导言区结束才生效,
cls 里那句 \setlength 读到 article 默认 \textwidth=345pt,算出 249.87pt,
比应有的 417.02pt 少 167.15pt。longtable 把窄表居中排,整块右移 83.6pt。
修法:计算挪进 \AtBeginDocument 并减去 | 竖线的 \arrayrulewidth;
R 列由 >{\hfill}m{2.5cm} 改为 >{\raggedright\arraybackslash}p{2.5cm}。
日期左边缘 145.1 -> 48.5pt,与其余章节严格对齐。
这类错误零 error 零 warning,只能量 PDF 坐标才能发现。
二、西文换 Cochineal(fonts/cochineal/ + fonts.tex + 简历 cls)
中文思源宋体配 Termes 时西文笔画偏细,中英混排会「陷进去」。
Cochineal 宽 225.42pt vs Termes 229.68pt,只窄 1.9%,断行位置基本不动;
Pagella/XCharter 宽 7~11%,会把全库断行推着变,故不选。
字体 920KB 入 fonts/cochineal/(SIL OFL 1.1,附 OFL.txt),
fonts.tex 新增 \oucUseCochineal 开关,只简历调用,其余 10 个模板不受影响。
三、换字体后暴露的真实缺陷
西文窄 1.9% 让断点整体前移,ICIEA 那条论文冲出 88.49pt(文字顶到纸边)。
根因是中文紧跟英文的位置不是断开点,整串被当长单词。
加 \emergencystretch=3em 解决。
四、课程执行大纲漏网占位符(ouccourse.sty)
××学部××学院 硬编码在 \ccschool 里,#11 只扫了 .tex 没扫 .sty 所以漏了。
拆成 \ccdepartment / \cccollege 两个名称宏,默认「信息科学与工程学部 /
计算机科学与技术学院」。重编后全文 × 归零。
「代码库 PDF 没更新」经核实不成立:本地/远程 HEAD 均为 8984b93,
从服务器下载 8 个 PDF 逐字节比对全部一致,简历.pdf 3 页 0 个 ×。
验证:简历 3 页 0 error/0 Overfull/0 Underfull;全库 12 项编译回归与基线一致。
课程执行大纲 —— 本科课程教学执行大纲、教学日历(LaTeX 模板)
中国海洋大学下发的《本科课程教学执行大纲》Word 模板的 XeLaTeX 复刻版。 内容全部虚构(课程名、课程代码、开课号、教师、教材、思政案例),只复刻版式。
样张是一份填完整的虚构大纲:《信号与系统基础》2026 秋、电子信息工程专业、 56 课时 3.0 学分(含 18 实践学时)、开课号
99663311、任课教师「陈立群」、 教材用吴大正《信号与线性系统分析》(高等教育出版社)、参考书用郑君里那本。注意本模板刻意不套用其他模板的「数字逻辑 / 张远航」那套设定 —— 这份大纲原作就是《信号与线性系统分析》的课,强行改成数字逻辑, 大纲里的章节体系、学时分配、思政案例就全对不上了。虚构也要虚构得自洽。
| 文件 | 说明 |
|---|---|
课程执行大纲.tex |
主文件。虚构课程的一份完整示例 |
ouccourse.sty |
版式宏包。尺寸全部从原 docx 的 OOXML 量出 |
课程执行大纲.pdf |
编译产物,5 页(与原 docx 一致) |
编译
xelatex 课程执行大纲.tex # 单次即可,无交叉引用
需要 ctex + geometry + fontspec + xeCJK + tabularray。
实测环境:TeX Live 2022 / tabularray 2022A。
换成一门真实的课
只改 课程执行大纲.tex 顶部的宏定义,不要动 ouccourse.sty。
\newcommand{\cfcourse}{信号与系统基础} % 课程名
\newcommand{\cfyear}{2026} % 学年
\newcommand{\cfseason}{秋} % 季学期
\newcommand{\cfmode}{考试} % 考核方式:考试/考查/论文
\newcommand{\cfcode}{081203304517} % 课程代码
\newcommand{\cfhour}{56} % 总课时
\newcommand{\cfcredit}{3.0} % 学分
\newcommand{\cfprac}{18} % 实践学时
\newcommand{\cfteacher}{陈立群} % 任课教师
\newcommand{\cfteachno}{99663311} % 开课号
\newcommand{\cfmajor}{电子信息工程} % 面向专业
\newcommand{\cfattr}{专业核心必修课} % 课程属性
正文各节直接用 \ccsec{}(一级标题)、\ccp{}(带 2 字首行缩进的正文)。
表 0 —— 成绩综合评分体系
\begin{ccscoretable}
成绩综合评分体系 & 比例\% \\ % 表头
1.课下作业、课堂讨论及平常表现 & 24 \\
2.实验成绩 & 20 \\
3.期末考试成绩 & 56 \\
总计 & 100 \\
\end{ccscoretable}
行数可以增减,行高自动(每行 7.834mm)。
表 1 —— 教学日历
\begin{cctable}
{\ccfang\ccszxi\bfseries 周次} & ... & {\ccszix 内容} & 2 & {\ccszix ...} & {\ccszix ...} \\
\end{cctable}
- 6 列,顺序固定:周次 / 内容顺序 / 主题 / 计划课时 / 教学内容及教学方式 / 思政点及支撑指标点情况
- 纵向合并周次段用
\SetCell[r=2]{c}(跨 2 行,r=N即跨 N 行) - 表尾「合计」行后有两个
\SetCell[c=6]{c}的整行合并(任课老师签字 / 审核意见) - 表内默认 9pt;表头用
\ccszxi(11pt)加粗;审核意见格内部钉死 10.5pt/12.6pt
版式数据来源(twips → mm)
原 docx 的 sectPr:
| 属性 | twips | mm | 说明 |
|---|---|---|---|
pgSz w |
11910 | 210.08 | WPS 存的"非标准 A4",本包用标准 210 |
pgSz h |
16840 | 297.04 | 同上,用 297 |
pgMar top |
1420 | 25.05 | 上边距 |
pgMar bottom |
280 | 4.94 | 下边距极小,原文件为塞进 5 页压出来的 |
pgMar left |
1560 | 27.52 | 左边距 |
pgMar right |
1300 | 22.93 | 右边距(左右不对称,照抄) |
pgMar header/footer |
720 | 12.70 | 无页眉页脚内容,仅占位 |
换算:mm = twips / 1440 × 25.4,pt = twips / 20。
表 0(成绩综合评分体系)
| 项目 | twips | mm |
|---|---|---|
gridCol |
7479 + 1418 | 131.921 + 25.012 |
| 表宽 | 8897 | 156.93 |
tblCellMar left/right |
108 | 1.905 |
trHeight(exact) |
454 | 8.01(本包用 7.834,见坑 3) |
边框 sz |
4 | 0.5pt |
tblLayout fixed、jc center、tblW 0 auto。全表 12pt 仿宋(朱雀仿宋)。
表 1(教学日历)
| 项目 | twips | mm |
|---|---|---|
gridCol |
846,1134,1877,850,2835,1843 | 14.922, 20.002, 33.108, 14.993, 50.006, 32.508 |
| 表宽 | 9385 | 165.54(超版心 5.91) |
trHeight R0(atLeast) |
917 | 16.17 |
trHeight R14(atLeast) |
1825 | 32.19 |
trHeight R15(atLeast) |
1073 | 18.93(只是下限,实际被撑到 56mm) |
16 行。R1~R13 无 trHeight,行高由内容决定。纵向合并 5 组(R1-R2、R3-R4、
R5-R6、R7-R8、R9-R10);R14/R15 是 gridSpan=6 的整行合并。
六个必须知道的坑
1. 表宽 > 版心时,不要缩放列宽
docx 里表 1 是 165.54mm,版心只有 159.55mm。Word 允许表格超出、居中后压进左右页边距。
不要按 159.55/165.54 按比例缩列宽。 缩了之后长文字会提前折行,行高、页数全变。
正确做法:列宽照抄 gridCol,用 \leftskip 把整块左移。
\hsize=\cctblw \linewidth=\cctblw % 让表内得下,不报 Overfull
\leftskip=-\cctblshift \rightskip=0pt % 整块左移 5.29mm,落到 22.23mm
\hspace* 对 longtblr 生成的 \halign 盒子无效,会被吞掉,必须用 \leftskip。
2. wd= 是内容宽,不含竖线自身的宽度
tabularray 的 Q[...,wd=X] 里 X 是内容宽。每条 vline 自身还占 0.5pt = 0.17639mm。
表 1:6 列 7 条线,每列承担 7/6 条 ⇒ wd = gridCol − 2×colsep − 0.2058
表 0:2 列 3 条线,每列承担 1.5 条 ⇒ wd = gridCol − 2×colsep − 0.2646
漏算的后果很隐蔽:表看起来对,但总宽每列多 0.18mm,6 列就差出 1mm。
3. ht= 也含横线宽度预算
row{1-Z}={ht=8.01mm} 画出来是 8.19mm(每行多一条 0.5pt 横线)。
要得到 8.01mm 的真实行高,ht 要给 7.834mm。
4. presep/postsep/headsep/footsep 是 outer 键
写进 \begin{longtblr}[...] 的方括号里;写进花括号(inner spec)不会生效,
反而会把 0pt 当表内容印在表格第一行 —— 表头上会出现一串
0pt0pt0pt0pt 的垃圾文字,而且不报错。
同理,表级默认字号必须写 cells={font=\ccszix},单独写 font= 会被静默忽略。
5. 跨页续页提示要清两组模板
longtblr 跨页时默认印 ( Continued )、表尾印 Continued on next page,
有 caption 时还印 表0:。清干净要动两组:
% (a) 内容模板 *-text —— 不能设成 empty!会报
% "LaTeX3 Error: Erroneous variable \l__tblr_template_conthead_text_tl"
\DefTblrTemplate{conthead-text}{normal}{}
\DefTblrTemplate{contfoot-text}{normal}{}
\SetTblrTemplate{conthead-text}{normal}
\SetTblrTemplate{contfoot-text}{normal}
% (b) 模板实例
\SetTblrTemplate{caption-tag}{empty}
\SetTblrTemplate{caption-sep}{empty}
\SetTblrTemplate{caption-text}{empty}
\SetTblrTemplate{caption}{empty}
\SetTblrTemplate{conthead}{empty}
\SetTblrTemplate{contfoot}{empty}
只做 (b) 时第 5 页仍会出现「表0:」与「(Continued)」,因为模板实例里调的是
\UseTblrTemplate{...}{default},会回退到 normal 内容。
6. \linespread 是乘在基准字号上的
ctex 默认 \linespread ≈ 1.3,会把 \fontsize{12}{18} 的行距放大到 23.4pt。
给字号设行距时必须先归 1:
\newcommand{\ccfont}[2]{\linespread{1}\relax\fontsize{#1}{#2}\selectfont}
反过来,在已经缩小过字号的上下文里,不能用 \linespread{1.2} 当"1.2 倍行距"
(它乘的是外层的 9pt,不是当前的 10.5pt),要直接钉 \fontsize{10.5}{12.6}。
字体
原 docx 用了 4 个字体,其中 3 个是方正商业字体,嵌在 docx 里但本机没装。
旧版做法是降级到 Windows 自带字体(宋体/黑体/仿宋 + AutoFakeBold 伪粗),
但这既依赖本机装了什么字体(换台机器就可能编不出),而且 SimSun / SimHei /
FangSong 也都不允许随仓库分发。
现在全部改用仓库公共字体包 ../fonts.tex:
| docx 原字体 | 用在哪 | 本包替代 | 命令 |
|---|---|---|---|
| 方正小标宋简体 | 校名、副标题、大标题、教学日历 | OUC Serif 真粗体 | \ccbiaosong |
| 方正仿宋_GB2312 | 正文、表 0、签字栏 | 朱雀仿宋 | \ccfang |
| 黑体 | 各级标题 | OUC Sans(思源黑体) | \cchei |
| 宋体 | 教学日历表 9pt | OUC Serif(思源宋体) | \ccsong |
比原来的伪粗更好:小标宋本来就是宋体的标题变体,用思源宋体自带的真粗体,
笔画不会像 AutoFakeBold=3.2 那样糊在一起。
⚠️ 朱雀仿宋只有常规一档,
\ccfang下\bfseries不会真的变粗。 教学日历表头(课程执行大纲.tex里的{\ccfang\ccszxi\bfseries 周次}等 6 处) 原来靠AutoFakeBold=2.5伪粗,现在给ccfang单独开了FakeBold=0.8保住层次(见ouccourse.sty的注释)。若要更实在的粗体,把那几处\ccfang换成\cchei—— 黑体本身就是标题用的重字面。
同时 \xeCJKsetup{CJKecglue={}} 关掉了西文与汉字之间的自动空隙 —— 原 docx 没有这种空隙,
不关会在中英交界处多出一个空格(原 docx 里紧挨着的「2026 学年」「56/3.0」都会松开)。
院名可改(原先是硬编码的 ×× 占位)
首页抬头第二行原本在 ouccourse.sty 里写死成「××学部××学院」,PDF 里
能直接看到 4 个叉号。现在拆成两个名称宏,改院名只动导言区:
\renewcommand{\ccdepartment}{海洋地球科学学院} % 默认「信息科学与工程学部」
\renewcommand{\cccollege}{地质学系} % 默认「计算机科学与技术学院」
默认值取自本模板的虚构设定(陈立群 / 电子信息工程 / 2025 秋),与课程教学日历、 成绩构成说明、试卷等模板保持一致。校名「中国海洋大学」是真实的,不虚构。
⚠️ 为什么不写成
\ccschool[学部][学院]:LaTeX 的\newcommand只支持 一个可选参数,第二个方括号会被当成正文印出来。
与 docx 的已知差异
| 项目 | docx | 本模板 | 原因 |
|---|---|---|---|
| 纸张 | 210.08 × 297.04 | 210 × 297 | 标准 A4,肉眼不可辨 |
| 表格是否跨页 | 表 1 跨第 4/5 页 | 同 | 表高 334mm > 版心 267mm |
| 跨页处表头 | 不重复(无 tblHeader) |
不重复 | 一致 |
| 行内是否允许断开 | 允许(无 cantSplit) |
允许 | 一致 |
| 表 0 每行高 | 8.01 | 8.01 | 一致 |
| 表 1 表宽 | 165.54 | 165.36(−0.18) | 竖线宽度舍入 |
| 字体 | 方正小标宋/仿宋 | 思源宋体粗/朱雀仿宋 | 商业字体不可分发,已换开源替代 |
| 修订标记 | 46 处 w:ins |
不保留 | 已接受全部插入修订 |
46 处 w:ins 中的红字 |
color=C00000 |
黑色 | 那是修订高亮,非正式版式 |
校验方法
不靠肉眼,靠量。
pdftocairo -svg -f 4 -l 4 课程执行大纲.pdf /tmp/p4.svg # 矢量线条
pdftotext -bbox 课程执行大纲.pdf /tmp/bbox.html # 字坐标
或用 pymupdf 直接读(推荐,能同时拿到线段与 span 的 bbox):
import pymupdf
d = pymupdf.open('课程执行大纲.pdf')
for dr in d[3].get_drawings(): # 表格横竖线
for it in dr['items']:
if it[0] == 'l':
print(it[1], it[2]) # 两端点,单位 pt
注意:同一条竖线会被重复计入多次(每个单元格一段),做列宽计算前必须
sorted(set(round(x,2) ...)) 去重,否则 xs[1]-xs[0] 算出来是 0。
验收结果(实测,26/26 项达标)
表 0 宽 156.753 目标 156.930 差 −0.177
左 27.608 目标 27.520
高 40.040 目标 40.050
列 131.830 / 24.924 目标 131.921 / 25.012
表 1 宽 165.358 目标 165.540 差 −0.182
左 22.320 目标 22.270
列 14.894 / 19.971 / 33.076 / 14.965 / 49.975 / 32.477
目标 14.922 / 20.002 / 33.108 / 14.993 / 50.006 / 32.508
R0 16.334(目标 16.170) R14 32.385(目标 32.190)
R15 56.339(atLeast 下限 18.930,被 12 段内容撑高)
页数 5(与原 docx 一致)
编译 零错误、零 Overfull、零 Underfull
各页最低点均 ≤ 292.06mm 版心下沿,无越界