PORTAL TÉCNICO
TR
Técnico
Sin clínica
Sin plan
--:--:--
0
Pendientes
0
Completados
0
Urgentes
0m
Tiempo Prom.
📤 Subir Estudio
Envía imágenes al motor de IA VoxlumX
Datos del Paciente

Parámetros del Estudio

Médico Referente

Imagen del Estudio
🩻

Arrastra el archivo aquí o haz clic para seleccionar

DICOM (.dcm) · JPEG · PNG — Máx 50MB

📁
Iniciando...
✅ Análisis completado — Motor IA VoxlumX
📋 Cola de Trabajo
Estudios en tiempo real — Puerto DICOM 11112
Cargando worklist...
🩻 Visor DICOM
Visualización y análisis de imágenes médicas
🔍 Zoom
✋ Mover
☀️ Brillo/Contraste
📏 Regla
📐 Ángulo
⬡ ROI/Área
↔️ Flip H
↕️ Flip V
🔄 Rotar
🌓 Invertir
⟳ Reset
HU:
Cerebro
Pulmón
Hueso
Abdomen
Hígado
Tejido
Mediastino
SIN IMAGEN — Carga un estudio
🩻
Arrastra un DICOM aquí o selecciona de la cola
Mediciones Activas
Sin mediciones. Usa las herramientas del visor.
📡 Recepción DICOM en Vivo
Imágenes recibidas desde los equipos de la clínica — Puerto 11112
Conectando...
Modo de Recepción
AUTOMÁTICO — Las imágenes recibidas se envían directamente a IA con los datos del equipo DICOM.
MANUAL
AUTO
Modo Automático activo — Las imágenes se enviarán a IA automáticamente usando los datos recibidos del equipo DICOM.
Cola Stand-by
📡
Esperando imágenes de los equipos...
Puerto DICOM: 11112
⬛ MPR Multiplanar
Reconstrucción en tres planos simultáneos
AXIAL
Plano Axial
CORONAL
Plano Coronal
SAGITAL
Plano Sagital
3D RENDER
🧊
Requiere serie CT
↔️ Comparador
Estudio actual vs estudios previos
ESTUDIO ACTUAL
HOY
🩻
Sin imagen
ESTUDIO PREVIO
PREVIO
🗂️
Selecciona del historial
🗂️ Historial del Paciente
Estudios previos y evolución clínica
Busca un paciente para ver su historial
🖨️ Configuración de Impresión
Configura ANTES de recibir el resultado — se aplica automáticamente
Impresión del Reporte
Impresión automática al recibir resultado
Número de copias
Impresión de Imágenes
Impresión automática de imágenes al recibir resultado
💿 Exportar DVD / USB
Genera un paquete que abre en cualquier Windows 7+

El sistema genera un paquete HTML autoejectable con el visor de imágenes, el reporte y el código QR del paciente. No requiere ningún software especial — abre directamente en cualquier navegador de Windows 7 en adelante.

1
Selecciona el estudio que deseas exportar desde el historial o la cola de trabajo.
2
Elige el contenido a incluir: imágenes, reporte, QR y autorun.
3
Haz clic en Generar — el sistema crea el paquete HTML listo para copiar al DVD o USB.
4
Entrega al paciente — al insertar el USB, se abre automáticamente el visor en el navegador.

CONTENIDO A INCLUIR:
✍️ Firma Digital
Firma electrónica del técnico radiólogo
Datos del Técnico
FIRMA ELECTRÓNICA (dibuja en el área):
💬 Chat con Radiólogo
Comunicación directa en tiempo real
Radiólogo disponible
👨‍⚕️
Dr. Vox Rad
● En línea
Hola, estoy disponible para consultas sobre los estudios. ¿En qué puedo ayudarte?
Dr. Vox Rad · ahora
📊 Estadísticas del Turno
Rendimiento en tiempo real
Resumen del Turno
0
Procesados
0
Urgentes/STAT
0m
Tiempo Prom.
0%
Tasa de éxito
Distribución por Modalidad
Sin datos en este turno
`); pw.document.close(); pw.focus(); setTimeout(()=>pw.print(),500); } function printNow() { if(S.pc.rep==='win') printReport(S.result); if(S.pc.img==='win') window.print(); if(S.pc.img==='dicom') sendToDicom(); } async function testDicom() { const ip=document.getElementById('dicom-ip').value; if(!ip){toast('error','⚠️ Sin IP','Ingresa la IP de la impresora DICOM');return;} toast('info','🔌 Probando conexión','Conectando a '+ip+'...'); try { const r=await fetch('/api/dicom/test-printer',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+S.token},body:JSON.stringify({ip,port:S.pc.port,ae_title:S.pc.ae})}); const d=await r.json(); if(d.success) toast('success','✅ Conexión exitosa','Impresora DICOM respondiendo'); else toast('error','❌ Sin respuesta','Verifica IP y que la impresora esté encendida'); } catch(e){toast('error','❌ Error','No se pudo conectar a la impresora DICOM');} } async function sendToDicom() { if(!S.pc.ip){toast('error','⚠️ Sin impresora DICOM','Configura la IP en Impresión');return;} toast('info','📡 Enviando a impresora DICOM','IP: '+S.pc.ip); try { await fetch('/api/dicom/print',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+S.token},body:JSON.stringify({study_id:S.studyId,printer_ip:S.pc.ip,printer_port:S.pc.port,ae_title:S.pc.ae})}); toast('success','✅ Enviado','Las imágenes se están imprimiendo en la impresora DICOM'); } catch(e){toast('error','❌ Error DICOM',e.message);} } // DVD/USB function genDVD() { if(!S.studyId&&!S.result){toast('error','⚠️ Sin estudio','Primero envía un estudio a análisis');return;} toast('info','💿 Generando paquete','Un momento...'); setTimeout(()=>{document.getElementById('dvd-res').style.display='block';toast('success','✅ Listo','El paquete DVD/USB está listo para descargar');},2000); } function dlDVD() { const content=S.result?(S.result.findings||S.result.conclusion||''):'Reporte no disponible'; const pn=document.getElementById('patient_name').value||'Paciente'; const html=`VoxlumX - ${pn}
MEDICAL SYSTEMS · TELERADIOLOGÍA IA

