Spaces:
Running
Running
| <html lang="es"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Calculadora de Urgencias Médicas</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" /> | |
| <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap" rel="stylesheet" /> | |
| <style> | |
| body { | |
| background-color: #f8fafc; | |
| font-family: "Montserrat", sans-serif; | |
| } | |
| /* Estilos para las pestañas */ | |
| .tab-btn { | |
| transition: background-color 0.2s, color 0.2s; | |
| } | |
| .tab-btn.active { | |
| background-color: #0d9488; /* teal-600 */ | |
| color: white; | |
| border-color: #0d9488; | |
| } | |
| .input-field { | |
| width: 100%; | |
| padding: 0.5rem 0.75rem; | |
| border-radius: 0.375rem; | |
| border: 1px solid #d1d5db; | |
| box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); | |
| font-size: 0.875rem; | |
| line-height: 1.25rem; | |
| } | |
| .input-field:focus { | |
| outline: none; | |
| border-color: #3b82f6; | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25); | |
| } | |
| .result-card { | |
| background-color: white; | |
| border: 1px solid #e5e7eb; | |
| border-radius: 0.5rem; | |
| padding: 1.5rem; | |
| margin-top: 1rem; | |
| min-height: 300px; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.05); | |
| } | |
| .drug-calculation span { | |
| font-weight: 600; | |
| color: #c026d3; /* fuchsia-700 */ | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen bg-gray-50 p-4 sm:p-6"> | |
| <div class="mx-auto max-w-3xl p-6 my-8 bg-white rounded-xl shadow-lg"> | |
| <div class="text-center mb-6"> | |
| <h1 class="text-2xl font-bold text-teal-700 flex items-center justify-center"> | |
| <i class="fas fa-calculator mr-3"></i>Calculadora de Urgencias | |
| </h1> | |
| <p class="text-gray-600 mt-2 text-sm leading-relaxed"> | |
| Herramienta rápida para Secuencia de Intubación y Bombas de Perfusión. | |
| </p> | |
| </div> | |
| <div class="bg-red-50 text-red-800 p-3 rounded-lg text-xs text-center mb-6 border border-red-200"> | |
| <i class="fas fa-exclamation-triangle mr-2"></i> | |
| <strong>Atención:</strong> Esta es una herramienta de ayuda y no reemplaza el juicio clínico. Verifique siempre los cálculos. | |
| </div> | |
| <div class="flex border-b border-gray-200 mb-6"> | |
| <button id="tab-sri" class="tab-btn active flex-1 py-2 px-4 text-sm font-semibold text-gray-600 border-b-2 border-transparent hover:bg-teal-50"> | |
| <i class="fas fa-lungs mr-2"></i>Secuencia Rápida Intubación | |
| </button> | |
| <button id="tab-bombas" class="tab-btn flex-1 py-2 px-4 text-sm font-semibold text-gray-600 border-b-2 border-transparent hover:bg-teal-50"> | |
| <i class="fas fa-syringe mr-2"></i>Bombas de Perfusión | |
| </button> | |
| </div> | |
| <div class="bg-teal-50 p-4 rounded-lg border border-teal-100 shadow-inner space-y-4 mb-6"> | |
| <div> | |
| <label for="patientWeight" class="block text-sm font-medium text-gray-700 mb-2"> | |
| <i class="fas fa-weight-scale mr-2"></i>Peso del paciente (kg) | |
| </label> | |
| <input type="number" id="patientWeight" class="input-field" placeholder="Ej: 70" value="70"> | |
| </div> | |
| </div> | |
| <main> | |
| <div id="content-sri" class="result-card"> | |
| </div> | |
| <div id="content-bombas" class="hidden"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> | |
| <div> | |
| <label for="drugSelector" class="block text-xs font-medium text-gray-600 mb-1">Fármaco</label> | |
| <select id="drugSelector" class="input-field appearance-none pr-8 bg-no-repeat" style="background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); background-position: right 0.5rem center; background-size: 1.5em 1.5em;"> | |
| <option value="noradrenalina">Noradrenalina</option> | |
| <option value="dopamina">Dopamina</option> | |
| <option value="dobutamina">Dobutamina</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label for="doseInput" class="block text-xs font-medium text-gray-600 mb-1">Dosis deseada (<span id="doseUnit">mcg/kg/min</span>)</label> | |
| <input type="number" id="doseInput" class="input-field" value="0.1" step="0.01"> | |
| </div> | |
| </div> | |
| <div id="pump-results" class="result-card"> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <script type="module"> | |
| // --- DATOS MÉDICOS (ACTUALIZADOS) --- | |
| const rsiDrugs = { | |
| premedicacion: [ | |
| { name: 'Fentanilo', dose: '1-3 mcg/kg', presentation: { value: 50, unit: 'mcg/ml' } }, | |
| { name: 'Lidocaína', dose: '1.5 mg/kg', presentation: { value: 20, unit: 'mg/ml' } } | |
| ], | |
| induccion: [ | |
| { name: 'Propofol', dose: '1-2 mg/kg', presentation: { value: 10, unit: 'mg/ml' } }, | |
| { name: 'Etomidato', dose: '0.2-0.3 mg/kg', presentation: { value: 2, unit: 'mg/ml' } }, | |
| { name: 'Ketamina', dose: '1-2 mg/kg', presentation: { value: 50, unit: 'mg/ml' } }, | |
| { name: 'Midazolam', dose: '0.1-0.3 mg/kg', presentation: { value: 5, unit: 'mg/ml' } } | |
| ], | |
| paralisis: [ | |
| { name: 'Rocuronio', dose: '1-1.2 mg/kg', presentation: { value: 10, unit: 'mg/ml' } }, | |
| { name: 'Succinilcolina', dose: '1-1.5 mg/kg', presentation: { value: 50, unit: 'mg/ml' } } | |
| ] | |
| }; | |
| const perfusionDrugs = { | |
| noradrenalina: { | |
| name: 'Noradrenalina', | |
| preparation: 'Añadir <strong>10 mg</strong> (2 ampollas de 5mg/10ml) en <strong>250 ml</strong> de Suero Glucosado 5%.', | |
| totalDrugMg: 10, | |
| totalVolumeMl: 250, | |
| doseUnit: 'mcg/kg/min', | |
| defaultDose: 0.1 | |
| }, | |
| dopamina: { | |
| name: 'Dopamina', | |
| preparation: 'Añadir <strong>200 mg</strong> (1 ampolla de 200mg/5ml) en <strong>250 ml</strong> de Suero Glucosado 5%.', | |
| totalDrugMg: 200, | |
| totalVolumeMl: 250, | |
| doseUnit: 'mcg/kg/min', | |
| defaultDose: 5 | |
| }, | |
| dobutamina: { | |
| name: 'Dobutamina', | |
| preparation: 'Añadir <strong>250 mg</strong> (1 vial de 250mg/20ml) en <strong>250 ml</strong> de Suero Glucosado 5%.', | |
| totalDrugMg: 250, | |
| totalVolumeMl: 250, | |
| doseUnit: 'mcg/kg/min', | |
| defaultDose: 5 | |
| } | |
| }; | |
| // --- REFERENCIAS AL DOM --- | |
| const patientWeightInput = document.getElementById('patientWeight'); | |
| const tabSri = document.getElementById('tab-sri'); | |
| const tabBombas = document.getElementById('tab-bombas'); | |
| const contentSri = document.getElementById('content-sri'); | |
| const contentBombas = document.getElementById('content-bombas'); | |
| const drugSelector = document.getElementById('drugSelector'); | |
| const doseInput = document.getElementById('doseInput'); | |
| const doseUnitSpan = document.getElementById('doseUnit'); | |
| const pumpResultsDisplay = document.getElementById('pump-results'); | |
| // --- LÓGICA DE LA APP --- | |
| function calculateDose(weight, doseString, presentation) { | |
| const doseValues = doseString.match(/[\d.]+/g).map(Number); | |
| const unit = doseString.includes('mcg') ? 'mcg' : 'mg'; | |
| let doseRange = []; | |
| if (doseValues.length === 1) { | |
| doseRange.push(weight * doseValues[0]); | |
| } else { | |
| doseRange.push(weight * doseValues[0]); | |
| doseRange.push(weight * doseValues[1]); | |
| } | |
| let doseMg = doseRange.map(d => (unit === 'mcg' ? d / 1000 : d)); | |
| let volumeMl = doseMg.map(d => d / presentation.value * (presentation.unit.includes('mcg') ? 1000 : 1)); | |
| const format = (arr) => arr.length === 1 ? arr[0].toFixed(1) : `${arr[0].toFixed(1)} - ${arr[1].toFixed(1)}`; | |
| return `Dosis: <span>${format(doseRange)} ${unit}</span> / Total: <span>${format(volumeMl)} ml</span>`; | |
| } | |
| function updateSRI() { | |
| const weight = parseFloat(patientWeightInput.value) || 0; | |
| if (weight <= 0) { | |
| contentSri.innerHTML = `<div class="text-center py-10 text-gray-400"><i class="fas fa-notes-medical text-4xl mb-3"></i><p>Introduzca un peso válido.</p></div>`; | |
| return; | |
| } | |
| let html = ` | |
| <h2 class="text-lg font-bold text-teal-700 mb-4"><i class="fas fa-list-ol mr-2"></i>Las 7 P's de la Intubación</h2> | |
| <div class="space-y-4 text-sm"> | |
| <p><strong>1. Preparación:</strong> Monitorización, material listo (tubos, laringo, aspirador), fármacos cargados.</p> | |
| <p><strong>2. Preoxigenación:</strong> FiO₂ 100% durante 3-5 minutos con mascarilla reservorio o VMNI.</p> | |
| <div> | |
| <p><strong>3. Premedicación:</strong> (Atenuar respuesta simpática)</p> | |
| <ul class="list-disc ml-6 mt-1 space-y-1"> | |
| ${rsiDrugs.premedicacion.map(drug => `<li class="drug-calculation"><strong>${drug.name}</strong> (${drug.presentation.value} ${drug.presentation.unit}): ${calculateDose(weight, drug.dose, drug.presentation)}</li>`).join('')} | |
| </ul> | |
| </div> | |
| <div> | |
| <p><strong>4. Parálisis con Inducción:</strong> Administrar inductor seguido inmediatamente del paralizante.</p> | |
| <p class="text-xs text-gray-500 mt-1"><u>Inductores:</u></p> | |
| <ul class="list-disc ml-6 mt-1 space-y-1"> | |
| ${rsiDrugs.induccion.map(drug => `<li class="drug-calculation"><strong>${drug.name}</strong> (${drug.presentation.value} ${drug.presentation.unit}): ${calculateDose(weight, drug.dose, drug.presentation)}</li>`).join('')} | |
| </ul> | |
| <p class="text-xs text-gray-500 mt-2"><u>Paralizantes:</u></p> | |
| <ul class="list-disc ml-6 mt-1 space-y-1"> | |
| ${rsiDrugs.paralisis.map(drug => `<li class="drug-calculation"><strong>${drug.name}</strong> (${drug.presentation.value} ${drug.presentation.unit}): ${calculateDose(weight, drug.dose, drug.presentation)}</li>`).join('')} | |
| </ul> | |
| </div> | |
| <p><strong>5. Posicionamiento:</strong> Alineación de ejes oral, faríngeo y laríngeo (posición de olfateo).</p> | |
| <p><strong>6. Progresión del tubo:</strong> Laringoscopia, visualización de cuerdas vocales e inserción del tubo.</p> | |
| <p><strong>7. Post-intubación:</strong> Comprobación (capnografía, auscultación), fijación del tubo, conexión a ventilador e inicio de sedoanalgesia.</p> | |
| </div> | |
| `; | |
| contentSri.innerHTML = html; | |
| } | |
| function updatePumps() { | |
| const weight = parseFloat(patientWeightInput.value) || 0; | |
| const selectedDrugKey = drugSelector.value; | |
| const desiredDose = parseFloat(doseInput.value) || 0; | |
| const drug = perfusionDrugs[selectedDrugKey]; | |
| if (weight <= 0 || !drug) { | |
| pumpResultsDisplay.innerHTML = `<div class="text-center py-10 text-gray-400"><i class="fas fa-notes-medical text-4xl mb-3"></i><p>Introduzca un peso y dosis válidos.</p></div>`; | |
| return; | |
| } | |
| const totalDrugMcg = drug.totalDrugMg * 1000; | |
| const concentrationMcgMl = totalDrugMcg / drug.totalVolumeMl; | |
| const doseMcgMin = desiredDose * weight; | |
| const doseMcgHour = doseMcgMin * 60; | |
| const infusionRateMlH = doseMcgHour / concentrationMcgMl; | |
| let html = ` | |
| <h3 class="text-base font-bold mb-3 text-teal-700"><i class="fas fa-prescription-bottle-alt mr-2"></i>Cálculo para ${drug.name}</h3> | |
| <div class="space-y-3 text-sm"> | |
| <div> | |
| <p class="font-semibold text-gray-600">1. Preparación:</p> | |
| <p class="pl-4">${drug.preparation}</p> | |
| </div> | |
| <div> | |
| <p class="font-semibold text-gray-600">2. Concentración:</p> | |
| <p class="pl-4">La concentración de la mezcla es <strong>${concentrationMcgMl.toFixed(2)} mcg/ml</strong>.</p> | |
| </div> | |
| <div class="mt-4 p-4 bg-teal-50 rounded-lg border border-teal-200"> | |
| <p class="font-semibold text-gray-800 text-base">3. Velocidad de Perfusión:</p> | |
| <p class="text-center text-2xl font-bold text-fuchsia-700 my-2">${infusionRateMlH.toFixed(1)} ml/h</p> | |
| <p class="text-xs text-center text-gray-500">Para una dosis de ${desiredDose} ${drug.doseUnit} en un paciente de ${weight} kg.</p> | |
| </div> | |
| </div> | |
| `; | |
| pumpResultsDisplay.innerHTML = html; | |
| doseUnitSpan.textContent = drug.doseUnit; | |
| } | |
| function handleTabClick(activeTab) { | |
| if (activeTab === 'sri') { | |
| tabSri.classList.add('active'); | |
| tabBombas.classList.remove('active'); | |
| contentSri.classList.remove('hidden'); | |
| contentBombas.classList.add('hidden'); | |
| } else { | |
| tabBombas.classList.add('active'); | |
| tabSri.classList.remove('active'); | |
| contentBombas.classList.remove('hidden'); | |
| contentSri.classList.add('hidden'); | |
| } | |
| updateAllCalculations(); | |
| } | |
| function updateAllCalculations() { | |
| updateSRI(); | |
| updatePumps(); | |
| } | |
| function onDrugSelectionChange() { | |
| const drug = perfusionDrugs[drugSelector.value]; | |
| doseInput.value = drug.defaultDose; | |
| updatePumps(); | |
| } | |
| // --- EVENT LISTENERS --- | |
| tabSri.addEventListener('click', () => handleTabClick('sri')); | |
| tabBombas.addEventListener('click', () => handleTabClick('bombas')); | |
| patientWeightInput.addEventListener('input', updateAllCalculations); | |
| drugSelector.addEventListener('change', onDrugSelectionChange); | |
| doseInput.addEventListener('input', updatePumps); | |
| // --- INICIALIZACIÓN --- | |
| handleTabClick('sri'); | |
| </script> | |
| </body> | |
| </html> |