"use client"; import * as React from "react"; import { DataGridPremium, GridToolbar, GridColDef, GridFilterModel } from "@mui/x-data-grid-premium"; import { LicenseInfo } from '@mui/x-license-pro'; // Garantir que a licença seja aplicada no componente if (typeof window !== 'undefined') { try { const PERPETUAL_LICENSE_KEY = 'e0d9bb8070ce0054c9d9ecb6e82cb58fTz0wLEU9MzI0NzIxNDQwMDAwMDAsUz1wcmVtaXVtLExNPXBlcnBldHVhbCxLVj0y'; LicenseInfo.setLicenseKey(PERPETUAL_LICENSE_KEY); console.log('✅ Licença MUI X aplicada no componente Analítico'); } catch (error) { console.warn('⚠️ Erro ao aplicar licença no componente:', error); } } import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogTrigger, } from "@/components/ui/dialog"; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer"; import { Download, Filter, X, Search, ArrowUpDown, ArrowUp, ArrowDown, Maximize2, Minimize2 } from "lucide-react"; import * as XLSX from "xlsx"; interface AnaliticoItem { codigo_grupo: string; codigo_subgrupo: string; codigo_fornecedor: string; nome_fornecedor: string; id: number; codfilial: string; recnum: number; data_competencia: string; data_vencimento: string; data_pagamento: string; data_caixa: string; codigo_conta: string; conta: string; codigo_centrocusto: string; centro_custo?: string; valor: number; historico: string; historico2: string; created_at: string; updated_at: string; // Campos adicionais do Oracle entidade?: string; tipo_parceiro?: string; valor_previsto?: number; valor_confirmado?: number; valor_pago?: number; numero_lancamento?: number; ano_mes_comp?: string; codgrupo?: string; // Novos campos data_lancamento?: string; data_compensacao?: string; data_pagto?: string; } interface AnaliticoProps { filtros: { dataInicio: string; dataFim: string; centroCusto?: string; codigoGrupo?: string; codigoSubgrupo?: string; codigoConta?: string; linhaSelecionada?: string; excluirCentroCusto?: string; excluirCodigoConta?: string; codigosCentrosCustoSelecionados?: string; codigosContasSelecionadas?: string; }; } // Componente de filtro customizado estilo Excel interface ExcelFilterProps { column: GridColDef; data: any[]; filteredData: any[]; // Dados filtrados para mostrar apenas valores disponíveis onFilterChange: (field: string, values: string[]) => void; onSortChange: (field: string, direction: 'asc' | 'desc' | null) => void; currentFilter?: string[]; currentSort?: 'asc' | 'desc' | null; } const ExcelFilter: React.FC = ({ column, data, filteredData, onFilterChange, onSortChange, currentFilter = [], currentSort = null, }) => { const [isOpen, setIsOpen] = React.useState(false); const [searchTerm, setSearchTerm] = React.useState(""); const [selectedValues, setSelectedValues] = React.useState(currentFilter); const [selectAll, setSelectAll] = React.useState(false); // Sincronizar selectedValues com currentFilter quando ele mudar React.useEffect(() => { setSelectedValues(currentFilter); }, [currentFilter]); // Obter valores únicos da coluna baseado nos dados filtrados const uniqueValues = React.useMemo(() => { const values = filteredData .map((row) => { const value = row[column.field]; if (value === null || value === undefined) return ""; return String(value); }) .filter((value, index, self) => self.indexOf(value) === index && value !== "") .sort(); return values; }, [filteredData, column.field]); // Filtrar valores baseado na busca const filteredValues = React.useMemo(() => { if (!searchTerm) return uniqueValues; return uniqueValues.filter((value) => value.toLowerCase().includes(searchTerm.toLowerCase()) ); }, [uniqueValues, searchTerm]); const handleSelectAll = (checked: boolean) => { if (checked) { setSelectedValues(filteredValues); setSelectAll(true); } else { setSelectedValues([]); setSelectAll(false); } }; const handleValueToggle = (value: string, checked: boolean) => { let newValues: string[]; if (checked) { newValues = [...selectedValues, value]; } else { newValues = selectedValues.filter((v) => v !== value); } setSelectedValues(newValues); setSelectAll(newValues.length === filteredValues.length && filteredValues.length > 0); }; const handleApply = () => { onFilterChange(column.field, selectedValues); setIsOpen(false); }; const handleClear = () => { setSelectedValues([]); setSelectAll(false); onFilterChange(column.field, []); setIsOpen(false); }; const handleSort = (direction: 'asc' | 'desc') => { onSortChange(column.field, direction); setIsOpen(false); }; return ( Filtrar por "{column.headerName}"
{/* Opções de ordenação */}
Ordenar
{/* Barra de pesquisa */}
setSearchTerm(e.target.value)} className="pl-8 h-8 text-sm" />
{/* Lista de valores com checkboxes */}
{filteredValues.map((value) => (
handleValueToggle(value, checked)} />
))}
{/* Botões de ação */}
); }; export default function AnaliticoComponent({ filtros }: AnaliticoProps) { const [data, setData] = React.useState([]); const [loading, setLoading] = React.useState(false); const [globalFilter, setGlobalFilter] = React.useState(""); const [open, setOpen] = React.useState(false); const [drawerOpen, setDrawerOpen] = React.useState(false); const [columnFilters, setColumnFilters] = React.useState>({}); const [columnSorts, setColumnSorts] = React.useState>({}); const [conditions, setConditions] = React.useState([ { column: "", operator: "contains", value: "" }, ]); // Estados para o card de agregação customizado (simplificado) const [aggregationCardRef, setAggregationCardRef] = React.useState(null); // Estado para armazenar filtros externos (vindos do teste.tsx) const [filtrosExternos, setFiltrosExternos] = React.useState(filtros); // Funções para gerenciar filtros customizados const handleColumnFilterChange = React.useCallback((field: string, values: string[]) => { setColumnFilters(prev => ({ ...prev, [field]: values })); }, []); const handleColumnSortChange = React.useCallback((field: string, direction: 'asc' | 'desc' | null) => { setColumnSorts(prev => ({ ...prev, [field]: direction })); }, []); // Função para contar filtros aplicados (apenas filtros internos do modal customizado) const getFilterCount = React.useCallback(() => { let count = 0; // Contar filtros de coluna (filtros do modal customizado) count += Object.keys(columnFilters).length; // Contar filtro global (se aplicável) if (globalFilter && globalFilter.trim() !== "") { count += 1; } return count; }, [columnFilters, globalFilter]); // Função para limpar todos os filtros internos (mantém filtros externos) const clearAllFilters = React.useCallback(() => { setColumnFilters({}); setColumnSorts({}); setGlobalFilter(""); }, []); // Atualizar filtros externos quando os props mudarem React.useEffect(() => { console.log('🔄 Analítico - useEffect dos filtros chamado'); console.log('📋 Filtros recebidos via props:', filtros); setFiltrosExternos(filtros); }, [filtros]); const fetchData = React.useCallback(async () => { console.log('🔄 Analítico - fetchData chamado'); console.log('📋 Filtros externos recebidos:', filtrosExternos); if (!filtrosExternos.dataInicio || !filtrosExternos.dataFim) { console.log('⚠️ Sem dataInicio ou dataFim, limpando dados'); setData([]); return; } setLoading(true); try { const params = new URLSearchParams(); if (filtrosExternos.dataInicio) { params.append('dataInicio', filtrosExternos.dataInicio); } if (filtrosExternos.dataFim) { params.append('dataFim', filtrosExternos.dataFim); } if (filtrosExternos.centroCusto) { params.append('centroCusto', filtrosExternos.centroCusto); } if (filtrosExternos.codigoGrupo) { params.append('codigoGrupo', filtrosExternos.codigoGrupo); } if (filtrosExternos.codigoConta) { params.append('codigoConta', filtrosExternos.codigoConta); } if (filtrosExternos.excluirCentroCusto) { params.append('excluirCentroCusto', filtrosExternos.excluirCentroCusto); } if (filtrosExternos.excluirCodigoConta) { params.append('excluirCodigoConta', filtrosExternos.excluirCodigoConta); } if (filtrosExternos.codigosCentrosCustoSelecionados) { params.append('codigosCentrosCustoSelecionados', filtrosExternos.codigosCentrosCustoSelecionados); } if (filtrosExternos.codigosContasSelecionadas) { params.append('codigosContasSelecionadas', filtrosExternos.codigosContasSelecionadas); } const url = `/api/analitico-oracle?${params.toString()}`; console.log('🌐 Fazendo requisição para:', url); const response = await fetch(url); if (response.ok) { const result = await response.json(); console.log('✅ Resposta da API recebida:', result.length, 'registros'); console.log('📝 Primeiros 2 registros:', result.slice(0, 2)); console.log('🔍 Verificando campos específicos:', { data_lancamento: result[0]?.data_lancamento, data_compensacao: result[0]?.data_compensacao, data_vencimento: result[0]?.data_vencimento, data_caixa: result[0]?.data_caixa, data_pagto: result[0]?.data_pagto, entidade: result[0]?.entidade, tipo_parceiro: result[0]?.tipo_parceiro, centro_custo: result[0]?.centro_custo, valor: result[0]?.valor, tipo_valor: typeof result[0]?.valor }); setData(result as AnaliticoItem[]); } else { console.error("❌ Erro ao buscar dados:", await response.text()); } } catch (error) { console.error("❌ Erro ao buscar dados:", error); } finally { setLoading(false); } }, [filtrosExternos]); React.useEffect(() => { fetchData(); }, [fetchData]); // Filtrar dados baseado nos filtros de coluna const filteredData = React.useMemo(() => { if (!data || data.length === 0) return data; return data.filter((row) => { return Object.entries(columnFilters).every(([field, filterValues]) => { if (!filterValues || filterValues.length === 0) return true; const cellValue = (row as any)[field]; const stringValue = cellValue === null || cellValue === undefined ? "" : String(cellValue); return filterValues.includes(stringValue); }); }).map((row, index) => ({ ...row, id: `filtered-${row.id || row.recnum || index}` // Garantir ID único e estável })); }, [data, columnFilters]); // Função para renderizar header com filtro Excel const renderHeaderWithFilter = React.useCallback((column: GridColDef) => { return (params: any) => (
{column.headerName}
); }, [data, filteredData, columnFilters, columnSorts, handleColumnFilterChange, handleColumnSortChange]); // Definir colunas do DataGridPro na ordem solicitada const columns = React.useMemo(() => { const dateCellRenderer = (params: any) => { if (!params.value) return "-"; try { return new Date(params.value).toLocaleDateString("pt-BR"); } catch (error) { return params.value; } }; const currencyCellRenderer = (params: any, showZero: boolean = false) => { const value = params.value; if (value === null || value === undefined || value === "") return "-"; if (!showZero && value === 0) return "-"; const numValue = typeof value === "string" ? parseFloat(value) : Number(value); if (isNaN(numValue)) return "-"; const formatted = new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(numValue); return ( {formatted} ); }; const baseColumns = [ { field: "data_lancamento", headerName: "Dt Lanc", width: 120, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: "data_compensacao", headerName: "Dt Comp", width: 120, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: "data_vencimento", headerName: "Dt Venc", width: 120, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: "data_caixa", headerName: "Dt Caixa", width: 120, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: "data_pagto", headerName: "Dt Pagto", width: 120, sortable: true, resizable: true, renderCell: dateCellRenderer, }, { field: "entidade", headerName: "Entidade", width: 100, sortable: true, resizable: true, renderCell: (params: any) => params.value || "-", }, { field: "tipo_parceiro", headerName: "Tipo Parc", width: 120, sortable: true, resizable: true, renderCell: (params: any) => params.value || "-", }, { field: "codigo_fornecedor", headerName: "Cod.Fornec", width: 120, sortable: true, resizable: true, }, { field: "nome_fornecedor", headerName: "Fornecedor", flex: 1, minWidth: 200, sortable: true, resizable: true, }, { field: "codigo_centrocusto", headerName: "Cod.CC", width: 100, sortable: true, resizable: true, }, { field: "centro_custo", headerName: "Centro Custo", flex: 1, minWidth: 200, sortable: true, resizable: true, renderCell: (params: any) => params.value || "-", }, { field: "codigo_conta", headerName: "Cod.Conta", width: 120, sortable: true, resizable: true, }, { field: "conta", headerName: "Conta", flex: 1, minWidth: 180, sortable: true, resizable: true, }, { field: "valor", headerName: "Vl.Realizado", type: "number" as const, width: 140, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, true), }, { field: "valor_previsto", headerName: "Vl.Previsto", type: "number" as const, width: 130, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: "valor_confirmado", headerName: "Vl.Confirmado", type: "number" as const, width: 140, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: "valor_pago", headerName: "Vl.Pago", type: "number" as const, width: 120, sortable: true, resizable: true, renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: "historico", headerName: "Historico", flex: 1, minWidth: 250, sortable: true, resizable: true, }, { field: "historico2", headerName: "Historico 2", flex: 1, minWidth: 300, sortable: true, resizable: true, }, { field: "numero_lancamento", headerName: "Num.Lanc", width: 100, sortable: true, resizable: true, renderCell: (params: any) => params.value || "-", }, ]; // Adicionar renderHeader com filtro Excel para todas as colunas return baseColumns.map((col) => ({ ...col, renderHeader: renderHeaderWithFilter(col), })); }, [renderHeaderWithFilter]); // Ordenar dados baseado na ordenação de coluna const sortedAndFilteredData = React.useMemo(() => { if (!filteredData || filteredData.length === 0) return filteredData; const sortField = Object.keys(columnSorts).find(field => columnSorts[field] !== null); if (!sortField || !columnSorts[sortField]) return filteredData; return [...filteredData].sort((a, b) => { const aValue = (a as any)[sortField]; const bValue = (b as any)[sortField]; // Converter para string para comparação const aString = aValue === null || aValue === undefined ? "" : String(aValue); const bString = bValue === null || bValue === undefined ? "" : String(bValue); if (columnSorts[sortField] === 'asc') { return aString.localeCompare(bString); } else { return bString.localeCompare(aString); } }); }, [filteredData, columnSorts]); // Calcular valor total dos dados filtrados const valorTotal = React.useMemo(() => { return sortedAndFilteredData.reduce((sum, item) => sum + (Number(item.valor) || 0), 0); }, [sortedAndFilteredData]); // Calcular totais das colunas de valor para o card de agregação const columnTotals = React.useMemo(() => { return { valor: sortedAndFilteredData.reduce((sum, item) => sum + (Number(item.valor) || 0), 0), valor_previsto: sortedAndFilteredData.reduce((sum, item) => sum + (Number(item.valor_previsto) || 0), 0), valor_confirmado: sortedAndFilteredData.reduce((sum, item) => sum + (Number(item.valor_confirmado) || 0), 0), valor_pago: sortedAndFilteredData.reduce((sum, item) => sum + (Number(item.valor_pago) || 0), 0), }; }, [sortedAndFilteredData]); // Limpar filtros de colunas que não têm mais valores disponíveis React.useEffect(() => { const updatedFilters = { ...columnFilters }; let hasChanges = false; Object.keys(columnFilters).forEach(field => { const currentFilterValues = columnFilters[field] || []; if (currentFilterValues.length === 0) return; // Obter valores únicos disponíveis para esta coluna nos dados filtrados const availableValues = filteredData .map(row => { const value = (row as any)[field]; return value === null || value === undefined ? "" : String(value); }) .filter((value, index, self) => self.indexOf(value) === index && value !== ""); // Filtrar apenas os valores que ainda estão disponíveis const validFilterValues = currentFilterValues.filter(value => availableValues.includes(value) ); if (validFilterValues.length !== currentFilterValues.length) { if (validFilterValues.length === 0) { delete updatedFilters[field]; } else { updatedFilters[field] = validFilterValues; } hasChanges = true; } }); if (hasChanges) { setColumnFilters(updatedFilters); } }, [filteredData, columnFilters]); // Exportação XLSX const exportToExcel = () => { if (sortedAndFilteredData.length === 0) return; const exportData = sortedAndFilteredData.map((item) => ({ "DTLANC": item.data_lancamento ? new Date(item.data_lancamento).toLocaleDateString("pt-BR") : "-", "DTCOMPENSACAO": item.data_compensacao ? new Date(item.data_compensacao).toLocaleDateString("pt-BR") : "-", "DTVENC": item.data_vencimento ? new Date(item.data_vencimento).toLocaleDateString("pt-BR") : "-", "DTCAIXA": item.data_caixa ? new Date(item.data_caixa).toLocaleDateString("pt-BR") : "-", "DTPAGTO": item.data_pagto ? new Date(item.data_pagto).toLocaleDateString("pt-BR") : "-", "ENTIDADE": item.entidade || "-", "TIPOPARCEIRO": item.tipo_parceiro || "-", "CODFORNEC": item.codigo_fornecedor || "-", "FORNECEDOR": item.nome_fornecedor || "-", "CODIGOCENTROCUSTO": item.codigo_centrocusto || "-", "CENTROCUSTO": item.centro_custo || "-", "CODCONTA": item.codigo_conta || "-", "CONTA": item.conta || "-", "VLREALIZADO": typeof item.valor === "string" ? parseFloat(item.valor) : (item.valor || 0), "VLPREVISTO": typeof item.valor_previsto === "string" ? parseFloat(item.valor_previsto) : (item.valor_previsto || 0), "VLCONFIRMADO": typeof item.valor_confirmado === "string" ? parseFloat(item.valor_confirmado) : (item.valor_confirmado || 0), "VLPAGO": typeof item.valor_pago === "string" ? parseFloat(item.valor_pago) : (item.valor_pago || 0), "HISTORICO": item.historico || "-", "HISTORICO2": item.historico2 || "-", "NUMLANC": item.numero_lancamento || "-", })); const wb = XLSX.utils.book_new(); const ws = XLSX.utils.json_to_sheet(exportData); const resumoData = [ { Métrica: "Total de Registros", Valor: sortedAndFilteredData.length }, { Métrica: "Valor Total", Valor: valorTotal }, { Métrica: "Filtros Aplicados", Valor: Object.keys(columnFilters).length > 0 ? "Sim" : "Não" }, ]; const wsResumo = XLSX.utils.json_to_sheet(resumoData); XLSX.utils.book_append_sheet(wb, ws, "Dados Analíticos"); XLSX.utils.book_append_sheet(wb, wsResumo, "Resumo"); const now = new Date(); const timestamp = now.toISOString().slice(0, 19).replace(/:/g, "-"); const fileName = `analitico_${timestamp}.xlsx`; XLSX.writeFile(wb, fileName); }; // Aplicar filtros avançados const applyFilters = () => { // Implementar lógica de filtros avançados se necessário setOpen(false); }; const clearFilters = () => { setConditions([{ column: "", operator: "contains", value: "" }]); setGlobalFilter(""); }; // Função para renderizar o conteúdo principal do componente (reutilizável) const renderAnaliticoContent = (isMaximized: boolean = false) => { return ( <> {/* Filtros Externos Ativos - Apenas quando maximizado */} {isMaximized && (filtrosExternos.dataInicio || filtrosExternos.centroCusto || filtrosExternos.codigoGrupo || filtrosExternos.codigoConta) && (
Filtros aplicados pela tabela DRE Gerencial:
{filtrosExternos.dataInicio && filtrosExternos.dataFim && ( Período: {filtrosExternos.dataInicio} a {filtrosExternos.dataFim} )} {filtrosExternos.centroCusto && ( Centro: {filtrosExternos.centroCusto} )} {filtrosExternos.codigoGrupo && ( Grupo: {filtrosExternos.codigoGrupo} )} {filtrosExternos.codigoConta && ( Conta: {filtrosExternos.codigoConta} )}
)} {/* Controls - Apenas quando maximizado */} {isMaximized && (
{data.length > 0 && ( )}
)} {/* DataGridPro */}

