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

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

862 lines
44 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.
%======================================================================
% oucexam.sty — 中国海洋大学 期末考试试卷 版式包
% 依据:数字逻辑 2025 秋 B 卷(195mm × 270mm 专用试卷纸)
% 所有尺寸单位 bp(PDF 点,1bp = 1/72in),与原卷 PDF 逐项对齐
%
% 用法见同目录 example-数字逻辑B卷.tex
%======================================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{oucexam}[2026/10/21 v1.0 OUC exam paper layout]
\RequirePackage{geometry}
\RequirePackage{fontspec}
\RequirePackage{xeCJK}
\RequirePackage{tikz}
\RequirePackage{graphicx}
\RequirePackage{eso-pic}
\RequirePackage{lastpage}
\RequirePackage{keyval}
\RequirePackage{ragged2e} % \justifying:原卷第3页设计题是两端对齐
\usetikzlibrary{calc}
%======================================================================
% 1. 页面版心
% 195mm × 270mm;左边距 29mm(装订侧),版心宽 154mm
% 版心上边界 34.13bp;首行基线落在 46.13bp
%======================================================================
\geometry{
paperwidth = 195mm,
paperheight = 270mm,
left = 82.2bp,
textwidth = 436.55bp,
top = 34.13bp,
textheight = 665.87bp,
headheight = 0pt,
headsep = 0pt,
footskip = 0pt,
}
\setlength{\parindent}{0pt}
\setlength{\parskip}{0pt}
\setlength{\topskip}{12bp} % 首行基线 = 34.13 + 12 = 46.13bp
\pagestyle{empty}
\raggedright % 左对齐,右端不拉伸(与原卷一致)
% 注意:ctexart 会在 \begin{document} 时把 \linespread 设为 1.3,
% 必须用同一钩子(后注册者后执行)压回 1,否则基线网格全乱。
\AtBeginDocument{\linespread{1}\Fivhao\selectfont}
%======================================================================
% 2. 字体(全部统一为思源宋体)
% 全部取自仓库公共字体包 ../fonts.tex(字体文件在 ../fonts/ 下)。
%
% ★ 本版把试卷的所有文字统一为**思源宋体(OUC Serif)**,中西文同一字族:
% 中文正文 / 标题 OUC Serif(真粗体,不再 AutoFakeBold)
% 西文 / 阿拉伯数字 OUC Serif ✅ 与中文同族(本版改动)
% 卷头三行填空 OUC Serif ✅ 原为霞鹜文楷
% 成绩表"题号/得分/一~八/总分" OUC Serif ✅ 原为霞鹜文楷
%
% ⚠️ 为什么西文也能用思源宋体
% 已实际OUCSerif-Regular.otf / -Bold.otf:13714 字形、cmap 7555 条,
% ASCII 字母数字与常用标点 35/35 全部命中。它不是纯中文字体,
% 西文字形是配套设计的,与汉字同灰度 —— 这正是要的效果。
%
% ⚠️⚠️ 与 Termes 的度量差异(换字体必然推动版面,别当回归)
% 旧版西文用 TeX Gyre Termes(Times 度量)。原卷 SimSun 的西文是
% 全 ASCII 0.500 em 等宽,Termes 的数字也是 0.500 em,所以选它能让
% 数字零漂移。思源宋体的西文**不是等宽**,比 Termes 宽:
% 数字 0-9 0.549~0.562 em (+0.049~+0.062)
% 小写 m 0.974 vs 0.778 (+0.196,最明显)
% 小写 b 0.638 vs 0.500 (+0.138)
% 句点 . 0.327 vs 0.250 (+0.077)
% 连字符 - 0.346 vs 0.333 (+0.013)
% 影响:题号、分值、页码右移约 6%,题干里的英文单词变长。
%
% ⚠️ 装订线的 4 组连字符虚线已改为**用线画**(见第 6 节),
% 不再受字体宽度影响。旧版是靠 18bp 连字符排出来的,
% 换字体后每串会长 4~7bp,故锁定为几何坐标。
%
% ⚠️ 数学公式**不在统一范围内**(答案卷的 $x$、$\dfrac{}{}$ 等仍走
% Computer Modern)。理由:思源宋体没有 MATH 表(实际只有
% GSUB/GPOS),不能作数学字体;强行塞进正文字体会破坏斜体变量、
% 正体数字、运算符间距这些数学排版规则。用户已确认保持不动。
%======================================================================
\input{../fonts.tex}
%----------------------------------------------------------------------
% 西文字族:把思源宋体登记成一个**独立字族** \OUCLatinSerif
%
% 为什么不直接把 \tnr 改成 \setmainfont 指过去:
% ① ../fonts.tex 是**全库共用**的,改它的 \tnr 会连带改掉科技报告和
% 简历 —— 那两个模板有自己的西文设定(Cochineal / Termes),不该外溢。
% ② 试卷需要的是"西文也用宋体",这在排版上是**回到中文字体的西文字形**,
% 本质是让西文跟 CJK 主字体一致,而不是"换一套西文字体"。
% 所以在试卷包内单独登记一族,只改本包的命令指向。
%
% ⚠️ 用 \newfontfamily 而不是 \setCJKfamilyfont:这里要的是西文字族,
% 走 fontspec 的 Latin 通道;中文由 \setCJKmainfont 那边管,互不干扰。
% ⚠️ 四个档位必须全给。少给会在 \bfseries 里静默回落到默认字体,
% 表现为"加粗失效"而不是报错(试卷的 \TNRB / \qnum / 大题标题都会踩到)。
% ⚠️ 斜体档:思源宋体没有真正的意大利斜体(只有 Regular / Bold 两档)。
% 这里让 Italic 指回 Regular、BoldItalic 指回 Bold —— 即"中文式斜体"
% (不倾斜)。本模板正文没有 \textit / \emph 用法,此设定只是防止将来
% 有人用了就报 Font shape undefined。真要斜体请用 \kaiti 代斜的惯例。
%----------------------------------------------------------------------
\newfontfamily\OUCLatinSerif{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
% 粗体专职档:与 \tnrb 的语义一致("取粗体那一字形当常规用")。
% \TNRB{} 用它,保证括号、分值数字是真的粗,而不是靠 AutoFakeBold 描边。
\newfontfamily\OUCLatinSerifBold{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Bold,
BoldFont = *-Bold,
ItalicFont = *-Bold,
BoldItalicFont = *-Bold,
]
%----------------------------------------------------------------------
% 把**默认西文字体**也换成思源宋体(这是关键一步)
%
% 模板里有大量文字**根本没走 \tnr**,而是走 \setmainfont(默认西文族):
% · \textbf{learning outcome} —— 裸加粗,西文走 \setmainfont
% · 页脚的页码 / 总页数 —— \node{...\thepage} 裸排
% · 任何 \fontsize..\selectfont 之后的裸 ASCII
% 第一轮只做了 \let\tnr\OUCLatinSerif,结果 PDF 里仍残留 22 个
% TeXGyreTermes span:页脚 6 个页码 + 6 个总页数 + 第 4 页的
% A./B./C./D. 与 learning outcome 等。
% ⇒ 必须连 \setmainfont 一起改,才算"全部用思源宋体"。
%
% ⚠️ 为什么可以安全地在这里 \setmainfont:
% 本包由试卷/答案卷各自的 .tex \usepackage 载入,\setmainfont 只影响
% 当前文档。其他模板(科技报告/简历/幻灯片)各自 \input ../fonts.tex
% 并各自设主字体,互不干扰。
%
% ⚠️ 四个档位必须全给。缺斜体档时 \textit 会报
% Font shape `TU/OUCSerif(0)/m/it' undefined 并静默回落。
% 思源宋体没有真斜体,这里让 it 指回 Regular(中文式斜体,不倾斜)。
%----------------------------------------------------------------------
\setmainfont{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
% sans 位也指到思源宋体:本试卷没有真正的 sans 用法,但 \textsf 之类的
% 兜底也应该是宋体,不能漏回 Termes。sans 位不加粗体档,用 Regular 顶上。
\setsansfont{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
%----------------------------------------------------------------------
% 把本包内的字体命令全部重定向到思源宋体
%
% ⚠️ \let 是一次性绑定:绑完再改 \tnr 的定义,\tnr 仍指旧目标。
% 这里 \let 到 \OUCLatinSerif 是**有意为之** —— 让 \tnr / \tnrb 与
% \setmainfont 走同一族,但保持两个独立命令名,因为 \tnrb 是
% "取粗体当常规用"(\TNRB 需要),与 \bfseries 语义不同。
%----------------------------------------------------------------------
\let\tnr\OUCLatinSerif
\let\tnrb\OUCLatinSerifBold
% \sunfont 原指 SimSun("宋体西文"占位),现一并指思源宋体。
% 保留命令名是为了不动 \qnum / \logicexpr / \sumsig 等所有调用点。
\let\sunfont\OUCLatinSerif
% \kaiti 在试卷里只用于卷头填空与成绩表题号(见 \kh / \scoretable)。
%为思源宋体,故整个包内把 \kaiti 也指到思源宋体。
% ⚠️ 用 \let 而不是改 \def\kaiti —— 后者会破坏 ../fonts.tex 的定义,
% 而 \kaiti 在别的模板里还要用楷体。
% ⚠️ 若将来要恢复楷体卷头,把下面这行注释掉即可,其余代码不用动。
\let\kaiti\songti
%----------------------------------------------------------------------
% ⚠️ xeCJK 陷阱:字体切换命令若紧邻 \par(或位于段落末尾),
% 该段结束时的字体状态会"溢出"到后续段落,导致后面的 ASCII
% 字符全部被排成 Times(\tnr{ABC}\par 会让下一段的 "3" 变 Times)。
% 故所有局部字体切换一律走下面两个包装:内部显式 \normalfont 收尾。
% ⇒ 正文中请用 \TNR{...} / \TNRB{...} / \SUN{...},不要裸用 \tnr。
%----------------------------------------------------------------------
\newcommand{\TNR}[1]{{\tnr #1\normalfont}}
\newcommand{\TNRB}[1]{{\tnrb #1\normalfont}}
\newcommand{\SUN}[1]{{\sunfont #1\normalfont}}
% Word「字符间距展开」模拟:逐字之间插入固定胶
% \spreadtext{0.30}{文字} —— 0.30bp 即 10.50→10.80bp 的步距
% 实现:先输出首字,再对余下每个字"先插空隙、后出字"(首字前不插,否则整体右移)
\newcommand{\spreadtext}[2]{%
\begingroup\spread@amt=#1bp\relax
\expandafter\@spreadtext#2\@nil\endgroup}
\newdimen\spread@amt
\def\@spreadtext#1#2\@nil{#1\@spreadeach#2\@nil}
\def\@spreadeach#1{%
\ifx#1\@nil\else\hspace*{\spread@amt}#1\expandafter\@spreadeach\fi}
% 中文与西文间自动间距:原卷实际固定 2.70bp(不随字号缩放,
% 故用绝对 bp 而非 em;原卷 10.5bp 与 12bp 处均为 2.7bp)
\xeCJKsetup{CJKecglue={\hskip 2.70bp\relax},PunctStyle=plain}
%======================================================================
% 3. 字号(bp,直接对应原卷)
%======================================================================
\newcommand{\Fivhao}{\fontsize{10.5bp}{15.6bp}\selectfont} % 五号 正文(原卷 10.5bp)
\newcommand{\Sihao}{\fontsize{12bp}{15bp}\selectfont} % 小四 大题
\newcommand{\DaSihao}{\fontsize{14.05bp}{16bp}\selectfont} % 四号 卷头
\newcommand{\Xiaowu}{\fontsize{9bp}{11bp}\selectfont} % 小五 图题
\AtBeginDocument{\Fivhao}
%======================================================================
% 4. 卷头参数
%======================================================================
\def\ouc@year{}\def\ouc@term{}\def\ouc@course{}\def\ouc@college{}
\def\ouc@type{}\def\ouc@proposer{}\def\ouc@reviewer{}
\def\ouc@mode{}\def\ouc@allowed{}
\define@key{ouc}{year}{\def\ouc@year{#1}}
\define@key{ouc}{term}{\def\ouc@term{#1}}
\define@key{ouc}{course}{\def\ouc@course{#1}}
\define@key{ouc}{college}{\def\ouc@college{#1}}
\define@key{ouc}{type}{\def\ouc@type{#1}}
\define@key{ouc}{proposer}{\def\ouc@proposer{#1}}
\define@key{ouc}{reviewer}{\def\ouc@reviewer{#1}}
\define@key{ouc}{mode}{\def\ouc@mode{#1}}
\define@key{ouc}{allowed}{\def\ouc@allowed{#1}}
\newcommand{\examsetup}[1]{\setkeys{ouc}{#1}}
%----------------------------------------------------------------------
% 页脚是否印"试卷类型字母"(课程名之后那个 A / B)
%
% ★ 原卷A 卷页脚【没有】字母(数字逻辑 + 一串短横线),
% B 卷页脚【有】B(392.48 处)。
% 即:这是出卷人手工敲的,不是规则。故默认不印,需要时显式打开:
% \examsetup{foottype = {B}} → 页脚印 B
% \examsetup{foottype = {}} → 页脚不印(默认)
%----------------------------------------------------------------------
\def\ouc@foottype{}
\define@key{ouc}{foottype}{\def\ouc@foottype{#1}}
%======================================================================
% 5. 页脚:+…………………………课程名称 X……… 第 N 页 共 M 页 + 基线 713.33bp
%
% 本地(原卷字符级):
% 82.20 '+' | 91.20~343.20 连续 29 个 '…'(每个步距 9.00)
% 352.20 起课程名(长度不定)| 类型字母在 390.48
% 396.48 起 3 个 '…' | 432.48 '第' | 443.64 页码 | 448.20 '页'
% 461.64 '共' | 472.92 总页 | 477.48 '页' | 499.92 '+'
%
% ★ 课程名长度可变,前面那串圆点必须"自动伸缩":
% · 课程名 ≤ 36bp(4 个汉字)→ 左锚保持 352.20,点区 29 个点(与原卷一致)
% · 课程名更长 → 左锚左移,点区自动缩短(这就是用户要的"按名称长度缩减")
% 点区终点固定在左锚前 3bp,绝不与课程名重叠。
%======================================================================
\newbox\ouc@dotbox
\newdimen\ouc@cnw
\newdimen\ouc@cstart
\newdimen\ouc@fw
\newdimen\ouc@tstart
\newdimen\ouc@tfw
% 测课程名宽度 -> 定左锚 -> 定点区宽度(shipout 时执行,读的是 \ouc@course)
\newcommand{\ouc@prepfooter}{%
\setbox\ouc@dotbox\hbox{\fontsize{9bp}{9bp}\selectfont\ouc@course}%
\ouc@cnw=\wd\ouc@dotbox
\ifdim\ouc@cnw>36bp
% 偏长:右端钉在 388.20,向左生长(点区自动变短)
\ouc@cstart=\dimexpr 388.20bp-\ouc@cnw\relax
\else
% 不长:用原卷锚点(此时点区正好 29 个点)
\ouc@cstart=352.20bp
\fi
% 点区宽度 = 左锚 - 起点 91.20
% ★ 不减空隙:\leaders 按整步距铺,最后一点的右缘正好落在左锚上
% (原卷正是这样:点占 91.20~352.20,课程名紧接 352.20 起)
\ouc@fw=\dimexpr\ouc@cstart-91.20bp\relax
\ifdim\ouc@fw<9bp \ouc@fw=9bp \fi
% ---- 无字母模式:三点从课程名右缘 +4bp 起,铺到"第"(432.48) 之前 ----
\ifx\ouc@foottype\@empty
\ouc@tstart=\dimexpr\ouc@cstart+\ouc@cnw+4bp\relax
\ouc@tfw=\dimexpr 432.48bp-\ouc@tstart\relax
\ifdim\ouc@tfw<9bp \ouc@tfw=9bp \fi
\fi}
% 点区:\leaders 按 9bp 步距自动铺满(个数自动取整)
\newcommand{\ouc@dotsfill}{%
\hbox to \ouc@fw{\leaders\hbox{\makebox[9bp][c]{…}}\hfill}}
% 无字母模式下课程名之后的点区(步距 9bp,铺到"第"之前)
\newcommand{\ouc@taildots}{%
\hbox to \ouc@tfw{\leaders\hbox{\makebox[9bp][c]{…}}\hfill}}
\newcommand{\ouc@makefooter}{%
\ouc@prepfooter
\begin{tikzpicture}[remember picture,overlay]
\coordinate (F) at ([yshift=-713.33bp]current page.north west);
% 左端 +
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=82.20bp]F) {+};
% 伸缩圆点区(\leaders 自动铺满,步距 9bp)
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=91.20bp]F) {\ouc@dotsfill};
% 课程名(左锚随长度自动左移)
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=\ouc@cstart]F) {\ouc@course};
% 类型字母(可选)+ 后随 3 点
% ★ 原卷 A 卷无字母、B 卷有 B,属手工差异 ⇒ 由 foottype 开关控制,
% 默认空(不印)。印字母时字母在 390.48、三点从 396.48 起;
% 不印时三点紧接课程名右侧 4bp 处(与原卷 A 卷一致)。
\ifx\ouc@foottype\@empty
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=\ouc@tstart]F) {\ouc@taildots};
\else
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=390.48bp]F) {\ouc@foottype};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=396.48bp]F) {\makebox[27bp][l]{………}};
\fi
% 逐段定位,避开 xeCJK 在中西文之间自动加的间距
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=432.48bp]F) {第};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=443.64bp]F) {\thepage};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=448.20bp]F) {页};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=461.64bp]F) {共};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=472.92bp]F) {\pageref{LastPage}};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=477.48bp]F) {页};
% 右端 +
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=499.92bp]F) {+};
\end{tikzpicture}%
}
% ★ 挂到 shipout 钩子:每页自动出页脚,\ouc@prepfooter 在 shipout 时机测宽度
\AddToShipoutPictureFG{\ouc@makefooter}
%======================================================================
% 6. 装订线(左侧竖栏)
%
% ★ 印张规则:试卷用大纸双面印刷,偶数页拼在奇数页背面(同一张纸)。
% "装订线 + 学号/姓名/…" 只印在**奇数页**(右页,即正面);
% 偶数页是它的背面,不能再印一遍,否则折进去看不见、还浪费。
% ⇒ 默认自动判断:本页是奇数页才画(用 \ifodd\value{page})。
%
% 用法:
% \bindstrip → 自动(奇数页画、偶数页不画)★推荐
% \bindstrip[on] → 强制画(比如检查偶数页效果)
% \bindstrip[off] → 强制不画
% \bindstrip[1.3] → 自动 + 纵向整体下移 1.3bp(复刻原卷该页瑕疵)
% \bindstrip[1.3,on] → 强制画 + 下移
% 局部覆盖单页:\ouc@bindforce 置 1/0
%
% 本地(原卷 p1,x 坐标全部 bp):
% 竖虚线 x=33.8,5 段:101.1~148.5 / 222.4~290.8 / 359.4~427.9
% 489.3~557.8 / 600.0~668.6
% 18bp Times 连字符串 x=55.69("装/订/线"三字压在上面,白底遮断)
% 栏目名 x=32.65(竖排,自下而上);冒号单列在 x=32.89
% ★ 竖线每段 = 对应栏目的"填写区"(冒号之后向上延伸),共 6 段。
% 第 6 段 37.6~69.4 是"座号"的填写区——原 B 卷 PDF 里漏画了这一段,
% 看起来就是"座号后面没横线",学生无处可填。此处按 A 卷补齐。
% 另有一圈细边框(x=17.4 / 60.2 两条竖线 + 上下横封)。
%======================================================================
\newdimen\ouc@bindshift
%--------------------------------------------------------------------
% 开关:\bindstriptrue / \bindstripfalse(全局是否启用装订线)
% \bindstripoddfalse(默认 false = 只在奇数页画)
% \bindstripoffset{1.3bp}(整体纵向偏移,复刻原卷瑕疵)
%--------------------------------------------------------------------
\newif\ifouc@bindon \ouc@bindontrue
\newif\ifouc@bindodd \ouc@bindoddfalse % false: 只画奇数页
\newcommand{\ouc@bindshiftdimen}{0bp}
\newcommand{\bindstripoffset}[1]{\setlength{\ouc@bindshift}{#1}}
\setlength{\ouc@bindshift}{0pt}
% \bindstrip:保留兼容。现在只在需要"本页强制"时才用它;
% 正常情况装订线由 shipout 钩子自动画(见文件末尾),无需逐页调用。
\newcommand{\bindstrip}[1][]{%
\ifx\relax#1\relax\else
\ifx\@empty#1\@empty\else \setlength{\ouc@bindshift}{#1bp}\fi
\fi}
%----------------------------------------------------------------------
% 装订线虚线段:一个连字符笔画 = 一条**竖直**短线段
%
% 参数:#1 = 这一串最上一笔的顶端 y 坐标(bp,从页面顶端往下量)
% #2 = 笔画个数
% 相邻笔画顶端间隔 6.00bp,与原卷 18bp 连字符的步距一致。
%
% 原卷的连字符是 rotate=90 排的,所以连字符的**横向长度转到了纵轴**、
% **线粗转到了横轴**。也就是说每一笔是「竖着的短杠」,不是「横着的短杠」:
% 竖:y 跨 4.30bp(这是连字符的字面长度)
% 横:x 跨 1.10bp(这是连字符的笔画粗细)
% 中心 x = 51.60bp
% 第一版按"水平线"画((49.40,y)--(53.70,y)),结果整条装订线变成
% 一把**梯子**(一排横杠叠在竖线位置),与基线观感完全不同。
%
% ⚠️ x 中心 51.60bp 是原卷连字符字符盒 x 41.60~59.60(18bp 宽),
% 但可见笔画只在 51.10~52.10,即字形在字符盒内偏右、
% 中心 51.60 —— 这是 Times 连字符的字形位置,不是笔误。
%
% ⚠️ 必须定义在 \ouc@dobindstrip **外面**。放进去的话每次 shipout 都会
% 重新 \newcommand 一次,第二页起报 "command already defined"。
% ⚠️ y 坐标**不能**写成 \dimexpr#1bp+\i*6bp:TikZ 的坐标解析器不认
% 带小数点的小数 + \dimexpr 组合,会报
% Illegal unit of measure (pt inserted)
% Package PGF Math Error: Unknown operator `.' or `.0'
% 必须先 \pgfmathsetmacro 算成纯数字,再拼 "bp"。
%----------------------------------------------------------------------
\newcommand{\ouc@dashseg}[2]{%
\foreach \i in {0,...,\the\numexpr#2-1\relax}{%
\pgfmathsetmacro{\ouc@dyy}{#1+\i*6.00}%
\pgfmathsetmacro{\ouc@dzz}{\ouc@dyy+4.30}%
\draw[line width=1.10bp,line cap=butt]
([xshift=51.60bp,yshift=-\ouc@dyy bp]B) --
([xshift=51.60bp,yshift=-\ouc@dzz bp]B);}}
\newcommand{\ouc@dobindstrip}{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (B) at ([yshift=-\ouc@bindshift]current page.north west);
% ---- ★ 原卷此处【没有】外框 ----
% 曾误把 PDF 里 x=17.4/18.12/60.15/60.87 那组线当成黑色外框,
% 实际它们是 fill=(1,1,1) 的**白色遮挡块**(Word 里盖住页眉页脚
% 的底色块),可见黑线只有 x=33.80 那 6 段竖虚线。
% 故此处不画任何竖线/封口线。
% ---- 竖虚线:每段 = 对应栏目的"填写区"(紧接栏目名冒号之后,向上延伸)----
% 原卷 6 段,逐段对应:
% 600.05~668.60 ← 学号(冒号止于 668.6)
% 489.30~557.80 ← 姓名(止于 557.8)
% 359.35~427.85 ← 专业年级(止于 427.8)
% 222.40~290.80 ← 授课教师
% 101.10~148.50 ← 考场教室号(止于 148.5)
% 37.60~ 69.40 ← 座号(冒号止于 69.6)★ 原 B 卷 PDF 漏画,此处补上
% —— 这就是"座号后面那条线",缺了学生没法填座号。
\foreach \a/\b in {37.60/69.40, 101.10/148.50, 222.40/290.80,
359.35/427.85, 489.30/557.80, 600.05/668.60}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=33.8bp,yshift=-\a bp]B) -- ([xshift=33.8bp,yshift=-\b bp]B);}
% ---- 虚线段(由「18bp 连字符排成」改为「用线画」)----
% 原卷这四段确实是 18bp Times 连字符排出来的,但本包把试卷字体
% 统一到思源宋体之后,连字符每个宽 0.346 em(Termes 是 0.333),
% 18bp 下每串会长出 4~7bp,正好破坏"复刻原卷长度"这个前提。
% ⇒ 改为几何画的短横线段,长度锁死在 \ouc@dashseg 的坐标里,
% 不受任何字体宽度影响。
% 实际原卷(720dpi 渲染后逐笔画测量):
% 单个连字符笔画 长 4.40bp、粗 1.10bp、x 中心 51.60bp
% → 左 49.40bp、右 53.80bp
% 相邻笔画步距 6.00bp(= 18bp × 0.333 em)
% 六段坐标与笔画数取自原卷逐笔画实际,见下方调用处。
\ouc@dashseg{62.20}{24}% 最下一串(座号区)
\ouc@dashseg{216.50}{24}% 考场教室号区
\ouc@dashseg{364.80}{3}% 截断的短线(原卷被白底遮断,照抄)
\ouc@dashseg{393.40}{13}% 授课教师区(上半截)
\ouc@dashseg{475.80}{16}% 专业年级区
\ouc@dashseg{582.10}{16}% 学号 + 姓名区(最上一串)
% ---- 竖排栏目名(自下而上读)----
% 原卷只有"姓名:""授课教师:"把冒号连排,其余冒号单独一行
\foreach \lab/\pos in {学号/694.06, 姓名:/585.10, 专业年级/474.46,
授课教师:/349.78, 考场教室号/207.46, 座号/96.70}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=0.7bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=32.65bp,yshift=-\pos bp]B) {\lab};}
% ---- 单独的冒号行:学号 / 专业年级 / 考场教室号 / 座号 ----
\foreach \pos in {672.94, 432.22, 154.66, 75.70}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=0.7bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=32.89bp,yshift=-\pos bp]B) {:};}
% ---- 装 / 订 / 线 ----
\foreach \lab/\pos in {装/581.44, 订/392.68, 线/215.80}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=1.2bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=52.69bp,yshift=-\pos bp]B) {\lab};}
\end{tikzpicture}%
}
%======================================================================
% 7. 成绩表(题号 / 得分)
% 默认 8 个题号 + 总分共 9 栏,与原卷逐项对齐(栏宽 44.05bp)。
% 大题数不是 8 时,用 \examsetup{nsec = 11} 指定,自动按等宽重算。
%======================================================================
\def\ouc@nsec{8}
\define@key{ouc}{nsec}{\def\ouc@nsec{#1}}
% 题号汉字(支持到十六)
\newcommand{\ouc@cnnum}[1]{%
\ifcase\numexpr#1\relax\or 一\or 二\or 三\or 四\or 五\or 六%
\or 七\or 八\or 九\or 十\or 十一\or 十二%
\or 十三\or 十四\or 十五\or 十六\fi}
\newcommand{\scoretable}{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (S) at (current page.north west);
\ifnum\ouc@nsec=8
% ---- 原卷版:坐标逐项硬对齐 ----
\foreach \y in {159.04,181.99,212.44}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=122.81bp,yshift=-\y bp]S) -- ([xshift=478.24bp,yshift=-\y bp]S);}
\foreach \x in {123.05,167.10,201.10,235.10,269.10,303.10,337.10,
371.10,405.10,439.10,478.00}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=\x bp,yshift=-158.80bp]S) -- ([xshift=\x bp,yshift=-212.20bp]S);}
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=145.075bp,yshift=-174.89bp]S) {题号};
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=145.075bp,yshift=-201.53bp]S) {得分};
\foreach \name/\cx in {一/184.10, 二/218.10, 三/252.10, 四/286.10,
五/320.10, 六/354.10, 七/388.10, 八/422.10,
总分/458.55}{%
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=\cx bp,yshift=-174.89bp]S) {\name};}
\else
% ---- 自适应版:标签栏 + nsec 格 + 总分格 ----
% 横向:标签栏 123.05~163.05(宽 40),其后 nsec+1 格等分到 478.00
% 12 个大题时每格 (478-163.05)/13 = 24.2bp,正好容得下"十一"(12bp×2=24)
\pgfmathsetmacro{\ouc@cwl}{163.05}
\pgfmathsetmacro{\ouc@cw}{(478.00-\ouc@cwl)/(\ouc@nsec+1)}
% 题号字号自适应:两字题号(如“十一”)需 2×字号 ≤ 格宽 - 2bp 余量
% 12 题 → 格宽 24.2bp → 字号 11.1bp(仍按 12bp 上限,视觉不变)
% 16 题 → 格宽 18.5bp → 字号 8.3bp(自动缩小,不溢出)
\pgfmathsetlengthmacro{\ouc@fs}{min(12,(\ouc@cw-2)/2)*1bp}
% 三条横线(原卷 159.04 / 181.99 / 212.44)
\foreach \y in {159.04,181.99,212.44}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=123.05bp,yshift=-\y bp]S) -- ([xshift=478.00bp,yshift=-\y bp]S);}
% 内容区竖线(标签栏右界即第一格左界,一并画上)
\foreach \i in {0,...,\the\numexpr\ouc@nsec+1\relax}{%
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+\i*\ouc@cw}%
\draw[line width=0.48bp,line cap=butt]
([xshift=\ouc@xx bp,yshift=-158.80bp]S) --
([xshift=\ouc@xx bp,yshift=-212.20bp]S);}
% 标签栏左侧那条竖线(原卷 123.05)
\draw[line width=0.48bp,line cap=butt]
([xshift=123.05bp,yshift=-158.80bp]S) --
([xshift=123.05bp,yshift=-212.20bp]S);
% 标签栏文字
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=143.05bp,yshift=-174.89bp]S) {题号};
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=143.05bp,yshift=-201.53bp]S) {得分};
% 题号 一…十二(居中于各自格子)
\foreach \i in {0,...,\the\numexpr\ouc@nsec-1\relax}{%
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+(\i+0.5)*\ouc@cw}%
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=\ouc@xx bp,yshift=-174.89bp]S)
{\ouc@cnnum{\numexpr\i+1\relax}};}
% 总分
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+(\ouc@nsec+0.5)*\ouc@cw}%
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=\ouc@xx bp,yshift=-174.89bp]S) {总分};
\fi
\end{tikzpicture}%
}
%======================================================================
% 8. 卷头
% 标题 + 三行填空 + 成绩表;随后补足垂直空白,
% 使正文首行基线正好落在 240.41bp
%======================================================================
\newcommand{\kh}[1]{\node[anchor=base west,inner sep=0pt,
font=\fontsize{10.45bp}{12bp}\selectfont\kaiti] at ([xshift=#1]H)}
\newcommand{\examhead}[1][184.39bp]{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (H) at (current page.north west);
% ---- 标题 ----
\node[anchor=base west,inner sep=0pt,
font=\fontsize{14.05bp}{16bp}\selectfont\bfseries]
at ([xshift=151.92bp,yshift=-54.65bp]H) {中国海洋大学全日制本科课程期末考试试卷};
% ---- 第 1 行 ----
\kh{113.52bp,yshift=-96.29bp} {\ouc@year};
\kh{139.80bp,yshift=-96.29bp} {年};
\kh{160.80bp,yshift=-96.29bp} {\ouc@term};
\kh{181.80bp,yshift=-96.29bp} {季学期};
\kh{224.04bp,yshift=-96.29bp} {考试科目:};
\kh{287.16bp,yshift=-96.29bp} {\ouc@course};
\kh{360.84bp,yshift=-96.29bp} {学院:};
\kh{402.96bp,yshift=-96.29bp} {\ouc@college};
\draw[line width=0.96bp,line cap=butt]
([xshift=113.50bp,yshift=-97.80bp]H) -- ([xshift=139.80bp,yshift=-97.80bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=150.20bp,yshift=-97.80bp]H) -- ([xshift=181.80bp,yshift=-97.80bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=276.70bp,yshift=-97.80bp]H) -- ([xshift=360.80bp,yshift=-97.80bp]H);
\draw[line width=0.48bp,line cap=butt]
([xshift=402.95bp,yshift=-97.40bp]H) -- ([xshift=508.40bp,yshift=-97.40bp]H);
% ---- 第 2 行 ----
\kh{116.40bp,yshift=-119.69bp} {试卷类型:};
\kh{184.92bp,yshift=-119.69bp} {\ouc@type};
\kh{207.60bp,yshift=-119.69bp} {卷};
\kh{228.60bp,yshift=-119.69bp} {命题人:};
\kh{276.00bp,yshift=-119.69bp} {\ouc@proposer};
\kh{363.60bp,yshift=-119.69bp} {审核人:};
\kh{410.00bp,yshift=-119.69bp} {\ouc@reviewer};
\draw[line width=0.96bp,line cap=butt]
([xshift=169.20bp,yshift=-121.20bp]H) -- ([xshift=207.60bp,yshift=-121.20bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=269.00bp,yshift=-121.20bp]H) -- ([xshift=358.30bp,yshift=-121.20bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=405.70bp,yshift=-121.20bp]H) -- ([xshift=495.00bp,yshift=-121.20bp]H);
% ---- 第 3 行:考试说明 ----
\kh{108.48bp,yshift=-154.73bp} {考试说明:本课程为\ouc@mode 考试,共};
\kh{264.84bp,yshift=-154.73bp} {\pageref{LastPage}};
\kh{275.40bp,yshift=-154.73bp} {页,除考场规定的必需用品外还可携带的文具有};
\kh{497.90bp,yshift=-154.73bp} {\ouc@allowed。};
\draw[line width=0.48bp,line cap=butt]
([xshift=259.55bp,yshift=-156.10bp]H) -- ([xshift=275.40bp,yshift=-156.10bp]H);
\draw[line width=0.48bp,line cap=butt]
([xshift=492.60bp,yshift=-156.10bp]H) -- ([xshift=513.60bp,yshift=-156.10bp]H);
\end{tikzpicture}%
\scoretable
\par\vspace*{#1}\nointerlineskip
}
%======================================================================
% 9. 正文构件
%======================================================================
% 大题标题:宋体小四伪粗;与下一行基线距 15.0bp(正文 15.6bp)
% 标题内数字/括号用 Times Bold,中文与它们之间是固定 bp 空隙(原卷如此),
% 故局部关掉 xeCJK 自动间距,空隙一律显式给:\oucsp{6}
\newcommand{\oucsp}[1]{\hspace*{#1bp}}
\newcommand{\examheading}[2][0bp]{%
\par\ifdim#1>0bp\vspace*{#1}\fi
\noindent{\xeCJKsetup{CJKecglue={}}\fontsize{12bp}{15bp}\selectfont\bfseries #2}\par
\vspace*{\ouc@headgap}}
% 小题:\qi[题号栏宽]{题号}{题干}
% 原卷第 1 页题号用宋体半角("1." 占 10.44bp)+ 5.28bp 空隙 = 栏宽 15.72bp
% 第 2/3 页题号用 Times("1." 占 8.16bp)+ 空格,栏宽 13.08bp
% 少数题(如 3. 6.)题号后不留空,栏宽 10.44bp
\newcommand{\qnum}[1]{\makebox[15.72bp][l]{\sunfont #1.}}
\newcommand{\qi}[3][15.72bp]{\par\noindent\makebox[#1][l]{\sunfont #2.}#3\par}
% 注意:\tnr 只包住题号本身,必须用 {\tnr #2.} 关掉,否则 Times 泄到正文
% ★ 题干内部换行一律用 \\*(禁止分页),不要用裸 \\:
% 裸 \\ 是"允许在此断页",题干会被切到上下两页,学生看到半句话。
\newcommand{\qiT}[3][13.08bp]{\par\noindent\makebox[#1][l]{{\tnr #2.}}\ignorespaces#3\par}
% 宋体题号版(第 3 页设计题:原卷 "1." 是 SimSun 10.45,且题号后无空格)
\newcommand{\qiS}[3][15.72bp]{\par\noindent\makebox[#1][l]{{\sunfont #2.}}\ignorespaces#3\par}
% 选项:每栏 84bp,标签栏 15.72bp(与原卷逐字对齐)
\newcommand{\opt}[2]{\makebox[84bp][l]{\qnum{#1}#2}}
\newcommand{\choices}[4]{%
\par\noindent\opt{A}{#1}\opt{B}{#2}\opt{C}{#3}\opt{D}{#4}\par}
\newcommand{\optone}[2]{\par\noindent\opt{#1}{#2}\par}
% 图题:小五,居中于版心
\newcommand{\examfigcaption}[1]{%
\par\nointerlineskip\centerline{\Xiaowu #1}\par\nointerlineskip}
% 图题(五号):原卷第 3 页 "图3" 实际10.45bp
\newcommand{\examfigcaptioniii}[1]{%
\par\nointerlineskip\centerline{\Fivhao #1}\par\nointerlineskip\vspace*{5.40bp}}
% 插图:\examfig[水平偏移]{宽度}{文件}
% 用 \vspace* 精确控制与上一基线的距离,偏移以版心左边界为基准
\newcommand{\examfig}[3][0bp]{%
\par\nointerlineskip\vspace*{\ouc@figskip}%
\noindent\hspace*{#1}\includegraphics[width=#2]{#3}%
\par\nointerlineskip\vspace*{\ouc@figtail}}
\def\ouc@headgap{-0.6bp}
\def\ouc@figskip{0bp}
\def\ouc@figtail{0bp}
\newcommand{\figskip}[1]{\def\ouc@figskip{#1}}
\newcommand{\figtail}[1]{\def\ouc@figtail{#1}}
% 逻辑表达式:按原卷用宋体直排文本,不用数学模式(字距才对得上)
\newcommand{\logicexpr}[1]{{\sunfont #1}}
% 求和符号 Σ / 带 Φ 的 Σ,跟正文同高(原卷是混排文本,不是数学符号)
\newcommand{\sumsig}{\hbox{\sunfont ∑}}
\newcommand{\sumphisig}{\hbox{\sunfont ∑Φ}}
% 下标(原卷 M_L / M_S)
% L/S 字号 5.30bp(SimSun),基线相对正文下移 1.56bp;
% M(210.00) → L(215.16) 步距 5.16bp(M 的半角宽),
% L → 和 3.96bp,故 M 起点到"和"共 9.12bp。
% 用宽度 3.87bp 的盒接管下标宽度,使 5.25 + 3.87 = 9.12 对齐原卷。
\newcommand{\ssub}[1]{%
\raisebox{-1.56bp}{\makebox[3.87bp][l]{\fontsize{5.30bp}{5.30bp}\selectfont #1}}}
%======================================================================
% 10. 题型构件(通用)
% 设计原则:不依赖任何具体课程,只提供"骨架",
% 题目内容由正文填写。所有题型都沿用本卷实际的版面参数:
% · 正文 10.5bp / 行距 15.6bp
% · 中英之间 2.70bp(ecglue)
% · 题号栏 15.72bp(宋体题号,题号后空 5.28bp)
%======================================================================
%----------------------------------------------------------------------
% 10.1 分值标注(题号右侧、行尾右对齐)
% \qscore{5} → 在当前位置右对齐显示 "(5分)"
% 单独成行右对齐:\scorerow{5}
%----------------------------------------------------------------------
\newcommand{\qscore}[1]{{\Fivhao\hfill(#1分)}}
\newcommand{\scorerow}[1]{\par\noindent\hfill{\Fivhao(#1分)}\par}
%----------------------------------------------------------------------
% 10.2 填空横线
% \blank → 5 个下划线的短空(约 3 个汉字宽)
% \blank[8] → 指定字宽的横线(8 个字宽)
% \lblank → 通栏长横线(整行)
% 用 \rule 画,落在基线下方,与 Word 的下划线观感一致
%----------------------------------------------------------------------
\newlength\ouc@blw
\newcommand{\blank}[1][5]{%
\settowidth{\ouc@blw}{\Fivhao 国}%
\setlength{\ouc@blw}{\dimexpr\ouc@blw*#1\relax}%
\hspace*{0.6bp}\rule[0.35bp]{\ouc@blw}{0.5bp}\hspace*{0.6bp}}
\newcommand{\lblank}{\par\noindent\rule[0.35bp]{\linewidth}{0.5bp}\par}
%----------------------------------------------------------------------
% 10.3 括号填空(\tk 在括号内留出可写空间)
% \tk → 3 个字宽的括号空:\tk 写成 (\hspace.. )
%----------------------------------------------------------------------
\newcommand{\tk}{\makebox[2.4em]{\dotfill}}
%----------------------------------------------------------------------
% 10.4 选项:两种版式
% \choices{...}{...}{...}{...} 一行四栏(3 个汉字以内的短选项)
% \choicesII{...}{...}{...}{...} 两行两栏(长选项,每栏半行宽)
% \optgrid{...}{...} 任意栏数,自动按半行宽排
%----------------------------------------------------------------------
% 长选项:每栏半行宽(含标签栏)
\newlength\ouc@halfw
\newcommand{\optII}[2]{%
\setlength{\ouc@halfw}{\dimexpr\linewidth/2\relax}%
\makebox[\ouc@halfw][l]{\qnum{#1}#2}}
\newcommand{\choicesII}[4]{%
\par\noindent\optII{A}{#1}\optII{B}{#2}\par
\noindent\optII{C}{#3}\optII{D}{#4}\par}
% 任意栏数(每行 #1 栏)
% \optgrid{3}{甲,乙,丙,丁} → 每行 3 栏,逗号分隔
% ⚠️ 两个坑:
% (1) 不能用 LaTeX2e 的 \@for 遍历:它对每个元素做 \edef 展开,
% 中文(xeCJK 活动字符)会被提前展开,选项内容直接丢失。
% (2) expl3 里 @ 不是字母,控制序列名不能再含 @(\ouc@foo 会被读成
% \ouc + "@foo"),故 expl3 侧一律用 \__ouc_ 前缀。
\ExplSyntaxOn
\seq_new:N \l__ouc_opt_seq
\int_new:N \l__ouc_opt_i
\cs_new_protected:Npn \__ouc_optgrid:nn #1#2
{
\seq_set_split:Nnn \l__ouc_opt_seq {,} {#2}
\int_zero:N \l__ouc_opt_i
\seq_map_inline:Nn \l__ouc_opt_seq
{
\makebox[\dim_eval:n {\linewidth/#1}][l]{##1}
\int_incr:N \l__ouc_opt_i
\int_compare:nT { \l__ouc_opt_i = #1 }
{ \par \noindent \int_zero:N \l__ouc_opt_i }
}
\par
}
\NewDocumentCommand \optgrid { m m } { \par \noindent \__ouc_optgrid:nn {#1} {#2} }
\ExplSyntaxOff
%----------------------------------------------------------------------
% 10.5 判断题:括号在题首(原卷常见写法)
% \judge{序号}{题干} → "( )1. 题干",括号默认 3 字宽
% \judge[5]{序号}{题干} → 括号 5 字宽(长答案用)
% 括号用 \makebox + \hfill 撑开,"("居左、")"居右,中间留答题位。
% 括号在行尾的写法直接用 \qi{1}{题干(\hspace{1.67em})} 即可。
%----------------------------------------------------------------------
\newlength\ouc@jdw
\newlength\ouc@juw
\newcommand{\judge}[3][3]{%
\par\noindent
\settowidth{\ouc@juw}{\Fivhao 国}%
\setlength{\ouc@jdw}{\dimexpr\ouc@juw*#1\relax}%
\makebox[\ouc@jdw][l]{(\hfill )}%
\hspace*{2bp}\SUN{#2.}\hspace*{5.28bp}#3\par}
%----------------------------------------------------------------------
% 10.6 答题横线
% \answerlines[行数] → 在当前位置下方排 n 条等距横线(每条占 1 行距 15.6bp)
% 注意:不能用 \vbox 整体打包 —— 那样它会成为一个不可分割的原子块,
% 页面剩余空间不够时整块被推到下一页,页脚会留出大片空白。
% 改为逐条 "\par\nointerlineskip\vspace*{..}\hrule" 输出,允许跨页断开。
%----------------------------------------------------------------------
\newcommand{\answerlines}[1][3]{%
\par
\@tempcnta=0
\loop\ifnum\@tempcnta<#1
\nointerlineskip\vspace*{15.0bp}%
\noindent\hrule height 0.4bp width \linewidth
\par
\advance\@tempcnta by 1
\repeat
\nointerlineskip\vspace*{3bp}}
%----------------------------------------------------------------------
% 10.7 大题标题的"带分值"简写
% \bigsection{一}{填空题}{3 小题,每题 4 分,共 12 分}
% 中间的"共"字由宏自己补,第三个参数不要再写"共"
%----------------------------------------------------------------------
\newcommand{\bigsection}[3]{%
\examheading{#1、#2\TNRB{(}共\oucsp{6}#3\TNRB{)}}}
%----------------------------------------------------------------------
% 10.8 答题方框
% \answerbox{高度bp} → 通栏、指定高度的矩形框(作图 / 计算作答用)
%----------------------------------------------------------------------
\newcommand{\answerbox}[1]{%
\par\nointerlineskip\vspace*{4bp}\noindent
\framebox[\linewidth]{\rule{0pt}{#1}}%
\par\nointerlineskip\vspace*{6bp}}
%----------------------------------------------------------------------
% 10.10 配伍题(连线匹配)
% \mtpair{左侧内容}{右侧内容} → 左 44% | 中 12% 空白(供连线)| 右 44%
% 逐行写即可,行列自动对齐:
% \mtpair{\qnum{1} 甲}{A. 子}
% \mtpair{\qnum{2} 乙}{B. 丑}
% 中间空白留给学生画连线,不需要画虚线。
%----------------------------------------------------------------------
\newcommand{\mtpair}[2]{%
\par\noindent
\makebox[0.44\linewidth][l]{#1}%
\makebox[0.12\linewidth][c]{}%
\makebox[0.44\linewidth][l]{#2}\par}
% 配伍题整体上下留白
\newcommand{\matchinggap}{\par\vspace*{3bp}}
%----------------------------------------------------------------------
% 10.11 表格(成绩表 / 数据表):等宽 tabular,自动加横线
% \datatable{列格式}{表体}
% 表内数字请用 \TNR{},不要用 $...$(数学模式基线偏低,会与中文错行)
%----------------------------------------------------------------------
\newcommand{\datatable}[2]{%
\par\vspace*{5bp}%
\centerline{\begin{tabular}{@{}#1@{}}#2\end{tabular}}%
\par\vspace*{5bp}}
%======================================================================
% 11. 自动装订线钩子
% ★ 印张规则:试卷用大纸双面印,偶数页拼在奇数页背面(同一张纸)。
% "装订线 + 学号/姓名/专业年级/授课教师/考场教室号/座号"只印正面,
% 即**只画奇数页**;偶数页是背面,再画一遍折进去也看不见。
% ⇒ 钩到这里,按 \value{page} 自动判断,.tex 里不必逐页调用。
% ⚠️ 必须放在最后:\ouc@dobindstrip 依赖前面定义的 \ouc@bindshift 等。
%======================================================================
\AddToShipoutPictureFG{%
\ifouc@bindon
\ifouc@bindodd
\ouc@dobindstrip % 每页都画(nup 拼版等特殊需要)
\else
\ifodd\value{page}\ouc@dobindstrip\fi % 默认:只画奇数页
\fi
\fi}
\endinput