fix: correção da exportação dos dados sintéticos
This commit is contained in:
parent
beeedbff69
commit
a5ce93042c
|
|
@ -1,12 +1,13 @@
|
||||||
"use client";
|
"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 { useEffect, useState, useCallback, startTransition, memo } from "react";
|
||||||
import AnaliticoComponent from "./analitico";
|
import AnaliticoComponent from "./analitico";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
import * as XLSX from "xlsx";
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetContent,
|
SheetContent,
|
||||||
|
|
@ -498,6 +499,299 @@ export default function Teste() {
|
||||||
setContasSelecionadas([]);
|
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(() => {
|
const toggleExpandAll = useCallback(() => {
|
||||||
if (isAllExpanded) {
|
if (isAllExpanded) {
|
||||||
// Recolher tudo - usar startTransition para atualizações não urgentes
|
// Recolher tudo - usar startTransition para atualizações não urgentes
|
||||||
|
|
@ -1157,6 +1451,18 @@ export default function Teste() {
|
||||||
|
|
||||||
{/* Controles */}
|
{/* Controles */}
|
||||||
<div className="flex items-center gap-2">
|
<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 */}
|
{/* Botão de Expandir/Recolher */}
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue