UP
This commit is contained in:
@@ -115,7 +115,7 @@ foreach ($lugares as $lugar) {
|
|||||||
FROM turnero_turnos t
|
FROM turnero_turnos t
|
||||||
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
||||||
WHERE t.sesion_id = ?
|
WHERE t.sesion_id = ?
|
||||||
AND t.estado IN ('en_espera_lugar', 'en_servicio')
|
AND t.estado = 'en_servicio'
|
||||||
AND t.lugar_destino_id = ?
|
AND t.lugar_destino_id = ?
|
||||||
ORDER BY t.llamado_lugar_at DESC
|
ORDER BY t.llamado_lugar_at DESC
|
||||||
LIMIT 1"
|
LIMIT 1"
|
||||||
|
|||||||
@@ -566,7 +566,7 @@ function showAnnouncement({ codigo, destino, paciente, color }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── State ── */
|
/* ── State ── */
|
||||||
let lastTurnoKey = null;
|
let lastSeenKeys = new Set(); // clave por turno+destino+llamado_at
|
||||||
let llamados = [];
|
let llamados = [];
|
||||||
|
|
||||||
function renderSnapshot(snap) {
|
function renderSnapshot(snap) {
|
||||||
@@ -576,48 +576,53 @@ function renderSnapshot(snap) {
|
|||||||
const lblEl = document.getElementById('lugar-label');
|
const lblEl = document.getElementById('lugar-label');
|
||||||
const ringEl = document.getElementById('pulse-ring');
|
const ringEl = document.getElementById('pulse-ring');
|
||||||
|
|
||||||
const turnos = [];
|
// Recopilar TODOS los turnos activos: recepción + lugares
|
||||||
|
const allTurnos = [];
|
||||||
(snap.activos_recepcion || []).forEach(d => {
|
(snap.activos_recepcion || []).forEach(d => {
|
||||||
if (d.turno) turnos.push({ ...d.turno, destino: d.desk_nombre, tipo: 'rec' });
|
if (d.turno) allTurnos.push({ ...d.turno, destino: d.desk_nombre });
|
||||||
});
|
});
|
||||||
(snap.lugares || []).forEach(l => {
|
(snap.lugares || []).forEach(l => {
|
||||||
if (l.turno) turnos.push({ ...l.turno, destino: l.lugar_nombre, tipo: 'mue' });
|
if (l.turno) allTurnos.push({ ...l.turno, destino: l.lugar_nombre });
|
||||||
});
|
});
|
||||||
|
|
||||||
if (turnos.length > 0) {
|
// Detectar turno nuevo en CUALQUIER estación y anunciar
|
||||||
const t = turnos[0];
|
const currentKeys = new Set();
|
||||||
|
let anuncioNuevo = false;
|
||||||
|
allTurnos.forEach(t => {
|
||||||
|
const key = t.codigo + '|' + t.destino + '|' + (t.llamado_at || '');
|
||||||
|
currentKeys.add(key);
|
||||||
|
if (!lastSeenKeys.has(key)) {
|
||||||
|
const c = t.prioridad_color || '<?= $_labColor ?>';
|
||||||
|
queueAnnouncement({ _key: key, codigo: t.codigo, destino: t.destino, paciente: t.paciente_nombre, color: c });
|
||||||
|
llamados.unshift({ codigo: t.codigo, destino: t.destino, paciente: t.paciente_nombre, color: c });
|
||||||
|
if (llamados.length > 30) llamados.pop();
|
||||||
|
anuncioNuevo = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lastSeenKeys = currentKeys;
|
||||||
|
if (anuncioNuevo) renderLlamados();
|
||||||
|
|
||||||
|
// zona-activo: mostrar el turno llamado más recientemente
|
||||||
|
const sorted = allTurnos.slice().sort((a, b) => {
|
||||||
|
return new Date(b.llamado_at || 0) - new Date(a.llamado_at || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sorted.length > 0) {
|
||||||
|
const t = sorted[0];
|
||||||
codEl.textContent = t.codigo;
|
codEl.textContent = t.codigo;
|
||||||
lugEl.textContent = t.destino;
|
lugEl.textContent = t.destino;
|
||||||
pacEl.textContent = t.paciente_nombre || '';
|
pacEl.textContent = t.paciente_nombre || '';
|
||||||
lblEl.textContent = 'Llamado a';
|
lblEl.textContent = 'Llamado a';
|
||||||
ringEl.classList.add('active');
|
ringEl.classList.add('active');
|
||||||
|
|
||||||
const c = t.prioridad_color || '<?= $_labColor ?>';
|
const c = t.prioridad_color || '<?= $_labColor ?>';
|
||||||
codEl.style.color = c;
|
codEl.style.color = c;
|
||||||
document.getElementById('zona-activo').style.setProperty('--brand', c);
|
document.getElementById('zona-activo').style.setProperty('--brand', c);
|
||||||
|
|
||||||
const key = t.codigo + '|' + t.destino + '|' + (t.llamado_at || '');
|
|
||||||
if (key !== lastTurnoKey) {
|
|
||||||
queueAnnouncement({
|
|
||||||
_key: key,
|
|
||||||
codigo: t.codigo,
|
|
||||||
destino: t.destino,
|
|
||||||
paciente: t.paciente_nombre,
|
|
||||||
color: c
|
|
||||||
});
|
|
||||||
lastTurnoKey = key;
|
|
||||||
llamados.unshift({ codigo: t.codigo, destino: t.destino, paciente: t.paciente_nombre, color: c });
|
|
||||||
if (llamados.length > 30) llamados.pop();
|
|
||||||
renderLlamados();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
codEl.textContent = '—';
|
codEl.textContent = '—';
|
||||||
lugEl.textContent = '—';
|
lugEl.textContent = '—';
|
||||||
pacEl.textContent = '';
|
pacEl.textContent = '';
|
||||||
lblEl.textContent = 'Llamado a';
|
lblEl.textContent = 'Llamado a';
|
||||||
codEl.style.color = '<?= $_labColor ?>';
|
codEl.style.color = '<?= $_labColor ?>';
|
||||||
lastTurnoKey = null;
|
|
||||||
ringEl.classList.remove('active');
|
ringEl.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+111
-76
@@ -176,6 +176,29 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
|
|||||||
}
|
}
|
||||||
.selector-lugar-box h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 1.5rem; }
|
.selector-lugar-box h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 1.5rem; }
|
||||||
|
|
||||||
|
/* ── Toast ── */
|
||||||
|
.rec-toast {
|
||||||
|
position: fixed; bottom: 2rem; right: 2rem; z-index: 9999;
|
||||||
|
display: flex; align-items: center; gap: .7rem;
|
||||||
|
padding: .8rem 1.2rem; border-radius: 12px;
|
||||||
|
background: #fff; border: 1px solid #e2e8f0;
|
||||||
|
box-shadow: 0 8px 30px rgba(0,0,0,.12);
|
||||||
|
font-size: .9rem; font-weight: 500;
|
||||||
|
transform: translateY(120%); opacity: 0;
|
||||||
|
transition: transform .3s ease, opacity .3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.rec-toast.show { transform: translateY(0); opacity: 1; }
|
||||||
|
.rec-toast.success { border-left: 4px solid #22c55e; }
|
||||||
|
.rec-toast.info { border-left: 4px solid #3b82f6; }
|
||||||
|
.rec-toast.warn { border-left: 4px solid #f59e0b; }
|
||||||
|
.rec-toast.error { border-left: 4px solid #ef4444; }
|
||||||
|
.rec-toast .ico { font-size: 1.2rem; }
|
||||||
|
.rec-toast.success .ico { color: #22c55e; }
|
||||||
|
.rec-toast.info .ico { color: #3b82f6; }
|
||||||
|
.rec-toast.warn .ico { color: #f59e0b; }
|
||||||
|
.rec-toast.error .ico { color: #ef4444; }
|
||||||
|
|
||||||
/* ── Indicador de bloqueo ── */
|
/* ── Indicador de bloqueo ── */
|
||||||
.bloqueo-banner {
|
.bloqueo-banner {
|
||||||
background: #fef2f2; border: 1px solid #fca5a5; border-radius: 10px;
|
background: #fef2f2; border: 1px solid #fca5a5; border-radius: 10px;
|
||||||
@@ -313,8 +336,8 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
|||||||
|
|
||||||
<!-- ── Barra de acciones ── -->
|
<!-- ── Barra de acciones ── -->
|
||||||
<div class="ficha-acciones">
|
<div class="ficha-acciones">
|
||||||
<button class="btn btn-success" id="btn-iniciar" onclick="iniciarAtencion()">
|
<button class="btn btn-primary" id="btn-iniciar" onclick="iniciarAtencion()">
|
||||||
<i class="fas fa-play me-1"></i>Iniciar atención
|
<i class="fas fa-bell me-1"></i>Llamar
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary d-none" id="btn-finalizar" onclick="finalizarAtencion()">
|
<button class="btn btn-primary d-none" id="btn-finalizar" onclick="finalizarAtencion()">
|
||||||
<i class="fas fa-flag-checkered me-1"></i>Finalizar
|
<i class="fas fa-flag-checkered me-1"></i>Finalizar
|
||||||
@@ -442,7 +465,7 @@ async function recuperarTurnoActivo() {
|
|||||||
function confirmarLugar() {
|
function confirmarLugar() {
|
||||||
const sel = document.getElementById('sel-lugar-init');
|
const sel = document.getElementById('sel-lugar-init');
|
||||||
const id = parseInt(sel.value);
|
const id = parseInt(sel.value);
|
||||||
if (!id) return alert('Seleccione un lugar.');
|
if (!id) return mostrarError('Seleccione un lugar.');
|
||||||
lugarId = id;
|
lugarId = id;
|
||||||
const txt = sel.options[sel.selectedIndex].text;
|
const txt = sel.options[sel.selectedIndex].text;
|
||||||
document.getElementById('lbl-lugar-titulo').textContent = txt;
|
document.getElementById('lbl-lugar-titulo').textContent = txt;
|
||||||
@@ -470,11 +493,16 @@ async function cargarCola() {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _colaMap = new Map(); // id → turno object
|
||||||
|
|
||||||
function renderCola(snap) {
|
function renderCola(snap) {
|
||||||
const items = snap.cola || [];
|
const items = snap.cola || [];
|
||||||
const espera = items.filter(t => t.estado === 'en_espera_lugar');
|
const espera = items.filter(t => t.estado === 'en_espera_lugar');
|
||||||
document.getElementById('badge-count').textContent = espera.length;
|
document.getElementById('badge-count').textContent = espera.length;
|
||||||
|
|
||||||
|
// Guardar mapa para selección sin llamar
|
||||||
|
_colaMap = new Map(items.map(t => [t.id, t]));
|
||||||
|
|
||||||
const lista = document.getElementById('cola-items');
|
const lista = document.getElementById('cola-items');
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
lista.innerHTML = `<div class="cola-vacia">
|
lista.innerHTML = `<div class="cola-vacia">
|
||||||
@@ -484,39 +512,50 @@ function renderCola(snap) {
|
|||||||
lista.innerHTML = items.map(t => {
|
lista.innerHTML = items.map(t => {
|
||||||
const enServicio = t.estado === 'en_servicio';
|
const enServicio = t.estado === 'en_servicio';
|
||||||
const esActivo = turnoActivo?.id == t.id;
|
const esActivo = turnoActivo?.id == t.id;
|
||||||
if (enServicio) {
|
const onclick = enServicio
|
||||||
return `
|
? `seleccionarSinLlamar(${t.id})`
|
||||||
<div class="cola-card en-servicio-card ${esActivo ? 'activo' : ''}"
|
: `seleccionarSinLlamar(${t.id})`;
|
||||||
style="cursor:pointer" onclick="rellamarDesdeCard(${t.id})"
|
const indicador = enServicio
|
||||||
title="Re-llamar turno ${escHtml(t.codigo)}">
|
? `<div class="ms-auto d-flex flex-column align-items-center" style="gap:1px">
|
||||||
<div class="prio-dot" style="background:${t.prioridad_color}">${t.prioridad_codigo}</div>
|
<i class="fas fa-stethoscope text-success" style="font-size:.85rem"></i>
|
||||||
<div class="turno-info">
|
<span style="font-size:.58rem;color:#16a34a;font-weight:700">EN SERVICIO</span>
|
||||||
<div class="cod">${escHtml(t.codigo)}</div>
|
</div>`
|
||||||
<div class="pac">${escHtml(t.paciente_nombre || 'Paciente')}</div>
|
: `<i class="fas fa-chevron-right text-muted ms-auto" style="font-size:.7rem"></i>`;
|
||||||
</div>
|
|
||||||
<div class="ms-auto d-flex flex-column align-items-center" style="gap:1px">
|
|
||||||
<i class="fas fa-bell text-success" style="font-size:.85rem"></i>
|
|
||||||
<span style="font-size:.58rem;color:#16a34a;font-weight:700">RE-LLAMAR</span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
return `
|
return `
|
||||||
<div class="cola-card ${esActivo ? 'activo' : ''}"
|
<div class="cola-card ${enServicio ? 'en-servicio-card' : ''} ${esActivo ? 'activo' : ''}"
|
||||||
style="cursor:pointer" onclick="llamarTurnoEspecifico(${t.id})"
|
style="cursor:pointer" onclick="${onclick}"
|
||||||
title="Llamar turno ${escHtml(t.codigo)}">
|
title="${enServicio ? 'Ver turno en servicio' : `Ver turno ${escHtml(t.codigo)}`}">
|
||||||
<div class="prio-dot" style="background:${t.prioridad_color}">${t.prioridad_codigo}</div>
|
<div class="prio-dot" style="background:${t.prioridad_color}">${t.prioridad_codigo}</div>
|
||||||
<div class="turno-info">
|
<div class="turno-info">
|
||||||
<div class="cod">${escHtml(t.codigo)}</div>
|
<div class="cod">${escHtml(t.codigo)}</div>
|
||||||
<div class="pac">${escHtml(t.paciente_nombre || 'Paciente')}</div>
|
<div class="pac">${escHtml(t.paciente_nombre || 'Paciente')}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto d-flex flex-column align-items-center" style="gap:1px">
|
${indicador}
|
||||||
<i class="fas fa-bell text-primary" style="font-size:.85rem"></i>
|
|
||||||
<span style="font-size:.58rem;color:#1d4ed8;font-weight:700">LLAMAR</span>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abre la ficha SIN llamar ni cambiar estado
|
||||||
|
async function seleccionarSinLlamar(turnoId) {
|
||||||
|
const t = _colaMap.get(turnoId);
|
||||||
|
if (!t) return;
|
||||||
|
turnoActivo = t;
|
||||||
|
document.getElementById('ficha-placeholder').classList.add('d-none');
|
||||||
|
document.getElementById('ficha-turno').classList.remove('d-none');
|
||||||
|
document.getElementById('ficha-codigo').textContent = t.codigo;
|
||||||
|
document.getElementById('ficha-prio-nombre').textContent = t.prioridad_nombre || '';
|
||||||
|
const dot = document.getElementById('ficha-prio-dot');
|
||||||
|
dot.textContent = t.prioridad_codigo || '—';
|
||||||
|
dot.style.background = t.prioridad_color || '#6366f1';
|
||||||
|
const badgeCod = document.getElementById('badge-turno-activo');
|
||||||
|
badgeCod.textContent = t.codigo;
|
||||||
|
badgeCod.classList.remove('d-none');
|
||||||
|
actualizarEstadoBadge(t.estado);
|
||||||
|
await cargarFichaSolicitud(t.id);
|
||||||
|
clearInterval(pollingConsentId);
|
||||||
|
pollingConsentId = setInterval(() => actualizarConsentimientos(turnoActivo?.id), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
async function rellamarDesdeCard(turnoId) {
|
async function rellamarDesdeCard(turnoId) {
|
||||||
const res = await fetch(API + 'llamar_turno.php', {
|
const res = await fetch(API + 'llamar_turno.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -529,24 +568,22 @@ async function rellamarDesdeCard(turnoId) {
|
|||||||
await abrirFicha(json.turno);
|
await abrirFicha(json.turno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Llamar siguiente ──────────────────────────────────────────
|
// ── Llamar siguiente: selecciona el primero en espera sin llamarlo ─
|
||||||
async function llamarSiguiente() {
|
async function llamarSiguiente() {
|
||||||
await _llamar({});
|
const primero = [..._colaMap.values()].find(t => t.estado === 'en_espera_lugar');
|
||||||
|
if (!primero) { mostrarToast('Cola vacía — no hay turnos en espera.', 'warn', 3000); return; }
|
||||||
|
await seleccionarSinLlamar(primero.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function llamarTurnoEspecifico(turnoId) {
|
async function llamarTurnoEspecifico(turnoId) {
|
||||||
if (turnoActivo?.id == turnoId) {
|
await seleccionarSinLlamar(turnoId);
|
||||||
// Ya está activo — solo mostrar la ficha sin re-llamar API
|
|
||||||
await abrirFicha(turnoActivo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _llamar({ turno_id: turnoId });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _llamar(extra) {
|
async function _llamar(extra) {
|
||||||
if (!lugarId) { alert('Primero seleccione un lugar.'); return; }
|
if (!lugarId) { mostrarError('Primero seleccione un lugar.'); return; }
|
||||||
const btn = document.getElementById('btn-llamar');
|
const btn = document.getElementById('btn-llamar');
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
|
mostrarToast('Consultando siguiente turno…', 'info', 1500);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(API + 'llamar_turno.php', {
|
const res = await fetch(API + 'llamar_turno.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -554,13 +591,14 @@ async function _llamar(extra) {
|
|||||||
body: JSON.stringify({ area: 'lugar', lugar_id: lugarId, ...extra }),
|
body: JSON.stringify({ area: 'lugar', lugar_id: lugarId, ...extra }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.ok) { alert('Error: ' + json.error); return; }
|
if (!json.ok) { mostrarError(json.error); return; }
|
||||||
if (!json.turno) { alert('Cola del lugar vacía.'); return; }
|
if (!json.turno) { mostrarToast('Cola vacía — no hay turnos en espera.', 'warn', 3000); return; }
|
||||||
|
mostrarLlamando(json.turno.codigo);
|
||||||
anunciarTurno(json.turno.codigo);
|
anunciarTurno(json.turno.codigo);
|
||||||
await abrirFicha(json.turno);
|
await abrirFicha(json.turno);
|
||||||
cargarCola();
|
cargarCola();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Error: ' + err.message);
|
mostrarError(err.message);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
@@ -722,10 +760,10 @@ async function reenviarConsentimiento(turnoId) {
|
|||||||
body: JSON.stringify({ turno_id: turnoId }),
|
body: JSON.stringify({ turno_id: turnoId }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.ok) { alert('Error: ' + json.error); return; }
|
if (!json.ok) { mostrarError(json.error); return; }
|
||||||
await actualizarConsentimientos(turnoId);
|
await actualizarConsentimientos(turnoId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Error: ' + err.message);
|
mostrarError(err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,35 +801,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// ── Acciones del turno ────────────────────────────────────────
|
// ── Acciones del turno ────────────────────────────────────────
|
||||||
async function iniciarAtencion() {
|
async function iniciarAtencion() {
|
||||||
if (!turnoActivo) return;
|
if (!turnoActivo) return;
|
||||||
if (hayPendientes) return; // botón ya deshabilitado, doble seguro
|
if (hayPendientes) return;
|
||||||
|
// Llamar via llamar_turno.php para que suene la campana y notifique el display
|
||||||
const btn = document.getElementById('btn-iniciar');
|
await _llamar({ turno_id: turnoActivo.id });
|
||||||
btn.disabled = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(API + 'cambiar_estado.php', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ turno_id: turnoActivo.id, nuevo_estado: 'en_servicio' }),
|
|
||||||
});
|
|
||||||
const json = await res.json();
|
|
||||||
if (!json.ok) {
|
|
||||||
alert('Error: ' + json.error);
|
|
||||||
btn.disabled = hayPendientes;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
turnoActivo = json.turno;
|
|
||||||
actualizarEstadoBadge('en_servicio');
|
|
||||||
|
|
||||||
// Mostrar "Finalizar" y "Regresar", ocultar "Iniciar"
|
|
||||||
btn.classList.add('d-none');
|
|
||||||
document.getElementById('btn-finalizar').classList.remove('d-none');
|
|
||||||
document.getElementById('btn-regresar').classList.remove('d-none');
|
|
||||||
cargarCola();
|
|
||||||
} catch (err) {
|
|
||||||
alert('Error: ' + err.message);
|
|
||||||
btn.disabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function finalizarAtencion() {
|
async function finalizarAtencion() {
|
||||||
@@ -824,11 +836,11 @@ async function regresarCola() {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.ok) { alert('Error: ' + json.error); return; }
|
if (!json.ok) { mostrarError(json.error); return; }
|
||||||
resetFicha();
|
resetFicha();
|
||||||
cargarCola();
|
cargarCola();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Error: ' + err.message);
|
mostrarError(err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,11 +852,11 @@ async function cambiarEstadoTurno(nuevoEstado) {
|
|||||||
body: JSON.stringify({ turno_id: turnoActivo.id, nuevo_estado: nuevoEstado }),
|
body: JSON.stringify({ turno_id: turnoActivo.id, nuevo_estado: nuevoEstado }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.ok) { alert('Error: ' + json.error); return; }
|
if (!json.ok) { mostrarError(json.error); return; }
|
||||||
resetFicha();
|
resetFicha();
|
||||||
cargarCola();
|
cargarCola();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Error: ' + err.message);
|
mostrarError(err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,10 +920,10 @@ async function rellamarTurno() {
|
|||||||
body: JSON.stringify({ area: 'lugar', lugar_id: lugarId, turno_id: turnoActivo.id }),
|
body: JSON.stringify({ area: 'lugar', lugar_id: lugarId, turno_id: turnoActivo.id }),
|
||||||
});
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (!json.ok) alert('Error: ' + json.error);
|
if (!json.ok) mostrarError(json.error);
|
||||||
else if (json.turno) anunciarTurno(json.turno.codigo);
|
else if (json.turno) { mostrarLlamando(json.turno.codigo); anunciarTurno(json.turno.codigo); }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Error: ' + err.message);
|
mostrarError(err.message);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
@@ -922,6 +934,29 @@ function escHtml(str) {
|
|||||||
d.appendChild(document.createTextNode(String(str ?? '')));
|
d.appendChild(document.createTextNode(String(str ?? '')));
|
||||||
return d.innerHTML;
|
return d.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Toast (igual que recepción) ───────────────────────────────
|
||||||
|
let _toastTimer = null;
|
||||||
|
function mostrarToast(msg, type = 'info', duration = 2500) {
|
||||||
|
const el = document.getElementById('lug-toast');
|
||||||
|
const ico = document.getElementById('lug-toast-ico');
|
||||||
|
const txt = document.getElementById('lug-toast-msg');
|
||||||
|
const icons = { success: 'fa-check-circle', info: 'fa-info-circle', warn: 'fa-exclamation-triangle', error: 'fa-times-circle' };
|
||||||
|
el.className = 'rec-toast ' + type;
|
||||||
|
ico.innerHTML = '<i class="fas ' + (icons[type] || icons.info) + '"></i>';
|
||||||
|
txt.textContent = msg;
|
||||||
|
el.classList.add('show');
|
||||||
|
clearTimeout(_toastTimer);
|
||||||
|
_toastTimer = setTimeout(() => el.classList.remove('show'), duration);
|
||||||
|
}
|
||||||
|
function mostrarError(msg) { mostrarToast(msg, 'error', 4000); }
|
||||||
|
function mostrarLlamando(cod) { mostrarToast('Llamando turno ' + cod + '…', 'info', 2000); }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="rec-toast" id="lug-toast">
|
||||||
|
<span class="ico" id="lug-toast-ico"><i class="fas fa-info-circle"></i></span>
|
||||||
|
<span id="lug-toast-msg"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user