docs: add mobile OA print-to-PDF download design for WeChat

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-13 10:47:54 +08:00
1 parent 828ada6ac3
commit 433eb5d113
1 file changed
+100
@@ -0,0 +1,100 @@
# 移动端 OA「打印」改为下载 PDF(微信预览)
> 日期:2026-08-13
> 范围:`mobile-oa-h5`(打印导出)+ `mobile-h5`(微信宿主文档预览)
> 状态:已确认
> 关联:`docs/superpowers/specs/2026-07-15-oa-approval-print-pdf-design.md`(web 端 PDF 权威版式)
## 1. 目标
将移动端 OA 详情「打印」与列表长按「打印」(`autoPrint=1`)从当前的 `window.print()`(微信 web-view 内基本不可用)改为与 **web-admin 一致**:前端用钉钉风格模板生成 PDF,并在微信内打开**系统文档预览**(可转发 /「用其他应用打开」保存)。
主运行环境:微信小程序内 `mobile-h5` → `web-view` → `mobile-oa-h5`。
## 2. 非目标
- 不新增后端 PDF 渲染引擎(本期仍前端生成)
- 不改 web-admin 打印实现
- 关联审批嵌套块本期仍可用「已关联 N 条」摘要(不对齐 web 完整嵌套打印树);若需对齐另开变更
- 不导出附件二进制;附件行仍展示 URL / 文件名文本(与 web 一致)
## 3. 方案选型
采用 **前端 html2canvas + jspdf → 上传附件存储 → 宿主 `openDocument` 预览**:
| 步骤 | 负责端 | 说明 |
|------|--------|------|
| 1 | `mobile-oa-h5` | 组装 print model,离屏渲染打印 DOM |
| 2 | `mobile-oa-h5` | `html2canvas` + `jspdf` 生成 PDF Blob(算法对齐 web `oa-approval-print.ts`) |
| 3 | `mobile-oa-h5` | `uploadAttachment` → MinIO(现有 `/web/admin/attachment/upload`,`folder=oa-approval`) |
| 4 | `mobile-oa-h5` | `wx.miniProgram.navigateTo` 打开宿主预览页(带文件 URL + 文件名) |
| 5 | `mobile-h5` | `uni.downloadFile` → `uni.openDocument({ showMenu: true })` |
不采用:纯 `pdf.save()` / `a[download]`(微信不可靠);后端生成 PDF(版式双端维护成本高)。
微信外(普通手机浏览器 / H5 iframe):可回退为 `jspdf` 的 `save()` 直接下载,无需跳转宿主。
## 4. 交互
| 入口 | 行为 |
|------|------|
| 详情底栏「打印」 | loading → 生成 → 上传 → 跳转预览;失败 toast,留在详情 |
| 列表长按「打印」→ `autoPrint=1` | 详情加载完成后自动走同一导出链路 |
按钮:导出过程中 `printing` loading,防重复点击。
文件名(与 web 一致):`{发起人姓名}提交的{流程名称}.pdf`;缺省用「用户」/「审批单」;非法路径字符替换为 `_`。
预览页:打开后自动下载并调起系统预览;失败 toast。**预览调起成功后自动 `navigateBack`** 回详情 web-view,避免预览页在导航栈堆积;用户从系统预览返回后仍在详情。
## 5. PDF 版式(对齐 web)
权威:web `OaApprovalPrintSheet` + `oa-approval-print.ts` / `2026-07-15-oa-approval-print-pdf-design.md`。
结构自上而下:
1. 标题(`appName` 优先)
2. 元信息:公司名固定 `安徽中科兴皖医学研究有限公司` + `创建时间:YYYY-MM-DD`
3. 主表(标签 | 值):审批编号、创建人、创建人部门 + 表单字段 + 审批流程行
4. 右上角钉钉风印章(状态映射与 web / `resolveStamp` 一致)
5. 页脚:打印时间、打印人
6. 水印:打印人姓名斜向淡色铺底
7. 页码:`第 N 页`(canvas 绘制中文,避免 jsPDF 内置字体乱码)
纸张:A4 竖向;切片与略超一页容差对齐 web(`EPS_MM ≈ 1.5`)。
实现方式:可继续用现有 `buildPrintHtml` 字符串模板渲染到离屏 iframe/div,再 `html2canvas`;CSS/印章 DOM 须向 web 打印页收敛,避免与详情页 72px 印章混用两套视觉。
## 6. 微信通信约束
- `wx.miniProgram.postMessage` **不会立即送达**宿主(多在后退/销毁时触发),**不能**靠 postMessage 传 PDF。
- 大文件不能塞进 `navigateTo` query;必须先上传,query 只传 **HTTPS 文件 URL + 文件名**。
- 预签名:优先 `fetchAttachmentDownloadUrl` 得到带 `Content-Disposition` 的地址再下载;失败则回退直连上传返回的 `url`。
## 7. 主要改动文件
| 路径 | 职责 |
|------|------|
| `mobile-oa-h5/package.json` | 增加依赖 `html2canvas`、`jspdf` |
| `mobile-oa-h5/src/oa/print/exportOaApprovalPdf.js` | 改为 canvas→PDF;微信上传+跳转;浏览器 `save` 回退 |
| `mobile-oa-h5/src/views/OaDetail.vue` | 打印成功/失败文案对齐「导出 PDF」;去掉「系统打印不可用」类提示 |
| `mobile-oa-h5/src/api/oa.js` | 复用已有 `uploadAttachment` / `fetchAttachmentDownloadUrl` |
| `mobile-h5/pages/oa/pdf-preview/index.vue` | 新建:download + openDocument |
| `mobile-h5/pages.json` | 注册 `pages/oa/pdf-preview/index` |
## 8. 错误处理
| 场景 | 表现 |
|------|------|
| 无详情 / 生成失败 | toast,不跳转 |
| 上传失败 | toast,不跳转 |
| 非微信且无 `save` 能力 | toast |
| 宿主 download / openDocument 失败 | 预览页 toast |
## 9. 验收
1. 微信小程序:详情点「打印」→ 出现系统 PDF 预览,可转发 / 用其他应用打开。
2. 列表长按「打印」:进入详情后自动导出并预览。
3. PDF 视觉与 web「打印」导出大体一致(标题、表、印章、水印、页脚、页码)。
4. 普通浏览器打开 `mobile-oa-h5`:点打印直接下载 PDF 文件。
5. 导出失败时详情页不关闭,可重试。