diff --git a/dist/traework-gongwen-skill.zip b/dist/traework-gongwen-skill.zip index 124c2c9..ac7dbb7 100644 Binary files a/dist/traework-gongwen-skill.zip and b/dist/traework-gongwen-skill.zip differ diff --git a/references/assets/visual-audit/all-rules/command-1.png b/references/assets/visual-audit/all-rules/command-1.png index 2b57c56..7b49bb7 100644 Binary files a/references/assets/visual-audit/all-rules/command-1.png and b/references/assets/visual-audit/all-rules/command-1.png differ diff --git a/references/assets/visual-audit/all-rules/command-2.png b/references/assets/visual-audit/all-rules/command-2.png index 606ff04..fe9be1f 100644 Binary files a/references/assets/visual-audit/all-rules/command-2.png and b/references/assets/visual-audit/all-rules/command-2.png differ diff --git a/references/assets/visual-audit/all-rules/contact-sheet.png b/references/assets/visual-audit/all-rules/contact-sheet.png index 49039bd..04eb935 100644 Binary files a/references/assets/visual-audit/all-rules/contact-sheet.png and b/references/assets/visual-audit/all-rules/contact-sheet.png differ diff --git a/references/assets/visual-audit/all-rules/formal-attachments-3.png b/references/assets/visual-audit/all-rules/formal-attachments-3.png index b9dafcc..6bc5647 100644 Binary files a/references/assets/visual-audit/all-rules/formal-attachments-3.png and b/references/assets/visual-audit/all-rules/formal-attachments-3.png differ diff --git a/references/assets/visual-audit/all-rules/formal-attachments-4.png b/references/assets/visual-audit/all-rules/formal-attachments-4.png index f3b689e..fb32399 100644 Binary files a/references/assets/visual-audit/all-rules/formal-attachments-4.png and b/references/assets/visual-audit/all-rules/formal-attachments-4.png differ diff --git a/references/assets/visual-audit/all-rules/formal-attachments-detached-3.png b/references/assets/visual-audit/all-rules/formal-attachments-detached-3.png index 45f1d71..b0ea401 100644 Binary files a/references/assets/visual-audit/all-rules/formal-attachments-detached-3.png and b/references/assets/visual-audit/all-rules/formal-attachments-detached-3.png differ diff --git a/references/assets/visual-audit/all-rules/formal-digital-all-1.png b/references/assets/visual-audit/all-rules/formal-digital-all-1.png index a429aa2..9f1b9e8 100644 Binary files a/references/assets/visual-audit/all-rules/formal-digital-all-1.png and b/references/assets/visual-audit/all-rules/formal-digital-all-1.png differ diff --git a/references/assets/visual-audit/all-rules/formal-digital-all-2.png b/references/assets/visual-audit/all-rules/formal-digital-all-2.png index 3db9ddc..be94306 100644 Binary files a/references/assets/visual-audit/all-rules/formal-digital-all-2.png and b/references/assets/visual-audit/all-rules/formal-digital-all-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-digital-upward-1.png b/references/assets/visual-audit/all-rules/formal-digital-upward-1.png index 09453db..2e81be0 100644 Binary files a/references/assets/visual-audit/all-rules/formal-digital-upward-1.png and b/references/assets/visual-audit/all-rules/formal-digital-upward-1.png differ diff --git a/references/assets/visual-audit/all-rules/formal-digital-upward-2.png b/references/assets/visual-audit/all-rules/formal-digital-upward-2.png index f68a585..43d1519 100644 Binary files a/references/assets/visual-audit/all-rules/formal-digital-upward-2.png and b/references/assets/visual-audit/all-rules/formal-digital-upward-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-joint-1.png b/references/assets/visual-audit/all-rules/formal-joint-1.png index 629e23b..8264580 100644 Binary files a/references/assets/visual-audit/all-rules/formal-joint-1.png and b/references/assets/visual-audit/all-rules/formal-joint-1.png differ diff --git a/references/assets/visual-audit/all-rules/formal-joint-2.png b/references/assets/visual-audit/all-rules/formal-joint-2.png index d3a1d87..3a1a2df 100644 Binary files a/references/assets/visual-audit/all-rules/formal-joint-2.png and b/references/assets/visual-audit/all-rules/formal-joint-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-long-2.png b/references/assets/visual-audit/all-rules/formal-long-2.png index 51207e2..4deac30 100644 Binary files a/references/assets/visual-audit/all-rules/formal-long-2.png and b/references/assets/visual-audit/all-rules/formal-long-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-long-3.png b/references/assets/visual-audit/all-rules/formal-long-3.png index f549f50..12a0951 100644 Binary files a/references/assets/visual-audit/all-rules/formal-long-3.png and b/references/assets/visual-audit/all-rules/formal-long-3.png differ diff --git a/references/assets/visual-audit/all-rules/formal-preprinted-1.png b/references/assets/visual-audit/all-rules/formal-preprinted-1.png index a07677c..b95974a 100644 Binary files a/references/assets/visual-audit/all-rules/formal-preprinted-1.png and b/references/assets/visual-audit/all-rules/formal-preprinted-1.png differ diff --git a/references/assets/visual-audit/all-rules/formal-preprinted-2.png b/references/assets/visual-audit/all-rules/formal-preprinted-2.png index 606ff04..fe9be1f 100644 Binary files a/references/assets/visual-audit/all-rules/formal-preprinted-2.png and b/references/assets/visual-audit/all-rules/formal-preprinted-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-seal-2.png b/references/assets/visual-audit/all-rules/formal-seal-2.png index 457a3c9..d000960 100644 Binary files a/references/assets/visual-audit/all-rules/formal-seal-2.png and b/references/assets/visual-audit/all-rules/formal-seal-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-signed-2.png b/references/assets/visual-audit/all-rules/formal-signed-2.png index 8bade76..93a16e3 100644 Binary files a/references/assets/visual-audit/all-rules/formal-signed-2.png and b/references/assets/visual-audit/all-rules/formal-signed-2.png differ diff --git a/references/assets/visual-audit/all-rules/formal-unsigned-1.png b/references/assets/visual-audit/all-rules/formal-unsigned-1.png index 2e355c4..23b43eb 100644 Binary files a/references/assets/visual-audit/all-rules/formal-unsigned-1.png and b/references/assets/visual-audit/all-rules/formal-unsigned-1.png differ diff --git a/references/assets/visual-audit/all-rules/formal-unsigned-2.png b/references/assets/visual-audit/all-rules/formal-unsigned-2.png index 8b47196..c502441 100644 Binary files a/references/assets/visual-audit/all-rules/formal-unsigned-2.png and b/references/assets/visual-audit/all-rules/formal-unsigned-2.png differ diff --git a/references/assets/visual-audit/all-rules/horizontal-table-1.png b/references/assets/visual-audit/all-rules/horizontal-table-1.png index 3202e5b..40a88d3 100644 Binary files a/references/assets/visual-audit/all-rules/horizontal-table-1.png and b/references/assets/visual-audit/all-rules/horizontal-table-1.png differ diff --git a/references/assets/visual-audit/all-rules/letter-1.png b/references/assets/visual-audit/all-rules/letter-1.png index e92aecf..96e6a20 100644 Binary files a/references/assets/visual-audit/all-rules/letter-1.png and b/references/assets/visual-audit/all-rules/letter-1.png differ diff --git a/references/assets/visual-audit/all-rules/letter-fields-1.png b/references/assets/visual-audit/all-rules/letter-fields-1.png index 05871d7..ab6f2ae 100644 Binary files a/references/assets/visual-audit/all-rules/letter-fields-1.png and b/references/assets/visual-audit/all-rules/letter-fields-1.png differ diff --git a/references/assets/visual-audit/all-rules/manifest.tsv b/references/assets/visual-audit/all-rules/manifest.tsv index ed0a231..7fbc137 100644 --- a/references/assets/visual-audit/all-rules/manifest.tsv +++ b/references/assets/visual-audit/all-rules/manifest.tsv @@ -1,19 +1,19 @@ scenario profile pdf_pages committed_screenshot_examples command command 2 references/assets/visual-audit/all-rules/command-1.png, references/assets/visual-audit/all-rules/command-2.png -formal-attachments-detached digital 4 references/assets/visual-audit/all-rules/formal-attachments-detached-3.png -formal-attachments digital 4 references/assets/visual-audit/all-rules/formal-attachments-3.png, references/assets/visual-audit/all-rules/formal-attachments-4.png +formal-attachments-detached preprinted 4 references/assets/visual-audit/all-rules/formal-attachments-detached-3.png +formal-attachments preprinted 4 references/assets/visual-audit/all-rules/formal-attachments-3.png, references/assets/visual-audit/all-rules/formal-attachments-4.png formal-digital-all digital 2 references/assets/visual-audit/all-rules/formal-digital-all-1.png, references/assets/visual-audit/all-rules/formal-digital-all-2.png formal-digital-upward digital 2 references/assets/visual-audit/all-rules/formal-digital-upward-1.png, references/assets/visual-audit/all-rules/formal-digital-upward-2.png formal-joint digital 2 references/assets/visual-audit/all-rules/formal-joint-1.png, references/assets/visual-audit/all-rules/formal-joint-2.png -formal-long digital 3 references/assets/visual-audit/all-rules/formal-long-2.png, references/assets/visual-audit/all-rules/formal-long-3.png -formal-preprinted digital 2 references/assets/visual-audit/all-rules/formal-preprinted-1.png, references/assets/visual-audit/all-rules/formal-preprinted-2.png -formal-seal digital 2 references/assets/visual-audit/all-rules/formal-seal-2.png -formal-signed digital 2 references/assets/visual-audit/all-rules/formal-signed-2.png -formal-unsigned digital 2 references/assets/visual-audit/all-rules/formal-unsigned-1.png, references/assets/visual-audit/all-rules/formal-unsigned-2.png +formal-long preprinted 3 references/assets/visual-audit/all-rules/formal-long-2.png, references/assets/visual-audit/all-rules/formal-long-3.png +formal-preprinted preprinted 2 references/assets/visual-audit/all-rules/formal-preprinted-1.png, references/assets/visual-audit/all-rules/formal-preprinted-2.png +formal-seal preprinted 2 references/assets/visual-audit/all-rules/formal-seal-2.png +formal-signed preprinted 2 references/assets/visual-audit/all-rules/formal-signed-2.png +formal-unsigned preprinted 2 references/assets/visual-audit/all-rules/formal-unsigned-1.png, references/assets/visual-audit/all-rules/formal-unsigned-2.png horizontal-table horizontal-table 1 references/assets/visual-audit/all-rules/horizontal-table-1.png letter-fields letter 2 references/assets/visual-audit/all-rules/letter-fields-1.png letter letter 1 references/assets/visual-audit/all-rules/letter-1.png -minutes digital 2 references/assets/visual-audit/all-rules/minutes-1.png, references/assets/visual-audit/all-rules/minutes-2.png +minutes minutes 2 references/assets/visual-audit/all-rules/minutes-1.png, references/assets/visual-audit/all-rules/minutes-2.png ordinary-calibration ordinary 2 references/assets/visual-audit/all-rules/ordinary-calibration-1.png ordinary ordinary 1 references/assets/visual-audit/all-rules/ordinary-1.png -table ordinary 1 references/assets/visual-audit/all-rules/table-1.png +table formal 1 references/assets/visual-audit/all-rules/table-1.png diff --git a/references/assets/visual-audit/all-rules/minutes-1.png b/references/assets/visual-audit/all-rules/minutes-1.png index 7ac9d4c..e67a895 100644 Binary files a/references/assets/visual-audit/all-rules/minutes-1.png and b/references/assets/visual-audit/all-rules/minutes-1.png differ diff --git a/references/assets/visual-audit/all-rules/minutes-2.png b/references/assets/visual-audit/all-rules/minutes-2.png index 875be1c..d031d1e 100644 Binary files a/references/assets/visual-audit/all-rules/minutes-2.png and b/references/assets/visual-audit/all-rules/minutes-2.png differ diff --git a/references/assets/visual-audit/all-rules/ordinary-1.png b/references/assets/visual-audit/all-rules/ordinary-1.png index 049afdc..502f9a2 100644 Binary files a/references/assets/visual-audit/all-rules/ordinary-1.png and b/references/assets/visual-audit/all-rules/ordinary-1.png differ diff --git a/references/assets/visual-audit/all-rules/ordinary-calibration-1.png b/references/assets/visual-audit/all-rules/ordinary-calibration-1.png index 18e660e..e1a7a00 100644 Binary files a/references/assets/visual-audit/all-rules/ordinary-calibration-1.png and b/references/assets/visual-audit/all-rules/ordinary-calibration-1.png differ diff --git a/references/assets/visual-audit/all-rules/table-1.png b/references/assets/visual-audit/all-rules/table-1.png index bd9b656..ca28f7c 100644 Binary files a/references/assets/visual-audit/all-rules/table-1.png and b/references/assets/visual-audit/all-rules/table-1.png differ diff --git a/scripts/generate_gongwen_docx.mjs b/scripts/generate_gongwen_docx.mjs index c2dc3ac..e02907a 100755 --- a/scripts/generate_gongwen_docx.mjs +++ b/scripts/generate_gongwen_docx.mjs @@ -240,6 +240,22 @@ function floatingAgencyMarkParagraph(text, lineCount = 1, size = "56") { }); } +function floatingJointAgencyTable(names, size = "48", includeFile = true) { + const maxNameLength = Math.max(...names.map((name) => [...name].length), 1); + const rightWidth = includeFile ? 1600 : 0; + const leftWidth = Math.min(CONTENT_W - rightWidth, Math.max(3600, maxNameLength * 520 + 400)); + const tableWidth = leftWidth + rightWidth; + const cellMargins = ''; + const lineParagraph = (text) => `${run(text, { fontPreset: "title", size, color: "FF0000" })}`; + const leftCell = `${cellMargins}${names.map(lineParagraph).join("")}`; + const rightCell = includeFile + ? `${cellMargins}${lineParagraph("文件")}` + : ""; + const tablePr = ``; + const grid = `${includeFile ? `` : ""}`; + return `${tablePr}${grid}${leftCell}${rightCell}`; +} + function agencyMarkFlowSpacer(extraDxa = 0) { return paragraph("\u00a0", { align: "left", @@ -797,12 +813,9 @@ function buildDocument(blocks, args) { 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("文件") - ? jointNames.map((name, index) => index === middleIndex ? `${name} 文件` : name).join("\n") - : agencyNames.join(" "); - const agencyMarkSize = agencyNames.length > 1 ? (jointText.length > 16 ? "44" : "48") : "56"; - body.push(floatingAgencyMarkParagraph(jointText, jointOrganizations.length ? jointNames.length : 1, agencyMarkSize)); + const agencyMarkSize = agencyNames.length > 1 ? (Math.max(...jointNames.map((name) => [...name].length)) > 10 ? "44" : "48") : "56"; + if (jointOrganizations.length) body.push(floatingJointAgencyTable(jointNames, agencyMarkSize, host.endsWith("文件"))); + else body.push(floatingAgencyMarkParagraph(agencyNames.join(" "), 1, agencyMarkSize)); body.push(agencyMarkFlowSpacer(jointOrganizations.length ? Math.max(0, jointNames.length - 1) * 560 : 0)); if (args["doc-no"]) body.push(...blankGridLines(2)); } diff --git a/scripts/verify_gongwen_docx.mjs b/scripts/verify_gongwen_docx.mjs index 9ca0c29..c41caf5 100755 --- a/scripts/verify_gongwen_docx.mjs +++ b/scripts/verify_gongwen_docx.mjs @@ -133,17 +133,29 @@ if (profile === "formal") { check("Red rule width", /style="width:156mm;height:0\.5mm"/.test(doc), "header separator spans the 156 mm type area"); const docParagraphs = paragraphs(doc); const agencyIndex = docParagraphs.findIndex((p) => /w:sz w:val="(?:56|48|44)"/.test(p) && /w:color w:val="FF0000"/.test(p)); + const jointAgencyTable = doc.match(/[\s\S]*?]*w:vertAnchor="margin"[^>]*w:horzAnchor="margin"[^>]*w:tblpXSpec="center"[^>]*w:tblpY="1984"[\s\S]*?<\/w:tbl>/)?.[0] ?? ""; // Keep this expected value independent from the generator's calibration // constants. It is 35 mm in twentieths of a point, as required by 7.2.4. const agencyOffsetFromTypeAreaTop = Math.round(35 * 56.692913); - check("Digital red-head agency position", agencyIndex >= 0 && new RegExp(`w:framePr[^>]*w:hAnchor="margin"[^>]*w:vAnchor="margin"[^>]*w:xAlign="center"[^>]*w:y="${agencyOffsetFromTypeAreaTop}"`).test(docParagraphs[agencyIndex]) && /w:before="0"/.test(docParagraphs[agencyIndex]), "agency mark is independently fixed 35 mm below the type-area top"); + const agencyFrameOk = agencyIndex >= 0 + && new RegExp(`w:framePr[^>]*w:hAnchor="margin"[^>]*w:vAnchor="margin"[^>]*w:xAlign="center"[^>]*w:y="${agencyOffsetFromTypeAreaTop}"`).test(docParagraphs[agencyIndex]) + && /w:before="0"/.test(docParagraphs[agencyIndex]); + const jointAgencyFrameOk = Boolean(jointAgencyTable) && new RegExp(`w:tblpY="${agencyOffsetFromTypeAreaTop}"`).test(jointAgencyTable); + check("Digital red-head agency position", agencyFrameOk || jointAgencyFrameOk, "agency mark is independently fixed 35 mm below the type-area top"); + if (jointAgencyTable) { + const jointRows = (jointAgencyTable.match(//g) ?? []).length; + const hasFileCell = /]*>文件<\/w:t>/.test(jointAgencyTable); + const centeredCells = (jointAgencyTable.match(/w:vAlign w:val="center"/g) ?? []).length; + check("Joint agency vertical layout", jointRows >= 2 && centeredCells >= (hasFileCell ? 2 : 1) && /w:color w:val="FF0000"/.test(jointAgencyTable), hasFileCell ? "joint names are stacked and 文件 is vertically centered in a right-side cell" : "joint names are stacked and vertically centered"); + } const fixedHeaderFrames = docParagraphs .filter((p) => /w:framePr[^>]*w:hAnchor="margin"[^>]*w:vAnchor="margin"/.test(p)) .map((p) => Number((p.match(/w:y="(\d+)"/) ?? [])[1])) .filter((value) => Number.isFinite(value)); check("Digital red-head field frames", fixedHeaderFrames.every((value, index) => value === index * 560 || value === agencyOffsetFromTypeAreaTop), "left-corner fields use first-line grid positions without changing the agency mark anchor"); const docNoIndex = docParagraphs.findIndex((p) => /〔\d{4}〕[1-9]\d*号/.test(textOf(p))); - const agencyToDocNo = agencyIndex >= 0 && docNoIndex > agencyIndex ? docParagraphs.slice(agencyIndex + 1, docNoIndex) : []; + const agencyBoundary = agencyIndex >= 0 ? agencyIndex + 1 : jointAgencyTable ? 0 : -1; + const agencyToDocNo = agencyBoundary >= 0 && docNoIndex > agencyBoundary ? docParagraphs.slice(agencyBoundary, docNoIndex) : []; const agencyFlowSpacer = agencyToDocNo.filter((p) => /w:before="[1-9]\d*"/.test(p) && /w:snapToGrid w:val="false"/.test(p)); const agencyGapLines = agencyToDocNo.slice(-2); check("Agency mark to document number two blank lines", docNoIndex < 0 || (agencyFlowSpacer.length === 1 && agencyGapLines.length === 2 && agencyGapLines.every(isExplicitBlankGridLine)), "document number follows the fixed agency mark with two exact 28-point grid lines"); diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 538eee5..d0d744b 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -130,10 +130,42 @@ 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 'w:sz w:val="48"' +"$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/joint-four-agencies.docx" --format formal --letterhead digital --org "主办机关文件" --joint-org "协办机关一" --joint-org "协办机关二" --joint-org "协办机关三" --doc-no "示例发〔2026〕4号" --title "四机关联合行文测试" +"$NODE" "$VERIFY" --input "$TMP_DIR/joint-four-agencies.docx" --profile formal --letterhead digital +"$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/joint-without-file-suffix.docx" --format formal --letterhead digital --org "主办机关" --joint-org "协办机关" --doc-no "示例发〔2026〕5号" --title "无文件后缀联合行文测试" +"$NODE" "$VERIFY" --input "$TMP_DIR/joint-without-file-suffix.docx" --profile formal --letterhead digital +python3 - "$TMP_DIR/joint.docx" "$TMP_DIR/joint-four-agencies.docx" <<'PY' +import re +import sys +import zipfile + +for filename, expected_count in ((sys.argv[1], 2), (sys.argv[2], 4)): + with zipfile.ZipFile(filename) as archive: + xml = archive.read("word/document.xml").decode() + tables = re.findall(r'[\s\S]*?]*w:tblpY="1984"[\s\S]*?', xml) + assert len(tables) == 1, filename + table = tables[0] + assert table.count('') >= 2, filename + assert table.count('') == 2, filename + assert table.count('') == expected_count + 1, filename + assert '文件' in table, filename +PY +python3 - "$TMP_DIR/joint-without-file-suffix.docx" <<'PY' +import re +import sys +import zipfile + +with zipfile.ZipFile(sys.argv[1]) as archive: + xml = archive.read("word/document.xml").decode() +tables = re.findall(r'[\s\S]*?]*w:tblpY="1984"[\s\S]*?', xml) +assert len(tables) == 1 +table = tables[0] +assert table.count('') >= 1 +assert '文件' not in table +PY + if "$NODE" "$GEN" --input "$FIXTURE" --output "$TMP_DIR/missing-joint-name.docx" --format formal --letterhead digital --org "主办机关文件" --joint-org --doc-no "示例发〔2026〕4号" --title "缺少联署机关名称" >"$TMP_DIR/missing-joint-name.out" 2>&1; then echo "missing joint agency name unexpectedly succeeded" >&2 exit 1 diff --git a/tests/visual-audit.sh b/tests/visual-audit.sh index cf14281..a1b281c 100755 --- a/tests/visual-audit.sh +++ b/tests/visual-audit.sh @@ -27,7 +27,7 @@ node "$gen" --input "$all" --output "$out_dir/docx/formal-unsigned.docx" --forma node "$gen" --input "$all" --output "$out_dir/docx/formal-attachments.docx" --format formal --letterhead preprinted --letterhead-reserve-mm 72 --doc-no "示例发〔2026〕10号" --title "多附件实测" --attachment-note "1. 数据清单;2. 实施计划。" --attachment-file "$attach_a" --attachment-file "$attach_b" --page-number standard node "$gen" --input "$all" --output "$out_dir/docx/formal-attachments-detached.docx" --format formal --letterhead preprinted --letterhead-reserve-mm 72 --doc-no "示例发〔2026〕15号" --title "分离装订附件实测" --attachment-note "1. 数据清单;2. 实施计划。" --attachment-file "$attach_a" --attachment-file "$attach_b" --attachment-detached --page-number standard node "$gen" --input "$long" --output "$out_dir/docx/formal-long.docx" --format formal --letterhead preprinted --letterhead-reserve-mm 72 --doc-no "示例发〔2026〕11号" --title "长文版记与单双页实测" --cc "办公室、财务部、审计部、采购部、法务部、信息中心" --print-org "示例印发机关" --print-date "2026年9月10日" --page-number standard -node "$gen" --input "$all" --output "$out_dir/docx/formal-joint.docx" --format formal --letterhead digital --org "主办机关文件" --joint-org "协办机关一" --joint-org "协办机关二" --doc-no "示例发〔2026〕16号" --title "联合行文实测" --page-number standard +node "$gen" --input "$all" --output "$out_dir/docx/formal-joint.docx" --format formal --letterhead digital --org "主办机关文件" --joint-org "协办机关一" --joint-org "协办机关二" --joint-org "协办机关三" --doc-no "示例发〔2026〕16号" --title "联合行文实测" --page-number standard node "$gen" --input "$all" --output "$out_dir/docx/letter.docx" --format letter --org "示例机关" --doc-no "示例〔2026〕12号" --title "信函格式实测" --page-number none node "$gen" --input "$all" --output "$out_dir/docx/letter-fields.docx" --format letter --org "示例机关" --copy-no 7 --secret "机密★3年" --urgent "特急" --doc-no "示例〔2026〕14号" --title "信函版头字段实测" --page-number none node "$gen" --input "$all" --output "$out_dir/docx/command.docx" --format command --org "示例机关命令" --doc-no "第1号" --title "命令格式实测" --page-number standard