feat: botón Ver paciente con historial en vista lugar
Agrega botón "Ver" en la sección Paciente de la ficha del turno. Abre modal con datos completos del paciente (nombre, doc, fecha nac, celular, médico, embarazo) y timeline de historial de visitas anterior (misma lógica que recepción), cargado desde get_historial.php. El botón solo aparece cuando hay un paciente vinculado al turno. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
282c372de3
commit
a526a29a68
@@ -319,6 +319,51 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
|
||||
}
|
||||
.selector-lugar-box h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 1.5rem; }
|
||||
|
||||
/* ── Modal paciente ── */
|
||||
#modal-pac-lugar { display:none; position:fixed; inset:0; z-index:9500;
|
||||
background:rgba(0,0,0,.55); align-items:center; justify-content:center; padding:16px; }
|
||||
#modal-pac-lugar.show { display:flex; }
|
||||
.mpac-dialog {
|
||||
background:#fff; border-radius:16px; width:min(96vw,540px);
|
||||
max-height:90vh; display:flex; flex-direction:column; overflow:hidden;
|
||||
box-shadow:0 8px 40px rgba(0,0,0,.22);
|
||||
}
|
||||
.mpac-hdr {
|
||||
display:flex; align-items:center; justify-content:space-between;
|
||||
padding:13px 18px; border-bottom:1px solid #e2e8f0; flex-shrink:0; background:#f8fafc;
|
||||
}
|
||||
.mpac-hdr-title { font-weight:700; font-size:.97rem; color:#1e293b; display:flex; align-items:center; gap:.5rem; }
|
||||
.mpac-close { background:none; border:none; font-size:1.2rem; color:#94a3b8; cursor:pointer; padding:2px 6px; border-radius:6px; }
|
||||
.mpac-close:hover { background:#f1f5f9; color:#475569; }
|
||||
.mpac-body { overflow-y:auto; padding:18px; flex:1; }
|
||||
.mpac-dato { display:flex; gap:.5rem; align-items:baseline; margin-bottom:.4rem; }
|
||||
.mpac-dato .lbl { font-size:.72rem; color:#94a3b8; min-width:95px; flex-shrink:0; }
|
||||
.mpac-dato .val { font-size:.88rem; color:#1e293b; font-weight:500; }
|
||||
.mpac-sec-title {
|
||||
font-size:.7rem; text-transform:uppercase; letter-spacing:.07em;
|
||||
color:#475569; font-weight:700; margin:14px 0 8px;
|
||||
display:flex; align-items:center; gap:.4rem;
|
||||
}
|
||||
/* Historial timeline */
|
||||
.mpac-timeline { padding: 0; }
|
||||
.mtl-item {
|
||||
display:flex; gap:10px; align-items:flex-start;
|
||||
padding-bottom:12px; position:relative;
|
||||
}
|
||||
.mtl-item:not(:last-child)::before {
|
||||
content:''; position:absolute; left:6px; top:14px;
|
||||
width:2px; bottom:0; background:#e2e8f0;
|
||||
}
|
||||
.mtl-dot {
|
||||
width:14px; height:14px; border-radius:50%; flex-shrink:0;
|
||||
margin-top:2px; border:2px solid #fff; box-shadow:0 0 0 2px currentColor;
|
||||
}
|
||||
.mtl-content { flex:1; min-width:0; }
|
||||
.mtl-fecha { font-size:.68rem; color:#94a3b8; }
|
||||
.mtl-codigo { font-size:.82rem; font-weight:700; }
|
||||
.mtl-lugar { font-size:.73rem; color:#64748b; }
|
||||
.mtl-eb { font-size:.62rem; padding:1px 7px; border-radius:99px; font-weight:700; display:inline-block; margin-top:2px; }
|
||||
|
||||
/* ── Toast ── */
|
||||
.rec-toast {
|
||||
position: fixed; bottom: 2rem; right: 2rem; z-index: 9999;
|
||||
@@ -448,7 +493,13 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
||||
|
||||
<!-- ── Paciente ── -->
|
||||
<div class="ficha-sec">
|
||||
<div class="ficha-sec-hdr"><i class="fas fa-user"></i>Paciente</div>
|
||||
<div class="ficha-sec-hdr">
|
||||
<i class="fas fa-user"></i>Paciente
|
||||
<button id="btn-ver-paciente" class="btn btn-sm btn-outline-primary ms-auto d-none"
|
||||
onclick="abrirModalPaciente()" style="font-size:.72rem;padding:2px 10px;border-radius:20px">
|
||||
<i class="fas fa-eye me-1"></i>Ver
|
||||
</button>
|
||||
</div>
|
||||
<div id="bloque-pac-info">
|
||||
<div class="pac-dato"><span class="lbl">Nombre</span><span class="val" id="pac-nombre">—</span></div>
|
||||
<div class="pac-dato"><span class="lbl">Documento</span><span class="val" id="pac-doc">—</span></div>
|
||||
@@ -561,6 +612,39 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
||||
</div><!-- /lugar-layout -->
|
||||
</main>
|
||||
|
||||
<!-- ── Modal datos + historial del paciente ─────────────────────── -->
|
||||
<div id="modal-pac-lugar" onclick="if(event.target===this)cerrarModalPaciente()">
|
||||
<div class="mpac-dialog">
|
||||
<div class="mpac-hdr">
|
||||
<span class="mpac-hdr-title"><i class="fas fa-user-circle text-primary"></i><span id="mpac-nombre-titulo">Paciente</span></span>
|
||||
<button class="mpac-close" onclick="cerrarModalPaciente()"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<div class="mpac-body">
|
||||
<!-- Datos básicos -->
|
||||
<div class="mpac-sec-title"><i class="fas fa-id-card"></i>Información del paciente</div>
|
||||
<div id="mpac-datos">
|
||||
<div class="mpac-dato"><span class="lbl">Nombre</span><span class="val" id="mpac-val-nombre">—</span></div>
|
||||
<div class="mpac-dato"><span class="lbl">Documento</span><span class="val" id="mpac-val-doc">—</span></div>
|
||||
<div class="mpac-dato"><span class="lbl">Fecha nac.</span><span class="val" id="mpac-val-fec">—</span></div>
|
||||
<div class="mpac-dato"><span class="lbl">Celular</span><span class="val" id="mpac-val-cel">—</span></div>
|
||||
<div class="mpac-dato" id="mpac-row-medico" style="display:none">
|
||||
<span class="lbl">Médico</span><span class="val" id="mpac-val-medico" style="color:#4f46e5">—</span>
|
||||
</div>
|
||||
<div id="mpac-badge-emb" class="d-none mt-1">
|
||||
<span class="badge text-bg-danger"><i class="fas fa-baby me-1"></i>Paciente embarazada</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Historial -->
|
||||
<div class="mpac-sec-title"><i class="fas fa-history" style="color:#6366f1"></i>Historial de visitas</div>
|
||||
<div id="mpac-historial-content">
|
||||
<div class="text-center text-muted py-3 small">
|
||||
<i class="fas fa-spinner fa-spin me-1"></i>Cargando historial…
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Modal de consentimiento embebido (modo embebido) ────────── -->
|
||||
<div id="modal-consentimiento" style="
|
||||
display:none;position:fixed;inset:0;z-index:9000;
|
||||
@@ -599,6 +683,8 @@ let hayPendientes = false;
|
||||
let pollingColaId = null;
|
||||
let pollingConsentId = null;
|
||||
let _consentTokenCache = null;
|
||||
let _pacienteActivo = null;
|
||||
let _solicitudActiva = null;
|
||||
|
||||
const API = '<?= BASE_URL ?>modules/turnero/api/';
|
||||
const BASE_WA = '<?= BASE_URL ?>';
|
||||
@@ -827,6 +913,7 @@ async function cargarFichaSolicitud(turnoId) {
|
||||
|
||||
const sol = json.solicitud;
|
||||
const pac = json.paciente;
|
||||
_solicitudActiva = sol || null;
|
||||
const exams = json.examenes || [];
|
||||
const consts = json.consentimientos || [];
|
||||
|
||||
@@ -851,6 +938,7 @@ async function cargarFichaSolicitud(turnoId) {
|
||||
}
|
||||
|
||||
if (pac) {
|
||||
_pacienteActivo = pac;
|
||||
document.getElementById('bloque-pac-info').style.display = '';
|
||||
document.getElementById('bloque-pac-sin').classList.add('d-none');
|
||||
document.getElementById('pac-nombre').textContent =
|
||||
@@ -859,9 +947,12 @@ async function cargarFichaSolicitud(turnoId) {
|
||||
((pac.tipo_documento || '') + ' ' + (pac.numero_documento || pac.documento || '')).trim() || '—';
|
||||
document.getElementById('pac-fec').textContent = pac.fecha_nacimiento || '—';
|
||||
document.getElementById('pac-cel').textContent = pac.telefono || pac.celular || '—';
|
||||
document.getElementById('btn-ver-paciente').classList.remove('d-none');
|
||||
} else {
|
||||
_pacienteActivo = null;
|
||||
document.getElementById('bloque-pac-info').style.display = 'none';
|
||||
document.getElementById('bloque-pac-sin').classList.remove('d-none');
|
||||
document.getElementById('btn-ver-paciente').classList.add('d-none');
|
||||
}
|
||||
|
||||
// Exámenes
|
||||
@@ -1127,6 +1218,10 @@ function resetFicha() {
|
||||
tieneConsent = false;
|
||||
hayPendientes = false;
|
||||
_consentTokenCache = null;
|
||||
_pacienteActivo = null;
|
||||
_solicitudActiva = null;
|
||||
cerrarModalPaciente();
|
||||
document.getElementById('btn-ver-paciente').classList.add('d-none');
|
||||
|
||||
cerrarModalConsentimiento();
|
||||
|
||||
@@ -1265,6 +1360,118 @@ async function guardarComentario() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Modal paciente ────────────────────────────────────────────
|
||||
function abrirModalPaciente() {
|
||||
if (!_pacienteActivo) return;
|
||||
const pac = _pacienteActivo;
|
||||
const sol = _solicitudActiva;
|
||||
|
||||
document.getElementById('mpac-nombre-titulo').textContent =
|
||||
pac.nombre_completo || pac.full_name || 'Paciente';
|
||||
document.getElementById('mpac-val-nombre').textContent =
|
||||
pac.nombre_completo || pac.full_name || '—';
|
||||
document.getElementById('mpac-val-doc').textContent =
|
||||
((pac.tipo_documento || '') + ' ' + (pac.numero_documento || pac.documento || '')).trim() || '—';
|
||||
document.getElementById('mpac-val-fec').textContent = pac.fecha_nacimiento || '—';
|
||||
document.getElementById('mpac-val-cel').textContent = pac.telefono || pac.celular || '—';
|
||||
|
||||
const rowMed = document.getElementById('mpac-row-medico');
|
||||
if (sol && sol.medico_nombre) {
|
||||
rowMed.style.display = '';
|
||||
const esp = sol.medico_especialidad ? ' · ' + sol.medico_especialidad : '';
|
||||
document.getElementById('mpac-val-medico').textContent = sol.medico_nombre + esp;
|
||||
} else {
|
||||
rowMed.style.display = 'none';
|
||||
}
|
||||
|
||||
const badgeEmb = document.getElementById('mpac-badge-emb');
|
||||
badgeEmb.classList.toggle('d-none', !(sol && sol.embarazada == 1));
|
||||
|
||||
document.getElementById('mpac-historial-content').innerHTML =
|
||||
'<div class="text-center text-muted py-3 small"><i class="fas fa-spinner fa-spin me-1"></i>Cargando historial…</div>';
|
||||
document.getElementById('modal-pac-lugar').classList.add('show');
|
||||
|
||||
cargarHistorialModal(pac.id);
|
||||
}
|
||||
|
||||
function cerrarModalPaciente() {
|
||||
document.getElementById('modal-pac-lugar').classList.remove('show');
|
||||
}
|
||||
|
||||
async function cargarHistorialModal(pacienteId) {
|
||||
const cont = document.getElementById('mpac-historial-content');
|
||||
try {
|
||||
const res = await fetch(`${API}get_historial.php?paciente_id=${pacienteId}&per_page=10&page=1`);
|
||||
const json = await res.json();
|
||||
if (!json.ok || !json.turnos || !json.turnos.length) {
|
||||
cont.innerHTML = '<div class="text-center text-muted py-3 small"><i class="fas fa-inbox me-1"></i>Sin visitas anteriores registradas</div>';
|
||||
return;
|
||||
}
|
||||
cont.innerHTML = renderHistorialTimeline(json.turnos, json.total);
|
||||
} catch(_) {
|
||||
cont.innerHTML = '<div class="text-center text-danger py-2 small">Error al cargar historial</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderHistorialTimeline(turnos, total) {
|
||||
const ESTADO_LBL = {
|
||||
espera:'Espera', en_recepcion:'Recepción', en_espera_lugar:'Esp. lugar',
|
||||
en_servicio:'En servicio', finalizado:'Finalizado', ausente:'Ausente', cancelado:'Cancelado',
|
||||
};
|
||||
const ESTADO_STYLE = {
|
||||
finalizado: 'background:#f1f5f9;color:#334155',
|
||||
ausente: 'background:#fee2e2;color:#991b1b',
|
||||
cancelado: 'background:#f1f5f9;color:#9ca3af',
|
||||
en_servicio: 'background:#dcfce7;color:#166534',
|
||||
en_espera_lugar:'background:#fde68a;color:#92400e',
|
||||
en_recepcion: 'background:#dbeafe;color:#1e40af',
|
||||
espera: 'background:#fef9c3;color:#78350f',
|
||||
};
|
||||
const totalLabel = total > turnos.length
|
||||
? `<div style="font-size:.67rem;color:#94a3b8;text-align:right;padding:4px 0">Mostrando ${turnos.length} de ${total} visitas</div>` : '';
|
||||
|
||||
const items = turnos.map(t => {
|
||||
const color = t.prioridad_color || '#6366f1';
|
||||
const lugar = escHtml(t.lugar_nombre || 'Recepción');
|
||||
const fecha = escHtml(t.fecha_sesion || '—');
|
||||
const est = t.estado || '';
|
||||
const eStyle = ESTADO_STYLE[est] || 'background:#f1f5f9;color:#334155';
|
||||
const eLbl = escHtml(ESTADO_LBL[est] || est);
|
||||
const mins = t.servicio_min != null
|
||||
? `<span style="font-size:.65rem;color:#94a3b8;margin-left:4px">${t.servicio_min} min</span>` : '';
|
||||
|
||||
let examStr = '';
|
||||
if (t.examenes && t.examenes.length) {
|
||||
examStr = `<div style="margin-top:5px;font-size:.74rem">
|
||||
<strong style="color:#64748b">Exámenes:</strong>
|
||||
<span style="color:#475569">${t.examenes.map(e => escHtml(e.nombre)).join(', ')}</span>
|
||||
</div>`;
|
||||
}
|
||||
let comStr = '';
|
||||
if (t.comentarios && t.comentarios.length) {
|
||||
comStr = `<div style="margin-top:5px;font-size:.71rem;border-top:1px solid #e2e8f0;padding-top:5px">
|
||||
<strong style="color:#64748b">📝 Comentarios:</strong>
|
||||
<div style="color:#475569;margin-top:3px">${t.comentarios.map(c =>
|
||||
`<div style="margin-bottom:2px"><strong>${escHtml(c.usuario_nombre)}</strong>: ${escHtml(c.comentario)}</div>`
|
||||
).join('')}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
return `<div class="mtl-item">
|
||||
<div class="mtl-dot" style="color:${color};background:${color}"></div>
|
||||
<div class="mtl-content">
|
||||
<div class="mtl-fecha">${fecha}</div>
|
||||
<div class="mtl-codigo" style="color:${color}">${escHtml(t.codigo)}</div>
|
||||
<div class="mtl-lugar">${lugar}</div>
|
||||
<span class="mtl-eb" style="${eStyle}">${eLbl}</span>${mins}
|
||||
${examStr}${comStr}
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
return `<div class="mpac-timeline">${items}</div>${totalLabel}`;
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────
|
||||
function escHtml(str) {
|
||||
const d = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user