|
|
@@ -0,0 +1,203 @@
|
|
|
+/**
|
|
|
+ * Electron打印适配器
|
|
|
+ * 使用Electron的webContents.print() API实现打印功能
|
|
|
+ * 需要在preload.js中暴露electronPrint API
|
|
|
+ */
|
|
|
+
|
|
|
+import { IPrintAdapter } from '../IPrintAdapter';
|
|
|
+import { PrintOptions, PrintFeatures } from '../types';
|
|
|
+import { prepareFilmForPrint, cleanupAfterPrint } from '../utils/canvasToImage';
|
|
|
+
|
|
|
+export class ElectronPrintAdapter implements IPrintAdapter {
|
|
|
+ private isPrinting: boolean = false;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行打印操作
|
|
|
+ */
|
|
|
+ async print(options: PrintOptions): Promise<void> {
|
|
|
+ if (this.isPrinting) {
|
|
|
+ throw new Error('打印正在进行中,请稍候');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查Electron打印API是否可用
|
|
|
+ if (!window.electronPrint) {
|
|
|
+ throw new Error('Electron打印API不可用,请确保已在preload.js中暴露');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isPrinting = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1. 获取要打印的元素
|
|
|
+ const element = document.getElementById(options.elementId);
|
|
|
+ if (!element) {
|
|
|
+ throw new Error(`未找到要打印的元素: ${options.elementId}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('[Electron打印] 开始打印流程');
|
|
|
+
|
|
|
+ // 2. 准备打印:将Canvas转换为图片
|
|
|
+ await prepareFilmForPrint(element);
|
|
|
+
|
|
|
+ // 3. 获取打印内容的HTML
|
|
|
+ const printContent = element.outerHTML;
|
|
|
+
|
|
|
+ // 4. 包装完整的HTML文档
|
|
|
+ const fullHtml = this.wrapHtmlDocument(printContent, options);
|
|
|
+
|
|
|
+ // 5. 调用Electron打印API
|
|
|
+ console.log('[Electron打印] 调用 electronPrint.print()');
|
|
|
+ await window.electronPrint.print({
|
|
|
+ html: fullHtml,
|
|
|
+ orientation: options.orientation,
|
|
|
+ paperSize: options.paperSize,
|
|
|
+ silent: options.silent || false,
|
|
|
+ margins: options.margins,
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('[Electron打印] 打印完成');
|
|
|
+
|
|
|
+ // 6. 清理
|
|
|
+ cleanupAfterPrint(element);
|
|
|
+ this.isPrinting = false;
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ this.isPrinting = false;
|
|
|
+ console.error('[Electron打印] 打印失败:', error);
|
|
|
+
|
|
|
+ // 确保清理
|
|
|
+ const element = document.getElementById(options.elementId);
|
|
|
+ if (element) {
|
|
|
+ cleanupAfterPrint(element);
|
|
|
+ }
|
|
|
+
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 显示打印预览
|
|
|
+ */
|
|
|
+ async preview(options: PrintOptions): Promise<void> {
|
|
|
+ // Electron可以通过设置silent=false来显示打印对话框
|
|
|
+ const previewOptions = { ...options, silent: false };
|
|
|
+ await this.print(previewOptions);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取支持的功能特性
|
|
|
+ */
|
|
|
+ getSupportedFeatures(): PrintFeatures {
|
|
|
+ return {
|
|
|
+ supportsSilentPrint: true,
|
|
|
+ supportsPreview: true,
|
|
|
+ supportsPaperSizeSelection: true,
|
|
|
+ supportsSaveToPDF: typeof window.electronPrint?.printToPDF === 'function',
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取适配器名称
|
|
|
+ */
|
|
|
+ getName(): string {
|
|
|
+ return 'ElectronPrintAdapter';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 包装完整的HTML文档
|
|
|
+ */
|
|
|
+ private wrapHtmlDocument(content: string, options: PrintOptions): string {
|
|
|
+ const { orientation, paperSize, margins } = options;
|
|
|
+
|
|
|
+ const defaultMargins = margins || {
|
|
|
+ top: 10,
|
|
|
+ right: 10,
|
|
|
+ bottom: 10,
|
|
|
+ left: 10,
|
|
|
+ };
|
|
|
+
|
|
|
+ return `
|
|
|
+<!DOCTYPE html>
|
|
|
+<html>
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <title>打印胶片</title>
|
|
|
+ <style>
|
|
|
+ * {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ body {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ @page {
|
|
|
+ size: ${paperSize} ${orientation};
|
|
|
+ margin: ${defaultMargins.top}mm ${defaultMargins.right}mm ${defaultMargins.bottom}mm ${defaultMargins.left}mm;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 隐藏Canvas,显示图片 */
|
|
|
+ .screen-only {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .print-only {
|
|
|
+ display: block !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 确保打印内容占满页面 */
|
|
|
+ #${options.elementId} {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ page-break-inside: avoid;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ ${content}
|
|
|
+</body>
|
|
|
+</html>
|
|
|
+ `;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存为PDF(如果支持)
|
|
|
+ */
|
|
|
+ async printToPDF(options: PrintOptions): Promise<void> {
|
|
|
+ if (!window.electronPrint?.printToPDF) {
|
|
|
+ throw new Error('Electron不支持printToPDF功能');
|
|
|
+ }
|
|
|
+
|
|
|
+ const element = document.getElementById(options.elementId);
|
|
|
+ if (!element) {
|
|
|
+ throw new Error(`未找到要打印的元素: ${options.elementId}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('[Electron打印] 开始导出PDF');
|
|
|
+
|
|
|
+ // 准备打印
|
|
|
+ await prepareFilmForPrint(element);
|
|
|
+
|
|
|
+ // 获取打印内容
|
|
|
+ const printContent = element.outerHTML;
|
|
|
+ const fullHtml = this.wrapHtmlDocument(printContent, options);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用PDF导出
|
|
|
+ await window.electronPrint.printToPDF({
|
|
|
+ html: fullHtml,
|
|
|
+ orientation: options.orientation,
|
|
|
+ paperSize: options.paperSize,
|
|
|
+ margins: options.margins,
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('[Electron打印] PDF导出完成');
|
|
|
+ } finally {
|
|
|
+ // 清理
|
|
|
+ cleanupAfterPrint(element);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|