Files

272 lines
13 KiB
TeX
Raw Permalink Normal View History

%======================================================================
% oucksfm.sty — 信息科学与工程学部 试卷归档封面(理论课)版式包
%
% 依据:附件1:信息科学与工程学院试卷封面(理论课).doc
% (SynologyDrive/授课/数字逻辑/2025/归档/)
% 原名与内文标题写的是「学院」,按现行建制改为「学部」,
% 模板标题相应为「信息科学与工程学部试卷归档封面」。
2026-11-01 09:29:00 +08:00
% 目标:版式与逐项对齐。所有尺寸都由 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. 页面与版心
%
2026-11-01 09:29:00 +08:00
% 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}
2026-11-01 09:29:00 +08:00
\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}
2026-11-01 09:29:00 +08:00
% 三档字号(行距取字号的 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 里这些 × 实际用的是
2026-11-01 09:29:00 +08:00
% 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. 列的宽度模型
%
2026-11-01 09:29:00 +08:00
% 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 的取整差,
2026-11-01 09:29:00 +08:00
% 实际需再微调(见 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. 行高
%
2026-11-01 09:29:00 +08:00
% 每行都是 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. 表外标题
%
2026-11-01 09:29:00 +08:00
% 第 1 段:黑体、加粗、w:sz=36(18pt)、jc=center
%
% 原文标题是「信息科学与工程学院试卷」,按现行建制与文档实际用途已改为
% 「信息科学与工程学部试卷归档封面」
2026-11-01 09:29:00 +08:00
% 实际18pt 下宽 94.89mm,版心宽 170mm,左右各余约 37mm,单行不折。
% 再加长(比如后面挂"(理论课)")仍有余量,超过 170mm 才会折行。
%
2026-11-01 09:29:00 +08:00
% 标题与表格之间有 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. 表后空行
%
2026-11-01 09:29:00 +08:00
% 表格之后还有一个空段落(idx 212)。
%======================================================================
\newcommand{\sfmtail}{\par\null\par}
\AtBeginDocument{\sfmbodyfont}
\endinput