print-designer 1.0.3 → 1.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.
Files changed (2) hide show
  1. package/README.md +381 -67
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -6,10 +6,12 @@
6
6
 
7
7
  - 📐 **可视化设计** - 拖拽式设计界面,所见即所得
8
8
  - 🎨 **丰富控件** - 支持文本、字段、图片、条码、二维码、线条等多种控件
9
- - 📊 **带区设计** - 支持页头、页脚、明细带区等报表结构
10
- - 🖨️ **打印预览** - 实时预览打印效果
9
+ - 📊 **带区设计** - 支持页头、明细、汇总、页脚带区
10
+ - 🖨️ **打印预览** - 实时预览打印效果,支持分页
11
11
  - 📄 **PDF 导出** - 一键导出 PDF 文件
12
+ - ⌨️ **键盘操作** - 支持方向键微调、Shift 锁定方向、快捷键
12
13
  - 🔧 **高度可定制** - 灵活的属性配置和样式设置
14
+ - 📝 **公式支持** - 支持计算字段和公式编辑
13
15
 
14
16
  ## 安装
15
17
 
@@ -19,127 +21,438 @@ npm install print-designer
19
21
 
20
22
  ## 快速开始
21
23
 
24
+ ### 基本使用(设计器模式)
25
+
22
26
  ```tsx
23
27
  import { BandBoundaryDesigner } from 'print-designer';
28
+ import 'print-designer/dist/style.css';
24
29
 
30
+ // 定义数据字段
25
31
  const dataFields = [
26
- { name: 'orderNo', label: '订单号', type: 'string' },
27
- { name: 'customer', label: '客户名称', type: 'string' },
28
- { name: 'amount', label: '金额', type: 'number' },
29
- { name: 'products', label: '产品明细', type: 'array', children: [
30
- { name: 'name', label: '产品名称', type: 'string' },
31
- { name: 'qty', label: '数量', type: 'number' },
32
- { name: 'price', label: '单价', type: 'number' },
33
- ]},
32
+ // 主表字段
33
+ { name: 'orderNo', label: '订单号', type: 'string', source: 'master' },
34
+ { name: 'customer', label: '客户名称', type: 'string', source: 'master' },
35
+ { name: 'orderDate', label: '订单日期', type: 'date', source: 'master' },
36
+ { name: 'totalAmount', label: '总金额', type: 'currency', source: 'master' },
37
+ // 明细字段(source 'detail'
38
+ { name: 'products.name', label: '产品名称', type: 'string', source: 'detail' },
39
+ { name: 'products.quantity', label: '数量', type: 'number', source: 'detail' },
40
+ { name: 'products.price', label: '单价', type: 'currency', source: 'detail' },
41
+ { name: 'products.amount', label: '金额', type: 'currency', source: 'detail' },
34
42
  ];
35
43
 
44
+ // 预览数据
36
45
  const previewData = {
37
46
  orderNo: 'ORD-2024001',
38
- customer: '测试客户',
39
- amount: 1000,
47
+ customer: '测试客户公司',
48
+ orderDate: '2024-01-15',
49
+ totalAmount: 15000,
50
+ // 明细数据(数组名称根据字段定义自动识别,如 products.name → products)
40
51
  products: [
41
- { name: '产品A', qty: 10, price: 50 },
42
- { name: '产品B', qty: 5, price: 100 },
52
+ { name: '产品A', quantity: 10, price: 500, amount: 5000 },
53
+ { name: '产品B', quantity: 20, price: 300, amount: 6000 },
54
+ { name: '产品C', quantity: 8, price: 500, amount: 4000 },
43
55
  ],
44
56
  };
45
57
 
46
58
  function App() {
59
+ const handleSave = (design) => {
60
+ console.log('保存设计:', design);
61
+ // 保存到服务器或本地存储
62
+ localStorage.setItem('design', JSON.stringify(design));
63
+ };
64
+
65
+ const handleDesignChange = (bands) => {
66
+ console.log('设计变更:', bands);
67
+ };
68
+
47
69
  return (
48
70
  <BandBoundaryDesigner
49
71
  dataFields={dataFields}
50
72
  data={previewData}
51
- onSave={(design) => {
52
- console.log('保存设计:', design);
53
- }}
73
+ onSave={handleSave}
74
+ onDesignChange={handleDesignChange}
54
75
  />
55
76
  );
56
77
  }
57
78
  ```
58
79
 
