diff --git a/modules/turnero/api/get_dashboard.php b/modules/turnero/api/get_dashboard.php index 148fd1f..a675c17 100644 --- a/modules/turnero/api/get_dashboard.php +++ b/modules/turnero/api/get_dashboard.php @@ -7,6 +7,7 @@ * - resumen global (total, atendidos, pendientes, ausentes, tiempo promedio) * - desglose por prioridad * - desglose por lugar + * - desglose por recepcionista y por bacteriólogo (quién atendió a cuántos) * - lista de turnos del día (para tabla detalle) */ require_once __DIR__ . '/_helpers.php'; @@ -41,10 +42,12 @@ if (!$sesion) { 'tiempo_espera_promedio_min' => null, 'tiempo_servicio_promedio_min' => null, ], - 'por_prioridad' => [], - 'por_lugar' => [], - 'consent_stats' => [], - 'turnos' => [], + 'por_prioridad' => [], + 'por_lugar' => [], + 'por_recepcionista' => [], + 'por_bacteriologo' => [], + 'consent_stats' => [], + 'turnos' => [], ]); } @@ -125,6 +128,55 @@ $stmtLug = $pdo->prepare( $stmtLug->execute([$sesionId]); $porLugar = $stmtLug->fetchAll(PDO::FETCH_ASSOC); +// ── 4b. Desglose por recepcionista ──────────────────────────── +// Mismo molde que el ranking de enfermeras de lab_domicilios +// (api/lab/get_metricas.php). atendido_recepcion_por guarda al PRIMER +// recepcionista que tomó el turno (COALESCE en cambiar_estado.php). +$stmtRec = $pdo->prepare( + "SELECT u.id, + COALESCE(NULLIF(u.full_name, ''), u.username) AS nombre, + COUNT(t.id) AS total, + SUM(t.estado IN ('finalizado','en_servicio','en_espera_lugar')) AS atendidos, + SUM(t.estado = 'ausente') AS ausentes, + SUM(t.estado = 'cancelado') AS cancelados, + ROUND(AVG( + CASE + WHEN t.fin_recepcion_at IS NOT NULL AND t.inicio_recepcion_at IS NOT NULL + THEN TIMESTAMPDIFF(SECOND, t.inicio_recepcion_at, t.fin_recepcion_at) / 60.0 + END + ), 1) AS tiempo_promedio_min + FROM turnero_turnos t + JOIN admin_users u ON u.id = t.atendido_recepcion_por + WHERE t.sesion_id = ? + GROUP BY u.id, u.full_name, u.username + ORDER BY atendidos DESC, total DESC" +); +$stmtRec->execute([$sesionId]); +$porRecepcionista = $stmtRec->fetchAll(PDO::FETCH_ASSOC); + +// ── 4c. Desglose por bacteriólogo (quien atendió en el lugar) ── +$stmtBac = $pdo->prepare( + "SELECT u.id, + COALESCE(NULLIF(u.full_name, ''), u.username) AS nombre, + COUNT(t.id) AS total, + SUM(t.estado = 'finalizado') AS finalizados, + SUM(t.estado = 'en_servicio') AS en_servicio, + SUM(t.estado = 'ausente') AS ausentes, + ROUND(AVG( + CASE + WHEN t.fin_lugar_at IS NOT NULL AND t.inicio_lugar_at IS NOT NULL + THEN TIMESTAMPDIFF(SECOND, t.inicio_lugar_at, t.fin_lugar_at) / 60.0 + END + ), 1) AS tiempo_promedio_min + FROM turnero_turnos t + JOIN admin_users u ON u.id = t.atendido_lugar_por + WHERE t.sesion_id = ? + GROUP BY u.id, u.full_name, u.username + ORDER BY finalizados DESC, total DESC" +); +$stmtBac->execute([$sesionId]); +$porBacteriologo = $stmtBac->fetchAll(PDO::FETCH_ASSOC); + // ── 5. Lista de turnos del día ──────────────────────────────── $stmtTurnos = $pdo->prepare( "SELECT t.id, t.codigo, t.numero, t.estado, @@ -157,22 +209,47 @@ $stmtTurnos = $pdo->prepare( $stmtTurnos->execute([$sesionId]); $turnos = $stmtTurnos->fetchAll(PDO::FETCH_ASSOC); -// Enriquecer con exámenes y comentarios -foreach ($turnos as &$turno) { +// Enriquecer con exámenes y comentarios — en lote. +// Antes eran 2 consultas por turno dentro del foreach (N+1): con 80 turnos en +// el día eran 160 consultas evitables. Mismo patrón que get_historial.php. +$turnoIds = array_column($turnos, 'id'); +$examenesPorTurno = []; +$comentariosPorTurno = []; + +if ($turnoIds) { + $ph = implode(',', array_fill(0, count($turnoIds), '?')); + $stmtEx = $pdo->prepare( - "SELECT DISTINCT et.nombre FROM turnero_examen_items tei - JOIN exam_tipos et ON et.id = tei.exam_tipo_id - WHERE tei.solicitud_id = (SELECT id FROM turnero_solicitudes WHERE turno_id = ? LIMIT 1)" + "SELECT DISTINCT ts.turno_id, et.nombre + FROM turnero_solicitudes ts + JOIN turnero_examen_items tei ON tei.solicitud_id = ts.id + JOIN exam_tipos et ON et.id = tei.exam_tipo_id + WHERE ts.turno_id IN ($ph) + ORDER BY et.nombre ASC" ); - $stmtEx->execute([$turno['id']]); - $turno['examenes'] = $stmtEx->fetchAll(PDO::FETCH_ASSOC); + $stmtEx->execute($turnoIds); + foreach ($stmtEx->fetchAll(PDO::FETCH_ASSOC) as $row) { + $examenesPorTurno[(int)$row['turno_id']][] = ['nombre' => $row['nombre']]; + } $stmtCom = $pdo->prepare( - "SELECT usuario_nombre, comentario, tipo, creado_at - FROM turnero_comentarios WHERE turno_id = ? ORDER BY creado_at ASC" + "SELECT turno_id, usuario_nombre, comentario, tipo, creado_at + FROM turnero_comentarios + WHERE turno_id IN ($ph) + ORDER BY turno_id, creado_at ASC" ); - $stmtCom->execute([$turno['id']]); - $turno['comentarios'] = $stmtCom->fetchAll(PDO::FETCH_ASSOC); + $stmtCom->execute($turnoIds); + foreach ($stmtCom->fetchAll(PDO::FETCH_ASSOC) as $row) { + $tid = (int)$row['turno_id']; + unset($row['turno_id']); + $comentariosPorTurno[$tid][] = $row; + } +} + +foreach ($turnos as &$turno) { + $tid = (int)$turno['id']; + $turno['examenes'] = $examenesPorTurno[$tid] ?? []; + $turno['comentarios'] = $comentariosPorTurno[$tid] ?? []; } unset($turno); @@ -201,6 +278,8 @@ jsonOk([ 'resumen' => $resumen, 'por_prioridad' => $porPrioridad, 'por_lugar' => $porLugar, + 'por_recepcionista' => $porRecepcionista, + 'por_bacteriologo' => $porBacteriologo, 'consent_stats' => $consentStats, 'turnos' => $turnos, ]); diff --git a/modules/turnero/views/dashboard.php b/modules/turnero/views/dashboard.php index 2e15bb5..6911d8d 100644 --- a/modules/turnero/views/dashboard.php +++ b/modules/turnero/views/dashboard.php @@ -287,6 +287,18 @@ try {
+ + + + + +