610 lines
19 KiB
Vue
610 lines
19 KiB
Vue
<template>
|
|
<section class="stack">
|
|
<h2>EliTabela</h2>
|
|
|
|
<!-- Exemplo: botão de ação "Novo" no cabeçalho que adiciona uma linha -->
|
|
<EliTabela :tabela="tabelaOk" :key="versaoTabelaOk" />
|
|
|
|
<EliTabela :tabela="tabelaVazia" />
|
|
|
|
<EliTabela :tabela="tabelaErro" />
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, ref } from "vue";
|
|
import { codigosResposta } from "p-respostas";
|
|
import { BadgeCheck, Eye, Pencil, Plus, Trash2 } from "lucide-vue-next";
|
|
import { celulaTabela, EliTabela } from "@/componentes/EliTabela";
|
|
import type { ComponenteEntrada } from "@/componentes/EliEntrada/tiposEntradas";
|
|
import type { tipoEliTabelaConsulta } from "@/componentes/EliTabela";
|
|
import type { tipoFiltro } from "@/componentes/EliTabela/types-eli-tabela";
|
|
|
|
type Linha = {
|
|
empreendedor: string;
|
|
empreendimento: string;
|
|
documento: string;
|
|
email: string;
|
|
telefone: string;
|
|
faturamento: number;
|
|
peso_kg: number;
|
|
criado_em: string;
|
|
atualizado_em: string;
|
|
};
|
|
|
|
export default defineComponent({
|
|
name: "TabelaPlayground",
|
|
components: { EliTabela },
|
|
setup() {
|
|
const acoesLinha: tipoEliTabelaConsulta<Linha>["acoesLinha"] = [
|
|
{
|
|
icone: Eye,
|
|
cor: "#2563eb",
|
|
rotulo: "Detalhes",
|
|
acao: (linha) => {
|
|
console.log("Visualizar detalhes de", linha.empreendedor);
|
|
},
|
|
},
|
|
{
|
|
icone: Trash2,
|
|
cor: "#dc2626",
|
|
rotulo: "Remover",
|
|
acao: (linha) => {
|
|
console.log("Remover cadastro de", linha.empreendedor);
|
|
},
|
|
exibir: (linha) => !linha.empreendimento.toLowerCase().includes("café"),
|
|
},
|
|
];
|
|
|
|
const linhasPadrao = ref<Linha[]>([
|
|
{
|
|
empreendedor: "Maria Silva",
|
|
empreendimento: "Doces da Maria",
|
|
documento: "12.345.678/0001-90",
|
|
email: "contato.comercial.super.longo@doces-da-maria-exemplo-muito-grande.com.br",
|
|
telefone: "(11) 91234-5678",
|
|
faturamento: 12500.5,
|
|
peso_kg: 12.4,
|
|
criado_em: "2026-01-09T16:15:00Z",
|
|
atualizado_em: "2026-01-29T15:30:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "João Pereira",
|
|
empreendimento: "Café Peregrino",
|
|
documento: "98.765.432/0001-12",
|
|
email: "contato@cafeperegrino.com",
|
|
telefone: "(11) 93456-7810",
|
|
faturamento: 8000,
|
|
peso_kg: 6.2,
|
|
criado_em: "2026-01-02T10:00:00-03:00",
|
|
atualizado_em: "2026-01-20T08:10:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Ana Costa",
|
|
empreendimento: "Flor de Sal Gastronomia",
|
|
documento: "45.678.912/0001-55",
|
|
email: "ana@flordesal.com",
|
|
telefone: "(21) 99876-5432",
|
|
faturamento: 3200.75,
|
|
peso_kg: 4.8,
|
|
criado_em: "2025-12-10T09:30:00-03:00",
|
|
atualizado_em: "2026-01-15T19:20:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Rafael Lima",
|
|
empreendimento: "Tech Agro Solutions",
|
|
documento: "07.654.321/0001-00",
|
|
email: "rafael@techagro.com",
|
|
telefone: "(31) 94567-8899",
|
|
faturamento: 15999.9,
|
|
peso_kg: 9.1,
|
|
criado_em: "2026-01-12T12:00:00-03:00",
|
|
atualizado_em: "2026-01-28T11:00:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Juliana Torres",
|
|
empreendimento: "Torres Moda Sustentável",
|
|
documento: "33.210.987/0001-44",
|
|
email: "juliana@torresmoda.com",
|
|
telefone: "(71) 97766-5544",
|
|
faturamento: 4500,
|
|
peso_kg: 3.3,
|
|
criado_em: "2026-01-01T00:00:00Z",
|
|
atualizado_em: "2026-01-10T13:45:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Marcos Vieira",
|
|
empreendimento: "Padaria Pão Quentinho",
|
|
documento: "21.109.876/0001-32",
|
|
email: "marcos@paoquentinho.com",
|
|
telefone: "(48) 99654-3210",
|
|
faturamento: 2200.4,
|
|
peso_kg: 15.7,
|
|
criado_em: "2026-01-05T07:25:00-03:00",
|
|
atualizado_em: "2026-01-23T20:15:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Bianca Rocha",
|
|
empreendimento: "Studio Beleza em Casa",
|
|
documento: "54.321.098/0001-21",
|
|
email: "contato@belezaemcasa.com",
|
|
telefone: "(85) 98877-1122",
|
|
faturamento: 990,
|
|
peso_kg: 1.9,
|
|
criado_em: "2026-01-03T14:00:00-03:00",
|
|
atualizado_em: "2026-01-29T09:00:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Caio Albuquerque",
|
|
empreendimento: "Albuquerque Engenharia Verde",
|
|
documento: "65.432.109/0001-09",
|
|
email: "caio@engenhariaverde.com",
|
|
telefone: "(61) 98123-4567",
|
|
faturamento: 100000,
|
|
peso_kg: 21.3,
|
|
criado_em: "2025-11-18T16:10:00-03:00",
|
|
atualizado_em: "2026-01-25T10:40:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Fernanda Almeida",
|
|
empreendimento: "Faz Bem Produtos Naturais",
|
|
documento: "87.654.210/0001-98",
|
|
email: "fernanda@fazbem.com",
|
|
telefone: "(41) 99777-6655",
|
|
faturamento: 5600.2,
|
|
peso_kg: 8.6,
|
|
criado_em: "2026-01-08T12:12:00-03:00",
|
|
atualizado_em: "2026-01-21T17:55:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Gabriel Martins",
|
|
empreendimento: "Martins Tech Repair",
|
|
documento: "19.876.543/0001-76",
|
|
email: "suporte@martinstech.com",
|
|
telefone: "(19) 98888-9090",
|
|
faturamento: 7550,
|
|
peso_kg: 7.7,
|
|
criado_em: "2026-01-11T11:00:00-03:00",
|
|
atualizado_em: "2026-01-18T11:30:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Helena Duarte",
|
|
empreendimento: "Ateliê Costura Criativa",
|
|
documento: "23.456.789/0001-65",
|
|
email: "helena@costuracriativa.com",
|
|
telefone: "(51) 98765-4433",
|
|
faturamento: 2700,
|
|
peso_kg: 2.5,
|
|
criado_em: "2026-01-07T08:00:00-03:00",
|
|
atualizado_em: "2026-01-16T14:10:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Igor Santos",
|
|
empreendimento: "Santos Consultoria Financeira",
|
|
documento: "43.219.876/0001-54",
|
|
email: "igor@santosconsultoria.com",
|
|
telefone: "(31) 99332-1100",
|
|
faturamento: 12000,
|
|
peso_kg: 5.4,
|
|
criado_em: "2026-01-06T10:30:00-03:00",
|
|
atualizado_em: "2026-01-22T18:30:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Jéssica Nunes",
|
|
empreendimento: "Nunes Eventos & Decoração",
|
|
documento: "09.876.543/0001-33",
|
|
email: "jessica@nunesdecora.com",
|
|
telefone: "(62) 99922-3344",
|
|
faturamento: 3300.1,
|
|
peso_kg: 4.1,
|
|
criado_em: "2026-01-04T13:30:00-03:00",
|
|
atualizado_em: "2026-01-26T09:20:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Leonardo Prado",
|
|
empreendimento: "Prado Bike Courier",
|
|
documento: "72.345.098/0001-27",
|
|
email: "contato@pradobike.com",
|
|
telefone: "(47) 98444-6677",
|
|
faturamento: 4100,
|
|
peso_kg: 6.8,
|
|
criado_em: "2026-01-02T18:40:00-03:00",
|
|
atualizado_em: "2026-01-27T12:00:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Marina Lopes",
|
|
empreendimento: "Lopes Design Digital",
|
|
documento: "56.789.012/0001-11",
|
|
email: "marina@lopesdesign.com",
|
|
telefone: "(27) 99911-2233",
|
|
faturamento: 2100,
|
|
peso_kg: 3.7,
|
|
criado_em: "2026-01-09T09:00:00-03:00",
|
|
atualizado_em: "2026-01-19T15:35:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Nicolas Teixeira",
|
|
empreendimento: "QualiVida Fitness",
|
|
documento: "34.567.890/0001-02",
|
|
email: "nicolas@qualivida.com",
|
|
telefone: "(92) 99456-7788",
|
|
faturamento: 8600.9,
|
|
peso_kg: 11.2,
|
|
criado_em: "2026-01-12T19:15:00-03:00",
|
|
atualizado_em: "2026-01-29T10:50:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Olívia Azevedo",
|
|
empreendimento: "Azevedo Pet Care",
|
|
documento: "88.901.234/0001-45",
|
|
email: "olivia@petcare.com",
|
|
telefone: "(16) 99788-6655",
|
|
faturamento: 1900.3,
|
|
peso_kg: 2.2,
|
|
criado_em: "2026-01-10T15:00:00-03:00",
|
|
atualizado_em: "2026-01-14T16:00:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Paulo Henrique",
|
|
empreendimento: "Henrique Soluções Elétricas",
|
|
documento: "44.556.778/0001-90",
|
|
email: "paulo@solucoeseletricas.com",
|
|
telefone: "(13) 98810-2020",
|
|
faturamento: 50000,
|
|
peso_kg: 17.9,
|
|
criado_em: "2026-01-13T10:10:00-03:00",
|
|
atualizado_em: "2026-01-24T21:00:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Renata Souza",
|
|
empreendimento: "Souza Traduções Especializadas",
|
|
documento: "11.223.344/0001-08",
|
|
email: "renata@souzatraducoes.com",
|
|
telefone: "(24) 99661-7788",
|
|
faturamento: 6400,
|
|
peso_kg: 9.9,
|
|
criado_em: "2026-01-08T07:00:00-03:00",
|
|
atualizado_em: "2026-01-28T09:05:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Tiago Moura",
|
|
empreendimento: "Moura Agro Sustentável",
|
|
documento: "78.912.345/0001-67",
|
|
email: "tiago@mouraagro.com",
|
|
telefone: "(68) 99999-4545",
|
|
faturamento: 7200,
|
|
peso_kg: 13.5,
|
|
criado_em: "2026-01-03T12:00:00-03:00",
|
|
atualizado_em: "2026-01-23T12:45:00-03:00",
|
|
},
|
|
{
|
|
empreendedor: "Viviane Castro",
|
|
empreendimento: "Castro Arte & Cerâmica",
|
|
documento: "32.165.498/0001-87",
|
|
email: "viviane@castroarte.com",
|
|
telefone: "(81) 98787-1212",
|
|
faturamento: 2800,
|
|
peso_kg: 4.6,
|
|
criado_em: "2026-01-01T09:00:00-03:00",
|
|
atualizado_em: "2026-01-17T09:30:00-03:00",
|
|
},
|
|
]);
|
|
|
|
// Incrementamos a chave para forçar o EliTabela a recarregar a consulta.
|
|
// (Como o componente não expõe um método público de refresh)
|
|
const versaoTabelaOk = ref(0);
|
|
|
|
function adicionarLinha() {
|
|
const proximo = linhasPadrao.value.length + 1;
|
|
|
|
linhasPadrao.value.unshift({
|
|
empreendedor: `Novo Empreendedor ${proximo}`,
|
|
empreendimento: `Novo Empreendimento ${proximo}`,
|
|
documento: "00.000.000/0000-00",
|
|
email: `novo${proximo}@exemplo.com`,
|
|
telefone: "(00) 90000-0000",
|
|
faturamento: 0,
|
|
peso_kg: 0,
|
|
criado_em: new Date().toISOString(),
|
|
atualizado_em: new Date().toISOString(),
|
|
});
|
|
|
|
versaoTabelaOk.value++;
|
|
}
|
|
|
|
|
|
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 compararOperador = (operador: string, valorLinha: any, valorFiltro: any): boolean => {
|
|
switch (operador) {
|
|
case "=":
|
|
return valorLinha == valorFiltro;
|
|
case "!=":
|
|
return valorLinha != valorFiltro;
|
|
case ">":
|
|
return Number(valorLinha) > Number(valorFiltro);
|
|
case ">=":
|
|
return Number(valorLinha) >= Number(valorFiltro);
|
|
case "<":
|
|
return Number(valorLinha) < Number(valorFiltro);
|
|
case "<=":
|
|
return Number(valorLinha) <= Number(valorFiltro);
|
|
case "like": {
|
|
const a = String(valorLinha ?? "").toLowerCase();
|
|
const b = String(valorFiltro ?? "").toLowerCase();
|
|
return a.includes(b);
|
|
}
|
|
case "in": {
|
|
const arr = Array.isArray(valorFiltro)
|
|
? valorFiltro
|
|
: String(valorFiltro ?? "")
|
|
.split(",")
|
|
.map((s) => s.trim())
|
|
.filter(Boolean);
|
|
return arr.includes(String(valorLinha));
|
|
}
|
|
case "isNull":
|
|
return valorLinha === null || valorLinha === undefined || valorLinha === "";
|
|
default:
|
|
return true;
|
|
}
|
|
};
|
|
|
|
const filtrarPorFiltrosAvancados = (linhas: Linha[], filtros?: tipoFiltro[]) => {
|
|
const lista = [...linhas];
|
|
if (!filtros?.length) return lista;
|
|
|
|
return lista.filter((linha: any) => {
|
|
return filtros.every((f) => {
|
|
const vLinha = linha?.[String((f as any).coluna)];
|
|
return compararOperador(String((f as any).operador), vLinha, (f as any).valor);
|
|
});
|
|
});
|
|
};
|
|
|
|
const ordenarLinhas = (linhas: Linha[], parametros?: { coluna_ordem?: keyof Linha; direcao_ordem?: "asc" | "desc" }) => {
|
|
if (!parametros?.coluna_ordem) return [...linhas];
|
|
|
|
const direcao = parametros.direcao_ordem ?? "asc";
|
|
const chave = parametros.coluna_ordem;
|
|
const multiplicador = direcao === "asc" ? 1 : -1;
|
|
|
|
return [...linhas].sort((a, b) => {
|
|
const valorA = a[chave];
|
|
const valorB = b[chave];
|
|
|
|
return (
|
|
multiplicador *
|
|
String(valorA ?? "").localeCompare(String(valorB ?? ""), "pt-BR", {
|
|
sensitivity: "base",
|
|
})
|
|
);
|
|
});
|
|
};
|
|
|
|
const tabelaOk: tipoEliTabelaConsulta<Linha> = {
|
|
nome: 'Exemplo',
|
|
registros_por_consulta: 10,
|
|
mostrarCaixaDeBusca: true,
|
|
acoesTabela: [
|
|
{
|
|
icone: Plus,
|
|
cor: "#16a34a",
|
|
rotulo: "Novo",
|
|
acao: adicionarLinha,
|
|
},
|
|
],
|
|
colunas: [
|
|
{
|
|
rotulo: "Empreendedor",
|
|
celula: (l) => celulaTabela('textoSimples', { texto: l.empreendedor }),
|
|
coluna_ordem: "empreendedor",
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Empreendimento",
|
|
celula: (l) => celulaTabela('textoSimples', { texto: l.empreendimento }),
|
|
coluna_ordem: "empreendimento",
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Documento",
|
|
celula: (l) => celulaTabela('textoSimples', { texto: l.documento }),
|
|
coluna_ordem: "documento",
|
|
visivel: false,
|
|
},
|
|
{
|
|
rotulo: "E-mail",
|
|
celula: (l) => celulaTabela('textoTruncado', {
|
|
texto: l.email, acao: () => {
|
|
// Exemplo de ação: poderia abrir detalhes
|
|
alert(`Clicou em ${l.email}`);
|
|
}
|
|
}),
|
|
coluna_ordem: "email",
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Telefone",
|
|
celula: (l) => celulaTabela('textoSimples', { texto: l.telefone }),
|
|
coluna_ordem: "telefone",
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Faturamento",
|
|
celula: (l) =>
|
|
celulaTabela("numero", {
|
|
numero: l.faturamento,
|
|
prefixo: "R$",
|
|
// Exemplo de ação (clicável)
|
|
acao: () => alert(`Faturamento de ${l.empreendedor}: R$ ${l.faturamento}`),
|
|
}),
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Peso",
|
|
celula: (l) =>
|
|
celulaTabela("numero", {
|
|
numero: l.peso_kg,
|
|
sufixo: "kg",
|
|
}),
|
|
visivel: false,
|
|
},
|
|
{
|
|
rotulo: "Status",
|
|
celula: (l) =>
|
|
celulaTabela("tags", {
|
|
opcoes: [
|
|
{
|
|
rotulo: "Ativo",
|
|
cor: "success",
|
|
icone: BadgeCheck,
|
|
},
|
|
{
|
|
rotulo: "Editar",
|
|
cor: "primary",
|
|
icone: Pencil,
|
|
acao: () => {
|
|
alert(`Editar ${l.empreendedor}`);
|
|
},
|
|
},
|
|
],
|
|
}),
|
|
visivel: true,
|
|
},
|
|
{
|
|
rotulo: "Criado em",
|
|
celula: (l) =>
|
|
celulaTabela("data", {
|
|
valor: l.criado_em,
|
|
formato: "data",
|
|
}),
|
|
visivel: false,
|
|
},
|
|
{
|
|
rotulo: "Atualizado",
|
|
celula: (l) =>
|
|
celulaTabela("data", {
|
|
valor: l.atualizado_em,
|
|
formato: "relativo",
|
|
acao: () => alert(`Atualizado em: ${l.atualizado_em}`),
|
|
}),
|
|
visivel: true,
|
|
},
|
|
],
|
|
acoesLinha: acoesLinha,
|
|
filtroAvancado: [
|
|
{
|
|
coluna: "empreendedor",
|
|
operador: "like",
|
|
entrada: ["texto", { rotulo: "Empreendedor" }] as ComponenteEntrada,
|
|
rotulo: 'Empreendedor'
|
|
},
|
|
{
|
|
coluna: "documento",
|
|
operador: "like",
|
|
entrada: ["texto", { rotulo: "Documento", formato: "cpfCnpj" }] as ComponenteEntrada,
|
|
'rotulo': 'Documento'
|
|
},
|
|
{
|
|
coluna: "email",
|
|
operador: "like",
|
|
entrada: ["texto", { rotulo: "E-mail", formato: "email" }] as ComponenteEntrada,
|
|
rotulo: 'E-mail'
|
|
},
|
|
],
|
|
consulta: async (parametrosConsulta) => {
|
|
// Agora a EliTabela envia paginação/ordenação/busca OU filtros avançados para a consulta.
|
|
// (busca tem prioridade; quando existe texto_busca, filtros não vêm no payload)
|
|
|
|
const limite = Math.max(1, Number(parametrosConsulta?.limit ?? 10));
|
|
const offset = Math.max(0, Number(parametrosConsulta?.offSet ?? 0));
|
|
|
|
// 1) filtra (busca OU filtro avançado)
|
|
const base = [...linhasPadrao.value];
|
|
const filtradas = parametrosConsulta?.texto_busca
|
|
? filtrarPorBusca(base, parametrosConsulta.texto_busca)
|
|
: filtrarPorFiltrosAvancados(base, (parametrosConsulta as any)?.filtros);
|
|
|
|
// 2) ordena
|
|
const ordenadas = ordenarLinhas(filtradas, parametrosConsulta);
|
|
|
|
// 3) pagina
|
|
const valores = ordenadas.slice(offset, offset + limite);
|
|
|
|
return {
|
|
cod: codigosResposta.sucesso,
|
|
eCerto: true,
|
|
eErro: false,
|
|
mensagem: undefined,
|
|
valor: {
|
|
quantidade: ordenadas.length,
|
|
valores,
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
const tabelaVazia: tipoEliTabelaConsulta<Linha> = {
|
|
nome: "Exemplo",
|
|
registros_por_consulta: tabelaOk.registros_por_consulta,
|
|
mostrarCaixaDeBusca: tabelaOk.mostrarCaixaDeBusca,
|
|
colunas: tabelaOk.colunas,
|
|
consulta: async (_parametrosConsulta) => {
|
|
return {
|
|
cod: codigosResposta.sucesso,
|
|
eCerto: true,
|
|
eErro: false,
|
|
mensagem: undefined,
|
|
valor: {
|
|
quantidade: 0,
|
|
valores: [],
|
|
},
|
|
};
|
|
},
|
|
mensagemVazio: "Nada para mostrar aqui.",
|
|
acoesLinha: acoesLinha,
|
|
};
|
|
|
|
const tabelaErro: tipoEliTabelaConsulta<Linha> = {
|
|
nome: "Exemplo",
|
|
registros_por_consulta: tabelaOk.registros_por_consulta,
|
|
mostrarCaixaDeBusca: tabelaOk.mostrarCaixaDeBusca,
|
|
colunas: tabelaOk.colunas,
|
|
acoesLinha: acoesLinha,
|
|
consulta: async (_parametrosConsulta) => {
|
|
return {
|
|
cod: codigosResposta.erroConhecido,
|
|
eCerto: false,
|
|
eErro: true,
|
|
mensagem: "Falha ao buscar dados",
|
|
valor: undefined,
|
|
};
|
|
},
|
|
};
|
|
|
|
return { tabelaOk, tabelaVazia, tabelaErro, versaoTabelaOk };
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.stack {
|
|
display: grid;
|
|
gap: 16px;
|
|
}
|
|
|
|
.stack :deep(.eli-tabela) {
|
|
max-width: 900px;
|
|
}
|
|
</style>
|