Turnero: mejoras UI, historial detallado, kiosko scanner, firma por turno
- Kiosko: detector scanner (gap < 80ms), iconos 90px, fa-person-pregnant, ticket Arial - Recepción: vincular_paciente.php para persistir paciente_id antes de firmar consentimiento - Historial y dashboard: recepción desk, empleado recepción/muestras, exámenes y comentarios - display_global: turno más pequeño, lugar-nombre más grande - lab_pacientes: modal compacta con form-sm - Configuración: icono embarazada fa-person-pregnant en prioridades - ver_formulario_enviado: firma por campo (fix doble firma) - docker-compose.local.yml: override BD producción para dev local Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ebbf4ac6cf
commit
f363631b32
@@ -137,6 +137,7 @@ Layout::open('Dashboard Turnero', 'fas fa-chart-bar');
|
||||
<th>Espera</th>
|
||||
<th>Servicio</th>
|
||||
<th>Entrada</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbodyTurnos">
|
||||
@@ -324,7 +325,8 @@ function renderTabla(turnos) {
|
||||
const hora = t.creado_at ? new Date(t.creado_at.replace(' ', 'T')).toLocaleTimeString('es-CO', {hour:'2-digit',minute:'2-digit'}) : '—';
|
||||
const espMin = t.espera_min !== null ? t.espera_min + ' m' : '—';
|
||||
const srvMin = t.servicio_min !== null ? t.servicio_min + ' m' : '—';
|
||||
return `<tr>
|
||||
const rowId = `dash-det-${t.id}`;
|
||||
return `<tr style="cursor:pointer" onclick="toggleDashDetalle('${rowId}', this)">
|
||||
<td><span class="fw-bold" style="color:${escHtml(t.prioridad_color || '#333')}">${escHtml(t.codigo)}</span></td>
|
||||
<td><span class="estado-badge" style="background:${escHtml(t.prioridad_color+'22'||'#eee')};color:${escHtml(t.prioridad_color||'#333')}">${escHtml(t.prioridad_codigo)}</span></td>
|
||||
<td>${nombrePac}</td>
|
||||
@@ -333,10 +335,77 @@ function renderTabla(turnos) {
|
||||
<td>${espMin}</td>
|
||||
<td>${srvMin}</td>
|
||||
<td>${hora}</td>
|
||||
<td><i class="fas fa-chevron-down text-muted" style="font-size:.65rem"></i></td>
|
||||
</tr>
|
||||
<tr id="${rowId}" style="display:none;background:#f8fafc">
|
||||
<td colspan="9" style="padding:0">
|
||||
<div style="padding:12px 16px;border-top:1px solid #e2e8f0">
|
||||
${renderDashDetalle(t)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function toggleDashDetalle(rowId, tr) {
|
||||
const det = document.getElementById(rowId);
|
||||
const icon = tr.querySelector('.fa-chevron-down, .fa-chevron-up');
|
||||
if (!det) return;
|
||||
const open = det.style.display !== 'none';
|
||||
det.style.display = open ? 'none' : '';
|
||||
if (icon) icon.className = open ? 'fas fa-chevron-down text-muted' : 'fas fa-chevron-up text-muted';
|
||||
if (icon) icon.style.fontSize = '.65rem';
|
||||
}
|
||||
|
||||
function renderDashDetalle(t) {
|
||||
const e = s => escHtml(s || '—');
|
||||
const fmt = dt => dt ? new Date(dt.replace(' ','T')).toLocaleString('es-CO',{dateStyle:'short',timeStyle:'short'}) : '—';
|
||||
|
||||
const chips = [
|
||||
{ lbl:'Recepción (desk)', val: e(t.recepcion_desk_nombre) },
|
||||
{ lbl:'Atendió recepción', val: e(t.atendido_recepcion_nombre) },
|
||||
{ lbl:'Atendió muestras', val: e(t.atendido_lugar_nombre) },
|
||||
{ lbl:'Inicio recepción', val: fmt(t.inicio_recepcion_at) },
|
||||
{ lbl:'Fin recepción', val: fmt(t.fin_recepcion_at) },
|
||||
{ lbl:'Inicio servicio', val: fmt(t.inicio_lugar_at) },
|
||||
{ lbl:'Fin servicio', val: fmt(t.fin_lugar_at) },
|
||||
];
|
||||
|
||||
let grid = `<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;margin-bottom:10px">
|
||||
${chips.map(c=>`<div style="background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:7px 11px">
|
||||
<div style="font-size:.63rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8">${c.lbl}</div>
|
||||
<div style="font-size:.82rem;font-weight:600;color:#1e293b">${c.val}</div>
|
||||
</div>`).join('')}
|
||||
</div>`;
|
||||
|
||||
// Notas
|
||||
if (t.notas) {
|
||||
grid += `<div style="margin-bottom:8px;font-size:.82rem"><span style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8">📝 Notas: </span>${e(t.notas)}</div>`;
|
||||
}
|
||||
|
||||
// Exámenes
|
||||
if (t.examenes && t.examenes.length) {
|
||||
grid += `<div style="margin-bottom:8px">
|
||||
<span style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8"><i class="fas fa-vials me-1"></i>Exámenes (${t.examenes.length}): </span>
|
||||
${t.examenes.map(ex=>`<span class="badge" style="background:#dcfce7;color:#166534;margin:1px 2px">${e(ex.nombre)}</span>`).join('')}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// Comentarios
|
||||
if (t.comentarios && t.comentarios.length) {
|
||||
grid += `<div style="border-top:1px solid #e2e8f0;padding-top:8px">
|
||||
<div style="font-size:.67rem;text-transform:uppercase;letter-spacing:.07em;color:#94a3b8;margin-bottom:5px"><i class="fas fa-comments me-1"></i>Comentarios</div>
|
||||
${t.comentarios.map(c=>`<div style="font-size:.8rem;padding:4px 0;border-bottom:1px solid #f1f5f9">
|
||||
<strong>${e(c.usuario_nombre)}</strong>
|
||||
<span style="color:#94a3b8;font-size:.72rem;margin-left:6px">${fmt(c.creado_at)}</span>
|
||||
<div style="color:#475569">${e(c.comentario)}</div>
|
||||
</div>`).join('')}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
function filtrarTabla() {
|
||||
const q = document.getElementById('filtroBusqueda').value.toLowerCase().trim();
|
||||
if (!q) { renderTabla(_turnos); return; }
|
||||
|
||||
Reference in New Issue
Block a user