skills/docx-cn/SKILL.md
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

490 lines
15 KiB
Markdown
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.

---
name: docx-cn
description: "基于 docx-js (Node.js) 创建和编辑符合 GB/T 9704-2012 中国公文格式标准的 Word 文档。当用户需要生成公文、研究报告、内部文件等中文 Word 文档时使用。触发词公文、Word、docx、报告排版、格式规范、GB/T 9704。"
---
# 中文公文 Word 文档生成docx-js
## 概述
基于官方 docx skill 微调,专为中文公文 / 金融研究报告场景优化。
使用 **docx-js**Node.js生成文档配合官方 skill 的 unpack/pack/validate 工具链编辑现有文档。
## 核心工具链
| 任务 | 方法 |
|------|------|
| **新建文档** | `docx-js` — 本文件中的模板 |
| **编辑现有文档** | unpack XML → 编辑 → repack见「编辑现有文档」节 |
| **验证** | `python .claude/skills/docx/scripts/office/validate.py output.docx` |
| **读取内容** | `pandoc document.docx -o output.md` |
---
## GB/T 9704-2012 公文格式常量
### 单位换算速查
```
1 inch = 1440 DXA = 72 pt = 25.4 mm
1 mm = 56.693 DXA
1 pt = 20 DXAspacing/行距用)
font size 单位 = half-point半磅如 14pt = 28
```
### 页面设置A4
```javascript
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, // 210mm - 28mm - 26mm
};
```
### 字号对照表
| 中文字号 | pt | half-point (docx-js size) | 用途 |
|----------|-----|---------------------------|------|
| 二号 | 22 | 44 | 大标题 |
| 三号 | 16 | 32 | 一级标题 |
| 四号 | 14 | 28 | 正文 / 二级标题 |
| 小四 | 12 | 24 | 表格内容 |
| 五号 | 10.5 | 21 | 页脚、注释 |
### 字体规范
```javascript
// 中文字体必须同时设置 eastAsia否则 Word 渲染时可能回退到宋体
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" }, // 备用
};
```
### 行距与段落
```javascript
const SPACING = {
// 行距twips = pt × 20lineRule: "exact" → 固定值
BODY: { line: 560, lineRule: "exact" }, // 28pt 固定行距
HEADING1: { line: 640, lineRule: "exact" }, // 32pt
HEADING2: { line: 560, lineRule: "exact" }, // 28pt
TABLE: { line: 440, lineRule: "exact" }, // 22pt
// 段前段后twips
H1_BEFORE: 240, H1_AFTER: 120, // 12pt / 6pt
H2_BEFORE: 120, H2_AFTER: 60, // 6pt / 3pt
};
const INDENT = {
FIRST_LINE: 560, // 首行缩进 2 字符 ≈ 28pt = 560 DXA
};
```
---
## 创建新文档
### 安装
```bash
npm install docx # 项目内安装即可,无需全局
```
### 完整模板:公文报告(无封面)
```javascript
const fs = require("fs");
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType,
ShadingType, PageNumber, PageBreak, LevelFormat, TabStopType, TabStopPosition,
} = require("docx");
// ─── GB/T 9704-2012 格式常量 ─────────────────────────────
const PAGE = {
WIDTH: 11906, HEIGHT: 16838,
MARGIN_TOP: 2098, MARGIN_BOTTOM: 1985,
MARGIN_LEFT: 1588, MARGIN_RIGHT: 1474,
CONTENT_WIDTH: 8844,
};
const FONT = {
HEITI: { ascii: "SimHei", eastAsia: "黑体", hAnsi: "SimHei" },
FANGSONG: { ascii: "FangSong", eastAsia: "仿宋", hAnsi: "FangSong" },
KAITI: { ascii: "KaiTi", eastAsia: "楷体", hAnsi: "KaiTi" },
};
// ─── 样式定义 ─────────────────────────────────────────────
const styles = {
default: {
document: {
run: { font: FONT.FANGSONG, size: 28 }, // 默认:仿宋四号
paragraph: {
spacing: { line: 560, lineRule: "exact" },
},
},
},
paragraphStyles: [
{
id: "Heading1", name: "Heading 1",
basedOn: "Normal", next: "Normal", quickFormat: true,
run: { font: FONT.HEITI, size: 32, bold: true }, // 黑体三号
paragraph: {
spacing: { line: 640, lineRule: "exact", before: 240, after: 120 },
outlineLevel: 0,
},
},
{
id: "Heading2", name: "Heading 2",
basedOn: "Normal", next: "Normal", quickFormat: true,
run: { font: FONT.KAITI, size: 28, bold: true }, // 楷体四号加粗
paragraph: {
spacing: { line: 560, lineRule: "exact", before: 120, after: 60 },
outlineLevel: 1,
},
},
],
};
// ─── 列表定义 ─────────────────────────────────────────────
const numbering = {
config: [
{
reference: "bullets",
levels: [{
level: 0, format: LevelFormat.BULLET, text: "\u2022",
alignment: AlignmentType.LEFT,
style: {
run: { font: FONT.FANGSONG, size: 28 },
paragraph: { indent: { left: 1120, hanging: 560 } }, // 缩进 2 字符 + 悬挂
},
}],
},
],
};
// ─── 辅助函数 ─────────────────────────────────────────────
/** 创建正文段落(仿宋四号,首行缩进 2 字符) */
function bodyParagraph(text, options = {}) {
const { bold = false, alignment = AlignmentType.JUSTIFIED } = options;
return new Paragraph({
alignment,
indent: { firstLine: 560 },
spacing: { line: 560, lineRule: "exact" },
children: [new TextRun({ text, font: FONT.FANGSONG, size: 28, bold })],
});
}
/** 创建一级标题(黑体三号) */
function heading1(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_1,
children: [new TextRun({ text, font: FONT.HEITI, size: 32, bold: true })],
});
}
/** 创建二级标题(楷体四号加粗) */
function heading2(text) {
return new Paragraph({
heading: HeadingLevel.HEADING_2,
children: [new TextRun({ text, font: FONT.KAITI, size: 28, bold: true })],
});
}
/** 创建三线表 */
function threeLineTable(headers, rows) {
const noBorder = { style: BorderStyle.NONE, size: 0 };
const thickBorder = { style: BorderStyle.SINGLE, size: 12, color: "000000" }; // 1.5pt
const thinBorder = { style: BorderStyle.SINGLE, size: 6, color: "000000" }; // 0.75pt
// 表头行边框:顶粗 + 底细
const headerBorders = {
top: thickBorder, bottom: thinBorder,
left: noBorder, right: noBorder,
};
// 数据行边框:无顶底左右(靠 insideH 提供行间线)
const dataBorders = {
top: noBorder, bottom: noBorder,
left: noBorder, right: noBorder,
};
// 最后一行底部:粗线
const lastRowBorders = {
top: noBorder, bottom: thickBorder,
left: noBorder, right: noBorder,
};
const colWidths = headers.map(() => Math.floor(PAGE.CONTENT_WIDTH / headers.length));
function makeCell(text, isHeader, borders) {
return new TableCell({
borders,
width: { size: colWidths[0], type: WidthType.DXA },
shading: isHeader
? { fill: "F2F2F2", type: ShadingType.CLEAR }
: undefined,
margins: { top: 40, bottom: 40, left: 80, right: 80 },
children: [new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { line: 440, lineRule: "exact" },
children: [new TextRun({
text,
font: isHeader ? FONT.HEITI : FONT.FANGSONG,
size: 24, // 小四 12pt
bold: isHeader,
})],
})],
});
}
const tableRows = [
// 表头
new TableRow({
children: headers.map(h => makeCell(h, true, headerBorders)),
}),
// 数据行
...rows.map((row, rowIdx) =>
new TableRow({
children: row.map(cell =>
makeCell(cell, false, rowIdx === rows.length - 1 ? lastRowBorders : dataBorders)
),
})
),
];
return new Table({
width: { size: PAGE.CONTENT_WIDTH, type: WidthType.DXA },
columnWidths: colWidths,
rows: tableRows,
});
}
/** 报告标题区(居中,无封面) */
function titleBlock(title, subtitle, date, institution) {
return [
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { line: 640, lineRule: "exact", after: 0 },
children: [new TextRun({ text: title, font: FONT.HEITI, size: 32, bold: true })],
}),
subtitle ? new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { line: 640, lineRule: "exact", after: 120 },
children: [new TextRun({ text: subtitle, font: FONT.HEITI, size: 32 })],
}) : null,
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { line: 560, lineRule: "exact", after: 0 },
children: [new TextRun({ text: date, font: FONT.FANGSONG, size: 28 })],
}),
institution ? new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { line: 560, lineRule: "exact", after: 240 },
children: [new TextRun({ text: institution, font: FONT.FANGSONG, size: 28 })],
}) : null,
].filter(Boolean);
}
// ─── 使用示例:构建文档 ──────────────────────────────────
const doc = new Document({
styles,
numbering,
sections: [{
properties: {
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,
},
},
},
headers: {
default: new Header({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({
text: "内部资料 注意保密",
font: FONT.FANGSONG, size: 21, color: "808080",
})],
})],
}),
},
footers: {
default: new Footer({
children: [new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun({ text: "— ", font: FONT.FANGSONG, size: 21 }),
new TextRun({ children: [PageNumber.CURRENT], font: FONT.FANGSONG, size: 21 }),
new TextRun({ text: " —", font: FONT.FANGSONG, size: 21 }),
],
})],
}),
},
children: [
// 标题区
...titleBlock(
"zn04鲁肆号年金组合",
"权益投资分析与策略展望报告",
"估值日2026年3月10日",
"工银瑞信基金管理有限公司"
),
// 正文
heading1("一、投资策略与研判框架"),
bodyParagraph("本组合采用"多维度全局配置"策略横跨A股和港股市场..."),
heading2("1.1 八大核心研判及验证"),
threeLineTable(
["#", "核心判断", "验证状态", "关键证据"],
[
["1", "恒生科技有超额收益", "1月验证后逆转", "1月+4.2%→3月-12.45%"],
["2", "AI国内参与性价比不高", "已验证", "A股AI概念高位回落"],
]
),
heading1("二、组合现状概览"),
bodyParagraph("截至估值日组合单位净值1.4430权益仓位合计占比约23%。"),
],
}],
});
// 导出
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync("output.docx", buffer);
console.log("✅ 已生成: output.docx");
});
```
### 运行
```bash
node generate_report.js
# 验证(可选,使用官方 docx skill 的验证工具)
python .claude/skills/docx/scripts/office/validate.py output.docx
```
---
## 辅助函数速查
| 函数 | 用途 | 格式 |
|------|------|------|
| `titleBlock(title, subtitle, date, institution)` | 报告标题区(无封面) | 黑体三号居中 |
| `heading1(text)` | 一级标题 | 黑体三号 16pt |
| `heading2(text)` | 二级标题 | 楷体四号加粗 |
| `bodyParagraph(text, {bold, alignment})` | 正文段落 | 仿宋四号首行缩进28pt行距 |
| `threeLineTable(headers, rows)` | 三线表 | 顶底1.5pt内部0.75pt,无竖线 |
---
## 编辑现有文档
当需要修改已有 .docx 文件时,使用官方 docx skill 的 unpack/pack 工作流:
```bash
# 1. 解包
python .claude/skills/docx/scripts/office/unpack.py document.docx unpacked/
# 2. 编辑 unpacked/word/document.xml直接用 Edit 工具修改 XML
# 3. 重新打包
python .claude/skills/docx/scripts/office/pack.py unpacked/ output.docx --original document.docx
```
### 公文格式关键 XML 片段
#### 页面设置(插入 `<w:sectPr>` 中)
```xml
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="2098" w:right="1474" w:bottom="1985" w:left="1588"
w:header="851" w:footer="851" w:gutter="0"/>
```
#### 正文段落格式
```xml
<w:pPr>
<w:spacing w:line="560" w:lineRule="exact"/>
<w:ind w:firstLine="560"/>
<w:jc w:val="both"/>
</w:pPr>
<w:rPr>
<w:rFonts w:ascii="FangSong" w:eastAsia="仿宋" w:hAnsi="FangSong"/>
<w:sz w:val="28"/>
<w:szCs w:val="28"/>
</w:rPr>
```
#### 一级标题
```xml
<w:pPr>
<w:pStyle w:val="Heading1"/>
<w:spacing w:line="640" w:lineRule="exact" w:before="240" w:after="120"/>
</w:pPr>
<w:rPr>
<w:rFonts w:ascii="SimHei" w:eastAsia="黑体" w:hAnsi="SimHei"/>
<w:b/>
<w:sz w:val="32"/>
<w:szCs w:val="32"/>
</w:rPr>
```
#### 三线表边框(`<w:tblBorders>` 内)
```xml
<w:top w:val="single" w:sz="12" w:space="0" w:color="000000"/>
<w:bottom w:val="single" w:sz="12" w:space="0" w:color="000000"/>
<w:insideH w:val="single" w:sz="6" w:space="0" w:color="000000"/>
<w:left w:val="none" w:sz="0" w:space="0" w:color="auto"/>
<w:right w:val="none" w:sz="0" w:space="0" w:color="auto"/>
<w:insideV w:val="none" w:sz="0" w:space="0" w:color="auto"/>
```
---
## 从现有文档提取内容并重建
当需要对已有文档「重排版」时,推荐提取内容后用 docx-js 重建:
```bash
# 提取为 Markdown
pandoc original.docx -o content.md
# 然后读取 content.md用上面的模板函数构建新文档
```
这比原地修改格式更可靠,避免了样式冲突和继承问题。
---
## 格式检查清单
- [ ] 纸张A411906 × 16838 DXA
- [ ] 页边距上37 / 下35 / 左28 / 右26 mm
- [ ] 一级标题黑体三号16pt固定行距 32pt
- [ ] 二级标题楷体四号加粗14pt固定行距 28pt
- [ ] 正文仿宋四号14pt固定行距 28pt首行缩进 2 字符
- [ ] 表格:三线表,表头黑体小四 + 浅灰底,内容仿宋小四
- [ ] 页脚:居中 "— 页码 —",仿宋五号
- [ ] 字体必须设置 `eastAsia` 属性
## 依赖
- **Node.js**: v18+
- **docx**: `npm install docx`docx-js 库)
- **pandoc**: 文本提取(可选)
- **官方 docx skill**: 提供 validate.py / unpack.py / pack.py