diff --git a/docs/superpowers/specs/2026-09-05-crm-contract-generate-word-design.md b/docs/superpowers/specs/2026-09-05-crm-contract-generate-word-design.md new file mode 100644 index 000000000..84eba8925 --- /dev/null +++ b/docs/superpowers/specs/2026-09-05-crm-contract-generate-word-design.md @@ -0,0 +1,112 @@ +# 合同管理:打印弹窗「生成 Word」设计 + +日期:2026-09-05 +范围:`web-admin` 合同管理打印弹窗(`/#/crm/contract` 及相关详情入口) +状态:已评审(方案 1 前端 HTML→DOCX,用户确认继续) + +## 1. 背景与目标 + +合同管理打印弹窗已支持富文本预览/编辑、打印与「生成 PDF」。业务希望增加「生成 Word」,下载可编辑的 `.docx`,方便改完后再发给客户。 + +目标: + +- 与当前打印预览内容同源(占位符已替换) +- 正文、表格可在 Word 中继续编辑 +- 红章跟随弹窗「显示/隐藏红章」开关 +- 水印 / Logo 规则与现有「生成 PDF」一致 + +## 2. 采用方案 + +**方案 1**:前端将打印弹窗当前 HTML 转为 DOCX 并下载。 + +库选型:`@turbodocx/html-to-docx`(浏览器可用,表格/图片支持相对成熟),下载沿用已有 `file-saver`。 + +不采用: + +- 方案 2(后端 Pandoc / LibreOffice 转换)——需新接口与部署依赖;合同导出现为纯前端,本期成本过高 +- 方案 3(将 PDF 截图嵌入 Word)——几乎不可编辑,与「改完再发给客户」冲突 + +## 3. 入口与交互 + +### 3.1 位置 + +合同管理打印弹窗底栏,「生成 PDF」旁增加「生成 Word」。 + +需同步两处入口: + +- `web-admin/src/views/crm/contract/components/ContractDetailDialog.vue` +- `web-admin/src/views/crm/contract/detail.vue` + +按钮须带前置 `el-icon`(与现有打印 / PDF 一致,例如 Document 类图标)。 + +### 3.2 行为 + +1. 点击「生成 Word」→ loading(独立 `wordGenerating`,不与 PDF loading 互相覆盖) +2. 成功 → 下载 `.docx` +3. 文件名:与 PDF 同规则——`{合同名称或合同编号}合同.docx`,非法文件名字符替换为 `-` +4. 失败 → 提示「生成 Word 失败,请重试」,不关闭打印弹窗 +5. 不影响既有「打印」「生成 PDF」行为 + +## 4. 导出链路 + +``` +打印弹窗当前 HTML(contractContent) + → 按需刷新占位符(与 PDF 同源:getContractDetail + replacePlaceholders) + → 红章:直接使用弹窗当前 HTML(开=已含印章图;关=已 strip) + → 水印 / Logo:按合同号供方编码规则(与 PDF 一致) + → 预处理:相对图片路径转绝对 URL;SX 水印改为可进 Word 的 (不用 CSS background) + → @turbodocx/html-to-docx → Blob → file-saver 下载 +``` + +无后端接口变更。 + +## 5. 红章 / 水印 / Logo 约定 + +### 5.1 红章 + +- 与弹窗开关一致:显示则导出含印章图;隐藏则不含 +- 导出前将印章等图片的相对 `src` 转为绝对 URL,尽量保留宽高 +- 已知局限:Word 对 `position: absolute` 支持弱,印章可能不完全叠在签字区正中,允许用户在 Word 中微调 + +### 5.2 水印与 Logo(对齐 PDF) + +- 从合同编号解析供方编码(`^([A-Z]+)/X-JT`);解析不到默认 `SX` +- 供方为 `SX`:导出前在文档内容区插入半透明水印图(`/watermask.jpg` 绝对 URL,居中、约半宽、低透明度,尽量贴近 PDF 观感);不依赖 CSS `background-image` / `::before` +- 非 `SX`:去掉 Logo(与 PDF 一致的匹配规则),不加水印 + +## 6. 改动范围 + +| 文件 / 依赖 | 变更 | +|---|---| +| `web-admin/package.json` | 增加 `@turbodocx/html-to-docx` | +| `web-admin/src/utils/crm/contract-html-to-docx.ts`(新建) | 组装导出 HTML(水印/Logo 预处理、绝对 URL)并调用库生成 Blob | +| `ContractDetailDialog.vue` | 底栏按钮 + `handleGenerateWordFromDialog` | +| `detail.vue` | 底栏按钮 + 对应 handler(复用工具函数) | + +后端:不改。报价单、调价函、运输单据等其它打印弹窗:本期不做。 + +## 7. 非目标 + +- 不追求与打印预览像素级一致 +- 不做服务端 Word 生成或落库 +- 不改合同模板存库结构 +- 不扩展到报价单等其它模块 +- 不把 Word 生成做成截图式不可编辑文档 + +## 8. 验收 + +| 场景 | 期望 | +|---|---| +| 按钮入口 | 合同打印弹窗底栏有「生成 Word」,与「生成 PDF」同级;两处入口均有 | +| 下载 | 可下载可编辑 `.docx`;正文/表格可改 | +| 红章开 | 导出 Word 含印章图 | +| 红章关 | 导出 Word 不含印章图 | +| SX 合同 | 含水印;保留 Logo 规则与 PDF 一致 | +| 非 SX 合同 | 无水印;Logo 已去除 | +| 失败 | 有错误提示;弹窗仍可继续打印 / 生成 PDF | +| 回归 | 既有打印、生成 PDF 行为不变 | + +## 9. 已知局限(可接受) + +- 印章叠放位置、水印跨页表现、复杂表格宽度可能需在 Word 中微调 +- 上述局限符合「下载后修改再发给客户」的用途,不作为阻塞项