implementado filtro26
This commit is contained in:
parent
ba0e116a92
commit
5124844773
18 changed files with 3247 additions and 3257 deletions
|
|
@ -193,14 +193,12 @@ export default defineComponent({
|
|||
|
||||
/** Filtro avançado (config + estado modal) */
|
||||
const modalFiltroAberto = ref(false)
|
||||
type LinhaFiltroUI<T> = {
|
||||
coluna: keyof T
|
||||
type LinhaFiltroUI = {
|
||||
chave: string
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
||||
valor: any
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic ui
|
||||
const filtrosUi = ref<Array<LinhaFiltroUI<any>>>(
|
||||
const filtrosUi = ref<Array<LinhaFiltroUI>>(
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic load
|
||||
carregarFiltroAvancado<any>(props.tabela.nome) as any,
|
||||
)
|
||||
|
|
@ -238,29 +236,23 @@ export default defineComponent({
|
|||
else void carregar()
|
||||
}
|
||||
|
||||
const filtrosAvancadosAtivos = computed<tipoFiltro[]>(() => {
|
||||
// Operador vem travado na definição (`tabela.filtroAvancado`).
|
||||
const base = (props.tabela.filtroAvancado ?? []) as Array<{
|
||||
coluna: string
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic operator
|
||||
operador: any
|
||||
}>
|
||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
||||
const filtrosAvancadosAtivos = computed<tipoFiltro<any>[]>(() => {
|
||||
const base = props.tabela.filtroAvancado ?? []
|
||||
|
||||
return (filtrosUi.value ?? [])
|
||||
.filter((f) => f && f.coluna !== undefined)
|
||||
.map((f) => {
|
||||
const b = base.find((x) => String(x.coluna) === String(f.coluna))
|
||||
if (!b) return null
|
||||
return (
|
||||
(filtrosUi.value ?? [])
|
||||
.filter((f) => f && f.chave !== undefined)
|
||||
.map((f) => {
|
||||
const b = base.find((x) => String(x.chave) === String(f.chave))
|
||||
if (!b) return null
|
||||
|
||||
return {
|
||||
coluna: String(b.coluna),
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic operator
|
||||
operador: b.operador as any,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
||||
valor: (f as any).valor,
|
||||
} as tipoFiltro
|
||||
})
|
||||
.filter(Boolean) as tipoFiltro[]
|
||||
// O filtro já vem pronto da função definida na configuração
|
||||
return b.filtro(f.valor)
|
||||
})
|
||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
||||
.filter(Boolean) as tipoFiltro<any>[]
|
||||
)
|
||||
})
|
||||
|
||||
/** Alias reativo da prop tabela */
|
||||
|
|
@ -647,7 +639,8 @@ export default defineComponent({
|
|||
const offset = (paginaAtual.value - 1) * limite
|
||||
|
||||
const parametrosConsulta: {
|
||||
filtros?: tipoFiltro[]
|
||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
||||
filtros?: tipoFiltro<any>[]
|
||||
coluna_ordem?: never
|
||||
direcao_ordem?: "asc" | "desc"
|
||||
offSet: number
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@
|
|||
</div>
|
||||
|
||||
<div v-else class="eli-tabela-modal-filtro__lista">
|
||||
<div v-for="(linha, idx) in linhas" :key="String(linha.coluna)" class="eli-tabela-modal-filtro__linha">
|
||||
<div v-for="(linha, idx) in linhas" :key="String(linha.chave)" class="eli-tabela-modal-filtro__linha">
|
||||
<div class="eli-tabela-modal-filtro__entrada">
|
||||
<component
|
||||
:is="componenteEntrada(linha.entrada)"
|
||||
v-model:value="linha.valor"
|
||||
:value="linha.valor"
|
||||
@update:value="(v: any) => (linha.valor = v)"
|
||||
@input="(v: any) => (linha.valor = v)"
|
||||
:opcoes="opcoesEntrada(linha.entrada)"
|
||||
density="compact"
|
||||
/>
|
||||
|
|
@ -38,12 +40,12 @@
|
|||
|
||||
<div class="eli-tabela-modal-filtro__acoes">
|
||||
<select
|
||||
v-model="colunaParaAdicionar"
|
||||
v-model="chaveParaAdicionar"
|
||||
class="eli-tabela-modal-filtro__select"
|
||||
:disabled="!opcoesParaAdicionar.length"
|
||||
>
|
||||
<option disabled value="">Selecione um filtro…</option>
|
||||
<option v-for="o in opcoesParaAdicionar" :key="String(o.coluna)" :value="String(o.coluna)">
|
||||
<option v-for="o in opcoesParaAdicionar" :key="String(o.chave)" :value="String(o.chave)">
|
||||
{{ rotuloDoFiltro(o) }}
|
||||
</option>
|
||||
</select>
|
||||
|
|
@ -51,7 +53,7 @@
|
|||
type="button"
|
||||
class="eli-tabela-modal-filtro__botao"
|
||||
@click="adicionar"
|
||||
:disabled="!colunaParaAdicionar"
|
||||
:disabled="!chaveParaAdicionar"
|
||||
>
|
||||
Adicionar
|
||||
</button>
|
||||
|
|
@ -80,33 +82,23 @@ import {
|
|||
EliEntradaNumero,
|
||||
EliEntradaTexto,
|
||||
} from "../EliEntrada"
|
||||
import type {
|
||||
ComponenteEntrada,
|
||||
TipoEntrada,
|
||||
} from "../EliEntrada/tiposEntradas"
|
||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas"
|
||||
import type { tipoEliTabelaConsulta } from "./types-eli-tabela"
|
||||
|
||||
type FiltroBase<T> = NonNullable<
|
||||
tipoEliTabelaConsulta<T>["filtroAvancado"]
|
||||
>[number]
|
||||
|
||||
type LinhaFiltro<T> = {
|
||||
coluna: keyof T
|
||||
type LinhaFiltro = {
|
||||
chave: string
|
||||
entrada: ComponenteEntrada
|
||||
operador: string
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
||||
valor: any
|
||||
}
|
||||
|
||||
function isTipoEntrada(v: unknown): v is TipoEntrada {
|
||||
return v === "texto" || v === "numero" || v === "dataHora"
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
||||
function rotuloDoFiltro(f: FiltroBase<any>) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic access
|
||||
const rotulo = (f?.entrada?.[1] as any)?.rotulo
|
||||
return rotulo ? String(rotulo) : String(f?.coluna ?? "Filtro")
|
||||
return f.rotulo
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -114,7 +106,7 @@ export default defineComponent({
|
|||
props: {
|
||||
aberto: { type: Boolean, required: true },
|
||||
filtrosBase: {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic filter type
|
||||
// biome-ignore lint/suspicious/noExplicitAny: generic component
|
||||
type: Array as PropType<Array<FiltroBase<any>>>,
|
||||
required: true,
|
||||
},
|
||||
|
|
@ -131,19 +123,18 @@ export default defineComponent({
|
|||
salvar: (_linhas: any[]) => true,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
||||
const linhas = ref<Array<LinhaFiltro<any>>>([])
|
||||
const linhas = ref<Array<LinhaFiltro>>([])
|
||||
|
||||
const colunaParaAdicionar = ref<string>("")
|
||||
const chaveParaAdicionar = ref<string>("")
|
||||
|
||||
const colunasDisponiveis = computed(() =>
|
||||
(props.filtrosBase ?? []).map((b) => String(b.coluna)),
|
||||
const chavesDisponiveis = computed(() =>
|
||||
(props.filtrosBase ?? []).map((b) => String(b.chave)),
|
||||
)
|
||||
|
||||
const opcoesParaAdicionar = computed(() => {
|
||||
const usadas = new Set(linhas.value.map((l) => String(l.coluna)))
|
||||
const usadas = new Set(linhas.value.map((l) => String(l.chave)))
|
||||
return (props.filtrosBase ?? []).filter(
|
||||
(b) => !usadas.has(String(b.coluna)),
|
||||
(b) => !usadas.has(String(b.chave)),
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -169,42 +160,30 @@ export default defineComponent({
|
|||
function normalizarModelo() {
|
||||
const base = props.filtrosBase ?? []
|
||||
const modelo = Array.isArray(props.modelo) ? props.modelo : []
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic model
|
||||
linhas.value = modelo.map((m: any) => {
|
||||
// operador vem travado no base
|
||||
const baseItem =
|
||||
base.find((b) => String(b.coluna) === String(m.coluna)) ?? base[0]
|
||||
const entrada = (baseItem?.entrada ?? m.entrada) as ComponenteEntrada
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
||||
const col = (baseItem?.coluna ?? m.coluna) as any
|
||||
const op = String(baseItem?.operador ?? "=")
|
||||
const val = m.valor ?? valorInicialPorEntrada(entrada)
|
||||
linhas.value = modelo
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic model item
|
||||
.map((m: any) => {
|
||||
const baseItem =
|
||||
base.find((b) => String(b.chave) === String(m.chave)) ?? base[0]
|
||||
|
||||
return {
|
||||
coluna: col,
|
||||
operador: op,
|
||||
entrada,
|
||||
valor: val,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic cast
|
||||
} as LinhaFiltro<any>
|
||||
})
|
||||
if (!baseItem) return null
|
||||
|
||||
// se vazio e existe base, adiciona 1 linha default
|
||||
// não auto-adiciona; usuário escolhe quais filtros quer usar
|
||||
const entrada = (baseItem.entrada ?? m.entrada) as ComponenteEntrada
|
||||
const chave = String(baseItem.chave ?? m.chave)
|
||||
const val = m.valor ?? valorInicialPorEntrada(entrada)
|
||||
|
||||
// se algum filtro mudou a coluna para valor inválido, ajusta
|
||||
for (const l of linhas.value) {
|
||||
if (!colunasDisponiveis.value.includes(String(l.coluna))) continue
|
||||
l.operador = String(
|
||||
base.find((b) => String(b.coluna) === String(l.coluna))?.operador ??
|
||||
"=",
|
||||
)
|
||||
// sanity
|
||||
if (l.entrada && !isTipoEntrada(l.entrada[0])) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic sanity
|
||||
l.entrada = ["texto", { rotulo: "Valor" }] as any
|
||||
}
|
||||
}
|
||||
return {
|
||||
chave: chave,
|
||||
entrada,
|
||||
valor: val,
|
||||
} as LinhaFiltro
|
||||
})
|
||||
.filter(Boolean) as LinhaFiltro[]
|
||||
|
||||
// se algum filtro mudou a chave para valor inválido, ajusta
|
||||
linhas.value = linhas.value.filter((l) =>
|
||||
chavesDisponiveis.value.includes(String(l.chave)),
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
|
|
@ -216,24 +195,21 @@ export default defineComponent({
|
|||
)
|
||||
|
||||
function adicionar() {
|
||||
if (!colunaParaAdicionar.value) return
|
||||
if (!chaveParaAdicionar.value) return
|
||||
const b0 = (props.filtrosBase ?? []).find(
|
||||
(b) => String(b.coluna) === String(colunaParaAdicionar.value),
|
||||
(b) => String(b.chave) === String(chaveParaAdicionar.value),
|
||||
)
|
||||
if (!b0) return
|
||||
// evita repetição
|
||||
if (linhas.value.some((l) => String(l.coluna) === String(b0.coluna)))
|
||||
return
|
||||
if (linhas.value.some((l) => String(l.chave) === String(b0.chave))) return
|
||||
|
||||
linhas.value.push({
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
||||
coluna: b0.coluna as any,
|
||||
chave: String(b0.chave),
|
||||
entrada: b0.entrada,
|
||||
operador: String(b0.operador ?? "="),
|
||||
valor: valorInicialPorEntrada(b0.entrada),
|
||||
})
|
||||
|
||||
colunaParaAdicionar.value = ""
|
||||
chaveParaAdicionar.value = ""
|
||||
}
|
||||
|
||||
function remover(idx: number) {
|
||||
|
|
@ -252,7 +228,7 @@ export default defineComponent({
|
|||
emit(
|
||||
"salvar",
|
||||
linhas.value.map((l) => ({
|
||||
coluna: l.coluna,
|
||||
chave: l.chave,
|
||||
valor: l.valor,
|
||||
})),
|
||||
)
|
||||
|
|
@ -261,12 +237,11 @@ export default defineComponent({
|
|||
return {
|
||||
linhas,
|
||||
opcoesParaAdicionar,
|
||||
colunaParaAdicionar,
|
||||
chaveParaAdicionar,
|
||||
componenteEntrada,
|
||||
opcoesEntrada,
|
||||
adicionar,
|
||||
remover,
|
||||
// exibimos operador fixo só como texto
|
||||
emitFechar,
|
||||
emitSalvar,
|
||||
emitLimpar,
|
||||
|
|
|
|||
|
|
@ -16,15 +16,12 @@ function normalizarConfig(valor: unknown): EliTabelaColunasConfig {
|
|||
return { visiveis: [], invisiveis: [] }
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic config
|
||||
const v = valor as any
|
||||
const v = valor as EliTabelaColunasConfig
|
||||
const visiveis = Array.isArray(v.visiveis)
|
||||
? // biome-ignore lint/suspicious/noExplicitAny: dynamic array item
|
||||
v.visiveis.filter((x: any) => typeof x === "string")
|
||||
? v.visiveis.filter((x: unknown) => typeof x === "string")
|
||||
: []
|
||||
const invisiveis = Array.isArray(v.invisiveis)
|
||||
? // biome-ignore lint/suspicious/noExplicitAny: dynamic array item
|
||||
v.invisiveis.filter((x: any) => typeof x === "string")
|
||||
? v.invisiveis.filter((x: unknown) => typeof x === "string")
|
||||
: []
|
||||
return { visiveis, invisiveis }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export type EliTabelaFiltroAvancadoSalvo<T> = Array<{
|
||||
coluna: keyof T
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
||||
valor: any
|
||||
|
||||
valor: T[keyof T]
|
||||
}>
|
||||
|
||||
function key(nomeTabela: string) {
|
||||
|
|
@ -17,8 +17,7 @@ export function carregarFiltroAvancado<T>(
|
|||
const parsed = JSON.parse(raw)
|
||||
return Array.isArray(parsed)
|
||||
? (parsed as EliTabelaFiltroAvancadoSalvo<T>)
|
||||
: // biome-ignore lint/suspicious/noExplicitAny: dynamic cast
|
||||
([] as any)
|
||||
: ([] as unknown as EliTabelaFiltroAvancadoSalvo<T>)
|
||||
} catch {
|
||||
return [] as unknown as EliTabelaFiltroAvancadoSalvo<T>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import type { LucideIcon } from "lucide-vue-next"
|
||||
import type { operadores, zFiltro } from "p-comuns"
|
||||
import type { tipoFiltro26 } from "p-comuns"
|
||||
|
||||
export type tipoFiltro<T> = tipoFiltro26<T>
|
||||
|
||||
import type { tipoResposta } from "p-respostas"
|
||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas"
|
||||
import type {
|
||||
|
|
@ -7,9 +10,6 @@ import type {
|
|||
tipoTabelaCelula,
|
||||
} from "./celulas/tiposTabelaCelulas"
|
||||
|
||||
// `p-comuns` expõe `zFiltro` (schema). Inferimos o tipo a partir do `parse`.
|
||||
export type tipoFiltro = ReturnType<(typeof zFiltro)["parse"]>
|
||||
|
||||
export type tipoComponenteCelulaBase<T extends tipoTabelaCelula> = readonly [
|
||||
T,
|
||||
tiposTabelaCelulas[T],
|
||||
|
|
@ -72,7 +72,7 @@ export type tipoEliTabelaAcao<T> = {
|
|||
}
|
||||
|
||||
export type parametrosConsulta<T> = {
|
||||
filtros?: tipoFiltro[]
|
||||
filtros?: tipoFiltro26<T>[]
|
||||
coluna_ordem?: keyof T
|
||||
direcao_ordem?: "asc" | "desc"
|
||||
offSet?: number
|
||||
|
|
@ -143,8 +143,13 @@ export type tipoEliTabelaConsulta<T> = {
|
|||
}[]
|
||||
|
||||
filtroAvancado?: {
|
||||
coluna: keyof T
|
||||
operador: operadores | keyof typeof operadores
|
||||
/** Identificador único do filtro (usado para persistência) */
|
||||
chave: string
|
||||
/** Rótulo exibido no select de adicionar filtro */
|
||||
rotulo: string
|
||||
/** vai gerar filtro e mescla com os filtros já existentes */
|
||||
filtro: (valor: unknown) => tipoFiltro26<T>
|
||||
/** componente de entrada que vai receber o valor para o filtro */
|
||||
entrada: ComponenteEntrada
|
||||
}[]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue