Módulo de bitácoras y bitácora de accesos

This commit is contained in:
2025-05-22 15:36:03 -06:00
parent ffcf1e51f4
commit c294c859fc
9 changed files with 224 additions and 40 deletions

View File

@@ -4,20 +4,36 @@ require_once __DIR__ . '/../helpers/crypto.php';
session_start();
function login()
function index()
{
if (!isset($_SESSION['usuario_id'])) {
die("⚠️ No autorizado.");
include __DIR__ . '/../../views/bitacoras/dashboard_bitacoras.php';
}
function lista()
{
if (!($_SESSION['usuario_id'] ?? false)) {
header('Location: /IMPORTADORES/login');
exit;
}
$conn = getConnection();
$sql = "SELECT id, id_usuario, email, ip, fecha, exito, detalle FROM bitacora_login ORDER BY fecha DESC";
$stmt = sqlsrv_query($conn, $sql);
$sql = "
SELECT u.id_usuario, u.nombre, b.id, b.email, b.ip, b.fecha, b.exito, b.detalle
FROM dbo.bitacora_login b
JOIN dbo.usuarios_sistema u ON u.id_usuario = b.id_usuario
ORDER BY b.id DESC
";
$logins = [];
$stmt = sqlsrv_query($conn, $sql);
if ($stmt === false) {
die("Error en lista(): " . print_r(sqlsrv_errors(), true));
}
$bitacoras = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$logins[] = $row;
$row['nombre'] = decrypt($row['nombre']); // Desencripta aquí
$bitacoras[] = $row;
}
include __DIR__ . '/../../views/bitacoras/bitacora_login.php';

View File

@@ -108,8 +108,3 @@ function seguridad()
{
include __DIR__ . '/../../views/configuracion/seguridad.php';
}
function bitacoras()
{
include __DIR__ . '/../../views/configuracion/bitacoras.php';
}

View File

@@ -0,0 +1,136 @@
<?php
include __DIR__ . '/../partials/sidebar_configuracion.php';
if ($_GET['view'] === 'bitacoras') {
lista();
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Configuración</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<style>
body {
font-family: 'Segoe UI', sans-serif;
background-color: #f4f6f9;
}
.sidebar {
width: 220px;
height: 100vh;
background-color: #343a40;
position: fixed;
top: 0;
left: 0;
padding-top: 56px; /* Alineado con la altura de la navbar */
z-index: 1040; /* Asegura que esté por encima del contenido */
}
.sidebar .nav-link {
font-weight: bold;
color: white;
transition: all 0.3s ease;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
background-color: #495057;
color: #fff;
}
.content {
margin-top: 56px; /* Ajusta debajo de navbar */
padding: 40px 20px;
position: relative;
z-index: 1;
background-color: #f4f6f9; /* Asegura fondo uniforme */
transition: margin-left 0.3s ease;
}
.navbar {
position: fixed;
top: 0;
width: 100%;
z-index: 1050;
}
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) {
.content {
margin-left: 250px; /* Ancho del sidebar */
}
}
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content {
margin-left: 0;
}
.sidebar .nav-link {
font-weight: normal;
color: #343a40;
background-color: transparent;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
background-color: #e9ecef;
color: #212529;
}
}
.card { border-radius: 12px; }
table.dataTable thead th { background: #343a40; color: #fff; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4">👥 Acceso de Usuarios</h4>
<div class="card p-3 shadow-sm">
<div class="table-responsive">
<table class="table table-striped" id="tabla-logins">
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Correo</th>
<th>IP</th>
<th>Fecha</th>
<th>Estatus</th>
<th>Detalles</th>
</tr>
</thead>
<tbody>
<?php foreach ($bitacoras as $b): ?>
<tr>
<td><?= htmlspecialchars($b['id_usuario']) ?></td>
<td><?= htmlspecialchars($b['nombre']) ?></td>
<td><?= htmlspecialchars($b['email']) ?></td>
<td><?= htmlspecialchars($b['ip']) ?></td>
<td><?= $b['fecha']->format('Y-m-d H:i:s') ?></td>
<td>
<?= $b['exito'] == 1 ? 'Éxito' : 'Fallido' ?>
</td>
<td><?= htmlspecialchars($b['detalle']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#tabla-logins').DataTable({
language: {
url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
}
});
});
</script>
</body>
</html>

View File

