Update lab_formularios.php

This commit is contained in:
Lizandro Guarnizo
2026-04-07 14:57:00 -05:00
parent 8e89775e9e
commit 61728b6ee2
+138 -12
View File
@@ -118,23 +118,47 @@ $puedeEscribir = $esAdmin && hasModuleWrite('lab_formularios');
<!-- ── ENVÍOS ─────────────────────────────────────────────── -->
<div id="panel-envios" style="display:none">
<!-- Filtros -->
<div class="row g-2 mb-3 align-items-end">
<div class="col-sm-3">
<!-- Filtros fila 1 -->
<div class="row g-2 mb-2 align-items-end">
<div class="col-sm-2">
<label class="form-label small mb-1">Desde</label>
<input type="date" id="env-f-desde" class="form-control form-control-sm" oninput="envios.filtrar()">
</div>
<div class="col-sm-3">
<div class="col-sm-2">
<label class="form-label small mb-1">Hasta</label>
<input type="date" id="env-f-hasta" class="form-control form-control-sm" oninput="envios.filtrar()">
</div>
<div class="col-sm-4">
<label class="form-label small mb-1">Formulario</label>
<select id="env-f-formulario" class="form-select form-select-sm" onchange="envios.filtrar()">
<option value="">Todos los formularios</option>
</select>
</div>
<div class="col-sm-2">
<label class="form-label small mb-1">Estado</label>
<select id="env-f-estado" class="form-select form-select-sm" onchange="envios.filtrar()">
<option value="">Todos los estados</option>
<option value="pendiente">🕐 Pendiente</option>
<option value="completado">✅ Completado</option>
<option value="firmado">✍️ Firmado</option>
<option value="expirado">⏰ Expirado</option>
</select>
</div>
</div>
<!-- Filtros fila 2 -->
<div class="row g-2 mb-3 align-items-end">
<div class="col-sm-4">
<label class="form-label small mb-1">Paciente</label>
<input type="text" id="env-f-paciente" class="form-control form-control-sm"
placeholder="Buscar paciente…" oninput="envios.filtrar()">
</div>
<div class="col-sm-2">
<button class="btn btn-outline-secondary btn-sm w-100" onclick="envios.limpiarFiltros()">
<div class="col-sm-auto ms-auto">
<button class="btn btn-success btn-sm" onclick="envios.exportarExcel()">
<i class="fas fa-file-excel me-1"></i>Exportar Excel
</button>
</div>
<div class="col-sm-auto">
<button class="btn btn-outline-secondary btn-sm" onclick="envios.limpiarFiltros()">
<i class="fas fa-times me-1"></i>Limpiar
</button>
</div>
@@ -484,6 +508,7 @@ const envios = {
const d = await r.json();
this._data = d.data || [];
this._pagina = 1;
this._poblarSelectFormulario();
this._aplicarFiltros();
},
@@ -493,22 +518,46 @@ const envios = {
},
limpiarFiltros() {
$('env-f-desde').value = '';
$('env-f-hasta').value = '';
$('env-f-paciente').value = '';
$('env-f-desde').value = '';
$('env-f-hasta').value = '';
$('env-f-paciente').value = '';
$('env-f-formulario').value = '';
$('env-f-estado').value = '';
this.filtrar();
},
_poblarSelectFormulario() {
const sel = $('env-f-formulario');
if (!sel) return;
const valorActual = sel.value;
sel.innerHTML = '<option value="">Todos los formularios</option>';
const vistos = new Set();
this._data.forEach(e => {
if (e.formulario_id && !vistos.has(e.formulario_id)) {
vistos.add(e.formulario_id);
const opt = document.createElement('option');
opt.value = e.formulario_id;
opt.textContent = e.form_nombre || ('Formulario #' + e.formulario_id);
sel.appendChild(opt);
}
});
if (valorActual) sel.value = valorActual;
},
_aplicarFiltros() {
const desde = $('env-f-desde').value;
const hasta = $('env-f-hasta').value;
const paciente = $('env-f-paciente').value.trim().toLowerCase();
const desde = $('env-f-desde').value;
const hasta = $('env-f-hasta').value;
const paciente = $('env-f-paciente').value.trim().toLowerCase();
const formId = $('env-f-formulario').value;
const estadoFilt = $('env-f-estado').value;
this._filtrado = this._data.filter(e => {
const fecha = (e.created_at || '').slice(0, 10);
if (desde && fecha < desde) return false;
if (hasta && fecha > hasta) return false;
if (paciente && !(e.paciente_nombre || '').toLowerCase().includes(paciente)) return false;
if (formId && String(e.formulario_id) !== String(formId)) return false;
if (estadoFilt && e.estado !== estadoFilt) return false;
return true;
});
@@ -521,6 +570,83 @@ const envios = {
this._render();
},
exportarExcel() {
const rows = this._filtrado;
if (!rows.length) { showToast('Sin datos para exportar'); return; }
// Columnas fijas
const fixedCols = ['Formulario','Categoría','Paciente','Estado','Fecha envío','Fecha completado'];
// Recolectar todas las columnas dinámicas (campos del esquema) en orden de aparición
const fieldMap = new Map(); // label → id (primer visto)
rows.forEach(e => {
try {
const esquema = JSON.parse(e.esquema || '[]');
esquema.forEach(c => {
if (!['separador','firma','firma_profesional','parrafo',
'parrafo_inline','lista_marcable'].includes(c.tipo)
&& c.id && c.label && !fieldMap.has(c.label)) {
fieldMap.set(c.label, c.id);
}
});
} catch(_) {}
});
const fieldCols = [...fieldMap.entries()]; // [[label, id], ...]
const allCols = [...fixedCols, ...fieldCols.map(([l]) => l)];
const csvRows = [allCols];
rows.forEach(e => {
let cliente = {}, prefill = {};
try { cliente = JSON.parse(e.datos_cliente || '{}'); } catch(_) {}
try { prefill = JSON.parse(e.datos_prefilled || '{}'); } catch(_) {}
const todos = { ...prefill, ...cliente };
// Para este envío construir mapa label → id
const labelToId = new Map();
try {
JSON.parse(e.esquema || '[]').forEach(c => {
if (c.id && c.label) labelToId.set(c.label, c.id);
});
} catch(_) {}
const fixed = [
e.form_nombre || '',
e.categoria || '',
e.paciente_nombre || '',
e.estado || '',
(e.created_at || '').slice(0, 16).replace('T', ' '),
(e.completado_en || '').slice(0, 16).replace('T', ' '),
];
const campos = fieldCols.map(([label, defaultId]) => {
const id = labelToId.get(label) || defaultId;
const val = todos[id];
if (val === undefined || val === null) return '';
return Array.isArray(val) ? val.join('; ') : String(val);
});
csvRows.push([...fixed, ...campos]);
});
// Generar CSV con BOM UTF-8 para Excel
const csv = '\uFEFF' + csvRows.map(row =>
row.map(v => '"' + String(v).replace(/"/g, '""') + '"').join(',')
).join('\r\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'envios_formularios_' + new Date().toISOString().slice(0, 10) + '.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showToast('✅ Exportando ' + rows.length + ' envíos…');
},
_render() {
const tb = $('tbody-envios');
const total = this._filtrado.length;