skills/docx-cn/scripts/gongwen_constants.js
wangyitong a65adcc2e5 Initial commit: merged, deduplicated, and vetted skill collection
Sources: extracted from two upstream archives (skill-repo, skills-main),
merged with the following policy:

- 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or
  ../../.agents/skills on a foreign machine) discarded
- 3 real name collisions with identical content (ai-pair, ifind-http-api,
  zhipu-websearch) kept as one copy
- Functional overlaps deduped keeping the strongest variant:
  - docx family: kept docx (official, full toolchain) + docx-cn
    (GB/T 9704 Chinese official-document constants),
    dropped docx_writer (no scripts, name collided with docx)
  - humanizer family: kept humanizer-zh (6 zh reference docs),
    dropped humanizer (en, redundant for CN workflow)
- Skills that only ran in a foreign environment removed:
  ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill,
  claude-driver
- alphapai excluded from this public repo because its SKILL.md hard-coded
  live credentials

Result: 25 skills, 572 files, ~7.5 MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:47:12 +08:00

288 lines
9.9 KiB
JavaScript
Raw Permalink 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.

/**
* GB/T 9704-2012 公文格式常量
* 供所有公文文档生成脚本共享
*/
const { AlignmentType, BorderStyle, WidthType, ShadingType, LevelFormat,
HeadingLevel, Paragraph, TextRun, Table, TableRow, TableCell,
Header, Footer, PageNumber } = require("docx");
// ─── 页面 ─────────────────────────────────────────────────
const PAGE = {
WIDTH: 11906, // 210mm
HEIGHT: 16838, // 297mm
MARGIN_TOP: 2098, // 37mm
MARGIN_BOTTOM: 1985, // 35mm
MARGIN_LEFT: 1588, // 28mm
MARGIN_RIGHT: 1474, // 26mm
CONTENT_WIDTH: 8844, // 210 - 28 - 26 mm
};
// ─── 字体 ─────────────────────────────────────────────────
const FONT = {
HEITI: { ascii: "SimHei", eastAsia: "黑体", hAnsi: "SimHei" },
FANGSONG: { ascii: "FangSong", eastAsia: "仿宋", hAnsi: "FangSong" },
KAITI: { ascii: "KaiTi", eastAsia: "楷体", hAnsi: "KaiTi" },
SONGTI: { ascii: "SimSun", eastAsia: "宋体", hAnsi: "SimSun" },
};
// ─── 字号half-point ───────────────────────────────────
const SIZE = {
ER_HAO: 44, // 二号 22pt
SAN_HAO: 32, // 三号 16pt
SI_HAO: 28, // 四号 14pt
XIAO_SI: 24, // 小四 12pt
WU_HAO: 21, // 五号 10.5pt
};
// ─── 行距twips = pt × 20 ─────────────────────────────
const LINE = {
BODY: { line: 560, lineRule: "exact" }, // 28pt
HEADING1: { line: 640, lineRule: "exact" }, // 32pt
HEADING2: { line: 560, lineRule: "exact" }, // 28pt
TABLE: { line: 440, lineRule: "exact" }, // 22pt
TITLE: { line: 640, lineRule: "exact" }, // 32pt
COMPACT: { line: 360, lineRule: "exact" }, // 18pt
};
// ─── 缩进DXA ─────────────────────────────────────────
const INDENT = {
FIRST_LINE: 560, // 首行缩进 2 字符
BULLET_LEFT: 1120,
BULLET_HANG: 560,
};
// ─── 边框 ─────────────────────────────────────────────────
const BORDER = {
NONE: { style: BorderStyle.NONE, size: 0 },
THICK: { style: BorderStyle.SINGLE, size: 12, color: "000000" }, // 1.5pt
THIN: { style: BorderStyle.SINGLE, size: 6, color: "000000" }, // 0.75pt
};
// ─── 样式预设 ─────────────────────────────────────────────
function getStyles() {
return {
default: {
document: {
run: { font: FONT.FANGSONG, size: SIZE.SI_HAO },
paragraph: { spacing: LINE.BODY },
},
},
paragraphStyles: [
{
id: "Heading1", name: "Heading 1",
basedOn: "Normal", next: "Normal", quickFormat: true,
run: { font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true },
paragraph: { spacing: { ...LINE.HEADING1, before: 240, after: 120 }, outlineLevel: 0 },
},
{
id: "Heading2", name: "Heading 2",
basedOn: "Normal", next: "Normal", quickFormat: true,
run: { font: FONT.KAITI, size: SIZE.SI_HAO, bold: true },
paragraph: { spacing: { ...LINE.HEADING2, before: 120, after: 60 }, outlineLevel: 1 },
},
],
};
}
function getNumbering() {
return {
config: [{
reference: "bullets",
levels: [{
level: 0, format: LevelFormat.BULLET, text: "\u2022",
alignment: AlignmentType.LEFT,
style: {
run: { font: FONT.FANGSONG, size: SIZE.SI_HAO },
paragraph: { indent: { left: INDENT.BULLET_LEFT, hanging: INDENT.BULLET_HANG } },
},
}],
}],
};
}
// ─── 辅助函数 ─────────────────────────────────────────────
/** 报告标题区(无封面,居中) */
function titleBlock(title, subtitle, date, institution) {
const items = [];
items.push(new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { ...LINE.TITLE, after: 0 },
children: [new TextRun({ text: title, font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true })],
}));
if (subtitle) {
items.push(new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { ...LINE.TITLE, after: 120 },
children: [new TextRun({ text: subtitle, font: FONT.HEITI, size: SIZE.SAN_HAO })],
}));
}
items.push(new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { ...LINE.BODY, after: 0 },
children: [new TextRun({ text: date, font: FONT.FANGSONG, size: SIZE.SI_HAO })],
}));
if (institution) {
items.push(new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { ...LINE.BODY, after: 240 },
children: [new TextRun({ text: institution, font: FONT.FANGSONG, size: SIZE.SI_HAO })],
}));
}
return items;
}
/** 一级标题 */
function h1(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_1,
spacing: { ...LINE.HEADING1, before: 240, after: 120 },
children: [new TextRun({ text, font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true })],
});
}
/** 二级标题 */
function h2(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_2,
spacing: { ...LINE.HEADING2, before: 120, after: 60 },
children: [new TextRun({ text, font: FONT.KAITI, size: SIZE.SI_HAO, bold: true })],
});
}
/** 正文段落 */
function body(text, opts = {}) {
const { bold = false, align = AlignmentType.JUSTIFIED, indent = true } = opts;
return new Paragraph({
alignment: align,
indent: indent ? { firstLine: INDENT.FIRST_LINE } : undefined,
spacing: LINE.BODY,
children: [new TextRun({ text, font: FONT.FANGSONG, size: SIZE.SI_HAO, bold })],
});
}
/** 多 run 正文段落(支持混排加粗) */
function bodyRuns(runs, opts = {}) {
const { align = AlignmentType.JUSTIFIED, indent = true } = opts;
return new Paragraph({
alignment: align,
indent: indent ? { firstLine: INDENT.FIRST_LINE } : undefined,
spacing: LINE.BODY,
children: runs.map(r => {
if (typeof r === "string") {
return new TextRun({ text: r, font: FONT.FANGSONG, size: SIZE.SI_HAO });
}
return new TextRun({ font: FONT.FANGSONG, size: SIZE.SI_HAO, ...r });
}),
});
}
/** 列表项 */
function bullet(text) {
return new Paragraph({
numbering: { reference: "bullets", level: 0 },
spacing: LINE.BODY,
children: [new TextRun({ text, font: FONT.FANGSONG, size: SIZE.SI_HAO })],
});
}
/** 三线表 */
function threeLineTable(headers, rows, opts = {}) {
const { colWidths } = opts;
const widths = colWidths || headers.map(() => Math.floor(PAGE.CONTENT_WIDTH / headers.length));
function cell(text, isHeader, isLastRow, colIdx) {
const borders = {
top: isHeader ? BORDER.THICK : BORDER.NONE,
bottom: isHeader ? BORDER.THIN : (isLastRow ? BORDER.THICK : BORDER.NONE),
left: BORDER.NONE,
right: BORDER.NONE,
};
return new TableCell({
borders,
width: { size: widths[colIdx], type: WidthType.DXA },
shading: isHeader ? { fill: "1F3864", type: ShadingType.CLEAR } : undefined,
margins: { top: 40, bottom: 40, left: 80, right: 80 },
children: [new Paragraph({
alignment: AlignmentType.CENTER,
spacing: LINE.TABLE,
children: [new TextRun({
text: String(text),
font: isHeader ? FONT.HEITI : FONT.FANGSONG,
size: SIZE.XIAO_SI,
bold: isHeader,
color: isHeader ? "FFFFFF" : undefined,
})],
})],
});
}
// 表级边框全部 NONE由 cell 级别控制三线效果
const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
return new Table({
width: { size: PAGE.CONTENT_WIDTH, type: WidthType.DXA },
columnWidths: widths,
borders: {
top: noBorder, bottom: noBorder,
left: noBorder, right: noBorder,
insideHorizontal: noBorder, insideVertical: noBorder,
},
rows: [
new TableRow({ children: headers.map((h, i) => cell(h, true, false, i)) }),
...rows.map((row, ri) =>
new TableRow({
children: row.map((c, ci) => cell(c, false, ri === rows.length - 1, ci)),
})
),
],
});
}
/** 标准页脚(— 页码 —) */
function pageFooter() {
return new Footer({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun({ text: "— ", font: FONT.FANGSONG, size: SIZE.WU_HAO }),
new TextRun({ children: [PageNumber.CURRENT], font: FONT.FANGSONG, size: SIZE.WU_HAO }),
new TextRun({ text: " —", font: FONT.FANGSONG, size: SIZE.WU_HAO }),
],
})],
});
}
/** 标准页眉 */
function pageHeader(text = "内部资料 注意保密") {
return new Header({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({
text, font: FONT.FANGSONG, size: SIZE.WU_HAO, color: "808080",
})],
})],
});
}
/** section 属性(页面设置) */
function sectionProps(opts = {}) {
return {
page: {
size: { width: PAGE.WIDTH, height: PAGE.HEIGHT },
margin: {
top: PAGE.MARGIN_TOP, bottom: PAGE.MARGIN_BOTTOM,
left: PAGE.MARGIN_LEFT, right: PAGE.MARGIN_RIGHT,
},
},
...opts,
};
}
module.exports = {
PAGE, FONT, SIZE, LINE, INDENT, BORDER,
getStyles, getNumbering, sectionProps,
titleBlock, h1, h2, body, bodyRuns, bullet,
threeLineTable, pageFooter, pageHeader,
};