Reporte del Estudio

Paciente
${pn}
Fecha
${new Date().toLocaleString('es-DO')}
Modalidad
${document.getElementById('modality').value}
Hallazgos IA
${content}
© 2026 VoxlumX Medical Systems · Reporte generado por IA · Requiere validación de médico especialista
`; const blob=new Blob([html],{type:'text/html'}); const url=URL.createObjectURL(blob); const a=document.createElement('a'); a.href=url; a.download='VoxlumX_'+pn.replace(/\s/g,'_')+'_'+Date.now()+'.html'; a.click(); URL.revokeObjectURL(url); toast('success','⬇️ Descargando','Copia el archivo al DVD o USB'); } // QR function showQR() { document.getElementById('qr-panel').style.display='block'; const qd=document.getElementById('qrcode'); qd.textContent='QR: '+window.location.origin+'/api/reports/'+S.studyId; qd.style.cssText='width:110px;height:110px;background:#fff;display:flex;align-items:center;justify-content:center;color:#000;font-size:0.6em;text-align:center;padding:8px;border-radius:4px;'; } // VISOR function previewDicom() { const f=fi.files[0]; if(!f) return; go('visor'); const canvas=document.getElementById('dicom-canvas'); const ctx=canvas.getContext('2d'); const ph=document.getElementById('viewer-ph'); if(f.type.startsWith('image/')) { const img=new Image(); img.onload=()=>{ canvas.style.display='block'; ph.style.display='none'; ctx.fillStyle='#000'; ctx.fillRect(0,0,canvas.width,canvas.height); const sc=Math.min(canvas.width/img.width,canvas.height/img.height); const x=(canvas.width-img.width*sc)/2, y=(canvas.height-img.height*sc)/2; ctx.drawImage(img,x,y,img.width*sc,img.height*sc); document.getElementById('viewer-info').textContent=f.name+' · '+img.width+'×'+img.height; }; img.src=URL.createObjectURL(f); } else { canvas.style.display='none'; ph.style.display='block'; ph.innerHTML='
🩻
DICOM: '+f.name+'
Requiere Cornerstone.js para visualización completa
'; } } function setTool(t,el) { S.tool=t; document.querySelectorAll('.tool').forEach(b=>b.classList.remove('active')); el.classList.add('active'); } function setWL(w,l) { S.vState.wl={w,l}; document.getElementById('viewer-info').textContent='W:'+w+' L:'+l; } function flipH() { S.vState.flipH=!S.vState.flipH; applyT(); } function flipV() { S.vState.flipV=!S.vState.flipV; applyT(); } function rot90() { S.vState.rot=(S.vState.rot+90)%360; applyT(); } function invertImg() { S.vState.inv=!S.vState.inv; document.getElementById('dicom-canvas').style.filter=S.vState.inv?'invert(1)':''; } function resetViewer() { S.vState={zoom:1,rot:0,flipH:false,flipV:false,inv:false}; applyT(); document.getElementById('dicom-canvas').style.filter=''; } function applyT() { const c=document.getElementById('dicom-canvas'); c.style.transform=`rotate(${S.vState.rot}deg) scaleX(${S.vState.flipH?-1:1}) scaleY(${S.vState.flipV?-1:1})`; } // FIRMA function initFirma() { const c=document.getElementById('firma-canvas'); if(!c) return; const ctx=c.getContext('2d'); ctx.strokeStyle='#00f2ff'; ctx.lineWidth=2; ctx.lineCap='round'; let drawing=false; c.addEventListener('mousedown',e=>{drawing=true;ctx.beginPath();ctx.moveTo(e.offsetX,e.offsetY);}); c.addEventListener('mousemove',e=>{if(!drawing)return;ctx.lineTo(e.offsetX,e.offsetY);ctx.stroke();}); c.addEventListener('mouseup',()=>drawing=false); c.addEventListener('mouseleave',()=>drawing=false); c.addEventListener('touchstart',e=>{e.preventDefault();drawing=true;const t=e.touches[0],r=c.getBoundingClientRect();ctx.beginPath();ctx.moveTo(t.clientX-r.left,t.clientY-r.top);},{passive:false}); c.addEventListener('touchmove',e=>{e.preventDefault();if(!drawing)return;const t=e.touches[0],r=c.getBoundingClientRect();ctx.lineTo(t.clientX-r.left,t.clientY-r.top);ctx.stroke();},{passive:false}); c.addEventListener('touchend',()=>drawing=false); } function clearFirma() { const c=document.getElementById('firma-canvas'); c.getContext('2d').clearRect(0,0,c.width,c.height); S.firma=null; document.getElementById('firma-ok').style.display='none'; } function saveFirma() { const n=document.getElementById('tech-name-in').value.trim(); if(!n){toast('error','⚠️ Nombre requerido','Ingresa el nombre del técnico');return;} S.firma=document.getElementById('firma-canvas').toDataURL(); S.techName=n; localStorage.setItem('vx_tech',n); localStorage.setItem('vx_firma',S.firma); document.getElementById('tech-name').textContent=n; document.getElementById('firma-ok').style.display='block'; toast('success','✅ Firma guardada','Se adjuntará a todos los estudios de este turno'); } // CHAT function sendChat() { const inp=document.getElementById('chat-in'), msg=inp.value.trim(); if(!msg) return; const cb=document.getElementById('chat-body'); cb.innerHTML+=`
${msg}
Tú · ${new Date().toLocaleTimeString('es-DO',{hour:'2-digit',minute:'2-digit'})}
`; inp.value=''; cb.scrollTop=cb.scrollHeight; setTimeout(()=>{cb.innerHTML+=`
Recibido. Revisaré el estudio en un momento.
Dr. Vox Rad · ahora
`;cb.scrollTop=cb.scrollHeight;},1500); } // HISTORIAL async function searchHistory() { const q=document.getElementById('search-pat').value.trim(), mod=document.getElementById('filter-mod').value; if(q.length<2) return; try { const r=await fetch(`/api/studies/results?patient=${encodeURIComponent(q)}&modality=${mod}`,{headers:{'Authorization':'Bearer '+S.token}}); const data=await r.json(); const studies=data.studies||data.results||[]; const c=document.getElementById('hist-container'); if(!studies.length){c.innerHTML='
Sin estudios encontrados
';return;} c.innerHTML=studies.map(s=>`
🩻
${s.patient_name||'Paciente'}
${s.modality||'--'} · ${s.region||''} · ${s.created_at?new Date(s.created_at).toLocaleDateString('es-DO'):'--'}
${(s.findings||s.result||'Sin hallazgos').slice(0,120)}...
`).join(''); } catch(e){document.getElementById('hist-container').innerHTML='
Error cargando historial
';} } function loadFromHist(id) { S.studyId=id; toast('info','📂 Estudio cargado',id); go('compare'); } // STATS function loadStats() { const sv=localStorage.getItem('vx_stats'); if(sv) try{Object.assign(S.stats,JSON.parse(sv));}catch(e){} updateSBar(); updateSPage(); } function saveStats() { localStorage.setItem('vx_stats',JSON.stringify(S.stats)); updateSPage(); } function resetStats() { S.stats={total:0,urgent:0,times:[],success:0}; saveStats(); updateSBar(); toast('info','🔄 Turno reiniciado','Estadísticas reseteadas'); } function updateSBar() { document.getElementById('s-done').textContent=S.stats.total; document.getElementById('s-urgent').textContent=S.stats.urgent; const avg=S.stats.times.length?Math.round(S.stats.times.reduce((a,b)=>a+b,0)/S.stats.times.length/60):0; document.getElementById('s-avg').textContent=avg+'m'; } function updateSPage() { document.getElementById('ss-total').textContent=S.stats.total; document.getElementById('ss-urgent').textContent=S.stats.urgent; const avg=S.stats.times.length?Math.round(S.stats.times.reduce((a,b)=>a+b,0)/S.stats.times.length/60):0; document.getElementById('ss-avg').textContent=avg+'m'; const rate=S.stats.total>0?Math.round((S.stats.success/S.stats.total)*100):0; document.getElementById('ss-rate').textContent=rate+'%'; } // TOASTS function toast(type,title,msg) { const icons={success:'✅',error:'❌',info:'ℹ️',warning:'⚠️'}; const c=document.getElementById('toasts'); const t=document.createElement('div'); t.className='toast '+type; t.innerHTML=`
${icons[type]||'📢'}
${title}
${msg}
`; c.appendChild(t); setTimeout(()=>{t.style.opacity='0';t.style.transition='opacity 0.3s';setTimeout(()=>t.remove(),300);},4000); } // STATUS async function checkStatus() { try { const r=await fetch('/api/heartbeat/status'); const d=await r.json(); const dot=document.getElementById('status-dot'); dot.style.background=d.status==='ok'?'var(--green)':'var(--red)'; dot.style.boxShadow='0 0 8px '+(d.status==='ok'?'var(--green)':'var(--red)'); } catch(e){const dot=document.getElementById('status-dot');dot.style.background='var(--red)';dot.style.boxShadow='0 0 8px var(--red)';} }