diff --git a/src/layout/melissa/MelissaRelatorios.vue b/src/layout/melissa/MelissaRelatorios.vue index 13ec3c6..b137e3f 100644 --- a/src/layout/melissa/MelissaRelatorios.vue +++ b/src/layout/melissa/MelissaRelatorios.vue @@ -12,12 +12,15 @@ * isoWeek/isoMonth + Chart.js). */ import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'; +import { useToast } from 'primevue/usetoast'; import { supabase } from '@/lib/supabase/client'; import { useTenantStore } from '@/stores/tenantStore'; +import { exportSessionsToPDF, exportSessionsToXLSX, exportSessionsToCSV } from '@/services/reportExport.service'; // Chart/DataTable/Column/Tag/Skeleton: auto via PrimeVueResolver const emit = defineEmits(['close']); const tenantStore = useTenantStore(); +const toast = useToast(); // ── Breakpoints + drawer mobile ──────────────────────── const drawerOpen = ref(false); @@ -251,6 +254,66 @@ function patientName(s) { return s.patients?.nome_completo || '—'; } +// ── Export PDF / Excel / CSV ────────────────────────── +const exportingPdf = ref(false); +const exportingXlsx = ref(false); + +function buildExportParams() { + const period = PERIOD_OPTIONS.find(p => p.key === selectedPeriod.value)?.label || ''; + const normalized = sessionsFiltradas.value.map(s => ({ + ...s, + paciente_nome: s.patients?.nome_completo || '—' + })); + return { + title: 'Relatório de Sessões', + subtitle: period, + sessions: normalized, + kpis: [ + { label: 'Total', value: total.value }, + { label: 'Realizadas', value: realizadas.value }, + { label: 'Faltas', value: faltas.value }, + { label: 'Canceladas', value: canceladas.value } + ], + tenantName: tenantStore.activeTenantName || tenantStore.tenant?.name || '', + terapeutaNome: tenantStore.user?.full_name || tenantStore.user?.email || '' + }; +} + +async function exportPdf() { + if (exportingPdf.value) return; + exportingPdf.value = true; + try { + const file = await exportSessionsToPDF(buildExportParams()); + toast.add({ severity: 'success', summary: 'PDF gerado', detail: file, life: 2500 }); + } catch (e) { + toast.add({ severity: 'error', summary: 'Erro ao gerar PDF', detail: e?.message || '', life: 4500 }); + } finally { + exportingPdf.value = false; + } +} + +async function exportXlsx() { + if (exportingXlsx.value) return; + exportingXlsx.value = true; + try { + const file = await exportSessionsToXLSX(buildExportParams()); + toast.add({ severity: 'success', summary: 'Excel gerado', detail: file, life: 2500 }); + } catch (e) { + toast.add({ severity: 'error', summary: 'Erro ao gerar Excel', detail: e?.message || '', life: 4500 }); + } finally { + exportingXlsx.value = false; + } +} + +function exportCsv() { + try { + const file = exportSessionsToCSV(buildExportParams()); + toast.add({ severity: 'success', summary: 'CSV gerado', detail: file, life: 2500 }); + } catch (e) { + toast.add({ severity: 'error', summary: 'Erro ao gerar CSV', detail: e?.message || '', life: 4500 }); + } +} + watch(selectedPeriod, () => { statusFilter.value = null; loadSessions(); @@ -308,6 +371,30 @@ onBeforeUnmount(() => { {{ periodLabel }}
+ + +