Dashboard: que cada indicador diga qué está midiendo

Las etiquetas eran tan cortas que se prestaban para entender otra cosa.
«Servicio prom. en lugar» y «Total prom. puerta a puerta» parecían medir lo
mismo, y no cuadraban entre sí: 16,3 de espera más 7,4 de servicio no dan los
36,6 del total.

Sí cuadran, pero el recorrido tiene cuatro tramos y el tablero solo mostraba
dos. Los otros dos —6,4 min dentro de recepción y 8,4 esperando el puesto—
suman casi quince minutos que no aparecían por ningún lado.

Cada casilla lleva ahora una línea que explica de dónde sale el número, y el
total dice explícitamente por qué es mayor que la suma de las anteriores. Las
etiquetas pasan a lenguaje llano: «Espera para recepción» en vez de «Espera
prom.», «No se presentaron» en vez de «Ausentes».

En la de tiempo en el puesto se aclara que los protocolos prolongados cuentan
hasta la primera toma, para que nadie lea ese número como si midiera lo que
dura una curva completa.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-19 17:23:59 -05:00
co-authored by Claude Opus 5
parent 336836f06d
commit 51b22c4dfc
+25 -10
View File
@@ -47,6 +47,8 @@ Layout::open('Dashboard Turnero', 'fas fa-chart-bar');
.kpi-card .kpi-val { font-size:2rem; font-weight:800; line-height:1.1; }
.kpi-card .kpi-lbl { font-size:.72rem; text-transform:uppercase; letter-spacing:.07em; color:#64748b; margin-top:4px; }
.kpi-card .kpi-sub { font-size:.75rem; color:#94a3b8; margin-top:2px; }
.kpi-ayuda { font-size:.62rem; color:#94a3b8; line-height:1.3; margin-top:5px;
border-top:1px solid #f1f5f9; padding-top:5px; }
/* ── Charts / tables section ── */
.section-card { background:#fff; border:1px solid #e2e8f0; border-radius:12px; padding:20px; margin-bottom:20px; }
@@ -484,14 +486,22 @@ function renderDashboard(json) {
const pct = total > 0 ? Math.round(atendidos / total * 100) : 0;
document.getElementById('kpiGrid').innerHTML = `
${kpiCard(total, '📋 Total turnos', '')}
${kpiCard(atendidos,'✅ Atendidos', pct + '%')}
${kpiCard(enEspera, '⏳ En espera', '')}
${kpiCard(ausentes, '🚫 Ausentes', '')}
${kpiCard(cancelados,'❌ Cancelados', '')}
${kpiCard(tEspera !== null ? tEspera + ' min' : '—', '⏱ Espera prom.', 'hasta recepción')}
${kpiCard(tServicio !== null ? tServicio + ' min' : '—', '⏱ Servicio prom.', 'en lugar')}
${kpiCard(tTotal !== null ? tTotal + ' min' : '—', '⏱ Total prom.', 'puerta a puerta')}
${kpiCard(total, '📋 Turnos del día', '',
'Todos los turnos generados hoy, sin importar cómo terminaron.')}
${kpiCard(atendidos, '✅ Atendidos', pct + ' % del día',
'Ya terminaron su atención, más los que están siendo atendidos en este momento.')}
${kpiCard(enEspera, '⏳ Esperando', '',
'Todavía no los llaman, o ya salieron de recepción y esperan el puesto de toma.')}
${kpiCard(ausentes, '🚫 No se presentaron', '',
'Se les llamó y no llegaron. Recepción registra el motivo al marcarlos.')}
${kpiCard(cancelados, '❌ Cancelados', '',
'Turnos anulados antes de atenderlos.')}
${kpiCard(tEspera !== null ? tEspera + ' min' : '—', '⏱ Espera para recepción', 'sacar el turno → lo llaman',
'Cuánto aguarda el paciente sentado desde que saca el turno hasta que recepción lo atiende.')}
${kpiCard(tServicio !== null ? tServicio + ' min' : '—', '⏱ Tiempo en el puesto', 'toma de muestras',
'Lo que dura la toma. En protocolos prolongados (curvas) se cuenta hasta la primera toma: las horas de espera del examen no son trabajo del puesto.')}
${kpiCard(tTotal !== null ? tTotal + ' min' : '—', '⏱ Total en el laboratorio', 'llegada → salida',
'Todo el recorrido: espera + recepción + espera del puesto + toma. Por eso es mayor que la suma de las dos casillas anteriores.')}
`;
// ── Consentimientos ────────────────────────────────────
@@ -584,11 +594,16 @@ function renderPersonas(sectionId, gridId, filas, columnas) {
</div>`).join('');
}
function kpiCard(val, lbl, sub) {
return `<div class="kpi-card">
function kpiCard(val, lbl, sub, ayuda) {
// `ayuda` explica de dónde sale el número. Las etiquetas cortas se prestan
// para malentendidos —«servicio» no es lo mismo que «tiempo en el
// laboratorio»— y quien lee el tablero no tiene por qué adivinarlo.
const t = ayuda ? ` title="${escHtml(ayuda)}"` : '';
return `<div class="kpi-card"${t}>
<div class="kpi-val">${val !== null && val !== undefined ? escHtml(String(val)) : '—'}</div>
<div class="kpi-lbl">${lbl}</div>
${sub ? `<div class="kpi-sub">${escHtml(sub)}</div>` : ''}
${ayuda ? `<div class="kpi-ayuda">${escHtml(ayuda)}</div>` : ''}
</div>`;
}