feat(export): UI unificada de Excel + PDF en los 4 módulos

- Nuevos assets compartidos /assets/donna-export.{css,js}: botón
  "Exportar ▾" + menú dropdown Excel/PDF y helpers DonnaExport.toExcel
  / .toPDF / .attach / .buttonHtml
- escrituras: refactor de exportExcel/exportPDF para usar el módulo
  compartido (sin cambio de comportamiento)
- tramites: nuevo botón en la toolbar de cada tab (adm/corp/mig/lit),
  exporta los rows filtrados de ese tab; PDF excluye Involucrados
- calendario: nuevo botón al final de la toolbar, exporta visibleEvents()
  (respeta chips de origen y búsqueda)
- horas: reemplaza CSV server-side por XLSX client-side + agrega PDF;
  removida la acción ?action=export del api.php
This commit is contained in:
Soporte ZH Consultores
2026-06-04 22:30:37 -05:00
parent 012c4e1c66
commit eff590af47
7 changed files with 377 additions and 236 deletions
+37 -15
View File
@@ -111,9 +111,6 @@ header{background:var(--navy);border-bottom:3px solid var(--gold);padding:0 24px
.but-n{font-size:9.5px;color:var(--gray-400);text-align:right;}
.but-empty{padding:14px 16px;font-size:11.5px;color:var(--gray-400);text-align:center;}
.btn-export{padding:8px 14px;background:#1e7e3e;color:#fff;border:none;border-radius:8px;font-size:13px;font-weight:500;display:inline-flex;align-items:center;gap:6px;}
.btn-export:hover{background:#15692f;}
.btn-export svg{width:14px;height:14px;}
.tbl-card{background:#fff;border:1px solid var(--gray-100);border-radius:10px;
overflow:hidden;box-shadow:var(--shadow);}
@@ -144,6 +141,7 @@ tr a.tramite-link:hover{color:var(--gold-d);text-decoration:underline;}
.toast.show{transform:translateY(0);opacity:1;}
.toast.error{border-left-color:#ef5350;}
</style>
<link rel="stylesheet" href="/assets/donna-export.css">
</head>
<body>
@@ -203,10 +201,7 @@ tr a.tramite-link:hover{color:var(--gold-d);text-decoration:underline;}
</div>
</div>
<div class="tb-spacer"></div>
<button class="btn-export" onclick="exportExcel()" title="Descargar CSV (compatible con Excel)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Exportar a Excel
</button>
<div id="export-mount"></div>
<button class="btn-primary" onclick="loadAll()">Aplicar</button>
</div>
@@ -243,6 +238,8 @@ tr a.tramite-link:hover{color:var(--gold-d);text-decoration:underline;}
<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 MY_EMAIL = (window.DONNA && window.DONNA.me) || '';
const MY_NAME = (window.DONNA && window.DONNA.name) || '';
@@ -450,15 +447,40 @@ function toggleByUser(safeName){
function openTramite(codigo){
window.location.href = '/tramites/?edit=' + encodeURIComponent(codigo);
}
function exportExcel(){
const params = new URLSearchParams({
action: 'export',
from: $('f-from').value || '',
to: $('f-to').value || '',
user: ($('f-user') && $('f-user').value) || '0',
});
window.location.href = '/horas/api.php?' + params.toString();
const HORAS_HEADERS = ['Fecha','Abogado','Departamento','Código','Trámite','Cliente','Estatus','Horas','Descripción'];
const HORAS_WIDTHS = [16,22,18,12,30,22,16,8,38];
const DEPT_LONG = { adm:'Administrativo', corp:'Corp · Com · Civil', mig:'Migración', lit:'Litigios' };
function horasExportRows(){
return (data && data.entries || []).map(e => [
(e.fecha || '').substring(0,16).replace('T',' '),
e.abogado || '',
DEPT_LONG[e.tramite_departamento] || e.tramite_departamento || '',
e.tramite_codigo || '',
e.tramite_title || '',
e.tramite_cliente || '',
e.tramite_estatus || '',
fmtHours(e.hrs),
e.descripcion || '',
]);
}
function exportExcel(){
DonnaExport.toExcel({
filename: 'Reporte_Horas_AALN', sheetName: 'Horas',
headers: HORAS_HEADERS, rows: horasExportRows(), columnWidths: HORAS_WIDTHS,
onEmpty: () => toast('No hay entradas para exportar','error'),
});
}
function exportPDF(){
DonnaExport.toPDF({
filename: 'Reporte_Horas_AALN',
title: 'Reporte de Horas',
headers: HORAS_HEADERS, rows: horasExportRows(),
pdfCols: [0,1,3,4,5,7,8], // Fecha, Abogado, Código, Trámite, Cliente, Horas, Descripción
onEmpty: () => toast('No hay entradas para exportar','error'),
});
}
document.getElementById('export-mount').innerHTML = DonnaExport.buttonHtml();
DonnaExport.attach('export-wrap', { onExcel: exportExcel, onPDF: exportPDF });
['f-from','f-to'].forEach(id => {
$(id).addEventListener('change', loadAll);