pdv.frontend/src/components/POS/PrinterConfigModal.vue

228 lines
11 KiB
Vue

<template>
<div v-if="show" class="fixed inset-0 z-50 overflow-y-auto" aria-labelledby="modal-title" role="dialog"
aria-modal="true">
<!-- Overlay -->
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
<!-- Modal -->
<div class="flex min-h-full items-center justify-center p-4">
<div
class="relative transform overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all w-full max-w-lg">
<!-- Header -->
<div class="bg-indigo-600 px-6 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<GoogleIcon name="print" class="text-2xl text-white" />
<h3 class="text-lg font-semibold text-white">
Configuración de Impresora
</h3>
</div>
<button @click="$emit('close')" type="button"
class="text-white hover:text-gray-200 transition-colors">
<GoogleIcon name="close" class="text-xl" />
</button>
</div>
</div>
<!-- Body -->
<div class="px-6 py-4 space-y-4">
<!-- Estado de QZ Tray -->
<div class="flex items-center gap-3 p-4 rounded-lg"
:class="isConnected ? 'bg-green-50 dark:bg-green-900/20' : 'bg-red-50 dark:bg-red-900/20'">
<div class="flex-shrink-0">
<div class="w-3 h-3 rounded-full" :class="isConnected ? 'bg-green-500' : 'bg-red-500'">
</div>
</div>
<div class="flex-1">
<p class="text-sm font-medium"
:class="isConnected ? 'text-green-800 dark:text-green-200' : 'text-red-800 dark:text-red-200'">
{{ isConnected ? 'QZ Tray conectado' : 'QZ Tray no está activo' }}
</p>
<p class="text-xs mt-1"
:class="isConnected ? 'text-green-600 dark:text-green-300' : 'text-red-600 dark:text-red-300'">
{{ isConnected ? 'Listo para imprimir' : 'Por favor, inicia la aplicación QZ Tray' }}
</p>
</div>
<button @click="refreshConnection" type="button"
class="p-2 rounded-lg hover:bg-white dark:hover:bg-gray-700 transition-colors">
<GoogleIcon name="refresh" class="text-lg" />
</button>
</div>
<!-- Selección de impresora -->
<div v-if="isConnected">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
Seleccionar Impresora
</label>
<div v-if="loading" class="flex items-center justify-center py-8">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600"></div>
</div>
<div v-else-if="printers.length === 0" class="text-center py-8">
<GoogleIcon name="print_disabled" class="text-4xl text-gray-400 mx-auto mb-2" />
<p class="text-sm text-gray-500 dark:text-gray-400">
No se encontraron impresoras
</p>
</div>
<div v-else class="space-y-2">
<button v-for="printer in printers" :key="printer" @click="selectPrinter(printer)"
type="button" class="w-full flex items-center justify-between p-3 rounded-lg border-2 transition-all"
:class="selectedPrinter === printer
? 'border-indigo-600 bg-indigo-50 dark:bg-indigo-900/20'
: 'border-gray-200 dark:border-gray-600 hover:border-indigo-400 dark:hover:border-indigo-500'
">
<div class="flex items-center gap-3">
<GoogleIcon name="print" class="text-xl"
:class="selectedPrinter === printer ? 'text-indigo-600' : 'text-gray-400'" />
<span class="text-sm font-medium"
:class="selectedPrinter === printer ? 'text-indigo-900 dark:text-indigo-100' : 'text-gray-700 dark:text-gray-300'">
{{ printer }}
</span>
</div>
<GoogleIcon v-if="selectedPrinter === printer" name="check_circle"
class="text-xl text-indigo-600" />
</button>
</div>
<!-- Botón de prueba -->
<button v-if="selectedPrinter" @click="testPrint" type="button"
class="w-full mt-4 flex items-center justify-center gap-2 px-4 py-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-200 rounded-lg transition-colors">
<GoogleIcon name="science" class="text-lg" />
Imprimir página de prueba
</button>
</div>
<!-- Instrucciones si no está conectado -->
<div v-else class="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
<h4 class="text-sm font-semibold text-blue-900 dark:text-blue-100 mb-2">
¿Cómo activar QZ Tray?
</h4>
<ol class="text-sm text-blue-800 dark:text-blue-200 space-y-2 list-decimal list-inside">
<li>Descarga QZ Tray desde <a href="https://qz.io/download" target="_blank"
class="underline font-medium">qz.io/download</a></li>
<li>Instala la aplicación en tu computadora</li>
<li>Inicia QZ Tray (debería aparecer en la bandeja del sistema)</li>
<li>Haz clic en el botón de actualizar arriba</li>
</ol>
</div>
</div>
<!-- Footer -->
<div class="bg-gray-50 dark:bg-gray-900 px-6 py-4 flex justify-end gap-3">
<button @click="$emit('close')" type="button"
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors">
Cancelar
</button>
<button @click="saveConfiguration" type="button"
:disabled="!selectedPrinter"
class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-300 disabled:cursor-not-allowed rounded-lg transition-colors">
Guardar Configuración
</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import GoogleIcon from '@Shared/GoogleIcon.vue';
import printService from '@Services/printService';
defineProps({
show: Boolean
});
const emit = defineEmits(['close', 'saved']);
const isConnected = ref(false);
const loading = ref(false);
const printers = ref([]);
const selectedPrinter = ref(null);
const refreshConnection = async () => {
try {
loading.value = true;
await printService.connect();
isConnected.value = printService.isAvailable();
if (isConnected.value) {
await loadPrinters();
}
} catch (error) {
console.error('Error conectando con QZ Tray:', error);
isConnected.value = false;
window.Notify.error('No se pudo conectar con QZ Tray. Asegúrate de que esté ejecutándose.');
} finally {
loading.value = false;
}
};
const loadPrinters = async () => {
try {
loading.value = true;
const printerList = await printService.getPrinters();
printers.value = printerList;
// Cargar impresora guardada
const savedPrinter = printService.getSavedPrinter();
if (savedPrinter && printerList.includes(savedPrinter)) {
selectedPrinter.value = savedPrinter;
} else if (printerList.length > 0) {
// Seleccionar la primera impresora por defecto
const defaultPrinter = await printService.getDefaultPrinter();
selectedPrinter.value = defaultPrinter || printerList[0];
}
} catch (error) {
console.error('Error cargando impresoras:', error);
window.Notify.error('Error al cargar la lista de impresoras');
} finally {
loading.value = false;
}
};
const selectPrinter = (printer) => {
selectedPrinter.value = printer;
};
const testPrint = async () => {
try {
window.Notify.info('Enviando página de prueba a la impresora...');
// Crear un PDF de prueba simple
const testHTML = `
<div style="font-family: monospace; padding: 20px; text-align: center;">
<h2>Página de Prueba</h2>
<p>Impresora: ${selectedPrinter.value}</p>
<p>Fecha: ${new Date().toLocaleString('es-MX')}</p>
<p style="margin-top: 20px;">Si puedes ver esto, la impresora está funcionando correctamente.</p>
</div>
`;
await printService.printHTML(testHTML, selectedPrinter.value);
window.Notify.success('Página de prueba enviada a la impresora');
} catch (error) {
console.error('Error imprimiendo página de prueba:', error);
window.Notify.error('Error al enviar la página de prueba');
}
};
const saveConfiguration = () => {
if (!selectedPrinter.value) {
window.Notify.warning('Por favor selecciona una impresora');
return;
}
printService.setDefaultPrinter(selectedPrinter.value);
window.Notify.success(`Impresora configurada: ${selectedPrinter.value}`);
emit('saved', selectedPrinter.value);
emit('close');
};
onMounted(() => {
refreshConnection();
});
</script>