548 lines
18 KiB
PHP
548 lines
18 KiB
PHP
<?php
|
|
require __DIR__ . '/../config/app.php';
|
|
|
|
require __DIR__ . '/../config/app.php';
|
|
|
|
if (is_logged_in()) {
|
|
header('Location: ' . BASE_URL);
|
|
exit;
|
|
}
|
|
|
|
require __DIR__ . '/../partials/header.php';
|
|
?>
|
|
|
|
<link rel="stylesheet" href="../css/views/usuarios.css">
|
|
|
|
<div class="container mt-4">
|
|
|
|
<div class="row"> <!-- Grilla -->
|
|
<div class="col-12">
|
|
<div id="pantallaGrilla" class="card shadow-sm rounded-3 overflow-hidden"
|
|
data-aos="fade-up"
|
|
data-aos-duration="600"
|
|
data-aos-easing="ease-out-cubic"
|
|
data-aos-delay="60"
|
|
data-aos-once="false">
|
|
<div class="card-header bg-light text-body border-bottom">
|
|
<h5 class="text-primary fw-semibold mb-0">
|
|
<i class="bi bi-people me-2"></i> Usuarios
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div id="lstTabla"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> <!-- Grilla -->
|
|
|
|
<div class="row"> <!-- Formulario -->
|
|
<div class="col-12">
|
|
<div id="pantallaFormulario" class="card shadow-sm rounded-3 overflow-hidden d-none"
|
|
data-aos="fade-right"
|
|
data-aos-duration="650"
|
|
data-aos-easing="ease-out-cubic"
|
|
data-aos-delay="80"
|
|
data-aos-once="false">
|
|
<div class="card-header bg-light text-body border-bottom">
|
|
<h5 class="text-primary fw-semibold mb-0">
|
|
<i class="bi bi-person-fill-add me-2"></i> Nuevo Usuario
|
|
</h5>
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<form id="miFormulario" class="row needs-validation" novalidate>
|
|
<input type="hidden" id="iptId" name="id">
|
|
|
|
<!-- columna izquierda -->
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptNombre">
|
|
<span class="small">Nombre</span><span class="text-danger">*</span>
|
|
</label>
|
|
<input type="text" class="form-control form-control-sm" id="iptNombre" name="iptNombre"
|
|
placeholder="Ingrese el nombre" autocomplete="off" required>
|
|
<div class="invalid-feedback">Debe ingresar el nombre!</div>
|
|
</div>
|
|
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptDni">
|
|
<span class="small">DNI</span><span class="text-danger">*</span>
|
|
</label>
|
|
<input type="text" class="form-control form-control-sm" id="iptDni" name="iptDni"
|
|
placeholder="Ingrese el documento" autocomplete="off" required>
|
|
<div class="invalid-feedback">Debe ingresar el documento!</div>
|
|
</div>
|
|
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptId_rol">
|
|
<span class="small">Rol</span><span class="text-danger">*</span>
|
|
</label>
|
|
<select class="form-select form-select-sm" id="iptId_rol" name="iptId_rol" required></select>
|
|
<div class="invalid-feedback">Seleccione el rol</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- columna derecha -->
|
|
<div class="col-md-6">
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptUsuario">
|
|
<span class="small">Usuario</span><span class="text-danger">*</span>
|
|
</label>
|
|
<input type="text" class="form-control form-control-sm" id="iptUsuario" name="iptUsuario"
|
|
placeholder="Ingrese el usuario" autocomplete="off" required>
|
|
<div class="invalid-feedback">Debe ingresar el usuario!</div>
|
|
</div>
|
|
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptEmail">
|
|
<span class="small">Email</span><span class="text-danger">*</span>
|
|
</label>
|
|
<input type="text" class="form-control form-control-sm" id="iptEmail" name="iptEmail"
|
|
placeholder="Ingrese el correo" autocomplete="off" required>
|
|
<div class="invalid-feedback">Debe ingresar el correo!</div>
|
|
</div>
|
|
|
|
<div class="form-group mb-2">
|
|
<label class="col-form-label" for="iptId_habilitado">
|
|
<span class="small">¿Activo?</span><span class="text-danger">*</span>
|
|
</label>
|
|
<select class="form-select form-select-sm" id="iptId_habilitado" name="iptId_habilitado" required>
|
|
<option value="">--Seleccione si está activo--</option>
|
|
<option value="1">Si</option>
|
|
<option value="0">No</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<button type="submit" class="btn btn-success me-2" id="btnGuardar">
|
|
<i class="bi bi-save2-fill me-1"></i> Guardar
|
|
</button>
|
|
<button type="button" class="btn btn-secondary" id="btnCancelar">
|
|
<i class="bi bi-arrow-left-short me-1"></i> Cancelar
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div> <!-- Formulario -->
|
|
|
|
</div>
|
|
|
|
<?php
|
|
require __DIR__ . '/../partials/footer.php';
|
|
?>
|
|
|
|
<script src="../js/cargar_datos.js"></script>
|
|
<script src="../js/convertir_form.js"></script>
|
|
|
|
<script>
|
|
AOS.init({
|
|
duration: 600, // velocidad “cómoda”
|
|
easing: 'ease-out-cubic',
|
|
once: false,
|
|
offset: 0 // que no espere scroll extra
|
|
});
|
|
$.ajax({ // Solicitud ajax para cargar los roles
|
|
url: "../ajax/roles.ajax.php",
|
|
cache: false,
|
|
dataType: "json",
|
|
type: 'POST',
|
|
data: {
|
|
'accion': 'LOV'
|
|
},
|
|
success: function(respuesta) {
|
|
var options = '<option selected value="">--Seleccione el rol--</option>';
|
|
for (let i = 0; i < respuesta.length; i++) {
|
|
options = options + '<option value=' + respuesta[i][0] + '>' + respuesta[i][1] + '</option>';
|
|
}
|
|
$("#iptId_rol").append(options);
|
|
}
|
|
}); // Solicitud ajax para cargar los roles
|
|
|
|
function inicializarFormularioNuevoUsuario() {
|
|
$('#miFormulario')[0].reset();
|
|
$('#miFormulario').removeClass('was-validated');
|
|
$('#iptId').val('');
|
|
|
|
$('#pantallaFormulario h5')
|
|
.html('<i class="bi bi-people me-2"></i>Nuevo Usuario')
|
|
.removeClass('text-warning')
|
|
.addClass('text-success');
|
|
// $('#iptActivo').val('1');
|
|
// $('#iptEn_lista').val('1');
|
|
$('#iptId').hide();
|
|
}
|
|
|
|
document.getElementById("btnCancelar").addEventListener("click", function() {
|
|
cambiarVista('#pantallaGrilla', '#pantallaFormulario');
|
|
});
|
|
|
|
function cargarFormularioParaEditar(rowData) {
|
|
const $form = $('#miFormulario');
|
|
$form[0].reset();
|
|
$form.removeClass('was-validated');
|
|
|
|
var datos = new FormData();
|
|
datos.append("id", rowData.id);
|
|
datos.append("accion", "DATOS");
|
|
$.ajax({
|
|
url: "../ajax/usuarios.ajax.php",
|
|
type: "POST",
|
|
data: datos,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
dataType: 'json',
|
|
success: function(respuesta) {
|
|
const data = Array.isArray(respuesta) ? (respuesta[0] || {}) : (respuesta || {});
|
|
fillFormFromData($form, data);
|
|
// Ajusta encabezado
|
|
$('#pantallaFormulario h5')
|
|
.html('<i class="bi bi-people me-2"></i>Editar Usuario')
|
|
.removeClass('text-success')
|
|
.addClass('text-warning');
|
|
|
|
$('#iptId_usuario').show();
|
|
|
|
cambiarVista('#pantallaFormulario', '#pantallaGrilla');
|
|
}
|
|
});
|
|
}
|
|
|
|
function eliminarRegistro(rowData) {
|
|
Swal.fire({
|
|
icon: 'question',
|
|
title: '¿Está seguro?',
|
|
html: `Se eliminará el usuario <b>"${rowData.nombre}"</b>`,
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Sí, borrar',
|
|
cancelButtonText: 'Cancelar',
|
|
buttonsStyling: false, // importante para usar Bootstrap
|
|
customClass: {
|
|
popup: 'my-swal-popup',
|
|
actions: 'my-swal-actions',
|
|
confirmButton: 'btn btn-sm btn-outline-danger', // igual al botón borrar
|
|
cancelButton: 'btn btn-sm btn-outline-primary', // igual al botón editar/cancelar
|
|
icon: 'my-swal-icon'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const datos = new FormData();
|
|
datos.append('accion', 'BORRAR');
|
|
datos.append('id', rowData.id);
|
|
|
|
$.ajax({
|
|
url: "../ajax/usuarios.ajax.php",
|
|
method: 'POST',
|
|
data: datos,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
dataType: 'json',
|
|
success: function(respuesta) {
|
|
if (respuesta.respuesta === 'OK') {
|
|
Swal.fire({
|
|
toast: true,
|
|
position: 'top',
|
|
icon: 'success',
|
|
title: 'El registro fue eliminado',
|
|
showConfirmButton: false,
|
|
timer: 2500,
|
|
timerProgressBar: true
|
|
});
|
|
|
|
// Recargar grilla manteniendo estado
|
|
const estadoGrid = grid.getPersistData();
|
|
$.ajax({
|
|
url: "../ajax/usuarios.ajax.php",
|
|
method: 'POST',
|
|
data: {
|
|
accion: 'LISTAR'
|
|
},
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
grid.dataSource = data;
|
|
const estado = JSON.parse(estadoGrid);
|
|
if (estado.filterSettings) grid.filterSettings = estado.filterSettings;
|
|
if (estado.searchSettings) grid.searchSettings = estado.searchSettings;
|
|
}
|
|
});
|
|
} else {
|
|
Swal.fire('Error', respuesta.mensaje, 'error');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#lstTabla').on('click', '.btnEliminar', function() {
|
|
const row = $(this).closest('tr');
|
|
const rowData = grid.getRowObjectFromUID(row.attr('data-uid')).data;
|
|
eliminarRegistro(rowData);
|
|
});
|
|
|
|
$('#lstTabla').on('click', '.btnEditar', function() {
|
|
const row = $(this).closest('tr');
|
|
const rowData = grid.getRowObjectFromUID(row.attr('data-uid')).data;
|
|
cargarFormularioParaEditar(rowData);
|
|
});
|
|
|
|
document.getElementById("miFormulario").addEventListener("submit", function(e) {
|
|
e.preventDefault();
|
|
if (!this.checkValidity()) {
|
|
this.classList.add('was-validated');
|
|
return;
|
|
}
|
|
const datos = buildPayload(this);
|
|
|
|
$.ajax({
|
|
url: "../ajax/usuarios.ajax.php",
|
|
method: "POST",
|
|
data: datos,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
dataType: "json",
|
|
success: function(resultado) {
|
|
if (resultado.respuesta === "OK") {
|
|
const estadoGrid = grid.getPersistData(); // Guarda el estado
|
|
|
|
Swal.fire({
|
|
position: 'top', // Parte superior, centrado horizontal
|
|
icon: 'success',
|
|
title: 'El registro fue guardado',
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
toast: true, // sigue siendo un toast, pero en 'top' se centra
|
|
customClass: {
|
|
popup: 'swal2-toast swal2-top-center'
|
|
}
|
|
});
|
|
cambiarVista('#pantallaGrilla', '#pantallaFormulario');
|
|
|
|
// Recargar grilla manteniendo estado
|
|
$.ajax({
|
|
url: "../ajax/usuarios.ajax.php",
|
|
method: 'POST',
|
|
data: {
|
|
accion: 'LISTAR'
|
|
},
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
grid.dataSource = data;
|
|
const estado = JSON.parse(estadoGrid);
|
|
if (estado.filterSettings) grid.filterSettings = estado.filterSettings;
|
|
if (estado.searchSettings) grid.searchSettings = estado.searchSettings;
|
|
}
|
|
});
|
|
} else {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Error al guardar',
|
|
text: resultado.mensaje,
|
|
confirmButtonText: 'Aceptar',
|
|
customClass: {
|
|
confirmButton: 'btn btn-danger',
|
|
popup: 'rounded'
|
|
},
|
|
buttonsStyling: false
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
function cambiarVista(vistaMostrar, vistaOcultar) {
|
|
const $show = $(vistaMostrar).hasClass('card') ? $(vistaMostrar) : $(vistaMostrar).closest('.card');
|
|
const $hide = $(vistaOcultar).hasClass('card') ? $(vistaOcultar) : $(vistaOcultar).closest('.card');
|
|
|
|
// Elegir clase de salida según el efecto de AOS del que se va
|
|
const hideEffect = ($hide.attr('data-aos') || '').toLowerCase();
|
|
const exitClass =
|
|
hideEffect.includes('fade-right') ? 'aos-exit-right' : 'aos-exit-up'; // por defecto "up"
|
|
|
|
const exitMs = parseInt($hide.attr('data-aos-duration'), 10) || 600;
|
|
|
|
// 1) Animación de salida
|
|
$hide.addClass(exitClass).one('animationend', function() {
|
|
// 2) Tras salir, oculto y limpio
|
|
$hide.removeClass(exitClass + ' aos-animate').addClass('d-none');
|
|
|
|
// 3) Preparar y animar la entrada con AOS
|
|
$show.removeClass('d-none aos-animate');
|
|
(AOS.refreshHard || AOS.refresh).call(AOS);
|
|
requestAnimationFrame(() => $show.addClass('aos-animate'));
|
|
});
|
|
|
|
// Fallback por si el evento no dispara (raro, pero seguro)
|
|
setTimeout(() => {
|
|
if (!$hide.hasClass('d-none')) {
|
|
$hide.removeClass(exitClass + ' aos-animate').addClass('d-none');
|
|
$show.removeClass('d-none aos-animate');
|
|
(AOS.refreshHard || AOS.refresh).call(AOS);
|
|
requestAnimationFrame(() => $show.addClass('aos-animate'));
|
|
}
|
|
}, exitMs + 50);
|
|
}
|
|
|
|
|
|
let grid;
|
|
$.ajax({ // Solicitud ajax para cargar los usuarios en la grilla
|
|
url: '../ajax/usuarios.ajax.php',
|
|
method: 'POST',
|
|
data: {
|
|
accion: 'LISTAR'
|
|
},
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
ej.grids.Grid.Inject(ej.grids.Sort, ej.grids.Search, ej.grids.ColumnChooser, ej.grids.Filter, ej.grids.ExcelExport);
|
|
grid = new ej.grids.Grid({
|
|
id: 'lstTabla',
|
|
dataSource: data,
|
|
locale: 'es-ES',
|
|
allowPaging: true,
|
|
allowSorting: true,
|
|
allowFiltering: true,
|
|
allowExcelExport: true,
|
|
showColumnChooser: true,
|
|
filterSettings: {
|
|
type: 'Excel',
|
|
operators: {
|
|
stringOperator: [{
|
|
value: 'contains',
|
|
text: 'Contiene'
|
|
},
|
|
{
|
|
value: 'equal',
|
|
text: 'Igual'
|
|
},
|
|
{
|
|
value: 'startswith',
|
|
text: 'Empieza con'
|
|
},
|
|
{
|
|
value: 'endswith',
|
|
text: 'Termina con'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
toolbar: [
|
|
'Search',
|
|
{
|
|
text: '<i class="bi bi-layout-three-columns"></i> Columnas',
|
|
tooltipText: 'Mostrar/ocultar columnas',
|
|
id: 'btnColumnas'
|
|
},
|
|
{
|
|
text: '<i class="bi bi-person-fill-add"></i> Nuevo',
|
|
tooltipText: 'Crear nuevo usuario',
|
|
id: 'btnNuevo'
|
|
},
|
|
{
|
|
text: '<i class="bi bi-file-earmark-excel-fill"></i> Excel',
|
|
tooltipText: 'Exportar a Excel',
|
|
id: 'btnExcel'
|
|
}
|
|
],
|
|
toolbarClick: function(args) {
|
|
if (args.item.id === 'btnExcel') {
|
|
const hoy = new Date().toISOString().slice(0, 10);
|
|
grid.excelExport({
|
|
fileName: `usuarios_${hoy}.xlsx`
|
|
});
|
|
} else if (args.item.id === 'btnNuevo') {
|
|
inicializarFormularioNuevoUsuario();
|
|
cambiarVista('#pantallaFormulario', '#pantallaGrilla');
|
|
} else if (args.item.id === 'btnColumnas') {
|
|
grid.columnChooserModule.openColumnChooser(0, 0); // puedes ajustar posición x, y
|
|
}
|
|
},
|
|
disableHtmlEncode: true,
|
|
pageSettings: {
|
|
pageSize: 10
|
|
},
|
|
locale: 'es-ES',
|
|
columns: [{
|
|
headerText: '',
|
|
width: 100,
|
|
template: function() {
|
|
return `
|
|
<div class="text-center d-flex justify-content-center gap-2">
|
|
<button class="btn btn-sm btn-outline-primary btn-icon-sm btnEditar" title="Editar">
|
|
<i class="bi bi-pencil-fill"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-danger btn-icon-sm btnEliminar" title="Eliminar">
|
|
<i class="bi bi-trash-fill"></i>
|
|
</button>
|
|
</div>
|
|
`;
|
|
},
|
|
allowSorting: false
|
|
},
|
|
{
|
|
field: 'id',
|
|
headerText: '#',
|
|
width: 80
|
|
},
|
|
{
|
|
field: 'nombre',
|
|
headerText: 'Nombre',
|
|
width: 150,
|
|
clipMode: 'EllipsisWithTooltip'
|
|
},
|
|
{
|
|
field: 'usuario',
|
|
headerText: 'Usuario',
|
|
width: 120,
|
|
clipMode: 'EllipsisWithTooltip'
|
|
},
|
|
{
|
|
field: 'dni',
|
|
headerText: 'DNI',
|
|
width: 100
|
|
},
|
|
{
|
|
field: 'email',
|
|
headerText: 'Email',
|
|
width: 180,
|
|
clipMode: 'EllipsisWithTooltip'
|
|
},
|
|
{
|
|
field: 'rol',
|
|
headerText: 'Rol',
|
|
width: 100
|
|
},
|
|
{
|
|
field: 'activo',
|
|
headerText: '¿Activo?',
|
|
width: 100
|
|
}
|
|
],
|
|
});
|
|
grid.locale = 'es-ES';
|
|
grid.appendTo('#lstTabla');
|
|
|
|
$('#lstTabla').on('click', '.btnEditar', function() {
|
|
const row = $(this).closest('tr');
|
|
const rowData = grid.getRowObjectFromUID(row.attr('data-uid')).data;
|
|
|
|
// cargarFormularioParaEditar(rowData);
|
|
});
|
|
|
|
$('#lstTabla').on('click', '.btnEliminar', function() {
|
|
const row = $(this).closest('tr');
|
|
const rowData = grid.getRowObjectFromUID(row.attr('data-uid')).data;
|
|
});
|
|
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Error cargando datos:', error);
|
|
}
|
|
});
|
|
</script>
|