Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
062f565ab5 | ||
|
|
6d63112d76 | ||
|
|
9e7637582d | ||
|
|
92e4d01181 | ||
|
|
e90cfda3f3 | ||
|
|
d6e1d083f4 | ||
|
|
f724e2e94c | ||
|
|
86be0669af | ||
|
|
3b1b7c9333 | ||
|
|
ba27511414 |
@@ -48,6 +48,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
|
||||
requireAuthentication();
|
||||
|
||||
/**
|
||||
* Shorthand para obtener la conexión PDO.
|
||||
*/
|
||||
function db(): \PDO {
|
||||
return Database::getInstance()->getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* ID del admin autenticado actualmente.
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Verifica si un número de teléfono está registrado en WhatsApp (tabla users).
|
||||
*/
|
||||
require_once __DIR__ . '/_helpers.php';
|
||||
requireAuth();
|
||||
// requireAuthentication() ya fue llamado por _helpers.php
|
||||
|
||||
$phone = trim($_GET['phone'] ?? '');
|
||||
if (!$phone) { jsonError('phone requerido', 400); }
|
||||
|
||||
@@ -13,6 +13,11 @@ requireMethod('POST');
|
||||
try {
|
||||
$datos = inputJson();
|
||||
|
||||
// user_id vacío → null para evitar error de tipo en la BD
|
||||
if (isset($datos['user_id']) && $datos['user_id'] === '') {
|
||||
$datos['user_id'] = null;
|
||||
}
|
||||
|
||||
// ── Validación de formato de campos del paciente ────────────────────────
|
||||
$nombreVal = trim($datos['nombre_completo'] ?? '');
|
||||
if ($nombreVal !== '') {
|
||||
|
||||
@@ -132,11 +132,12 @@ body {
|
||||
}
|
||||
|
||||
.sidebar-menu .nav-link.active {
|
||||
color: var(--brand-dark, #0d47a1);
|
||||
color: var(--cat-color, var(--brand-dark, #0d47a1));
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
|
||||
transform: translateX(3px);
|
||||
border-left: 3px solid var(--cat-color, var(--brand, #1565c0));
|
||||
}
|
||||
|
||||
.sidebar-menu .nav-link i {
|
||||
@@ -169,7 +170,7 @@ body {
|
||||
}
|
||||
.sidebar-menu li.sidebar-section:hover { color: rgba(255,255,255,.9); background: rgba(255,255,255,.07); }
|
||||
.sidebar-menu li.sidebar-section.has-active {
|
||||
border-left-color: rgba(255,255,255,.7);
|
||||
border-left-color: var(--cat-color, rgba(255,255,255,.7));
|
||||
background: rgba(255,255,255,.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ class Layout
|
||||
<!-- Font Awesome 6 -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||
<!-- Estilos del sistema -->
|
||||
<link href="<?= $base ?>/assets/css/styles.css?v=13" rel="stylesheet">
|
||||
<link href="<?= $base ?>/assets/css/styles.css?v=14" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
|
||||
+2
-2
@@ -531,9 +531,9 @@ async function verificarWhatsapp() {
|
||||
try {
|
||||
const r = await fetch(`api/lab/check_whatsapp.php?phone=${encodeURIComponent(tel)}`);
|
||||
const d = await r.json();
|
||||
if (d.ok && d.data.found) {
|
||||
if (d.ok && d.found) {
|
||||
badge.innerHTML = '<span class="text-success"><i class="fab fa-whatsapp me-1"></i>Registrado en WhatsApp</span>';
|
||||
hiddenUid.value = d.data.user_id;
|
||||
hiddenUid.value = d.user_id;
|
||||
} else {
|
||||
badge.innerHTML = '<span class="text-muted"><i class="fas fa-times-circle me-1"></i>Sin WhatsApp registrado</span>';
|
||||
hiddenUid.value = '';
|
||||
|
||||
+47
-50
@@ -1,18 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Descriptor del módulo Turnero — Oleada 1
|
||||
* Links filtrados por rol con sub-acordeones para recepción y muestras.
|
||||
* Los links visibles se filtran según el rol del usuario.
|
||||
*/
|
||||
|
||||
$_trRole = $_SESSION['admin_user']['role'] ?? 'admin';
|
||||
$_trIsRecep = $_trRole === 'recepcionista';
|
||||
$_trIsBacte = $_trRole === 'bacteriologo';
|
||||
$_trRole = $_SESSION['admin_user']['role'] ?? 'admin';
|
||||
$_trAdminRoles = ['superadmin', 'admin', 'supervisor'];
|
||||
$_trIsAdmin = in_array($_trRole, $_trAdminRoles, true);
|
||||
$_trIsRecep = $_trRole === 'recepcionista';
|
||||
$_trIsBacte = $_trRole === 'bacteriologo';
|
||||
|
||||
try {
|
||||
$_trPdo = Database::getInstance()->getConnection();
|
||||
|
||||
$_trDesks = $_trPdo->query(
|
||||
"SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='recepcion' ORDER BY sort_order"
|
||||
)->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$_trMuestras = $_trPdo->query(
|
||||
"SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='muestras' ORDER BY sort_order"
|
||||
)->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -21,67 +25,60 @@ try {
|
||||
$_trMuestras = [];
|
||||
}
|
||||
|
||||
// Sub-links de recepción
|
||||
$_trRecepChildren = [];
|
||||
foreach ($_trDesks as $_d) {
|
||||
$_trRecepChildren[] = [
|
||||
'name' => $_d['nombre'],
|
||||
'icon' => 'fas fa-chair',
|
||||
'route' => '/erp.php?m=turnero&v=recepcion&desk_id=' . (int)$_d['id'],
|
||||
];
|
||||
}
|
||||
if (empty($_trRecepChildren)) {
|
||||
$_trRecepChildren[] = ['name' => 'Recepción', 'icon' => 'fas fa-chair', 'route' => '/erp.php?m=turnero&v=recepcion'];
|
||||
}
|
||||
|
||||
// Sub-links de muestras
|
||||
$_trMuestrasChildren = [];
|
||||
foreach ($_trMuestras as $_m) {
|
||||
$_trMuestrasChildren[] = [
|
||||
'name' => $_m['nombre'],
|
||||
'icon' => 'fas fa-flask',
|
||||
'route' => '/erp.php?m=turnero&v=lugar&lugar_id=' . (int)$_m['id'],
|
||||
];
|
||||
}
|
||||
|
||||
$_trLinks = [];
|
||||
|
||||
// ── Recepcionista ─────────────────────────────────────────────
|
||||
// ── Recepcionista: solo sus escritorios + pantalla TV ─────────
|
||||
if ($_trIsRecep) {
|
||||
$_trLinks[] = ['name' => 'Pantalla TV', 'icon' => 'fas fa-tv', 'route' => '/erp.php?m=turnero&v=display_global'];
|
||||
if (count($_trRecepChildren) > 1) {
|
||||
$_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => null, 'children' => $_trRecepChildren];
|
||||
if (!empty($_trDesks)) {
|
||||
foreach ($_trDesks as $_d) {
|
||||
$_trLinks[] = [
|
||||
'name' => $_d['nombre'],
|
||||
'icon' => 'fas fa-concierge-bell',
|
||||
'route' => '/erp.php?m=turnero&v=recepcion&desk_id=' . (int)$_d['id'],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$_trLinks[] = array_merge($_trRecepChildren[0], ['icon' => 'fas fa-concierge-bell']);
|
||||
$_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => '/erp.php?m=turnero&v=recepcion'];
|
||||
}
|
||||
|
||||
// ── Bacteriólogo ──────────────────────────────────────────────
|
||||
// ── Bacteriólogo: dashboard, historial, TV + sus estaciones ──
|
||||
} elseif ($_trIsBacte) {
|
||||
$_trLinks[] = ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'];
|
||||
$_trLinks[] = ['name' => 'Historial', 'icon' => 'fas fa-history', 'route' => '/erp.php?m=turnero&v=historial'];
|
||||
$_trLinks[] = ['name' => 'Pantalla TV', 'icon' => 'fas fa-tv', 'route' => '/erp.php?m=turnero&v=display_global'];
|
||||
if (count($_trMuestrasChildren) > 1) {
|
||||
$_trLinks[] = ['name' => 'Estaciones', 'icon' => 'fas fa-flask', 'route' => null, 'children' => $_trMuestrasChildren];
|
||||
} elseif (!empty($_trMuestrasChildren)) {
|
||||
$_trLinks[] = $_trMuestrasChildren[0];
|
||||
foreach ($_trMuestras as $_m) {
|
||||
$_trLinks[] = [
|
||||
'name' => $_m['nombre'],
|
||||
'icon' => 'fas fa-flask',
|
||||
'route' => '/erp.php?m=turnero&v=lugar&lugar_id=' . (int)$_m['id'],
|
||||
];
|
||||
}
|
||||
|
||||
// ── Admin / Supervisor / otros ────────────────────────────────
|
||||
// ── Admin / Supervisor / otros: acceso completo ───────────────
|
||||
} else {
|
||||
$_trLinks[] = ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'];
|
||||
$_trLinks[] = ['name' => 'Historial', 'icon' => 'fas fa-history', 'route' => '/erp.php?m=turnero&v=historial'];
|
||||
$_trLinks[] = ['name' => 'Configuración', 'icon' => 'fas fa-sliders-h', 'route' => '/erp.php?m=turnero&v=configuracion'];
|
||||
$_trLinks[] = ['name' => 'Kiosko', 'icon' => 'fas fa-desktop', 'route' => '/erp.php?m=turnero&v=kiosko'];
|
||||
$_trLinks[] = ['name' => 'Pantalla TV', 'icon' => 'fas fa-tv', 'route' => '/erp.php?m=turnero&v=display_global'];
|
||||
if (count($_trRecepChildren) > 1) {
|
||||
$_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => null, 'children' => $_trRecepChildren];
|
||||
} elseif (!empty($_trRecepChildren)) {
|
||||
$_trLinks[] = array_merge($_trRecepChildren[0], ['icon' => 'fas fa-concierge-bell']);
|
||||
$_trLinks[] = ['name' => 'Dashboard', 'icon' => 'fas fa-tachometer-alt', 'route' => '/erp.php?m=turnero&v=dashboard'];
|
||||
$_trLinks[] = ['name' => 'Historial', 'icon' => 'fas fa-history', 'route' => '/erp.php?m=turnero&v=historial'];
|
||||
$_trLinks[] = ['name' => 'Configuración', 'icon' => 'fas fa-sliders-h', 'route' => '/erp.php?m=turnero&v=configuracion'];
|
||||
$_trLinks[] = ['name' => 'Kiosko', 'icon' => 'fas fa-desktop', 'route' => '/erp.php?m=turnero&v=kiosko'];
|
||||
$_trLinks[] = ['name' => 'Pantalla TV Global', 'icon' => 'fas fa-th-large', 'route' => '/erp.php?m=turnero&v=display_global'];
|
||||
if (!empty($_trDesks)) {
|
||||
foreach ($_trDesks as $_d) {
|
||||
$_trLinks[] = [
|
||||
'name' => $_d['nombre'],
|
||||
'icon' => 'fas fa-concierge-bell',
|
||||
'route' => '/erp.php?m=turnero&v=recepcion&desk_id=' . (int)$_d['id'],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$_trLinks[] = ['name' => 'Recepción', 'icon' => 'fas fa-concierge-bell', 'route' => '/erp.php?m=turnero&v=recepcion'];
|
||||
}
|
||||
if (count($_trMuestrasChildren) > 1) {
|
||||
$_trLinks[] = ['name' => 'Estaciones', 'icon' => 'fas fa-flask', 'route' => null, 'children' => $_trMuestrasChildren];
|
||||
} elseif (!empty($_trMuestrasChildren)) {
|
||||
$_trLinks[] = $_trMuestrasChildren[0];
|
||||
foreach ($_trMuestras as $_m) {
|
||||
$_trLinks[] = [
|
||||
'name' => $_m['nombre'],
|
||||
'icon' => 'fas fa-flask',
|
||||
'route' => '/erp.php?m=turnero&v=lugar&lugar_id=' . (int)$_m['id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,26 +116,54 @@ Layout::open('Dashboard Turnero', 'fas fa-chart-bar');
|
||||
</style>
|
||||
|
||||
<?php
|
||||
// Cargar lugares activos para los botones de acceso rápido
|
||||
$_dbLugares = [];
|
||||
$_dashRole = $_SESSION['admin_user']['role'] ?? 'admin';
|
||||
$_dashIsAdmin = in_array($_dashRole, ['superadmin', 'admin', 'supervisor'], true);
|
||||
$_dashIsRecep = $_dashRole === 'recepcionista';
|
||||
$_dashIsBacte = $_dashRole === 'bacteriologo';
|
||||
|
||||
$_dashReceps = [];
|
||||
$_dashMuestras = [];
|
||||
try {
|
||||
$_pdo = Database::getInstance()->getConnection();
|
||||
// Recepción: primer escritorio
|
||||
$_receps = $_pdo->query("SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='recepcion' ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$_muestras = $_pdo->query("SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='muestras' ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($_receps as $_l) $_dbLugares[] = ['icon'=>'fas fa-concierge-bell', 'label'=>$_l['nombre'], 'url'=>BASE_URL.'erp.php?m=turnero&v=recepcion&desk_id='.$_l['id']];
|
||||
foreach ($_muestras as $_l) $_dbLugares[] = ['icon'=>'fas fa-flask', 'label'=>$_l['nombre'], 'url'=>BASE_URL.'erp.php?m=turnero&v=lugar&lugar_id='.$_l['id']];
|
||||
if ($_dashIsAdmin || $_dashIsRecep)
|
||||
$_dashReceps = $_pdo->query("SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='recepcion' ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
||||
if ($_dashIsAdmin || $_dashIsBacte)
|
||||
$_dashMuestras = $_pdo->query("SELECT id, nombre FROM turnero_lugares WHERE activo=1 AND tipo='muestras' ORDER BY sort_order")->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (\Throwable $_) {}
|
||||
?>
|
||||
<div class="page-header">
|
||||
<h1><i class="fas fa-chart-bar me-2 text-primary"></i>Dashboard Turnero</h1>
|
||||
|
||||
<!-- Accesos rápidos a lugares -->
|
||||
<?php foreach ($_dbLugares as $_btn): ?>
|
||||
<a href="<?= htmlspecialchars($_btn['url'], ENT_QUOTES) ?>" class="btn btn-sm btn-outline-primary">
|
||||
<i class="<?= $_btn['icon'] ?> me-1"></i><?= htmlspecialchars($_btn['label'], ENT_QUOTES) ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
<!-- Accesos rápidos: dropdown por grupo, filtrado por rol -->
|
||||
<?php if (!empty($_dashReceps)): ?>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
<i class="fas fa-concierge-bell me-1"></i>Recepción
|
||||
</button>
|
||||
<ul class="dropdown-menu shadow-sm">
|
||||
<?php foreach ($_dashReceps as $_r): ?>
|
||||
<li><a class="dropdown-item" href="<?= BASE_URL ?>erp.php?m=turnero&v=recepcion&desk_id=<?= (int)$_r['id'] ?>">
|
||||
<i class="fas fa-chair me-1 text-primary"></i><?= htmlspecialchars($_r['nombre'], ENT_QUOTES) ?>
|
||||
</a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($_dashMuestras)): ?>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-outline-success dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
<i class="fas fa-flask me-1"></i>Toma de Muestras
|
||||
</button>
|
||||
<ul class="dropdown-menu shadow-sm">
|
||||
<?php foreach ($_dashMuestras as $_m): ?>
|
||||
<li><a class="dropdown-item" href="<?= BASE_URL ?>erp.php?m=turnero&v=lugar&lugar_id=<?= (int)$_m['id'] ?>">
|
||||
<i class="fas fa-vial me-1 text-success"></i><?= htmlspecialchars($_m['nombre'], ENT_QUOTES) ?>
|
||||
</a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Selector de fecha -->
|
||||
<div class="d-flex align-items-center gap-2 ms-auto">
|
||||
|
||||
@@ -150,8 +150,7 @@ $adminNombre = $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['
|
||||
}
|
||||
.pac-resultado:hover { background: #f1f5f9; }
|
||||
.pac-resultado .pac-nombre { font-weight: 600; font-size: .9rem; }
|
||||
.pac-resultado .pac-doc { font-size: .78rem; color: #64748b; display:flex; gap:10px; flex-wrap:wrap; margin-top:2px; }
|
||||
.pac-resultado .pac-doc span { display:flex; align-items:center; gap:4px; }
|
||||
.pac-resultado .pac-doc { font-size: .78rem; color: #64748b; }
|
||||
.pac-seleccionado {
|
||||
background: #eff6ff; border: 1px solid #93c5fd;
|
||||
border-radius: 8px; padding: .65rem .9rem;
|
||||
@@ -907,16 +906,12 @@ async function buscarPaciente() {
|
||||
<a href="#" onclick="abrirNuevoPaciente('${escHtml(q)}');return false">Crear nuevo</a></div>`;
|
||||
return;
|
||||
}
|
||||
lista.innerHTML = datos.map(function(p) {
|
||||
var doc = (p.tipo_documento||'') + (p.numero_documento ? ' ' + p.numero_documento : '');
|
||||
var tel = p.telefono || '';
|
||||
var docHtml = doc.trim() ? '<span><i class="fas fa-id-card"></i> ' + escHtml(doc) + '</span>' : '';
|
||||
var telHtml = tel ? '<span><i class="fas fa-phone"></i> ' + escHtml(tel) + '</span>' : '';
|
||||
return '<div class="pac-resultado" onclick="seleccionarPaciente(' + JSON.stringify(p).replace(/"/g,'"') + ')">'
|
||||
+ '<div class="pac-nombre">' + escHtml(p.nombre_completo||'Sin nombre') + '</div>'
|
||||
+ '<div class="pac-doc">' + docHtml + telHtml + '</div>'
|
||||
+ '</div>';
|
||||
}).join('');
|
||||
lista.innerHTML = datos.map(p => `
|
||||
<div class="pac-resultado" onclick="seleccionarPaciente(${JSON.stringify(p).replace(/"/g,'"')})">
|
||||
<div class="pac-nombre">${escHtml(p.nombre_completo||p.full_name||p.nombre||'')}</div>
|
||||
<div class="pac-doc">${escHtml(p.tipo_documento||'')} ${escHtml(p.documento||p.numero_documento||'')}
|
||||
${p.telefono||p.celular ? '· ' + escHtml(p.telefono||p.celular) : ''}</div>
|
||||
</div>`).join('');
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,16 @@ $_base = defined('APP_URL') ? rtrim(APP_URL, '/') : '';
|
||||
<ul class="sidebar-menu" id="sb-menu">
|
||||
|
||||
<?php
|
||||
// ── Paleta de colores por categoría ────────────────────────────────────────
|
||||
$_catPalette = [
|
||||
'lab' => '#60a5fa',
|
||||
'bot' => '#4ade80',
|
||||
'turnero' => '#fbbf24',
|
||||
'clinico' => '#c084fc',
|
||||
'formularios' => '#22d3ee',
|
||||
'sistema' => '#94a3b8',
|
||||
];
|
||||
|
||||
// ── Renderizado dinámico desde ModuleRegistry ───────────────────────────────
|
||||
if (class_exists('ModuleRegistry', false)) {
|
||||
$sidebarGroups = ModuleRegistry::forSidebar();
|
||||
@@ -155,10 +165,12 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
if ($__route && $_isActive($__route) !== '') { $_catHasActive = true; break; }
|
||||
}
|
||||
}
|
||||
$catId = 'sb-cat-' . htmlspecialchars($catKey, ENT_QUOTES, 'UTF-8');
|
||||
$catId = 'sb-cat-' . htmlspecialchars($catKey, ENT_QUOTES, 'UTF-8');
|
||||
$_catColor = $_catPalette[$catKey] ?? '#94a3b8';
|
||||
?>
|
||||
<li class="sidebar-section<?= $_catHasActive ? ' has-active' : '' ?>"
|
||||
data-cat="<?= $catId ?>"
|
||||
style="--cat-color:<?= $_catColor ?>"
|
||||
onclick="sbToggleCat('<?= $catId ?>',this,event)">
|
||||
<span class="sb-cat-label">
|
||||
<i class="<?= htmlspecialchars($catData['icon'], ENT_QUOTES, 'UTF-8') ?> me-1"></i>
|
||||
@@ -166,48 +178,20 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
</span>
|
||||
<i class="fas fa-chevron-down sb-chevron"></i>
|
||||
</li>
|
||||
<li class="sb-group" id="<?= $catId ?>">
|
||||
<li class="sb-group" id="<?= $catId ?>" style="--cat-color:<?= $_catColor ?>">
|
||||
<ul>
|
||||
<?php foreach ($catData['modules'] as $slug => $mod):
|
||||
$links = $mod['links'] ?? [];
|
||||
if (!empty($links)):
|
||||
foreach ($links as $lnkIdx => $lnk):
|
||||
$children = $lnk['children'] ?? [];
|
||||
if (!empty($children)):
|
||||
// Sub-acordeón para links con hijos
|
||||
$subId = $catId . '-sub-' . $slug . '-' . $lnkIdx;
|
||||
$hasActive = false;
|
||||
foreach ($children as $ch) { if ($_isActive($ch['route']) !== '') { $hasActive = true; break; } }
|
||||
?>
|
||||
<li class="sb-sub-header<?= $hasActive ? ' has-active' : '' ?>"
|
||||
onclick="sbToggleSub('<?= $subId ?>',this,event)">
|
||||
<i class="<?= htmlspecialchars($lnk['icon'], ENT_QUOTES, 'UTF-8') ?>"></i>
|
||||
<span><?= htmlspecialchars($lnk['name'], ENT_QUOTES, 'UTF-8') ?></span>
|
||||
<i class="fas fa-chevron-down sb-sub-chev"></i>
|
||||
</li>
|
||||
<li class="sb-sub-group<?= $hasActive ? '' : ' collapsed' ?>" id="<?= $subId ?>">
|
||||
<ul>
|
||||
<?php foreach ($children as $ch):
|
||||
$href = $_base . $ch['route'];
|
||||
$active = $_isActive($ch['route']);
|
||||
?>
|
||||
<li><a href="<?= htmlspecialchars($href, ENT_QUOTES, 'UTF-8') ?>"
|
||||
class="nav-link nav-link-sub<?= $active ?>">
|
||||
<i class="<?= htmlspecialchars($ch['icon'], ENT_QUOTES, 'UTF-8') ?>"></i>
|
||||
<?= htmlspecialchars($ch['name'], ENT_QUOTES, 'UTF-8') ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php else:
|
||||
$href = $_base . ($lnk['route'] ?? '');
|
||||
$active = isset($lnk['route']) ? $_isActive($lnk['route']) : '';
|
||||
foreach ($links as $lnk):
|
||||
$href = $_base . $lnk['route'];
|
||||
$active = $_isActive($lnk['route']);
|
||||
?>
|
||||
<li><a href="<?= htmlspecialchars($href, ENT_QUOTES, 'UTF-8') ?>"
|
||||
class="nav-link<?= $active ?>">
|
||||
<i class="<?= htmlspecialchars($lnk['icon'], ENT_QUOTES, 'UTF-8') ?>"></i>
|
||||
<?= htmlspecialchars($lnk['name'], ENT_QUOTES, 'UTF-8') ?></a></li>
|
||||
<?php endif;
|
||||
endforeach;
|
||||
<?php endforeach;
|
||||
else:
|
||||
$route = $mod['route'] ?? '';
|
||||
$href = $route ? $_base . $route : '#';
|
||||
@@ -382,25 +366,6 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
.sb-group { overflow: hidden; transition: max-height .28s ease, opacity .2s ease; }
|
||||
.sb-group > ul { list-style: none; padding: 0 0 4px; margin: 0; }
|
||||
.sb-group.collapsed { max-height: 0 !important; opacity: 0; pointer-events: none; }
|
||||
|
||||
/* Sub-acordeón dentro de un módulo */
|
||||
.sb-sub-header {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 7px 16px 7px 20px;
|
||||
cursor: pointer; user-select: none;
|
||||
color: rgba(255,255,255,.75);
|
||||
font-size: .84rem;
|
||||
border-radius: 6px; margin: 1px 6px;
|
||||
transition: background .15s, color .15s;
|
||||
}
|
||||
.sb-sub-header:hover, .sb-sub-header.has-active { color: #fff; background: rgba(255,255,255,.1); }
|
||||
.sb-sub-header span { flex: 1; }
|
||||
.sb-sub-chev { font-size: .6rem; opacity: .7; transition: transform .22s ease; flex-shrink: 0; }
|
||||
.sb-sub-header.collapsed .sb-sub-chev { transform: rotate(-90deg); }
|
||||
.sb-sub-group { overflow: hidden; transition: max-height .25s ease, opacity .2s ease; }
|
||||
.sb-sub-group > ul { list-style: none; padding: 0; margin: 0; }
|
||||
.sb-sub-group.collapsed { max-height: 0 !important; opacity: 0; pointer-events: none; }
|
||||
.nav-link-sub { padding-left: 36px !important; font-size: .82rem !important; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -427,28 +392,6 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
}
|
||||
}
|
||||
|
||||
window.sbToggleSub = function(subId, headerEl, ev) {
|
||||
if (ev) { ev.preventDefault(); ev.stopPropagation(); }
|
||||
var group = document.getElementById(subId);
|
||||
if (!group) return;
|
||||
var collapsed = group.classList.contains('collapsed');
|
||||
if (collapsed) {
|
||||
group.classList.remove('collapsed');
|
||||
group.style.maxHeight = group.scrollHeight + 'px';
|
||||
group.style.opacity = '1';
|
||||
headerEl.classList.remove('collapsed');
|
||||
} else {
|
||||
group.style.maxHeight = group.scrollHeight + 'px';
|
||||
group.style.opacity = '1';
|
||||
requestAnimationFrame(function(){
|
||||
group.classList.add('collapsed');
|
||||
headerEl.classList.add('collapsed');
|
||||
group.style.maxHeight = '0';
|
||||
group.style.opacity = '0';
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.sbToggleCat = function(catId, sectionEl, ev) {
|
||||
if (ev) { ev.preventDefault(); ev.stopPropagation(); }
|
||||
var nav = document.getElementById('erp-sidebar');
|
||||
@@ -535,14 +478,6 @@ if (class_exists('ModuleRegistry', false)) {
|
||||
style.textContent = '.sb-group { transition: none !important; }';
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Inicializar sub-grupos
|
||||
document.querySelectorAll('.sb-sub-group').forEach(function(sg) {
|
||||
if (!sg.classList.contains('collapsed')) {
|
||||
sg.style.maxHeight = sg.scrollHeight + 'px';
|
||||
sg.style.opacity = '1';
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.sb-group').forEach(function(group) {
|
||||
var catId = group.id;
|
||||
var section = document.querySelector('[data-cat="' + catId + '"]');
|
||||
|
||||
Reference in New Issue
Block a user