x-print-designer 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +382 -307
- package/dist/Axis-B3MEVZ27.js +18214 -0
- package/dist/JsBarcode-DR3EuD60.js +3866 -0
- package/dist/browser-DXN-y76H.js +2153 -0
- package/dist/charts-BEFiaBSj.js +18428 -0
- package/dist/components-DLGmq9Hs.js +16442 -0
- package/dist/core-BH5GCqh2.js +233 -0
- package/dist/createSeriesData-C8TQkDhm.js +434 -0
- package/dist/customGraphicKeyframeAnimation-Co1OX5Xt.js +9429 -0
- package/dist/dom-to-image-more.min-S-TpuEqL.js +540 -0
- package/dist/graphic-BP8Wuks8.js +11299 -0
- package/dist/html2canvas.esm-DWZSdXKi.js +7795 -0
- package/dist/index-CcUJ-UmV.js +336 -0
- package/dist/index.es-698hP6_U.js +10445 -0
- package/dist/jspdf.es.min-CSbVoGg3.js +11560 -0
- package/dist/jszip.min-BKMA8ptO.js +2354 -0
- package/dist/print-designer.css +1 -0
- package/dist/print-designer.es.js +4 -0
- package/dist/print-designer.umd.js +380 -0
- package/dist/purify.es-CoISWr_W.js +1082 -0
- package/dist/renderers-YjB_OS7R.js +2387 -0
- package/dist/typeof-DxTVrAEz.js +11 -0
- package/dist/web-component-ZD0SqIW-.js +48430 -0
- package/dist/web-component.d.ts +102 -0
- package/package.json +1 -1
- package/dist/assets/Axis-r61YvV2N.js +0 -8
- package/dist/assets/JsBarcode-BOwNyIpk.js +0 -1
- package/dist/assets/barcode-BoWGE6Vo.js +0 -8
- package/dist/assets/browser-CR_q2Gy7.js +0 -1
- package/dist/assets/canvg-ChoTXRpY.js +0 -18
- package/dist/assets/charts-lpQQN2Ks.js +0 -1
- package/dist/assets/components-D_JDMQgr.js +0 -22
- package/dist/assets/core-BrVw2LCo.js +0 -1
- package/dist/assets/createSeriesData-BS3ONHiF.js +0 -1
- package/dist/assets/customGraphicKeyframeAnimation-CXbdssPk.js +0 -3
- package/dist/assets/dom-to-image-more.min-CWakCYDx.js +0 -1
- package/dist/assets/favicon-o5K9zUr2.ico +0 -0
- package/dist/assets/graphic-DgPervEb.js +0 -29
- package/dist/assets/html2canvas.esm-QH1iLAAe.js +0 -22
- package/dist/assets/index-JEGgaCHA.css +0 -1
- package/dist/assets/index-OtDSuAAX.js +0 -154
- package/dist/assets/jszip.min-DLPWIKb1.js +0 -12
- package/dist/assets/logo-DXm7qK2I.png +0 -0
- package/dist/assets/monaco-DvnI3chM.js +0 -11
- package/dist/assets/pdf-D4995UXf.js +0 -170
- package/dist/assets/purify.es-BaNf_EpD.js +0 -2
- package/dist/assets/renderers-BUy3EJql.js +0 -3
- package/dist/assets/utils-C6aID195.js +0 -1
- package/dist/assets/vendor-ClC5F-pT.js +0 -39
- package/dist/index.html +0 -19
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# X-Print-Designer
|
|
2
2
|
|
|
3
|
-
基于 Vue 3 + TypeScript 开发的打印设计器,支持可视化拖拽设计打印模板,集成 ECharts
|
|
3
|
+
基于 Vue 3 + TypeScript 开发的打印设计器,支持可视化拖拽设计打印模板,集成 ECharts 图表组件。
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,11 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
- [核心概念:模板模式 vs 报告模式](#核心概念模板模式-vs-报告模式)
|
|
10
10
|
- [快速开始](#快速开始)
|
|
11
|
+
- [Vue 组件使用说明](#vue-组件使用说明)
|
|
12
|
+
- [Web Component 使用说明](#web-component-使用说明)
|
|
11
13
|
- [传入数据格式](#传入数据格式)
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
14
|
+
- [保存回调 `onSave`](#保存回调-onsave)
|
|
15
|
+
- [自动保存配置](#自动保存配置)
|
|
16
|
+
- [模板数据结构(完整格式)](#模板数据结构完整格式)
|
|
17
|
+
- [元素数据绑定](#元素数据绑定)
|
|
15
18
|
- [变量语法参考](#变量语法参考)
|
|
19
|
+
- [支持的元素类型](#支持的元素类型)
|
|
16
20
|
- [技术栈](#技术栈)
|
|
17
21
|
|
|
18
22
|
---
|
|
@@ -21,103 +25,36 @@
|
|
|
21
25
|
|
|
22
26
|
设计器支持两种工作模式,通过 `mode` 属性/方法进行切换。
|
|
23
27
|
|
|
24
|
-
###
|
|
25
|
-
|
|
26
|
-
**适用场景:** 创建可复用的打印模板,模板与数据分离。先在设计器中画好布局,打印时再填入真实数据。
|
|
27
|
-
|
|
28
|
-
**保存行为:**
|
|
29
|
-
- 保存时**只保存页面布局信息**(元素位置、样式、画布大小、参考线等)
|
|
30
|
-
- **不保存**测试数据(`testData`)
|
|
28
|
+
### 模板模式(`template`)— 默认模式
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
1. 在设计器中拖拽元素,设计打印模板的布局
|
|
34
|
-
2. 使用变量语法(如 `{#orderNo}`)标记数据占位符
|
|
35
|
-
3. 保存模板,模板只包含布局结构
|
|
36
|
-
4. 业务系统调用打印/导出时,传入真实数据替换变量
|
|
30
|
+
**适用场景:** 创建可复用的打印模板,模板与数据分离。布局固定,数据在打印时动态注入。
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
- 保存时**只保存页面布局**(元素位置、样式、画布大小等)
|
|
33
|
+
- **不保存** `testData`(测试数据)
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
"pages": [ /* 页面和元素列表 */ ],
|
|
43
|
-
"canvasSize": { "width": 794, "height": 1123 },
|
|
44
|
-
"guides": [],
|
|
45
|
-
"zoom": 1,
|
|
46
|
-
"showGrid": true,
|
|
47
|
-
"headerHeight": 0,
|
|
48
|
-
"footerHeight": 0,
|
|
49
|
-
"watermark": { "enabled": false, "text": "", "angle": -30, "color": "#000000", "opacity": 0.1, "size": 24, "density": 160 },
|
|
50
|
-
"unit": "mm",
|
|
51
|
-
"pageSpacingX": 0,
|
|
52
|
-
"pageSpacingY": 0,
|
|
53
|
-
"canvasBackground": "#ffffff"
|
|
54
|
-
}
|
|
55
|
-
```
|
|
35
|
+
### 报告模式(`report`)
|
|
56
36
|
|
|
57
|
-
|
|
37
|
+
**适用场景:** 数据与布局绑定在一起的完整报告(如检测报告、统计报表)。
|
|
58
38
|
|
|
59
|
-
|
|
39
|
+
- 保存时**同时保存页面布局 + 测试数据**(`testData`)
|
|
60
40
|
|
|
61
|
-
|
|
62
|
-
- 保存时**同时保存页面布局信息和测试数据**(`testData`)
|
|
63
|
-
- `testData` 中包含当前设计器中填写/导入的测试数据
|
|
41
|
+
### 对比
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
43
|
+
| 特性 | `template` | `report` |
|
|
44
|
+
|------|-----------|----------|
|
|
45
|
+
| 保存布局 | ✅ | ✅ |
|
|
46
|
+
| 保存 testData | ❌ | ✅ |
|
|
47
|
+
| 典型用途 | 订单打印、标签 | 检测报告、报表 |
|
|
70
48
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
{
|
|
75
|
-
"pages": [ /* ... */ ],
|
|
76
|
-
"canvasSize": { "width": 794, "height": 1123 },
|
|
77
|
-
"watermark": { /* ... */ },
|
|
78
|
-
"testData": {
|
|
79
|
-
"orderNo": "A001",
|
|
80
|
-
"customerName": "张三",
|
|
81
|
-
"items": [
|
|
82
|
-
{ "name": "产品A", "price": 100, "quantity": 2 }
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 对比总结
|
|
89
|
-
|
|
90
|
-
| 特性 | 模板模式 (template) | 报告模式 (report) |
|
|
91
|
-
|------|-------------------|------------------|
|
|
92
|
-
| 保存布局 | ✅ 是 | ✅ 是 |
|
|
93
|
-
| 保存测试数据 (`testData`) | ❌ 否 | ✅ 是 |
|
|
94
|
-
| 适用场景 | 通用打印模板 | 数据+布局一体的报告 |
|
|
95
|
-
| 数据注入时机 | 打印/导出时传入 | 设计时即绑定 |
|
|
96
|
-
| 典型用途 | 订单打印、标签打印 | 检测报告、统计报表 |
|
|
97
|
-
|
|
98
|
-
### 如何切换模式
|
|
99
|
-
|
|
100
|
-
**Vue 组件方式:**
|
|
49
|
+
### 切换模式
|
|
101
50
|
|
|
102
51
|
```vue
|
|
103
|
-
<template
|
|
104
|
-
|
|
105
|
-
<PrintDesigner mode="template" />
|
|
106
|
-
|
|
107
|
-
<!-- 报告模式 -->
|
|
108
|
-
<PrintDesigner mode="report" />
|
|
109
|
-
</template>
|
|
52
|
+
<PrintDesigner mode="template" />
|
|
53
|
+
<PrintDesigner mode="report" />
|
|
110
54
|
```
|
|
111
55
|
|
|
112
|
-
**Web Component 方式:**
|
|
113
|
-
|
|
114
56
|
```js
|
|
115
|
-
const designer = document.querySelector('print-designer');
|
|
116
|
-
|
|
117
|
-
// 切换为模板模式(默认)
|
|
118
57
|
designer.setMode('template');
|
|
119
|
-
|
|
120
|
-
// 切换为报告模式
|
|
121
58
|
designer.setMode('report');
|
|
122
59
|
```
|
|
123
60
|
|
|
@@ -125,43 +62,100 @@ designer.setMode('report');
|
|
|
125
62
|
|
|
126
63
|
## 快速开始
|
|
127
64
|
|
|
128
|
-
### 安装
|
|
129
|
-
|
|
130
65
|
```bash
|
|
131
66
|
npm install
|
|
132
67
|
npm run dev
|
|
133
68
|
```
|
|
134
69
|
|
|
135
|
-
###
|
|
70
|
+
### 最简接入
|
|
136
71
|
|
|
137
72
|
```vue
|
|
138
73
|
<template>
|
|
139
74
|
<PrintDesigner
|
|
140
75
|
mode="template"
|
|
141
76
|
:sample-data="sampleData"
|
|
77
|
+
:on-save="handleSave"
|
|
142
78
|
/>
|
|
143
79
|
</template>
|
|
144
80
|
|
|
145
81
|
<script setup>
|
|
146
82
|
import { ref } from 'vue';
|
|
147
|
-
import PrintDesigner from '
|
|
83
|
+
import PrintDesigner from '@/components/PrintDesigner.vue';
|
|
148
84
|
|
|
149
85
|
const sampleData = ref({
|
|
150
86
|
id: 1,
|
|
151
87
|
name: '测试报告',
|
|
88
|
+
templateId: 'tpl_001',
|
|
152
89
|
variables: {
|
|
153
90
|
title: '报告标题',
|
|
154
91
|
customerName: '张三',
|
|
155
92
|
items: [
|
|
156
|
-
{ name: '产品A', price: 100, quantity: 2 }
|
|
157
|
-
{ name: '产品B', price: 200, quantity: 3 }
|
|
93
|
+
{ name: '产品A', price: 100, quantity: 2 }
|
|
158
94
|
]
|
|
159
95
|
}
|
|
160
96
|
});
|
|
97
|
+
|
|
98
|
+
const handleSave = (payload) => {
|
|
99
|
+
console.log('保存数据:', payload);
|
|
100
|
+
// { id: '...', name: '测试报告', data: {...}, isNew: false }
|
|
101
|
+
// 用户自行调用接口保存
|
|
102
|
+
};
|
|
161
103
|
</script>
|
|
162
104
|
```
|
|
163
105
|
|
|
164
|
-
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Vue 组件使用说明
|
|
109
|
+
|
|
110
|
+
### 组件 Props 一览
|
|
111
|
+
|
|
112
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
113
|
+
|------|------|--------|------|
|
|
114
|
+
| `mode` | `'template'` \| `'report'` | `'template'` | 工作模式 |
|
|
115
|
+
| `sample-data` | `object` | — | 传入的示例数据 |
|
|
116
|
+
| `on-save` | `(payload) => void \| Promise<void>` | — | 保存回调,详见下方 |
|
|
117
|
+
| `auto-save-enabled` | `boolean` | `false` | 是否开启定时自动保存 |
|
|
118
|
+
| `auto-save-interval-ms` | `number` | `120000` | 自动保存间隔(毫秒),默认 2 分钟 |
|
|
119
|
+
|
|
120
|
+
### Props 详细说明
|
|
121
|
+
|
|
122
|
+
#### `mode`
|
|
123
|
+
|
|
124
|
+
工作模式。`'template'` 保存时只存布局,`'report'` 保存时同时存布局和 testData。
|
|
125
|
+
|
|
126
|
+
```vue
|
|
127
|
+
<PrintDesigner mode="report" />
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### `sample-data`
|
|
131
|
+
|
|
132
|
+
传入设计器的示例数据。**最关键的属性**。详见下方 [传入数据格式](#传入数据格式)。
|
|
133
|
+
|
|
134
|
+
```vue
|
|
135
|
+
<PrintDesigner :sample-data="{ id: 1, name: '报告', variables: {...} }" />
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### `on-save`
|
|
139
|
+
|
|
140
|
+
保存回调函数。当用户点击保存按钮(或自动保存触发)时,设计器组装好数据后调用此回调,**不再自动调接口**,完全交由用户自行处理。
|
|
141
|
+
|
|
142
|
+
```vue
|
|
143
|
+
<PrintDesigner :on-save="(payload) => fetch('/api/save', { method: 'POST', body: JSON.stringify(payload) })" />
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### `auto-save-enabled`
|
|
147
|
+
|
|
148
|
+
是否开启定时自动保存。开启后每隔 `auto-save-interval-ms` 毫秒自动触发 `on-save` 回调。详见 [自动保存配置](#自动保存配置)。
|
|
149
|
+
|
|
150
|
+
#### `auto-save-interval-ms`
|
|
151
|
+
|
|
152
|
+
自动保存间隔时间(毫秒),默认 `120000`(2 分钟)。
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Web Component 使用说明
|
|
157
|
+
|
|
158
|
+
### 标签方式
|
|
165
159
|
|
|
166
160
|
```html
|
|
167
161
|
<print-designer id="designer"></print-designer>
|
|
@@ -169,131 +163,272 @@ const sampleData = ref({
|
|
|
169
163
|
<script>
|
|
170
164
|
const designer = document.getElementById('designer');
|
|
171
165
|
|
|
172
|
-
// 设置模式
|
|
173
166
|
designer.setMode('template');
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
designer.setTestData({
|
|
177
|
-
orderNo: 'ORD-001',
|
|
178
|
-
customerName: '张三',
|
|
179
|
-
items: [
|
|
180
|
-
{ name: '产品A', price: 100, quantity: 2 }
|
|
181
|
-
]
|
|
167
|
+
designer.setOnSave((payload) => {
|
|
168
|
+
fetch('/api/save', { method: 'POST', body: JSON.stringify(payload) });
|
|
182
169
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
designer.setTemplates([
|
|
186
|
-
{
|
|
187
|
-
id: 'tpl-1',
|
|
188
|
-
name: 'A4 打印模板',
|
|
189
|
-
data: {
|
|
190
|
-
pages: [],
|
|
191
|
-
canvasSize: { width: 794, height: 1123 },
|
|
192
|
-
unit: 'mm'
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
], { currentTemplateId: 'tpl-1' });
|
|
170
|
+
designer.setAutoSave(true, 120000);
|
|
171
|
+
designer.setTestData({ orderNo: 'ORD-001', items: [...] });
|
|
196
172
|
</script>
|
|
197
173
|
```
|
|
198
174
|
|
|
175
|
+
### API 速览
|
|
176
|
+
|
|
177
|
+
| 方法 | 说明 |
|
|
178
|
+
|------|------|
|
|
179
|
+
| `setMode(mode)` | 设置模式:`'template'` / `'report'` |
|
|
180
|
+
| `setOnSave(handler)` | 设置保存回调 |
|
|
181
|
+
| `setAutoSave(enabled, intervalMs?)` | 开启/关闭自动保存 |
|
|
182
|
+
| `setTestData(data)` | 设置测试数据 |
|
|
183
|
+
| `setVariables(vars)` | 打印/导出时注入真实变量 |
|
|
184
|
+
| `setTemplates(list, opts)` | 设置模板列表 |
|
|
185
|
+
| `loadTemplate(id)` | 加载指定模板到画布 |
|
|
186
|
+
| `print(request)` | 执行打印 |
|
|
187
|
+
| `export(request)` | 导出 PDF/图片/HTML |
|
|
188
|
+
|
|
189
|
+
### 打印时注入真实数据
|
|
190
|
+
|
|
191
|
+
```js
|
|
192
|
+
const designer = document.querySelector('print-designer');
|
|
193
|
+
|
|
194
|
+
await designer.loadTemplate('tpl-order');
|
|
195
|
+
|
|
196
|
+
designer.setVariables({
|
|
197
|
+
orderNo: 'REAL-2026-001',
|
|
198
|
+
customerName: '李四',
|
|
199
|
+
totalAmount: 5999.00
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await designer.print({ mode: 'browser', options: { silent: true } });
|
|
203
|
+
```
|
|
204
|
+
|
|
199
205
|
---
|
|
200
206
|
|
|
201
207
|
## 传入数据格式
|
|
202
208
|
|
|
203
|
-
|
|
209
|
+
数据以 **扁平键值对** 形式传入,所有字段在根级别,在模板中通过 `@变量名` 或 `{#变量名}` 直接引用。
|
|
204
210
|
|
|
205
|
-
|
|
211
|
+
### `sample-data` 字段说明
|
|
206
212
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
214
|
+
|------|------|------|------|
|
|
215
|
+
| `id` | `number` / `string` | 是 | **业务数据的 ID**,如报告 ID、订单 ID |
|
|
216
|
+
| `templateId` | `string` | 否 | 加载的打印模板 ID,不传则用当前已选模板 |
|
|
217
|
+
| `name` | `string` | 否 | 数据名称,如报告标题、订单名称 |
|
|
218
|
+
| `variables` | `object` | 否 | **业务变量对象**,包含模板中绑定的所有字段 |
|
|
219
|
+
| 任意自定义字段 | `any` | 否 | 如 `createTime`、`selected`,也可在模板中引用 |
|
|
211
220
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
> `id` 是业务数据的标识,`templateId` 是打印模板的标识,两者是不同概念。
|
|
222
|
+
|
|
223
|
+
### `variables` 内部结构
|
|
224
|
+
|
|
225
|
+
`variables` 是一个扁平或嵌套的 JSON 对象,其中的所有字段都可在模板元素中通过变量语法绑定。
|
|
226
|
+
|
|
227
|
+
支持的数据类型:
|
|
228
|
+
- **字符串** `string` — 文本元素绑定
|
|
229
|
+
- **数字** `number` — 文本、图表数据
|
|
230
|
+
- **布尔值** `boolean`
|
|
231
|
+
- **数组** `array` — 表格数据源、图表数据源
|
|
232
|
+
- **嵌套对象** `object` — 多级路径访问
|
|
233
|
+
|
|
234
|
+
### 示例:完整数据格式
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"id": 8,
|
|
239
|
+
"name": "宝安机场飞行任务记录",
|
|
240
|
+
"templateId": "tpl_report_drone",
|
|
241
|
+
"createTime": "2026-05-01",
|
|
242
|
+
"variables": {
|
|
243
|
+
"dockname": "宝安国际无人机机场",
|
|
244
|
+
"dronesn": "6EE5NC104E0PY6",
|
|
245
|
+
"dronename": "M300 RTK",
|
|
246
|
+
"reportname": "宝安机场飞行任务记录报告",
|
|
247
|
+
"tasktype": "航线巡检",
|
|
248
|
+
"totalcount": 4,
|
|
249
|
+
"totaldistance": "48.6 km",
|
|
250
|
+
"conclusion": "本轮飞行任务覆盖宝安区重点航线,数据采集完整。",
|
|
251
|
+
"flightRecords": [
|
|
252
|
+
{
|
|
253
|
+
"time": "2026-04-02 09:30",
|
|
254
|
+
"taskname": "宝安港区A线巡检",
|
|
255
|
+
"dockname": "宝安国际无人机机场",
|
|
256
|
+
"distance": "12.5 km",
|
|
257
|
+
"image": "https://picsum.photos/id/1/200/80"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"time": "2026-04-08 14:00",
|
|
261
|
+
"taskname": "西乡街道线路巡查",
|
|
262
|
+
"dockname": "罗湖无人机机场",
|
|
263
|
+
"distance": "10.2 km",
|
|
264
|
+
"image": "https://picsum.photos/id/10/200/80"
|
|
265
|
+
}
|
|
224
266
|
],
|
|
225
|
-
|
|
226
|
-
{
|
|
227
|
-
|
|
228
|
-
|
|
267
|
+
"taskRecords": [
|
|
268
|
+
{
|
|
269
|
+
"time": "2026-04-02 09:30",
|
|
270
|
+
"taskname": "宝安港区A线巡检",
|
|
271
|
+
"dockname": "宝安国际无人机机场",
|
|
272
|
+
"warn": 2
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"time": "2026-04-08 14:00",
|
|
276
|
+
"taskname": "西乡街道线路巡查",
|
|
277
|
+
"dockname": "罗湖无人机机场",
|
|
278
|
+
"warn": 1
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
"chartData": [
|
|
282
|
+
{ "category": "一月", "value": 1200 },
|
|
283
|
+
{ "category": "二月", "value": 1500 },
|
|
284
|
+
{ "category": "三月", "value": 1800 }
|
|
229
285
|
]
|
|
230
286
|
}
|
|
231
|
-
}
|
|
232
|
-
</script>
|
|
287
|
+
}
|
|
233
288
|
```
|
|
234
289
|
|
|
235
|
-
|
|
290
|
+
### 在模板中绑定变量
|
|
236
291
|
|
|
237
|
-
|
|
|
238
|
-
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `variables` | `
|
|
292
|
+
| 变量 | 绑定写法 | 应用元素 |
|
|
293
|
+
|------|---------|---------|
|
|
294
|
+
| `variables.dockname` | `@dockname` 或 `{#dockname}` | 文本 |
|
|
295
|
+
| `variables.reportname` | `@reportname` | 文本 |
|
|
296
|
+
| `variables.totaldistance` | `@totaldistance` | 文本 |
|
|
297
|
+
| `variables.createtime` | `@createtime` | 文本 |
|
|
298
|
+
| `variables.flightRecords` | `@flightRecords` | 表格、自定义表格 |
|
|
299
|
+
| `variables.taskRecords` | `@taskRecords` | 表格 |
|
|
300
|
+
| `variables.chartData` | `@chartData` | 图表 |
|
|
242
301
|
|
|
243
|
-
|
|
244
|
-
- **简单值:** `string`、`number`、`boolean`
|
|
245
|
-
- **数组:** 用于表格和图表组件的数据源
|
|
246
|
-
- **嵌套对象:** 支持多级路径访问
|
|
302
|
+
### 表格数据
|
|
247
303
|
|
|
248
|
-
|
|
304
|
+
表格需要三个维度的变量:
|
|
249
305
|
|
|
250
|
-
|
|
251
|
-
|
|
306
|
+
| 绑定字段 | 变量名 | 格式 | 说明 |
|
|
307
|
+
|---------|-------|------|------|
|
|
308
|
+
| `variable` | `@items` | `Array<Object>` | 表格行数据 |
|
|
309
|
+
| `columnsVariable` | `@tableCols` | `Array<{field, header, width}>` | 列定义 |
|
|
310
|
+
| `footerDataVariable` | `@tableFooter` | `Array<Object>` | 页脚汇总行 |
|
|
252
311
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
{ name:
|
|
258
|
-
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"items": [
|
|
315
|
+
{ "name": "产品A", "price": 100, "quantity": 2 },
|
|
316
|
+
{ "name": "产品B", "price": 200, "quantity": 3 }
|
|
317
|
+
],
|
|
318
|
+
"tableCols": [
|
|
319
|
+
{ "field": "name", "header": "产品名称", "width": 120 },
|
|
320
|
+
{ "field": "price", "header": "单价", "width": 80 },
|
|
321
|
+
{ "field": "quantity", "header": "数量", "width": 80 }
|
|
259
322
|
],
|
|
260
|
-
|
|
261
|
-
{
|
|
262
|
-
{ category: '二月', value: 1500 }
|
|
323
|
+
"tableFooter": [
|
|
324
|
+
{ "name": { "value": "合计" }, "price": { "value": "300" } }
|
|
263
325
|
]
|
|
264
|
-
}
|
|
326
|
+
}
|
|
265
327
|
```
|
|
266
328
|
|
|
267
|
-
###
|
|
329
|
+
### 图表数据
|
|
268
330
|
|
|
269
|
-
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"chartData": [
|
|
334
|
+
{ "category": "一月", "value": 1200 },
|
|
335
|
+
{ "category": "二月", "value": 1500 }
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
```
|
|
270
339
|
|
|
271
|
-
|
|
272
|
-
|
|
340
|
+
图表元素需配置:
|
|
341
|
+
- **chartDataVariable:** `@chartData`
|
|
342
|
+
- **chartXField:** `category`(X 轴字段名)
|
|
343
|
+
- **chartYField:** `value`(Y 轴字段名)
|
|
344
|
+
- **chartNameField:** `category`(饼图名称字段)
|
|
273
345
|
|
|
274
|
-
|
|
275
|
-
await designer.loadTemplate('tpl-order');
|
|
346
|
+
---
|
|
276
347
|
|
|
277
|
-
|
|
278
|
-
designer.setVariables({
|
|
279
|
-
orderNo: 'REAL-2026-001',
|
|
280
|
-
customerName: '李四',
|
|
281
|
-
totalAmount: 5999.00
|
|
282
|
-
});
|
|
348
|
+
## 保存回调 `onSave`
|
|
283
349
|
|
|
284
|
-
|
|
285
|
-
|
|
350
|
+
传入 `onSave` 后,用户点击保存按钮(`Ctrl+S` 或工具栏按钮)时,设计器不再自动调接口,而是将组装好的数据通过回调交给用户自行处理。
|
|
351
|
+
|
|
352
|
+
### 回调参数
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
interface SavePayload {
|
|
356
|
+
id: string | null; // 模板 ID,null 表示新建
|
|
357
|
+
name: string; // 模板名称
|
|
358
|
+
data: Record<string, any>; // 完整模板数据(pages/canvasSize/watermark/testData...)
|
|
359
|
+
isNew: boolean; // 是否新建模板
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 使用示例
|
|
364
|
+
|
|
365
|
+
```vue
|
|
366
|
+
<PrintDesigner
|
|
367
|
+
:on-save="handleSave"
|
|
368
|
+
/>
|
|
369
|
+
|
|
370
|
+
<script setup>
|
|
371
|
+
const handleSave = async (payload) => {
|
|
372
|
+
// payload.data 包含 pages、canvasSize、watermark、testData 等所有画布数据
|
|
373
|
+
const response = await fetch('/api/save', {
|
|
374
|
+
method: 'POST',
|
|
375
|
+
headers: { 'Content-Type': 'application/json' },
|
|
376
|
+
body: JSON.stringify(payload)
|
|
377
|
+
});
|
|
378
|
+
if (!response.ok) throw new Error('保存失败');
|
|
379
|
+
};
|
|
380
|
+
</script>
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
> 不传 `onSave` 时,设计器会走原有的默认保存逻辑(调用内置 CRUD 接口或存 localStorage),行为不变。
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 自动保存配置
|
|
388
|
+
|
|
389
|
+
传入 `onSave` 后,可同时开启自动保存。开启后设计器会每隔固定时间调用 `onSave` 回调,右下角显示最近保存时间。
|
|
390
|
+
|
|
391
|
+
### Props 配置
|
|
392
|
+
|
|
393
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
394
|
+
|------|------|--------|------|
|
|
395
|
+
| `auto-save-enabled` | `boolean` | `false` | 是否开启 |
|
|
396
|
+
| `auto-save-interval-ms` | `number` | `120000` | 间隔(毫秒),默认 2 分钟 |
|
|
397
|
+
|
|
398
|
+
### 示例
|
|
399
|
+
|
|
400
|
+
```vue
|
|
401
|
+
<PrintDesigner
|
|
402
|
+
:on-save="handleSave"
|
|
403
|
+
:auto-save-enabled="true"
|
|
404
|
+
:auto-save-interval-ms="120000"
|
|
405
|
+
/>
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
```js
|
|
409
|
+
designer.setOnSave(handleSave);
|
|
410
|
+
designer.setAutoSave(true, 120000); // 每 2 分钟自动保存
|
|
411
|
+
designer.setAutoSave(false); // 关闭
|
|
286
412
|
```
|
|
287
413
|
|
|
288
|
-
|
|
414
|
+
> 右下角会显示 "最近保存: HH:MM:SS",每次回调完成后自动更新时间。
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## 模板数据结构(完整格式)
|
|
289
419
|
|
|
290
|
-
|
|
420
|
+
当用户直接保存/加载完整模板时,使用以下数据结构:
|
|
291
421
|
|
|
292
422
|
```json
|
|
293
423
|
{
|
|
294
424
|
"id": "tpl_001",
|
|
295
425
|
"name": "A4 订单模板",
|
|
296
426
|
"updatedAt": 1715251200000,
|
|
427
|
+
"permissions": {
|
|
428
|
+
"editable": true,
|
|
429
|
+
"deletable": true,
|
|
430
|
+
"copyable": true
|
|
431
|
+
},
|
|
297
432
|
"data": {
|
|
298
433
|
"pages": [
|
|
299
434
|
{
|
|
@@ -307,11 +442,7 @@ await designer.print({ mode: 'browser', options: { silent: true } });
|
|
|
307
442
|
"width": 200,
|
|
308
443
|
"height": 24,
|
|
309
444
|
"content": "订单号: {#orderNo}",
|
|
310
|
-
"style": {
|
|
311
|
-
"fontSize": 14,
|
|
312
|
-
"fontWeight": "bold",
|
|
313
|
-
"color": "#111827"
|
|
314
|
-
}
|
|
445
|
+
"style": { "fontSize": 14, "fontWeight": "bold", "color": "#111827" }
|
|
315
446
|
},
|
|
316
447
|
{
|
|
317
448
|
"id": "el_table_1",
|
|
@@ -360,9 +491,7 @@ await designer.print({ mode: 'browser', options: { silent: true } });
|
|
|
360
491
|
},
|
|
361
492
|
"testData": {
|
|
362
493
|
"orderNo": "A001",
|
|
363
|
-
"items": [
|
|
364
|
-
{ "name": "产品A", "price": 100, "quantity": 2 }
|
|
365
|
-
]
|
|
494
|
+
"items": [{ "name": "产品A", "price": 100, "quantity": 2 }]
|
|
366
495
|
}
|
|
367
496
|
},
|
|
368
497
|
"ext": {
|
|
@@ -380,154 +509,100 @@ await designer.print({ mode: 'browser', options: { silent: true } });
|
|
|
380
509
|
}
|
|
381
510
|
```
|
|
382
511
|
|
|
383
|
-
|
|
512
|
+
### 顶层字段
|
|
384
513
|
|
|
385
514
|
| 字段 | 类型 | 必填 | 说明 |
|
|
386
515
|
|-----|------|-----|------|
|
|
387
|
-
| `id` | `string` | 是 |
|
|
516
|
+
| `id` | `string` | 是 | 模板唯一 ID |
|
|
388
517
|
| `name` | `string` | 是 | 模板名称 |
|
|
389
518
|
| `updatedAt` | `number` | 否 | 更新时间戳(毫秒) |
|
|
519
|
+
| `permissions` | `object` | 否 | `{ editable, deletable, copyable }` |
|
|
390
520
|
| `data` | `object` | 是 | 模板设计数据 |
|
|
391
|
-
| `
|
|
392
|
-
| `data.canvasSize` | `Size` | 是 | 画布尺寸 `{ width, height }` |
|
|
393
|
-
| `data.unit` | `string` | 否 | 单位:`mm` / `px` / `pt` / `in` / `cm` |
|
|
394
|
-
| `data.watermark` | `WatermarkSettings` | 否 | 水印配置 |
|
|
395
|
-
| `data.guides` | `Guide[]` | 否 | 参考线列表 |
|
|
396
|
-
| `data.testData` | `object` | 否 | 测试数据(报告模式会保存) |
|
|
397
|
-
| `ext` | `object` | 否 | 扩展字段 |
|
|
398
|
-
| `ext.availableVariables` | `VariableTreeItem[]` | 否 | 模板绑定的变量树 |
|
|
399
|
-
| `permissions` | `object` | 否 | 权限控制 `{ editable, deletable, copyable }` |
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
## 支持的元素类型
|
|
404
|
-
|
|
405
|
-
| 元素类型 | 说明 | 数据支持 |
|
|
406
|
-
|---------|------|---------|
|
|
407
|
-
| 文本(Text) | 显示静态文本或变量内容 | 静态内容 / 变量引用 |
|
|
408
|
-
| 长文本(LongText) | 自动扩展的多行文本 | 静态内容 / 变量引用 |
|
|
409
|
-
| 图片(Image) | 显示图片 | 静态URL / 变量引用 |
|
|
410
|
-
| 表格(Table) | 展示数据表格,支持自动分页 | 静态数据 / 数据变量 |
|
|
411
|
-
| 自定义表格(CustomTable) | 自由合并单元格的表格 | 静态数据 / 数据变量 |
|
|
412
|
-
| 条形码(Barcode) | 生成条形码 | 变量引用 |
|
|
413
|
-
| 二维码(QRCode) | 生成二维码 | 变量引用 |
|
|
414
|
-
| 图表(Chart) | ECharts 图表(柱状图/折线图/饼图/环形图/面积图) | 静态数据 / 数据变量 |
|
|
415
|
-
| 线条(Line) | 绘制直线 | — |
|
|
416
|
-
| 矩形(Rect) | 绘制矩形 | — |
|
|
417
|
-
| 圆形(Circle) | 绘制圆形 | — |
|
|
418
|
-
| 页码(PageNumber) | 显示页码信息 | — |
|
|
419
|
-
|
|
420
|
-
---
|
|
421
|
-
|
|
422
|
-
## 数据绑定方式
|
|
423
|
-
|
|
424
|
-
### 1. 静态数据
|
|
425
|
-
|
|
426
|
-
直接在元素属性面板中输入静态内容,适用于固定不变的文本、图片URL等。
|
|
427
|
-
|
|
428
|
-
### 2. 变量绑定
|
|
429
|
-
|
|
430
|
-
使用特殊语法引用外部传入的数据,数据在打印/导出时动态替换。
|
|
431
|
-
|
|
432
|
-
### 3. 数组数据(表格 & 图表)
|
|
433
|
-
|
|
434
|
-
表格和图表组件可以绑定数组类型的数据变量。
|
|
435
|
-
|
|
436
|
-
**表格数据格式:**
|
|
437
|
-
|
|
438
|
-
```json
|
|
439
|
-
{
|
|
440
|
-
"items": [
|
|
441
|
-
{ "name": "产品A", "price": 100, "quantity": 2 },
|
|
442
|
-
{ "name": "产品B", "price": 200, "quantity": 3 }
|
|
443
|
-
],
|
|
444
|
-
"tableCols": [
|
|
445
|
-
{ "field": "name", "header": "产品名称", "width": 120 },
|
|
446
|
-
{ "field": "price", "header": "单价", "width": 80 },
|
|
447
|
-
{ "field": "quantity", "header": "数量", "width": 80 }
|
|
448
|
-
],
|
|
449
|
-
"tableFooter": [
|
|
450
|
-
{ "name": { "value": "合计" }, "price": { "value": "300" } }
|
|
451
|
-
]
|
|
452
|
-
}
|
|
453
|
-
```
|
|
521
|
+
| `ext` | `object` | 否 | 扩展数据(变量树等) |
|
|
454
522
|
|
|
455
|
-
|
|
456
|
-
- **数据变量(variable):** 绑定到 `@items`
|
|
457
|
-
- **列定义变量(columnsVariable):** 绑定到 `@tableCols`
|
|
458
|
-
- **页脚数据变量(footerDataVariable):** 绑定到 `@tableFooter`
|
|
523
|
+
### `data` 内部字段
|
|
459
524
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
{
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
525
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
526
|
+
|-----|------|-----|------|
|
|
527
|
+
| `pages` | `Page[]` | 是 | 页面列表,每页含 `elements` 数组 |
|
|
528
|
+
| `canvasSize` | `{ width, height }` | 是 | 画布尺寸(默认 A4: 794×1123) |
|
|
529
|
+
| `unit` | `'mm'`\|`'px'`\|`'pt'`\|`'in'`\|`'cm'` | 否 | 单位 |
|
|
530
|
+
| `watermark` | `WatermarkSettings` | 否 | 水印配置 |
|
|
531
|
+
| `guides` | `Guide[]` | 否 | 参考线 |
|
|
532
|
+
| `zoom` | `number` | 否 | 缩放比例 |
|
|
533
|
+
| `showGrid` | `boolean` | 否 | 显示网格 |
|
|
534
|
+
| `headerHeight` | `number` | 否 | 页眉高度 |
|
|
535
|
+
| `footerHeight` | `number` | 否 | 页脚高度 |
|
|
536
|
+
| `pageSpacingX` | `number` | 否 | 水平边距 |
|
|
537
|
+
| `pageSpacingY` | `number` | 否 | 垂直边距 |
|
|
538
|
+
| `canvasBackground` | `string` | 否 | 画布背景色 |
|
|
539
|
+
| `testData` | `object` | 否 | 测试数据(报告模式保存) |
|
|
540
|
+
|
|
541
|
+
### 元素基本字段
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
interface PrintElement {
|
|
545
|
+
id: string; // 元素唯一 ID
|
|
546
|
+
type: ElementType; // 元素类型: 'text'|'image'|'table'|'customTable'|'barcode'|'qrcode'|'line'|'rect'|'circle'|'chart'|'pageNumber'|'longtext'
|
|
547
|
+
x: number; // X 坐标
|
|
548
|
+
y: number; // Y 坐标
|
|
549
|
+
width: number; // 宽度
|
|
550
|
+
height: number; // 高度
|
|
551
|
+
content?: string; // 文本内容(支持变量占位符)
|
|
552
|
+
variable?: string; // 绑定变量名(如 '@items')
|
|
553
|
+
style: ElementStyle; // 样式对象
|
|
469
554
|
}
|
|
470
555
|
```
|
|
471
556
|
|
|
472
|
-
图表元素支持的绑定字段:
|
|
473
|
-
- **chartDataVariable:** 数据变量名
|
|
474
|
-
- **chartXField:** X轴/分类字段名
|
|
475
|
-
- **chartYField:** Y轴/数值字段名
|
|
476
|
-
- **chartNameField:** 名称字段(饼图)
|
|
477
|
-
|
|
478
557
|
---
|
|
479
558
|
|
|
480
|
-
##
|
|
481
|
-
|
|
482
|
-
在设计器中编辑时,可以手动编辑测试数据以便预览变量渲染效果。
|
|
483
|
-
|
|
484
|
-
### 设计器内编辑
|
|
559
|
+
## 元素数据绑定
|
|
485
560
|
|
|
486
|
-
|
|
561
|
+
### 变量语法
|
|
487
562
|
|
|
488
|
-
|
|
563
|
+
| 语法 | 示例 | 说明 |
|
|
564
|
+
|-----|------|------|
|
|
565
|
+
| `@变量名` | `@customerName` | 直接引用变量 |
|
|
566
|
+
| `{#变量路径}` | `{#order.items[0].name}` | 支持嵌套路径和数组索引 |
|
|
489
567
|
|
|
490
|
-
|
|
491
|
-
// Web Component 方式
|
|
492
|
-
designer.setTestData({
|
|
493
|
-
orderNo: 'TEST-001',
|
|
494
|
-
customerName: '测试客户'
|
|
495
|
-
});
|
|
568
|
+
### 各元素可绑定字段
|
|
496
569
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
570
|
+
| 元素 | 绑定的属性 | 示例 |
|
|
571
|
+
|------|----------|------|
|
|
572
|
+
| 文本 / 长文本 | `content` | `订单号: {#orderNo}` |
|
|
573
|
+
| 图片 | `variable` | `@imageUrl` |
|
|
574
|
+
| 表格 | `variable` + `columnsVariable` + `footerDataVariable` | `@items`, `@tableCols`, `@tableFooter` |
|
|
575
|
+
| 条形码 | `variable` | `@barcode` |
|
|
576
|
+
| 二维码 | `variable` | `@url` |
|
|
577
|
+
| 图表 | `chartDataVariable` + `chartXField` + `chartYField` | `@chartData`, `category`, `value` |
|
|
500
578
|
|
|
501
579
|
---
|
|
502
580
|
|
|
503
|
-
##
|
|
504
|
-
|
|
505
|
-
| 语法 | 示例 | 说明 |
|
|
506
|
-
|-----|------|------|
|
|
507
|
-
| `@变量名` | `@customerName` | 使用 `@` 符号引用顶层变量 |
|
|
508
|
-
| `{#变量路径}` | `{#order.details[0].name}` | 使用 `{#}` 包裹,支持嵌套路径和数组索引 |
|
|
509
|
-
| `{#变量名}` | `{#orderNo}` | 与 `@` 等价,推荐使用此格式 |
|
|
510
|
-
|
|
511
|
-
在元素属性中绑定变量:
|
|
581
|
+
## 支持的元素类型
|
|
512
582
|
|
|
513
|
-
|
|
|
514
|
-
|
|
515
|
-
| 文本 | `
|
|
516
|
-
|
|
|
517
|
-
|
|
|
518
|
-
|
|
|
519
|
-
|
|
|
520
|
-
|
|
|
583
|
+
| 类型 | 标识 | 说明 |
|
|
584
|
+
|------|------|------|
|
|
585
|
+
| 文本 | `text` | 静态文本或变量内容 |
|
|
586
|
+
| 长文本 | `longtext` | 多行自动扩展文本 |
|
|
587
|
+
| 图片 | `image` | 图片显示(URL 绑定) |
|
|
588
|
+
| 表格 | `table` | 数据表格,支持自动分页、页脚 |
|
|
589
|
+
| 自定义表格 | `customTable` | 自由合并单元格 |
|
|
590
|
+
| 条形码 | `barcode` | 一维条形码 |
|
|
591
|
+
| 二维码 | `qrcode` | 二维码 |
|
|
592
|
+
| 图表 | `chart` | ECharts(柱状图/折线图/饼图/环形图/面积图) |
|
|
593
|
+
| 线条 | `line` | 直线 |
|
|
594
|
+
| 矩形 | `rect` | 矩形 |
|
|
595
|
+
| 圆形 | `circle` | 圆形 |
|
|
596
|
+
| 页码 | `pageNumber` | 页码显示 |
|
|
521
597
|
|
|
522
598
|
---
|
|
523
599
|
|
|
524
600
|
## 技术栈
|
|
525
601
|
|
|
526
|
-
- Vue 3
|
|
527
|
-
- TypeScript
|
|
602
|
+
- Vue 3 / TypeScript
|
|
528
603
|
- Pinia(状态管理)
|
|
529
604
|
- Tailwind CSS
|
|
530
605
|
- ECharts 5
|
|
531
|
-
- Monaco Editor
|
|
606
|
+
- Monaco Editor
|
|
532
607
|
|
|
533
608
|
---
|