228 lines
11 KiB
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>
|