Files
ouc_latex_template/会议预算表/oucmeeting.sty
T
laoyang 333e2a7789 会议预算表:修掉多出的一列,签字盖章间距拉开 #24
用户反馈两点:
  ① 所在单位负责人意见下面,签字和盖章距离太近
  ② 表格右侧整体多出一列

## ② 多出一列的根因

实测竖线 **9 条 = 8 列**,而 colspec 只定义了 7 列。
多出来那列宽 2.18mm,横贯全部 28 行。

定位过程:
  删掉 R27/R28(意见+签字两行)→ 变 8 条竖线(7 列,正确)
  加回去 → 又变 9 条
  ⇒ 问题就在这两行。

四种组合全试过,全部失败:

| 内容段数 | cell 声明 | 结果 |
|---|---|---|
| 8 段(7 个 &) | cell{27}{4}={c=4} | 9 条竖线,多一列 ❌ |
| 7 段(6 个 &) | cell{27}{4}={c=4} | 9 条竖线,多一列 ❌ |
| 2 段(1 个 &) | cell{27}{4}={c=4} | 列数对,但第 2 段被合并盖住,内容消失 ❌ |
| 2 段 | cell{27}{2}={c=6} | 网格散架(3 页、横线全无)❌ |
| 7 段 | 无 cell 声明 | 同样散架 ❌ |

根因:tabularray 2022A 对「跨整行的大合并」处理不稳定,要求
「内容段数 / cell 起始列 / 跨度」三者严格自洽;在固定列宽 + colsep
1.0mm 的组合下,这三者无法同时满足。

### 解法:物理隔离

主表只到 R26「合计」(26 行),R27/R28 用独立的 oucmeetsign 环境
紧贴在下方。视觉上是同一张表,排版上互不干扰。

签字表列宽**不能自己估**,必须按主表实际竖线位置反推:
   主表竖线 79.65~514.31 = 153.34mm
   3:4 分界 231.89 -> 距左 53.71mm
   第1列 wd = 53.71 - 2 = 51.71mm
   第2列 wd = 153.34 - 53.71 - 2 = 97.63mm
(减 2 = 两侧 colsep 各 1mm)

⚠️ 第一版估的 47.18/93.80 总宽只有 144.98mm,比主表窄 10.5mm,
边框对不上,两格在 pymupdf 里连成一串,看着像只有一格。

## ① 签字盖章间距

3em(27bp=9.5mm) → 5em(45bp=15.8mm)。
实测「(签字)」右端 274.2,「(盖章)」左端 319.0,间距 44.8bp = 15.8mm。

