@jcyao/print-sdk 1.1.1 → 1.1.3
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/CHANGELOG.md +39 -0
- package/README.md +55 -1
- package/dist/PrintSDK.d.ts +35 -0
- package/dist/index.esm.js +133 -11
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +133 -11
- package/dist/index.js.map +1 -1
- package/dist/sdk.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
所有版本的变更记录都列在这里,遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/) 规范。
|
|
4
4
|
|
|
5
|
+
## [1.1.2] - 2026-05-07
|
|
6
|
+
|
|
7
|
+
### 🐛 问题修复
|
|
8
|
+
|
|
9
|
+
| 问题 | 修复内容 |
|
|
10
|
+
|------|----------|
|
|
11
|
+
| 打印内容偏左 | `@media print` 中 `.print-page` 的 `margin` 未完全覆盖,导致 `auto` margin 在打印时产生偏移 |
|
|
12
|
+
| 批量打印无边距 | `generateBatchPrintStyles` 未设置 `.print-page` 的 `padding`,导致边距功能失效 |
|
|
13
|
+
|
|
14
|
+
### ✨ 新增功能
|
|
15
|
+
|
|
16
|
+
- **多模板批量打印**:新增 `printMultiTemplate` 方法,支持一次打印操作中组合多个不同模板及各自对应的数据列表(一客一模板场景)
|
|
17
|
+
|
|
18
|
+
### 🔧 修复详情
|
|
19
|
+
|
|
20
|
+
#### 1. 打印样式 `@media print` 增强
|
|
21
|
+
|
|
22
|
+
- `body` 样式增加 `!important` 标记,确保打印时完全重置 `margin`、`padding`、`background`
|
|
23
|
+
- `.print-page` 的 `margin-bottom: 0 !important` 改为 `margin: 0 !important`,完全覆盖所有方向的 `auto` margin
|
|
24
|
+
- `.print-page` 的 `box-shadow` 增加 `!important` 标记
|
|
25
|
+
|
|
26
|
+
**影响范围**:`generatePrintPageStyles`、`generateBatchPrintStyles`
|
|
27
|
+
|
|
28
|
+
#### 2. 批量打印边距修复
|
|
29
|
+
|
|
30
|
+
- `generateBatchPrintStyles` 的 `.print-page` 基础样式增加 `padding: ${marginTop}mm ${marginRight}mm ${marginBottom}mm ${marginLeft}mm`
|
|
31
|
+
- 确保批量打印时页面边距功能正常生效
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## [1.1.1] - 2026-01-22
|
|
36
|
+
|
|
37
|
+
### ✨ 新增功能
|
|
38
|
+
|
|
39
|
+
- **表格嵌套对象数据支持**:表格打印支持嵌套对象格式的数据源(如 `{ a: { b: 1 } }`),数据绑定时可通过路径(如 `a.b`)正确解析
|
|
40
|
+
- **服务架构简化**:移除独立 server 服务,改用 Vite mock 集成,降低开发和部署复杂度
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
5
44
|
## [1.1.0] - 2026-04-15
|
|
6
45
|
|
|
7
46
|
### 🎯 重大改进
|
package/README.md
CHANGED
|
@@ -5,7 +5,17 @@
|
|
|
5
5
|
|
|
6
6
|
通用打印 SDK - 客户端打印解决方案
|
|
7
7
|
|
|
8
|
-
**当前版本**: v1.1.
|
|
8
|
+
**当前版本**: v1.1.2
|
|
9
|
+
|
|
10
|
+
## 🆕 v1.1.2 问题修复
|
|
11
|
+
|
|
12
|
+
- 🐛 **打印内容偏移修复**:`@media print` 中 `.print-page` 的 `margin` 完全覆盖,解决打印内容偏左问题
|
|
13
|
+
- 🐛 **批量打印边距修复**:`generateBatchPrintStyles` 增加 `padding` 设置,批量打印边距功能正常生效
|
|
14
|
+
|
|
15
|
+
## 🆕 v1.1.1 新增功能
|
|
16
|
+
|
|
17
|
+
- ✨ **表格嵌套对象数据支持**:表格打印支持嵌套对象格式的数据源
|
|
18
|
+
- 🔧 **服务架构简化**:移除独立 server 服务,改用 Vite mock 集成
|
|
9
19
|
|
|
10
20
|
## 🆕 v1.1.0 重大改进
|
|
11
21
|
|
|
@@ -128,6 +138,50 @@ await sdk.printMultiple(myTemplate, dataList, {
|
|
|
128
138
|
});
|
|
129
139
|
```
|
|
130
140
|
|
|
141
|
+
### `sdk.printMultiTemplate(groups, options)`
|
|
142
|
+
|
|
143
|
+
多模板批量打印(多模板 + 各自对应的数据列表)。
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
await sdk.printMultiTemplate([
|
|
147
|
+
{ template: templateA, dataList: [dataA1, dataA2] },
|
|
148
|
+
{ template: templateB, dataList: [dataB1] },
|
|
149
|
+
], {
|
|
150
|
+
preview: true,
|
|
151
|
+
onProgress: (progress) => {
|
|
152
|
+
console.log(
|
|
153
|
+
`组: ${progress.completedGroups}/${progress.totalGroups}, 数据: ${progress.completedDataItems}/${progress.totalDataItems}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**参数:**
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface PrintTemplateGroup {
|
|
163
|
+
template: PrintTemplate;
|
|
164
|
+
dataList: any[];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface MultiTemplatePrintOptions {
|
|
168
|
+
preview?: boolean;
|
|
169
|
+
onProgress?: (progress: MultiTemplatePrintProgress) => void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface MultiTemplatePrintProgress {
|
|
173
|
+
totalGroups: number; // 模板组总数
|
|
174
|
+
completedGroups: number; // 已完成组数
|
|
175
|
+
totalDataItems: number; // 总数据条目
|
|
176
|
+
completedDataItems: number; // 已完成数据条目
|
|
177
|
+
failed: number; // 失败条目数
|
|
178
|
+
currentGroupIndex: number; // 当前处理组索引
|
|
179
|
+
currentDataIndex: number; // 当前处理数据索引
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> ⚠️ **已知限制**:所有模板必须使用相同的纸张尺寸和边距设置。混合纸张尺寸暂不支持。
|
|
184
|
+
|
|
131
185
|
## 🎨 支持的组件
|
|
132
186
|
|
|
133
187
|
- **文本组件** - 显示文本内容,支持标签和数据绑定
|
package/dist/PrintSDK.d.ts
CHANGED
|
@@ -28,6 +28,32 @@ export interface BatchPrintProgress {
|
|
|
28
28
|
failed: number;
|
|
29
29
|
currentIndex: number;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 模板 + 数据组
|
|
33
|
+
*/
|
|
34
|
+
export interface PrintTemplateGroup {
|
|
35
|
+
template: PrintTemplate;
|
|
36
|
+
dataList: any[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 多模板打印选项
|
|
40
|
+
*/
|
|
41
|
+
export interface MultiTemplatePrintOptions {
|
|
42
|
+
preview?: boolean;
|
|
43
|
+
onProgress?: (progress: MultiTemplatePrintProgress) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 多模板打印进度
|
|
47
|
+
*/
|
|
48
|
+
export interface MultiTemplatePrintProgress {
|
|
49
|
+
totalGroups: number;
|
|
50
|
+
completedGroups: number;
|
|
51
|
+
totalDataItems: number;
|
|
52
|
+
completedDataItems: number;
|
|
53
|
+
failed: number;
|
|
54
|
+
currentGroupIndex: number;
|
|
55
|
+
currentDataIndex: number;
|
|
56
|
+
}
|
|
31
57
|
export declare class PrintSDK {
|
|
32
58
|
/**
|
|
33
59
|
* 打印
|
|
@@ -64,6 +90,15 @@ export declare class PrintSDK {
|
|
|
64
90
|
* @param options 批量打印选项
|
|
65
91
|
*/
|
|
66
92
|
printMultiple(template: PrintTemplate, dataList: any[], options?: BatchPrintOptions): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* 多模板批量打印
|
|
95
|
+
* 支持多个模板各自绑定数据列表,一次打印确认
|
|
96
|
+
*
|
|
97
|
+
* 注意:所有模板需使用相同纸张尺寸,混合尺寸暂不支持
|
|
98
|
+
* @param groups 模板+数据组列表
|
|
99
|
+
* @param options 打印选项
|
|
100
|
+
*/
|
|
101
|
+
printMultiTemplate(groups: PrintTemplateGroup[], options?: MultiTemplatePrintOptions): Promise<void>;
|
|
67
102
|
}
|
|
68
103
|
/**
|
|
69
104
|
* 创建 SDK 实例(无需配置)
|
package/dist/index.esm.js
CHANGED
|
@@ -209,8 +209,9 @@ function generatePrintPageStyles(config) {
|
|
|
209
209
|
|
|
210
210
|
@media print {
|
|
211
211
|
body {
|
|
212
|
-
|
|
213
|
-
padding: 0;
|
|
212
|
+
margin: 0 !important;
|
|
213
|
+
padding: 0 !important;
|
|
214
|
+
background: white !important;
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
@page {
|
|
@@ -219,9 +220,9 @@ function generatePrintPageStyles(config) {
|
|
|
219
220
|
}
|
|
220
221
|
|
|
221
222
|
.print-page {
|
|
223
|
+
margin: 0 !important;
|
|
224
|
+
box-shadow: none !important;
|
|
222
225
|
page-break-after: always;
|
|
223
|
-
margin-bottom: 0 !important;
|
|
224
|
-
box-shadow: none; /* 移除阴影 */
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
.print-page:last-child {
|
|
@@ -248,7 +249,7 @@ function generatePrintPageStyles(config) {
|
|
|
248
249
|
* 用于 PrintSDK 的 printMultiple
|
|
249
250
|
*/
|
|
250
251
|
function generateBatchPrintStyles(config) {
|
|
251
|
-
const { pageWidthMm, pageHeightMm, isContinuous = false, minHeightMm = 100, } = config;
|
|
252
|
+
const { pageWidthMm, pageHeightMm, marginTop = 0, marginRight = 0, marginBottom = 0, marginLeft = 0, isContinuous = false, minHeightMm = 100, } = config;
|
|
252
253
|
return `
|
|
253
254
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
254
255
|
body { margin: 0; padding: 0; background: #f5f5f5; }
|
|
@@ -259,8 +260,8 @@ function generateBatchPrintStyles(config) {
|
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
@media print {
|
|
262
|
-
body { margin: 0; padding: 0; background: white; }
|
|
263
|
-
.print-page { margin: 0; page-break-after: always; box-shadow: none !important; }
|
|
263
|
+
body { margin: 0 !important; padding: 0 !important; background: white !important; }
|
|
264
|
+
.print-page { margin: 0 !important; page-break-after: always; box-shadow: none !important; }
|
|
264
265
|
.print-page:last-child { page-break-after: auto; }
|
|
265
266
|
}
|
|
266
267
|
|
|
@@ -271,7 +272,7 @@ function generateBatchPrintStyles(config) {
|
|
|
271
272
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
272
273
|
}
|
|
273
274
|
}
|
|
274
|
-
|
|
275
|
+
|
|
275
276
|
.print-page {
|
|
276
277
|
width: ${pageWidthMm}mm;
|
|
277
278
|
height: ${isContinuous ? 'auto' : pageHeightMm + 'mm'};
|
|
@@ -279,6 +280,7 @@ function generateBatchPrintStyles(config) {
|
|
|
279
280
|
background: white;
|
|
280
281
|
position: relative;
|
|
281
282
|
box-sizing: border-box;
|
|
283
|
+
padding: ${marginTop}mm ${marginRight}mm ${marginBottom}mm ${marginLeft}mm;
|
|
282
284
|
}
|
|
283
285
|
|
|
284
286
|
${generateComponentStyles()}
|
|
@@ -1991,7 +1993,7 @@ class PrintSDK {
|
|
|
1991
1993
|
* @param options 批量打印选项
|
|
1992
1994
|
*/
|
|
1993
1995
|
async printMultiple(template, dataList, options = {}) {
|
|
1994
|
-
var _a, _b;
|
|
1996
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1995
1997
|
const { preview = false, onProgress, } = options;
|
|
1996
1998
|
const { page } = template;
|
|
1997
1999
|
const progress = {
|
|
@@ -2034,6 +2036,10 @@ class PrintSDK {
|
|
|
2034
2036
|
const styles = generateBatchPrintStyles({
|
|
2035
2037
|
pageWidthMm,
|
|
2036
2038
|
pageHeightMm,
|
|
2039
|
+
marginTop: (_b = (_a = page.marginMm) === null || _a === void 0 ? void 0 : _a.top) !== null && _b !== void 0 ? _b : 0,
|
|
2040
|
+
marginRight: (_d = (_c = page.marginMm) === null || _c === void 0 ? void 0 : _c.right) !== null && _d !== void 0 ? _d : 0,
|
|
2041
|
+
marginBottom: (_f = (_e = page.marginMm) === null || _e === void 0 ? void 0 : _e.bottom) !== null && _f !== void 0 ? _f : 0,
|
|
2042
|
+
marginLeft: (_h = (_g = page.marginMm) === null || _g === void 0 ? void 0 : _g.left) !== null && _h !== void 0 ? _h : 0,
|
|
2037
2043
|
isContinuous: page.size === 'CONTINUOUS',
|
|
2038
2044
|
minHeightMm: page.minHeightMm,
|
|
2039
2045
|
});
|
|
@@ -2063,7 +2069,7 @@ class PrintSDK {
|
|
|
2063
2069
|
iframe.style.top = '-9999px';
|
|
2064
2070
|
iframe.style.left = '-9999px';
|
|
2065
2071
|
document.body.appendChild(iframe);
|
|
2066
|
-
const iframeDoc = (
|
|
2072
|
+
const iframeDoc = (_j = iframe.contentWindow) === null || _j === void 0 ? void 0 : _j.document;
|
|
2067
2073
|
if (!iframeDoc) {
|
|
2068
2074
|
throw new Error('Failed to access iframe document');
|
|
2069
2075
|
}
|
|
@@ -2071,13 +2077,129 @@ class PrintSDK {
|
|
|
2071
2077
|
iframeDoc.close();
|
|
2072
2078
|
// 等待所有图片加载完成后再打印
|
|
2073
2079
|
await waitForImagesLoaded(iframeDoc);
|
|
2074
|
-
(
|
|
2080
|
+
(_k = iframe.contentWindow) === null || _k === void 0 ? void 0 : _k.print();
|
|
2075
2081
|
// 打印完成后移除 iframe
|
|
2076
2082
|
setTimeout(() => {
|
|
2077
2083
|
document.body.removeChild(iframe);
|
|
2078
2084
|
}, 1000);
|
|
2079
2085
|
}
|
|
2080
2086
|
}
|
|
2087
|
+
/**
|
|
2088
|
+
* 多模板批量打印
|
|
2089
|
+
* 支持多个模板各自绑定数据列表,一次打印确认
|
|
2090
|
+
*
|
|
2091
|
+
* 注意:所有模板需使用相同纸张尺寸,混合尺寸暂不支持
|
|
2092
|
+
* @param groups 模板+数据组列表
|
|
2093
|
+
* @param options 打印选项
|
|
2094
|
+
*/
|
|
2095
|
+
async printMultiTemplate(groups, options = {}) {
|
|
2096
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2097
|
+
const { preview = false, onProgress } = options;
|
|
2098
|
+
if (!groups || groups.length === 0) {
|
|
2099
|
+
console.warn('[PrintSDK] printMultiTemplate: groups 为空,跳过打印');
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
const totalDataItems = groups.reduce((sum, g) => sum + g.dataList.length, 0);
|
|
2103
|
+
const progress = {
|
|
2104
|
+
totalGroups: groups.length,
|
|
2105
|
+
completedGroups: 0,
|
|
2106
|
+
totalDataItems,
|
|
2107
|
+
completedDataItems: 0,
|
|
2108
|
+
failed: 0,
|
|
2109
|
+
currentGroupIndex: 0,
|
|
2110
|
+
currentDataIndex: -1,
|
|
2111
|
+
};
|
|
2112
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2113
|
+
const allPagesHTML = [];
|
|
2114
|
+
for (let groupIdx = 0; groupIdx < groups.length; groupIdx++) {
|
|
2115
|
+
const group = groups[groupIdx];
|
|
2116
|
+
progress.currentGroupIndex = groupIdx;
|
|
2117
|
+
progress.currentDataIndex = -1;
|
|
2118
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2119
|
+
for (let dataIdx = 0; dataIdx < group.dataList.length; dataIdx++) {
|
|
2120
|
+
const data = group.dataList[dataIdx];
|
|
2121
|
+
progress.currentDataIndex = dataIdx;
|
|
2122
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2123
|
+
try {
|
|
2124
|
+
const engine = createPrintEngine(group.template, data);
|
|
2125
|
+
const html = await engine.generatePrintHTML();
|
|
2126
|
+
const bodyContent = extractBodyContent(html);
|
|
2127
|
+
if (bodyContent) {
|
|
2128
|
+
allPagesHTML.push(bodyContent);
|
|
2129
|
+
}
|
|
2130
|
+
progress.completedDataItems++;
|
|
2131
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2132
|
+
}
|
|
2133
|
+
catch (error) {
|
|
2134
|
+
progress.failed++;
|
|
2135
|
+
progress.completedDataItems++;
|
|
2136
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2137
|
+
console.error(`[PrintSDK] 处理失败: groupIndex=${groupIdx}, dataIndex=${dataIdx}`, error);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
progress.completedGroups++;
|
|
2141
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2142
|
+
}
|
|
2143
|
+
progress.currentGroupIndex = -1;
|
|
2144
|
+
progress.currentDataIndex = -1;
|
|
2145
|
+
onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
|
|
2146
|
+
const { page } = groups[0].template;
|
|
2147
|
+
const { widthMm: pageWidthMm, heightMm: pageHeightMm } = getPageSizeFromConfig(page);
|
|
2148
|
+
const styles = generateBatchPrintStyles({
|
|
2149
|
+
pageWidthMm,
|
|
2150
|
+
pageHeightMm,
|
|
2151
|
+
marginTop: (_b = (_a = page.marginMm) === null || _a === void 0 ? void 0 : _a.top) !== null && _b !== void 0 ? _b : 0,
|
|
2152
|
+
marginRight: (_d = (_c = page.marginMm) === null || _c === void 0 ? void 0 : _c.right) !== null && _d !== void 0 ? _d : 0,
|
|
2153
|
+
marginBottom: (_f = (_e = page.marginMm) === null || _e === void 0 ? void 0 : _e.bottom) !== null && _f !== void 0 ? _f : 0,
|
|
2154
|
+
marginLeft: (_h = (_g = page.marginMm) === null || _g === void 0 ? void 0 : _g.left) !== null && _h !== void 0 ? _h : 0,
|
|
2155
|
+
isContinuous: page.size === 'CONTINUOUS',
|
|
2156
|
+
minHeightMm: page.minHeightMm,
|
|
2157
|
+
});
|
|
2158
|
+
const fullHTML = generatePrintHTML({
|
|
2159
|
+
title: '多模板批量打印',
|
|
2160
|
+
styles,
|
|
2161
|
+
bodyContent: allPagesHTML.join('\n'),
|
|
2162
|
+
});
|
|
2163
|
+
if (preview) {
|
|
2164
|
+
const printWindow = window.open('', '_blank');
|
|
2165
|
+
if (!printWindow) {
|
|
2166
|
+
throw new Error('Failed to open print window');
|
|
2167
|
+
}
|
|
2168
|
+
printWindow.document.write(fullHTML);
|
|
2169
|
+
printWindow.document.close();
|
|
2170
|
+
await waitForImagesLoaded(printWindow.document);
|
|
2171
|
+
printWindow.print();
|
|
2172
|
+
}
|
|
2173
|
+
else {
|
|
2174
|
+
const iframe = document.createElement('iframe');
|
|
2175
|
+
iframe.style.position = 'fixed';
|
|
2176
|
+
iframe.style.top = '-9999px';
|
|
2177
|
+
iframe.style.left = '-9999px';
|
|
2178
|
+
document.body.appendChild(iframe);
|
|
2179
|
+
const iframeDoc = (_j = iframe.contentWindow) === null || _j === void 0 ? void 0 : _j.document;
|
|
2180
|
+
if (!iframeDoc) {
|
|
2181
|
+
throw new Error('Failed to access iframe document');
|
|
2182
|
+
}
|
|
2183
|
+
iframeDoc.write(fullHTML);
|
|
2184
|
+
iframeDoc.close();
|
|
2185
|
+
await waitForImagesLoaded(iframeDoc);
|
|
2186
|
+
const cleanup = () => {
|
|
2187
|
+
if (iframe.parentNode) {
|
|
2188
|
+
document.body.removeChild(iframe);
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
if (iframe.contentWindow) {
|
|
2192
|
+
iframe.contentWindow.addEventListener('afterprint', cleanup, { once: true });
|
|
2193
|
+
}
|
|
2194
|
+
(_k = iframe.contentWindow) === null || _k === void 0 ? void 0 : _k.print();
|
|
2195
|
+
setTimeout(() => {
|
|
2196
|
+
if (iframe.parentNode) {
|
|
2197
|
+
console.warn('[PrintSDK] afterprint 事件未触发,执行兜底清理');
|
|
2198
|
+
cleanup();
|
|
2199
|
+
}
|
|
2200
|
+
}, 5000);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2081
2203
|
}
|
|
2082
2204
|
/**
|
|
2083
2205
|
* 创建 SDK 实例(无需配置)
|