feat(bandeja): filtros por fecha, nombre, # orden y estado

- Inputs desde/hasta pasan al API y filtran por rango de fechas
- Buscador cubre nombre, número de orden, código y examen
- API usa fecha cuando se pasa, sesión actual como fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-29 20:22:22 -05:00
co-authored by Claude Sonnet 4.6
parent 4cb133010a
commit 118e98b360
2 changed files with 23 additions and 14 deletions
+14 -10
View File
@@ -91,6 +91,17 @@ if (isset($_GET['turno_id'])) {
}
// ── LISTA ─────────────────────────────────────────────────────
$desde = $_GET['desde'] ?? null;
$hasta = $_GET['hasta'] ?? null;
if ($desde && $hasta) {
$whereClause = "DATE(t.inicio_lugar_at) BETWEEN ? AND ?";
$params = [$desde, $hasta];
} else {
$whereClause = "t.sesion_id = ?";
$params = [$sesionId];
}
$stmt = $pdo->prepare("
SELECT t.id, t.codigo, t.paciente_nombre, t.estado,
t.inicio_lugar_at, t.fin_lugar_at, t.bandeja_visto_at,
@@ -107,24 +118,17 @@ $stmt = $pdo->prepare("
LEFT JOIN turnero_examen_items tei ON tei.solicitud_id = ts.id
LEFT JOIN exam_tipos et ON et.id = tei.exam_tipo_id
LEFT JOIN turnero_comentarios tc ON tc.turno_id = t.id
WHERE t.sesion_id = ? AND t.inicio_lugar_at IS NOT NULL
WHERE $whereClause AND t.inicio_lugar_at IS NOT NULL
GROUP BY t.id
ORDER BY ts.numero_orden ASC
");
$stmt->execute([$sesionId]);
$stmt->execute($params);
$todos = $stmt->fetchAll(PDO::FETCH_ASSOC);
$pendientes = array_values(array_filter($todos, fn($t) => $t['bandeja_visto_at'] === null));
$vistos = array_values(array_filter($todos, fn($t) => $t['bandeja_visto_at'] !== null));
$stmtMp = $pdo->prepare("
SELECT COUNT(*) FROM turnero_muestras tm
JOIN turnero_solicitudes ts ON ts.id = tm.solicitud_id
JOIN turnero_turnos t ON t.id = ts.turno_id
WHERE t.sesion_id = ? AND tm.estado = 'pendiente'
");
$stmtMp->execute([$sesionId]);
$muestrasPendientes = (int)$stmtMp->fetchColumn();
$muestrasPendientes = array_sum(array_column($todos, 'muestras_pendientes'));
jsonOk([
'pendientes' => $pendientes,
+9 -4
View File
@@ -352,11 +352,13 @@ Layout::open('Bandeja del día', 'fas fa-layer-group');
<div class="bnd-wrap">
<div class="bnd-topbar">
<span class="bnd-title"><i class="fas fa-layer-group"></i> Bandeja del día</span>
<span class="bnd-title"><i class="fas fa-layer-group"></i> Bandeja</span>
<span class="bnd-chip bnd-chip-total" id="st-total"><i class="fas fa-users"></i> —</span>
<span class="bnd-chip bnd-chip-pend" id="st-pend"><i class="fas fa-clock"></i> Por revisar: —</span>
<span class="bnd-chip bnd-chip-vis" id="st-vis"><i class="fas fa-eye"></i> Vistos: —</span>
<span class="bnd-chip bnd-chip-mp" id="st-mp"><i class="fas fa-exclamation-triangle"></i> Muestras pend.: —</span>
<input type="date" id="bnd-desde" onchange="_bndRefrescarLista()" style="border:1px solid #cbd5e1;border-radius:6px;padding:3px 7px;font-size:.78rem;color:#475569;background:#fff;outline:none">
<input type="date" id="bnd-hasta" onchange="_bndRefrescarLista()" style="border:1px solid #cbd5e1;border-radius:6px;padding:3px 7px;font-size:.78rem;color:#475569;background:#fff;outline:none">
<select id="bnd-filtro-estado" onchange="_bndFiltrar()" style="border:1px solid #cbd5e1;border-radius:6px;padding:3px 8px;font-size:.78rem;color:#475569;background:#fff;cursor:pointer;outline:none">
<option value="">Todos los estados</option>
<option value="en_espera_lugar">En espera</option>
@@ -374,7 +376,7 @@ Layout::open('Bandeja del día', 'fas fa-layer-group');
<div class="bnd-body">
<div class="bnd-list">
<div class="bnd-search-box">
<input type="text" id="bnd-filtro" placeholder="Buscar por nombre o examen…" oninput="_bndFiltrar()" autocomplete="off">
<input type="text" id="bnd-filtro" placeholder="Nombre, # orden o examen…" oninput="_bndFiltrar()" autocomplete="off">
</div>
<div class="bnd-list-scroll" id="bnd-list-scroll">
<div class="bnd-section-hdr">Cargando...</div>
@@ -436,7 +438,10 @@ async function _bndRefrescarLista() {
spin.style.transform = 'rotate(360deg)';
setTimeout(()=>{ spin.style.transition=''; spin.style.transform=''; }, 400);
const res = await fetch(BND_API).then(r=>r.json()).catch(()=>null);
const desde = document.getElementById('bnd-desde')?.value || '';
const hasta = document.getElementById('bnd-hasta')?.value || '';
const qs = (desde && hasta) ? `?desde=${desde}&hasta=${hasta}` : '';
const res = await fetch(BND_API + qs).then(r=>r.json()).catch(()=>null);
if (!res?.ok) return;
_bndAllData = res;
@@ -453,7 +458,7 @@ function _bndFiltrar() {
const q = (document.getElementById('bnd-filtro')?.value || '').toLowerCase().trim();
const st = document.getElementById('bnd-filtro-estado')?.value || '';
const match = t =>
(!q || (t.paciente_nombre || '').toLowerCase().includes(q) || (t.examenes_txt || '').toLowerCase().includes(q)) &&
(!q || (t.paciente_nombre || '').toLowerCase().includes(q) || (t.examenes_txt || '').toLowerCase().includes(q) || String(t.numero_orden || '').includes(q) || (t.codigo || '').toLowerCase().includes(q)) &&
(!st || (st === 'muestras_pendientes' ? +t.muestras_pendientes > 0 : t.estado === st));
_renderLista(