修正联合行文标志与参数校验

This commit is contained in:
mizzlelover
2026-09-11 08:02:21 +08:00
parent de1fd6574d
commit 9f3598d60d
38 changed files with 41 additions and 20 deletions
+1 -1
View File
@@ -106,7 +106,7 @@ node scripts/verify_gongwen_docx.mjs --input /tmp/formal.docx --profile formal -
只有需要完整电子红头文件时,才加 `--letterhead digital`。红头和标题要使用目标电脑中实际安装的小标宋体;生成器缺少小标宋体或仿宋体时会在终端明确警告并写出替代字体,要求严格阻止替代输出时加 `--require-standard-fonts`。红线下标题会写入两个显式的28磅版心空行,不会依赖渲染器自行解释段前距;发文机关标志到文号也按相同方式留出两行。上行文的文号和签发人会在同一行编排。打开文档后,Word/WPS 的“引用→目录”可以按“标题1—标题4”生成并更新目录;是否显示第四级,在目录设置中选择。 只有需要完整电子红头文件时,才加 `--letterhead digital`。红头和标题要使用目标电脑中实际安装的小标宋体;生成器缺少小标宋体或仿宋体时会在终端明确警告并写出替代字体,要求严格阻止替代输出时加 `--require-standard-fonts`。红线下标题会写入两个显式的28磅版心空行,不会依赖渲染器自行解释段前距;发文机关标志到文号也按相同方式留出两行。上行文的文号和签发人会在同一行编排。打开文档后,Word/WPS 的“引用→目录”可以按“标题1—标题4”生成并更新目录;是否显示第四级,在目录设置中选择。
信函、命令(令)、纪要和横排表格走专用分支:信函生成170mm上粗下细、下页边20mm处上细下粗的两条红色双线,底线放在页脚并关闭页码;命令(令)落实机关标志距版心上边缘20mm、令号下空二行、正文下空二行;纪要把“出席”“请假”“列席”标签设为黑体、人员名单设为仿宋,并放在正文或附件说明下一行;横排表格生成横向A4和225mm表格,单双页表头方向仍需目标Word/WPS模板核对。联合行文可重复传入 `--joint-org`,不能与正文一起装订的附件加 `--attachment-detached` 会在首行补排文号和附件序号。附件可用重复的 `--attachment-file` 另页生成“附件”标签、第三行标题和正文,并保持正式页码连续。带抄送或印发信息时,版记浮动锚定在最后一页版心底部,首末粗线约0.35mm、中间细线约0.25mm。 信函、命令(令)、纪要和横排表格走专用分支:信函生成170mm上粗下细、下页边20mm处上细下粗的两条红色双线,底线放在页脚并关闭页码;命令(令)落实机关标志距版心上边缘20mm、令号下空二行、正文下空二行;纪要把“出席”“请假”“列席”标签设为黑体、人员名单设为仿宋,并放在正文或附件说明下一行;横排表格生成横向A4和225mm表格,单双页表头方向仍需目标Word/WPS模板核对。联合行文可重复传入 `--joint-org`生成主办机关在前、联署机关名称分行排列且“文件”置右并上下居中的标志;不能与正文一起装订的附件加 `--attachment-detached` 会在首行补排文号和附件序号。附件可用重复的 `--attachment-file` 另页生成“附件”标签、第三行标题和正文,并保持正式页码连续。带抄送或印发信息时,版记浮动锚定在最后一页版心底部,首末粗线约0.35mm、中间细线约0.25mm。
## 跨平台安装 ## 跨平台安装
+2 -2
View File
@@ -15,7 +15,7 @@ GB/T 9704-2012《党政机关公文格式》现行,2025-05-30 复审继续有
本工具只处理排版,不判断单位身份、授权状态或后续盖章方式。它会根据用户明确选择的版式模式应用对应的排版规则,不因“正式”“国企”“报告”或仅提供机构名称而擅自使用红头。 本工具只处理排版,不判断单位身份、授权状态或后续盖章方式。它会根据用户明确选择的版式模式应用对应的排版规则,不因“正式”“国企”“报告”或仅提供机构名称而擅自使用红头。
生成器可输出 A4、156mm×225mm 版心、三号仿宋正文、小标宋二号标题、四级标题层次、两字缩进,以及居中或单双页页码。四级标题均写入 Word/WPS 标题样式和大纲级别,便于后续插入、更新目录;文章总标题使用独立“公文标题”样式,不进入目录。上行文的文号和签发人在同一行编排,左右各空一字;信函、命令(令)、纪要和横排表格使用各自专用版式;电子联合行文可重复传入 `--joint-org`分离装订附件可加 `--attachment-detached`;重复传入 `--attachment-file` 时必须同时提供与附件顺序、标题一致的 `--attachment-note`,附件会另页生成并保持页码连续。版记会锚定最后一页版心底部,正式页码按版心下边缘下7mm的位置生成。正式版头的份号、密级、紧急程度和电子机关标志以版心上边缘为垂直锚点固定定位,不会因为左上字段而把机关标志或预印红头留白向下推移。只有传入密级而未传入份号时,首行会保留空位,密级仍从第二行开始。 生成器可输出 A4、156mm×225mm 版心、三号仿宋正文、小标宋二号标题、四级标题层次、两字缩进,以及居中或单双页页码。四级标题均写入 Word/WPS 标题样式和大纲级别,便于后续插入、更新目录;文章总标题使用独立“公文标题”样式,不进入目录。上行文的文号和签发人在同一行编排,左右各空一字;信函、命令(令)、纪要和横排表格使用各自专用版式;电子联合行文可重复传入 `--joint-org`;主办机关在前,联署机关名称分行排列,“文件”置右并按联署名称上下居中;分离装订附件可加 `--attachment-detached`;重复传入 `--attachment-file` 时必须同时提供与附件顺序、标题一致的 `--attachment-note`,附件会另页生成并保持页码连续。版记会锚定最后一页版心底部,正式页码按版心下边缘下7mm的位置生成。正式版头的份号、密级、紧急程度和电子机关标志以版心上边缘为垂直锚点固定定位,不会因为左上字段而把机关标志或预印红头留白向下推移。只有传入密级而未传入份号时,首行会保留空位,密级仍从第二行开始。
`references/formal-checklist.md` 是可选的版式复核清单。涉及印章或签名章时,使用者可在 Word/WPS 中插入已取得的图片或完成实体盖章;本生成器不内置印章图像。 `references/formal-checklist.md` 是可选的版式复核清单。涉及印章或签名章时,使用者可在 Word/WPS 中插入已取得的图片或完成实体盖章;本生成器不内置印章图像。
@@ -35,7 +35,7 @@ node scripts/generate_gongwen_docx.mjs --input source.md --output output.docx --
node scripts/generate_gongwen_docx.mjs --input source.md --output output.docx --format formal --letterhead digital --org "发文机关名称" --doc-no "单位发〔20261号" --title "文档标题" node scripts/generate_gongwen_docx.mjs --input source.md --output output.docx --format formal --letterhead digital --org "发文机关名称" --doc-no "单位发〔20261号" --title "文档标题"
``` ```
`letter``command``minutes``horizontal-table` 分别对应信函、命令(令)、纪要和横排表格格式;需要时显式传入 `--format` 和相应字段。横排表格会生成横向A4页面和225mm表格,单双页表头在订口/切口的朝向仍需目标 Word/WPS 模板核对。联合行文使用 `--joint-org`;附件不能与正文一起装订时使用 `--attachment-detached`,附件首行会补排文号和附件序号。`command` 会要求机关标志以“命令”或“令”结尾;信函中的份号、密级和紧急程度会在第一条双线下按标准顺序编排,联合行文和机关专用信函模板仍需目标软件核对。正式发文默认单双页页码;`standard` 为单页右、双页左,`center``none` 供普通材料选择。 `letter``command``minutes``horizontal-table` 分别对应信函、命令(令)、纪要和横排表格格式;需要时显式传入 `--format` 和相应字段。横排表格会生成横向A4页面和225mm表格,单双页表头在订口/切口的朝向仍需目标 Word/WPS 模板核对。联合行文使用 `--joint-org`,主办机关在前、联署机关名称分行排列,“文件”置右并按联署名称上下居中;附件不能与正文一起装订时使用 `--attachment-detached`,附件首行会补排文号和附件序号。`command` 会要求机关标志以“命令”或“令”结尾;信函中的份号、密级和紧急程度会在第一条双线下按标准顺序编排,联合行文和机关专用信函模板仍需目标软件核对。正式发文默认单双页页码;`standard` 为单页右、双页左,`center``none` 供普通材料选择。
附件可重复传入 `--attachment-file attachment.md`。附件 Markdown 的首个一级标题会作为附件标题,第一页第一行写“附件1”(后续文件递增),第三行写标题,随后排正文;附件说明通过 `--attachment-note` 提供,工具会统一为“附件:”并去除末尾标点,同时拒绝顺序或标题与附件文件不一致的输入。复杂横排附件、不能与正文一起装订的附件和机关专用模板仍需在目标 Word/WPS 中核对。 附件可重复传入 `--attachment-file attachment.md`。附件 Markdown 的首个一级标题会作为附件标题,第一页第一行写“附件1”(后续文件递增),第三行写标题,随后排正文;附件说明通过 `--attachment-note` 提供,工具会统一为“附件:”并去除末尾标点,同时拒绝顺序或标题与附件文件不一致的输入。复杂横排附件、不能与正文一起装订的附件和机关专用模板仍需在目标 Word/WPS 中核对。
BIN
View File
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

