Spaces:
Running
Running
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Sistema de Control de Sobrantes de Medicamentos</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#3b82f6', | |
| secondary: '#10b981', | |
| danger: '#ef4444', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.3s ease-out forwards; | |
| } | |
| .signature-pad { | |
| border: 1px dashed #ccc; | |
| border-radius: 4px; | |
| background-color: #f9fafb; | |
| } | |
| input:focus, select:focus, textarea:focus { | |
| outline: 2px solid #3b82f6; | |
| outline-offset: 2px; | |
| } | |
| @media print { | |
| .no-print { | |
| display: none ; | |
| } | |
| .print-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 10px; | |
| } | |
| .print-table th, .print-table td { | |
| border: 1px solid #ddd; | |
| padding: 4px; | |
| text-align: left; | |
| } | |
| .print-table th { | |
| background-color: #f2f2f2; | |
| } | |
| .print-header { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| .print-footer { | |
| text-align: center; | |
| margin-top: 20px; | |
| font-size: 10px; | |
| color: #666; | |
| } | |
| .page-break { | |
| page-break-after: always; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8 max-w-4xl"> | |
| <!-- Header --> | |
| <header class="mb-8 text-center"> | |
| <h1 class="text-3xl font-bold text-primary mb-2"> | |
| <i class="fas fa-pills mr-2"></i>Control de Sobrantes de Medicamentos | |
| </h1> | |
| <p class="text-gray-600">Registro y gesti贸n de medicamentos sobrantes con fechas de caducidad e informaci贸n de estabilidad</p> | |
| </header> | |
| <!-- Control Panel --> | |
| <div class="bg-white rounded-lg shadow-md p-6 mb-8 no-print"> | |
| <div class="flex flex-wrap gap-4 mb-6"> | |
| <button id="scanBtn" class="flex items-center px-4 py-2 bg-primary text-white rounded-lg hover:bg-blue-700 transition"> | |
| <i class="fas fa-barcode mr-2"></i> Escanear C贸digo | |
| </button> | |
| <button id="manualBtn" class="flex items-center px-4 py-2 bg-secondary text-white rounded-lg hover:bg-emerald-700 transition"> | |
| <i class="fas fa-keyboard mr-2"></i> Ingreso Manual | |
| </button> | |
| <button id="clearBtn" class="flex items-center px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition"> | |
| <i class="fas fa-trash-alt mr-2"></i> Limpiar Formulario | |
| </button> | |
| <button id="saveBtn" class="flex items-center px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition ml-auto"> | |
| <i class="fas fa-save mr-2"></i> Guardar Registro | |
| </button> | |
| <button id="printBtn" class="flex items-center px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 transition"> | |
| <i class="fas fa-print mr-2"></i> Imprimir Registros | |
| </button> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <!-- Left Column --> | |
| <div> | |
| <div class="mb-4"> | |
| <label for="medication" class="block text-sm font-medium text-gray-700 mb-1">Nombre del Medicamento *</label> | |
| <div class="relative"> | |
| <input type="text" id="medication" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary" placeholder="Ingrese nombre del medicamento"> | |
| <div id="medSuggestions" class="absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg hidden"></div> | |
| </div> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="batch" class="block text-sm font-medium text-gray-700 mb-1">N煤mero de Lote *</label> | |
| <input type="text" id="batch" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Ingrese n煤mero de lote"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="expiration" class="block text-sm font-medium text-gray-700 mb-1">Fecha de Caducidad *</label> | |
| <input type="date" id="expiration" class="w-full px-4 py-2 border border-gray-300 rounded-lg"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="quantity" class="block text-sm font-medium text-gray-700 mb-1">Cantidad Restante *</label> | |
| <div class="flex"> | |
| <input type="number" id="quantity" class="w-3/4 px-4 py-2 border border-gray-300 rounded-l-lg" placeholder="Ingrese cantidad"> | |
| <select id="unit" class="w-1/4 px-2 py-2 border border-gray-300 rounded-r-lg bg-gray-50"> | |
| <option value="tabletas">tabletas</option> | |
| <option value="ml">ml</option> | |
| <option value="mg">mg</option> | |
| <option value="viales">viales</option> | |
| <option value="ampollas">ampollas</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Column --> | |
| <div> | |
| <div class="mb-4"> | |
| <label for="productionDate" class="block text-sm font-medium text-gray-700 mb-1">Fecha de Producci贸n</label> | |
| <input type="date" id="productionDate" class="w-full px-4 py-2 border border-gray-300 rounded-lg"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="stability" class="block text-sm font-medium text-gray-700 mb-1">Informaci贸n de Estabilidad</label> | |
| <select id="stability" class="w-full px-4 py-2 border border-gray-300 rounded-lg"> | |
| <option value="">Seleccione estabilidad</option> | |
| <option value="room_temp">Temperatura ambiente (15-25掳C)</option> | |
| <option value="refrigerated">Refrigerado (2-8掳C)</option> | |
| <option value="frozen">Congelado (-20掳C o menos)</option> | |
| <option value="protected_light">Protegido de la luz</option> | |
| <option value="special">Condiciones especiales (ver notas)</option> | |
| </select> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="useExpiration" class="block text-sm font-medium text-gray-700 mb-1">Fecha de Caducidad despu茅s de abrir</label> | |
| <input type="date" id="useExpiration" class="w-full px-4 py-2 border border-gray-300 rounded-lg"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="laboratory" class="block text-sm font-medium text-gray-700 mb-1">Fabricante/Laboratorio</label> | |
| <input type="text" id="laboratory" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Ingrese nombre del fabricante"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Notes Section --> | |
| <div class="mb-6"> | |
| <label for="notes" class="block text-sm font-medium text-gray-700 mb-1">Notas Adicionales</label> | |
| <textarea id="notes" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Cualquier instrucci贸n especial o notas sobre este medicamento"></textarea> | |
| </div> | |
| <!-- Signature Section --> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Firma del Responsable</label> | |
| <div class="signature-pad p-4 mb-2"> | |
| <canvas id="signatureCanvas" width="100%" height="100"></canvas> | |
| </div> | |
| <div class="flex justify-between"> | |
| <button id="clearSignature" class="text-sm text-gray-500 hover:text-gray-700"> | |
| <i class="fas fa-eraser mr-1"></i> Limpiar Firma | |
| </button> | |
| <div class="text-sm text-gray-500"> | |
| <i class="fas fa-info-circle mr-1"></i> Firme arriba para confirmar | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Recent Records --> | |
| <div class="bg-white rounded-lg shadow-md p-6 no-print"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center"> | |
| <i class="fas fa-history mr-2"></i> Registros Recientes | |
| </h2> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Medicamento</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Lote</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Caducidad</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Cantidad</th> | |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> | |
| </tr> | |
| </thead> | |
| <tbody id="recordsTable" class="bg-white divide-y divide-gray-200"> | |
| <!-- Records will be added here dynamically --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Print Format (hidden until printing) --> | |
| <div id="printFormat" class="hidden"> | |
| <!-- This will be populated with print content when printing --> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Base de datos de medicamentos para autocompletado | |
| const medicationDatabase = [ | |
| { name: "Amoxicilina 500mg", commonBatch: "AMX2023", stability: "room_temp", lab: "PharmaCorp" }, | |
| { name: "Ibuprofeno 200mg", commonBatch: "IBU2305", stability: "room_temp", lab: "MediHealth" }, | |
| { name: "Insulina Glargina", commonBatch: "INS456", stability: "refrigerated", lab: "BioSolutions" }, | |
| { name: "Paracetamol 500mg", commonBatch: "PARA789", stability: "room_temp", lab: "GenericMeds" }, | |
| { name: "Loratadina 10mg", commonBatch: "LORA123", stability: "room_temp", lab: "AllerFree" }, | |
| { name: "Omeprazol 20mg", commonBatch: "OME456", stability: "room_temp", lab: "GastroPharm" } | |
| ]; | |
| // Establecer la fecha de hoy como predeterminada | |
| const today = new Date(); | |
| const todayFormatted = today.toISOString().split('T')[0]; | |
| document.getElementById('productionDate').value = todayFormatted; | |
| // Inicializar el pad de firma | |
| const canvas = document.getElementById('signatureCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| let isDrawing = false; | |
| let lastX = 0; | |
| let lastY = 0; | |
| // Establecer tama帽o del canvas | |
| function resizeCanvas() { | |
| const container = canvas.parentElement; | |
| canvas.width = container.offsetWidth; | |
| canvas.height = 100; | |
| } | |
| resizeCanvas(); | |
| window.addEventListener('resize', resizeCanvas); | |
| // Funcionalidad de dibujo de firma | |
| canvas.addEventListener('mousedown', (e) => { | |
| isDrawing = true; | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| }); | |
| canvas.addEventListener('mousemove', (e) => { | |
| if (!isDrawing) return; | |
| ctx.beginPath(); | |
| ctx.moveTo(lastX, lastY); | |
| ctx.lineTo(e.offsetX, e.offsetY); | |
| ctx.strokeStyle = '#000'; | |
| ctx.lineWidth = 2; | |
| ctx.stroke(); | |
| [lastX, lastY] = [e.offsetX, e.offsetY]; | |
| }); | |
| canvas.addEventListener('mouseup', () => isDrawing = false); | |
| canvas.addEventListener('mouseout', () => isDrawing = false); | |
| // Soporte t谩ctil para firma | |
| canvas.addEventListener('touchstart', (e) => { | |
| e.preventDefault(); | |
| const touch = e.touches[0]; | |
| const mouseEvent = new MouseEvent('mousedown', { | |
| clientX: touch.clientX, | |
| clientY: touch.clientY | |
| }); | |
| canvas.dispatchEvent(mouseEvent); | |
| }); | |
| canvas.addEventListener('touchmove', (e) => { | |
| e.preventDefault(); | |
| const touch = e.touches[0]; | |
| const mouseEvent = new MouseEvent('mousemove', { | |
| clientX: touch.clientX, | |
| clientY: touch.clientY | |
| }); | |
| canvas.dispatchEvent(mouseEvent); | |
| }); | |
| canvas.addEventListener('touchend', () => { | |
| const mouseEvent = new MouseEvent('mouseup'); | |
| canvas.dispatchEvent(mouseEvent); | |
| }); | |
| // Limpiar firma | |
| document.getElementById('clearSignature').addEventListener('click', () => { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| }); | |
| // Autocompletado de medicamentos | |
| const medicationInput = document.getElementById('medication'); | |
| const suggestionsContainer = document.getElementById('medSuggestions'); | |
| medicationInput.addEventListener('input', function() { | |
| const input = this.value.toLowerCase(); | |
| if (input.length < 2) { | |
| suggestionsContainer.classList.add('hidden'); | |
| return; | |
| } | |
| const matches = medicationDatabase.filter(med => | |
| med.name.toLowerCase().includes(input) | |
| ); | |
| if (matches.length > 0) { | |
| suggestionsContainer.innerHTML = ''; | |
| matches.forEach(med => { | |
| const div = document.createElement('div'); | |
| div.className = 'px-4 py-2 hover:bg-gray-100 cursor-pointer'; | |
| div.textContent = med.name; | |
| div.addEventListener('click', () => { | |
| medicationInput.value = med.name; | |
| document.getElementById('batch').value = med.commonBatch; | |
| document.getElementById('stability').value = med.stability; | |
| document.getElementById('laboratory').value = med.lab; | |
| suggestionsContainer.classList.add('hidden'); | |
| // Establecer una fecha de caducidad futura (1 a帽o desde ahora) | |
| const futureDate = new Date(); | |
| futureDate.setFullYear(futureDate.getFullYear() + 1); | |
| document.getElementById('expiration').value = futureDate.toISOString().split('T')[0]; | |
| // Establecer caducidad despu茅s de abrir (30 d铆as desde ahora) | |
| const useDate = new Date(); | |
| useDate.setDate(useDate.getDate() + 30); | |
| document.getElementById('useExpiration').value = useDate.toISOString().split('T')[0]; | |
| }); | |
| suggestionsContainer.appendChild(div); | |
| }); | |
| suggestionsContainer.classList.remove('hidden'); | |
| } else { | |
| suggestionsContainer.classList.add('hidden'); | |
| } | |
| }); | |
| // Cerrar sugerencias al hacer clic en otro lugar | |
| document.addEventListener('click', (e) => { | |
| if (e.target !== medicationInput) { | |
| suggestionsContainer.classList.add('hidden'); | |
| } | |
| }); | |
| // Datos de registros de ejemplo | |
| let records = [ | |
| { | |
| date: '2023-06-15', | |
| medication: 'Amoxicilina 500mg', | |
| batch: 'AMX2023', | |
| expiration: '2024-06-14', | |
| quantity: '15 tabletas', | |
| stability: 'Temperatura ambiente', | |
| useExpiration: '2023-07-15', | |
| laboratory: 'PharmaCorp', | |
| notes: 'Mantener en lugar seco' | |
| }, | |
| { | |
| date: '2023-06-10', | |
| medication: 'Insulina Glargina', | |
| batch: 'INS456', | |
| expiration: '2023-12-10', | |
| quantity: '2 viales', | |
| stability: 'Refrigerado', | |
| useExpiration: '2023-07-10', | |
| laboratory: 'BioSolutions', | |
| notes: 'No congelar' | |
| } | |
| ]; | |
| // Renderizar tabla de registros | |
| function renderRecords() { | |
| const tableBody = document.getElementById('recordsTable'); | |
| tableBody.innerHTML = ''; | |
| records.forEach((record, index) => { | |
| const row = document.createElement('tr'); | |
| row.className = 'fade-in'; | |
| row.innerHTML = ` | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.date}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${record.medication}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.batch}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.expiration}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.quantity}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <button class="text-primary hover:text-blue-700 mr-3 view-btn" data-index="${index}"> | |
| <i class="fas fa-eye mr-1"></i> Ver | |
| </button> | |
| <button class="text-danger hover:text-red-700 delete-btn" data-index="${index}"> | |
| <i class="fas fa-trash-alt mr-1"></i> Eliminar | |
| </button> | |
| </td> | |
| `; | |
| tableBody.appendChild(row); | |
| }); | |
| // Agregar event listeners a los botones | |
| document.querySelectorAll('.view-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const index = this.getAttribute('data-index'); | |
| viewRecord(index); | |
| }); | |
| }); | |
| document.querySelectorAll('.delete-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const index = this.getAttribute('data-index'); | |
| deleteRecord(index); | |
| }); | |
| }); | |
| } | |
| // Ver detalles del registro | |
| function viewRecord(index) { | |
| const record = records[index]; | |
| alert(`Medicamento: ${record.medication}\nLote: ${record.batch}\nCaducidad: ${record.expiration}\nCantidad: ${record.quantity}\nEstabilidad: ${record.stability}\nUsar hasta: ${record.useExpiration}\nLaboratorio: ${record.laboratory}\nNotas: ${record.notes}`); | |
| } | |
| // Eliminar registro | |
| function deleteRecord(index) { | |
| if (confirm('驴Est谩 seguro que desea eliminar este registro?')) { | |
| records.splice(index, 1); | |
| renderRecords(); | |
| } | |
| } | |
| // Guardar nuevo registro | |
| document.getElementById('saveBtn').addEventListener('click', function() { | |
| const medication = document.getElementById('medication').value; | |
| const batch = document.getElementById('batch').value; | |
| const expiration = document.getElementById('expiration').value; | |
| const quantity = document.getElementById('quantity').value + ' ' + document.getElementById('unit').value; | |
| const productionDate = document.getElementById('productionDate').value; | |
| const stability = document.getElementById('stability').options[document.getElementById('stability').selectedIndex].text; | |
| const useExpiration = document.getElementById('useExpiration').value; | |
| const laboratory = document.getElementById('laboratory').value; | |
| const notes = document.getElementById('notes').value; | |
| if (!medication || !batch || !expiration || !quantity) { | |
| alert('Por favor complete todos los campos requeridos (marcados con *)'); | |
| return; | |
| } | |
| // Verificar si hay firma | |
| const signatureEmpty = canvas.toDataURL() === document.createElement('canvas').toDataURL(); | |
| if (signatureEmpty) { | |
| alert('Por favor proporcione una firma para confirmar el registro'); | |
| return; | |
| } | |
| const newRecord = { | |
| date: todayFormatted, | |
| medication, | |
| batch, | |
| expiration, | |
| quantity, | |
| productionDate, | |
| stability, | |
| useExpiration, | |
| laboratory, | |
| notes | |
| }; | |
| records.unshift(newRecord); | |
| renderRecords(); | |
| // Limpiar formulario | |
| document.getElementById('clearBtn').click(); | |
| // Mostrar mensaje de 茅xito | |
| const successMsg = document.createElement('div'); | |
| successMsg.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg flex items-center'; | |
| successMsg.innerHTML = '<i class="fas fa-check-circle mr-2"></i> 隆Registro guardado con 茅xito!'; | |
| document.body.appendChild(successMsg); | |
| setTimeout(() => { | |
| successMsg.classList.add('opacity-0', 'transition-opacity', 'duration-500'); | |
| setTimeout(() => successMsg.remove(), 500); | |
| }, 3000); | |
| }); | |
| // Limpiar formulario | |
| document.getElementById('clearBtn').addEventListener('click', function() { | |
| document.getElementById('medication').value = ''; | |
| document.getElementById('batch').value = ''; | |
| document.getElementById('expiration').value = ''; | |
| document.getElementById('quantity').value = ''; | |
| document.getElementById('unit').value = 'tabletas'; | |
| document.getElementById('productionDate').value = todayFormatted; | |
| document.getElementById('stability').value = ''; | |
| document.getElementById('useExpiration').value = ''; | |
| document.getElementById('laboratory').value = ''; | |
| document.getElementById('notes').value = ''; | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| }); | |
| // Simular escaneo de c贸digo de barras | |
| document.getElementById('scanBtn').addEventListener('click', function() { | |
| // Simular escaneo de un medicamento aleatorio | |
| const randomMed = medicationDatabase[Math.floor(Math.random() * medicationDatabase.length)]; | |
| document.getElementById('medication').value = randomMed.name; | |
| document.getElementById('batch').value = randomMed.commonBatch; | |
| document.getElementById('stability').value = randomMed.stability; | |
| document.getElementById('laboratory').value = randomMed.lab; | |
| // Establecer fechas | |
| const futureDate = new Date(); | |
| futureDate.setFullYear(futureDate.getFullYear() + 1); | |
| document.getElementById('expiration').value = futureDate.toISOString().split('T')[0]; | |
| const useDate = new Date(); | |
| useDate.setDate(useDate.getDate() + 30); | |
| document.getElementById('useExpiration').value = useDate.toISOString().split('T')[0]; | |
| // Establecer cantidad aleatoria | |
| document.getElementById('quantity').value = Math.floor(Math.random() * 20) + 5; | |
| // Mostrar animaci贸n de escaneo | |
| const scanAnimation = document.createElement('div'); | |
| scanAnimation.className = 'fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50'; | |
| scanAnimation.innerHTML = ` | |
| <div class="bg-white p-6 rounded-lg text-center max-w-sm"> | |
| <div class="text-4xl mb-4"> | |
| <i class="fas fa-barcode animate-pulse text-primary"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold mb-2">Escaneando C贸digo de Barras</h3> | |
| <p class="text-gray-600 mb-4">Detectado: ${randomMed.name}</p> | |
| <div class="h-1 w-full bg-gray-200 rounded-full overflow-hidden"> | |
| <div class="h-full bg-primary rounded-full animate-progress"></div> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(scanAnimation); | |
| setTimeout(() => { | |
| scanAnimation.classList.add('opacity-0', 'transition-opacity', 'duration-300'); | |
| setTimeout(() => scanAnimation.remove(), 300); | |
| }, 1500); | |
| }); | |
| // Funci贸n para imprimir registros | |
| document.getElementById('printBtn').addEventListener('click', function() { | |
| if (records.length === 0) { | |
| alert('No hay registros para imprimir'); | |
| return; | |
| } | |
| const printFormat = document.getElementById('printFormat'); | |
| printFormat.innerHTML = ''; | |
| // Agrupar registros en p谩ginas de 30 | |
| const recordsPerPage = 30; | |
| const pageCount = Math.ceil(records.length / recordsPerPage); | |
| for (let i = 0; i < pageCount; i++) { | |
| const start = i * recordsPerPage; | |
| const end = start + recordsPerPage; | |
| const pageRecords = records.slice(start, end); | |
| const pageDiv = document.createElement('div'); | |
| pageDiv.className = 'p-4 print-page'; | |
| // Encabezado de impresi贸n | |
| const header = document.createElement('div'); | |
| header.className = 'print-header'; | |
| header.innerHTML = ` | |
| <h1 class="text-xl font-bold">Farmacia "Salud Integral"</h1> | |
| <h2 class="text-lg">Registro de Sobrantes de Medicamentos</h2> | |
| <p class="text-sm">P谩gina ${i + 1} de ${pageCount} - Impreso el ${todayFormatted}</p> | |
| <hr class="my-2"> | |
| `; | |
| pageDiv.appendChild(header); | |
| // Tabla de registros | |
| const table = document.createElement('table'); | |
| table.className = 'print-table'; | |
| table.innerHTML = ` | |
| <thead> | |
| <tr> | |
| <th>No.</th> | |
| <th>Fecha</th> | |
| <th>Medicamento</th> | |
| <th>Lote</th> | |
| <th>Caducidad</th> | |
| <th>Cantidad</th> | |
| <th>Estabilidad</th> | |
| <th>Usar hasta</th> | |
| <th>Laboratorio</th> | |
| <th>Notas</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| ${pageRecords.map((record, idx) => ` | |
| <tr> | |
| <td>${start + idx + 1}</td> | |
| <td>${record.date}</td> | |
| <td>${record.medication}</td> | |
| <td>${record.batch}</td> | |
| <td>${record.expiration}</td> | |
| <td>${record.quantity}</td> | |
| <td>${record.stability}</td> | |
| <td>${record.useExpiration}</td> | |
| <td>${record.laboratory}</td> | |
| <td>${record.notes}</td> | |
| </tr> | |
| `).join('')} | |
| </tbody> | |
| `; | |
| pageDiv.appendChild(table); | |
| // Pie de p谩gina | |
| const footer = document.createElement('div'); | |
| footer.className = 'print-footer'; | |
| footer.innerHTML = ` | |
| <hr class="my-2"> | |
| <p>Farmacia "Salud Integral" - Av. Principal 123, Ciudad</p> | |
| <p>Tel茅fono: 555-1234 - Email: info@saludintegral.com</p> | |
| `; | |
| pageDiv.appendChild(footer); | |
| // Agregar salto de p谩gina si no es la 煤ltima p谩gina | |
| if (i < pageCount - 1) { | |
| pageDiv.classList.add('page-break'); | |
| } | |
| printFormat.appendChild(pageDiv); | |
| } | |
| // Mostrar di谩logo de impresi贸n | |
| printFormat.classList.remove('hidden'); | |
| window.print(); | |
| printFormat.classList.add('hidden'); | |
| }); | |
| // Renderizar registros iniciales | |
| renderRecords(); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 馃К <a href="https://enzostvs-deepsite.hf.space?remix=lechugaFria1/cmp-version-2-0" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |