fix: correção da exportação dos dados sintéticos

This commit is contained in:
Alessandro Gonçaalves 2025-10-22 14:19:16 -03:00
parent beeedbff69
commit a5ce93042c
1 changed files with 307 additions and 1 deletions

View File

@ -1,12 +1,13 @@
"use client";
import { LoaderPinwheel, ChevronDown, ChevronRight, Filter, Maximize2, Minimize2 } from "lucide-react";
import { LoaderPinwheel, ChevronDown, ChevronRight, Filter, Maximize2, Minimize2, Download } from "lucide-react";
import { useEffect, useState, useCallback, startTransition, memo } from "react";
import AnaliticoComponent from "./analitico";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import * as XLSX from "xlsx";
import {
Sheet,
SheetContent,
@ -498,6 +499,299 @@ export default function Teste() {
setContasSelecionadas([]);
};
const exportarXLSX = () => {
if (!data.length) {
console.log('⚠️ Nenhum dado para exportar');
return;
}
console.log('📊 Exportando TODOS os dados expandidos para XLSX...');
// Criar uma versão completamente expandida dos dados hierárquicos
const dadosCompletosExpandidos = buildHierarchicalDataCompleta();
// Preparar dados para exportação
const dadosExportacao = dadosCompletosExpandidos.map((row, index) => {
const linha: any = {
'Linha': index + 1,
'Tipo': row.type,
'Nível': row.level,
'Grupo': row.grupo || '',
'Centro de Custo': row.centro_custo || '',
'Conta': row.conta || '',
'Código Centro': row.codigo_centro_custo || '',
'Código Conta': row.codigo_conta || '',
'Total': row.total || 0,
};
// Adicionar colunas dos meses
mesesDisponiveis.forEach(mes => {
const valor = row.valoresPorMes?.[mes] || 0;
const percentual = row.percentuaisPorMes?.[mes] || 0;
linha[`Valor ${mes}`] = valor;
linha[`% ${mes}`] = percentual;
});
return linha;
});
// Criar workbook
const wb = XLSX.utils.book_new();
// Criar worksheet principal
const ws = XLSX.utils.json_to_sheet(dadosExportacao);
// Ajustar largura das colunas
const colWidths = [
{ wch: 8 }, // Linha
{ wch: 15 }, // Tipo
{ wch: 8 }, // Nível
{ wch: 30 }, // Grupo
{ wch: 25 }, // Centro de Custo
{ wch: 35 }, // Conta
{ wch: 15 }, // Código Centro
{ wch: 12 }, // Código Conta
{ wch: 15 }, // Total
];
// Adicionar larguras para colunas dos meses
mesesDisponiveis.forEach(() => {
colWidths.push({ wch: 15 }); // Valor
colWidths.push({ wch: 10 }); // %
});
ws['!cols'] = colWidths;
// Adicionar worksheet ao workbook
XLSX.utils.book_append_sheet(wb, ws, 'DRE Gerencial Completo');
// Criar worksheet de resumo
const resumoData = [
{ 'Informação': 'Período', 'Valor': `${filtros.periodoDe} a ${filtros.periodoAte}` },
{ 'Informação': 'Grupo', 'Valor': filtros.grupo },
{ 'Informação': 'Subgrupo', 'Valor': filtros.subgrupo },
{ 'Informação': 'Centro de Custo', 'Valor': filtros.centroCusto },
{ 'Informação': 'Conta', 'Valor': filtros.conta },
{ 'Informação': 'Valor Mínimo', 'Valor': filtros.valorMin || 'N/A' },
{ 'Informação': 'Valor Máximo', 'Valor': filtros.valorMax || 'N/A' },
{ 'Informação': 'Busca Textual', 'Valor': filtros.buscaTextual || 'N/A' },
{ 'Informação': 'Ordem Hierárquica', 'Valor': ordemHierarquiaContasPrimeiro ? 'Contas → Centros' : 'Centros → Contas' },
{ 'Informação': 'Total de Registros', 'Valor': dadosCompletosExpandidos.length },
{ 'Informação': 'Data de Exportação', 'Valor': new Date().toLocaleString('pt-BR') },
];
const wsResumo = XLSX.utils.json_to_sheet(resumoData);
wsResumo['!cols'] = [{ wch: 20 }, { wch: 30 }];
XLSX.utils.book_append_sheet(wb, wsResumo, 'Resumo');
// Gerar nome do arquivo
const dataAtual = new Date().toISOString().split('T')[0];
const nomeArquivo = `DRE_Gerencial_Completo_${dataAtual}.xlsx`;
// Exportar arquivo
XLSX.writeFile(wb, nomeArquivo);
console.log('✅ Arquivo XLSX completo exportado:', nomeArquivo);
};
// Função para construir dados hierárquicos completamente expandidos
const buildHierarchicalDataCompleta = (): HierarchicalRow[] => {
const rows: HierarchicalRow[] = [];
// Agrupar dados por grupo
const grupos = data.reduce((acc, item) => {
if (!acc[item.grupo]) {
acc[item.grupo] = [];
}
acc[item.grupo].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar grupos por código
const sortedGrupos = Object.entries(grupos).sort(([grupoA, itemsA], [grupoB, itemsB]) => {
const codigoA = itemsA[0]?.codgrupo || "";
const codigoB = itemsB[0]?.codgrupo || "";
return codigoA.localeCompare(codigoB);
});
sortedGrupos.forEach(([grupo, items]) => {
const totalGrupo = items.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha do grupo (Level 0)
const valoresGrupoPorMes = calcularValoresPorMes(items);
rows.push({
type: "grupo",
level: 0,
grupo,
total: totalGrupo,
valoresPorMes: valoresGrupoPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(valoresGrupoPorMes, grupo),
isCalculado: items[0]?.isCalculado || false,
});
if (ordemHierarquiaContasPrimeiro) {
// ORDEM: Grupos → Contas → Centros de Custo
// Agrupar por conta dentro do grupo
const contas = items.reduce((acc, item) => {
if (!acc[item.conta]) {
acc[item.conta] = [];
}
acc[item.conta].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar contas por CODCONTA
const sortedContas = Object.entries(contas).sort(([contaA, itemsA], [contaB, itemsB]) => {
const codigoA = itemsA[0]?.codigo_conta || 0;
const codigoB = itemsB[0]?.codigo_conta || 0;
return codigoA - codigoB;
});
sortedContas.forEach(([conta, contaItems]) => {
const totalConta = contaItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha da conta (Level 1)
const valoresContaPorMes = calcularValoresPorMes(contaItems);
rows.push({
type: "conta",
level: 1,
grupo,
conta,
codigo_conta: contaItems[0].codigo_conta,
codigo_centro_custo: contaItems[0].codigo_centro_custo,
total: totalConta,
valoresPorMes: valoresContaPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(valoresContaPorMes, grupo),
});
// Agrupar por centro de custo dentro da conta
const centros = contaItems.reduce((acc, item) => {
if (!acc[item.centro_custo]) {
acc[item.centro_custo] = [];
}
acc[item.centro_custo].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar centros de custo por CODIGOCENTROCUSTO
const sortedCentros = Object.entries(centros).sort(([centroA, itemsA], [centroB, itemsB]) => {
const codigoA = itemsA[0]?.codigo_centro_custo || "";
const codigoB = itemsB[0]?.codigo_centro_custo || "";
return codigoA.localeCompare(codigoB);
});
sortedCentros.forEach(([centro, centroItems]) => {
const totalCentro = centroItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha do centro de custo (Level 2)
const valoresCentroPorMes = calcularValoresPorMes(centroItems);
rows.push({
type: "centro_custo",
level: 2,
grupo,
centro_custo: centro,
conta,
codigo_conta: contaItems[0].codigo_conta,
codigo_centro_custo: centroItems[0].codigo_centro_custo,
total: totalCentro,
valoresPorMes: valoresCentroPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(valoresCentroPorMes, grupo),
});
});
});
} else {
// ORDEM ORIGINAL: Grupos → Centros de Custo → Contas
// Agrupar por centro de custo dentro do grupo
const centros = items.reduce((acc, item) => {
if (!acc[item.centro_custo]) {
acc[item.centro_custo] = [];
}
acc[item.centro_custo].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar centros de custo por CODIGOCENTROCUSTO
const sortedCentros = Object.entries(centros).sort(([centroA, itemsA], [centroB, itemsB]) => {
const codigoA = itemsA[0]?.codigo_centro_custo || "";
const codigoB = itemsB[0]?.codigo_centro_custo || "";
return codigoA.localeCompare(codigoB);
});
sortedCentros.forEach(([centro, centroItems]) => {
const totalCentro = centroItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha do centro de custo (Level 1)
const valoresCentroPorMes = calcularValoresPorMes(centroItems);
rows.push({
type: "centro_custo",
level: 1,
grupo,
centro_custo: centro,
codigo_conta: centroItems[0].codigo_conta,
codigo_centro_custo: centroItems[0].codigo_centro_custo,
total: totalCentro,
valoresPorMes: valoresCentroPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(valoresCentroPorMes, grupo),
});
// Agrupar por conta dentro do centro de custo
const contas = centroItems.reduce((acc, item) => {
if (!acc[item.conta]) {
acc[item.conta] = [];
}
acc[item.conta].push(item);
return acc;
}, {} as Record<string, DREItem[]>);
// Ordenar contas por CODCONTA
const sortedContas = Object.entries(contas).sort(([contaA, itemsA], [contaB, itemsB]) => {
const codigoA = itemsA[0]?.codigo_conta || 0;
const codigoB = itemsB[0]?.codigo_conta || 0;
return codigoA - codigoB;
});
sortedContas.forEach(([conta, contaItems]) => {
const totalConta = contaItems.reduce(
(sum, item) => sum + parseFloat(item.valor),
0
);
// Linha da conta (Level 2)
const valoresContaPorMes = calcularValoresPorMes(contaItems);
rows.push({
type: "conta",
level: 2,
grupo,
centro_custo: centro,
conta,
codigo_conta: contaItems[0].codigo_conta,
codigo_centro_custo: centroItems[0].codigo_centro_custo,
total: totalConta,
valoresPorMes: valoresContaPorMes,
percentuaisPorMes: calcularPercentuaisPorMes(valoresContaPorMes, grupo),
});
});
});
}
});
return rows;
};
const toggleExpandAll = useCallback(() => {
if (isAllExpanded) {
// Recolher tudo - usar startTransition para atualizações não urgentes
@ -1157,6 +1451,18 @@ export default function Teste() {
{/* Controles */}
<div className="flex items-center gap-2">
{/* Botão de Exportar XLSX */}
<Button
variant="outline"
size="sm"
onClick={exportarXLSX}
disabled={!filtrosAplicados || hierarchicalData.length === 0}
className="flex items-center gap-2 text-xs h-8 px-3 transition-all duration-150 ease-in-out hover:scale-105 disabled:hover:scale-100"
>
<Download className="w-4 h-4" />
Exportar XLSX
</Button>
{/* Botão de Expandir/Recolher */}
<Button
variant="outline"