434 lines
12 KiB
Vue
434 lines
12 KiB
Vue
<template>
|
|
<section class="stack">
|
|
<h2>EliTabela</h2>
|
|
|
|
<!-- Exemplo: botão de ação "Novo" no cabeçalho que adiciona uma linha -->
|
|
<div style="margin-bottom: 12px">
|
|
<strong>Selecionados:</strong> {{ selecionados.map(s => s.empreendedor).join(', ') || 'Nenhum' }}
|
|
</div>
|
|
<EliTabela :tabela="tabelaOk" :key="versaoTabelaOk" v-model:selecionados="selecionados" />
|
|
|
|
<EliTabela :tabela="tabelaVazia" />
|
|
|
|
<EliTabela :tabela="tabelaErro" />
|
|
|
|
<!-- Modal de simulação de cadastro -->
|
|
<v-dialog v-model="mostrarModalCadastro" max-width="500px">
|
|
<v-card>
|
|
<v-card-title>Novo Cadastro</v-card-title>
|
|
<v-card-text>
|
|
<v-alert
|
|
v-if="erroCadastro"
|
|
type="error"
|
|
variant="tonal"
|
|
density="compact"
|
|
class="mb-4"
|
|
>
|
|
{{ erroCadastro }}
|
|
</v-alert>
|
|
<v-text-field
|
|
v-model="novoCadastro.empreendedor"
|
|
label="Empreendedor"
|
|
variant="outlined"
|
|
density="compact"
|
|
class="mb-2"
|
|
></v-text-field>
|
|
<v-text-field
|
|
v-model="novoCadastro.empreendimento"
|
|
label="Empreendimento"
|
|
variant="outlined"
|
|
density="compact"
|
|
></v-text-field>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
color="grey-darken-1"
|
|
variant="text"
|
|
@click="mostrarModalCadastro = false"
|
|
:disabled="salvando"
|
|
>
|
|
Cancelar
|
|
</v-btn>
|
|
<v-btn
|
|
color="primary"
|
|
variant="elevated"
|
|
@click="salvarNovoCadastro"
|
|
:loading="salvando"
|
|
>
|
|
Salvar
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { BadgeCheck, Eye, Pencil, Plus, Trash2 } from "@lucide/vue"
|
|
import { criarFiltro26, type tipoFiltro26 } from "p-comuns"
|
|
import { codigosResposta } from "p-respostas"
|
|
import { defineComponent, ref } from "vue"
|
|
import type { ComponenteEntrada } from "@/componentes/EliEntrada/tiposEntradas"
|
|
import type { tipoEliTabelaConsulta } from "@/componentes/EliTabela"
|
|
import { celulaTabela, EliTabela } from "@/componentes/EliTabela"
|
|
|
|
import { api_criar, api_deletar, api_ler, type Linha } from "./api_simulador"
|
|
|
|
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) => {
|
|
removerCadastro(linha)
|
|
},
|
|
exibir: (linha) => !linha.empreendimento.toLowerCase().includes("café"),
|
|
},
|
|
]
|
|
|
|
const versaoTabelaOk = ref(0)
|
|
const selecionados = ref<Linha[]>([])
|
|
const mostrarModalCadastro = ref(false)
|
|
const salvando = ref(false)
|
|
const novoCadastro = ref({
|
|
empreendedor: "",
|
|
empreendimento: "",
|
|
documento: "",
|
|
email: "",
|
|
telefone: "",
|
|
faturamento: 0,
|
|
peso_kg: 0,
|
|
})
|
|
const erroCadastro = ref<string | undefined>(undefined)
|
|
|
|
// Armazena a função de atualização da tabela atual (vinda da ação do cabeçalho)
|
|
let atualizarTabelaCallback: (() => Promise<void>) | undefined
|
|
|
|
// A ação do cabeçalho recebe { atualizarConsulta, editarLista, ... }
|
|
// biome-ignore lint/suspicious/noExplicitAny: playground
|
|
function abrirModalCadastro(params?: any) {
|
|
if (params?.atualizarConsulta) {
|
|
atualizarTabelaCallback = params.atualizarConsulta
|
|
}
|
|
|
|
novoCadastro.value = {
|
|
empreendedor: "",
|
|
empreendimento: "",
|
|
documento: "",
|
|
email: "",
|
|
telefone: "",
|
|
faturamento: 0,
|
|
peso_kg: 0,
|
|
}
|
|
erroCadastro.value = undefined
|
|
mostrarModalCadastro.value = true
|
|
}
|
|
|
|
async function salvarNovoCadastro() {
|
|
salvando.value = true
|
|
erroCadastro.value = undefined
|
|
try {
|
|
const resposta = await api_criar(novoCadastro.value)
|
|
if (resposta.eErro) {
|
|
erroCadastro.value = resposta.mensagem
|
|
return
|
|
}
|
|
|
|
// PADRÃO RECOMENDADO:
|
|
// Se temos o callback de atualização, usamos ele para recarregar os dados na tabela
|
|
// sem precisar remontar o componente (sem alterar key).
|
|
if (atualizarTabelaCallback) {
|
|
await atualizarTabelaCallback()
|
|
} else {
|
|
// Fallback (caso não tenha vindo pela ação da tabela): força re-render
|
|
versaoTabelaOk.value++
|
|
}
|
|
|
|
mostrarModalCadastro.value = false
|
|
} catch (e) {
|
|
erroCadastro.value = String(e)
|
|
} finally {
|
|
salvando.value = false
|
|
}
|
|
}
|
|
|
|
function removerCadastro(linha: Linha) {
|
|
// Exemplo de uso do api_deletar
|
|
// Não temos um ID único confiável além das propriedades, vamos usar empreendedor como chave neste exemplo simples
|
|
if (confirm(`Tem certeza que deseja remover ${linha.empreendedor}?`)) {
|
|
api_deletar("empreendedor", linha.empreendedor).then(() => {
|
|
versaoTabelaOk.value++
|
|
})
|
|
}
|
|
}
|
|
|
|
const tabelaOk: tipoEliTabelaConsulta<Linha> = {
|
|
nome: "ExemploPlaygroundData",
|
|
registros_por_consulta: 10,
|
|
mostrarCaixaDeBusca: true,
|
|
mostrar_selecao: true,
|
|
chave_selecao: "empreendedor",
|
|
acoesTabela: [
|
|
{
|
|
posicao: "superior",
|
|
icone: Plus,
|
|
cor: "#16a34a",
|
|
rotulo: "Novo (Superior)",
|
|
acao: abrirModalCadastro,
|
|
},
|
|
{
|
|
posicao: "inferior",
|
|
icone: Plus,
|
|
cor: "#2563eb",
|
|
rotulo: "Novo (Inferior)",
|
|
acao: abrirModalCadastro,
|
|
},
|
|
],
|
|
|
|
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: [
|
|
{
|
|
chave: "empreendedor",
|
|
rotulo: "Empreendedor",
|
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
filtro: (valor: unknown) =>
|
|
criarFiltro26({
|
|
// biome-ignore lint/suspicious/noExplicitAny: playground
|
|
empreendedor: { like: valor as string } as any,
|
|
}) as tipoFiltro26<Linha>,
|
|
entrada: ["texto", { rotulo: "Empreendedor" }] as ComponenteEntrada,
|
|
},
|
|
{
|
|
chave: "documento",
|
|
rotulo: "Documento",
|
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
filtro: (valor: string) =>
|
|
criarFiltro26({
|
|
// biome-ignore lint/suspicious/noExplicitAny: playground
|
|
documento: { like: valor as string } as any,
|
|
}) as tipoFiltro26<Linha>,
|
|
entrada: [
|
|
"texto",
|
|
{ rotulo: "Documento", formato: "cpfCnpj" },
|
|
] as ComponenteEntrada,
|
|
},
|
|
{
|
|
chave: "email",
|
|
rotulo: "E-mail",
|
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
filtro: (valor: string) =>
|
|
criarFiltro26({
|
|
// biome-ignore lint/suspicious/noExplicitAny: playground
|
|
email: { like: valor as string } as any,
|
|
}) as tipoFiltro26<Linha>,
|
|
entrada: [
|
|
"texto",
|
|
{ rotulo: "E-mail", formato: "email" },
|
|
] as ComponenteEntrada,
|
|
},
|
|
],
|
|
consulta: async (parametrosConsulta) => {
|
|
try {
|
|
const resposta = await api_ler(parametrosConsulta)
|
|
return {
|
|
cod: codigosResposta.sucesso,
|
|
eCerto: true,
|
|
eErro: false,
|
|
mensagem: undefined,
|
|
valor: {
|
|
quantidade: resposta.total,
|
|
valores: resposta.dados,
|
|
},
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
cod: codigosResposta.erroConhecido,
|
|
eCerto: false,
|
|
eErro: true,
|
|
mensagem: String(error),
|
|
valor: undefined,
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
const tabelaVazia: tipoEliTabelaConsulta<Linha> = {
|
|
nome: "Exemplo Vazio",
|
|
registros_por_consulta: 10,
|
|
mostrarCaixaDeBusca: true,
|
|
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,
|
|
mostrarModalCadastro,
|
|
salvando,
|
|
novoCadastro,
|
|
salvarNovoCadastro,
|
|
erroCadastro,
|
|
selecionados,
|
|
}
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.stack {
|
|
display: grid;
|
|
gap: 16px;
|
|
}
|
|
|
|
.stack :deep(.eli-tabela) {
|
|
max-width: 900px;
|
|
}
|
|
</style>
|