- DB: columna muestra_espera_at en turnero_turnos - Panel 'Esperando siguiente muestra' en la cola de lugar.php · Muestra pacientes en espera con countdown a siguiente_toma_at · Botón 'Llamar' los devuelve a la cola activa - Botón 'Mandar a espera' en la ficha (visible cuando toma progresiva activa) · Desaparece de la cola principal, queda en sección de espera - get_cola.php: excluye muestra_espera_at IS NOT NULL de cola y activo · Agrega array en_espera_muestra en la respuesta - Nuevas APIs: poner_en_espera_muestra.php, llamar_desde_espera.php Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
208 lines
8.5 KiB
PHP
208 lines
8.5 KiB
PHP
<?php
|
|
/**
|
|
* GET /modules/turnero/api/get_cola.php
|
|
* Devuelve el estado de la cola para pantallas TV y kiosko.
|
|
* No requiere autenticación (acceso público).
|
|
*
|
|
* Query params:
|
|
* area string requerido "recepcion" | "lugar"
|
|
* lugar_id int requerido si area = "lugar"
|
|
*/
|
|
|
|
require_once __DIR__ . '/_helpers.php';
|
|
requireMethod('GET');
|
|
|
|
$area = isset($_GET['area']) ? trim($_GET['area']) : '';
|
|
$lugarId = isset($_GET['lugar_id']) ? (int) $_GET['lugar_id'] : null;
|
|
|
|
if (!in_array($area, ['recepcion', 'lugar'], true)) {
|
|
jsonError('area debe ser "recepcion" o "lugar".');
|
|
}
|
|
if ($area === 'lugar' && !$lugarId) {
|
|
jsonError('lugar_id es obligatorio cuando area = "lugar".');
|
|
}
|
|
|
|
$pdo = db();
|
|
|
|
// ── Sesión de hoy ─────────────────────────────────────────────
|
|
// Si no existe sesión hoy o está cerrada (fin_at set), pantalla limpia.
|
|
$_ses = sesionHoy();
|
|
$sesionCerrada = (!$_ses || $_ses['fin_at'] !== null);
|
|
// Usar sesion_id real solo si está abierta; 0 hace que las queries devuelvan vacío.
|
|
$sesionId = ($sesionCerrada) ? 0 : (int)$_ses['id'];
|
|
|
|
if ($sesionCerrada) {
|
|
jsonOk([
|
|
'sesion_cerrada' => true,
|
|
'activo' => null,
|
|
'cola' => [],
|
|
'stats' => [
|
|
'total' => 0, 'en_espera' => 0, 'en_recepcion' => 0,
|
|
'en_espera_lugar' => 0, 'en_servicio' => 0,
|
|
'finalizados' => 0, 'no_atendidos' => 0,
|
|
'tiempo_promedio_atencion' => null,
|
|
],
|
|
'timestamp' => date('c'),
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// ── Cola según área ───────────────────────────────────────────
|
|
if ($area === 'recepcion') {
|
|
// Recepción: todos los turnos en espera/en_recepcion
|
|
$inEstados = "'espera', 'en_recepcion'";
|
|
$stmt = $pdo->prepare(
|
|
"SELECT t.id, t.codigo, t.numero, t.estado, t.paciente_nombre,
|
|
t.recepcion_desk_id, t.creado_at, t.llamado_recepcion_at, t.llamado_lugar_at,
|
|
p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre,
|
|
p.color AS prioridad_color, p.orden_peso,
|
|
COALESCE(s.solo_muestras, 0) AS solo_muestras
|
|
FROM turnero_turnos t
|
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
|
LEFT JOIN turnero_solicitudes s ON s.turno_id = t.id
|
|
WHERE t.sesion_id = ? AND t.estado IN ($inEstados)
|
|
ORDER BY t.creado_at ASC"
|
|
);
|
|
$stmt->execute([$sesionId]);
|
|
} else {
|
|
// Lugar: cola = en_espera_lugar del grupo + en_servicio en ESTA estación
|
|
$grupoIds = lugarIdsDeGrupo($lugarId);
|
|
$inLugares = implode(',', array_map('intval', $grupoIds));
|
|
|
|
$cols = "t.id, t.codigo, t.numero, t.estado, t.paciente_nombre,
|
|
t.recepcion_desk_id, t.creado_at, t.llamado_recepcion_at, t.llamado_lugar_at,
|
|
p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre,
|
|
p.color AS prioridad_color, p.orden_peso,
|
|
COALESCE(s.solo_muestras, 0) AS solo_muestras";
|
|
|
|
$stmt = $pdo->prepare(
|
|
"SELECT * FROM (
|
|
(SELECT $cols
|
|
FROM turnero_turnos t
|
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
|
LEFT JOIN turnero_solicitudes s ON s.turno_id = t.id
|
|
WHERE t.sesion_id = ?
|
|
AND t.estado = 'en_espera_lugar'
|
|
AND t.lugar_destino_id IN ($inLugares)
|
|
AND t.muestra_espera_at IS NULL)
|
|
UNION ALL
|
|
(SELECT $cols
|
|
FROM turnero_turnos t
|
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
|
LEFT JOIN turnero_solicitudes s ON s.turno_id = t.id
|
|
WHERE t.sesion_id = ?
|
|
AND t.estado = 'en_servicio'
|
|
AND t.lugar_destino_id = ?
|
|
AND t.muestra_espera_at IS NULL)
|
|
) AS cola_union
|
|
ORDER BY solo_muestras DESC, orden_peso ASC, creado_at ASC"
|
|
);
|
|
$stmt->execute([$sesionId, $sesionId, $lugarId]);
|
|
}
|
|
$cola = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Enriquecer con datos de toma progresiva (cuenta regresiva en tarjetas de cola)
|
|
if (!empty($cola)) {
|
|
$turnoIds = implode(',', array_map('intval', array_column($cola, 'id')));
|
|
$tomaRows = $pdo->query(
|
|
"SELECT tc.turno_id, tc.siguiente_toma_at
|
|
FROM turnero_consentimientos tc
|
|
JOIN lab_formularios f ON f.id = tc.formulario_id AND f.es_toma_progresiva = 1
|
|
WHERE tc.turno_id IN ($turnoIds) AND tc.estado = 'en_progreso'
|
|
ORDER BY tc.siguiente_toma_at ASC"
|
|
)->fetchAll(PDO::FETCH_ASSOC);
|
|
$tomaInfo = [];
|
|
foreach ($tomaRows as $row) {
|
|
if (!isset($tomaInfo[$row['turno_id']])) {
|
|
$tomaInfo[$row['turno_id']] = $row['siguiente_toma_at'];
|
|
}
|
|
}
|
|
foreach ($cola as &$t) {
|
|
$t['en_toma_progresiva'] = isset($tomaInfo[$t['id']]) ? 1 : 0;
|
|
$t['siguiente_toma_at'] = $tomaInfo[$t['id']] ?? null;
|
|
}
|
|
unset($t);
|
|
}
|
|
|
|
// ── Turno actualmente en pantalla (último llamado) ────────────
|
|
$campoLlamado = $area === 'recepcion' ? 'llamado_recepcion_at' : 'llamado_lugar_at';
|
|
$estadoActivo = $area === 'recepcion' ? "'en_recepcion'" : "'en_servicio'";
|
|
// Activo: para lugar filtrar SOLO por esta estación (ya fue asignada al llamar)
|
|
$filtroActivo = $area === 'lugar' ? 'AND t.lugar_destino_id = ? AND t.muestra_espera_at IS NULL' : '';
|
|
$bindActivo = $area === 'lugar' ? [$sesionId, $lugarId] : [$sesionId];
|
|
|
|
$stmt = $pdo->prepare(
|
|
"SELECT t.id,
|
|
t.codigo,
|
|
t.numero,
|
|
t.estado,
|
|
t.paciente_nombre,
|
|
t.{$campoLlamado} 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 = {$estadoActivo}
|
|
{$filtroActivo}
|
|
ORDER BY t.{$campoLlamado} DESC
|
|
LIMIT 1"
|
|
);
|
|
$stmt->execute($bindActivo);
|
|
$activo = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
|
|
|
|
// ── Estadísticas de la sesión ─────────────────────────────────
|
|
$stmt = $pdo->prepare(
|
|
"SELECT
|
|
COUNT(*) AS total,
|
|
SUM(estado = 'espera') AS en_espera,
|
|
SUM(estado = 'en_recepcion') AS en_recepcion,
|
|
SUM(estado = 'en_espera_lugar') AS en_espera_lugar,
|
|
SUM(estado = 'en_servicio') AS en_servicio,
|
|
SUM(estado = 'finalizado') AS finalizados,
|
|
SUM(estado IN ('ausente','cancelado')) AS no_atendidos,
|
|
SEC_TO_TIME(
|
|
AVG(
|
|
CASE WHEN fin_lugar_at IS NOT NULL AND creado_at IS NOT NULL
|
|
THEN TIMESTAMPDIFF(SECOND, creado_at, fin_lugar_at)
|
|
ELSE NULL END
|
|
)
|
|
) AS tiempo_promedio_atencion
|
|
FROM turnero_turnos
|
|
WHERE sesion_id = ?"
|
|
);
|
|
$stmt->execute([$sesionId]);
|
|
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
// ── Pacientes en espera entre muestras (toma progresiva) ─────
|
|
$enEsperaMuestra = [];
|
|
if ($area === 'lugar') {
|
|
$stmtEsp = $pdo->prepare("
|
|
SELECT t.id, t.paciente_nombre, ts.numero_orden, t.muestra_espera_at,
|
|
(SELECT tc.siguiente_toma_at
|
|
FROM turnero_consentimientos tc
|
|
JOIN lab_formularios f ON f.id = tc.formulario_id AND f.es_toma_progresiva = 1
|
|
WHERE tc.turno_id = t.id AND tc.estado = 'en_progreso'
|
|
ORDER BY tc.siguiente_toma_at ASC LIMIT 1) AS siguiente_toma_at
|
|
FROM turnero_turnos t
|
|
JOIN turnero_solicitudes ts ON ts.turno_id = t.id
|
|
WHERE t.sesion_id = ? AND t.lugar_destino_id IN ($inLugares)
|
|
AND t.muestra_espera_at IS NOT NULL AND t.fin_lugar_at IS NULL
|
|
ORDER BY t.muestra_espera_at ASC
|
|
");
|
|
$stmtEsp->execute([$sesionId]);
|
|
$enEsperaMuestra = $stmtEsp->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
jsonOk([
|
|
'sesion_id' => $sesionId,
|
|
'area' => $area,
|
|
'lugar_id' => $lugarId,
|
|
'activo' => $activo,
|
|
'cola' => $cola,
|
|
'en_espera_muestra' => $enEsperaMuestra,
|
|
'stats' => $stats,
|
|
'timestamp' => date('c'),
|
|
]);
|