Total de Registros: {sortedAndFilteredData.length}

Valor Total: {new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(valorTotal)}
row.id || `row-${row.recnum || Math.random()}`} sx={{ overflowAnchor: 'none', height: "100%", display: "flex", flexDirection: "column", "& .MuiDataGrid-root": { display: "flex", flexDirection: "column", height: "100%", flex: 1, overflow: "hidden", }, "& .MuiDataGrid-main": { overflow: "hidden !important", position: "relative", height: "100%", display: "flex", flexDirection: "column", flex: 1, }, // Container dos headers - DEVE FICAR FIXO (não rola) "& .MuiDataGrid-container--top": { overflow: "hidden !important", position: "relative", zIndex: 100, backgroundColor: "#f9fafb", flexShrink: 0, flexGrow: 0, }, "& .MuiDataGrid-columnHeaders": { position: "relative !important", backgroundColor: "#f9fafb !important", zIndex: 100, borderBottom: "1px solid #e5e7eb", }, "& .MuiDataGrid-columnHeader": { backgroundColor: "#f9fafb !important", }, "& .MuiDataGrid-columnHeaderRow": { backgroundColor: "#f9fafb !important", }, "& .MuiDataGrid-columnHeadersInner": { backgroundColor: "#f9fafb !important", }, "& .MuiDataGrid-cell": { borderBottom: "1px solid #f0f0f0", fontSize: "0.875rem", }, // Container do virtualScroller - deve ter scroll e ocupar espaço restante "& .MuiDataGrid-container--bottom": { flex: 1, overflow: "hidden !important", position: "relative", minHeight: 0, display: "flex", flexDirection: "column", }, // Apenas o virtualScroller deve ter scroll "& .MuiDataGrid-virtualScroller": { overflowY: "auto !important", overflowX: "auto !important", height: "100% !important", flex: 1, overflowAnchor: 'none', // Garantir que a barra de scroll seja visível scrollbarWidth: "thin", "&::-webkit-scrollbar": { height: "8px", width: "8px", }, "&::-webkit-scrollbar-track": { background: "#f1f1f1", }, "&::-webkit-scrollbar-thumb": { background: "#888", borderRadius: "4px", }, "&::-webkit-scrollbar-thumb:hover": { background: "#555", }, }, "& .MuiDataGrid-virtualScrollerContent": { minWidth: "max-content", }, "& .MuiDataGrid-row": { minWidth: "max-content", }, "& .MuiDataGrid-toolbarContainer": { backgroundColor: "#f8fafc", borderBottom: "1px solid #e5e7eb", padding: "8px 16px", }, "& .MuiDataGrid-scrollbar": { display: "none", }, // Ocultar todos os ícones nativos das colunas "& .MuiDataGrid-columnHeaderMenuContainer": { display: "none !important", }, "& .MuiDataGrid-columnHeaderMenuButton": { display: "none !important", }, "& .MuiDataGrid-columnHeaderSortIcon": { display: "none !important", }, "& .MuiDataGrid-columnHeaderSortIconContainer": { display: "none !important", }, "& .MuiDataGrid-iconButtonContainer": { display: "none !important", }, "& .MuiDataGrid-columnHeaderSeparator": { display: "none !important", }, "& .MuiDataGrid-columnHeaderSortButton": { display: "none !important", }, // Ocultar qualquer ícone de menu adicional "& .MuiDataGrid-menuIcon": { display: "none !important", }, "& .MuiDataGrid-menuIconButton": { display: "none !important", }, "& .MuiDataGrid-columnHeaderMenuIcon": { display: "none !important", }, "& .MuiDataGrid-columnHeaderMenuIconButton": { display: "none !important", }, "& .MuiDataGrid-menuContainer": { display: "none !important", }, "& .MuiDataGrid-menu": { display: "none !important", }, // Ocultar footer de paginação "& .MuiDataGrid-footerContainer": { display: "none !important", }, "& .MuiDataGrid-pagination": { display: "none !important", }, "& .MuiTablePagination-root": { display: "none !important", }, // Garantir que nosso botão customizado apareça "& .MuiDataGrid-columnHeaderTitleContainer": { width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between", }, }} /> {/* Card de Agregação Customizado */} {sortedAndFilteredData.length > 0 && (
Vl.Realizado: {new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(columnTotals.valor)}
Vl.Previsto: {new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(columnTotals.valor_previsto)}
Vl.Confirmado: {new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(columnTotals.valor_confirmado)}
Vl.Pago: {new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL", }).format(columnTotals.valor_pago)}
Total de Registros: {sortedAndFilteredData.length}
)}
); }; return (
{/* Header Section */}

Análise Analítica{filtros.linhaSelecionada ? ` - ${filtros.linhaSelecionada}` : ""}

Relatório detalhado de transações

{/* Filtros Externos Ativos - Centralizado */} {(filtrosExternos.dataInicio || filtrosExternos.centroCusto || filtrosExternos.codigoGrupo || filtrosExternos.codigoConta) && (
Filtros aplicados pela tabela DRE Gerencial:
{filtrosExternos.dataInicio && filtrosExternos.dataFim && ( Período: {filtrosExternos.dataInicio} a {filtrosExternos.dataFim} )} {filtrosExternos.centroCusto && ( Centro: {filtrosExternos.centroCusto} )} {filtrosExternos.codigoGrupo && ( Grupo: {filtrosExternos.codigoGrupo} )} {filtrosExternos.codigoConta && ( Conta: {filtrosExternos.codigoConta} )}
)} {/* Controls */}
{/* ) => setGlobalFilter(e.target.value) } className="w-64 bg-white border-gray-300 focus:border-blue-500 focus:ring-blue-500" /> */} {globalFilter && ( )}
{data.length > 0 && ( )}
Análise Analítica{filtros.linhaSelecionada ? ` - ${filtros.linhaSelecionada}` : ""} Relatório detalhado de transações - Versão Maximizada
{renderAnaliticoContent(true)}
{/* Conteúdo Principal - Versão Normal */} {renderAnaliticoContent(false)} {/* Advanced Filters Dialog */} Filtros Avançados

Estes filtros são aplicados sobre os dados já filtrados pela tabela DRE Gerencial.

{conditions.map((cond, idx) => (
{!(cond.operator === "empty" || cond.operator === "notEmpty") && (
) => { const next = [...conditions]; next[idx].value = e.target.value; setConditions(next); }} placeholder="Digite o valor" className="w-full bg-white border-gray-300" />
)} {conditions.length > 1 && (
)}
))}
); }