59
- ## API
80
+ ### 直接打印输出(无需设计器)
81
+
82
+ 如果已有设计模板,可以直接调用打印输出接口:
83
+
84
+ ```tsx
85
+ import {
86
+ renderToHtml,
87
+ exportToPdf,
88
+ getPrintableHtml,
89
+ openPrintWindow
90
+ } from 'print-designer';
91
+
92
+ // 从存储加载设计模板
93
+ const savedDesign = JSON.parse(localStorage.getItem('design') || '{}');
94
+ const template = savedDesign.bands;
95
+ const pageSettings = savedDesign.pageSettings;
96
+
97
+ // 打印配置
98
+ const printOptions = {
99
+ template, // 设计模板(带区数据)
100
+ data: previewData, // 业务数据
101
+ dataFields, // 数据字段定义
102
+ pageSettings, // 页面设置(可选)
103
+ };
104
+
105
+ // 1. 渲染为 HTML 字符串
106
+ const result = renderToHtml(printOptions);
107
+ console.log('总页数:', result.totalPages);
108
+ console.log('HTML:', result.html);
109
+
110
+ // 2. 导出 PDF
111
+ await exportToPdf({
112
+ ...printOptions,
113
+ fileName: '订单报表', // PDF 文件名
114
+ download: true, // 直接下载
115
+ });
116
+
117
+ // 3. 获取完整的可打印 HTML 文档
118
+ const printHtml = getPrintableHtml(printOptions);
119
+ // 可以发送给服务器生成 PDF 或打印
120
+
121
+ // 4. 打开打印窗口
122
+ openPrintWindow(printOptions);
123
+ ```
124
+
125
+ ## API 文档
60
126
 
61
127
  ### BandBoundaryDesigner
62
128
 
63
129
  主设计器组件。
64
130
 
