From df798df8d78caa57136ca4b686294f8ad2b0514d Mon Sep 17 00:00:00 2001 From: Luiz Silva Date: Tue, 27 Jan 2026 13:48:54 -0300 Subject: [PATCH] bkp --- src/components/eli/EliTabela/EliTabela.vue | 56 ++++++++- .../eli/EliTabela/EliTabelaCaixaDeBusca.vue | 116 ++++++++++++++++++ .../eli/EliTabela/types-eli-tabela.ts | 22 +++- src/playground/tabela.playground.vue | 33 +++-- 4 files changed, 213 insertions(+), 14 deletions(-) create mode 100644 src/components/eli/EliTabela/EliTabelaCaixaDeBusca.vue diff --git a/src/components/eli/EliTabela/EliTabela.vue b/src/components/eli/EliTabela/EliTabela.vue index f2b3c5f..f7689e7 100644 --- a/src/components/eli/EliTabela/EliTabela.vue +++ b/src/components/eli/EliTabela/EliTabela.vue @@ -8,6 +8,7 @@ import { computed, defineComponent, h, onBeforeUnmount, onMounted, PropType, ref import type { ComponentPublicInstance } from "vue"; import { ArrowDown, ArrowUp, MoreVertical } from "lucide-vue-next"; import { codigosResposta } from "p-respostas"; +import EliTabelaCaixaDeBusca from "./EliTabelaCaixaDeBusca.vue"; import EliTabelaPaginacao from "./EliTabelaPaginacao.vue"; import type { EliTabelaConsulta } from "./types-eli-tabela"; @@ -31,9 +32,11 @@ export default defineComponent({ const acoesVisiveis = ref([]); const menuAberto = ref(null); const menuElementos = new Map(); + const valorBusca = ref(""); const paginaAtual = ref(1); const colunaOrdenacao = ref(null); const direcaoOrdenacao = ref<"asc" | "desc">("asc"); + const exibirBusca = computed(() => Boolean(props.tabela.mostrarCaixaDeBusca)); const registrosPorConsulta = computed(() => { const valor = props.tabela.registros_por_consulta; if (typeof valor === "number" && valor > 0) { @@ -94,6 +97,18 @@ export default defineComponent({ } } + function atualizarBusca(texto: string) { + if (valorBusca.value === texto) { + return; + } + valorBusca.value = texto; + if (paginaAtual.value !== 1) { + paginaAtual.value = 1; + } else { + void carregar(); + } + } + function irParaPagina(pagina: number) { const alvo = Math.min(Math.max(1, pagina), totalPaginas.value); if (alvo !== paginaAtual.value) { @@ -174,11 +189,16 @@ export default defineComponent({ direcao_ordem?: "asc" | "desc"; offSet: number; limit: number; + texto_busca?: string; } = { offSet: offset, limit: limite, }; + if (valorBusca.value) { + parametrosConsulta.texto_busca = valorBusca.value; + } + if (colunaOrdenacao.value) { parametrosConsulta.coluna_ordem = colunaOrdenacao.value as never; parametrosConsulta.direcao_ordem = direcaoOrdenacao.value; @@ -215,7 +235,7 @@ export default defineComponent({ return; } - const acoes = tabelaConfig.acoes ?? []; + const acoes = tabelaConfig.acoesLinha ?? []; if (!acoes.length) { acoesVisiveis.value = []; @@ -284,6 +304,20 @@ export default defineComponent({ void carregar(); }); + watch( + () => props.tabela.mostrarCaixaDeBusca, + (mostrar) => { + if (!mostrar && valorBusca.value) { + valorBusca.value = ""; + if (paginaAtual.value !== 1) { + paginaAtual.value = 1; + } else { + void carregar(); + } + } + } + ); + watch(paginaAtual, (nova, antiga) => { if (nova !== antiga) { void carregar(); @@ -301,6 +335,7 @@ export default defineComponent({ menuElementos.clear(); colunaOrdenacao.value = null; direcaoOrdenacao.value = "asc"; + valorBusca.value = ""; if (paginaAtual.value !== 1) { paginaAtual.value = 1; } else { @@ -337,7 +372,7 @@ export default defineComponent({ } const colunas = tabela.colunas; - const acoes = tabela.acoes ?? []; + const acoes = tabela.acoesLinha ?? []; const temAcoes = acoes.length > 0; if (!linhas.value.length) { @@ -408,7 +443,18 @@ export default defineComponent({ ); } - const conteudoTabela = [ + const conteudoTabela: ReturnType[] = []; + + if (exibirBusca.value) { + conteudoTabela.push( + h(EliTabelaCaixaDeBusca, { + modelo: valorBusca.value, + onBuscar: atualizarBusca, + }) + ); + } + + conteudoTabela.push( h("table", { class: "eli-tabela__table" }, [ h( "thead", @@ -583,8 +629,8 @@ export default defineComponent({ ); }) ), - ]), - ]; + ]) + ); if (totalPaginas.value > 1 && quantidade.value > 0) { conteudoTabela.push( diff --git a/src/components/eli/EliTabela/EliTabelaCaixaDeBusca.vue b/src/components/eli/EliTabela/EliTabelaCaixaDeBusca.vue new file mode 100644 index 0000000..2e62dd0 --- /dev/null +++ b/src/components/eli/EliTabela/EliTabelaCaixaDeBusca.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/components/eli/EliTabela/types-eli-tabela.ts b/src/components/eli/EliTabela/types-eli-tabela.ts index 811dddc..8a88142 100644 --- a/src/components/eli/EliTabela/types-eli-tabela.ts +++ b/src/components/eli/EliTabela/types-eli-tabela.ts @@ -46,8 +46,11 @@ export type EliTabelaAcao = { * * - `colunas`: definição de colunas e como renderizar cada célula * - `consulta`: função que recupera os dados, com suporte a ordenação/paginação + * - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho */ export type EliTabelaConsulta = { + /** Indica se a caixa de busca deve ser exibida acima da tabela. */ + mostrarCaixaDeBusca?: boolean; /** Lista de colunas da tabela. */ colunas: EliColuna[]; /** Quantidade de registros solicitados por consulta (padrão `10`). */ @@ -61,11 +64,28 @@ export type EliTabelaConsulta = { direcao_ordem?: "asc" | "desc"; offSet?: number; limit?: number; + /** Texto digitado na caixa de busca, quando habilitada. */ + texto_busca?: string; }) => Promise>>; /** Quantidade máxima de botões exibidos na paginação (padrão `7`). */ maximo_botoes_paginacao?: number; /** Mensagem exibida quando a consulta retorna ok porém sem dados. */ mensagemVazio?: string; /** Ações exibidas à direita de cada linha. */ - acoes?: EliTabelaAcao[]; + acoesLinha?: EliTabelaAcao[]; + + + /** configurações do botões que serão inseridos a direta da caixa de busca, seu uso mais como será para criar novo regitros, mas poderá ter outras utilidades */ + + acoesTabela?: { + + /** Ícone (Lucide) exibido no botão */ + icone?: LucideIcon; + /** Cor aplicada ao botão. */ + cor?: string; + /** Texto descritivo da ação. */ + rotulo: string; + /** Função executada ao clicar no botão. */ + acao: () => void; + }[]; }; diff --git a/src/playground/tabela.playground.vue b/src/playground/tabela.playground.vue index a45a0e1..559c922 100644 --- a/src/playground/tabela.playground.vue +++ b/src/playground/tabela.playground.vue @@ -29,7 +29,7 @@ export default defineComponent({ name: "TabelaPlayground", components: { EliTabela }, setup() { - const acoesTabela: EliTabelaConsulta["acoes"] = [ + const acoesTabela: EliTabelaConsulta["acoesLinha"] = [ { icone: Eye, cor: "#2563eb", @@ -200,19 +200,33 @@ export default defineComponent({ ]; + const filtrarPorBusca = (linhas: Linha[], texto?: string) => { + const termo = texto?.trim().toLowerCase(); + if (!termo) { + return [...linhas]; + } + + return linhas.filter((linha) => { + const campos = [linha.empreendedor, linha.empreendimento]; + return campos.some((valor) => valor.toLowerCase().includes(termo)); + }); + }; + const ordenarLinhas = ( linhas: Linha[], - parametros?: { coluna_ordem?: keyof Linha; direcao_ordem?: "asc" | "desc" } + parametros?: { coluna_ordem?: keyof Linha; direcao_ordem?: "asc" | "desc"; texto_busca?: string } ) => { + const listaFiltrada = filtrarPorBusca(linhas, parametros?.texto_busca); + if (!parametros?.coluna_ordem) { - return [...linhas]; + return listaFiltrada; } const direcao = parametros.direcao_ordem ?? "asc"; const chave = parametros.coluna_ordem; const multiplicador = direcao === "asc" ? 1 : -1; - return [...linhas].sort((a, b) => { + return [...listaFiltrada].sort((a, b) => { const valorA = a[chave]; const valorB = b[chave]; @@ -241,6 +255,7 @@ export default defineComponent({ const tabelaOk: EliTabelaConsulta = { registros_por_consulta: 10, + mostrarCaixaDeBusca: true, colunas: [ { rotulo: "Empreendedor", @@ -272,7 +287,7 @@ export default defineComponent({ coluna_ordem: "telefone", }, ], - acoes: acoesTabela, + acoesLinha: acoesTabela, consulta: async (parametrosConsulta) => { const ordenadas = ordenarLinhas(linhasPadrao, parametrosConsulta); const valores = aplicarPaginacao(ordenadas, parametrosConsulta); @@ -283,7 +298,7 @@ export default defineComponent({ eErro: false, mensagem: undefined, valor: { - quantidade: linhasPadrao.length, + quantidade: ordenadas.length, valores, }, }; @@ -292,6 +307,7 @@ export default defineComponent({ const tabelaVazia: EliTabelaConsulta = { registros_por_consulta: tabelaOk.registros_por_consulta, + mostrarCaixaDeBusca: tabelaOk.mostrarCaixaDeBusca, colunas: tabelaOk.colunas, consulta: async (_parametrosConsulta) => { return { @@ -306,13 +322,14 @@ export default defineComponent({ }; }, mensagemVazio: "Nada para mostrar aqui.", - acoes: acoesTabela, + acoesLinha: acoesTabela, }; const tabelaErro: EliTabelaConsulta = { registros_por_consulta: tabelaOk.registros_por_consulta, + mostrarCaixaDeBusca: tabelaOk.mostrarCaixaDeBusca, colunas: tabelaOk.colunas, - acoes: acoesTabela, + acoesLinha: acoesTabela, consulta: async (_parametrosConsulta) => { return { cod: codigosResposta.erroConhecido,