print-designer 1.0.3 → 1.0.6

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