65
- | 属性 | 类型 | 必填 | 说明 |
66
- |------|------|------|------|
67
- | dataFields | `DataField[]` | ✓ | 数据字段定义 |
68
- | data | `Record<string, any>` | | 预览数据 |
69
- | initialDesign | `Band[]` | | 初始设计数据 |
70
- | options | `Partial<DesignerOptions>` | | 设计器配置 |
71
- | onDesignChange | `(bands: Band[]) => void` | | 设计变更回调 |
72
- | onSave | `(design: any) => void` | | 保存回调 |
73
- | onPreview | `() => void` | | 预览回调 |
131
+ ```tsx
132
+ import { BandBoundaryDesigner } from 'print-designer';
133
+ ```
134
+
135
+ | 属性 | 类型 | 必填 | 默认值 | 说明 |
136
+ |------|------|:----:|--------|------|
137
+ | dataFields | `DataField[]` | | - | 数据字段定义 |
138
+ | data | `Record<string, any>` | | `{}` | 预览数据 |
139
+ | initialDesign | `Band[]` | | - | 初始设计数据(用于加载已保存的设计) |
140
+ | options | `Partial<DesignerOptions>` | | - | 设计器配置选项 |
141
+ | initialPageSettings | `PageSettings` | | A4 纵向 | 初始页面设置 |
142
+ | onDesignChange | `(bands: Band[]) => void` | | - | 设计变更回调(实时) |
143
+ | onSave | `(design: any) => void` | | - | 保存按钮回调 |
144
+ | onPreview | `() => void` | | - | 预览按钮回调 |
145
+ | onPageSettingsChange | `(settings: PageSettings) => void` | | - | 页面设置变更回调 |
146
+
147
+ ### PrintPreview
148
+
149
+ 打印预览组件,可独立使用。
150
+
151
+ ```tsx
152
+ import { PrintPreview } from 'print-designer';
153
+ ```
154
+
155
+ | 属性 | 类型 | 必填 | 默认值 | 说明 |
156
+ |------|------|:----:|--------|------|
157
+ | bands | `Band[]` | ✓ | - | 带区设计数据 |
158
+ | data | `Record<string, any>` | ✓ | - | 预览数据 |
159
+ | dataFields | `DataField[]` | ✓ | - | 数据字段定义 |
160
+ | onClose | `() => void` | ✓ | - | 关闭回调 |
161
+ | pageWidth | `number` | | `794` | 页面宽度(px) |
162
+ | pageHeight | `number` | | `1123` | 页面高度(px) |
163
+ | pageMargins | `{ top, bottom, left, right }` | | `{ top: 40, bottom: 40, left: 40, right: 40 }` | 页边距(px) |
164
+ | showPageNumbers | `boolean` | | `true` | 是否显示页码 |
165
+ | paperWidthMm | `number` | | `210` | 纸张宽度(mm),用于PDF导出 |
166
+ | paperHeightMm | `number` | | `297` | 纸张高度(mm),用于PDF导出 |
167
+
168
+ ### 打印输出函数
169
+
170
+ #### renderToHtml(options)
171
+
172
+ 将设计模板和数据渲染为 HTML 字符串。
173
+
174
+ ```typescript
175
+ import { renderToHtml } from 'print-designer';
176
+
177
+ const result = renderToHtml({
178
+ template: Band[], // 设计模板(带区数据)
179
+ data: object, // 业务数据
180
+ dataFields?: DataField[],// 数据字段定义
181
+ pageSettings?: PageSettings, // 页面设置
182
+ pageWidth?: number, // 页面宽度(px),默认 794
183
+ pageHeight?: number, // 页面高度(px),默认 1123
184
+ pageMargins?: { top, bottom, left, right }, // 页边距(px)
185
+ });
186
+
187
+ // 返回结果
188
+ console.log(result.html); // HTML 字符串
189
+ console.log(result.totalPages); // 总页数
190
+ console.log(result.pageWidth); // 页面宽度(px)
191
+ console.log(result.pageHeight); // 页面高度(px)
192
+ console.log(result.paperWidthMm); // 纸张宽度(mm)
193
+ console.log(result.paperHeightMm);// 纸张高度(mm)
194
+ ```
195
+
196
+ #### exportToPdf(options)
197
+
198
+ 导出为 PDF 文件。
199
+
200
+ ```typescript
201
+ import { exportToPdf } from 'print-designer';
202
+
203
+ await exportToPdf({
204
+ template: Band[], // 设计模板
205
+ data: object, // 业务数据
206
+ dataFields?: DataField[],// 数据字段定义
207
+ pageSettings?: PageSettings, // 页面设置
208
+ fileName?: string, // 文件名(不含扩展名),默认 '报表_日期'
209
+ download?: boolean, // 是否直接下载,默认 true
210
+ scale?: number, // 图片缩放比例,默认 2
211
+ });
212
+
213
+ // 如果 download 为 false,返回 Blob 对象
214
+ const pdfBlob = await exportToPdf({ ...options, download: false });
215
+ ```
216
+
217
+ #### getPrintableHtml(options)
218
+
219
+ 获取完整的可打印 HTML 文档,包含样式和打印配置。
220
+
221
+ ```typescript
222
+ import { getPrintableHtml } from 'print-designer';
223
+
224
+ const html = getPrintableHtml({
225
+ template: Band[],
226
+ data: object,
227
+ dataFields?: DataField[],
228
+ pageSettings?: PageSettings,
229
+ });
230
+
231
+ // 返回完整的 HTML 文档字符串(包含 DOCTYPE、打印样式等)
232
+ // 可用于:
233
+ // - 发送给服务器生成 PDF
234
+ // - iframe 打印
235
+ // - 保存为 HTML 文件
236
+ ```
237
+
238
+ #### openPrintWindow(options)
239
+
240
+ 在新窗口中打开打印预览,并触发打印对话框。
241
+
242
+ ```typescript
243
+ import { openPrintWindow } from 'print-designer';
244
+
245
+ openPrintWindow({
246
+ template: Band[],
247
+ data: object,
248
+ dataFields?: DataField[],
249
+ pageSettings?: PageSettings,
250
+ });
251
+ // 会打开新窗口并自动调用 window.print()
252
+ ```
253
+
254
+ ## 类型定义
74
255
 
75
- ### DataField 类型
256
+ ### DataField
257
+
258
+ 数据字段定义。
76
259
 
