---
name: Universal Document Print
overview: 设计并实现跨项目的通用单据打印框架,覆盖 erp-frontend-vue (Vue 3) 和 mom-backend-ui (Vue 2) 两个前端项目中所有单据类型的打印需求,采用配置驱动方式,一套设计思路适配全部单据。
todos:
- id: install-deps-vue3
content: "erp-frontend-vue: 安装 qrcode + @types/qrcode"
status: completed
- id: install-deps-vue2
content: "mom-backend-ui: 安装 qrcode(已有 vue-plugin-hiprint 用于标签,文档打印需另行处理)"
status: pending
- id: print-types
content: 创建 PrintConfig 类型/接口定义(两项目各一份,结构一致)
status: completed
- id: qrcode-vue3
content: "erp-frontend-vue: 创建 src/components/print/QrCode.vue"
status: completed
- id: print-dialog-vue3
content: "erp-frontend-vue: 创建 src/components/print/PrintDialog.vue(含 @media print 样式)"
status: completed
- id: qrcode-vue2
content: "mom-backend-ui: 创建 src/components/PrintDoc/QrCode.vue(Vue 2 版)"
status: pending
- id: print-dialog-vue2
content: "mom-backend-ui: 创建 src/components/PrintDoc/PrintDialog.vue(Vue 2 版,含 @media print 样式)"
status: pending
- id: task-api
content: "erp-frontend-vue: 在 workOrder.ts 中添加 ProTask 类型和 getTaskListByWorkorder API"
status: completed
- id: integrate-workorder-vue3
content: "erp-frontend-vue: 生产工单 form.vue 集成打印"
status: completed
- id: integrate-sales-vue3
content: "erp-frontend-vue: 销售订单 form.vue 集成打印"
status: completed
- id: integrate-purchase-vue3
content: "erp-frontend-vue: 采购订单 form.vue 集成打印"
status: completed
- id: integrate-issue-vue3
content: "erp-frontend-vue: 生产领料单 form.vue 集成打印"
status: completed
- id: integrate-arrival-vue2
content: "mom-backend-ui: 到货通知单 index.vue 集成打印"
status: pending
- id: integrate-itemrecpt-vue2
content: "mom-backend-ui: 物料入库单 index.vue 集成打印"
status: pending
- id: integrate-productsales-vue2
content: "mom-backend-ui: 销售出库单 index.vue 集成打印"
status: pending
- id: integrate-remaining-vue2
content: "mom-backend-ui: 其余仓库单据(退货/转移/杂项等)逐步集成打印"
status: pending
isProject: false
---
# 通用单据打印框架(跨项目)
## 现状分析
### erp-frontend-vue(Vue 3 + Element Plus)
- `handlePrint()` 要么仅调 `window.print()`(生产工单、采购订单),要么是占位符(销售订单等)
- 无 `@media print` 样式、无 QR 码库、无打印组件
- 包含单据:销售订单、采购订单、生产工单、生产领料单、采购到货单(表单未完成)
### mom-backend-ui(Vue 2 + Element UI)
- 已有 `vue-plugin-hiprint` 用于**条码标签**打印(物料/仓库/工位标签),但**无单据格式打印**
- `handleHiPrint` 仅在 detail 页做标签打印,不是单据表单打印
- 包含大量仓库单据模块:到货通知、入库单(4种)、领料单(3种)、出库单(2种)、退货单(3种)、转移单、装箱单、备料通知等
### 两项目共同点
所有单据结构高度一致:**表头字段** + **明细行列表**,适合用统一的配置驱动方案。
## 架构设计
### 核心思路:配置驱动 + 双项目适配
```mermaid
graph TB
subgraph config ["PrintConfig 配置接口(结构一致)"]
fields["headerFields: 表头字段数组"]
cols["columns: 明细列定义"]
data["data: 明细行数据"]
meta["title / qrCode / footer"]
end
subgraph vue3 ["erp-frontend-vue (Vue 3)"]
pd3["PrintDialog.vue"]
qr3["QrCode.vue"]
pages3["各单据 form.vue"]
end
subgraph vue2 ["mom-backend-ui (Vue 2)"]
pd2["PrintDialog.vue"]
qr2["QrCode.vue"]
pages2["各单据 index.vue"]
end
pages3 -->|"构建 config"| pd3
pages2 -->|"构建 config"| pd2
pd3 --> qr3
pd2 --> qr2
config -.->|"同一结构"| pd3
config -.->|"同一结构"| pd2
```
### PrintConfig 接口定义
两个项目各自维护一份(Vue 3 用 TypeScript,Vue 2 用 JSDoc),结构完全一致:
```typescript
/** 表头字段 */
interface PrintHeaderField {
label: string // "单据编码"
value: string | number // "SCDD000001"
span?: number // 占列数,默认 1(共 4 列一行)
}
/** 明细表列 */
interface PrintColumn {
prop: string // 数据字段名
label: string // 列标题
width?: string // 列宽
align?: 'left' | 'center' | 'right'
type?: 'text' | 'index' | 'qrcode' | 'amount'
qrCodeProp?: string // type=qrcode 时的编码内容字段
formatter?: (row: any, index: number) => string
}
/** 合计行 */
interface PrintSummary {
label: string
value: string | number
}
/** 完整打印配置 */
interface PrintConfig {
systemName?: string // 默认 "升阳云ERP"
title: string // "销售订单" | "到货通知单" | ...
subtitle?: string // "加工车间" 等
qrCodeValue?: string // 右上角二维码内容
headerFields: PrintHeaderField[] // 4 列网格,自动换行
columns: PrintColumn[] // 明细表列
data: any[] // 明细表数据
summaries?: PrintSummary[] // 合计行(可选)
footer: {
creator?: string // 制单人
approver?: string // 审核人
}
}
```
### 打印页面统一布局
```
+------------------------------------------------------------------+
| 升阳云ERP [QR 码] |
| {title} - {subtitle} |
| |
| {label}: {value} {label}: {value} {label}: {value} {label}:|
| {label}: {value} {label}: {value} {label}: {value} {label}:|
| |
| +----+----------+----------+------+------+----------+------+ |
| | 序号| 列1 | 列2 | 列3 | 列4 | 列5 | 列6 | |
| +----+----------+----------+------+------+----------+------+ |
| | 1 | ... | ... | ... | ... | [QR码] | ... | |
| +----+----------+----------+------+------+----------+------+ |
| |
| 制单人: xxx 审核人: xxx 打印日期: 2025-xx-xx |
+------------------------------------------------------------------+
```
## 实现步骤
### 第一步:依赖安装
**erp-frontend-vue:**
```bash
cd erp-frontend-vue && npm install qrcode && npm install -D @types/qrcode
```
**mom-backend-ui:**
```bash
cd mom-backend-ui && npm install qrcode
```
### 第二步:公共组件开发
#### Vue 3 版(erp-frontend-vue)
新建目录 `src/components/print/`,包含 3 个文件:
| 文件 | 说明 |
| --------------------------------------------------------------------------------------------- | -------------------------- |
| [src/components/print/types.ts](erp-frontend-vue/src/components/print/types.ts) | PrintConfig 等类型定义 |
| [src/components/print/QrCode.vue](erp-frontend-vue/src/components/print/QrCode.vue) | QR 码组件(Props: value, size) |
| [src/components/print/PrintDialog.vue](erp-frontend-vue/src/components/print/PrintDialog.vue) | 通用打印对话框 |
**QrCode.vue** — 使用 `qrcode.toDataURL()` 生成 base64 图片,渲染 `
` 标签。
**PrintDialog.vue** — 核心组件:
- Props: `v-model:visible`、`config: PrintConfig`
- `el-dialog`(fullscreen)包裹打印预览
- 对话框 header 有「打印」「关闭」按钮
- 打印内容区使用纯 HTML table + CSS Grid(不依赖 Element Plus),确保打印输出干净
- 组件内嵌 `@media print` 样式,隐藏对话框 header/footer,仅保留 `.print-content`
#### Vue 2 版(mom-backend-ui)
新建目录 `src/components/PrintDoc/`,包含 2 个文件:
| 文件 | 说明 |
| ------------------------------------------------------------------------------------------------- | --------------------------------------- |
| [src/components/PrintDoc/QrCode.vue](mom-backend-ui/src/components/PrintDoc/QrCode.vue) | QR 码组件(Vue 2 语法) |
| [src/components/PrintDoc/PrintDialog.vue](mom-backend-ui/src/components/PrintDoc/PrintDialog.vue) | 通用打印对话框(Vue 2 + Element UI `el-dialog`) |
两个版本的**布局 HTML 和 CSS 完全一致**,仅框架语法不同:
- Vue 3: `