This commit is contained in:
Lizandro Guarnizo
2026-04-21 18:13:53 -05:00
parent 957e264a64
commit 63da89c31a
5 changed files with 309 additions and 135 deletions
+35
View File
@@ -0,0 +1,35 @@
-- ════════════════════════════════════════════════════════════════
-- Migration 006 — Tipos de lugar en el Turnero
-- Permite distinguir escritorios de Recepción de estaciones de Muestras.
-- ════════════════════════════════════════════════════════════════
-- Añadir columna tipo a turnero_lugares
ALTER TABLE turnero_lugares
ADD COLUMN IF NOT EXISTS tipo
ENUM('recepcion', 'muestras') NOT NULL DEFAULT 'muestras'
COMMENT 'recepcion=ventanilla de recepcion | muestras=estacion de toma de muestras'
AFTER nombre;
-- Los lugares existentes (Toma de Muestras, Rayos X, etc.) quedan como 'muestras'
-- Los escritorios de recepción se crean desde el panel de configuración.
-- Insertar escritorios de recepción de ejemplo si no existen
INSERT IGNORE INTO turnero_lugares (id, nombre, tipo, descripcion, activo, sort_order) VALUES
(10, 'Recepción 1', 'recepcion', 'Primer escritorio de recepción', 1, 1),
(11, 'Recepción 2', 'recepcion', 'Segundo escritorio de recepción', 1, 2);
-- Índice para filtrar por tipo
ALTER TABLE turnero_lugares
ADD INDEX IF NOT EXISTS idx_tipo (tipo);
-- ────────────────────────────────────────────────────────────────
-- Añadir recepcion_desk_id a turnero_turnos
-- Permite saber en qué escritorio de recepción fue atendido el turno
-- (opcional: si NULL = recepcionista no seleccionó escritorio)
ALTER TABLE turnero_turnos
ADD COLUMN IF NOT EXISTS recepcion_desk_id INT UNSIGNED DEFAULT NULL
COMMENT 'FK turnero_lugares.id (tipo=recepcion) — escritorio que llamó el turno'
AFTER lugar_destino_id;
ALTER TABLE turnero_turnos
ADD INDEX IF NOT EXISTS idx_rec_desk (recepcion_desk_id);
+77 -24
View File
@@ -12,33 +12,86 @@ requireMethod('GET');
$pdo = db();
$sesionId = obtenerOCrearSesionHoy();
// ── 1. TODOS los turnos activos en Recepción ─────────────────
// Puede haber varios simultáneos (un escritorio por operador).
$stmtRec = $pdo->prepare(
"SELECT t.id,
t.codigo,
t.numero,
t.estado,
t.paciente_nombre,
t.llamado_recepcion_at AS llamado_at,
t.atendido_recepcion_por,
p.codigo AS prioridad_codigo,
p.nombre AS prioridad_nombre,
p.color AS prioridad_color
FROM turnero_turnos t
JOIN turnero_prioridades p ON p.id = t.prioridad_id
WHERE t.sesion_id = ?
AND t.estado = 'en_recepcion'
ORDER BY t.llamado_recepcion_at DESC"
// ── 1. Escritorios de Recepción activos + su turno en_recepcion ─
// Cada escritorio puede tener un turno distinto (varios recepcionistas).
$stmtDesks = $pdo->query(
"SELECT id, nombre, sort_order
FROM turnero_lugares
WHERE activo = 1 AND tipo = 'recepcion'
ORDER BY sort_order ASC"
);
$stmtRec->execute([$sesionId]);
$activosRecepcion = $stmtRec->fetchAll(PDO::FETCH_ASSOC);
$escritoriosRec = $stmtDesks->fetchAll(PDO::FETCH_ASSOC);
// ── 2. Lugares activos con su turno en servicio ───────────────
$activosRecepcion = [];
foreach ($escritoriosRec as $desk) {
// El turno activo de este escritorio: el más reciente asociado a él
$stmtT = $pdo->prepare(
"SELECT t.id,
t.codigo,
t.numero,
t.estado,
t.paciente_nombre,
t.llamado_recepcion_at AS llamado_at,
p.codigo AS prioridad_codigo,
p.nombre AS prioridad_nombre,
p.color AS prioridad_color
FROM turnero_turnos t
JOIN turnero_prioridades p ON p.id = t.prioridad_id
WHERE t.sesion_id = ?
AND t.estado = 'en_recepcion'
AND (t.recepcion_desk_id = ? OR t.recepcion_desk_id IS NULL)
ORDER BY t.llamado_recepcion_at DESC
LIMIT 1"
);
$stmtT->execute([$sesionId, (int)$desk['id']]);
$turno = $stmtT->fetch(PDO::FETCH_ASSOC) ?: null;
$activosRecepcion[] = [
'desk_id' => (int)$desk['id'],
'desk_nombre'=> $desk['nombre'],
'sort_order' => (int)$desk['sort_order'],
'turno' => $turno,
];
}
// Si no hay escritorios configurados, mostrar todos en_recepcion sin desk
if (empty($escritoriosRec)) {
$stmtRec = $pdo->prepare(
"SELECT t.id,
t.codigo,
t.numero,
t.estado,
t.paciente_nombre,
t.llamado_recepcion_at AS llamado_at,
p.codigo AS prioridad_codigo,
p.nombre AS prioridad_nombre,
p.color AS prioridad_color
FROM turnero_turnos t
JOIN turnero_prioridades p ON p.id = t.prioridad_id
WHERE t.sesion_id = ?
AND t.estado = 'en_recepcion'
ORDER BY t.llamado_recepcion_at DESC"
);
$stmtRec->execute([$sesionId]);
foreach ($stmtRec->fetchAll(PDO::FETCH_ASSOC) as $i => $t) {
$activosRecepcion[] = [
'desk_id' => 0,
'desk_nombre'=> 'Recepción ' . ($i + 1),
'sort_order' => $i,
'turno' => $t,
];
}
// Si no hay ninguno activo, mostrar un panel vacío
if (empty($activosRecepcion)) {
$activosRecepcion[] = ['desk_id' => 0, 'desk_nombre' => 'Recepción', 'sort_order' => 0, 'turno' => null];
}
}
// ── 2. Estaciones de Muestras activas + su turno ─────────────
$stmtLugares = $pdo->query(
"SELECT id, nombre, sort_order
FROM turnero_lugares
WHERE activo = 1
WHERE activo = 1 AND (tipo = 'muestras' OR tipo IS NULL)
ORDER BY sort_order ASC"
);
$lugares = $stmtLugares->fetchAll(PDO::FETCH_ASSOC);
@@ -122,8 +175,8 @@ $stats = $stmtStats->fetch(PDO::FETCH_ASSOC);
jsonOk([
'sesion_id' => $sesionId,
'activos_recepcion'=> $activosRecepcion, // array — todos los en_recepcion
'lugares' => $lugaresActivos,
'activos_recepcion'=> $activosRecepcion, // array de desks con su turno
'lugares' => $lugaresActivos, // array de estaciones de muestras
'cola' => $cola,
'stats' => $stats,
'timestamp' => date('c'),
+6 -4
View File
@@ -46,20 +46,22 @@ $nombre = trim($input['nombre'] ?? '');
$desc = trim($input['descripcion'] ?? '');
$sortOrder = (int)($input['sort_order'] ?? 99);
$activo = (int)($input['activo'] ?? 1);
$tipo = in_array($input['tipo'] ?? '', ['recepcion', 'muestras'], true)
? $input['tipo'] : 'muestras';
if ($nombre === '') jsonError('El nombre es requerido');
if ($sortOrder < 1) jsonError('El orden debe ser mayor a 0');
if ($id) {
$stmt = db()->prepare(
'UPDATE turnero_lugares SET nombre=?, descripcion=?, sort_order=?, activo=? WHERE id=?'
'UPDATE turnero_lugares SET nombre=?, tipo=?, descripcion=?, sort_order=?, activo=? WHERE id=?'
);
$stmt->execute([$nombre, $desc ?: null, $sortOrder, $activo, $id]);
$stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo, $id]);
jsonOk(['id' => $id], 'Lugar actualizado');
} else {
$stmt = db()->prepare(
'INSERT INTO turnero_lugares (nombre, descripcion, sort_order, activo) VALUES (?, ?, ?, ?)'
'INSERT INTO turnero_lugares (nombre, tipo, descripcion, sort_order, activo) VALUES (?, ?, ?, ?, ?)'
);
$stmt->execute([$nombre, $desc ?: null, $sortOrder, $activo]);
$stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo]);
jsonOk(['id' => (int)db()->lastInsertId()], 'Lugar creado');
}
+144 -68
View File
@@ -166,15 +166,24 @@ $tab = $_GET['tab'] ?? 'lugares';
<!-- ════════════════════════════════════════
TAB 1 — LUGARES
════════════════════════════════════════ -->
<?php if ($tab === 'lugares'): ?>
<p class="section-title">Estaciones de servicio configurables</p>
<?php if ($tab === 'lugares'):
$lugaresRec = array_values(array_filter($lugares, fn($l) => ($l['tipo'] ?? 'muestras') === 'recepcion'));
$lugaresMues = array_values(array_filter($lugares, fn($l) => ($l['tipo'] ?? 'muestras') === 'muestras'));
?>
<div id="lista-lugares">
<?php foreach ($lugares as $lu): ?>
<!-- ── Escritorios de Recepción ─────────────────── -->
<div class="d-flex align-items-center gap-2 mb-2">
<i class="fas fa-door-open text-primary"></i>
<p class="section-title mb-0">Escritorios de Recepción</p>
<span class="badge bg-primary-subtle text-primary"><?= count($lugaresRec) ?></span>
</div>
<p class="text-muted small mb-3">Cada escritorio es una ventanilla donde un recepcionista atiende pacientes. Aparecerá en la columna izquierda de la pantalla TV global.</p>
<div id="lista-recepcion">
<?php foreach ($lugaresRec as $lu): ?>
<div class="item-row" data-id="<?= $lu['id'] ?>">
<span class="drag-handle text-muted me-1" style="cursor:grab" title="Reordenar">
<i class="fas fa-grip-vertical"></i>
</span>
<span class="drag-handle text-muted me-1" style="cursor:grab"><i class="fas fa-grip-vertical"></i></span>
<i class="fas fa-door-open text-primary me-1" style="font-size:.8rem"></i>
<span class="item-name"><?= htmlspecialchars($lu['nombre']) ?></span>
<?php if ($lu['descripcion']): ?>
<small class="text-muted d-none d-md-inline"><?= htmlspecialchars($lu['descripcion']) ?></small>
@@ -182,10 +191,7 @@ $tab = $_GET['tab'] ?? 'lugares';
<span class="badge <?= $lu['activo'] ? 'bg-success-subtle text-success' : 'bg-secondary-subtle text-secondary' ?> ms-1">
<?= $lu['activo'] ? 'Activo' : 'Inactivo' ?>
</span>
<button class="btn-icon" onclick="copiarUrlDisplay(<?= $lu['id'] ?>)" title="Copiar URL pantalla TV">
<i class="fas fa-tv"></i>
</button>
<button class="btn-icon text-primary" onclick="editarLugar(<?= $lu['id'] ?>,'<?= addslashes($lu['nombre']) ?>','<?= addslashes($lu['descripcion'] ?? '') ?>',<?= $lu['activo'] ?>,<?= $lu['sort_order'] ?>)" title="Editar">
<button class="btn-icon text-primary" onclick="editarLugar(<?= $lu['id'] ?>,'<?= addslashes($lu['nombre']) ?>','<?= addslashes($lu['descripcion'] ?? '') ?>',<?= $lu['activo'] ?>,<?= $lu['sort_order'] ?>,'recepcion')" title="Editar">
<i class="fas fa-pencil-alt"></i>
</button>
<button class="btn-icon text-danger" onclick="eliminarLugar(<?= $lu['id'] ?>, '<?= addslashes($lu['nombre']) ?>')" title="Eliminar">
@@ -193,28 +199,89 @@ $tab = $_GET['tab'] ?? 'lugares';
</button>
</div>
<?php endforeach; ?>
<?php if (empty($lugares)): ?>
<p class="text-muted text-center py-3">No hay lugares configurados</p>
<?php if (empty($lugaresRec)): ?>
<p class="text-muted text-center py-2 small">No hay escritorios de recepción configurados</p>
<?php endif; ?>
</div>
<div class="form-add mt-4">
<p class="section-title mb-3"><i class="fas fa-plus me-1"></i>Agregar lugar</p>
<div class="form-add mt-2 mb-4 p-3" style="background:#eff6ff;border-radius:10px;border:1px solid #bfdbfe">
<p class="section-title mb-3"><i class="fas fa-plus me-1"></i>Agregar escritorio de recepción</p>
<div class="row g-2 align-items-end">
<div class="col-md-4">
<div class="col-md-5">
<label class="form-label small fw-semibold">Nombre <span class="text-danger">*</span></label>
<input type="text" id="lu-nombre" class="form-control form-control-sm" placeholder="Toma de Muestras 3">
<input type="text" id="rec-nombre" class="form-control form-control-sm" placeholder="Recepción 1, Ventanilla 2…">
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold">Descripción</label>
<input type="text" id="lu-desc" class="form-control form-control-sm" placeholder="Opcional">
<input type="text" id="rec-desc" class="form-control form-control-sm" placeholder="Opcional">
</div>
<div class="col-md-2">
<div class="col-md-1">
<label class="form-label small fw-semibold">Orden</label>
<input type="number" id="lu-orden" class="form-control form-control-sm" value="<?= count($lugares) + 1 ?>" min="1">
<input type="number" id="rec-orden" class="form-control form-control-sm" value="<?= count($lugaresRec) + 1 ?>" min="1">
</div>
<div class="col-md-2">
<button class="btn btn-primary btn-sm w-100" onclick="guardarLugar()">
<button class="btn btn-primary btn-sm w-100" onclick="guardarLugar('recepcion')">
<i class="fas fa-save me-1"></i>Guardar
</button>
</div>
</div>
</div>
<hr class="my-3">
<!-- ── Estaciones de Toma de Muestras ──────────── -->
<div class="d-flex align-items-center gap-2 mb-2">
<i class="fas fa-vials text-success"></i>
<p class="section-title mb-0">Estaciones de Toma de Muestras</p>
<span class="badge bg-success-subtle text-success"><?= count($lugaresMues) ?></span>
</div>
<p class="text-muted small mb-3">Cada estación es donde se toman muestras o se realizan pruebas. Aparecerá en la columna derecha de la pantalla TV global.</p>
<div id="lista-muestras">
<?php foreach ($lugaresMues as $lu): ?>
<div class="item-row" data-id="<?= $lu['id'] ?>">
<span class="drag-handle text-muted me-1" style="cursor:grab"><i class="fas fa-grip-vertical"></i></span>
<i class="fas fa-flask text-success me-1" style="font-size:.8rem"></i>
<span class="item-name"><?= htmlspecialchars($lu['nombre']) ?></span>
<?php if ($lu['descripcion']): ?>
<small class="text-muted d-none d-md-inline"><?= htmlspecialchars($lu['descripcion']) ?></small>
<?php endif; ?>
<span class="badge <?= $lu['activo'] ? 'bg-success-subtle text-success' : 'bg-secondary-subtle text-secondary' ?> ms-1">
<?= $lu['activo'] ? 'Activo' : 'Inactivo' ?>
</span>
<button class="btn-icon" onclick="copiarUrlDisplay(<?= $lu['id'] ?>)" title="Copiar URL pantalla TV de este lugar">
<i class="fas fa-tv"></i>
</button>
<button class="btn-icon text-primary" onclick="editarLugar(<?= $lu['id'] ?>,'<?= addslashes($lu['nombre']) ?>','<?= addslashes($lu['descripcion'] ?? '') ?>',<?= $lu['activo'] ?>,<?= $lu['sort_order'] ?>,'muestras')" title="Editar">
<i class="fas fa-pencil-alt"></i>
</button>
<button class="btn-icon text-danger" onclick="eliminarLugar(<?= $lu['id'] ?>, '<?= addslashes($lu['nombre']) ?>')" title="Eliminar">
<i class="fas fa-trash"></i>
</button>
</div>
<?php endforeach; ?>
<?php if (empty($lugaresMues)): ?>
<p class="text-muted text-center py-2 small">No hay estaciones de muestras configuradas</p>
<?php endif; ?>
</div>
<div class="form-add mt-2 mb-4 p-3" style="background:#f0fdf4;border-radius:10px;border:1px solid #bbf7d0">
<p class="section-title mb-3"><i class="fas fa-plus me-1"></i>Agregar estación de toma de muestras</p>
<div class="row g-2 align-items-end">
<div class="col-md-5">
<label class="form-label small fw-semibold">Nombre <span class="text-danger">*</span></label>
<input type="text" id="mue-nombre" class="form-control form-control-sm" placeholder="Toma de Muestras 1, Rayos X…">
</div>
<div class="col-md-4">
<label class="form-label small fw-semibold">Descripción</label>
<input type="text" id="mue-desc" class="form-control form-control-sm" placeholder="Opcional">
</div>
<div class="col-md-1">
<label class="form-label small fw-semibold">Orden</label>
<input type="number" id="mue-orden" class="form-control form-control-sm" value="<?= count($lugaresMues) + 1 ?>" min="1">
</div>
<div class="col-md-2">
<button class="btn btn-success btn-sm w-100" onclick="guardarLugar('muestras')">
<i class="fas fa-save me-1"></i>Guardar
</button>
</div>
@@ -226,11 +293,12 @@ $tab = $_GET['tab'] ?? 'lugares';
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header py-2 px-3">
<h6 class="modal-title">Editar lugar</h6>
<h6 class="modal-title" id="modal-lugar-titulo">Editar lugar</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="edit-lu-id">
<input type="hidden" id="edit-lu-tipo" value="muestras">
<div class="mb-2">
<label class="form-label small fw-semibold">Nombre</label>
<input type="text" id="edit-lu-nombre" class="form-control form-control-sm">
@@ -256,46 +324,45 @@ $tab = $_GET['tab'] ?? 'lugares';
</div>
</div>
<!-- URL panel TV por lugar -->
<div class="mt-4">
<p class="section-title"><i class="fas fa-desktop me-1"></i>URLs de pantalla TV por lugar</p>
<?php foreach ($lugares as $lu): ?>
<!-- URLs de acceso -->
<hr class="my-4">
<p class="section-title"><i class="fas fa-desktop me-1"></i>URLs de pantalla TV</p>
<div class="mb-3 p-3" style="background:#fffbeb;border:1px solid #fde68a;border-radius:10px">
<div class="fw-semibold small mb-2"><i class="fas fa-star me-1 text-warning"></i>Pantalla Global (sala de espera — recomendada)</div>
<p class="text-muted small mb-2">Muestra TODOS los escritorios de recepción y estaciones de muestras en una sola pantalla.</p>
<div class="url-row">
<div class="url-box flex-1" id="url-global"
data-url="<?= htmlspecialchars(BASE_URL . 'erp.php?m=turnero&v=display_global') ?>"
><?= htmlspecialchars(BASE_URL . 'erp.php?m=turnero&v=display_global') ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-global')"><i class="fas fa-copy"></i></button>
</div>
</div>
<?php if (!empty($lugaresMues)): ?>
<div class="mb-3">
<div class="fw-semibold small text-muted mb-2"><i class="fas fa-flask me-1"></i>Pantallas individuales por estación de muestras</div>
<?php foreach ($lugaresMues as $lu): ?>
<div class="mb-2">
<small class="fw-semibold text-muted d-block mb-1"><?= htmlspecialchars($lu['nombre']) ?></small>
<small class="d-block mb-1 text-muted"><?= htmlspecialchars($lu['nombre']) ?></small>
<div class="url-row">
<div class="url-box flex-1"
id="url-lugar-<?= $lu['id'] ?>"
data-url="<?= htmlspecialchars(BASE_URL . 'modules/turnero/views/display.php?display=lugar&lugar_id=' . $lu['id']) ?>"
><?= htmlspecialchars(BASE_URL . 'modules/turnero/views/display.php?display=lugar&lugar_id=' . $lu['id']) ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-lugar-<?= $lu['id'] ?>')">
<i class="fas fa-copy"></i>
</button>
<div class="url-box flex-1" id="url-lugar-<?= $lu['id'] ?>"
data-url="<?= htmlspecialchars(BASE_URL . 'erp.php?m=turnero&v=display&display=lugar&lugar_id=' . $lu['id']) ?>"
><?= htmlspecialchars(BASE_URL . 'erp.php?m=turnero&v=display&display=lugar&lugar_id=' . $lu['id']) ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-lugar-<?= $lu['id'] ?>')"><i class="fas fa-copy"></i></button>
</div>
</div>
<?php endforeach; ?>
<div class="mb-2 mt-3">
<small class="fw-semibold text-muted d-block mb-1">Recepción (pantalla general)</small>
<div class="url-row">
<div class="url-box flex-1"
id="url-recepcion"
data-url="<?= htmlspecialchars(BASE_URL . 'modules/turnero/views/display.php?display=recepcion') ?>"
><?= htmlspecialchars(BASE_URL . 'modules/turnero/views/display.php?display=recepcion') ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-recepcion')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="mb-2 mt-1">
<small class="fw-semibold text-muted d-block mb-1">Kiosko de turnos (tablet/pantalla entrada)</small>
<div class="url-row">
<div class="url-box flex-1"
id="url-kiosko"
data-url="<?= htmlspecialchars(BASE_URL . 'modules/turnero/views/kiosko.php') ?>"
><?= htmlspecialchars(BASE_URL . 'modules/turnero/views/kiosko.php') ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-kiosko')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<?php endif; ?>
<div class="mb-2">
<small class="fw-semibold text-muted d-block mb-1"><i class="fas fa-tablet-alt me-1"></i>Kiosko de turnos (tablet entrada)</small>
<div class="url-row">
<div class="url-box flex-1" id="url-kiosko"
data-url="<?= htmlspecialchars(BASE_URL . 'modules/turnero/views/kiosko.php') ?>"
><?= htmlspecialchars(BASE_URL . 'modules/turnero/views/kiosko.php') ?></div>
<button class="btn btn-outline-secondary btn-sm" onclick="copiarUrl('url-kiosko')"><i class="fas fa-copy"></i></button>
</div>
</div>
@@ -677,15 +744,21 @@ function copiarUrlDisplay(lugarId) {
// ─────────────────────────────────────────────────────────────
// TAB 1: LUGARES
// ─────────────────────────────────────────────────────────────
async function guardarLugar(id = null) {
const nombre = (id ? document.getElementById('edit-lu-nombre') : document.getElementById('lu-nombre'))?.value.trim();
const desc = (id ? document.getElementById('edit-lu-desc') : document.getElementById('lu-desc'))?.value.trim();
const orden = parseInt((id ? document.getElementById('edit-lu-orden') : document.getElementById('lu-orden'))?.value) || 99;
const activo = id ? (document.getElementById('edit-lu-activo')?.checked ? 1 : 0) : 1;
async function guardarLugar(tipoOrId = 'muestras', id = null) {
// tipoOrId puede ser 'recepcion', 'muestras', o un número (id al editar)
const esEdicion = typeof tipoOrId === 'number';
if (esEdicion) { id = tipoOrId; tipoOrId = null; }
const prefijo = esEdicion ? 'edit-lu' : (tipoOrId === 'recepcion' ? 'rec' : 'mue');
const nombre = document.getElementById(esEdicion ? 'edit-lu-nombre' : `${prefijo}-nombre`)?.value.trim();
const desc = document.getElementById(esEdicion ? 'edit-lu-desc' : `${prefijo}-desc`)?.value.trim();
const orden = parseInt(document.getElementById(esEdicion ? 'edit-lu-orden' : `${prefijo}-orden`)?.value) || 99;
const activo = esEdicion ? (document.getElementById('edit-lu-activo')?.checked ? 1 : 0) : 1;
const tipo = esEdicion ? (document.getElementById('edit-lu-tipo')?.value || 'muestras') : tipoOrId;
if (!nombre) { toast('El nombre es requerido', 'error'); return; }
const body = { nombre, descripcion: desc, sort_order: orden, activo };
const body = { nombre, tipo, descripcion: desc, sort_order: orden, activo };
if (id) body.id = id;
try {
@@ -700,12 +773,15 @@ async function guardarLugar(id = null) {
} catch (e) { toast('Error de conexión', 'error'); }
}
function editarLugar(id, nombre, desc, activo, orden) {
document.getElementById('edit-lu-id').value = id;
document.getElementById('edit-lu-nombre').value = nombre;
document.getElementById('edit-lu-desc').value = desc;
document.getElementById('edit-lu-orden').value = orden;
function editarLugar(id, nombre, desc, activo, orden, tipo = 'muestras') {
document.getElementById('edit-lu-id').value = id;
document.getElementById('edit-lu-tipo').value = tipo;
document.getElementById('edit-lu-nombre').value = nombre;
document.getElementById('edit-lu-desc').value = desc;
document.getElementById('edit-lu-orden').value = orden;
document.getElementById('edit-lu-activo').checked = !!activo;
const titulo = tipo === 'recepcion' ? 'Editar escritorio de recepción' : 'Editar estación de muestras';
document.getElementById('modal-lugar-titulo').textContent = titulo;
new bootstrap.Modal(document.getElementById('modalEditarLugar')).show();
}
+47 -39
View File
@@ -258,19 +258,13 @@ $_labColor = preg_match('/^#[0-9a-fA-F]{3,8}$/', $_dispCfg['doc_color'] ?? '')
<!-- Cuerpo: Recepción | Muestras -->
<div class="pg-body" id="pg-body">
<!-- Panel Recepción -->
<!-- Panel Recepción (dinámico: N escritorios) -->
<div class="area-panel" id="panel-recepcion">
<div class="area-header recepcion">
<i class="fas fa-door-open"></i> Recepción
</div>
<div class="area-turno" id="turno-recepcion">
<div class="ring" id="ring-recepcion"></div>
<div class="lbl-destino">Pase a Recepción</div>
<div class="codigo-num" id="cod-recepcion">—</div>
<div class="pac-nombre" id="pac-recepcion"></div>
<div class="prio-chip" id="chip-recepcion">
<i class="fas fa-hourglass-half"></i> En espera
</div>
<div class="lugares-grid" id="rec-grid">
<!-- Se genera en JS según escritorios configurados -->
</div>
</div>
@@ -389,8 +383,8 @@ function anunciarTurno(codigo, destino) {
}
// ── Estado previo ──────────────────────────────────────────────
let lastCodRecepcion = null;
const lastCodLugar = {}; // { lugar_id: codigo }
const lastCodRecepcion = {}; // { desk_id: codigo }
const lastCodLugar = {}; // { lugar_id: codigo }
// ── Escape HTML ────────────────────────────────────────────────
function esc(str) {
@@ -417,36 +411,50 @@ function limpiarColor(panelEl, ringEl, chipEl) {
// ── Render snapshot global ─────────────────────────────────────
function renderSnapshot(snap) {
// ── Recepción ───────────────────────────────────────────
const rec = snap.activo_recepcion;
const panelRec = document.getElementById('turno-recepcion');
const ringRec = document.getElementById('ring-recepcion');
const codRec = document.getElementById('cod-recepcion');
const pacRec = document.getElementById('pac-recepcion');
const chipRec = document.getElementById('chip-recepcion');
// ── Recepción (múltiples escritorios) ───────────────────
const recList = snap.activos_recepcion || [];
const recGrid = document.getElementById('rec-grid');
if (rec) {
const color = rec.prioridad_color || '#1565c0';
if (rec.codigo !== lastCodRecepcion) {
anunciarTurno(rec.codigo, 'Recepción');
ringRec.classList.remove('animar');
void ringRec.offsetWidth;
ringRec.classList.add('animar');
lastCodRecepcion = rec.codigo;
recGrid.innerHTML = recList.map(d => {
const t = d.turno;
const color = t ? (t.prioridad_color || '#1565c0') : null;
const colorStyle = color ? `style="--prio-color:${color};background:${color}12"` : '';
const codStyle = color ? '' : 'style="color:#cbd5e1"';
const chipStyle = color
? `style="background:${color}22;color:${color}"`
: 'style="background:#f1f5f9;color:#94a3b8"';
const chipContent = t
? `<i class='fas fa-ticket-alt'></i> ${esc(t.prioridad_codigo)} — ${esc(t.prioridad_nombre)}`
: `<i class='fas fa-hourglass-half'></i> En espera`;
const codText = t ? esc(t.codigo) : '—';
const pacText = t ? esc(t.paciente_nombre || '') : '';
return `
<div class="lugar-sub" id="sub-rec-${d.desk_id}">
<div class="area-header" style="background:#1e40af;font-size:.7rem;padding:.35rem 1rem">
<i class="fas fa-door-open"></i> ${esc(d.desk_nombre)}
</div>
<div class="area-turno" id="area-rec-${d.desk_id}" ${colorStyle}>
<div class="ring" id="ring-rec-${d.desk_id}"></div>
<div class="lbl-destino">Pase a ${esc(d.desk_nombre)}</div>
<div class="codigo-num" id="cod-rec-${d.desk_id}" ${codStyle}>${codText}</div>
<div class="pac-nombre">${pacText}</div>
<div class="prio-chip" id="chip-rec-${d.desk_id}" ${chipStyle}>${chipContent}</div>
</div>
</div>`;
}).join('');
// Sonido/animación por desk
recList.forEach(d => {
const t = d.turno;
if (!t) { lastCodRecepcion[d.desk_id] = null; return; }
if (t.codigo !== lastCodRecepcion[d.desk_id]) {
anunciarTurno(t.codigo, d.desk_nombre);
const ring = document.getElementById(`ring-rec-${d.desk_id}`);
if (ring) { ring.classList.remove('animar'); void ring.offsetWidth; ring.classList.add('animar'); }
lastCodRecepcion[d.desk_id] = t.codigo;
}
aplicarColor(panelRec, ringRec, chipRec, color);
codRec.textContent = rec.codigo;
codRec.style.color = '';
pacRec.textContent = rec.paciente_nombre || '';
chipRec.innerHTML = `<i class="fas fa-ticket-alt"></i> ${esc(rec.prioridad_codigo)} — ${esc(rec.prioridad_nombre)}`;
} else {
limpiarColor(panelRec, ringRec, chipRec);
codRec.textContent = '—';
codRec.style.color = '#cbd5e1';
pacRec.textContent = '';
chipRec.innerHTML = '<i class="fas fa-hourglass-half"></i> En espera';
lastCodRecepcion = null;
}
});
// ── Lugares (muestras) ──────────────────────────────────
const lugares = snap.lugares || [];