feat: agregar funcionalidad para imprimir imágenes en base64 y mejorar la impresión de tickets

This commit is contained in:
Juan Felipe Zapata Moreno 2026-02-03 21:04:08 -06:00
parent 21b28b5bff
commit 4dfeeeea20
2 changed files with 124 additions and 15 deletions

View File

@ -341,6 +341,46 @@ class PrintService {
} }
}); });
} }
/**
* Imprimir imagen base64
* @param {string} base64Image - Imagen en base64 (png, jpg)
* @param {string} printerName - Nombre de la impresora (opcional)
* @returns {Promise}
*/
async printImage(base64Image, printerName = null) {
try {
await this.connect();
const printer = printerName || this.getSavedPrinter() || await this.getDefaultPrinter();
const config = this.qz.configs.create(printer, {
scaleContent: true
});
// Asegurar data URI
let imgData = base64Image;
if (!imgData.startsWith('data:image')) {
imgData = `data:image/png;base64,${base64Image}`;
}
const data = [
{
type: 'pixel',
format: 'image',
flavor: 'base64',
data: imgData
}
];
await this.qz.print(config, data);
console.log('Imagen impresa exitosamente');
return true;
} catch (error) {
console.error('Error imprimiendo imagen:', error);
throw error;
}
}
} }
// Exportar instancia singleton // Exportar instancia singleton

View File

@ -3,6 +3,30 @@ import QRCode from 'qrcode';
import { formatMoney, PAYMENT_METHODS } from '@/utils/formatters'; import { formatMoney, PAYMENT_METHODS } from '@/utils/formatters';
import printService from '@Services/printService'; import printService from '@Services/printService';
/**
* Cargar PDF.js dinámicamente desde CDN
*/
async function loadPdfJs() {
if (window.pdfjsLib) return window.pdfjsLib;
console.log('Cargando PDF.js desde CDN...');
// Cargar script principal
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js';
script.integrity = 'sha512-q+GRHzvH4z5fXN5WjM8oKGTf4PxcX1QzGjZfrFqVBqAdgEecT0kFvvn7uZ2+GL3LMDM9M79cfsREi+T17J9wMA==';
script.crossOrigin = 'anonymous';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
// Configurar worker
window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
return window.pdfjsLib;
}
/** /**
* Servicio para generar tickets de venta en formato PDF * Servicio para generar tickets de venta en formato PDF
*/ */
@ -367,25 +391,70 @@ const ticketService = {
// Imprimir automáticamente si se solicita // Imprimir automáticamente si se solicita
if (autoPrint) { if (autoPrint) {
try { try {
// Intentar convertir PDF a Imagen y usar QZ Tray (Mejor compatibilidad con térmicas)
try {
// Obtener Blob del PDF
const pdfBlob = doc.output('blob');
const pdfUrl = URL.createObjectURL(pdfBlob);
// Cargar librería PDF.js
const pdfjs = await loadPdfJs();
// Cargar documento
const pdf = await pdfjs.getDocument(pdfUrl).promise;
const page = await pdf.getPage(1); // Página 1
// Configurar escala (2.0 da buena nitidez para tickets)
const scale = 2.0;
const viewport = page.getViewport({ scale });
// Crear canvas temporal
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Renderizar PDF en Canvas
await page.render({
canvasContext: context,
viewport: viewport
}).promise;
// Convertir Canvas a Imagen Base64
const imgData = canvas.toDataURL('image/png');
// Enviar imagen a QZ Tray
await printService.printImage(imgData, printerName);
console.log('Ticket impreso como imagen con QZ Tray');
// Limpieza
URL.revokeObjectURL(pdfUrl);
canvas.remove();
} catch (imgError) {
console.warn('Falló impresión como imagen, intentando método nativo PDF:', imgError);
// Fallback: Intentar mandar el PDF directo (puede fallar en térmicas) o usar diálogo
// Convertir PDF a base64 data URI // Convertir PDF a base64 data URI
const pdfBase64 = doc.output('datauristring'); const pdfBase64 = doc.output('datauristring');
// Intentar imprimir con QZ Tray // Intentar QZ Tray Direct PDF
try { try {
await printService.printPDF(pdfBase64, printerName); await printService.printPDF(pdfBase64, printerName);
console.log('Ticket enviado a la impresora con QZ Tray');
} catch (qzError) { } catch (qzError) {
console.warn('QZ Tray falló, usando diálogo de impresión:', qzError.message); console.warn('QZ Tray PDF falló, abriendo diálogo:', qzError);
// Fallback: usar window.print()
await printService.printPDFWithDialog(pdfBase64); await printService.printPDFWithDialog(pdfBase64);
window.Notify.info('Se abrió el diálogo de impresión'); }
} }
} catch (error) { } catch (error) {
console.error('Error imprimiendo ticket:', error); console.error('Error general imprimiendo ticket:', error);
// Mostrar error al usuario // Fallback final
window.Notify.warning('No se pudo imprimir automáticamente. Usa el PDF descargado.'); const pdfBase64 = doc.output('datauristring');
await printService.printPDFWithDialog(pdfBase64);
window.Notify.warning('Hubo un problema con la impresión automática. Se abrió el diálogo del sistema.');
} }
} }