Agrega botón de cambio de estado en cada fila del historial de turnos.
Admins (sin role_id) pueden reabrir turnos finalizados/ausentes/cancelados.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
zoom en el elemento hijo encogía 100vh dejando espacio vacío abajo.
En html el browser recalcula vh correctamente y el layout llena la pantalla.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Los nombres en MAYÚSCULAS son deletreados por el motor de voz.
Convertir a Title Case para que se lean como palabras normales.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Elimina speechSynthesis.cancel() para que los anuncios no se interrumpan.
El overlay espera a que el TTS termine (onend) antes de pasar al siguiente,
con un mínimo visual de 5 segundos.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Muestra "Hoy", "Ayer" o la fecha entre grupos de mensajes de días distintos.
El timestamp del bubble ahora solo muestra la hora.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sonido más fuerte (gain 1.0, 3 pulsos grave-agudo), se repite cada
30 s mientras el banner no se cierre con click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El Tab es la señal de fin de cédula en el barcode. Al recibirlo se
activa _scannerLocked y se ignoran todos los caracteres siguientes
(apellidos, fecha, sangre) hasta que llegue Enter o se limpie el campo.
También se redujo el numpad ~10% para que entre en pantalla.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restaura campo WhatsApp (inputmode=none), mueve el numpad debajo.
El numpad detecta cuál input tiene foco y escribe en ese campo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El campo WhatsApp generaba fricción innecesaria. Ahora el numpad
tiene un botón "Obtener mi turno" de ancho completo como última fila.
WhatsApp queda como hidden vacío para no romper la API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- inputmode=none en inp-cedula suprime el teclado Windows
- Grid 3×4 con dígitos 0-9, C (borrar todo) y ⌫ (borrar uno)
- pointerdown + preventDefault mantiene el foco en el input
- El escáner sigue funcionando (escribe por keydown, no por IME)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Navegar al ERP dentro del kiosk no sirve porque --kiosk es un flag
del proceso. window.close() cierra Chrome y devuelve el escritorio
Windows táctil, desde donde pueden abrir el ERP normalmente.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Toca el logo o el nombre del laboratorio 7 veces en 4 s para abrir
el overlay de salida: ir al ERP, recargar kiosko o cancelar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- blur() en mostrarTicket, seleccionarOtraPrioridad y volverPrioridades
para que ningún campo quede enfocado al cambiar de pantalla
- pointerup en cada input: si ya estaba enfocado, blur+focus(30ms)
fuerza a Windows a reinvocar el teclado táctil
- El focus programático de seleccionarPrioridad se conserva (escáner)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El Tab se bloquea pero las letras seguían escribiéndose en el campo.
Ahora cualquier carácter no numérico trunca el valor inmediatamente.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El lector de cédula envía los campos con Tab entre ellos. Se previene
el cambio de foco en keydown. Si algo llega igualmente a inp-cel
(letras) se limpia y regresa el foco a la cédula.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El escáner envía cedula+nombre+apellidos+… en una sola ráfaga.
Se corta en el primer espacio/tab para quedarse solo con los dígitos.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- cambiar_estado: permite en_espera_lugar→en_recepcion y en_servicio→en_recepcion
- Al volver de un lugar limpia lugar_destino_id, llamado_lugar_at, inicio_lugar_at,
fin_recepcion_at y atendido_lugar_por para que quede reasignable
- lugar.php: botón "A recepción" visible en en_espera_lugar y en_servicio
- resetFicha oculta el botón nuevo al limpiar la ficha
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- touch-action: manipulation directo en cada botón e input (no solo en body)
- -ms-touch-action para compatibilidad Edge legacy
- position: relative en .kiosko-wrap para contener screens absolutas
- inset: 0 en .screen.hidden para que no se salga del contenedor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El JS no es servido por SigREST sino instalado en AppData del usuario.
Se agrega /assets/js/SigWebTablet.js como primera URL; los puertos
localhost quedan como fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Chrome bloquea scripts HTTP desde páginas HTTPS; SigWeb >=1.6.4 expone
el SDK en https://localhost:47290 para este caso. Fallback a http://47289
para instalaciones antiguas.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- cancelar_toma_pendiente: añade JOIN por paciente_id para prevenir IDOR
- cancelar_toma_pendiente: requiere turno_id para validar propiedad
- get_tomas_pendientes: porta filtros condicionales y _tomas_config de
guardar_toma.php para mostrar conteo de firmas correcto
- lugar.php: refresca sección tomas previas al completar via turneroFirmado
- lugar.php: muestra error en catch de cargarTomasPrevias en vez de silenciar
- lugar.php: limpia _tomaAlertados al cancelar toma previa
- lugar.php: pasa turno_id en POST de cancelar para ownership check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cuando el paciente regresa con un turno nuevo, toma de muestras muestra
las tomas en_progreso de visitas anteriores con botón Continuar o Cancelar.
Cancelar marca estado='rechazado' (campo ya existía en el enum).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a patient selects 'Muestra pendiente' (prioridad F) at the kiosk,
the turn is immediately set to en_espera_lugar pointing to the first
active muestras location. Recepcion never sees it; toma de muestras
picks it up from its queue with no consent forms required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Was sending 'consentimiento_turno' (plain text fallback) while the
configured template is 'consentimiento_turno_v2'. Now reads
turnero_wa_template and turnero_wa_lang from lab_config, matching
the same logic used in create_turno.php (kiosk).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add turno_id column to rips_examenes_pendientes (already migrated)
- Filter turno_id IS NULL in get_examenes_rips.php query
- New marcar_rips_usado.php marks record as consumed when loaded
- cargarExamenesRips() calls marker after loading exams into the turn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If the kiosk captured a numeric document number as paciente_nombre,
fire consultarExamenesRips immediately on turn open without waiting
for the receptionist to manually search the patient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously the history section required a manual click to expand and load.
Now it opens and fetches automatically when a patient is selected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detecta si el pad físico responde (GetTabletState), si falla instanciar
SigWebTablet (posible conflicto con SigPlus), y guía paso a paso.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detecta SigWeb al cargar; muestra badge verde solo si localhost:47289
responde. Si no hay pad, no aparece nada.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
El iframe pasa targetMs al padre via postMessage. El padre corre su propio
intervalo (5s) que dispara la notificación si el modal está cerrado.
Si el iframe alcanza el 0 primero, cancela el del padre para no duplicar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Usa Web Notifications API via postMessage iframe→parent para alertar
incluso cuando el tab está en segundo plano o la pantalla ocupada.
Pide permiso al iniciar el protocolo (primer gesto del usuario).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sin el sort, Otro (2 min) aparecía después de Minuto 15 en schema order,
haciendo que el countdown arrancara con 15 min en vez de 2.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sel-lugar movido a última sección (antes de acciones) para que el
usuario lo seleccione justo antes de guardar/pasar
- resetCheckboxes() ahora también limpia sel-lugar entre turnos
- pasarALugar() lee sel-lugar directamente como primera opción,
evitando que un solicitudActiva.lugar_id desactualizado cause errores
- Botón refresh (fa-sync-alt) en cabecera de consentimientos llama
refrescarConsentimientosLugar() para ver estado sin recargar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>