+1 -1
View File
@@ -52,7 +52,7 @@
- [ ] 印发机关和日期为四号仿宋,左空一字与右空一字;日期完整且不补零,后加“印发”。 - [ ] 印发机关和日期为四号仿宋,左空一字与右空一字;日期完整且不补零,后加“印发”。
- [ ] 页码为四号半角宋体阿拉伯数字,两侧各一字线,线距版心下边缘7mm;单页右空一字、双页左空一字;空白页、特定版记页和附件连续页码已按规则处理。 - [ ] 页码为四号半角宋体阿拉伯数字,两侧各一字线,线距版心下边缘7mm;单页右空一字、双页左空一字;空白页、特定版记页和附件连续页码已按规则处理。
- [ ] 横排表格使用 `--format horizontal-table` 或目标 Word/WPS 横向模板;本项目已实际渲染横向页面和225mm表格,但单双页表头在订口/切口的方向仍需目标软件核对。 - [ ] 横排表格使用 `--format horizontal-table` 或目标 Word/WPS 横向模板;本项目已实际渲染横向页面和225mm表格,但单双页表头在订口/切口的方向仍需目标软件核对。
- [ ] 信函、命令(令)、纪要、联合行文已使用相应专用版式;`formal --joint-org` 的截图已确认主办机关在前复杂机关标志仍按现行模板核对;不能用普通打印稿替代。 - [ ] 信函、命令(令)、纪要、联合行文已使用相应专用版式;`formal --joint-org` 的截图已确认主办机关在前、联署机关分行排列且“文件”置右并上下居中;复杂机关标志仍按现行模板核对;不能用普通打印稿替代。
- [ ] 信函格式已核对上边缘30mm、上粗下细双线、下页边20mm处上细下粗双线,双线长度均170mm;如有份号、密级、紧急程度,均置于第一条双线下并距线3号字高7/8;文号顶格居右;首页无页码且版记不画分隔线。当前生成器对这些可选信函版头字段要求使用专用模板。 - [ ] 信函格式已核对上边缘30mm、上粗下细双线、下页边20mm处上细下粗双线,双线长度均170mm;如有份号、密级、紧急程度,均置于第一条双线下并距线3号字高7/8;文号顶格居右;首页无页码且版记不画分隔线。当前生成器对这些可选信函版头字段要求使用专用模板。
- [ ] 命令(令)格式已核对发文机关全称加“命令”或“令”、标志上边缘距版心20mm、令号下空二行、正文下空二行;签发章和日期按7.3.5.3核对。 - [ ] 命令(令)格式已核对发文机关全称加“命令”或“令”、标志上边缘距版心20mm、令号下空二行、正文下空二行;签发章和日期按7.3.5.3核对。
- [ ] 纪要格式已核对标志上边缘距版心35mm,出席/请假/列席标签为黑体,人员为仿宋。 - [ ] 纪要格式已核对标志上边缘距版心35mm,出席/请假/列席标签为黑体,人员为仿宋。
+1 -1
View File
@@ -160,7 +160,7 @@
| 预印红头纸套打 | 是 | `--format formal --letterhead preprinted`,按纸样设置预留高度 | | 预印红头纸套打 | 是 | `--format formal --letterhead preprinted`,按纸样设置预留高度 |
| 完整电子红头 | 是 | `--format formal --letterhead digital` | | 完整电子红头 | 是 | `--format formal --letterhead digital` |
| 印章、签名章 | 文字版式之外 | 在 Word/WPS 中插入图片或实体盖章 | | 印章、签名章 | 文字版式之外 | 在 Word/WPS 中插入图片或实体盖章 |
| 联合行文 | 通过 `--joint-org` 行生成,主办机关在前 | 复杂机关专用标志和联署模板复核 | | 联合行文 | 通过 `--joint-org` 行生成,主办机关在前,“文件”置右并按联署名称上下居中 | 复杂机关专用标志和联署模板复核 |
| 附件 | 通过 `--attachment-file` 另页生成标签、标题和正文;`--attachment-detached` 补排文号和附件序号 | 复杂附件版式仍需人工复核 | | 附件 | 通过 `--attachment-file` 另页生成标签、标题和正文;`--attachment-detached` 补排文号和附件序号 | 复杂附件版式仍需人工复核 |
| 版记 | 是 | `--cc``--print-org``--print-date` 适用时生成 | | 版记 | 是 | `--cc``--print-org``--print-date` 适用时生成 |
| 信函、命令、纪要、横排表格 | 是/部分通过 | `--format letter|command|minutes|horizontal-table`,按实际字段生成;横排表头方向需模板复核 | | 信函、命令、纪要、横排表格 | 是/部分通过 | `--format letter|command|minutes|horizontal-table`,按实际字段生成;横排表头方向需模板复核 |
+1 -1
View File
@@ -20,7 +20,7 @@
| 7.2.1 | 份号六位、3 号、左上第一行 | `--copy-no` 只接受 1—6 位阿拉伯数字并补足六位 | 结构检查;实际是否需要份号由发文机关确认 | | 7.2.1 | 份号六位、3 号、左上第一行 | `--copy-no` 只接受 1—6 位阿拉伯数字并补足六位 | 结构检查;实际是否需要份号由发文机关确认 |
| 7.2.2 | 密级和保密期限第二行、3 号黑体 | `--secret` 按黑体3号写入;没有份号时自动保留第一行空位,使密级仍在第二行 | 结构检查和视觉审计;文字内容和期限写法人工复核 | | 7.2.2 | 密级和保密期限第二行、3 号黑体 | `--secret` 按黑体3号写入;没有份号时自动保留第一行空位,使密级仍在第二行 | 结构检查和视觉审计;文字内容和期限写法人工复核 |
| 7.2.3 | 紧急程度及排列顺序 | `--urgent` 按黑体 3 号写入,并按份号、密级、紧急程度顺序下移 | 适用性和紧急级别人工确认 | | 7.2.3 | 紧急程度及排列顺序 | `--urgent` 按黑体 3 号写入,并按份号、密级、紧急程度顺序下移 | 适用性和紧急级别人工确认 |
| 7.2.4 | 发文机关标志居中、红色、版心上边缘下 35mm、推荐小标宋 | `formal --letterhead digital` 才绘制;预印模式只留纸样区域;首面字段以版心上边缘为垂直锚点,机关标志固定在其下35mm,不推动机关标志或预留区;联合行文通过 `--joint-org` 行生成,主办机关在前,名称过长时自适应标志字号 | `verify_gongwen_docx.mjs``tests/measure-header-coordinates.mjs` 和[`gbt9704-screenshot-evidence.md`](gbt9704-screenshot-evidence.md);当前机缺少推荐字体时严格模式失败,复杂机关专用标志仍需模板核对 | | 7.2.4 | 发文机关标志居中、红色、版心上边缘下 35mm、推荐小标宋 | `formal --letterhead digital` 才绘制;预印模式只留纸样区域;首面字段以版心上边缘为垂直锚点,机关标志固定在其下35mm,不推动机关标志或预留区;联合行文通过 `--joint-org` 行生成,主办机关在前,“文件”置右并按联署名称上下居中;名称过长时自适应标志字号 | `verify_gongwen_docx.mjs``tests/measure-header-coordinates.mjs` 和[`gbt9704-screenshot-evidence.md`](gbt9704-screenshot-evidence.md);当前机缺少推荐字体时严格模式失败,复杂机关专用标志仍需模板核对 |
| 7.2.5 | 文号下空二行、六角括号、全年份、顺序号不加“第”不补零 | `formal`/`letter``--doc-no` 做格式校验,并写入两个显式 28 磅空行 | 文号语义由机关编号规则确认 | | 7.2.5 | 文号下空二行、六角括号、全年份、顺序号不加“第”不补零 | `formal`/`letter``--doc-no` 做格式校验,并写入两个显式 28 磅空行 | 文号语义由机关编号规则确认 |
| 7.2.6 | 上行文文号左空一字、签发人右空一字并同一行;标签仿宋、姓名楷体 | `--upward true --signer` 同行生成单一或两个签发人,左右各空一字;多签发人、联合行文转人工模板 | 结构校验和 PDF;复杂联合行文需按机关顺序人工排布 | | 7.2.6 | 上行文文号左空一字、签发人右空一字并同一行;标签仿宋、姓名楷体 | `--upward true --signer` 同行生成单一或两个签发人,左右各空一字;多签发人、联合行文转人工模板 | 结构校验和 PDF;复杂联合行文需按机关顺序人工排布 |
| 7.2.7 | 文号下 4mm、版心等宽红线 | `redRule()` 生成 156mm 红线,文号段后 4mm;预印模式不重绘 | PDF 量测;红色油墨和实际纸样人工核对 | | 7.2.7 | 文号下 4mm、版心等宽红线 | `redRule()` 生成 156mm 红线,文号段后 4mm;预印模式不重绘 | PDF 量测;红色油墨和实际纸样人工核对 |
+2 -2
View File
@@ -69,7 +69,7 @@ bash tests/visual-audit.sh /tmp/gongwen-visual-audit-all-rules
| 7.2.1 | 份号六位三号阿拉伯数字,版心左上第一行。 | `formal-digital-all-1.png``formal-preprinted-1.png` 显示 `000007`;独立坐标日志显示 39.88mm 首行位置。 | 截图通过。 | | 7.2.1 | 份号六位三号阿拉伯数字,版心左上第一行。 | `formal-digital-all-1.png``formal-preprinted-1.png` 显示 `000007`;独立坐标日志显示 39.88mm 首行位置。 | 截图通过。 |
| 7.2.2 | 密级和保密期限第二行三号黑体,数字用阿拉伯数字。 | `formal-digital-all-1.png` 显示 `机密★3年` 位于第二行。 | 截图通过;密级文字及期限是否适用需机关确认。 | | 7.2.2 | 密级和保密期限第二行三号黑体,数字用阿拉伯数字。 | `formal-digital-all-1.png` 显示 `机密★3年` 位于第二行。 | 截图通过;密级文字及期限是否适用需机关确认。 |
| 7.2.3 | 紧急程度三号黑体;与份号、密级同时出现时按份号、密级、紧急程度自上而下。 | `formal-digital-all-1.png` 显示三项顺序;`letter-fields-1.png` 显示信函双线下同顺序。 | 截图通过。 | | 7.2.3 | 紧急程度三号黑体;与份号、密级同时出现时按份号、密级、紧急程度自上而下。 | `formal-digital-all-1.png` 显示三项顺序;`letter-fields-1.png` 显示信函双线下同顺序。 | 截图通过。 |
| 7.2.4 | 机关全称/规范简称可加“文件”,居中红色;上边缘距版心上边缘35mm;联合行文主办机关在前,联署名称上下居中。 | `formal-digital-all-1.png``formal-joint-1.png`;坐标日志显示机关标志 71.41mm 页面坐标,字段差0.00mm;联合行文以主办机关在前并自适应同一行字号。 | 截图通过,推荐小标宋字体需目标机复核;复杂机关专用标志仍需模板核对。 | | 7.2.4 | 机关全称/规范简称可加“文件”,居中红色;上边缘距版心上边缘35mm;联合行文主办机关在前,联署名称上下居中。 | `formal-digital-all-1.png``formal-joint-1.png`;坐标日志显示机关标志 71.41mm 页面坐标,字段差0.00mm;联合行文以主办机关在前、联署机关名称分行排列,“文件”置右并按联署名称上下居中;名称过长时自适应标志字号。 | 截图通过,推荐小标宋字体需目标机复核;复杂机关专用标志仍需模板核对。 |
| 7.2.5 | 机关标志下空二行;年份全称、六角括号、顺序号不加“第”不补零、末尾“号”;上行文文号左空一字。 | `formal-digital-all-1.png``formal-digital-upward-1.png`;文号输入边界和显式空行均经校验。 | 截图通过。 | | 7.2.5 | 机关标志下空二行;年份全称、六角括号、顺序号不加“第”不补零、末尾“号”;上行文文号左空一字。 | `formal-digital-all-1.png``formal-digital-upward-1.png`;文号输入边界和显式空行均经校验。 | 截图通过。 |
| 7.2.6 | “签发人:”三号仿宋、姓名三号楷体,右空一字;多签发人按顺序、一般每行两名、回行对齐。 | `formal-digital-upward-1.png` 显示同一行双签发人,姓名字体和标签分 run。 | 截图通过;超过两名或联合行文复杂签发人仍须专用模板。 | | 7.2.6 | “签发人:”三号仿宋、姓名三号楷体,右空一字;多签发人按顺序、一般每行两名、回行对齐。 | `formal-digital-upward-1.png` 显示同一行双签发人,姓名字体和标签分 run。 | 截图通过;超过两名或联合行文复杂签发人仍须专用模板。 |
| 7.2.7 | 文号下4mm处、版心等宽红色分隔线。 | `formal-digital-all-1.png``formal-joint-1.png`;线宽156mm,红线下标题空两行。 | 截图通过;预印模式明确不重绘红线。 | | 7.2.7 | 文号下4mm处、版心等宽红色分隔线。 | `formal-digital-all-1.png``formal-joint-1.png`;线宽156mm,红线下标题空两行。 | 截图通过;预印模式明确不重绘红线。 |
@@ -98,7 +98,7 @@ bash tests/visual-audit.sh /tmp/gongwen-visual-audit-all-rules
## 本次发现并修正的实现问题 ## 本次发现并修正的实现问题
1. 命令(令)分支曾把20mm误当成纸张上边距,导致机关标志距离纸顶约20mm;现在恢复标准37mm天头,并在版心上边缘下20mm处排标志,实际截图已复核。 1. 命令(令)分支曾把20mm误当成纸张上边距,导致机关标志距离纸顶约20mm;现在恢复标准37mm天头,并在版心上边缘下20mm处排标志,实际截图已复核。
2. 联合行文曾把联署机关名称拆成多行,容易把“上下居中”误做成额外机关标志行;现在主办机关在前,联署名称同一居中行,自适应较小标志字号以保持一行 2. 联合行文曾把联署机关名称错误压成同一横行;现在主办机关在前、联署机关名称分行排列,“文件”置右并按联署名称上下居中,名称过长时自适应标志字号。
3. 纪要出席、请假、列席名单曾追加在附件和版记之后;现在紧跟正文或附件说明下一行生成,符合10.3的编排位置。 3. 纪要出席、请假、列席名单曾追加在附件和版记之后;现在紧跟正文或附件说明下一行生成,符合10.3的编排位置。
4. PDF 字形量测曾按 `yMin` 粗略分组,遇到高字形会把同一视觉行拆开;现在按字形垂直重叠合并后再量测,独立坐标结果稳定。 4. PDF 字形量测曾按 `yMin` 粗略分组,遇到高字形会把同一视觉行拆开;现在按字形垂直重叠合并后再量测,独立坐标结果稳定。
5. 视觉审计补入了横排表格、22×28校准页、联合行文、分离装订附件、不盖章公文和命令(令)等场景,不再只依赖电子红头样例。 5. 视觉审计补入了横排表格、22×28校准页、联合行文、分离装订附件、不盖章公文和命令(令)等场景,不再只依赖电子红头样例。
+2 -2
View File
@@ -58,7 +58,7 @@ bash tests/visual-audit.sh /tmp/gongwen-visual-audit-all-rules
| 7.2.1 | 份号六位、左上第一行 | 截图通过 | `formal-digital-all-1.png``formal-preprinted-1.png` 显示 `000007`;首面字段采用固定定位。 | | 7.2.1 | 份号六位、左上第一行 | 截图通过 | `formal-digital-all-1.png``formal-preprinted-1.png` 显示 `000007`;首面字段采用固定定位。 |
| 7.2.2 | 密级和保密期限第二行、3 号黑体 | 截图通过 | `formal-digital-all-1.png` 显示左上第二行;保密期限具体写法仍需机关确认。 | | 7.2.2 | 密级和保密期限第二行、3 号黑体 | 截图通过 | `formal-digital-all-1.png` 显示左上第二行;保密期限具体写法仍需机关确认。 |
| 7.2.3 | 紧急程度及顺序 | 截图通过 | `formal-digital-all-1.png` 显示份号、密级、紧急程度顺序;是否适用由发文机关决定。 | | 7.2.3 | 紧急程度及顺序 | 截图通过 | `formal-digital-all-1.png` 显示份号、密级、紧急程度顺序;是否适用由发文机关决定。 |
| 7.2.4 | 机关标志居中、红色、距版心上边缘 35 mm | 版式结构通过,标准字体需复核 | `formal-digital-all-1.png``references/assets/visual-audit/header-coordinates.log` 的 PDF 字形量测;左上字段不再推动机关标志。机关标志字体按标准为推荐小标宋,本机缺少该字体,严格模式失败。联合行文标志仍需专用模板。 | | 7.2.4 | 机关标志居中、红色、距版心上边缘 35 mm | 版式结构通过,标准字体需复核 | `formal-digital-all-1.png``references/assets/visual-audit/header-coordinates.log` 的 PDF 字形量测;左上字段不再推动机关标志。机关标志字体按标准为推荐小标宋,本机缺少该字体,严格模式失败`formal-joint-1.png` 已观察主办机关在前、联署机关分行排列且“文件”置右并按联署名称上下居中,复杂机关专用标志仍需模板。 |
| 7.2.5 | 文号下空二行、年份、六角括号、序号规则 | 截图通过 | `formal-digital-all-1.png``formal-digital-upward-1.png`;输入验证拒绝“第”和前导零。 | | 7.2.5 | 文号下空二行、年份、六角括号、序号规则 | 截图通过 | `formal-digital-all-1.png``formal-digital-upward-1.png`;输入验证拒绝“第”和前导零。 |
| 7.2.6 | 上行文签发人及多签发人 | 结构通过,仍需人工 | `formal-digital-upward-1.png` 已见同一行和两个签发人;超过两个签发人或联合行文转机关模板。 | | 7.2.6 | 上行文签发人及多签发人 | 结构通过,仍需人工 | `formal-digital-upward-1.png` 已见同一行和两个签发人;超过两个签发人或联合行文转机关模板。 |
| 7.2.7 | 文号下 4 mm、版心等宽红线 | 截图通过 | `formal-digital-all-1.png` 红线与版心同宽;预印模式不重绘,改由纸样提供。 | | 7.2.7 | 文号下 4 mm、版心等宽红线 | 截图通过 | `formal-digital-all-1.png` 红线与版心同宽;预印模式不重绘,改由纸样提供。 |
@@ -84,7 +84,7 @@ bash tests/visual-audit.sh /tmp/gongwen-visual-audit-all-rules
1. 版头字段曾以普通段落排列,份号、密级、紧急程度会把电子红头机关标志向下推移,预印红头套打的留白也会被挤开。现在这些字段改为首面固定定位,版心中保留等高占位;`formal-digital-all-1.png``formal-preprinted-1.png` 已重新观察。 1. 版头字段曾以普通段落排列,份号、密级、紧急程度会把电子红头机关标志向下推移,预印红头套打的留白也会被挤开。现在这些字段改为首面固定定位,版心中保留等高占位;`formal-digital-all-1.png``formal-preprinted-1.png` 已重新观察。
2. 命令(令)分支曾把20mm误当成纸顶边距;现在恢复37mm天头,并从版心上边缘下20mm量测。 2. 命令(令)分支曾把20mm误当成纸顶边距;现在恢复37mm天头,并从版心上边缘下20mm量测。
3. 联合行文曾把联署机关拆成多行;现在主办机关在前、联署名称同一居中行,并在名称过长时自适应标志字号。 3. 联合行文曾把联署机关错误压成同一横行;现在主办机关在前、联署名称分行排列,“文件”置右并按联署名称上下居中,名称过长时自适应标志字号。
4. 纪要人员曾追加在附件和版记之后;现在紧跟正文或附件说明下一行。 4. 纪要人员曾追加在附件和版记之后;现在紧跟正文或附件说明下一行。
5. 红线下标题曾只依赖段前距,部分渲染器会把标题贴在线上。现在红线或纸上红线之后写入两个显式 28 磅空段落;截图能看到标题与红线之间的实际距离。 5. 红线下标题曾只依赖段前距,部分渲染器会把标题贴在线上。现在红线或纸上红线之后写入两个显式 28 磅空段落;截图能看到标题与红线之间的实际距离。
6. 主送机关带不带末尾冒号时曾可能重复,现在归一化为一行全角冒号。 6. 主送机关带不带末尾冒号时曾可能重复,现在归一化为一行全角冒号。
+23 -10
View File
@@ -134,10 +134,14 @@ function parseArgs(argv) {
args[name] = true; args[name] = true;
continue; continue;
} }
const value = argv[i + 1];
if (value === undefined || value.startsWith("--")) {
throw new Error(`--${name} requires a value`);
}
if (repeatable.has(name)) { if (repeatable.has(name)) {
args[name] = [...(args[name] ?? []), argv[i + 1]]; args[name] = [...(args[name] ?? []), value];
} else { } else {
args[name] = argv[i + 1]; args[name] = value;
} }
i += 1; i += 1;
} }
@@ -786,17 +790,20 @@ function buildDocument(blocks, args) {
// not move the centered mark upward. // not move the centered mark upward.
const jointOrganizations = Array.isArray(args["joint-org"]) ? args["joint-org"].map((name) => String(name).trim()).filter(Boolean) : []; const jointOrganizations = Array.isArray(args["joint-org"]) ? args["joint-org"].map((name) => String(name).trim()).filter(Boolean) : [];
const agencyNames = [String(args.org).trim(), ...jointOrganizations]; const agencyNames = [String(args.org).trim(), ...jointOrganizations];
// GB/T 9704-2012 7.2.4.2 keeps joint agency names on one centered // GB/T 9704-2012 7.2.4 keeps joint agency names in order with the
// mark row, with the host agency first. Full-width spaces preserve a // host first. When “文件” is present it sits to the right of the
// visible separation without creating extra logo rows that would move // stacked names and is vertically centred against that name block.
// the document number and title downward.
const host = String(args.org).trim(); const host = String(args.org).trim();
const jointNames = jointOrganizations.length && host.endsWith("文件")
? [host.slice(0, -2), ...jointOrganizations]
: agencyNames;
const middleIndex = Math.floor((jointNames.length - 1) / 2);
const jointText = jointOrganizations.length && host.endsWith("文件") const jointText = jointOrganizations.length && host.endsWith("文件")
? [...[host.slice(0, -2), ...jointOrganizations], "文件"].join(" ") ? jointNames.map((name, index) => index === middleIndex ? `${name} 文件` : name).join("\n")
: agencyNames.join(" "); : agencyNames.join(" ");
const agencyMarkSize = agencyNames.length > 1 ? (jointText.length > 16 ? "44" : "48") : "56"; const agencyMarkSize = agencyNames.length > 1 ? (jointText.length > 16 ? "44" : "48") : "56";
body.push(floatingAgencyMarkParagraph(jointText, 1, agencyMarkSize)); body.push(floatingAgencyMarkParagraph(jointText, jointOrganizations.length ? jointNames.length : 1, agencyMarkSize));
body.push(agencyMarkFlowSpacer()); body.push(agencyMarkFlowSpacer(jointOrganizations.length ? Math.max(0, jointNames.length - 1) * 560 : 0));
if (args["doc-no"]) body.push(...blankGridLines(2)); if (args["doc-no"]) body.push(...blankGridLines(2));
} }
if (letterhead === "preprinted") { if (letterhead === "preprinted") {
@@ -1014,7 +1021,13 @@ function writeDocx(output, documentXml, pageNumberMode, format) {
fs.rmSync(dir, { recursive: true, force: true }); fs.rmSync(dir, { recursive: true, force: true });
} }
const args = parseArgs(process.argv); let args;
try {
args = parseArgs(process.argv);
} catch (error) {
console.error(`GENERATOR ERROR: ${error.message}`);
process.exit(2);
}
if (args.help || !args.input || !args.output) { if (args.help || !args.input || !args.output) {
usage(); usage();
process.exit(args.help ? 0 : 1); process.exit(args.help ? 0 : 1);
+8
View File
@@ -130,8 +130,16 @@ unzip -p "$TMP_DIR/horizontal-table.docx" word/document.xml | grep -q 'w:tblW w:
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '主办机关' unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '主办机关'
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '协办机关' unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '协办机关'
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '文件' unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '文件'
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '主办机关 文件</w:t><w:br/>'
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q '协办机关</w:t>'
unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q 'w:sz w:val="48"' unzip -p "$TMP_DIR/joint.docx" word/document.xml | grep -q 'w:sz w:val="48"'
if "$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/missing-joint-name.docx" --format formal --letterhead digital --org "主办机关文件" --joint-org --doc-no "示例发〔20264号" --title "缺少联署机关名称" >"$TMP_DIR/missing-joint-name.out" 2>&1; then
echo "missing joint agency name unexpectedly succeeded" >&2
exit 1
fi
grep -q 'GENERATOR ERROR: --joint-org requires a value' "$TMP_DIR/missing-joint-name.out"
if "$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/strict.docx" --format formal --letterhead digital --org "示例单位文件" --title "严格字体测试" --require-standard-fonts >"$TMP_DIR/strict.out" 2>&1; then if "$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/strict.docx" --format formal --letterhead digital --org "示例单位文件" --title "严格字体测试" --require-standard-fonts >"$TMP_DIR/strict.out" 2>&1; then
if ! fc-list -f '%{family}\n' | grep -Eq '方正小标宋简体|方正小标宋_GBK|FZXiaoBiaoSong'; then if ! fc-list -f '%{family}\n' | grep -Eq '方正小标宋简体|方正小标宋_GBK|FZXiaoBiaoSong'; then
echo "strict font mode unexpectedly succeeded without a small-standard-title font" >&2 echo "strict font mode unexpectedly succeeded without a small-standard-title font" >&2