⚠️ 第 1 格的「(签字)」不能用 \hfill 推到右边:第 1 格宽 51.71mm=146bp,
「(签字)」36bp,\hfill 推到格尾后文字**溢出单元格右边界**
(tabularray 不裁剪格内容),实测跑到 199~265 跨过分界线 232,
和第二个「(签字)」连成一串。
⇒ 直接顶格左排,前面补 1mm 抵消全角括号的字形左空白
(「(」的 ink 起点比盒起点靠左 2.5bp,不加会超出左界 79.40)。

## 验证

   主表竖线 8 条 -> **7 列**(多出的列已消除)
   内容核查 49 项,**缺失 0**
   校级领导意见 0 次
   其他费用竖排 y 531.3~586.4,上下留白各 13.4bp
   1 页  err 0  Overfull 0  Underfull 0
   最左 79.40(界79.40)  最右 521.58(界521.57)  最下 711.80(界742.65)

全库 15/15 通过。双端一致:
   WSL TeX Live 2025      1 页 err=0 over=0 under=0
   Windows TeX Live 2022  1 页 err=0 over=0 under=0
2026-10-30 23:37:12 +08:00

302 lines
15 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.
%======================================================================
% oucmeeting.sty —— 中国海洋大学 会议预算表 版式包
%
% 由学校下发的 .doc 复刻而来(源文件:会议预算表.doc,OLE2 老格式,
% 先经 LibreOffice 转 docx 再解析 OOXML)。尺寸全部从原文件量出。
%
% ⚠️ 编译: xelatex 会议预算表.tex
% 单次编译即可,无交叉引用。
% 依赖 ctex + geometry + fontspec + xeCJK + tabularray
% 与 课程大纲/、课程执行大纲/ 同源同风格。
%======================================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{oucmeeting}[2026/10/30 v1.0 OUC meeting budget form]
\RequirePackage{geometry}
\RequirePackage{fontspec}
\RequirePackage{xeCJK}
\RequirePackage{tabularray}
% 注:不再需要 graphicx。早期版本用 \rotatebox 做「其他费用」竖排,
% 现已改为 \shortstack 逐字竖排(#24 按用户意见修正),不再依赖 graphicx。
%======================================================================
% 1. 页面
%
% 原 docx sectPr 实测(11906 x 16838 twips):
% 宽 210.01 mm 高 297.00 mm ← 标准 A4
% top 2155 twips = 38.01 mm
% bottom 1985 twips = 35.01 mm
% left 1588 twips = 28.01 mm
% right 1474 twips = 26.00 mm
% header 0 twips = 0.00 mm (无页眉)
% footer 992 twips = 17.50 mm
%
% 四个边距都不常见(38/35/28/26),是原表为把 28 行表格塞进一页
% 压出来的。照抄,不"优化"——这是复刻件,不是重新设计。
%
% ⚠️ 版心宽 = 210 - 28.01 - 26.00 = 155.99 mm
% 而原表宽 169.12 mm,**超宽 13.12 mm**。
% 原 docx 用 tblLayout=fixed 硬撑,实际会压进右侧页边距。
% ⇒ 本包把表格等比缩到 155.99 mm(系数 0.9224),
% 列宽按比例重算,见第 3 节。这是唯一一处主动偏离原文件的地方。
%======================================================================
\geometry{
paperwidth = 210mm,
paperheight = 297mm,
left = 28.01mm,
right = 26.00mm,
top = 38.01mm,
bottom = 35.01mm,
headheight = 0pt,
headsep = 0pt,
footskip = 17.50mm,
}
\setlength{\parindent}{0pt}
\setlength{\parskip}{0pt}
\pagestyle{empty} % 原 docx 无页眉页脚页码
%======================================================================
% 2. 字体
%
% 原 docx 用宋体 / 黑体。仓库规矩(#17):不用商业字体,
% 全部取自公共字体包 ../fonts.tex。
%
% ⚠️ 原表字号分布实测:
% 22pt ×1 —— 标题「中国海洋大学会议预算表」
% 9pt ×47 —— 表格内全部文字 + 三条说明
% 无 12pt 段落,与课程大纲那套不同,别照抄那边的字号命令。
%======================================================================
\input{../fonts.tex}
\newcommand{\oucMeetFont}[2]{\fontsize{#1pt}{#2pt}\selectfont}
\newcommand{\Mtw}{\oucMeetFont{22}{30}} % 标题 22pt
\newcommand{\Mn}{\oucMeetFont{9}{12}} % 表格与说明 9pt
\AtBeginDocument{\Mn}
%======================================================================
% 3. 表格列宽
%
% 原 docx 网格(tblGrid,单位 twips):
% [424, 2054, 790, 1262, 2056, 209, 2793] 合计 9588
% 换算 mm(×25.4/1440):
% [7.48, 36.23, 13.93, 22.26, 36.27, 3.69, 49.27] 合计 169.12
%
% 等比缩到版心 155.99 mm(系数 0.9224):
% [6.9, 33.4, 12.9, 20.5, 33.4, 3.4, 45.4] 合计 155.9
%
% ⚠️ 第 6 列只有 3.4mm,是原文件里「其他费用」竖排标题那一列的残留
% (原 209 twips,几乎只是一条分隔线宽)。保留它是因为第 20~24 行
% 的「其他费用」合并单元格需要它占位,删掉会破坏网格。
%======================================================================
% ⚠️ 列定义**不能**放进宏再用 \OucMeetColspec 引用 —— tabularray 的
% colspec 解析器要求字面量,报
% Package tabularray Error: Unexpandable command ... inside Column type
% ⇒ 直接写在下方的 colspec={...} 里(实测唯一可行写法)。
%----------------------------------------------------------------------
% 行高(#24 修正)
%
% ⚠️⚠️ 原 docx 的 28 行里**只有 R26 显式设了 trHeight**(567 exact = 10mm),
% 其余 27 行都没设 —— 行高由内容自然撑开,9pt 字约 4.5~5mm。
%
% 第一版我给所有行硬设 ht=7.4mm(自己拍的数),结果:
% 28 × 7.4 = 207.2mm,加标题区约 30mm + 说明约 25mm = 262mm
% 而版心只有 224mm ⇒ **必然溢出一页**,说明文字被推到第 3 页。
%
% ⇒ 改为 row{2-Z} 不设 ht,让内容撑开(与原 docx 一致);
% 表头行(R6/R14 分节标题)和签署行(R26/R27)单独给最小高度,
% 保证印章框有空间。
%
% ⚠️ 但 9pt + 0 上下内边距时行高只有 4.2mm,全表 28×4.2=118mm,
% 偏挤且不像正式表格。折中取 ht=6.0mm(≈ 一点留白),
% 28×6.0=168mm,加标题 30 + 说明 25 = 223mm,正好卡在 224mm 内。
% ⚠️ 若将来内容变多导致溢出,优先降这个值,不要动页边距。
% (注:这个 6.0mm 是写在下方 row{1-Z}={ht=6.0mm} 里的字面量,
% 不做成宏 —— 原因见第 4 节开头的说明。)
%======================================================================
% 4. 主表环境
%
% ⚠️⚠️ 合并单元格用**矩阵式语法**,绝对不能写在内容里用 \SetCell
%
% 现状(tabularray 2022A + 本表的 7 列 Q[c,m,wd=…] + colsep=1mm):
% 只要在单元格内容里写 \SetCell[c=n],编译立刻报
% ! Missing number, treated as zero.
% ! Illegal unit of measure (pt inserted.)
% \__dim_eval_end:
% 且**全部错误都定位到 \end{tblr}**,根本看不出是哪个格。
% 最小复现(已验证):
% \begin{tblr}{colspec={Q[c,m,wd=21mm] ...7列..., colsep=0.8mm}}
% \SetCell[c=2]{c} A & \SetCell[c=5]{l} B \\
% \end{tblr}
% 必崩;把同样的合并改写成下面的 cell{} 语法就 0 错。
%
% ✅ 正确写法:在 tblr 的选项里用
% cell{行}{列}={c=n}{对齐}
% 被合并掉的格在内容里**留空**(写 `& &`),不要写 {}。
%
% ⚠️ 另有一个坑(#23):纵向合并 \SetCell[r=n] 与横向 \SetCell[c=m]
% 不能出现在同一行,同样报上面那串错。本表因此完全不用纵向合并,
% 「其他费用」改成竖排文字 + 该列留空(视觉上等价)。
%======================================================================
\newenvironment{oucmeettable}{%
\par\begingroup\Mn
\begin{tblr}[label=none]{
colspec={Q[c,m,wd=6.10mm] Q[c,m,wd=29.65mm] Q[c,m,wd=11.43mm] Q[c,m,wd=18.18mm] Q[c,m,wd=29.65mm] Q[c,m,wd=3.00mm] Q[c,m,wd=40.10mm]},
colsep=1.0mm, rowsep=0pt, stretch=0,
hline{1-Z}={0.5pt}, vline{1-Z}={0.5pt},
row{1-Z}={ht=5.6mm, font=\Mn, valign=m},
% ---- 合并规则(行号从 1 开始)----
% R1~R6 基本信息
cell{1}{1}={c=2}{c}, cell{1}{3}={c=5}{l},
cell{2}{1}={c=2}{c}, cell{2}{3}={c=2}{l}, cell{2}{5}={c=2}{c}, cell{2}{7}={c=1}{l},
cell{3}{1}={c=2}{c}, cell{3}{3}={c=5}{l},
cell{4}{1}={c=2}{c}, cell{4}{3}={c=5}{l},
cell{5}{1}={c=2}{c}, cell{5}{3}={c=5}{l},
cell{6}{1}={c=2}{c}, cell{6}{3}={c=5}{l},
% R7 收入预算标题(跨 7 列)
cell{7}{1}={c=7}{c},
% R8~R14 收入表
cell{8}{1}={c=2}{c}, cell{8}{3}={c=2}{c}, cell{8}{5}={c=2}{c}, cell{8}{7}={c=1}{c},
cell{9}{1}={c=2}{l}, cell{9}{3}={c=2}{l}, cell{9}{5}={c=2}{l}, cell{9}{7}={c=1}{l},
cell{10}{1}={c=2}{l}, cell{10}{3}={c=2}{l}, cell{10}{5}={c=2}{l}, cell{10}{7}={c=1}{l},
cell{11}{1}={c=2}{l}, cell{11}{3}={c=2}{l}, cell{11}{5}={c=2}{l}, cell{11}{7}={c=1}{l},
cell{12}{1}={c=2}{l}, cell{12}{3}={c=2}{l}, cell{12}{5}={c=2}{l}, cell{12}{7}={c=1}{l},
cell{13}{1}={c=2}{l}, cell{13}{3}={c=2}{l}, cell{13}{5}={c=2}{l}, cell{13}{7}={c=1}{l},
cell{14}{1}={c=2}{c}, cell{14}{3}={c=2}{l}, cell{14}{5}={c=2}{l}, cell{14}{7}={c=1}{l},
% R15 支出预算标题(跨 7 列)
cell{15}{1}={c=7}{c},
% R16~R20 支出表(3+2+2)
cell{16}{1}={c=3}{c}, cell{16}{4}={c=2}{c}, cell{16}{6}={c=2}{c},
cell{17}{1}={c=3}{l}, cell{17}{4}={c=2}{l}, cell{17}{6}={c=2}{l},
cell{18}{1}={c=3}{l}, cell{18}{4}={c=2}{l}, cell{18}{6}={c=2}{l},
cell{19}{1}={c=3}{l}, cell{19}{4}={c=2}{l}, cell{19}{6}={c=2}{l},
cell{20}{1}={c=3}{l}, cell{20}{4}={c=2}{l}, cell{20}{6}={c=2}{l},
% R21~R25 其他费用区(1+2+2+2)
% ★ 「其他费用」纵向合并 5 行,文字逐字竖排(不是旋转 90°)
% 写法:cell{21}{1}={r=5}{c} 声明纵向合并,
% 内容用 \shortstack{其\\他\\费\\用} 逐字堆叠。
% ⚠️ 不能用 \rotatebox{90} —— 那只是把整行文字旋转,
% 仍然是"横向一句转个角度",不是你要的上下排列(#24 修正)。
% ⚠️ 纵向合并也必须用 cell{} 矩阵语法。写成 \SetCell[r=5] 在
% 内容里,会与同行的 \SetCell[c=n] 冲突报 Missing number。
cell{21}{1}={r=5}{c},
cell{21}{2}={c=2}{l}, cell{21}{4}={c=2}{l}, cell{21}{6}={c=2}{l},
cell{22}{2}={c=2}{l}, cell{22}{4}={c=2}{l}, cell{22}{6}={c=2}{l},
cell{23}{2}={c=2}{l}, cell{23}{4}={c=2}{l}, cell{23}{6}={c=2}{l},
cell{24}{2}={c=2}{l}, cell{24}{4}={c=2}{l}, cell{24}{6}={c=2}{l},
cell{25}{2}={c=2}{l}, cell{25}{4}={c=2}{l}, cell{25}{6}={c=2}{l},
% R26 合计(3+2+2)
cell{26}{1}={c=3}{c}, cell{26}{4}={c=2}{l}, cell{26}{6}={c=2}{l},
% ⚠️ 主表只到 R26「合计」。
% R27/R28(意见+签字)已移到 5 节的独立签字表(oucmeetsign 环境),
% 原因见 5 节开头的说明 —— 那两行无论怎么调都会多出一列或丢内容。
% ⇒ 主表现在是 **26 行**,不是 28 行。
}%
}{%
\end{tblr}\par\endgroup}
%======================================================================
% 5. 签字栏(独立小表,不并入主表)
%
% ⚠️⚠️ 为什么把签字栏从主表里拆出来
%
% 主表 R27/R28(意见+签字)无论怎么调都无法同时满足"不多列"和
% "内容不丢失"。实测四种组合全失败:
% 内容 8 段 + cell{27}{4}={c=4} → 右侧多一列(9 条竖线)
% 内容 7 段 + cell{27}{4}={c=4} → 右侧多一列(9 条竖线)
% 内容 2 段 + cell{27}{4}={c=4} → 列数对,但第 2 段内容被合并盖住消失
% 内容 2 段 + cell{27}{2}={c=6} → 表格网格散架(溢出 3 页、无横线)
% 内容 7 段 + 无 cell 声明 → 同样散架
%
% 根因是这两行的"内容段数 / cell 起始列 / 跨度"三者必须严格自洽,
% 而 tabularray 2022A 在这种跨整行的大合并上行为不稳定。
%
% ⇒ 改为**物理隔离**:主表只到「合计」(27 行),签字栏用独立 tblr
% 紧贴在下方,视觉上是同一张表(边框对接、列宽对齐),
% 但排版上互不干扰。这是最稳的做法。
%
% 对齐要点:签字表的列宽必须让「3 列 : 4 列」的分界点与主表一致,
% 所以用主表前 3 列宽度之和 与 后 4 列宽度之和 作为两列宽度。
% 主表列宽 6.10 / 29.65 / 11.43 / 18.18 / 29.65 / 3.00 / 40.10
% 前 3 列 = 6.10+29.65+11.43 = 47.18mm,加两侧 colsep 3×2 = 53.18mm
% 后 4 列 = 18.18+29.65+3.00+40.10 = 91.02mm,加 colsep 4×2 = 99.02mm
% ⚠️ 签字表只有 2 列,colsep 共 4 个,需重新配平(见下方计算)。
%======================================================================
\newenvironment{oucmeetsign}{%
\par\begingroup\Mn
\begin{tblr}[label=none]{
colspec={Q[l,m,wd=51.71mm] Q[l,m,wd=97.63mm]},
colsep=1.0mm, rowsep=0pt, stretch=0,
hline{1-Z}={0.5pt}, vline{1-Z}={0.5pt},
row{1-Z}={ht=5.6mm, font=\Mn, valign=m, halign=l},
}%
}{%
\end{tblr}\par\endgroup}
%======================================================================
% 6. 标题与页首
%======================================================================
% 左上角「附件1」小字(原 docx 无字号设置,随正文 9pt)
\newcommand{\oucmeetattach}[1]{%
\par\noindent{\Mn #1}\par\vspace*{4bp}}
% 标题:22pt 居中
\newcommand{\oucmeettitle}[1]{%
\par\begingroup\Mtw\heiti\centering #1\par\endgroup
\vspace*{8bp}}
% 填表日期 / 金额单位 那一行(左右分列,中间留白)
% 原 docx 用一串空格撑开,这里用 \hfill 更稳
\newcommand{\oucmeetdateline}[1]{%
\par\noindent{\Mn #1}\par\vspace*{4bp}}
%======================================================================
% 6. 表尾说明
%
% ⚠️ 悬挂缩进不能用 \leftmargin=2em —— 实测报
% Overfull \hbox (26.71pt too wide)
% 因为「1、」「2、」是**全角字符 + 顿号**,9pt 下实测宽约 2.4em,
% 比 2em 宽,标签凸出到左边界外。⇒ \labelwidth 要给足 2.5em。
%
% ⚠️⚠️ \itemindent 不能设负值!
% 第一版写 \itemindent=-2.5em 想让「1、」顶格,结果整段被拉到
% x=65.95,而版心左界是 79.40 —— **说明文字跑到版心外左侧 13.45bp**,
% 且只报一个 5.1pt 的 Overfull(因为 \hbox 宽度的计算没把左溢算进去)。
% ⇒ 正确做法:\leftmargin 与 \labelwidth 相等,\itemindent=0,
% 标签自然落在左边界,「1、」后面直接接正文。
% \labelwidth 要 ≥ 标签实际宽度(「1、」9pt 全角约 2.4em),给 2.5em。
% 见下方 \oucmeetnote 的说明。环境只负责字号与上间距,不再用 list。
\newenvironment{oucmeetnotes}{%
\par\vspace*{2bp}\begingroup\Mn
}{\par\endgroup}
%----------------------------------------------------------------------
% 单条说明
%
% ⚠️ 为什么不用 list 环境:list 的 \leftmargin / \itemindent 组合极易
% 把内容推出边界,而且**不报 Overfull**(踩过一次,文字跑到版心
% 左外 13.45bp,日志里只有个无关的 5.1pt)。
%
% ⚠️ 也不要用 \hangindent 悬挂缩进。「2、」后面直接接正文,续行不需要
% 缩进;相反,\hangindent 会让续行可用宽度变窄,第 2 条
% (50 字,两行)因此溢出 5.1pt。
% ⇒ 就是普通的 \noindent + 段落,什么都不设。
%
% ⚠️⚠️ \tolerance / \emergencystretch 必须在**段落开始前**设置。
% 写成 `\noindent` 之后再改无效(\noindent 已开段落,实测 5.1pt
% 的 Overfull 纹丝不动)。
% ⇒ 这里用 \sloppy,它在内部改 \tolerance 和 \emergencystretch,
% 且必须在 \par 之前调用 —— 下面 #1#2 之前就调了,有效。
%
% ⚠️ 为什么会溢出:第 2 条说明正好 50 字,9pt 下版心一行放 49 字,
% 第 50 字「现」挤到第二行后,第一行欠宽极小、第二行只有「金;」
% 两个字,TeX 判定这比"溢出 5.1pt"更难看。\sloppy 允许更松的断行,
% 两害相权取其轻。这是内容长度与版心宽度的巧合冲突,不是排版错误。
%----------------------------------------------------------------------
\newcommand{\oucmeetnote}[2]{%
\par\noindent\sloppy #1#2\par
\vspace*{1bp}}
\endinput