77
260
  ```typescript
78
261
  interface DataField {
79
- name: string; // 字段名
80
- label: string; // 显示名称
81
- type: 'string' | 'number' | 'date' | 'boolean' | 'array';
82
- children?: DataField[]; // 子字段(用于明细数据)
262
+ name: string; // 字段名
263
+ label: string; // 显示名称
264
+ type: 'string' | 'number' | 'currency' | 'date'; // 数据类型
265
+ source: 'master' | 'detail'; // 数据来源:master-主表字段, detail-明细字段
266
+ }
267
+ ```
268
+
269
+ ### Band
270
+
271
+ 带区定义。
272
+
273
+ ```typescript
274
+ interface Band {
275
+ id: 'header' | 'detail' | 'summary' | 'footer'; // 带区ID
276
+ name: string; // 带区名称
277
+ type: string; // 带区类型
278
+ top: number; // 顶部位置
279
+ bottom: number; // 底部位置
280
+ actualBottom: number; // 实际底部位置
281
+ visible: boolean; // 是否可见
282
+ objects: ControlObject[]; // 带区内的控件
283
+ backgroundColor?: string; // 背景色
284
+ backgroundColorFormula?: string; // 背景色公式
285
+ summaryDisplayMode?: 'atEnd' | 'perPage' | 'perGroup'; // 汇总显示模式
286
+ }
287
+ ```
288
+
289
+ ### PageSettings
290
+
291
+ 页面设置。
292
+
293
+ ```typescript
294
+ interface PageSettings {
295
+ paperSize: 'A4' | 'A3' | 'A5' | 'B4' | 'B5' | 'Letter' | 'Legal' | 'Custom';
296
+ width: number; // 纸张宽度
297
+ height: number; // 纸张高度
298
+ unit: 'mm' | 'in'; // 单位
299
+ margins: {
300
+ top: number;
301
+ bottom: number;
302
+ left: number;
303
+ right: number;
304
+ };
305
+ orientation: 'portrait' | 'landscape'; // 纸张方向
306
+ }
307
+ ```
308
+
309
+ ### DesignerOptions
310
+
311
+ 设计器配置。
312
+
313
+ ```typescript
314
+ interface DesignerOptions {
315
+ minBandHeight: number; // 最小带区高度
316
+ defaultBandHeight: number; // 默认带区高度
317
+ showGrid: boolean; // 显示网格
318
+ gridSize: number; // 网格大小
319
+ bandSpacing: number; // 带区间距
83
320
  }
84
321
  ```
85
322
 
86
- ### 导出的组件
323
+ ## 支持的控件类型
324
+
325
+ | 控件类型 | 说明 | 主要属性 |
326
+ |----------|------|----------|
327
+ | `text` | 静态文本 | content, fontSize, color, fontWeight |
328
+ | `field` | 数据字段 | fieldName, format |
329
+ | `calculated` | 计算字段 | formula |
330
+ | `image` | 图片 | src, objectFit, floating |
331
+ | `barcode` | 条形码 | value, barcodeType, showText |
332
+ | `qrcode` | 二维码 | value, errorLevel |
333
+ | `line` | 线条 | x1, y1, x2, y2, strokeWidth, lineStyle |
334
+ | `rectangle` | 矩形 | backgroundColor, border |
335
+ | `page_number` | 页码 | format |
336
+ | `current_date` | 当前日期 | format |
337
+
338
+ ## 导出清单
87
339
 
88
- | 组件 | 说明 |
89
- |------|------|
90
- | BandBoundaryDesigner | 主设计器组件 |
91
- | PrintPreview | 打印预览组件 |
92
- | ObjectPropertyPanel | 对象属性面板 |
93
- | BandPropertyPanel | 带区属性面板 |
94
- | Toolbar | 工具栏 |
95
- | ColorPicker | 颜色选择器 |
96
- | FormulaEditor | 公式编辑器 |
340
+ ### 组件
341
+
342
+ ```typescript
343
+ import {
344
+ BandBoundaryDesigner, // 主设计器组件
345
+ PrintPreview, // 打印预览组件
346
+ ObjectPropertyPanel, // 对象属性面板
347
+ BandPropertyPanel, // 带区属性面板
348
+ Toolbar, // 工具栏
349
+ CanvasArea, // 画布区域
350
+ ColorPicker, // 颜色选择器
351
+ FormulaEditor, // 公式编辑器
352
+ RichTextEditor, // 富文本编辑器
353
+ PageSettingsPanel, // 页面设置面板
354
+ } from 'print-designer';
355
+ ```
356
+
357
+ ### 类型
358
+
359
+ ```typescript
360
+ import type {
361
+ Band,
362
+ ControlObject,
363
+ ControlObjectAll,
364
+ DataField,
365
+ DesignerOptions,
366
+ DesignerState,
367
+ BandBoundaryDesignerProps,
368
+ PageSettings,
369
+ } from 'print-designer';
370
+ ```
97
371
 
98
- ### 导出的工具函数
372
+ ### 工具函数
99
373
 