@@ -78,9 +78,23 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
</head>
<body>
<div class="content">
<div class="content">
<h4 class="mb-4">📖 Bitácoras</h4>
<div class="row g-4">
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-primary">Registro de Accesos</h5>
<p>Ver actividad de los usuarios.</p>
<a href="/IMPORTADORES/bitacoras/lista"
class="btn btn-primary btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/lista' ? 'active' : '' ?>">
Ver Accesos
</a>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -13,7 +13,6 @@
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<style>
table.dataTable thead th { background: #343a40; color: #fff; }
body {

View File

@@ -82,7 +82,6 @@ include __DIR__ . '/../partials/sidebar_importador.php';
<body>
<div class="content">
<br><br>
<h4 class="mb-4">📦 Panel del Importador</h4>
<div class="row g-4">

View File

@@ -43,9 +43,9 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
</button>
<span class="navbar-brand">SIIH | Configuración</span>
<div class="d-none d-md-flex">
<a href="/IMPORTADORES/importadores/dashboard" class="btn btn-outline-light btn-sm">
<- Volver al Panel Principal
<div class="d-flex ms-auto">
<a href="/IMPORTADORES/importadores/dashboard" class="btn btn-outline-light btn-sm" style="margin: 0 0 0 25px;">
Panel Principal
</a>
</div>
</div>
@@ -80,22 +80,42 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
</a>
<!-- BITÁCORAS -->
<a href="/IMPORTADORES/configuracion/bitacoras"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion/bitacoras') ? 'active' : '' ?>">
📖 Bitácoras
</a>
<?php
// Detecta si estamos en alguna ruta de bitácoras
$esVistaBitacoras = str_contains($_SERVER['REQUEST_URI'], '/bitacoras');
// Detecta si estamos en alguna parte de configuración
$esConfiguracion = str_contains($_SERVER['REQUEST_URI'], '/configuracion');
?>
<?php if ($esVistaBitacoras): ?>
<!-- Estamos en cualquier página relacionada a bitácoras -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaBitacoras ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuBitacoras" role="button" aria-expanded="true" aria-controls="submenuBitacoras">
📖 Bitácoras
<span class="badge bg-secondary">1</span>
</a>
<div class="collapse show" id="submenuBitacoras">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/bitacoras/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/lista' ? 'active' : '' ?>">
• Registro de Accesos
</a>
</nav>
</div>
<?php elseif ($esConfiguracion): ?>
<!-- Si estamos en configuración, pero no en bitácoras -->
<a href="/IMPORTADORES/bitacoras/index"
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
📖 Bitácoras
<span class="badge bg-secondary">1</span>
</a>
<?php endif; ?>
</nav>
</div>
<!-- OFFCANVAS PARA MÓVILES -->
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 56px;">
<div class="offcanvas-body">
<!-- INFORMACIÓN GENERAL -->
<!-- INFORMACIÓN GENERAL -->
<a href="/IMPORTADORES/configuracion/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion/dashboard_configuracion') ? 'active' : '' ?>">

View File

@@ -43,9 +43,16 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
</button>
<span class="navbar-brand">SIIH | Importador</span>
<div class="d-none d-md-flex text-white">
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2">Cerrar sesión</a>
<div class="d-flex ms-auto text-white">
<?php
// Verifica si estás en el dashboard principal del importador
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/importadores/dashboard');
if ($esDashboard): ?>
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
<?php else: ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
<?php endif; ?>
</div>
</div>
</nav>
@@ -132,7 +139,7 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuProveedores" role="button" aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'true' : 'false' ?>"
aria-controls="submenuProveedores">
🏭 Proveedores
🏭 Proveedores
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'show' : '' ?>" id="submenuProveedores">
@@ -166,7 +173,7 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
</nav>
</div>
<!-- EXPEDIENTE ELECTRÓNICO -->
<!-- EXPEDIENTE ELECTRÓNICO -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
<?= str_contains($_SERVER['REQUEST_URI'], '/expediente') ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuExpediente" role="button" aria-expanded="false">
@@ -195,7 +202,7 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
</div>
<!-- OFFCANVAS PARA MÓVILES -->
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu">
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 75px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
@@ -279,7 +286,7 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuProveedores" role="button" aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'true' : 'false' ?>"
aria-controls="submenuProveedores">
🏭 Proveedores
🏭 Proveedores
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'show' : '' ?>" id="submenuProveedores">

View File

@@ -119,7 +119,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
$(function(){
$('#transportistas-table').DataTable({
@@ -184,6 +183,5 @@
</script>
</body>
</html>