feat(turnero): UI/UX tablet improvements for recepcion and lugar views

- recepcion: wider queue column (370px), breakpoint at 680px so portrait
  tablets get 2-column layout; prominent "Llamar siguiente" button in queue
  column header; searchable exam filter; touch-friendly action bar with
  large primary/secondary button rows; larger touch targets for cards,
  checkboxes and consent items
- lugar: wider queue column (340px), breakpoint at 680px; larger action
  buttons (.8rem padding, 1rem font) and secondary buttons; consistent
  mobile breakpoint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-03 18:55:07 -05:00
co-authored by Claude Sonnet 4.6
parent b55c7c1a19
commit 5af985581c
2 changed files with 121 additions and 31 deletions
+13 -9
View File
@@ -45,11 +45,11 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
/* ── Layout ─────────────────────────────────────────────── */
.lugar-layout {
display: grid;
grid-template-columns: 290px 1fr;
grid-template-columns: 340px 1fr;
height: calc(100vh - 52px);
overflow: hidden;
}
@media (max-width: 860px) {
@media (max-width: 680px) {
.lugar-layout { grid-template-columns: 1fr; position: relative; overflow: hidden; }
.lugar-cola { transition: transform .22s ease; }
.lugar-cola.mobile-oculta { transform: translateX(-100%); position: absolute; inset: 0; pointer-events: none; }
@@ -173,7 +173,7 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
border-bottom: 1px solid #e2e8f0; flex-shrink: 0;
position: sticky; top: 0; z-index: 20;
}
@media (max-width: 860px) {
@media (max-width: 680px) {
.ficha-mobile-topbar { display: flex; }
}
.ficha-mobile-topbar .btn-back {
@@ -273,8 +273,8 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
.accion-consent-warn i { color: #f59e0b; flex-shrink: 0; }
.accion-primary-row { margin-bottom: .45rem; }
.btn-accion-primary {
width: 100%; padding: .7rem; border: none; border-radius: 11px;
font-size: .97rem; font-weight: 700; cursor: pointer;
width: 100%; padding: .8rem; border: none; border-radius: 11px;
font-size: 1rem; font-weight: 700; cursor: pointer;
display: flex; align-items: center; justify-content: center; gap: .45rem;
transition: background .15s, transform .1s, opacity .15s;
}
@@ -289,8 +289,8 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
}
.btn-accion-sec {
flex: 1; min-width: 80px;
padding: .45rem .5rem; border-radius: 9px;
font-size: .8rem; font-weight: 600; cursor: pointer;
padding: .55rem .5rem; border-radius: 9px;
font-size: .82rem; font-weight: 600; cursor: pointer;
display: flex; align-items: center; justify-content: center; gap: .35rem;
border: 1.5px solid; background: transparent; transition: background .12s;
}
@@ -921,11 +921,15 @@ async function cargarFichaSolicitud(turnoId) {
const pac = json.paciente;
_solicitudActiva = sol || null;
// Número de orden
// Número de orden (F-... azul, D-... verde)
const ordenEl = document.getElementById('ficha-orden');
const ordenValEl = document.getElementById('ficha-orden-val');
if (sol && sol.numero_orden) {
ordenValEl.textContent = sol.numero_orden;
const isDom = sol.numero_orden.startsWith('D-');
ordenEl.style.background = isDom ? '#f0fdf4' : '#eff6ff';
ordenEl.style.color = isDom ? '#15803d' : '#1d4ed8';
ordenEl.style.borderColor = isDom ? '#86efac' : '#bfdbfe';
ordenEl.classList.remove('d-none');
} else {
ordenEl.classList.add('d-none');
@@ -1271,7 +1275,7 @@ function resetFicha() {
}
// ── Mobile ────────────────────────────────────────────────────
function esMobile() { return window.innerWidth <= 860; }
function esMobile() { return window.innerWidth <= 680; }
function mostrarFichaMobile() {
if (!esMobile()) return;
+108 -22
View File
@@ -83,11 +83,11 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
/* ── Layout de dos columnas ── */
.rec-layout {
display: grid;
grid-template-columns: 320px 1fr;
grid-template-columns: 370px 1fr;
height: calc(100vh - 56px);
overflow: hidden;
}
@media (max-width: 900px) {
@media (max-width: 680px) {
.rec-layout { grid-template-columns: 1fr; position: relative; overflow: hidden; }
.rec-cola { transition: transform .2s ease; }
.rec-cola.mobile-oculta { transform: translateX(-100%); position: absolute; inset: 0; pointer-events: none; }
@@ -95,6 +95,8 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
.rec-ficha.mobile-visible { transform: translateX(0); }
.btn-volver-cola { display: inline-flex !important; align-items: center; gap: 6px; }
}
/* En pantalla 2 columnas el botón de topbar queda oculto (hay uno en la cola) */
@media (min-width: 681px) { #btn-llamar { display: none !important; } }
/* ── Columna cola ── */
.rec-cola {
@@ -266,6 +268,51 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
.timeline-codigo { font-size: .82rem; font-weight: 700; }
.timeline-lugar { font-size: .73rem; color: #64748b; }
.timeline-eb { font-size: .62rem; padding: 1px 7px; border-radius: 99px; font-weight: 700; display: inline-block; margin-top: 2px; }
/* ── Botón "Llamar siguiente" en columna de cola ── */
.btn-llamar-cola {
width: 100%; padding: .65rem 1rem; border: none; border-radius: 10px;
background: #2563eb; color: #fff; font-weight: 700; font-size: .92rem;
cursor: pointer; display: flex; align-items: center; justify-content: center; gap: .5rem;
transition: background .15s, transform .1s; margin-top: .5rem;
}
.btn-llamar-cola:hover { background: #1d4ed8; }
.btn-llamar-cola:active { transform: scale(.98); }
.btn-llamar-cola:disabled { background: #94a3b8; cursor: not-allowed; }
/* ── Barra de acciones: botones primarios/secundarios touch-friendly ── */
.accion-primary-row { margin-bottom: .5rem; }
.btn-accion-primary {
width: 100%; padding: .8rem 1rem; border: none; border-radius: 11px;
font-size: .97rem; font-weight: 700; cursor: pointer;
display: flex; align-items: center; justify-content: center; gap: .45rem;
transition: background .15s, transform .1s, opacity .15s;
}
.btn-accion-primary:active { transform: scale(.98); }
.btn-accion-primary:disabled { opacity: .55; cursor: not-allowed; }
.btn-accion-primary.verde { background: #16a34a; color: #fff; }
.btn-accion-primary.verde:hover { background: #15803d; }
.btn-accion-primary.azul { background: #2563eb; color: #fff; }
.btn-accion-primary.azul:hover { background: #1d4ed8; }
.accion-secondary-row { display: flex; gap: .4rem; flex-wrap: wrap; }
.btn-accion-sec {
flex: 1; min-width: 80px; padding: .55rem .5rem; border-radius: 9px;
font-size: .8rem; font-weight: 600; cursor: pointer;
display: flex; align-items: center; justify-content: center; gap: .35rem;
border: 1.5px solid; background: transparent; transition: background .12s;
}
.btn-accion-sec.warning { color: #92400e; border-color: #fcd34d; }
.btn-accion-sec.warning:hover { background: #fffbeb; }
.btn-accion-sec.info { color: #1e40af; border-color: #93c5fd; }
.btn-accion-sec.info:hover { background: #eff6ff; }
.btn-accion-sec.danger { color: #991b1b; border-color: #fca5a5; }
.btn-accion-sec.danger:hover { background: #fef2f2; }
/* ── Mejoras de touch target (tablet) ── */
.exam-check-item { min-height: 40px; }
.consent-item { min-height: 46px; }
.pac-resultado { min-height: 50px; }
.cola-card { min-height: 62px; padding: .7rem 1rem .7rem .85rem; }
</style>
</head>
<body>
@@ -340,6 +387,9 @@ document.addEventListener('DOMContentLoaded', function() {
</span>
<span class="badge bg-primary rounded-pill" id="badge-count">0</span>
</div>
<button class="btn-llamar-cola" id="btn-llamar-cola" onclick="llamarSiguiente()">
<i class="fas fa-bell"></i>Llamar siguiente
</button>
</div>
<div class="cola-items" id="cola-items">
<div class="cola-vacia">
@@ -511,6 +561,17 @@ document.addEventListener('DOMContentLoaded', function() {
<i class="fas fa-vial me-1"></i>Solo entrega de muestras
</label>
</div>
<div class="input-group input-group-sm mb-2">
<span class="input-group-text text-muted" style="background:#f8fafc"><i class="fas fa-search"></i></span>
<input type="text" id="inp-filtrar-exam" class="form-control"
placeholder="Filtrar exámenes…" autocomplete="off"
oninput="filtrarExamenes(this.value)">
<button class="btn btn-outline-secondary" type="button"
onclick="document.getElementById('inp-filtrar-exam').value='';filtrarExamenes('')"
title="Limpiar filtro">
<i class="fas fa-times"></i>
</button>
</div>
<div id="lista-examenes">
<?php foreach ($examenesAgrupados as $cat => $items): ?>
<div class="exam-group-title"><?= htmlspecialchars($cat) ?></div>
@@ -586,21 +647,25 @@ document.addEventListener('DOMContentLoaded', function() {
<!-- ── Acciones ── -->
<div class="ficha-acciones">
<button class="btn btn-success" id="btn-guardar" onclick="guardarSolicitud()">
<i class="fas fa-save me-1"></i>Guardar solicitud
</button>
<button class="btn btn-primary d-none" id="btn-pasar-lugar" onclick="pasarALugar()">
<i class="fas fa-arrow-right me-1"></i>Pasar a lugar
</button>
<button class="btn btn-warning d-none" id="btn-enviar-consent" onclick="enviarConsentimientos()">
<i class="fas fa-paper-plane me-1"></i>Enviar consentimientos
</button>
<button class="btn btn-outline-secondary" id="btn-soltar" onclick="soltarTurno()" title="Liberar turno para que otro escritorio lo llame">
<i class="fas fa-undo-alt me-1"></i>Soltar
</button>
<button class="btn btn-secondary ms-auto" onclick="marcarAusente()">
<i class="fas fa-user-slash me-1"></i>Ausente
</button>
<div class="accion-primary-row">
<button class="btn-accion-primary verde" id="btn-guardar" onclick="guardarSolicitud()">
<i class="fas fa-save"></i>Guardar solicitud
</button>
<button class="btn-accion-primary azul d-none" id="btn-pasar-lugar" onclick="pasarALugar()">
<i class="fas fa-arrow-right"></i>Pasar a lugar
</button>
</div>
<div class="accion-secondary-row">
<button class="btn-accion-sec warning d-none" id="btn-enviar-consent" onclick="enviarConsentimientos()">
<i class="fas fa-paper-plane"></i>Consentimientos
</button>
<button class="btn-accion-sec info" id="btn-soltar" onclick="soltarTurno()" title="Liberar turno para que otro escritorio lo llame">
<i class="fas fa-undo-alt"></i>Soltar
</button>
<button class="btn-accion-sec danger" onclick="marcarAusente()">
<i class="fas fa-user-slash"></i>Ausente
</button>
</div>
</div>
</div><!-- /ficha-turno -->
</div><!-- /rec-ficha -->
@@ -917,8 +982,10 @@ function renderCola(snap) {
// ── Llamar siguiente ──────────────────────────────────────────
async function llamarSiguiente() {
const btn = document.getElementById('btn-llamar');
btn.disabled = true;
const btn = document.getElementById('btn-llamar');
const btn2 = document.getElementById('btn-llamar-cola');
if (btn) btn.disabled = true;
if (btn2) btn2.disabled = true;
mostrarToast('Consultando siguiente turno…', 'info', 1500);
try {
const res = await fetch(API + 'llamar_turno.php', {
@@ -941,7 +1008,8 @@ async function llamarSiguiente() {
} catch (err) {
mostrarError(err.message);
} finally {
btn.disabled = false;
if (btn) btn.disabled = false;
if (btn2) btn2.disabled = false;
}
}
@@ -1014,7 +1082,7 @@ async function cargarConsecutivo() {
if (!inp) return;
inp.value = '…';
try {
const r = await fetch(API + 'get_consecutivo.php');
const r = await fetch(API + 'get_consecutivo.php?tipo=F');
const d = await r.json();
if (d.ok) inp.value = d.consecutivo;
} catch(_) { inp.value = ''; }
@@ -1764,12 +1832,30 @@ function resetCheckboxes() {
document.getElementById('chk-solo-muestras').checked = false;
document.querySelectorAll('.exam-chk').forEach(c => { c.checked = false; c.disabled = false; });
document.getElementById('lista-examenes').style.opacity = '';
const fi = document.getElementById('inp-filtrar-exam');
if (fi) { fi.value = ''; filtrarExamenes(''); }
document.getElementById('sel-pago').value = '';
document.getElementById('inp-total').value = '';
document.getElementById('inp-obs').value = '';
resetPagoCombinado();
resetMedico();
}
function filtrarExamenes(q) {
const query = q.toLowerCase().trim();
document.querySelectorAll('#lista-examenes .exam-check-item').forEach(item => {
item.style.display = (!query || item.textContent.toLowerCase().includes(query)) ? '' : 'none';
});
document.querySelectorAll('#lista-examenes .exam-group-title').forEach(title => {
let next = title.nextElementSibling;
let anyVisible = false;
while (next && !next.classList.contains('exam-group-title')) {
if (next.style.display !== 'none') anyVisible = true;
next = next.nextElementSibling;
}
title.style.display = anyVisible ? '' : 'none';
});
}
function toggleTodosExamenes(val) {
document.querySelectorAll('.exam-chk').forEach(c => c.checked = val);
}
@@ -1790,7 +1876,7 @@ function resetPlaceholder() {
volverACola();
}
function esMobile() { return window.innerWidth <= 900; }
function esMobile() { return window.innerWidth <= 680; }
function mostrarFichaMobile() {
if (!esMobile()) return;
document.getElementById('rec-ficha').classList.add('mobile-visible');