yh-hiprint 2.6.13 → 2.6.15

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/index.ts ADDED
@@ -0,0 +1,539 @@
1
+ import './libs/jquery';
2
+ import {
3
+ ElDialog,
4
+ ElSelect,
5
+ ElOption,
6
+ ElButton,
7
+ ElMessageBox,
8
+ ElLoading,
9
+ ElMessage,
10
+ } from 'element-plus';
11
+ import {createApp, createVNode} from 'vue';
12
+ import {
13
+ hiprint,
14
+ defaultElementTypeProvider,
15
+ print,
16
+ print2,
17
+ usePaper,
18
+ useScale,
19
+ useDataSource,
20
+ } from './hooks/useHiprint';
21
+ export {hiprint, defaultElementTypeProvider, print, print2, usePaper, useScale, useDataSource};
22
+ export {default as fontSize} from './font-size';
23
+ export {default as scale} from './scale';
24
+ export {default as zIndex} from './z-index';
25
+ export {default as panel} from './panel';
26
+ import {getPrintTemplate} from './libs/index.js';
27
+ export {default as defaultPrintElement} from './store/defaultPrintElement';
28
+ export {getPrintTemplate};
29
+
30
+ export function guid(): string {
31
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (t) {
32
+ var e = (16 * Math.random()) | 0;
33
+ return ('x' == t ? e : (3 & e) | 8).toString(16);
34
+ });
35
+ }
36
+
37
+ // 定义类型
38
+ interface HiprintFunParams {
39
+ code: string;
40
+ params?: any;
41
+ data?: any;
42
+ isCustom?: boolean;
43
+ returnHtml?: boolean;
44
+ }
45
+
46
+ interface SilentHiprintParams {
47
+ code: string;
48
+ params?: any;
49
+ data?: any;
50
+ }
51
+
52
+ interface MessageEvent {
53
+ data: {
54
+ type: string;
55
+ data: any;
56
+ };
57
+ }
58
+
59
+ interface TemplateResponse {
60
+ status: number;
61
+ data?: {
62
+ json: string;
63
+ };
64
+ message?: string;
65
+ }
66
+
67
+ interface HiprintTemplate {
68
+ new (options: {template: any}): any;
69
+ getHtml(data: any): Array<{innerHTML: string}>;
70
+ }
71
+
72
+ interface CustomWindow extends Window {
73
+ silentHiprint: typeof silentHiprint;
74
+ }
75
+
76
+ export function cLog(string: string, isError: boolean = false): void {
77
+ if (isError) {
78
+ console.error(
79
+ '%cyhHiprint:%c',
80
+ 'font-size: 16px;font-weight: bold;color: #00ffff',
81
+ 'font-size: 16px;font-weight: bold;color: #ccccc',
82
+ string
83
+ );
84
+ } else {
85
+ console.log(
86
+ '%cyhHiprint%c ' + string,
87
+ 'font-size: 18px;font-weight: bold;color: #61AFEF',
88
+ 'font-size: 12px;color: #999'
89
+ );
90
+ }
91
+ }
92
+
93
+ const hiprintFun = async ({
94
+ code,
95
+ params,
96
+ data,
97
+ isCustom,
98
+ returnHtml,
99
+ }: HiprintFunParams): Promise<any> => {
100
+ if (window.electronBrowserAPI && window.electronBrowserAPI.print) {
101
+ return clientPrintHandler(code, params, data);
102
+ } else {
103
+ const height: number = document.documentElement.clientHeight;
104
+ const width: number = 1200;
105
+ const left: number = (document.documentElement.clientWidth - 1200) / 2;
106
+ // 转换数组
107
+ let paramData: any = params;
108
+ if (!Array.isArray(params)) {
109
+ paramData = [params];
110
+ }
111
+ let url: string = '/hiprint/#/preview?code=' + encodeURIComponent(code);
112
+ if (params) {
113
+ url += `&params=${encodeURIComponent(JSON.stringify(paramData))}`;
114
+ }
115
+ if (data) {
116
+ url += `&data=${encodeURIComponent(JSON.stringify(data))}`;
117
+ }
118
+ if (isCustom) {
119
+ url += `&isCustom=${isCustom ? '1' : '0'}`;
120
+ }
121
+ if (returnHtml) {
122
+ url += `&returnHtml=${returnHtml ? '1' : '0'}`;
123
+ }
124
+ const windowOpen = window.open(
125
+ url,
126
+ 'hiprintWindow',
127
+ `height=${height}, width=${width}, top=20, left=${left}, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no`
128
+ );
129
+
130
+ return new Promise((resolve, reject) => {
131
+ if (!windowOpen) {
132
+ reject('预览窗口渲染失败!');
133
+ return;
134
+ }
135
+ function printHTMLHandler(e: MessageEvent): void {
136
+ const {type, data} = e.data;
137
+ if (type === 'sendPrintHTML' && data) {
138
+ resolve(data);
139
+ }
140
+ window.removeEventListener('message', printHTMLHandler);
141
+ }
142
+ window.addEventListener('message', printHTMLHandler);
143
+ });
144
+ }
145
+ };
146
+
147
+ const silentHiprint = async ({
148
+ code,
149
+ params = {},
150
+ data,
151
+ }: SilentHiprintParams): Promise<string | boolean> => {
152
+ if (!code || !data) {
153
+ ElMessageBox.alert('请正确的传递模板编号和打印数据', '提示');
154
+ return false;
155
+ }
156
+ let loading: any = null;
157
+ try {
158
+ loading = ElLoading.service({
159
+ text: '正在获取打印模板',
160
+ });
161
+ const res: TemplateResponse = await getPrintTemplate(code, params);
162
+ if (res.status === 200 && res.data && res.data.json) {
163
+ const json: string = res.data.json;
164
+ const hiprintTemplate: HiprintTemplate = new (hiprint as any).PrintTemplate({
165
+ template: JSON.parse(json),
166
+ });
167
+ const html: Array<{innerHTML: string}> = hiprintTemplate.getHtml(data);
168
+ if (html[0]) {
169
+ return html[0].innerHTML;
170
+ } else {
171
+ ElMessageBox.alert('打印内容渲染失败', '提示');
172
+ }
173
+ } else {
174
+ ElMessageBox.alert(res.message || '获取打印模板失败', '提示');
175
+ }
176
+ } catch (error) {
177
+ if (loading) {
178
+ loading.close();
179
+ loading = null;
180
+ }
181
+ console.error(error);
182
+ } finally {
183
+ if (loading) {
184
+ loading.close();
185
+ loading = null;
186
+ }
187
+ }
188
+ return false;
189
+ };
190
+
191
+ (window as unknown as CustomWindow).silentHiprint = silentHiprint;
192
+
193
+ interface InstallOptions {
194
+ router?: any;
195
+ pinia?: any;
196
+ isAdmin?: boolean;
197
+ isNew?: boolean;
198
+ addInitTask: (any) => {}
199
+ }
200
+
201
+ // 客户端打印处理函数
202
+ const clientPrintHandler = async (code, params, data) => {
203
+ let loading = null;
204
+ try {
205
+ loading = ElLoading.service({
206
+ text: '正在获取打印模板',
207
+ });
208
+ let reqParams = [];
209
+ try {
210
+ reqParams = params ? JSON.parse(params) : [];
211
+ } catch (error) {
212
+ console.error(error);
213
+ }
214
+ // 获取打印模板
215
+ let res = await getPrintTemplate(code, reqParams);
216
+ if (res.status !== 200 || !res.data || !res.data.json) {
217
+ ElMessageBox.alert(res.message || '获取打印模板失败', '提示');
218
+ return false;
219
+ }
220
+
221
+ loading.setText('正在连接打印客户端');
222
+
223
+ // 获取打印机列表
224
+ let printerList = await electronBrowserAPI.getPrinterList();
225
+ if (!printerList || printerList.length === 0) {
226
+ loading?.close();
227
+ ElMessageBox.alert('未获取到打印机列表', '提示');
228
+ return false;
229
+ }
230
+
231
+ loading.close();
232
+ loading = null;
233
+
234
+ // 显示选择打印机的对话框
235
+ return await showPrinterSelectionDialog(
236
+ printerList,
237
+ res.data.json,
238
+ res.data.list,
239
+ res.data.name,
240
+ data
241
+ );
242
+ } catch (error) {
243
+ if (loading) {
244
+ loading.close();
245
+ loading = null;
246
+ }
247
+ console.error(error);
248
+ ElMessageBox.alert('客户端打印出错: ' + error.message, '提示');
249
+ return false;
250
+ }
251
+ };
252
+
253
+ // 显示打印机选择对话框
254
+ const showPrinterSelectionDialog = (
255
+ printerList,
256
+ templateJson,
257
+ templateData,
258
+ templateName,
259
+ data
260
+ ) => {
261
+ return new Promise((resolve) => {
262
+ // 获取上次选择的打印机
263
+ const lastSelectedPrinter = localStorage.getItem('lastSelectedPrinter') || '';
264
+
265
+ let json = {};
266
+ try {
267
+ json = JSON.parse(templateJson);
268
+ } catch (error) {
269
+ console.error('客户端打印解析模板失败:', error);
270
+ ElMessageBox.alert('客户端打印解析模板失败', '提示');
271
+ document.body.removeChild(mountPoint);
272
+ resolve(false);
273
+ return;
274
+ }
275
+ // 创建挂载点
276
+ const mountPoint = document.createElement('div');
277
+ document.body.appendChild(mountPoint);
278
+
279
+ // 创建Vue组件
280
+ const PrinterSelectorComponent = {
281
+ components: {
282
+ ElDialog,
283
+ ElSelect,
284
+ ElOption,
285
+ ElButton,
286
+ },
287
+ data() {
288
+ return {
289
+ visible: true,
290
+ selectedPrinter: lastSelectedPrinter,
291
+ printerList: printerList,
292
+ };
293
+ },
294
+ methods: {
295
+ handlePrint: async function () {
296
+ if (!this.selectedPrinter) {
297
+ ElMessageBox.alert('请选择打印机', '提示');
298
+ return;
299
+ }
300
+ // 保存选择的打印机
301
+ localStorage.setItem('lastSelectedPrinter', this.selectedPrinter);
302
+
303
+ let loading = ElLoading.service({
304
+ text: '正在渲染打印内容',
305
+ });
306
+
307
+ try {
308
+ // 创建打印模板实例
309
+ let hiprintTemplate = new hiprint.PrintTemplate({template: json});
310
+
311
+ loading.setText('正在发送打印任务');
312
+ const newGuid = guid();
313
+ const printOption = {
314
+ printer: this.selectedPrinter,
315
+ title: templateName,
316
+ imgToBase64: true,
317
+ id: newGuid,
318
+ templateId: newGuid,
319
+ pageSize: {
320
+ width: (json?.panels[0]?.width || 210) * 1000,
321
+ height: (json?.panels[0]?.height || 297) * 1000,
322
+ },
323
+ };
324
+ const pCss = `<style rel="stylesheet" type="text/css">${printCss}</style>`;
325
+ const html = hiprintTemplate.getHtml(data || templateData, printOption)[0].outerHTML;
326
+
327
+ printOption.html = `${pCss}${html}`;
328
+
329
+ // 监听打印结果
330
+ const handlePrintResult = (event) => {
331
+ if (event.data && event.data.type) {
332
+ switch (event.data.type) {
333
+ case 'PRINT_SUCCESS':
334
+ loading.close();
335
+ this.handleClose(true);
336
+ ElMessage.success('打印任务已发送到打印机');
337
+ // 移除事件监听器
338
+ window.removeEventListener('message', handlePrintResult);
339
+ clearTimeout(timeoutId);
340
+ break;
341
+ case 'PRINT_ERROR':
342
+ loading.close();
343
+ const error = event.data.data;
344
+ ElMessageBox.alert('打印失败: ' + (error.msg || '未知错误'), '提示');
345
+ this.handleClose(false);
346
+ // 移除事件监听器
347
+ window.removeEventListener('message', handlePrintResult);
348
+ clearTimeout(timeoutId);
349
+ break;
350
+ default:
351
+ break;
352
+ }
353
+ }
354
+ };
355
+
356
+ // 添加事件监听器
357
+ window.addEventListener('message', handlePrintResult);
358
+
359
+ // 添加超时机制,防止监听器泄漏
360
+ const timeoutId = setTimeout(() => {
361
+ window.removeEventListener('message', handlePrintResult);
362
+ loading.close();
363
+ ElMessageBox.alert('打印超时', '提示');
364
+ this.handleClose(false);
365
+ }, 60 * 1000); // 30秒超时
366
+
367
+ // 发送到客户端打印
368
+ try {
369
+ electronBrowserAPI.print(printOption);
370
+ } catch (error) {
371
+ console.error('客户端打印发送失败:', error);
372
+ loading.close();
373
+ window.removeEventListener('message', handlePrintResult);
374
+ clearTimeout(timeoutId);
375
+ ElMessageBox.alert('客户端打印发送失败: ' + error.message, '提示');
376
+ this.handleClose(false);
377
+ }
378
+ } catch (error) {
379
+ if (loading) {
380
+ loading.close();
381
+ }
382
+ console.error(error);
383
+ ElMessageBox.alert('打印过程中发生错误: ' + error.message, '提示');
384
+ this.handleClose(false);
385
+ }
386
+ },
387
+ handleClose: function (result = false) {
388
+ this.visible = false;
389
+ // 移除固定延迟,直接执行卸载逻辑
390
+ app.unmount();
391
+ document.body.removeChild(mountPoint);
392
+ resolve(result);
393
+ },
394
+ },
395
+ render() {
396
+ return createVNode(
397
+ ElDialog,
398
+ {
399
+ modelValue: this.visible,
400
+ title: '选择打印机',
401
+ width: '500px',
402
+ onClose: () => this.handleClose(false),
403
+ onClosed: () => this.handleClose(false),
404
+ },
405
+ {
406
+ default: () => [
407
+ createVNode(
408
+ ElSelect,
409
+ {
410
+ modelValue: this.selectedPrinter,
411
+ 'onUpdate:modelValue': (val) => {
412
+ this.selectedPrinter = val;
413
+ },
414
+ placeholder: '请选择打印机',
415
+ style: 'width: 100%; margin-bottom: 15px;',
416
+ },
417
+ {
418
+ default: () =>
419
+ this.printerList.map((printer) =>
420
+ createVNode(ElOption, {
421
+ key: printer.name,
422
+ label: printer.name,
423
+ value: printer.name,
424
+ })
425
+ ),
426
+ }
427
+ ),
428
+ ],
429
+ footer: () => [
430
+ createVNode('span', {class: 'dialog-footer'}, [
431
+ createVNode(
432
+ ElButton,
433
+ {
434
+ onClick: () => this.handleClose(false),
435
+ },
436
+ {
437
+ default: () => '取消',
438
+ }
439
+ ),
440
+ createVNode(
441
+ ElButton,
442
+ {
443
+ type: 'primary',
444
+ onClick: this.handlePrint,
445
+ },
446
+ {
447
+ default: () => '打印',
448
+ }
449
+ ),
450
+ ]),
451
+ ],
452
+ }
453
+ );
454
+ },
455
+ };
456
+
457
+ // 创建应用实例
458
+ const app = createApp(PrinterSelectorComponent);
459
+
460
+ // 挂载应用
461
+ app.mount(mountPoint);
462
+ });
463
+ };
464
+
465
+ // window.silentHiprint = silentHiprint;
466
+
467
+ // 添加必要的类型定义
468
+ interface ElectronBrowserAPI {
469
+ print: (options: any) => void;
470
+ getPrinterList: () => Promise<any[]>;
471
+ }
472
+
473
+ declare global {
474
+ interface Window {
475
+ electronBrowserAPI?: ElectronBrowserAPI;
476
+ }
477
+ }
478
+
479
+ // 导入打印样式
480
+ import printCss from './libs/css/hiprint.css?inline';
481
+
482
+ export default {
483
+ install(
484
+ app: any,
485
+ {router, pinia, clientPrint = false,isNew = false, addInitTask}: InstallOptions & {clientPrint?: boolean}
486
+ ): void {
487
+ app.provide('$hiprint', hiprintFun);
488
+ app.provide('$silentHiprint', silentHiprint);
489
+
490
+ if(isNew) {
491
+ addInitTask(async () => {
492
+ if (!router || router.hasRoute('Index')) return;
493
+ router.addRoute('Index', {
494
+ path: 'hiprint/designer',
495
+ name: '打印设计器',
496
+ meta: {
497
+ icon: 'md-planet',
498
+ title: '打印设计器',
499
+ },
500
+ component: () => import('./HiprintDesigner.vue'),
501
+ });
502
+ router.addRoute({
503
+ path: '/preview',
504
+ name: 'printView',
505
+ meta: {
506
+ icon: 'md-planet',
507
+ title: 'printView',
508
+ },
509
+ component: () => import('./hiprintPreview.vue'),
510
+ });
511
+ })
512
+ } else {
513
+ if (router) {
514
+ router.addRoute('Index', {
515
+ path: 'hiprint/designer',
516
+ name: '打印设计器',
517
+ meta: {
518
+ icon: 'md-planet',
519
+ title: '打印设计器',
520
+ },
521
+ component: () => import('./HiprintDesigner.vue'),
522
+ });
523
+ router.addRoute({
524
+ path: '/preview',
525
+ name: 'printView',
526
+ meta: {
527
+ icon: 'md-planet',
528
+ title: 'printView',
529
+ },
530
+ component: () => import('./hiprintPreview.vue'),
531
+ });
532
+ } else {
533
+ if (!router) {
534
+ cLog('没有传递 router 对象,所以无法将路由添加到应用中', true);
535
+ }
536
+ }
537
+ }
538
+ },
539
+ };
package/libs/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import axios from '@/libs/api.request.js';
1
+ import http from '@/libs/api.request';
2
2
  export function getPrintTemplate (code, reqParams) {
3
- return axios
3
+ return http
4
4
  .request({
5
5
  url: `/printTemplate/data/${code}`,
6
6
  method: 'post',
@@ -0,0 +1,55 @@
1
+ // @ts-ignore
2
+ import axios from '@/libs/api.request';
3
+ import {ElMessage, ElMessageBox} from 'element-plus';
4
+ import {hiprint} from 'yh-hiprint';
5
+
6
+ export default async function (code) {
7
+ let {
8
+ data: {list, json},
9
+ } = await axios.request({
10
+ url: `/printTemplate/data/${code}`,
11
+ method: 'post',
12
+ type: 'json',
13
+ data: [
14
+ {
15
+ code: '50101820',
16
+ },
17
+ ],
18
+ });
19
+ if (json) {
20
+ if (Array.isArray(list) && list.length > 0) {
21
+ list = list.map((item) => {
22
+ let printData = {};
23
+ let datas = Object.entries(item);
24
+ datas.forEach((arr) => {
25
+ if (Array.isArray(arr[1])) {
26
+ printData[arr[0]] = arr[1];
27
+ } else {
28
+ if (arr[1] !== null && arr[1] !== undefined) {
29
+ let itemsEntries = Object.entries(arr[1]);
30
+ itemsEntries.forEach((cArr) => {
31
+ printData[`$${arr[0]}[${cArr[0]}]`] = cArr[1];
32
+ });
33
+ }
34
+ }
35
+ });
36
+ return printData;
37
+ });
38
+ } else {
39
+ list = [];
40
+ }
41
+ const htmlStr = new hiprint.PrintTemplate({template: JSON.parse(json)}).getHtml(list)[0].innerHTML;
42
+ ElMessageBox.alert(htmlStr, '打印预览', {
43
+ customClass: 'print-preview-dialog',
44
+ dangerouslyUseHTMLString: true,
45
+ closeOnClickModal: true,
46
+ closeOnPressEscape: true,
47
+ closeOnHashChange: true,
48
+ showConfirmButton: false,
49
+ });
50
+ } else {
51
+ ElMessage.warning({
52
+ message: '模板配置不存在,请检查',
53
+ });
54
+ }
55
+ }
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "yh-hiprint",
3
- "version": "2.6.13",
3
+ "version": "2.6.15",
4
4
  "description": "Hiprint for Vue3 by NoahLiu in ForceCon in Hunan Changesha",
5
- "main": "index.js",
6
- "types": "index.d.ts",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./index.ts",
9
+ "types": "./index.ts"
10
+ }
11
+ },
7
12
  "scripts": {
8
13
  "start": "npm run pub:aliyun && npm run pub:npm",
9
14
  "pub:aliyun": "npm publish --registry https://packages.aliyun.com/60765e0161a945067837bb5f/npm/npm-registry/ --tag latest --no-git-checks",
@@ -17,7 +22,8 @@
17
22
  "nzh": "1.0.9"
18
23
  },
19
24
  "peerDependencies": {
20
- "vue": "^3.0.0"
25
+ "vue": "^3.5.0",
26
+ "element-plus": "^2.9.0"
21
27
  },
22
28
  "author": "Liubin"
23
29
  }