100
374
  ```typescript
101
375
  import {
376
+ // 渲染工具
102
377
  getBandObjectsRenderData,
103
378
  getObjectRenderData,
379
+ getObjectContent,
380
+
381
+ // 公式工具
104
382
  evaluateFormula,
105
383
  validateFormula,
384
+ registerFunction,
385
+ getRegisteredFunctions,
386
+
387
+ // 打印工具
388
+ renderToHtml,
389
+ exportToPdf,
390
+ getPrintableHtml,
391
+ openPrintWindow,
106
392
  } from 'print-designer';
107
393
  ```
108
394
 
109
- ### 导出的常量
395
+ ### 常量
110
396
 
111
397
  ```typescript
112
398
  import {
113
- controlTypes, // 控件类型列表
114
- defaultBands, // 默认带区配置
115
- borderStyles, // 边框样式选项
116
- fontWeightOptions, // 字体粗细选项
117
- barcodeTypeOptions, // 条码类型选项
118
- // ... 更多常量
399
+ controlTypes, // 控件类型列表
400
+ defaultBands, // 默认带区配置
401
+ defaultOptions, // 默认设计器选项
402
+ defaultPageSettings, // 默认页面设置
403
+ pageSizePresets, // 纸张尺寸预设
404
+ marginPresets, // 边距预设
405
+ fontWeightOptions, // 字体粗细选项
406
+ fontStyleOptions, // 字体样式选项
407
+ textAlignOptions, // 文本对齐选项
408
+ borderStyles, // 边框样式选项
409
+ lineStyleOptions, // 线条样式选项
410
+ dateFormatOptions, // 日期格式选项
411
+ barcodeTypeOptions, // 条码类型选项
412
+ qrcodeErrorLevelOptions, // 二维码容错等级
413
+ getDetailDataKey, // 获取明细数据键名
119
414
  } from 'print-designer';
120
415
  ```
121
416
 
122
- ## 支持的控件类型
417
+ ### Hooks
123
418
 
124
- | 控件 | 说明 |
125
- |------|------|
126
- | text | 静态文本 |
127
- | field | 数据字段 |
128
- | calculated | 计算字段 |
129
- | image | 图片 |
130
- | barcode | 条形码 |
131
- | qrcode | 二维码 |
132
- | line | 线条 |
133
- | rectangle | 矩形 |
134
- | page_number | 页码 |
135
- | current_date | 当前日期 |
419
+ ```typescript
420
+ import {
421
+ useBandDesigner, // 设计器状态管理
422
+ useHistory, // 历史记录(撤销/重做)
423
+ } from 'print-designer';
424
+ ```
425
+
426
+ ## 键盘快捷键
427
+
428
+ | 快捷键 | 功能 |
429
+ |--------|------|
430
+ | `方向键` | 微调选中对象位置 (1px) |
431
+ | `Shift + 方向键` | 快速移动 (10px) |
432
+ | `Alt + 方向键` | 调整对象尺寸 |
433
+ | `Shift + 拖动` | 锁定水平/垂直方向 |
434
+ | `Ctrl/Cmd + C` | 复制 |
435
+ | `Ctrl/Cmd + V` | 粘贴 |
436
+ | `Ctrl/Cmd + Z` | 撤销 |
437
+ | `Ctrl/Cmd + Y` | 重做 |
438
+ | `Delete/Backspace` | 删除选中对象 |
136
439
 
137
440
  ## 浏览器支持
138
441
 
139
- - Chrome (推荐)
140
- - Firefox
141
- - Safari
142
- - Edge
442
+ - Chrome 80+ (推荐)
443
+ - Firefox 75+
444
+ - Safari 13+
445
+ - Edge 80+
446
+
447
+ ## 依赖
448
+
449
+ - React 17+
450
+ - react-rnd (拖拽调整)
451
+ - jspdf (PDF 导出)
452
+ - html2canvas (页面截图)
453
+ - jsbarcode (条形码)
454
+ - qrcode (二维码)
455
+ - dompurify (XSS 防护)
143
456
 
144
457
  ## License
145
458
 
@@ -153,3 +466,4 @@ MIT
153
466
 
154
467
  - [GitHub](https://github.com/chengyihua/print-designer)
155
468
  - [npm](https://www.npmjs.com/package/print-designer)
469
+ - [Issues](https://github.com/chengyihua/print-designer/issues)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "print-designer",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "报表设计器 React 组件库",
5
5
  "main": "dist/print-designer.umd.js",
6
6
  "module": "dist/print-designer.es.js",