feat(export): botón Exportar (Excel + PDF) en Usuarios y Registro de Transacciones
- Usuarios y permisos: exporta los rows visibles (respeta filtros de rol, activos y búsqueda). Columnas: Email, Nombre, Rol, Activo, Último login - Registro de transacciones: exporta las entradas cargadas en pantalla (respeta filtros de fecha/usuario/módulo/acción/texto). Excel incluye Email e IP; el PDF los omite para que quepa - Mismo módulo compartido DonnaExport — UI idéntica a los otros módulos
This commit is contained in:
@@ -170,6 +170,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
border-radius:6px; color:var(--gray-700); transition:all .15s; }
|
||||
.tb-quick-log:hover { background:var(--navy); color:#fff; border-color:var(--navy); }
|
||||
</style>
|
||||
<link rel="stylesheet" href="/assets/donna-export.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -223,6 +224,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
<option value="0">Solo inactivos</option>
|
||||
</select>
|
||||
<button class="btn-primary" onclick="openCreate()">+ Nuevo usuario</button>
|
||||
<div id="export-mount-users"></div>
|
||||
</div>
|
||||
|
||||
<div class="tbl-card">
|
||||
@@ -285,6 +287,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
<button class="tb-quick-log" onclick="setLogQuick('month')">Mes</button>
|
||||
<button class="tb-quick-log" onclick="setLogQuick('all')">Todo</button>
|
||||
<button class="btn-primary" onclick="loadLog()" style="padding:7px 14px;">Aplicar</button>
|
||||
<div id="export-mount-log"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -354,6 +357,8 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
||||
<script src="/assets/donna-export.js"></script>
|
||||
<script>
|
||||
const ROLES = ['admin','socio','abogado','usuario'];
|
||||
const ROLE_LABEL = { admin:'Admin', socio:'Socio', abogado:'Abogado', usuario:'Usuario' };
|
||||
@@ -644,7 +649,9 @@ function populateLogDropdowns(d){
|
||||
(d.acciones||[]).map(a => `<option value="${esc(a)}">${esc(ACCION_LABEL[a] || a)}</option>`).join('');
|
||||
aSel.value = aPrev;
|
||||
}
|
||||
let lastLogEntries = [];
|
||||
function renderLog(entries){
|
||||
lastLogEntries = entries || [];
|
||||
const tbody = $('log-tbody');
|
||||
const empty = $('log-empty');
|
||||
const info = $('log-rowinfo');
|
||||
@@ -677,6 +684,71 @@ $('log-search').addEventListener('input', () => {
|
||||
window._logSearchTimer = setTimeout(loadLog, 350);
|
||||
});
|
||||
|
||||
// ── EXPORT (Usuarios) ────────────────────────────────────────────────────
|
||||
const USERS_HEADERS = ['Email','Nombre completo','Rol','Activo','Último login'];
|
||||
function usersExportRows(){
|
||||
return visibleUsers().map(u => [
|
||||
u.email,
|
||||
u.name || '',
|
||||
ROLE_LABEL[u.role] || u.role,
|
||||
u.activo ? 'Sí' : 'No',
|
||||
u.last_login_at ? fmtDate(u.last_login_at) : 'Nunca',
|
||||
]);
|
||||
}
|
||||
function usersExportExcel(){
|
||||
DonnaExport.toExcel({
|
||||
filename: 'Usuarios_Donna_AALN', sheetName: 'Usuarios',
|
||||
headers: USERS_HEADERS, rows: usersExportRows(),
|
||||
columnWidths: [32,28,12,10,20],
|
||||
onEmpty: () => toast('Sin usuarios para exportar','error'),
|
||||
});
|
||||
}
|
||||
function usersExportPDF(){
|
||||
DonnaExport.toPDF({
|
||||
filename: 'Usuarios_Donna_AALN',
|
||||
title: 'Usuarios y permisos',
|
||||
orientation: 'portrait',
|
||||
headers: USERS_HEADERS, rows: usersExportRows(),
|
||||
onEmpty: () => toast('Sin usuarios para exportar','error'),
|
||||
});
|
||||
}
|
||||
document.getElementById('export-mount-users').innerHTML = DonnaExport.buttonHtml('export-wrap-users');
|
||||
DonnaExport.attach('export-wrap-users', { onExcel: usersExportExcel, onPDF: usersExportPDF });
|
||||
|
||||
// ── EXPORT (Registro de transacciones) ───────────────────────────────────
|
||||
const LOG_HEADERS = ['Fecha · Hora','Usuario','Email','Módulo','Acción','Entidad','Detalles','IP'];
|
||||
function logExportRows(){
|
||||
return (lastLogEntries||[]).map(e => [
|
||||
fmtLogDate(e.fecha),
|
||||
e.user_name || '',
|
||||
e.user_email || '',
|
||||
MOD_LABEL[e.modulo] || e.modulo,
|
||||
ACCION_LABEL[e.accion] || e.accion,
|
||||
(e.entity_label || '') + (e.entity_type ? ' ('+e.entity_type+')' : ''),
|
||||
e.detalles || '',
|
||||
e.ip_addr || '',
|
||||
]);
|
||||
}
|
||||
function logExportExcel(){
|
||||
DonnaExport.toExcel({
|
||||
filename: 'Registro_Transacciones_AALN', sheetName: 'Auditoría',
|
||||
headers: LOG_HEADERS, rows: logExportRows(),
|
||||
columnWidths: [18,22,28,14,18,28,50,14],
|
||||
onEmpty: () => toast('No hay transacciones para exportar — aplica filtros primero','error'),
|
||||
});
|
||||
}
|
||||
function logExportPDF(){
|
||||
DonnaExport.toPDF({
|
||||
filename: 'Registro_Transacciones_AALN',
|
||||
title: 'Registro de Transacciones',
|
||||
headers: LOG_HEADERS, rows: logExportRows(),
|
||||
pdfCols: [0,1,3,4,5,6], // omite Email e IP para que quepa
|
||||
onEmpty: () => toast('No hay transacciones para exportar — aplica filtros primero','error'),
|
||||
});
|
||||
}
|
||||
document.getElementById('export-mount-log').innerHTML = DonnaExport.buttonHtml('export-wrap-log');
|
||||
DonnaExport.attach('export-wrap-log', { onExcel: logExportExcel, onPDF: logExportPDF });
|
||||
|
||||
loadUsers();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user