feat(turnero): buscador y paginación en tab de examenes
Filtrado en tiempo real + paginación client-side (15 por página). Categorías vacías se ocultan automáticamente al buscar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
18d50a3a16
commit
333e856f38
@@ -466,7 +466,13 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
TAB 2 — EXÁMENES Y CONSENTIMIENTOS
|
TAB 2 — EXÁMENES Y CONSENTIMIENTOS
|
||||||
════════════════════════════════════════ -->
|
════════════════════════════════════════ -->
|
||||||
<?php elseif ($tab === 'examenes'): ?>
|
<?php elseif ($tab === 'examenes'): ?>
|
||||||
<p class="section-title">Tipos de examen y sus formularios de consentimiento</p>
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
|
<p class="section-title mb-0">Tipos de examen y sus formularios de consentimiento</p>
|
||||||
|
<div class="ms-auto" style="min-width:220px">
|
||||||
|
<input type="search" id="exam-buscar" class="form-control form-control-sm"
|
||||||
|
placeholder="Buscar examen…" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<?php
|
<?php
|
||||||
// Agrupar por categoría
|
// Agrupar por categoría
|
||||||
$categorias = [];
|
$categorias = [];
|
||||||
@@ -475,6 +481,7 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
$categorias[$cat][] = $et;
|
$categorias[$cat][] = $et;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
<div id="exam-lista">
|
||||||
<?php foreach ($categorias as $cat => $items): ?>
|
<?php foreach ($categorias as $cat => $items): ?>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="fw-semibold text-uppercase small text-secondary mb-1" style="font-size:.7rem;letter-spacing:.07em">
|
<div class="fw-semibold text-uppercase small text-secondary mb-1" style="font-size:.7rem;letter-spacing:.07em">
|
||||||
@@ -513,6 +520,8 @@ $tab = $_GET['tab'] ?? 'lugares';
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
</div><!-- #exam-lista -->
|
||||||
|
<div id="exam-pager"></div>
|
||||||
<?php if (empty($examTipos)): ?>
|
<?php if (empty($examTipos)): ?>
|
||||||
<p class="text-muted text-center py-3">No hay tipos de examen configurados</p>
|
<p class="text-muted text-center py-3">No hay tipos de examen configurados</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -1203,6 +1212,58 @@ async function eliminarExamen(id, nombre) {
|
|||||||
} catch (e) { toast('Error de conexión', 'error'); }
|
} catch (e) { toast('Error de conexión', 'error'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// BUSCADOR + PAGINADOR — Tab examenes
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
(function () {
|
||||||
|
const PAGE = 15;
|
||||||
|
let page = 1, q = '';
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
const lista = document.getElementById('exam-lista');
|
||||||
|
if (!lista) return;
|
||||||
|
const rows = Array.from(lista.querySelectorAll('.item-row'));
|
||||||
|
const term = q.toLowerCase();
|
||||||
|
const matched = rows.filter(r => r.textContent.toLowerCase().includes(term));
|
||||||
|
|
||||||
|
rows.forEach(r => r.hidden = true);
|
||||||
|
const start = (page - 1) * PAGE;
|
||||||
|
matched.slice(start, start + PAGE).forEach(r => r.hidden = false);
|
||||||
|
|
||||||
|
// Ocultar categorías vacías
|
||||||
|
lista.querySelectorAll('.mb-3').forEach(cat => {
|
||||||
|
cat.hidden = Array.from(cat.querySelectorAll('.item-row')).every(r => r.hidden);
|
||||||
|
});
|
||||||
|
|
||||||
|
renderPager(matched.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPager(total) {
|
||||||
|
const el = document.getElementById('exam-pager');
|
||||||
|
if (!el) return;
|
||||||
|
const pages = Math.ceil(total / PAGE);
|
||||||
|
if (pages <= 1) { el.innerHTML = total ? `<small class="text-muted">${total} resultado${total!==1?'s':''}</small>` : ''; return; }
|
||||||
|
const prev = `<button class="btn btn-sm btn-outline-secondary" ${page===1?'disabled':''} onclick="examPag(${page-1})"><i class="fas fa-chevron-left"></i></button>`;
|
||||||
|
const next = `<button class="btn btn-sm btn-outline-secondary" ${page===pages?'disabled':''} onclick="examPag(${page+1})"><i class="fas fa-chevron-right"></i></button>`;
|
||||||
|
el.innerHTML = `<div class="d-flex align-items-center gap-2 mt-2">
|
||||||
|
<small class="text-muted">${total} resultados</small>
|
||||||
|
<div class="ms-auto d-flex align-items-center gap-1">
|
||||||
|
${prev}
|
||||||
|
<span class="small px-1">Página ${page} de ${pages}</span>
|
||||||
|
${next}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.examPag = function (p) { page = p; update(); };
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const inp = document.getElementById('exam-buscar');
|
||||||
|
if (inp) inp.addEventListener('input', () => { q = inp.value; page = 1; update(); });
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// TAB 3: PRIORIDADES
|
// TAB 3: PRIORIDADES
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user