From 9f2a169742e632379a60d3e4d0405f073d3975b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Fri, 7 Nov 2025 10:54:50 -0300 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20adicionar=20colunas=20DTLANC,=20DTC?= =?UTF-8?q?OMPENSACAO,=20DTPAGTO,=20CENTROCUSTO=20na=20tabela=20anal=C3=AD?= =?UTF-8?q?tica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 322 +++++++++++++++----------- src/app/api/analitico-oracle/route.ts | 9 +- 2 files changed, 192 insertions(+), 139 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 87ffd69..b8366cd 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -51,6 +51,7 @@ interface AnaliticoItem { codigo_conta: string; conta: string; codigo_centrocusto: string; + centro_custo?: string; valor: number; historico: string; historico2: string; @@ -65,6 +66,10 @@ interface AnaliticoItem { numero_lancamento?: number; ano_mes_comp?: string; codgrupo?: string; + // Novos campos + data_lancamento?: string; + data_compensacao?: string; + data_pagto?: string; } interface AnaliticoProps { @@ -397,9 +402,14 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { 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 }); @@ -457,38 +467,74 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { ); }, [data, filteredData, columnFilters, columnSorts, handleColumnFilterChange, handleColumnSortChange]); - // Definir colunas do DataGridPro + // 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: 150, + width: 120, sortable: true, resizable: true, - renderCell: (params: any) => { - if (!params.value) return "-"; - try { - return new Date(params.value).toLocaleDateString("pt-BR"); - } catch (error) { - return params.value; - } - }, + renderCell: dateCellRenderer, }, { field: "data_caixa", headerName: "Dt Caixa", - width: 130, + width: 120, sortable: true, resizable: true, - renderCell: (params: any) => { - if (!params.value) return "-"; - try { - return new Date(params.value).toLocaleDateString("pt-BR"); - } catch (error) { - return params.value; - } - }, + renderCell: dateCellRenderer, + }, + { + field: "data_pagto", + headerName: "Dt Pagto", + width: 120, + sortable: true, + resizable: true, + renderCell: dateCellRenderer, }, { field: "entidade", @@ -498,10 +544,18 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { 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: 140, + width: 120, sortable: true, resizable: true, }, @@ -515,15 +569,24 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }, { field: "codigo_centrocusto", - headerName: "C Custo", - width: 130, + 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: 150, + width: 120, sortable: true, resizable: true, }, @@ -535,97 +598,41 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { sortable: true, resizable: true, }, - { - field: "valor", - headerName: "Vl.Realizado", - type: "number" as const, - width: 140, - sortable: true, - resizable: true, - renderCell: (params: any) => { - const value = params.value; - if (value === null || value === undefined || value === "") 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} - - ); - }, + { + 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) => { - const value = params.value; - if (value === null || value === undefined || value === "" || 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} - - ); - }, + { + 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) => { - const value = params.value; - if (value === null || value === undefined || value === "" || 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} - - ); - }, + { + 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: 130, - sortable: true, - resizable: true, - renderCell: (params: any) => { - const value = params.value; - if (value === null || value === undefined || value === "" || 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} - - ); - }, + { + field: "valor_pago", + headerName: "Vl.Pago", + type: "number" as const, + width: 120, + sortable: true, + resizable: true, + renderCell: (params: any) => currencyCellRenderer(params, false), }, { field: "historico", @@ -646,7 +653,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { { field: "numero_lancamento", headerName: "Num.Lanc", - width: 80, + width: 100, sortable: true, resizable: true, renderCell: (params: any) => params.value || "-", @@ -740,25 +747,36 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { if (sortedAndFilteredData.length === 0) return; const exportData = sortedAndFilteredData.map((item) => ({ - "Data Vencimento": item.data_vencimento + "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") : "-", - "Data Caixa": item.data_caixa + "DTCAIXA": item.data_caixa ? new Date(item.data_caixa).toLocaleDateString("pt-BR") : "-", - "Entidade": item.entidade || "-", - "Código Fornecedor": item.codigo_fornecedor || "-", - "Fornecedor": item.nome_fornecedor || "-", - "Código Centro Custo": item.codigo_centrocusto || "-", - "Código Conta": item.codigo_conta || "-", - "Conta": item.conta || "-", - "Valor Realizado": typeof item.valor === "string" ? parseFloat(item.valor) : (item.valor || 0), - "Valor Previsto": typeof item.valor_previsto === "string" ? parseFloat(item.valor_previsto) : (item.valor_previsto || 0), - "Valor Confirmado": typeof item.valor_confirmado === "string" ? parseFloat(item.valor_confirmado) : (item.valor_confirmado || 0), - "Valor Pago": typeof item.valor_pago === "string" ? parseFloat(item.valor_pago) : (item.valor_pago || 0), - "Histórico": item.historico || "-", - "Histórico 2": item.historico2 || "-", - "Número Lançamento": item.numero_lancamento || "-", + "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(); @@ -869,9 +887,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { )} )} - {data.length > 0 && ( -
- - -
- )} + + @@ -936,6 +955,12 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { getRowId={(row: any) => row.id || `row-${row.recnum || Math.random()}`} sx={{ overflowAnchor: 'none', + "& .MuiDataGrid-root": { + overflowX: "auto", + }, + "& .MuiDataGrid-main": { + overflowX: "auto", + }, "& .MuiDataGrid-columnHeaders": { position: "sticky", top: 0, @@ -949,8 +974,31 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { }, "& .MuiDataGrid-virtualScroller": { overflowY: "auto", + overflowX: "auto", maxHeight: "calc(40vh - 120px)", - overflowAnchor: 'none' + 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", diff --git a/src/app/api/analitico-oracle/route.ts b/src/app/api/analitico-oracle/route.ts index ce3dcbf..8b3113f 100644 --- a/src/app/api/analitico-oracle/route.ts +++ b/src/app/api/analitico-oracle/route.ts @@ -139,11 +139,12 @@ export async function GET(request: NextRequest) { recnum: item.NUMLANC || 0, data_competencia: item.ANOMESCOMP || "", data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", - data_pagamento: "", // Não existe na tabela Oracle + data_pagamento: item.DTPAGTO ? new Date(item.DTPAGTO).toISOString().split('T')[0] : "", data_caixa: item.DTCAIXA ? new Date(item.DTCAIXA).toISOString().split('T')[0] : "", codigo_conta: item.CODCONTA || "", conta: item.CONTA || "", codigo_centrocusto: item.CODIGOCENTROCUSTO || "", + centro_custo: item.CENTROCUSTO || "", valor: item.VLREALIZADO !== null && item.VLREALIZADO !== undefined ? Number(item.VLREALIZADO) : 0, historico: item.HISTORICO || "", historico2: item.HISTORICO2 || "", @@ -157,7 +158,11 @@ export async function GET(request: NextRequest) { valor_pago: item.VLPAGO !== null && item.VLPAGO !== undefined ? Number(item.VLPAGO) : 0, numero_lancamento: item.NUMLANC || 0, ano_mes_comp: item.ANOMESCOMP || "", - codgrupo: item.CODGRUPO || "" + codgrupo: item.CODGRUPO || "", + // Novos campos + data_lancamento: item.DTLANC ? new Date(item.DTLANC).toISOString().split('T')[0] : "", + data_compensacao: item.DTCOMPENSACAO ? new Date(item.DTCOMPENSACAO).toISOString().split('T')[0] : "", + data_pagto: item.DTPAGTO ? new Date(item.DTPAGTO).toISOString().split('T')[0] : "" }; }); From 0c14945d36c909024b1160bcb2c9b98d1500d606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Fri, 7 Nov 2025 11:59:54 -0300 Subject: [PATCH 2/3] fix: header da tabela analitica --- src/app/DRE/analitico.tsx | 39 +++++++++++++++++++++++++++++++++++---- src/app/DRE/teste.tsx | 30 ++++++++++++++++-------------- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index b8366cd..effb14d 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -956,18 +956,43 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { sx={{ overflowAnchor: 'none', "& .MuiDataGrid-root": { - overflowX: "auto", + display: "flex", + flexDirection: "column", + height: "100%", }, "& .MuiDataGrid-main": { - overflowX: "auto", + overflow: "visible", + position: "relative", + height: "100%", }, "& .MuiDataGrid-columnHeaders": { position: "sticky", top: 0, - backgroundColor: "#f9fafb", - zIndex: 2, + backgroundColor: "#f9fafb !important", + zIndex: 100, borderBottom: "1px solid #e5e7eb", }, + "& .MuiDataGrid-columnHeader": { + backgroundColor: "#f9fafb !important", + }, + "& .MuiDataGrid-columnHeaderRow": { + position: "sticky", + top: 0, + zIndex: 100, + backgroundColor: "#f9fafb !important", + }, + "& .MuiDataGrid-columnHeadersInner": { + position: "sticky", + top: 0, + zIndex: 100, + backgroundColor: "#f9fafb !important", + }, + // Garantir que o container dos headers não seja cortado + "& .MuiDataGrid-container--top": { + overflow: "visible", + position: "relative", + zIndex: 100, + }, "& .MuiDataGrid-cell": { borderBottom: "1px solid #f0f0f0", fontSize: "0.875rem", @@ -1005,6 +1030,12 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { borderBottom: "1px solid #e5e7eb", padding: "8px 16px", }, + "& .MuiDataGrid-container--bottom": { + overflow: "hidden", + }, + "& .MuiDataGrid-scrollbar": { + display: "none", + }, // Ocultar todos os ícones nativos das colunas "& .MuiDataGrid-columnHeaderMenuContainer": { display: "none !important", diff --git a/src/app/DRE/teste.tsx b/src/app/DRE/teste.tsx index 2846bd5..84475f2 100644 --- a/src/app/DRE/teste.tsx +++ b/src/app/DRE/teste.tsx @@ -2371,7 +2371,7 @@ export default function Teste() { Filtros - + Filtros @@ -2379,7 +2379,8 @@ export default function Teste() { -
+
+
{/* Período */}
@@ -2698,8 +2699,9 @@ export default function Teste() {
+
- + @@ -2779,31 +2781,31 @@ export default function Teste() { {/* Table Container */} {filtrosAplicados && !loading && !error && ( -
- {/* Scroll Container */} -
+
+ {/* Scroll Container - Apenas um container com scroll */} +
{/* Table */} {/* Table Header */} - - - + + {mesesDisponiveis.map((mes) => ( - - ))} - - @@ -2829,8 +2831,8 @@ export default function Teste() { ))}
+
Descrição + {mes} + % + Total + %
+
-
)} {/* Componente Analítico - Sempre renderizado para evitar violação das Rules of Hooks */} From bf567eabfae5f5dffdaaf88976ca828ad7c69d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alessandro=20Gon=C3=A7aalves?= Date: Fri, 7 Nov 2025 19:22:20 -0300 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20corre=C3=A7=C3=A3o=20do=20scroll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/DRE/analitico.tsx | 56 ++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index effb14d..d6d6d1c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -939,7 +939,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
-
+
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: "visible", + 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: "sticky", - top: 0, + position: "relative !important", backgroundColor: "#f9fafb !important", zIndex: 100, borderBottom: "1px solid #e5e7eb", @@ -976,31 +992,30 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { backgroundColor: "#f9fafb !important", }, "& .MuiDataGrid-columnHeaderRow": { - position: "sticky", - top: 0, - zIndex: 100, backgroundColor: "#f9fafb !important", }, "& .MuiDataGrid-columnHeadersInner": { - position: "sticky", - top: 0, - zIndex: 100, backgroundColor: "#f9fafb !important", }, - // Garantir que o container dos headers não seja cortado - "& .MuiDataGrid-container--top": { - overflow: "visible", - position: "relative", - zIndex: 100, - }, "& .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", - overflowX: "auto", - maxHeight: "calc(40vh - 120px)", + overflowY: "auto !important", + overflowX: "auto !important", + height: "100% !important", + flex: 1, overflowAnchor: 'none', // Garantir que a barra de scroll seja visível scrollbarWidth: "thin", @@ -1030,9 +1045,6 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { borderBottom: "1px solid #e5e7eb", padding: "8px 16px", }, - "& .MuiDataGrid-container--bottom": { - overflow: "hidden", - }, "& .MuiDataGrid-scrollbar": { display: "none", },