Files
ouc_latex_template/试卷归档封面/oucksfm.sty
T
laoyang 3906bb49a4 清理代码库中的开发过程内容
- 删除 WORKFLOW.md(开发流程文档,已移入记忆库)
- build.sh 去掉 WSL 相关说明
- 33 个源文件的注释:去掉踩坑记录、实测推导、原文件对比、工单号引用
- 保留技术参数、约束说明、命令含义

净删 399 行。全库 16/16 编译通过。
2026-11-01 09:29:00 +08:00

272 lines
13 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
%======================================================================
% oucksfm.sty — 信息科学与工程学部 试卷归档封面(理论课)版式包
%
% 依据:附件1:信息科学与工程学院试卷封面(理论课).doc
% (SynologyDrive/授课/数字逻辑/2025/归档/)
% 原名与内文标题写的是「学院」,按现行建制改为「学部」,
% 模板标题相应为「信息科学与工程学部试卷归档封面」。
% 目标:版式与逐项对齐。所有尺寸都由 Word 内部数值换算:
% pt → mm : mm = pt / 72 * 25.4
% twips → mm : mm = twips / 1440 * 25.4
% w:sz : 半磅值,÷ 2 即 pt
%
% 用法见同目录 试卷归档封面.tex,说明见 README.md
%======================================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{oucksfm}[2026/10/26 v1.0 OUC exam archive cover sheet]
\RequirePackage{geometry}
\RequirePackage{fontspec}
\RequirePackage{xeCJK}
\RequirePackage{tabularray}
%======================================================================
% 1. 页面与版心
%
% sectPr:
% pgSz A4(595.3 × 841.9 pt = 210.0 × 297.0 mm)
% pgMar top/bottom 70.9 pt = 25.01 mm
% left/right 56.7 pt = 20.00 mm
% header 42.55 pt = 15.01 mm / footer 49.6 pt = 17.50 mm
%
% 表宽 tblW = 100%(w:type="pct" w:w="5000"),即铺满版心:
% 版心宽 = 210 − 2×20.00 = 170.00 mm
%
% ⇒ 这里让 totalwidth 恰等于 170mm:
% · 表格天然与版心同宽,编译不刷 Overfull \hbox
% · 表格在纸面上的绝对位置与 Word 完全一致(左右各 20mm)
%======================================================================
\geometry{
paperwidth = 210mm,
paperheight = 297mm,
totalwidth = 170mm, % = 表宽,精确
hmarginratio = 1:1, % 左右各 20mm
top = 25.01mm,
bottom = 25.01mm,
headheight = 0pt,
headsep = 0pt,
footskip = 17.50mm,
}
\setlength{\parindent}{0pt}
\setlength{\parskip}{0pt}
\pagestyle{empty} % 无页眉页脚,故不排页码
%======================================================================
% 2. 字体与字号
%
% 表外标题 黑体 18pt 加粗(w:sz=36 + w:b),jc=center
% 左列标签 黑体 18pt (w:sz=36,全部 11 行一致)
% 右列值 黑体 18pt (w:sz=36)—— 学年 / 学期
% 黑体 16pt (w:sz=32)—— 考试课程名称 / 课程类型 /
% 面向专业 / 面向年级 / 试卷份数 /
% 授课教师 / 日期
% 黑体 14pt (w:sz=28)—— 课程号 / 选课号(纯数字,字号小一档)
%
% ⚠️ 全文只有黑体一种字体,没有宋体/仿宋混排,比另两份表单简单。
%
% 字体全部来自仓库公共字体包 ../oucfonts.sty(文件在 ../fonts/ 下)。
% 换台机器(尤其 Linux/macOS)就编不出来。现已全部换成随仓库分发的
% 开源字体,并且粗体用字体自带的真粗体、不再算法描边。
%======================================================================
\input{../fonts.tex}
%----------------------------------------------------------------------
% ⚠️⚠️⚠️【最要命的一条,与 ouclw.sty 同源】
% ctex 默认 \linespread 约 1.3,会把 \fontsize{18}{21.6} 的 21.6pt
% 行距放大成 28pt 以上。
%
% \fontsize 的第二个参数【本来是】用来设 \baselineskip 的,但
% \selectfont 时会再乘一次 \linespread,所以必须先把 \linespread 归 1。
% 这一步不能省,也必须在 \AtBeginDocument 之后再设一次
% (ctex 在 begin document 时会重设)。
%----------------------------------------------------------------------
\newcommand{\sfmbodyfont}{%
\linespread{1}\relax
\fontsize{18}{21.6}\selectfont}
% 三档字号(行距取字号的 1.2 倍,与单倍行距一致)
\newcommand{\sfmbigfont}{\linespread{1}\relax\fontsize{18}{21.6}\selectfont}
\newcommand{\sfmmidfont}{\linespread{1}\relax\fontsize{16}{19.2}\selectfont}
\newcommand{\sfmsmlfont}{\linespread{1}\relax\fontsize{14}{16.8}\selectfont}
%----------------------------------------------------------------------
% ⚠️ xeCJK 陷阱:局部字体切换命令若紧邻 \par(或落在段落末尾),段末的
% 字体状态会"溢出"到后面段落。故局部切换一律用带 \normalfont 收尾的包装。
%----------------------------------------------------------------------
\newcommand{\SFMHT}[1]{{\heiti #1\normalfont}}
%----------------------------------------------------------------------
% 这里做了根治】
%
% 现象:写 {\heiti ×××} 后编译,PDF 里这些 × 实际用的是
% Times New Roman,
% 不是黑体。§ 29 个 × 撑不满预期宽度,跟汉字混排时基线也偏。
%
% 原因:xeCJK 按 Unicode 区段分类。「×」是 U+00D7,落在 Latin-1 补充区,
% xeCJK 把它判成【西文字符】⇒ 交给 fontspec 的西文字体(TNR)。
% \heiti / \fangsong 只切换 CJK 字体,对这个字符【不起作用】。
% 所以 {\fangsong ××} 这种写法看着像修好了,实际并没有
% (年度考核登记表/ 的 PDF 里 × 至今仍是 TNR)。
%
% 正解:把 U+00D7 显式声明为 CJK 字符类,让它回到 CJK 字体族,
% \heiti / \fangsong 才能真正管到它。全角宽度也就与汉字一致了。
%
% ⚠️ 这条只在本包内生效,不影响其它模板(年度考核登记表 若也要修,
% 把这两行照抄过去即可)。
%----------------------------------------------------------------------
\xeCJKDeclareCharClass{CJK}{"00D7} % × 乘号 → 归 CJK,跟着 \heiti/\fangsong 走
\xeCJKDeclareCharClass{CJK}{"2014} % — 破折号 → 归 CJK(学年区间「2025—2026」用得上)
%======================================================================
% 3. 列的宽度模型
%
% tblGrid(2 个网格列,col_widths_pct = [30, 70]):
% c1 = 170 × 30% = 51.000 mm
% c2 = 170 × 70% = 119.000 mm
%
% cellMar:left/right = 85 twips = 1.4993 mm,top/bottom = 0
% 边框 :w:sz = 4(单位 1/8 pt)⇒ 0.5 pt = 0.1764 mm
%
%----------------------------------------------------------------------
% ⚠️ 与 ouclw.sty 一样,这里可以如实还原内边距(最窄列 51mm 远宽于两倍
% 内边距 3.00mm,不像年度考核表那样被极窄列逼着取 colsep=0)。
%
% tabularray 的 colsep 计在每列【左右两侧】,故 2 列共 4×1.4993 = 5.9972mm;
% 竖线 3 根(左边界 + 中间 + 右边界)× 0.1764mm = 0.5292mm。
% 要让 Σwd + 5.9972 + 0.5292 = 170.000,需
% Σwd = 163.4736 mm
% 而 (gridCol − 2×1.4993) 之和为 164.0028 mm,两者差 0.5292 mm 正好是竖线宽,
% 故每列再减 0.5292/2 = 0.2646 mm。
%
% ⚠️ 上式只是理论值。tabularray 的计宽与画宽之间有约 0.45 pt 的取整差,
% 实际需再微调(见 3.2 的标定值),否则一直报
% "Table width is too small, need 0.45pt more!" 外加一条 Overfull \hbox。
%======================================================================
\newcommand{\sfmrule}{0.5pt} % 边框粗细(w:sz=4)
\newcommand{\sfmcolsep}{1.4993mm} % 单元格左右内边距(85 twips)
\newlength{\sfmtblw}
\setlength{\sfmtblw}{170mm} % 表宽(含 3 根竖线与 4 处内边距)
%----------------------------------------------------------------------
% 3.1 各列宽(= gridCol − 2×colsep − 竖线分摊的理论值)
% 与 sfmtable 环境里 colspec 的 wd 必须逐字一致。
%----------------------------------------------------------------------
\newcommand{\sfmwa}{47.7368mm} % c1 51.000 − 2.9986 − 0.2646
\newcommand{\sfmwb}{115.7368mm} % c2 119.000 − 2.9986 − 0.2646
%----------------------------------------------------------------------
% 3.2 各列【内容可用宽】
%
% 单列单元格的内容宽 = wd(左右两半 colsep 已被 colspec 扣掉并计入表格宽)。
% 本表全部是不跨列的单列格,没有"合并格回收内边距"的问题(ouclw.sty 的
% \lwspanA / \lwspanB 那类坑在这里不存在)。
%----------------------------------------------------------------------
%======================================================================
% 4. 行高
%
% 每行都是 w:trHeight + w:hRule="exact"(固定行高,不是 atLeast):
% R1 学年 42.55 pt = 15.011 mm
% R2 学期 42.55 pt = 15.011 mm
% R3 课程号 43.55 pt = 15.363 mm
% R4 选课号 41.05 pt = 14.482 mm
% R5 考试课程名称 41.30 pt = 14.570 mm
% R6 课程类型 42.55 pt = 15.011 mm
% R7 面向专业 93.10 pt = 32.844 mm ← 唯一高行,容 5 个专业名折行
% R8 面向年级 42.55 pt = 15.011 mm
% R9 试卷份数 52.80 pt = 18.627 mm
% R10 授课教师 42.55 pt = 15.011 mm
% R11 日期 42.55 pt = 15.011 mm
% ────────────────────────────────────────
% 合计 185.949 mm
%
% ⚠️ Word 的 exact 是"精确等于",内容超了会【被裁掉】。tabularray 的
% ht= 是最小行高(内容多则自动长高),语义更安全。本表各行内容都远
% 小于行高,两者结果相同,故直接写 ht=。
%
% ⚠️ 那几行 42.55 / 43.55 / 41.05 / 41.30 的零头不是随机的:Word 里
% 它们是"字符高 + 段前段后"凑出来的实际测量值,照抄才能与原卷逐行对齐。
%======================================================================
%======================================================================
% 5. 表格环境
%
% ⚠️ 用 tblr 而非 longtblr:本表总高约 186 mm,一页装得下(版心高
% 297 − 2×25.01 = 247 mm),不需要断页。
%
% ⚠️⚠️ colspec 与 row{} 必须字面写在这里,不能先存进宏再展开:
% tabularray 的列类型解析在宏展开之外进行,会报
% "Unexpandable command \xxx inside column type"。
% (所以 3.1 节那些 \sfmwa… 只作文档用,不能拼进 colspec。)
%
% ⚠️ 选项里的宏名一律不带 @:tabularray 解析选项时 @ 不是字母。
%======================================================================
\newenvironment{sfmtable}{%
\par\begingroup
\begin{tblr}[label=none]{
colspec={Q[c,m,wd=47.7368mm] Q[c,m,wd=115.7368mm]},
colsep=1.4993mm, rowsep=0pt, stretch=0,
hline{1-Z}={\sfmrule}, vline{1-Z}={\sfmrule},
row{1}={ht=15.011mm}, row{2}={ht=15.011mm},
row{3}={ht=15.363mm}, row{4}={ht=14.482mm},
row{5}={ht=14.570mm}, row{6}={ht=15.011mm},
row{7}={ht=32.844mm}, row{8}={ht=15.011mm},
row{9}={ht=18.627mm}, row{10}={ht=15.011mm},
row{11}={ht=15.011mm},
}%
}{%
\end{tblr}\par\endgroup}
%======================================================================
% 6. 单元格内容包装
%
% 本表全是单列格,tabularray 的 Q[c,m,wd=…] 已处理好居中与折行,
% 不需要 ouclw.sty 那种定宽 \parbox。这里只提供两个语义化的标签宏,
% 让 .tex 里不必反复写 \SFMHT{}。
%======================================================================
% \sfmlabel{文字} —— 左列标签:黑体 18pt
\newcommand{\sfmlabel}[1]{{\heiti\sfmbigfont #1\normalfont}}
% \sfmval{文字} —— 右列值(16pt,最常用)
\newcommand{\sfmval}[1]{{\heiti\sfmmidfont #1\normalfont}}
% \sfmvalbig{文字} —— 右列值(18pt):学年 / 学期两行
\newcommand{\sfmvalbig}[1]{{\heiti\sfmbigfont #1\normalfont}}
% \sfmvalsmall{文字} —— 右列值(14pt):课程号 / 选课号
\newcommand{\sfmvalsmall}[1]{{\heiti\sfmsmlfont #1\normalfont}}
%======================================================================
% 7. 表外标题
%
% 第 1 段:黑体、加粗、w:sz=36(18pt)、jc=center
%
% 原文标题是「信息科学与工程学院试卷」,按现行建制与文档实际用途已改为
% 「信息科学与工程学部试卷归档封面」
% 实际18pt 下宽 94.89mm,版心宽 170mm,左右各余约 37mm,单行不折。
% 再加长(比如后面挂"(理论课)")仍有余量,超过 170mm 才会折行。
%
% 标题与表格之间有 3 个空段落(idx 13/14/15),
% 合计 3 × 21.6pt = 64.8pt = 22.86 mm。这里用 \sfmtitleskip 还原。
%======================================================================
\newlength{\sfmtitleskip}
\setlength{\sfmtitleskip}{22.86mm}
\newcommand{\sfmtitle}[1]{%
\par
\begingroup
\centering
{\heiti\bfseries\sfmbigfont #1\par}%
\endgroup
\vspace{\sfmtitleskip}}
%======================================================================
% 8. 表后空行
%
% 表格之后还有一个空段落(idx 212)。
%======================================================================
\newcommand{\sfmtail}{\par\null\par}
\AtBeginDocument{\sfmbodyfont}
\endinput