From 56fca47861ee3f327e31714db7da7b730f82a16d Mon Sep 17 00:00:00 2001 From: Felipe Batista Date: Tue, 23 Dec 2025 13:15:55 -0300 Subject: [PATCH] ajuste nas grid dre-entidade e unicidade de cada resultado retornado nas query do banco de dados --- src/app/DRE/analitico.tsx | 46 +- .../api/analitico-entidade-oracle/route.ts | 239 ++- src/app/api/analitico-filial-oracle/route.ts | 21 +- src/app/api/analitico-oracle/route.ts | 21 +- src/app/dre-entidade/analitico.tsx | 1349 +++++++++-------- src/app/dre-filial/analitico.tsx | 46 +- 6 files changed, 1028 insertions(+), 694 deletions(-) diff --git a/src/app/DRE/analitico.tsx b/src/app/DRE/analitico.tsx index 9cebc5e..278281c 100644 --- a/src/app/DRE/analitico.tsx +++ b/src/app/DRE/analitico.tsx @@ -64,7 +64,7 @@ interface AnaliticoItem { codigo_subgrupo: string; codigo_fornecedor: string; nome_fornecedor: string; - id: number; + id: string | number; // Pode ser string (gerado pela API) ou number (legado) codfilial: string; recnum: number; data_competencia: string; @@ -492,10 +492,25 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { return filterValues.includes(stringValue); }); }) - .map((row, index) => ({ - ...row, - id: `filtered-${row.id || row.recnum || index}`, // Garantir ID único e estável - })); + .map((row, index) => { + // Garantir ID único: usar o id original se existir, senão criar baseado em recnum e índice + const originalId = + row.id !== null && row.id !== undefined + ? typeof row.id === 'string' && row.id !== '' + ? row.id + : String(row.id) + : null; + const recnumValue = + row.recnum !== null && row.recnum !== undefined ? row.recnum : null; + const uniqueId = originalId + ? `filtered-${originalId}` + : `filtered-${recnumValue !== null ? recnumValue : 'idx'}-${index}`; + + return { + ...row, + id: uniqueId, // Garantir ID único e estável (agora é string) + }; + }); }, [data, columnFilters]); // Função para renderizar header com filtro Excel @@ -1107,9 +1122,24 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { disableColumnSorting={true} pagination={false} disableVirtualization={false} - getRowId={(row: any) => - row.id || `row-${row.recnum || Math.random()}` - } + getRowId={(row: any) => { + // Usar verificação explícita para garantir que id seja usado mesmo se for string vazia + if ( + row.id !== null && + row.id !== undefined && + row.id !== '' + ) { + return String(row.id); + } + // Fallback: usar recnum se disponível, senão criar ID único + const recnumValue = + row.recnum !== null && row.recnum !== undefined + ? row.recnum + : null; + return recnumValue !== null + ? `row-${recnumValue}` + : `row-${Math.random()}-${Date.now()}`; + }} sx={{ height: '100%', width: '100%', diff --git a/src/app/api/analitico-entidade-oracle/route.ts b/src/app/api/analitico-entidade-oracle/route.ts index 8b725d9..efcad67 100644 --- a/src/app/api/analitico-entidade-oracle/route.ts +++ b/src/app/api/analitico-entidade-oracle/route.ts @@ -1,5 +1,5 @@ -import { NextRequest, NextResponse } from 'next/server'; import { executeOracleQuery } from '@/db/oracle'; +import { NextRequest, NextResponse } from 'next/server'; export async function GET(request: NextRequest) { try { @@ -16,14 +16,18 @@ export async function GET(request: NextRequest) { const codigoGrupo = searchParams.get('codigoGrupo'); const codigoSubgrupo = searchParams.get('codigoSubgrupo'); const codigoConta = searchParams.get('codigoConta'); - + // Parâmetros para exclusão de valores específicos const excluirCentroCusto = searchParams.get('excluirCentroCusto'); const excluirCodigoConta = searchParams.get('excluirCodigoConta'); - + // Novos parâmetros para códigos selecionados no filtro - const codigosCentrosCustoSelecionados = searchParams.get('codigosCentrosCustoSelecionados'); - const codigosContasSelecionadas = searchParams.get('codigosContasSelecionadas'); + const codigosCentrosCustoSelecionados = searchParams.get( + 'codigosCentrosCustoSelecionados' + ); + const codigosContasSelecionadas = searchParams.get( + 'codigosContasSelecionadas' + ); console.log('🎯 Filtros recebidos na API:', { dataInicio, @@ -35,14 +39,17 @@ export async function GET(request: NextRequest) { excluirCentroCusto, excluirCodigoConta, codigosCentrosCustoSelecionados, - codigosContasSelecionadas + codigosContasSelecionadas, }); console.log('🔍 Verificação específica de centroCusto:', { centroCusto, tipo: typeof centroCusto, - vazio: centroCusto === null || centroCusto === undefined || centroCusto === '', + vazio: + centroCusto === null || centroCusto === undefined || centroCusto === '', codigosCentrosCustoSelecionados, - codigosCentrosCustoSelecionadosVazio: !codigosCentrosCustoSelecionados || codigosCentrosCustoSelecionados === '' + codigosCentrosCustoSelecionadosVazio: + !codigosCentrosCustoSelecionados || + codigosCentrosCustoSelecionados === '', }); // Construir query SQL com filtros usando a view DESPESA_ENTIDADE_ANALITICO @@ -52,10 +59,17 @@ export async function GET(request: NextRequest) { // Filtro por período (usando ANOMESCOMP) if (dataInicio && dataFim) { - sql += ` AND ANOMESCOMP >= :${paramIndex} AND ANOMESCOMP <= :${paramIndex + 1}`; + sql += ` AND ANOMESCOMP >= :${paramIndex} AND ANOMESCOMP <= :${ + paramIndex + 1 + }`; params.push(dataInicio, dataFim); paramIndex += 2; - console.log('📅 Adicionando filtro de período:', dataInicio, 'a', dataFim); + console.log( + '📅 Adicionando filtro de período:', + dataInicio, + 'a', + dataFim + ); } // Filtro por código do grupo @@ -87,12 +101,15 @@ export async function GET(request: NextRequest) { console.log('🔍 Antes de aplicar filtro de centro de custo:', { codigosCentrosCustoSelecionados, centroCusto, - codigosCentrosCustoSelecionadosVazio: !codigosCentrosCustoSelecionados || codigosCentrosCustoSelecionados.trim() === '', + codigosCentrosCustoSelecionadosVazio: + !codigosCentrosCustoSelecionados || + codigosCentrosCustoSelecionados.trim() === '', centroCustoVazio: !centroCusto || centroCusto.trim() === '', centroCustoLength: centroCusto?.length, - codigosCentrosCustoSelecionadosLength: codigosCentrosCustoSelecionados?.length + codigosCentrosCustoSelecionadosLength: + codigosCentrosCustoSelecionados?.length, }); - + // IMPORTANTE: Quando centroCusto individual é fornecido (clique na célula), ele tem PRIORIDADE ABSOLUTA // e deve filtrar APENAS por ele, ignorando codigosCentrosCustoSelecionados do filtro geral if (centroCusto && centroCusto.trim() !== '') { @@ -101,21 +118,44 @@ export async function GET(request: NextRequest) { sql += ` AND CODIGOCENTROCUSTO = :${paramIndex}`; params.push(centroCusto); paramIndex++; - console.log('🏢 PRIORIDADE: Filtrando APENAS por centroCusto individual (clique na célula):', centroCusto); - console.log('⚠️ Ignorando codigosCentrosCustoSelecionados do filtro geral quando há centroCusto individual'); - console.log('📝 SQL após adicionar filtro =:', sql.substring(0, 200) + '...'); - } else if (codigosCentrosCustoSelecionados && codigosCentrosCustoSelecionados.trim() !== '') { + console.log( + '🏢 PRIORIDADE: Filtrando APENAS por centroCusto individual (clique na célula):', + centroCusto + ); + console.log( + '⚠️ Ignorando codigosCentrosCustoSelecionados do filtro geral quando há centroCusto individual' + ); + console.log( + '📝 SQL após adicionar filtro =:', + sql.substring(0, 200) + '...' + ); + } else if ( + codigosCentrosCustoSelecionados && + codigosCentrosCustoSelecionados.trim() !== '' + ) { // Se só codigosCentrosCustoSelecionados existe (sem clique na célula), usar ele - const codigosArray = codigosCentrosCustoSelecionados.split(',').filter(c => c.trim() !== ''); + const codigosArray = codigosCentrosCustoSelecionados + .split(',') + .filter((c) => c.trim() !== ''); if (codigosArray.length > 0) { - const placeholders = codigosArray.map(() => `:${paramIndex++}`).join(','); + const placeholders = codigosArray + .map(() => `:${paramIndex++}`) + .join(','); sql += ` AND CODIGOCENTROCUSTO IN (${placeholders})`; params.push(...codigosArray); - console.log('🏢 Filtrando por códigos de centros de custo selecionados (filtro geral):', codigosArray); - console.log('📝 SQL após adicionar filtro IN:', sql.substring(0, 200) + '...'); + console.log( + '🏢 Filtrando por códigos de centros de custo selecionados (filtro geral):', + codigosArray + ); + console.log( + '📝 SQL após adicionar filtro IN:', + sql.substring(0, 200) + '...' + ); } } else { - console.log('⚠️ Nenhum filtro de centro de custo aplicado - ambos estão vazios'); + console.log( + '⚠️ Nenhum filtro de centro de custo aplicado - ambos estão vazios' + ); } // Exclusão de centro de custo específico (quando desmarcado) @@ -147,19 +187,33 @@ export async function GET(request: NextRequest) { sql += ` ORDER BY DTVENC, CODFORNEC, CODCONTA`; // Log detalhado da query SQL final - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); console.log('🗄️ QUERY SQL FINAL:'); - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); console.log(sql); - console.log('═══════════════════════════════════════════════════════════════'); - console.log('📋 PARÂMETROS FINAIS (na ordem dos placeholders :1, :2, :3, ...):'); - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); + console.log( + '📋 PARÂMETROS FINAIS (na ordem dos placeholders :1, :2, :3, ...):' + ); + console.log( + '═══════════════════════════════════════════════════════════════' + ); params.forEach((param, index) => { console.log(` :${index + 1} = ${param} (${typeof param})`); }); - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); console.log('📊 RESUMO DOS FILTROS APLICADOS:'); - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); console.log({ temPeriodo: dataInicio && dataFim, periodo: dataInicio && dataFim ? `${dataInicio} a ${dataFim}` : 'N/A', @@ -178,60 +232,111 @@ export async function GET(request: NextRequest) { temExcluirCentroCusto: !!excluirCentroCusto, excluirCentroCusto: excluirCentroCusto || 'N/A', temExcluirCodigoConta: !!excluirCodigoConta, - excluirCodigoConta: excluirCodigoConta || 'N/A' + excluirCodigoConta: excluirCodigoConta || 'N/A', }); - console.log('═══════════════════════════════════════════════════════════════'); - + console.log( + '═══════════════════════════════════════════════════════════════' + ); + // Se há centroCusto individual, destacar especialmente if (centroCusto && centroCusto.trim() !== '') { - console.log('🎯 FILTRO INDIVIDUAL DE CENTRO DE CUSTO ATIVO (clique na célula)'); + console.log( + '🎯 FILTRO INDIVIDUAL DE CENTRO DE CUSTO ATIVO (clique na célula)' + ); console.log(` Centro de Custo: ${centroCusto}`); - console.log(' ⚠️ Este filtro tem PRIORIDADE sobre codigosCentrosCustoSelecionados'); + console.log( + ' ⚠️ Este filtro tem PRIORIDADE sobre codigosCentrosCustoSelecionados' + ); } - console.log('═══════════════════════════════════════════════════════════════'); + console.log( + '═══════════════════════════════════════════════════════════════' + ); const data = await executeOracleQuery(sql, params); - console.log('✅ Query executada com sucesso:', data.length, 'registros encontrados'); + console.log( + '✅ Query executada com sucesso:', + data.length, + 'registros encontrados' + ); console.log('📝 Primeiros 3 registros:', data.slice(0, 3)); // Transformar os dados do Oracle para o formato esperado pelo componente // Usando a view DESPESA_ENTIDADE_ANALITICO - const transformedData = data.map((item: any) => { + const transformedData = data.map((item: any, index: number) => { + // Gerar ID único: combinar NUMLANC com índice para garantir unicidade + // Se NUMLANC for null/undefined, usar índice + outros campos para criar ID único + const numLanc = + item.NUMLANC !== null && item.NUMLANC !== undefined + ? item.NUMLANC + : null; + const uniqueId = + numLanc !== null + ? `${numLanc}-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${index}` + : `row-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${item.DTVENC || ''}-${index}`; + return { - codigo_grupo: item.CODGRUPO || "", - codigo_subgrupo: item.SUBGRUPO || "", // SUBGRUPO existe na nova view - codigo_fornecedor: item.CODFORNEC || "", - nome_fornecedor: item.FORNECEDOR || "", - id: item.NUMLANC || 0, - codfilial: "001", // Valor padrão - recnum: item.NUMLANC || 0, - data_competencia: item.ANOMESCOMP || "", - data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", - 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 || "", + codigo_grupo: item.CODGRUPO || '', + codigo_subgrupo: item.SUBGRUPO || '', // SUBGRUPO existe na nova view + codigo_fornecedor: item.CODFORNEC || '', + nome_fornecedor: item.FORNECEDOR || '', + id: uniqueId, + codfilial: '001', // Valor padrão + recnum: numLanc !== null ? numLanc : index, + data_competencia: item.ANOMESCOMP || '', + data_vencimento: item.DTVENC + ? new Date(item.DTVENC).toISOString().split('T')[0] + : '', + 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 || '', created_at: new Date().toISOString(), updated_at: new Date().toISOString(), // Campos adicionais do Oracle - entidade: item.ENTIDADE || "", - tipo_parceiro: item.TIPOPARCEIRO || "", - valor_previsto: item.VLPREVISTO !== null && item.VLPREVISTO !== undefined ? Number(item.VLPREVISTO) : 0, - valor_confirmado: item.VLCONFIRMADO !== null && item.VLCONFIRMADO !== undefined ? Number(item.VLCONFIRMADO) : 0, - valor_pago: item.VLPAGO !== null && item.VLPAGO !== undefined ? Number(item.VLPAGO) : 0, + entidade: item.ENTIDADE || '', + tipo_parceiro: item.TIPOPARCEIRO || '', + valor_previsto: + item.VLPREVISTO !== null && item.VLPREVISTO !== undefined + ? Number(item.VLPREVISTO) + : 0, + valor_confirmado: + item.VLCONFIRMADO !== null && item.VLCONFIRMADO !== undefined + ? Number(item.VLCONFIRMADO) + : 0, + 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 || "", + ano_mes_comp: item.ANOMESCOMP || '', + 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] : "" + 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] + : '', }; }); @@ -239,7 +344,6 @@ export async function GET(request: NextRequest) { console.log('📝 Primeiros 3 transformados:', transformedData.slice(0, 3)); return NextResponse.json(transformedData); - } catch (error) { console.error('❌ Erro ao buscar dados analíticos do Oracle:', error); @@ -247,10 +351,9 @@ export async function GET(request: NextRequest) { { success: false, error: error instanceof Error ? error.message : 'Erro desconhecido', - details: error instanceof Error ? error.stack : undefined + details: error instanceof Error ? error.stack : undefined, }, { status: 500 } ); } } - diff --git a/src/app/api/analitico-filial-oracle/route.ts b/src/app/api/analitico-filial-oracle/route.ts index 6dae070..ec79692 100644 --- a/src/app/api/analitico-filial-oracle/route.ts +++ b/src/app/api/analitico-filial-oracle/route.ts @@ -235,15 +235,30 @@ WHERE 1=1`; // Transformar os dados do Oracle para o formato esperado pelo componente // Usando a view VB_DRE_FILIAL_DESPESA_ANALITICO - const transformedData = data.map((item: any) => { + const transformedData = data.map((item: any, index: number) => { + // Gerar ID único: combinar NUMLANC com índice para garantir unicidade + // Se NUMLANC for null/undefined, usar índice + outros campos para criar ID único + const numLanc = + item.NUMLANC !== null && item.NUMLANC !== undefined + ? item.NUMLANC + : null; + const uniqueId = + numLanc !== null + ? `${numLanc}-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${index}` + : `row-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${item.DTVENC || ''}-${index}`; + return { codigo_grupo: item.CODGRUPO || "", codigo_subgrupo: item.SUBGRUPO || "", // SUBGRUPO existe na nova view codigo_fornecedor: item.CODFORNEC || "", nome_fornecedor: item.FORNECEDOR || "", - id: item.NUMLANC || 0, + id: uniqueId, codfilial: item.CODFILIAL || item.FILIAL || "001", // Usar CODFILIAL do JOIN ou FILIAL da view - recnum: item.NUMLANC || 0, + recnum: numLanc !== null ? numLanc : index, data_competencia: item.ANOMESCOMP || "", data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", data_pagamento: item.DTPAGTO ? new Date(item.DTPAGTO).toISOString().split('T')[0] : "", diff --git a/src/app/api/analitico-oracle/route.ts b/src/app/api/analitico-oracle/route.ts index 8b3113f..2393f63 100644 --- a/src/app/api/analitico-oracle/route.ts +++ b/src/app/api/analitico-oracle/route.ts @@ -119,7 +119,7 @@ export async function GET(request: NextRequest) { console.log('📝 Primeiros 3 registros:', data.slice(0, 3)); // Transformar os dados do Oracle para o formato esperado pelo componente - const transformedData = data.map((item: any) => { + const transformedData = data.map((item: any, index: number) => { // Debug dos valores monetários // console.log('🔍 Item original:', { // VLREALIZADO: item.VLREALIZADO, @@ -129,14 +129,29 @@ export async function GET(request: NextRequest) { // tipo_VLREALIZADO: typeof item.VLREALIZADO // }); + // Gerar ID único: combinar NUMLANC com índice para garantir unicidade + // Se NUMLANC for null/undefined, usar índice + outros campos para criar ID único + const numLanc = + item.NUMLANC !== null && item.NUMLANC !== undefined + ? item.NUMLANC + : null; + const uniqueId = + numLanc !== null + ? `${numLanc}-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${index}` + : `row-${item.CODFORNEC || ''}-${item.CODCONTA || ''}-${ + item.CODIGOCENTROCUSTO || '' + }-${item.DTVENC || ''}-${index}`; + return { codigo_grupo: item.CODGRUPO || "", codigo_subgrupo: "", // Não existe na tabela Oracle codigo_fornecedor: item.CODFORNEC || "", nome_fornecedor: item.FORNECEDOR || "", - id: item.NUMLANC || 0, + id: uniqueId, codfilial: "001", // Valor padrão - recnum: item.NUMLANC || 0, + recnum: numLanc !== null ? numLanc : index, data_competencia: item.ANOMESCOMP || "", data_vencimento: item.DTVENC ? new Date(item.DTVENC).toISOString().split('T')[0] : "", data_pagamento: item.DTPAGTO ? new Date(item.DTPAGTO).toISOString().split('T')[0] : "", diff --git a/src/app/dre-entidade/analitico.tsx b/src/app/dre-entidade/analitico.tsx index 91289b3..1dc82c9 100644 --- a/src/app/dre-entidade/analitico.tsx +++ b/src/app/dre-entidade/analitico.tsx @@ -1,57 +1,70 @@ -"use client"; +'use client'; -import * as React from "react"; -import { DataGridPremium, GridToolbar, GridColDef, GridFilterModel } from "@mui/x-data-grid-premium"; +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Checkbox } from '@/components/ui/checkbox'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from '@/components/ui/drawer'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { + DataGridPremium, + GridColDef, + GridToolbar, +} from '@mui/x-data-grid-premium'; import { LicenseInfo } from '@mui/x-license-pro'; +import { + ArrowDown, + ArrowUp, + ArrowUpDown, + Download, + Maximize2, + Minimize2, + Search, + X, +} from 'lucide-react'; +import * as React from 'react'; +import * as XLSX from 'xlsx'; // Garantir que a licença seja aplicada no componente atualização de licença if (typeof window !== 'undefined') { try { - const PERPETUAL_LICENSE_KEY = 'e0d9bb8070ce0054c9d9ecb6e82cb58fTz0wLEU9MzI0NzIxNDQwMDAwMDAsUz1wcmVtaXVtLExNPXBlcnBldHVhbCxLVj0y'; + 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; + id: string | number; // Pode ser string (gerado pela API) ou number (legado) codfilial: string; recnum: number; data_competencia: string; @@ -119,8 +132,9 @@ const ExcelFilter: React.FC = ({ currentSort = null, }) => { const [isOpen, setIsOpen] = React.useState(false); - const [searchTerm, setSearchTerm] = React.useState(""); - const [selectedValues, setSelectedValues] = React.useState(currentFilter); + const [searchTerm, setSearchTerm] = React.useState(''); + const [selectedValues, setSelectedValues] = + React.useState(currentFilter); const [selectAll, setSelectAll] = React.useState(false); // Sincronizar selectedValues com currentFilter quando ele mudar @@ -133,10 +147,12 @@ const ExcelFilter: React.FC = ({ const values = filteredData .map((row) => { const value = row[column.field]; - if (value === null || value === undefined) return ""; + if (value === null || value === undefined) return ''; return String(value); }) - .filter((value, index, self) => self.indexOf(value) === index && value !== "") + .filter( + (value, index, self) => self.indexOf(value) === index && value !== '' + ) .sort(); return values; @@ -168,7 +184,9 @@ const ExcelFilter: React.FC = ({ newValues = selectedValues.filter((v) => v !== value); } setSelectedValues(newValues); - setSelectAll(newValues.length === filteredValues.length && filteredValues.length > 0); + setSelectAll( + newValues.length === filteredValues.length && filteredValues.length > 0 + ); }; const handleApply = () => { @@ -206,7 +224,7 @@ const ExcelFilter: React.FC = ({ Filtrar por "{column.headerName}" - +
{/* Opções de ordenação */}
@@ -218,8 +236,7 @@ const ExcelFilter: React.FC = ({ className="h-8 text-xs" onClick={() => handleSort('asc')} > - - A a Z + A a Z
@@ -269,13 +285,15 @@ const ExcelFilter: React.FC = ({ (Selecionar Tudo) - + {filteredValues.map((value) => (
handleValueToggle(value, checked)} + onCheckedChange={(checked: boolean) => + handleValueToggle(value, checked) + } />
- - + - - - {/* Conteúdo Principal - Versão Normal */} - {renderAnaliticoContent(false)} + {/* Conteúdo Principal - Versão Normal */} + {renderAnaliticoContent(false)} {/* Advanced Filters Dialog */} @@ -1273,7 +1414,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { Filtros Avançados

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

@@ -1300,10 +1442,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { {columns.map((col: any) => ( - + {col.headerName} ))} @@ -1320,8 +1459,8 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { onValueChange={(v: string) => { const next = [...conditions]; next[idx].operator = v; - if (v === "empty" || v === "notEmpty") - next[idx].value = ""; + if (v === 'empty' || v === 'notEmpty') + next[idx].value = ''; setConditions(next); }} > @@ -1339,7 +1478,9 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { - {!(cond.operator === "empty" || cond.operator === "notEmpty") && ( + {!( + cond.operator === 'empty' || cond.operator === 'notEmpty' + ) && (
+ )} {conditions.length > 1 && (
- + +
+ )} - )} - ))}
@@ -1381,7 +1522,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { onClick={() => setConditions((prev) => [ ...prev, - { column: "", operator: "contains", value: "" }, + { column: '', operator: 'contains', value: '' }, ]) } className="flex items-center gap-2 text-blue-600 hover:text-blue-700 hover:bg-blue-50 border-blue-200" @@ -1393,7 +1534,7 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) {
- - +
diff --git a/src/app/dre-filial/analitico.tsx b/src/app/dre-filial/analitico.tsx index 5cdab95..186d131 100644 --- a/src/app/dre-filial/analitico.tsx +++ b/src/app/dre-filial/analitico.tsx @@ -57,7 +57,7 @@ interface AnaliticoItem { codigo_subgrupo: string; codigo_fornecedor: string; nome_fornecedor: string; - id: number; + id: string | number; // Pode ser string (gerado pela API) ou number (legado) codfilial: string; recnum: number; data_competencia: string; @@ -501,10 +501,25 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { return filterValues.includes(stringValue); }); }) - .map((row, index) => ({ - ...row, - id: `filtered-${row.id || row.recnum || index}`, // Garantir ID único e estável - })); + .map((row, index) => { + // Garantir ID único: usar o id original se existir, senão criar baseado em recnum e índice + const originalId = + row.id !== null && row.id !== undefined + ? typeof row.id === 'string' && row.id !== '' + ? row.id + : String(row.id) + : null; + const recnumValue = + row.recnum !== null && row.recnum !== undefined ? row.recnum : null; + const uniqueId = originalId + ? `filtered-${originalId}` + : `filtered-${recnumValue !== null ? recnumValue : 'idx'}-${index}`; + + return { + ...row, + id: uniqueId, // Garantir ID único e estável (agora é string) + }; + }); }, [data, columnFilters]); // Função para renderizar header com filtro Excel @@ -1110,9 +1125,24 @@ export default function AnaliticoComponent({ filtros }: AnaliticoProps) { disableColumnSorting={true} pagination={false} disableVirtualization={false} - getRowId={(row: any) => - row.id || `row-${row.recnum || Math.random()}` - } + getRowId={(row: any) => { + // Usar verificação explícita para garantir que id seja usado mesmo se for string vazia + if ( + row.id !== null && + row.id !== undefined && + row.id !== '' + ) { + return String(row.id); + } + // Fallback: usar recnum se disponível, senão criar ID único + const recnumValue = + row.recnum !== null && row.recnum !== undefined + ? row.recnum + : null; + return recnumValue !== null + ? `row-${recnumValue}` + : `row-${Math.random()}-${Date.now()}`; + }} sx={{ height: '100%', width: '100%',