diff --git a/modules/turnero/api/get_display_recepcion.php b/modules/turnero/api/get_display_recepcion.php new file mode 100644 index 0000000..19a52a2 --- /dev/null +++ b/modules/turnero/api/get_display_recepcion.php @@ -0,0 +1,65 @@ +prepare( + "SELECT id, nombre FROM turnero_lugares WHERE id = ? AND tipo = 'recepcion' AND activo = 1" +); +$stmtDesk->execute([$deskId]); +$desk = $stmtDesk->fetch(PDO::FETCH_ASSOC); + +if (!$desk) jsonError('Escritorio no encontrado.', 404); + +$sesionId = obtenerOCrearSesionHoy(); + +// Turno activo en este escritorio (el más reciente llamado_recepcion_at) +$stmtT = $pdo->prepare( + "SELECT t.id, + t.codigo, + t.numero, + t.estado, + t.paciente_nombre, + t.llamado_recepcion_at AS llamado_at, + p.codigo AS prioridad_codigo, + p.nombre AS prioridad_nombre, + p.color AS prioridad_color + FROM turnero_turnos t + JOIN turnero_prioridades p ON p.id = t.prioridad_id + WHERE t.sesion_id = ? + AND t.estado = 'en_recepcion' + AND t.recepcion_desk_id = ? + ORDER BY t.llamado_recepcion_at DESC + LIMIT 1" +); +$stmtT->execute([$sesionId, $deskId]); +$turno = $stmtT->fetch(PDO::FETCH_ASSOC) ?: null; + +// Stats básicos para el footer +$stmtStats = $pdo->prepare( + "SELECT SUM(estado = 'espera') AS en_espera, + SUM(estado IN ('en_recepcion','en_espera_lugar','en_servicio')) AS en_atencion, + SUM(estado = 'finalizado') AS finalizados + FROM turnero_turnos WHERE sesion_id = ?" +); +$stmtStats->execute([$sesionId]); +$stats = $stmtStats->fetch(PDO::FETCH_ASSOC); + +jsonOk([ + 'desk_id' => (int)$desk['id'], + 'desk_nombre'=> $desk['nombre'], + 'turno' => $turno, + 'stats' => $stats, + 'timestamp' => date('c'), +]); diff --git a/modules/turnero/api/llamar_turno.php b/modules/turnero/api/llamar_turno.php index e39d279..b0d8722 100644 --- a/modules/turnero/api/llamar_turno.php +++ b/modules/turnero/api/llamar_turno.php @@ -16,6 +16,7 @@ requireTurnero(); $datos = inputJson(); $area = $datos['area'] ?? ''; $lugarId = isset($datos['lugar_id']) ? (int) $datos['lugar_id'] : null; +$deskId = isset($datos['desk_id']) ? (int) $datos['desk_id'] : null; // ── Validación ──────────────────────────────────────────────── if (!in_array($area, ['recepcion', 'lugar'], true)) { @@ -42,12 +43,13 @@ try { $stmt = $pdo->prepare( 'UPDATE turnero_turnos SET estado = "en_recepcion", - llamado_recepcion_at = NOW(), - inicio_recepcion_at = NOW(), - atendido_recepcion_por = ? + llamado_recepcion_at = NOW(), + inicio_recepcion_at = NOW(), + atendido_recepcion_por = ?, + recepcion_desk_id = COALESCE(?, recepcion_desk_id) WHERE id = ? AND estado = "espera"' ); - $stmt->execute([adminId(), $turno['id']]); + $stmt->execute([adminId(), $deskId, $turno['id']]); if ($stmt->rowCount() === 0) { // Otro proceso lo tomó primero (race condition) diff --git a/modules/turnero/api/rellamar.php b/modules/turnero/api/rellamar.php new file mode 100644 index 0000000..6535487 --- /dev/null +++ b/modules/turnero/api/rellamar.php @@ -0,0 +1,47 @@ +prepare( + "UPDATE turnero_turnos + SET llamado_recepcion_at = NOW(), + recepcion_desk_id = COALESCE(?, recepcion_desk_id) + WHERE id = ? AND estado = 'en_recepcion'" +); +$stmt->execute([$deskId, $turnoId]); + +if ($stmt->rowCount() === 0) { + jsonError('El turno no está en estado en_recepcion o no existe.', 404); +} + +// Devolver el turno actualizado para que recepcion.php abra la ficha +$stmtT = $pdo->prepare( + "SELECT t.*, + p.codigo AS prioridad_codigo, + p.nombre AS prioridad_nombre, + p.color AS prioridad_color + FROM turnero_turnos t + JOIN turnero_prioridades p ON p.id = t.prioridad_id + WHERE t.id = ?" +); +$stmtT->execute([$turnoId]); +$turno = $stmtT->fetch(PDO::FETCH_ASSOC); + +jsonOk(['turno' => $turno]); diff --git a/modules/turnero/module.php b/modules/turnero/module.php index 40d20a9..c1256dd 100644 --- a/modules/turnero/module.php +++ b/modules/turnero/module.php @@ -3,6 +3,41 @@ * Descriptor del módulo Turnero — Oleada 1 * Sistema de Turnero Inteligente con gestión de consentimientos informados. */ + +// ── Links estáticos base ────────────────────────────────────── +$_trLinks = [ + ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'], + ['name' => 'Configuración', 'icon' => 'fas fa-sliders-h', 'route' => '/erp.php?m=turnero&v=configuracion'], + ['name' => 'Kiosko', 'icon' => 'fas fa-desktop', 'route' => '/erp.php?m=turnero&v=kiosko'], + ['name' => 'Pantalla TV Global', 'icon' => 'fas fa-th-large', 'route' => '/erp.php?m=turnero&v=display_global'], +]; + +// ── Links dinámicos: un enlace por escritorio de Recepción ──── +try { + $_trPdo = Database::getInstance()->getConnection(); + $_trDesks = $_trPdo->query( + "SELECT id, nombre FROM turnero_lugares + WHERE activo = 1 AND tipo = 'recepcion' + ORDER BY sort_order ASC" + )->fetchAll(PDO::FETCH_ASSOC); + + if (!empty($_trDesks)) { + foreach ($_trDesks as $_d) { + $_trLinks[] = [ + 'name' => $_d['nombre'], + 'icon' => 'fas fa-concierge-bell', + 'route' => '/erp.php?m=turnero&v=recepcion&desk_id=' . (int)$_d['id'], + ]; + } + } else { + // Sin escritorios configurados: enlace genérico + $_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => '/erp.php?m=turnero&v=recepcion']; + } +} catch (\Throwable $_) { + // BD no disponible todavía (instalación inicial) + $_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => '/erp.php?m=turnero&v=recepcion']; +} + return [ 'slug' => 'turnero', 'name' => 'Turnero', @@ -13,12 +48,5 @@ return [ 'sort_order' => 40, 'oleada' => 1, 'description' => 'Sistema de turnos presenciales en recepción con prioridades, consentimientos y pantallas TV', - 'links' => [ - ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'], - ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => '/erp.php?m=turnero&v=recepcion'], - ['name' => 'Configuración', 'icon' => 'fas fa-sliders-h', 'route' => '/erp.php?m=turnero&v=configuracion'], - ['name' => 'Kiosko', 'icon' => 'fas fa-desktop', 'route' => '/erp.php?m=turnero&v=kiosko'], - ['name' => 'Pantalla TV', 'icon' => 'fas fa-tv', 'route' => '/erp.php?m=turnero&v=display'], - ['name' => 'Pantalla TV Global', 'icon' => 'fas fa-th-large', 'route' => '/erp.php?m=turnero&v=display_global'], - ], + 'links' => $_trLinks, ]; diff --git a/modules/turnero/views/display_global.php b/modules/turnero/views/display_global.php index 394b83a..3732f96 100644 --- a/modules/turnero/views/display_global.php +++ b/modules/turnero/views/display_global.php @@ -231,12 +231,126 @@ $_labColor = preg_match('/^#[0-9a-fA-F]{3,8}$/', $_dispCfg['doc_color'] ?? '') .stat-item .lbl { font-size: .6rem; color: rgba(255,255,255,.65); text-transform: uppercase; letter-spacing: 1px; } .stat-sep { width: 1px; height: 26px; background: rgba(255,255,255,.2); } + -
+ +
+
+
+
+
Pase a Recepción
+
A01
+
+
+
+
+
+ + +
-
@@ -248,86 +362,58 @@ $_labColor = preg_match('/^#[0-9a-fA-F]{3,8}$/', $_dispCfg['doc_color'] ?? '')
-
--:--:--
- -
- - -
-
- Recepción -
-
- -
+
+
+
Recepción
+
- - -
- - -
-
- Toma de Muestras -
-
- -
+
+
+
Toma de Muestras
+
-
-
- EN ESPERA - Cola vacía + EN ESPERA +
+ Cola vacía
-
-
-
-
En espera
-
+
En espera
-
-
-
En atención
-
+
En atención
-
-
-
Atendidos hoy
-
+
Atendidos
-
-
-
Total del día
-
+
Total día
-
-
-
Tiempo prom.
-
+
T. promedio
+
+ + diff --git a/modules/turnero/views/recepcion.php b/modules/turnero/views/recepcion.php index ad0fa35..c92dbcb 100644 --- a/modules/turnero/views/recepcion.php +++ b/modules/turnero/views/recepcion.php @@ -27,11 +27,26 @@ try { $cat = $ex['categoria'] ?: 'General'; $examenesAgrupados[$cat][] = $ex; } + + // Escritorio de recepción (opcional, vía ?desk_id=X) + $deskId = (int)($_GET['desk_id'] ?? 0); + $desk = null; + if ($deskId) { + $stmtDesk = $pdo->prepare( + "SELECT id, nombre FROM turnero_lugares WHERE id = ? AND tipo = 'recepcion' AND activo = 1" + ); + $stmtDesk->execute([$deskId]); + $desk = $stmtDesk->fetch(PDO::FETCH_ASSOC) ?: null; + if (!$desk) { $deskId = 0; } // ID inválido → sin desk + } } catch (\Throwable $e) { $lugares = []; $examenesAgrupados = []; + $deskId = 0; + $desk = null; } +$deskNombre = $desk['nombre'] ?? null; // null = vista genérica $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['username'] ?? 'Operador'; ?> @@ -39,7 +54,7 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user'][' - Recepción — Turnero + <?= htmlspecialchars($deskNombre ?? 'Recepción') ?> — Turnero @@ -169,17 +184,19 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
- - Recepción + + Turno:
- - Ver Lugar + + + Ver Pantalla + @@ -364,8 +381,9 @@ let solicitudActiva = null; let consentimientos = []; let pollingColaId = null; -const API = 'modules/turnero/api/'; +const API = 'modules/turnero/api/'; const API_PAC = 'api/lab/get_pacientes.php'; +const DESK_ID = ; // ── Arranque ────────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { @@ -421,7 +439,7 @@ async function llamarSiguiente() { const res = await fetch(API + 'llamar_turno.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ area: 'recepcion' }), + body: JSON.stringify({ area: 'recepcion', desk_id: DESK_ID }), }); const json = await res.json(); if (!json.ok) { mostrarError(json.error); return; } @@ -454,8 +472,18 @@ async function seleccionarTurno(turnoId) { // ── Llamar turno específico (cambia estado → en_recepcion) ───────── async function llamarTurnoEspecifico(turnoId, estadoActual) { - // Si ya está en recepción, solo abrir ficha sin intentar re-transicionar + // Si ya está en recepción: re-llamar (actualiza llamado_at para que la pantalla TV reactive) if (estadoActual === 'en_recepcion') { + try { + const res = await fetch(API + 'rellamar.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ turno_id: turnoId, desk_id: DESK_ID }), + }); + const json = await res.json(); + if (json.ok && json.turno) { abrirFicha(json.turno); return; } + } catch (_) {} + // Fallback: solo abrir ficha seleccionarTurno(turnoId); return; }