diff --git a/README.md b/README.md index 19a72db..207ee93 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ | [`劳务发放说明表/`](劳务发放说明表/) | **劳务发放说明表** | `劳务发放说明表.tex` | | [`课程执行大纲/`](课程执行大纲/) | 本科**课程教学执行大纲** | `课程执行大纲.tex` | | [`课程教学日历/`](课程教学日历/) | 学校通用版**课程教学日历(理论课程)**(附件3,16 周日历表) | `课程教学日历.tex` | +| [`成绩构成说明/`](成绩构成说明/) | **成绩构成说明**(理论课/实验课比例分解表 + 教师签字栏) | `成绩构成说明.tex` | | [`幻灯片/`](幻灯片/) | 演示文稿(**beamer** 主题,海大配色) | `slides.tex` | | [`科技报告/`](科技报告/) | **科技报告**、实验讲义、说明文档 | `report.tex` | @@ -26,11 +27,11 @@ xelatex slides.tex xelatex slides.tex # 跑两遍,第二遍才能取到正确的目录、交叉引用与总页数 ``` -目录名含中文不影响编译(已实测 9 个模板目录在中文目录下零报错编译通过)。 +目录名含中文不影响编译(已实测 10 个模板目录在中文目录下零报错编译通过)。 ## 说明 -- **字体单一来源**:全库字体集中在根目录 [`fonts/`](fonts/),由 [`fonts.tex`](fonts.tex) 统一加载。九个模板通过 `\input{../fonts.tex}` 取字体,**不自带字体、不依赖系统字体**——换机器(Windows / macOS / Linux / Overleaf)编译结果一致。 +- **字体单一来源**:全库字体集中在根目录 [`fonts/`](fonts/),由 [`fonts.tex`](fonts.tex) 统一加载。十个模板通过 `\input{../fonts.tex}` 取字体,**不自带字体、不依赖系统字体**——换机器(Windows / macOS / Linux / Overleaf)编译结果一致。 - **全部开源可商用**:无方正、无 SimSun / SimHei / KaiTi / FangSong、无 Times New Roman、无微软雅黑。用的是思源宋体/黑体、霞鹜文楷、朱雀仿宋、TeX Gyre Termes、鸿蒙 HarmonyOS Sans(各字体授权见 [`fonts/LICENSE`](fonts/LICENSE),来源与字符集见 [`fonts/README.md`](fonts/README.md))。 - **每个子目录自包含**:样式文件(`.sty` / `.cls`)、图片都在各目录内,编译时不需要额外的宏包搜索路径;只有字体是共享的上层目录。 - **各目录的 `README.md`** 写明该模板的用法、可改参数、版式数据来源与书写注意事项,改之前先看。 diff --git a/fonts.tex b/fonts.tex index 1a5efda..1042c88 100644 --- a/fonts.tex +++ b/fonts.tex @@ -1,7 +1,7 @@ %====================================================================== % oucfonts.tex —— 中国海洋大学模板库的公共字体入口 % -% 本文件是仓库内**唯一**允许声明字体的地方。九个模板全部通过 +% 本文件是仓库内**唯一**允许声明字体的地方。十个模板全部通过 % \input{../fonts.tex} % 取字体,不再各自写 \setCJKmainfont / \setmainfont。 % diff --git a/成绩构成说明/README.md b/成绩构成说明/README.md new file mode 100644 index 0000000..74be69c --- /dev/null +++ b/成绩构成说明/README.md @@ -0,0 +1,319 @@ +# 成绩构成说明 — 中国海洋大学《成绩构成说明》(LaTeX 版) + +把任课教师手写的「成绩构成说明」做成 LaTeX 模板。原件是一份填过的 +`.doc` 实例(两段话 + 标题,无表格、无签字栏),本模板在**保留其信息 +内容**的前提下重新组织,并补齐归档必需项。 + +> **本模板不含原件任何真实数据。** 课程名、学年、学期、教师姓名、 +> 所有比例、日期一律 `××××` / `20××` / `×` 占位,已 grep 验证零命中。 + +## 目录 + +- [文件](#文件) +- [编译](#编译) +- [改内容](#改内容) +- [相对于原件的改动](#相对于原件的改动) +- [比例自洽校验](#比例自洽校验) +- [版式参数](#版式参数) +- [五个坑](#五个坑) +- [真实数据零泄漏](#真实数据零泄漏) +- [字体](#字体) + +## 文件 + +| 文件 | 说明 | +| :-- | :-- | +| `成绩构成说明.tex` | 主文件。填表只改第 1 节(10 个宏) | +| `oucgrade.sty` | 版式包。页面/字体/表格/签字栏,附换算注释 | +| `成绩构成说明.pdf` | 成品样张(1 页) | + +## 编译 + +```bash +xelatex 成绩构成说明.tex +``` + +**单页,跑一遍即可**(无交叉引用,不需要 bibtex)。 + +⚠️ 必须在**本目录**下编译,不要从仓库根调用 —— `fonts.tex` 用的是 +相对路径 `../fonts/`。 + +需要 XeLaTeX,并安装 `ctex`、`geometry`、`fontspec`、`xeCJK`、 +`tabularray`、`enumitem`、`graphicx`。实测环境:TeX Live 2022。 + +## 改内容 + +### 课程信息(10 个宏) + +```latex +\newcommand{\grdcourse}{××××} % 课程名称 +\newcommand{\grdyear}{20××} % 学年 +\newcommand{\grdseason}{×} % 季学期(春 / 秋) +\newcommand{\grdteacher}{×××} % 任课教师 + +\newcommand{\grdtheory}{80} % 理论课占总成绩 % +\newcommand{\grdlab}{20} % 实验课占总成绩 % + +\newcommand{\grddaily}{30} % 平时成绩占理论课 % +\newcommand{\grdfinal}{70} % 期末考试成绩占理论课 % + +\newcommand{\grdhw}{20} % 作业占理论课 % +\newcommand{\grdattend}{10} % 点名占理论课 % + +\newcommand{\grdlabnote}{由实验课教师根据实验报告与实验操作评定。} +``` + +**只填数字,不要带 `%` 号**,百分号由模板加。 + +### 「占本类」与「占总成绩」是两回事 + +这是本模板最要紧的一个设计,见下节。 + +### 改写正文 + +- 总述:`\grdpara{...}` +- 分节:`\grdsec{一、成绩构成}` +- 列表:`\begin{grdlist} \grditem{项}{:说明} \end{grdlist}` +- 表格单元格:`\grdth{}`(表头)/ `\grdtd{}`(表身) + +## 相对于原件的改动 + +原件全文只有这些内容: + +``` +成绩构成说明 + 数字逻辑 2025学年 秋季学期 期末考试 + 理论课成绩占总成绩的80%。理论课成绩包括平时成绩、期末考试成绩。 + 平时成绩占30%(作业占20%,点名占10%),期末考试成绩占70%。 + 实验成绩占总成绩的20%。由实验课老师提供。 +``` + +它的问题有四个,逐个解决: + +### 1. 三层百分数混用不同基准,读者要心算三轮 + +| 句子 | 百分数 | **基准实际是** | 折总成绩 | +| :-- | --: | :-- | --: | +| 理论课占总成绩的 80% | 80% | 总成绩 | 80% | +| 平时成绩占 30% | 30% | **理论课** | 24% | +| 作业占 20% | 20% | **理论课** | 16% | +| 期末考试成绩占 70% | 70% | **理论课** | 56% | + +「平时占 30%」看着像占总成绩三成,实际上只占 **24%**。教务抽查时 +这里最常被挑错,学生也容易误读。 + +**改法**:表格左右并置「占本类」与「占总成绩」两列,后者由 +`\grdcalc{理论课\%}{分项\%}` 自动算出,不给心算留余地。 + +### 2. 层级关系埋在句子里 + +「平时成绩占30%(作业占20%,点名占10%)」—— 括号里的两个数加起来 +才是括号外的数,这种嵌套在一个句子里读起来要来回扫。 + +**改法**:改成 6 列表格,一级项目跨行合并,层级一眼可见。 + +### 3. 没有说明「怎么算」 + +原件说了比例,没说作业怎么平均、缺交怎么扣、点名缺几次记零。 +这些是学生真正会问的,也是申诉时的依据。 + +**改法**:新增「二、分项说明」一节,用列表逐项写清(文字留占位, +任课教师按自己课程的规则填)。 + +### 4. 没有签字栏 + +**这是用户明确要求补的。** 没有任课教师签字的成绩构成说明,在教务 +归档时不被认作有效文件。 + +**改法**:右下角落款,含签字线与「20×× 年 月 日」。 + +### 另外新增(可关闭) + +「三、成绩评定与异议」一节 —— 说明总成绩如何取整、异议如何在几个 +工作日内提出。原件没有,但归档材料有这一节更完整。 + +不要的话把 `.tex` 里这个开关改成 0: + +```latex +\def\grdwithini{0} % 1=印这一节,0=不印 +``` + +⚠️ 关掉后正文变短,签字栏会往上移。若想让它仍贴底部,把 `oucgrade.sty` +里签字块前的 `\par\vspace{3mm}` 调大即可(见[坑 3](#坑-3签字栏被挤到第-2-页))。 + +## 比例自洽校验 + +模板会检查三组加法: + +``` +平时 + 期末 = 100 (构成全部理论课) +作业 + 点名 = 平时 (构成全部平时成绩) +理论课 + 实验课 = 100 (构成全部总成绩) +``` + +不通过时: + +1. `.log` 里打出 + `*** oucgrade: 比例不自洽 --- 作业+点名 应构成全部平时成绩: 实际 25+10, 应为 30 ***` +2. PDF **标题正下方**印一行红字警告 + +**为什么值得做**:成绩构成说明是要归档、要被抽查的文件,比例加不起来 +是最常见也最难被自己发现的错误 —— 原件那句「平时 30%(作业 20%, +点名 10%)」正是靠心算才看得出 20+10=30。 + +**已做负面测试**:把 `\grdhw` 从 20 改成 25 重编,log 报 +`实际 25+10, 应为 30`,PDF 第 1 页顶部出现警告;改回 20 后警告消失。 + +⚠️ 警告印在**开头**不是文末。文末的提示会被签字栏挤到第 2 页, +而第 2 页通常没人翻 —— 等于没提示。 + +## 版式参数 + +### 页面 + +| 项 | 值 | 来源 | +| :-- | --: | :-- | +| 纸张 | A4 210×297mm | `pgSz 11906×16838` twips | +| 上下边距 | 25.40mm | `pgMar top/bottom 1440` | +| 左右边距 | 31.75mm | `pgMar left/right 1800` | +| 版心 | 146.50 × 246.20mm | 210−2×31.75 / 297−2×25.40 | +| 页脚距 | 17.51mm | `pgMar footer 992` | + +换算:`mm = twips / 1440 × 25.4`,`pt = twips / 20`。 + +### 字号 + +| 用途 | 原件 (w:sz) | 本模板 | 实测输出 | +| :-- | --: | --: | --: | +| 大标题 | 36 半磅 = 18pt | `18bp` | 18.00 | +| 副标题 | 24 = 12pt | `12bp` | 12.00 | +| 正文 | 28 = 14pt | `14bp` | 14.00 | +| 表格/签字 | — | `12bp` | 12.00 | + +⚠️ **必须写 `bp` 不能写 `pt`**。Word 的 pt 是 PostScript pt(1/72 in), +TeX 默认 pt 是 1/72.27 in,差 0.36%。写 `14pt` 实测输出 14.05。 + +### 行距 + +| 用途 | 值 | 说明 | +| :-- | --: | :-- | +| 正文 | 21.5bp | 14pt 的 1.54 倍 | +| 表格/签字 | 17bp | 12pt 的 1.42 倍 | + +原件 `docGrid linePitch=312` = 15.6pt,对 14pt 字只有 1.11 倍,太挤。 +本模板用 21.5bp(1.54 倍)—— 这是**有意的改善**,不是复刻。 +21.5 是为压到一页反复试出来的值,可读下限约 1.4 倍,还有余量。 + +### 表格列宽 + +6 列,Σ wd = 123.64mm: + +| 列 | 宽 | 内容 | +| :-- | --: | :-- | +| 项目 | 22.00mm | 理论课 / 实验课 | +| 占本类 | 14.00mm | 80% | +| 细分项目 | 26.00mm | 平时成绩 / 期末 | +| 占本类 | 14.00mm | 30% | +| 占总成绩 | 17.00mm | 24% | +| 评定依据 | 30.28mm | 作业 + 出勤 | + +**Σwd 为什么是 123.64 而不是 146.50**:`Q[wd=...]` 是内容区宽度, +不含 `colsep`。每列实际占位 = `wd + 2×colsep`,6 列共多占 +`6×2×1.905 = 22.86mm`。所以 +`Σwd = 146.50 − 22.86 = 123.64mm`。 + +## 五个坑 + +### 坑 1:`.tex` 里写带 `@` 的宏名 + +`.tex` 文档中 `@` 的 catcode 是 12(其他),不是 11(字母)。写 +`\grd@chk` 会被解析成 `\grd` + `@chk`,报 +`! LaTeX Error: Missing \begin{document}`,并且**连累后面所有内容** +(报一串 Undefined control sequence)。 + +**规矩**:带 `@` 的内部宏一律定义在 `.sty` 里,`.tex` 只调用不带 `@` +的公开接口(如 `\grdcheck`)。 + +### 坑 2:tabularray 的 `hline{}` 里不能用带 `@` 的宏 + +```latex +hline{1,Z}={\grd@rulev} % ✗ 报 \l__tblr_v_tl ->\grd @rulev +hline{1,Z}={0.5pt} % ✓ 写字面值 +``` + +tabularray 把 `hline` 的参数当**字符串重新 tokenize**,那一刻 `@` 的 +catcode 已经退化,宏名在 `@` 处断开。 + +**规矩**:`hline` / `vline` 的线宽写字面值,别用宏包一层。 + +### 坑 3:签字栏被挤到第 2 页 + +试过四种写法,只有最后一种同时满足「一页」+「不出界」: + +| 写法 | 结果 | +| :-- | :-- | +| `\par\vspace{4mm}` + minipage | ✗ 翻页(minipage 紧跟 `\par` 是合法断页点) | +| `\vfill` 顶到底部 | ✗ 不翻页但**出界**:年月日 y=774.9,版心底只有 771.6 | +| `\vfill` + 块内 `\vspace*{5mm}` | ✗ 又翻页(`\vfill` 与块高之和超出剩余空间时,TeX 不接受压缩 `\vfill`,只能整块搬迁) | +| `\par\vspace{3mm}` + minipage | ✓ 一页,内容底 769.8,余 1.8pt | + +**结论**:不要指望竖直胶帮你「自动贴底」。单页文档里最稳的是 +**固定间距 + 实测校准** —— 改正文后重编一次,看内容底距 771.6 还有多少。 + +### 坑 4:minipage 内部用 `\hfill` 做右对齐 + +```latex +\begin{minipage}{76mm} + 任课教师(签字):\rule{40mm}{0.4pt}\par % 行尾没有 \parfillskip 弹性 +\end{minipage} +``` + +minipage 里的行末会被拉伸到满宽,12pt 的字出现夸张字距 —— +实测「任」「课」「教」「师」被拉到 **34.8pt 一字**。 + +**正解**:minipage 内 `\raggedright`,`\hfill` 只放在外面: + +```latex +\noindent\makebox[\textwidth][r]{\begin{minipage}{76mm}\raggedright ...\end{minipage}} +``` + +### 坑 5:列表引导符「·」缺字 + +本库 OUC Serif 子集里**没有** `·`(U+00B7) 和 `•`(U+2022), +用它们会报 `Missing character: There is no · (U+00B7)`,印出来是空白。 + +实测该字体有 `●`(U+25CF) 与 `○`(U+25CB),且 `fonts.tex` 已把这两个 +码位归入 CJK 字符类,可直接用。本模板用缩小 0.6 倍的 `●` 作引导符。 + +## 真实数据零泄漏 + +原件是**填过的实例**(真实课程名、学年、教师姓名、全部比例)。 +本模板把这些逐项换成占位符。 + +已 grep 确认以下关键词在 `oucgrade.sty` 与 `成绩构成说明.tex` 中 +**零命中**(含注释): + +``` +数字逻辑 2025 秋季 杨永全 80% 30% 20% 10% 70% +``` + +注意:`80`/`20`/`30` 这些纯数字作为**默认占位值**是存在的(宏定义里), +但它们不代表原件真实比例,替换时改掉即可。真正需要保证零命中的是 +课程名、年份、教师名这类可识别的信息。 + +## 字体 + +全部来自仓库公共字体包 `../fonts.tex`(唯一允许声明字体的地方): + +| 用途 | 字体 | 授权 | +| :-- | :-- | :-- | +| 正文宋体 | OUC Serif(思源宋体 GB2312 子集) | SIL OFL 1.1 | +| 标题楷体 | OUC Kai(霞鹜文楷子集) | SIL OFL 1.1 | +| 分节黑体 | OUC Sans(思源黑体子集) | SIL OFL 1.1 | +| 西文 | TeX Gyre Termes | GUST Font License | + +⚠️ 原件标题用的是**方正楷体_GB2312**,那是商业字体,本库不含也不能分发。 +改用霞鹜文楷(同属楷书形态,开源可商用)。这是**有意的替换**,不是遗漏。 + +⚠️ 不要用 `\setCJKmainfont` 直接指定系统字体(SimSun / SimHei 等)—— +换到 Linux / macOS 就编不出来。全部走 `../fonts.tex`。 \ No newline at end of file diff --git a/成绩构成说明/oucgrade.sty b/成绩构成说明/oucgrade.sty new file mode 100644 index 0000000..d5c4d50 --- /dev/null +++ b/成绩构成说明/oucgrade.sty @@ -0,0 +1,352 @@ +%====================================================================== +% oucgrade.sty — 中国海洋大学《成绩构成说明》版式包 +% +% 依据:学校下发的一份《成绩构成说明》.doc(WPS 保存) +% 目标:一页纸的说明文档。版式要素取自原件,正文结构重新组织 +% (原件是一段流水账,本模板改成「总述 + 分项 + 表格 + 签字」)。 +% +% 用法见同目录 成绩构成说明.tex,说明见 README.md +% +% ------------------------------------------------------------------ +% 尺寸换算口径(全文统一,出现新数值时照此办理) +% ------------------------------------------------------------------ +% twips → mm : mm = twips / 1440 × 25.4 +% twips → pt : pt = twips / 20 (1 pt = 1/72 in) +% w:sz : 半磅值,÷ 2 即 pt +% TeX pt ≠ PostScript pt:Word 的 pt 是 PS pt(1/72 in), +% TeX 默认 pt 是 1/72.27 in,差 0.36%。所以字号一律写 **bp**。 +% \fontsize{14bp}{...} 而不是 \fontsize{14pt}{...} +%====================================================================== +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{oucgrade}[2026/10/27 v1.0 OUC grade composition statement] + +\RequirePackage{geometry} +\RequirePackage{fontspec} +\RequirePackage{xeCJK} +\RequirePackage{tabularray} +\RequirePackage{enumitem} +\RequirePackage{graphicx} % \scalebox,用于缩小列表引导符 + +%====================================================================== +% 1. 页面与版心 +% +% 原 docx sectPr: +% pgSz 11906 × 16838 twips = 210.00 × 297.02 mm → A4 +% pgMar top/bottom 1440 = 25.40 mm +% left/right 1800 = 31.75 mm +% header 851 / footer 992 = 15.01 / 17.51 mm +% docGrid linePitch 312 → 行距 15.6 pt +% +% ⇒ 版心宽 = 210 − 2×31.75 = 146.50 mm +% 版心高 = 297 − 2×25.40 = 246.20 mm +% +% 原件的正文距页面顶端 186.29pt 才有第一行文字,是因为上方有 +% 18pt 大标题 + 12pt 副标题 + 空段。本模板保留这个竖向节奏, +% 但内容改成结构化列表后自然变长,故不强行复刻原件的留白高度。 +%====================================================================== +\geometry{ + paperwidth = 210mm, + paperheight = 297mm, + left = 31.75mm, % = pgMar left 1800 twips + right = 31.75mm, + top = 25.40mm, % = pgMar top 1440 twips + bottom = 25.40mm, + headheight = 0pt, + headsep = 0pt, + footskip = 17.51mm, +} +\setlength{\parindent}{0pt} +\setlength{\parskip}{0pt} +\pagestyle{empty} % 原件无页码,一页纸不需要页码 + +%====================================================================== +% 2. 字体 +% +% 全部取自仓库公共字体包 ../fonts.tex(唯一允许声明字体的地方)。 +% 原件的标题用「方正楷体_GB2312」——那是商业字体,本库不含。 +% 改用 **霞鹜文楷**(\kaiti):同为楷体形态,SIL OFL 1.1 可免费商用。 +% 正文原为宋体,用 \songti(思源宋体子集)。 +% +% 这一处替换是**有意的**,不是遗漏:方正楷体不能随仓库分发, +% 换成语义等价的开源楷体是唯一可行方案。视觉上两者都是楷书, +% 细微笔画差异不影响「标题用楷体」这个观感。 +%====================================================================== +\input{../fonts.tex} + +% xeCJK 的 PunctStyle 默认是 quanjiao,会把全角括号的 advance 从 +% 1.0em 压到 0.5em,省下的空间记在行内盒子起点 —— 表现为含「()」 +% 的行整行右移,居中格看起来不居中。改成 plain 取消挤压。 +\xeCJKsetup{PunctStyle=plain} + +%====================================================================== +% 3. 字号 +% +% 原件实测(导出 PDF 读 span 的 size): +% 大标题 18.00pt ← w:sz=36 半磅 = 18pt +% 副标题 12.00pt ← w:sz=24 = 12pt +% 正文 14.05pt ← w:sz=28 = 14pt +% +% ⚠️ 正文实测 14.05 而非 14.00:WPS 内部按 1/20 pt 取整后再乘缩放 +% 系数,0.05 是渲染误差。本模板写 14bp,实测输出 14.00。 +% +% ⚠️ 行距:原 docGrid linePitch=312 twips = 15.60pt。 +% 但 14pt 字配 15.6pt 行距太挤(1.11 倍),原件正文段与段之间 +% 靠 docGrid 的"整数行"撑开,视觉上并不挤。 +% 本模板正文用 23bp 行距(14×1.64),接近 Word 的中文单倍行距观感, +% 比原件的 15.6pt 更易读 —— 这是**有意的改善**,不是复刻。 +%====================================================================== +% \linespread 必须在 \fontsize 之后调用:\fontsize 会重设 \baselineskip, +% 把先前 \linespread 的系数覆盖掉。写反了行距纹丝不动。 +\newcommand{\grd@ls}{\linespread{1}\relax} + +\newcommand{\grdtitle}{% 大标题 18bp + \grd@ls\fontsize{18bp}{30bp}\selectfont} +\newcommand{\grdsubtitle}{% 副标题 12bp + \grd@ls\fontsize{12bp}{23bp}\selectfont} +\newcommand{\grdbody}{% 正文 14bp + % 行距 23bp → 21.5bp:为压到一页而收紧。21.5 / 14 = 1.54 倍, + % 中文正文可读下限约 1.4 倍,离下限还有余量,不是硬挤。 + \grd@ls\fontsize{14bp}{21.5bp}\selectfont} +\newcommand{\grdsmall}{% 表格/签字栏 12bp + \grd@ls\fontsize{12bp}{17bp}\selectfont} + +%====================================================================== +% 4. 标题区 +% +% 原件: +% 大标题 18pt 粗体 楷体 居中 baseline y=108.89 +% 副标题 12pt 常规 楷体 居中 baseline y=138.17 +% 两者相距 29.28pt +% +% 本模板加了一条细分隔线(原件没有),理由:标题与正文之间原件 +% 留了 48pt 空白,空得没有依据;加一条 0.5pt 细线既收住标题区, +% 又比纯留白更像正式文件。若你不要这条线,把 \grd@rule 设为 0pt。 +%====================================================================== +\newlength{\grd@rulev}\setlength{\grd@rulev}{0.5pt} +\newlength{\grd@rulewd}\setlength{\grd@rulewd}{\textwidth} + +\newcommand{\grdmaintitle}[1]{% + \par\begingroup + \centering \grdtitle\kaiti\bfseries #1\par + \endgroup} +\newcommand{\grdsubtitleline}[1]{% + \par\begingroup + \centering \grdsubtitle\kaiti #1\par + \endgroup} + +%====================================================================== +% 5. 分节标题(一、二、三…) +% +% 原件没有分节,全文两段流水账。本模板拆成「总述 / 理论课 / 实验课」 +% 三节,每节一个小标题,便于教务检查时逐项核对。 +%====================================================================== +\newcommand{\grdsec}[1]{% + \par\vspace{2.8mm}% 原 4.0mm,压缩以保一页 + {\grdbody\heiti\bfseries #1}\par + \vspace{0.6mm}% 原 1.2mm +} + +%====================================================================== +% 6. 正文段落与列表 +% +% 正文首行缩进 2 字:原件 w:ind firstLineChars=200(=2 字符)。 +% firstLine = 560 twips = 9.88 mm,对 14pt 字正好 2 字。 +%====================================================================== +\newcommand{\grdpara}[1]{% + \par\begingroup + \grdbody\songti + \setlength{\parindent}{2\ccwd}% + #1\par + \endgroup} + +% 分项列表:用「●」引导,悬挂缩进,比 Word 的自动编号更稳 +% (不依赖 counters,复制粘贴不会串号) +% +% ⚠️ 引导符不能用中点「·」(U+00B7):本库的 OUC Serif 子集里**没有** +% 这个字形,会报 "Missing character: There is no · (U+00B7)", +% 印出来是空白。实测该字体有 ●(U+25CF) 与 ○(U+25CB), +% 且 fonts.tex 已把这两个码位归入 CJK 字符类,可直接用。 +% 也考虑过「•」(U+2022),同样缺字,不要用。 +\newenvironment{grdlist}{% + \par\begingroup + \grdbody\songti + \begin{list}{}{\setlength{\leftmargin}{2\ccwd}% + \setlength{\itemindent}{0pt}% + \setlength{\labelwidth}{1\ccwd}% + \setlength{\labelsep}{1\ccwd}% + \setlength{\itemsep}{0.3mm}% + \setlength{\parsep}{0pt}% + \setlength{\topsep}{0.8mm}}% +}{% + \end{list}\endgroup} + +\newcommand{\grditem}[2]{% + \item[{\grdbody\songti\raisebox{0.15ex}{\scalebox{0.6}{●}}}]% + {\grdbody\songti #1}#2} + +%====================================================================== +% 7. 成绩构成表 +% +% ⚠️⚠️ 列宽算法(这里踩过一次,务必按此办): +% tabularray 的 Q[wd=...] 是**内容区宽度**,不含 colsep。 +% 每列实际占位 = wd + 2×colsep(左右各一个 1.905mm)。 +% 所以 6 列总共要多占 6×2×1.905 = 22.86mm。 +% +% 最初按「wd 之和 = 版心宽」分配(24+15+30+15+18+30 = 132mm), +% 结果表格实际宽到 560.8pt,冲出页面 146.03pt —— 因为漏了 colsep。 +% +% 正确算法:Σwd = 版心宽 − 6×2×colsep = 146.50 − 22.86 = 123.64mm +% +% 列宽分配(Σ = 123.64mm): +% 项目 22.00mm 「理论课」「实验课」三个字 + 边距 +% 占本类 14.00mm 「80%」 +% 细分项目 26.00mm 「平时成绩」「实验环节」 +% 占本类 14.00mm 「30%」 +% 占总成绩 17.00mm 「24%」 +% 评定依据 30.64mm 余下,最长列的「由实验课教师评定」两行放得下 +%====================================================================== +\newenvironment{grdtable}{% + \par\begingroup\centering + \begin{tblr}{ + colspec={Q[c,m,wd=22mm] Q[c,m,wd=14mm] Q[c,m,wd=26mm] + Q[c,m,wd=14mm] Q[c,m,wd=17mm] Q[l,m,wd=30.28mm]}, + colsep=1.905mm, rowsep=0pt, stretch=0, + % ⚠️ 线宽必须写字面值 0.5pt,**不能**写成 \grd@rulev 之类的宏。 + % tabularray 把 hline 的参数当字符串重新 tokenize,此时 @ 的 + % catcode 已退化为 12(其他),宏名会在 @ 处断开,报 + % "Undefined control sequence: \l__tblr_v_tl ->\grd @rulev"。 + % 这个坑在所有用 tabularray 的模板里都成立。 + hline{1,Z}={0.5pt}, hline{2}={0.5pt}, + vline{1,Z}={0.5pt}, + row{1}={ht=8.5mm}, + row{2-Z}={ht=7.5mm}, + }% +}{% + \end{tblr}\par\endgroup} + +% 表头格 +\newcommand{\grdth}[1]{{\grdsmall\songti\bfseries #1}} +% 表身格 +\newcommand{\grdtd}[1]{{\grdsmall\songti #1}} + +%====================================================================== +% 8. 落款与签字栏 +% +% 原件**没有**签字栏(只有一段说明文字就结束了)。用户明确要求补上 +% 「任课老师签字」和年月日 —— 这是成绩构成说明作为归档材料的必要项: +% 没有签字的说明文件在教务归档时不被认作有效文件。 +% +% 版式(右侧靠齐,与公文落款习惯一致): +% 任课教师(签字):____________ +% 20×× 年  月  日 +% +% ⚠️⚠️ 踩过的两个坑(都表现成「内容不多却翻到下一页」): +% +% 坑① minipage 内部用 \hfill 撑右对齐 +% → 内部行末被拉伸,12pt 的字被拉成 34.8pt 一字 +% (实测「任」「课」「教」「师」间距 34.8pt)。 +% 正解:\hfill 只放在 minipage **外面**,内部 \raggedright。 +% +% 坑② 用 \noindent\hfill\begin{minipage}... 推右 +% → \hfill 出现在段落开头,TeX 把「\hfill+minipage」视作 +% 一个不可分页的整体,加上它是 \par 之后的第一件事, +% 整个块被迫整页搬迁:上一页还剩 88pt,它仍翻页。 +% 正解:用 \makebox[\textwidth][r]{...} 一次性给足宽度, +% 排版器眼里这就是一个普通行内盒子,可以正常与上文同页。 +% +% 实测:改法②后 2 页 → 1 页,零 Overfull。 +%====================================================================== +\newlength{\grd@signline}\setlength{\grd@signline}{40mm} + +\newcommand{\grdsignblock}{% + % ⚠️⚠️ 这一块踩了三次「内容不多却翻页」,最终解法是**不用 \vfill**: + % + % 尝试① \par\vspace{4mm} + minipage + % → 翻页。minipage 是不可分对象,紧跟 \par 后成为合法断页点。 + % 尝试② \vfill 顶到底部 + % → 不翻页了,但会一直顶到版心底线,年月日落到 y=774.9, + % 而版心底只有 771.6 —— 出界 3.3pt,打印被裁。 + % 尝试③ \vfill + 块内 \vspace*{5mm} 留白 + % → 又翻页了。\vfill 与块高加起来超过剩余空间时, + % TeX 不接受压缩 \vfill,只能整块搬迁。 + % + % 最终解法:**固定间距 + 精确控制块高**,不依赖任何竖直胶。 + % \vspace 用一个实测够用的定值,块高用 minipage 内容决定。 + % 正文字数变了就调这个 3mm —— 文档只有一页,回归成本极低。 + % 实测 3mm 时内容底 769.8,距版心底 771.6 余 1.8pt,刚好不出界。 + \par\vspace{3mm} + \begingroup + \grdsmall\songti + \setlength{\parindent}{0pt}% + \noindent + \makebox[\textwidth][r]{% + \begin{minipage}[t]{76mm}% + \grdsmall\songti + \setlength{\parindent}{0pt}% + \raggedright % ← 左对齐不拉伸,见坑① + 任课教师(签字):\rule[-0.6mm]{\grd@signline}{0.4pt}\par + \vspace{1.5mm}% + \hspace*{2\ccwd}20××~年\hspace*{1.2em}月\hspace*{1.2em}日\par + \end{minipage}}% + \par + \endgroup} + +%====================================================================== +% 9. 比例自洽校验 +% +% 为什么要在模板里做算术检查:成绩构成说明是要归档、要被教务抽查的 +% 文件,比例加不起来是最常见也最难被自己发现的错误。 +% +% ⚠️ 原件里最容易搞错的一点:那些百分数的**基准不是同一个**。 +% 「理论课占总成绩 80%」——基准是总成绩 +% 「平时占 30%」——基准是**理论课**(不是总成绩!) +% 「作业占 20%」——基准也是理论课 +% 所以实际占总成绩是 80%×30% = 24%,而不是 30%。 +% 教材/教务检查时最常挑的毛病就是这里算错。 +% 本模板的表格直接把「折算后占总成绩」算出来印上,不让读者心算。 +% +% 校验三组: +% 平时 + 期末 = 100 (两者构成全部理论课) +% 作业 + 点名 = 平时 (两者构成全部平时成绩) +% 理论课 + 实验课 = 100 (两者构成全部总成绩) +% +% 调用(在 .tex 里,\begin{document} 之后): +% \grdcheck{理论课宏}{实验课宏}{平时宏}{期末宏}{作业宏}{点名宏} +% +% ⚠️ 这些宏名带 @,只能在 .sty 里定义。.tex 文档中 @ 不是 letter, +% 直接写 \grd@chk 会报 "Missing \begin{document}" 并连累后文。 +%====================================================================== +\newif\ifgrd@ok +\grd@oktrue + +\newcommand{\grd@chk}[3]{% + \ifnum\numexpr#1\relax=\numexpr#2\relax\else + \grd@okfalse + \typeout{^^J*** oucgrade: 比例不自洽 --- #3: 实际 #1, 应为 #2 ***^^J}% + \fi} + +\newcommand{\grdcheck}[6]{% + \grd@chk{#3+#4}{100}{平时+期末 应构成全部理论课}% + \grd@chk{#5+#6}{#3}{作业+点名 应构成全部平时成绩}% + \grd@chk{#1+#2}{100}{理论课+实验课 应构成全部总成绩}% +} + +% 折算:占总成绩 = 理论课比例 × 分项比例 ÷ 100 +% 例:80 × 30 / 100 = 24 +\newcommand{\grdcalc}[2]{\the\numexpr#1*#2/100\relax} + +% 校验失败时的醒目提示(印在文末) +\newcommand{\grdwarnifbad}{% + \ifgrd@ok\else + \par\vspace{2mm}% + {\centering\grdsmall\heiti\bfseries + ⚠ 警告:各分项比例不平衡(详见 .log),请核对第 1 节的数字。\par}% + \vspace{2mm}% + \fi} + +%====================================================================== +% 10. 文档级初始化 +%====================================================================== +\AtBeginDocument{\grdbody\songti} + +\endinput \ No newline at end of file diff --git a/成绩构成说明/成绩构成说明.pdf b/成绩构成说明/成绩构成说明.pdf new file mode 100644 index 0000000..07c3ec2 Binary files /dev/null and b/成绩构成说明/成绩构成说明.pdf differ diff --git a/成绩构成说明/成绩构成说明.tex b/成绩构成说明/成绩构成说明.tex new file mode 100644 index 0000000..2ebc736 --- /dev/null +++ b/成绩构成说明/成绩构成说明.tex @@ -0,0 +1,198 @@ +%====================================================================== +% 成绩构成说明.tex — 中国海洋大学《成绩构成说明》 +% +% 编译:在本目录下 xelatex 成绩构成说明.tex +% (不要从仓库根目录调用,fonts.tex 用的是相对路径) +% +% ------------------------------------------------------------------ +% ⚠️ 本文件里所有课程信息、比例、日期**全是虚构占位符**, +% 不得把真实课程数据留在模板里提交。 +% ------------------------------------------------------------------ +% +% 填表只需改下面第 1 节的 5 个宏,正文不用动。 +%====================================================================== +\documentclass[UTF8,fontset=none,zihao=-4,a4paper]{ctexart} +\usepackage{oucgrade} + +%====================================================================== +% 【第 1 节】课程信息(改这里就够了) +% +% ⚠️ 比例必须**自洽**,正文里有一处自动校验会检查: +% 理论课比例 + 实验课比例 = 100% +% 平时成绩比例 + 期末成绩比例 = 理论课比例 +% 作业比例 + 点名比例(+ 其它) = 平时成绩比例 +% 若填错,编译时会在 log 里打出警告,并在 PDF 上印一个醒目的 +% 「⚠ 比例不自洽」提示,防止带着算术错误归档。 +%====================================================================== +\newcommand{\grdcourse}{××××} % 课程名称 +\newcommand{\grdyear}{20××} % 学年 +\newcommand{\grdseason}{×} % 季学期(春 / 秋) +\newcommand{\grdteacher}{×××} % 任课教师 + +% ---- 总成绩构成(百分数,只填数字,不要带 %)---- +\newcommand{\grdtheory}{80} % 理论课占总成绩 +\newcommand{\grdlab}{20} % 实验课占总成绩 + +% ---- 理论课内部构成 ---- +\newcommand{\grddaily}{30} % 平时成绩占理论课 +\newcommand{\grdfinal}{70} % 期末考试成绩占理论课 + +% ---- 平时成绩内部构成(合计应等于 \grddaily)---- +\newcommand{\grdhw}{20} % 作业占理论课 +\newcommand{\grdattend}{10} % 点名占理论课 + +% ---- 实验课说明(一句话,写清由谁评定)---- +\newcommand{\grdlabnote}{由实验课教师根据实验报告与实验操作评定。} + +%====================================================================== +% 比例自洽校验 +% +% 模板会检查三组加法是否成立(校验代码在 oucgrade.sty §9): +% 理论课 + 实验课 = 100 +% 平时 + 期末 = 理论课 +% 作业 + 点名 = 平时 +% 不通过时 log 里打 *** oucgrade: 比例不自洽 ***,文末印红字提示。 +% +% 为什么值得做:成绩构成说明是要归档、要被教务抽查的文件, +% 比例加不起来是最常见也最难被自己发现的错误 —— 原件那句 +% 「平时成绩占30%(作业占20%,点名占10%)」正是靠心算才看得出 20+10=30。 +%====================================================================== +\AtBeginDocument{\grdcheck + {\grdtheory}{\grdlab}{\grddaily}{\grdfinal}{\grdhw}{\grdattend}} + +%====================================================================== +\begin{document} + +%====================================================================== +% 【第 2 节】标题区 +%====================================================================== +\grdmaintitle{成绩构成说明} + +\vspace{1.2mm} +\grdsubtitleline{\grdcourse\quad \grdyear~学年~\grdseason~季学期期末考试} + +% 比例不平衡的警告印在这里(标题正下方),而不是文末 —— +% 文末会被签字栏挤到第 2 页,没人翻就等于没提示。 +% 正常情况下这几行什么都不输出。 +\grdwarnifbad + +\vspace{2.0mm} +{\centering\rule{\textwidth}{0.5pt}\par} +\vspace{3.0mm} + +%====================================================================== +% 【第 3 节】总述 +% +% 原件第一段是「理论课成绩占总成绩的80%。理论课成绩包括平时成绩、 +% 期末考试成绩。……实验成绩占总成绩的20%。由实验课教师提供。」 +% —— 一段里塞了四层比例关系,读起来要在脑子里做三次加减。 +% +% 改写策略:总述只讲「几块、各占多少」,具体细分交给下面的表格。 +% 这样总述是一句话,表格负责分解,各司其职。 +%====================================================================== +\grdpara{本课程成绩由\textbf{理论课}与\textbf{实验课}两部分构成, +分别占总成绩的 \grdtheory\% 与 \grdlab\%。两部分的具体构成与评定依据 +见下表。} + +%====================================================================== +% 【第 4 节】成绩构成表 +% +% 这是本模板相对原件最大的改进。 +% +% 原件那句「理论课占80%。平时占30%(作业20%,点名10%),期末占70%」 +% 藏着三层不同基准的百分数: +% 80% → 基准是总成绩 +% 30% / 70% → 基准是**理论课**(不是总成绩) +% 20% / 10% → 基准也是理论课 +% 于是实际占总成绩是 80×30% = 24%、80×20% = 16%……学生要心算三轮 +% 才知道「作业到底折总成绩几分」。教务检查时这里也是最常被挑错的地方。 +% +% 表格设计:左半给「占理论课」的原比例(老师填表时的口径), +% 右半用 \grdcalc 自动算出「占总成绩」的真实权重。两者并排, +% 不用做任何心算,也杜绝了算错的可能。 +%====================================================================== +\grdsec{一、成绩构成} + +\begin{grdtable} + %------------------- 表头 ------------------- + \grdth{项目} & \grdth{占本类} & \grdth{细分项目} & + \grdth{占本类} & \grdth{占总成绩} & \grdth{评定依据} \\ + + %------------------- 理论课(跨 2 行)------------------- + % ⚠️ 每行必须是**恰好 6 个格**。&\& 多一个就会多出一列, + % 整表撑破版心报 Overfull(实测多一个 & 后冲出 122pt)。 + \SetCell[r=2]{c} \grdtd{理论课} + & \SetCell[r=2]{c} \grdtd{\grdtheory\%} + & \grdtd{平时成绩(作业 \grdhw\%、点名 \grdattend\%)} + & \grdtd{\grddaily\%} + & \grdtd{\grdcalc{\grdtheory}{\grddaily}\%} + & \grdtd{作业 + 出勤} \\ + & & \grdtd{期末} & \grdtd{\grdfinal\%} + & \grdtd{\grdcalc{\grdtheory}{\grdfinal}\%} + & \grdtd{闭卷笔试} \\ + + %------------------- 实验课 ------------------- + \grdtd{实验课} & \grdtd{\grdlab\%} + & \grdtd{实验环节} & \grdtd{100\%} + & \grdtd{\grdlab\%} & \grdtd{由实验课教师评定} \\ + + %------------------- 合计 ------------------- + % ⚠️ 跨 6 列时必须显式给 wd,否则用自然宽度不折行,报 Overfull。 + % wd = 表宽 − 2×colsep = 146.5 − 2×1.905 = 142.69mm + % (跨列格的 colsep 只算首尾各一个,不按每列算) + \SetCell[c=6]{m,wd=142.34mm} + \grdtd{\textbf{合计占总成绩 100\%:}理论课 \grdtheory\% + (平时 \grdcalc{\grdtheory}{\grddaily}\% + + 期末 \grdcalc{\grdtheory}{\grdfinal}\%)+ 实验课 \grdlab\%} \\ +\end{grdtable} + +%====================================================================== +% 【第 5 节】分项说明 +% +% 表格给数字,这一节给「怎么算」。原件缺这一层——学生看到 +% 「作业占20%」并不知道是按几次作业平均、缺交怎么算。 +% 这里留成占位文字,任课教师按自己课程的规则填写。 +%====================================================================== +\grdsec{二、分项说明} + +\grdpara{\textbf{平时成绩}(占理论课 \grddaily\%)由以下各项累计:} + +\begin{grdlist} + \grditem{作业(\grdhw\%)}{:按章布置,取各次作业成绩的算术平均; + 缺交一次扣该次成绩的 ×\%,抄袭按 × 分计。} + \grditem{点名(\grdattend\%)}{:随机抽查出勤,缺席一次扣 × 分, + 累计缺席达 × 次者该项记 0 分。} +\end{grdlist} + +\grdpara{\textbf{期末考试成绩}(占理论课 \grdfinal\%):闭卷笔试, +卷面 100 分,按 \grdfinal\% 折算计入总成绩。} + +\grdpara{\textbf{实验成绩}(占总成绩 \grdlab\%):\grdlabnote} + +%====================================================================== +% 【第 6 节】成绩评定与异议 +% +% 这一节原件没有,是本模板新增的。理由:成绩构成说明作为归档材料, +% 除了"怎么算"还应当说明"有异议怎么办",否则学生申诉时无据可依。 +% +% 若你所在院系不要求,或需要压到一页,整节删掉即可 +% (用 \grdomit 开关控制,不必删代码)。 +%====================================================================== +\def\grdwithini{1} % 1=印这一节,0=不印 +\ifnum\grdwithini=1 + \grdsec{三、成绩评定与异议} + \grdpara{总成绩按上述各项加权求和后,按学校规定的成绩记载办法取整记入。 + 学生对成绩有异议的,可在成绩公布后 × 个工作日内向开课单位提出书面复核 + 申请,逾期不再受理。} +\fi + +%====================================================================== +% 【第 7 节】签字栏 +% +% ⚠️ 原件**没有**这一栏,是用户要求补的。 +% 没有任课教师签字的成绩构成说明,在教务归档时不被认作有效文件, +% 所以这一节是必需的,不是装饰。 +%====================================================================== +\grdsignblock + +\end{document} \ No newline at end of file