docs: add design for contract print dialog Word export

Capture the agreed frontend HTML-to-DOCX approach for CRM contract print dialog.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-09-05 14:30:40 +08:00
1 parent f43ef91d70
commit 32f51274eb
1 file changed
+112
@@ -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 的 <img>(不用 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 中微调
- 上述局限符合「下载后修改再发给客户」的用途,不作为阻塞项