Files
ouc_latex_template/劳务发放说明表/README.md
T
laoyang 8984b93ee7 模板内容填充:全库 × 占位换成完整虚构示例,README 表述同步 #11
把 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 正文 × 清零;真实信息零泄漏。
2026-10-27 12:50:02 +08:00

183 lines
8.0 KiB
Markdown
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.
# 劳务发放说明表 — 中国海洋大学 劳务发放说明表(LaTeX 版)
把实验室用的《劳务发放说明表》Word 版复刻为 LaTeX 模板。版式与原 `.docx`
逐项对齐,**不含任何真人信息**:姓名、人数、项目名称、单位名称全部是编的。
## 文件
| 文件 | 说明 |
| :-- | :-- |
| `劳务发放说明表.tex` | 主文件。填表只改第 1 节(4 个变量) |
| `ouclw.sty` | 版式包。页面/字体/列宽/行高/全部尺寸写在这里,附换算注释 |
## 编译
```bash
xelatex 劳务发放说明表.tex
```
单页,跑一遍即可(无交叉引用)。
需要 **XeLaTeX**,并安装 `ctex`、`geometry`、`fontspec`、`xeCJK`、`tabularray`。
实测环境:TeX Live 2022 + `tabularray 2022A`。
## 改内容
```latex
\newcommand{\lwunit}{{\songti 信息科学与工程学部}} % 用工单位(学部 / 学院)
\newcommand{\lwreason}{{\songti 科研项目数据整理}} % 用工事由
\newcommand{\lwnote}{} % 备注(可留空)
\newcommand{\lwwork}{%
聘请{\songti 李承宇}等{\songti 2}位研究生参与《{\songti 近岸海域生态健康
多源数据融合与智能评估技术}》项目的研究工作。}
```
上列值是**样张实际用的虚构内容**(人名校验过:`李承宇` 不对应任何真实人员)。
### 关于 `\lwwork` 的句式
原文是一句「聘请某研究生等 N 位参与某项目研究工作」的表述 ——
真人姓名、人数、真实项目名均未保留,**句式一字未动**。
填表时把这三处换成实际内容即可:
| 样张值 | 含义 | 换成 |
| :-- | :-- | :-- |
| `李承宇` | 第一位研究生的姓名 | 真实姓名("等"字后面若只有一人,可删"等 N 位") |
| `2`(位) | 研究生人数 | 实际人数 |
| 《`近岸海域…技术`》 | 项目全称 | 真实项目名 |
> 不是满篇 `×` 的原因:这张表**正文只有一句话**,全打叉的话整页看着像没填完,
> 也判断不出这句话在该行里排几行。填一句完整的话才知道行高要不要调。
## 版式数据来源
全部尺寸从原 `.docx` 的 OOXML 里量出来,换算关系:
- 长度:`mm = twips ÷ 1440 × 25.4`,`pt = twips ÷ 20`
- 字号:`w:sz` 是半磅值,`sz=28` ⇒ 14 pt
- 行距:`docGrid linePitch=312` twips ⇒ 15.6 pt
| 项目 | docx 原值 | 换算 |
| :-- | :-- | :-- |
| 纸张 | `pgSz 11906×16838` | A4 210×297 mm |
| 页边距(上下) | `pgMar top/bottom 1361` | 24.01 mm |
| 页边距(左右) | `pgMar left/right 1797` | 31.70 mm |
| 表宽 | `tblW 8522` | 150.32 mm |
| 列宽 c1..c4 | `1384, 1418, 2883, 2837` | 24.41 / 25.01 / 50.85 / 50.04 mm |
| 单元格内边距(左右) | `tblCellMar 108` | 1.905 mm |
| 边框 | `tblBorders sz=4` | 0.5 pt |
| 字号 | `w:sz 28` | 14 pt,宋体 |
| 行距 | `linePitch 312` | 15.6 pt |
各行行高由**段落数**决定(原表没有 `trHeight`),每段一个行距 15.6 pt:
| 行 | 段数 | 高度 |
| :-- | :-- | :-- |
| R0 用工单位 | 2(`用工单位` / `(公章)`) | 31.2 pt = 11.01 mm |
| R1 用工事由 | 1 | 15.6 pt = 5.50 mm |
| R2 具体工作 | 9(长句 + 8 空段) | 140.4 pt = 49.53 mm |
| R3 三方签字 | 4(标签 + 2 空段 + 日期) | 62.4 pt = 22.01 mm |
| R4 备注 | 2 | 31.2 pt = 11.01 mm |
| 合计 | | 280.8 pt = 99.06 mm |
### 为什么左右页边距不对称
原表宽 150.32 mm,比 docx 版心(146.68 mm)宽 3.71 mm,而 `tblPr` 里**没有
`jc`、`tblInd` 又是 0** —— Word 按左对齐处理:表从左边距 31.70 mm 起排,
右端溢进右侧页边距 3.71 mm。
所以本模板照实复现这个不对称:`left = 31.70mm`、`totalwidth = 150.32mm`,
右边界自然落到 `210 − 31.70 − 150.32 = 27.98 mm`。**不要**改成左右等边距
(那样表会整体左移 1.86 mm,与 Word 里看到的位置不符)。
## 四个必须知道的坑
### 1. ctex 的 `\linespread ≈ 1.3` 会吃掉你设的行距
```latex
\fontsize{14}{15.6}\selectfont % \baselineskip = 20.28pt ✗
\linespread{1}\relax\fontsize{14}{15.6}\selectfont % = 15.60pt ✓
```
`\fontsize` 第二个参数本该直接设定 `\baselineskip`,但 `\selectfont` 时会
**再乘一次 `\linespread`**。ctex 默认 `\linespread ≈ 1.3`,于是 15.6 pt 被放大
成 20.28 pt,五行表从 99 mm 涨到 129 mm,`ht=` 也压不住(内容本身就那么高,
tabularray 只能被动撑开)。
本包的对策是 `\lwbodyfont`:
```latex
\newcommand{\lwbodyfont}{\linespread{1}\relax\fontsize{14}{15.6}\selectfont}
\AtBeginDocument{\lwbodyfont}
```
`\AtBeginDocument` 那一次不能省——ctex 在 begin document 时会重设 `\linespread`。
### 2. 合并格 `{c}` 是不折行的 LR 模式
`cell{r}{c}={c=n}{c}` 的 `{c}` 是 **LR 模式**,不是段落模式:
- 格内文字比所跨各列合计更宽时,它**不折行**,而是把列撑宽、整表超出版心;
- 合并格里的 `\hsize` **没有**被重设成该跨度宽度,仍是外层版心宽,
长文本会按版心折行、冲出格子。
⇒ 合并格里的文字一律包定宽 `\parbox`,本表提供 `\lwcell` / `\lwcellv` /
`\lwstack` / `\lwsign` 四个入口,`.tex` 里只要有内容就用它们,别裸写。
### 3. 合并格的“内容可用宽”要补回 `2·colsep·(n−1)`
单列的内容宽 = `wd`(左右两半 `colsep` 已被 colspec 扣掉);
但跨 n 列合并后,**n 列之间的 (n−1) 组内边距会被回收进内容宽**:
```
内容可用宽 = Σ 所跨各列 wd + 2 · colsep · (n − 1)
```
漏算的后果很隐蔽:`\parbox` 比真实格宽窄,短文本看不出问题,长文本会
**提前折行**。本表「批准单位负责人签字」共 9 字 × 14 pt = 44.45 mm,
而 c1+c2 只有 41.37 mm,就曾被折成「批准单位负责人签」+「字」两行,
docx 里明明是一行。正确值是 `41.3653 + 2×1.905 = 45.1753mm`。
### 4. `\parbox[t]` 会让行高超目标
tabularray 给每个单元格垫了 strut,`[t]` 生成的盒子顶部与 strut 顶部相加,
实测每行白白多出 **3.6 pt**(R0 从 31.67 → 35.26)。
原表 R0C1 / R2C1 之所以“贴顶”,不是靠 `vAlign=top`(它们其实没写 `vAlign`),
而是靠**段落数把行高填满**(2 段 = 31.2 pt、9 段 = 140.4 pt,正好等于行高)。
内容高度已等于行高时,`[c]` 居中的结果就等同于贴顶。
⇒ `.tex` 里用 `\lwcellv{内容\lwblank{n}}` 补足段落数,`\parbox` 保持 `[c]`。
## 与 docx 的已知差异
| 项 | docx | 本模板 | 说明 |
| :-- | :-- | :-- | :-- |
| 表宽 | 150.319 mm | 150.137 mm | 差 0.18 mm。tabularray 计宽按 n−1 根竖线、画宽按 n 根,系统性差 0.5 pt,为消除 Overfull 微调了列宽 |
| 行高 | 11.01 / 5.50 / 49.53 / 22.01 / 11.01 mm | 每行 +0.15 mm | 同上,竖线计入行高 |
| 字体 | 宋体 | OUC Serif(思源宋体子集) | 原用系统 SimSun。现改为仓库公共字体包 `../fonts/`,换机器/换系统都能编,且允许分发 |
| 标题 | 宋体 14 pt **加粗** | 同 | 字号与正文相同,只靠加粗区分 |
## 校验方法
不用肉眼看 PDF,直接量矢量:
```bash
pdftocairo -svg 劳务发放说明表.pdf out.svg # 取线条精确坐标
pdftotext -bbox 劳务发放说明表.pdf out.xml # 取每个字块的坐标
```
SVG 里解析 `<path d="M x y L x y" transform="matrix(...)"/>`,按
「`|Δy|<0.9` 且 `|Δx|>10` = 横线」「`|Δx|<0.9` 且 `|Δy|>2` = 竖线」分类去重,
即可得到每条线的精确端点。本模板的实测结果:
```
表宽 150.137 mm (目标 150.319,差 −0.18)
表左 31.662 mm (目标 31.700,差 −0.04)
表右 181.799 mm (目标 182.019,差 −0.22)
R0 11.172 / R1 5.668 / R2 49.646 / R3 22.159 / R4 11.172 mm 全部达标
```
三个签字格的标签基线完全重合(`rel-top 1.06 pt`),日期行也完全重合
(`rel-top 47.69 pt`)——这一条是特意做的:合并格与普通列的垂直居中算法
不同,若不统一包 `\parbox`,第一格会比另两格低 1.55 pt。