adicionado gestão de colunas
This commit is contained in:
parent
2afa99512e
commit
51c3808a7f
14 changed files with 1910 additions and 929 deletions
2
dist/eli-vue.css
vendored
2
dist/eli-vue.css
vendored
File diff suppressed because one or more lines are too long
2090
dist/eli-vue.es.js
vendored
2090
dist/eli-vue.es.js
vendored
File diff suppressed because it is too large
Load diff
28
dist/eli-vue.umd.js
vendored
28
dist/eli-vue.umd.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -6,6 +6,7 @@
|
||||||
import { PropType } from "vue";
|
import { PropType } from "vue";
|
||||||
/** Tipos da configuração/contrato da tabela */
|
/** Tipos da configuração/contrato da tabela */
|
||||||
import type { EliTabelaConsulta } from "./types-eli-tabela";
|
import type { EliTabelaConsulta } from "./types-eli-tabela";
|
||||||
|
import { type EliTabelaColunasConfig } from "./colunasStorage";
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||||
/** Configuração principal da tabela (colunas, consulta e ações) */
|
/** Configuração principal da tabela (colunas, consulta e ações) */
|
||||||
tabela: {
|
tabela: {
|
||||||
|
|
@ -34,6 +35,19 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
}[]>;
|
}[]>;
|
||||||
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
||||||
temAcoes: import("vue").ComputedRef<boolean>;
|
temAcoes: import("vue").ComputedRef<boolean>;
|
||||||
|
colunasEfetivas: import("vue").ComputedRef<any[]>;
|
||||||
|
rotulosColunas: import("vue").ComputedRef<string[]>;
|
||||||
|
modalColunasAberto: import("vue").Ref<boolean, boolean>;
|
||||||
|
configColunas: import("vue").Ref<{
|
||||||
|
visiveis: string[];
|
||||||
|
invisiveis: string[];
|
||||||
|
}, EliTabelaColunasConfig | {
|
||||||
|
visiveis: string[];
|
||||||
|
invisiveis: string[];
|
||||||
|
}>;
|
||||||
|
abrirModalColunas: () => void;
|
||||||
|
fecharModalColunas: () => void;
|
||||||
|
salvarModalColunas: (cfg: EliTabelaColunasConfig) => void;
|
||||||
alternarOrdenacao: (chave?: string) => void;
|
alternarOrdenacao: (chave?: string) => void;
|
||||||
atualizarBusca: (texto: string) => void;
|
atualizarBusca: (texto: string) => void;
|
||||||
irParaPagina: (pagina: number) => void;
|
irParaPagina: (pagina: number) => void;
|
||||||
|
|
@ -79,6 +93,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
type: BooleanConstructor;
|
type: BooleanConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
};
|
};
|
||||||
|
exibirBotaoColunas: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: false;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
valorBusca: {
|
valorBusca: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
|
|
@ -107,13 +126,20 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
}>, {
|
}>, {
|
||||||
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
||||||
emitBuscar: (texto: string) => void;
|
emitBuscar: (texto: string) => void;
|
||||||
|
emitColunas: () => void;
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||||
buscar(valor: string): boolean;
|
buscar(valor: string): boolean;
|
||||||
|
colunas(): true;
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||||
exibirBusca: {
|
exibirBusca: {
|
||||||
type: BooleanConstructor;
|
type: BooleanConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
};
|
};
|
||||||
|
exibirBotaoColunas: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: false;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
valorBusca: {
|
valorBusca: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
|
|
@ -141,7 +167,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
};
|
};
|
||||||
}>> & Readonly<{
|
}>> & Readonly<{
|
||||||
onBuscar?: ((valor: string) => any) | undefined;
|
onBuscar?: ((valor: string) => any) | undefined;
|
||||||
}>, {}, {}, {
|
onColunas?: (() => any) | undefined;
|
||||||
|
}>, {
|
||||||
|
exibirBotaoColunas: boolean;
|
||||||
|
}, {}, {
|
||||||
EliTabelaCaixaDeBusca: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
EliTabelaCaixaDeBusca: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||||
modelo: {
|
modelo: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
|
|
@ -464,6 +493,47 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
}>> & Readonly<{
|
}>> & Readonly<{
|
||||||
onAlterar?: ((pagina: number) => any) | undefined;
|
onAlterar?: ((pagina: number) => any) | undefined;
|
||||||
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||||
|
EliTabelaModalColunas: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||||
|
aberto: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
rotulosColunas: {
|
||||||
|
type: PropType<string[]>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
configInicial: {
|
||||||
|
type: PropType<EliTabelaColunasConfig>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
}>, {
|
||||||
|
visiveisLocal: import("vue").Ref<string[], string[]>;
|
||||||
|
invisiveisLocal: import("vue").Ref<string[], string[]>;
|
||||||
|
emitFechar: () => void;
|
||||||
|
emitSalvar: () => void;
|
||||||
|
onDragStart: (e: DragEvent, rotulo: string, origem: "visiveis" | "invisiveis", index: number) => void;
|
||||||
|
onDropItem: (e: DragEvent, destino: "visiveis" | "invisiveis", index: number) => void;
|
||||||
|
onDropLista: (e: DragEvent, destino: "visiveis" | "invisiveis", _index: number | null) => void;
|
||||||
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||||
|
fechar(): true;
|
||||||
|
salvar(_config: EliTabelaColunasConfig): true;
|
||||||
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||||
|
aberto: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
rotulosColunas: {
|
||||||
|
type: PropType<string[]>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
configInicial: {
|
||||||
|
type: PropType<EliTabelaColunasConfig>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
}>> & Readonly<{
|
||||||
|
onFechar?: (() => any) | undefined;
|
||||||
|
onSalvar?: ((_config: EliTabelaColunasConfig) => any) | undefined;
|
||||||
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||||
declare const _default: typeof __VLS_export;
|
declare const _default: typeof __VLS_export;
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
type: BooleanConstructor;
|
type: BooleanConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
};
|
};
|
||||||
|
exibirBotaoColunas: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: false;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
valorBusca: {
|
valorBusca: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
|
|
@ -20,13 +25,20 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
}>, {
|
}>, {
|
||||||
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
||||||
emitBuscar: (texto: string) => void;
|
emitBuscar: (texto: string) => void;
|
||||||
|
emitColunas: () => void;
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||||
buscar(valor: string): boolean;
|
buscar(valor: string): boolean;
|
||||||
|
colunas(): true;
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||||
exibirBusca: {
|
exibirBusca: {
|
||||||
type: BooleanConstructor;
|
type: BooleanConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
};
|
};
|
||||||
|
exibirBotaoColunas: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: false;
|
||||||
|
default: boolean;
|
||||||
|
};
|
||||||
valorBusca: {
|
valorBusca: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
required: true;
|
required: true;
|
||||||
|
|
@ -42,7 +54,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
||||||
};
|
};
|
||||||
}>> & Readonly<{
|
}>> & Readonly<{
|
||||||
onBuscar?: ((valor: string) => any) | undefined;
|
onBuscar?: ((valor: string) => any) | undefined;
|
||||||
}>, {}, {}, {
|
onColunas?: (() => any) | undefined;
|
||||||
|
}>, {
|
||||||
|
exibirBotaoColunas: boolean;
|
||||||
|
}, {}, {
|
||||||
EliTabelaCaixaDeBusca: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
EliTabelaCaixaDeBusca: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||||
modelo: {
|
modelo: {
|
||||||
type: StringConstructor;
|
type: StringConstructor;
|
||||||
|
|
|
||||||
46
dist/types/components/eli/EliTabela/EliTabelaModalColunas.vue.d.ts
vendored
Normal file
46
dist/types/components/eli/EliTabela/EliTabelaModalColunas.vue.d.ts
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { PropType } from "vue";
|
||||||
|
import type { EliTabelaColunasConfig } from "./colunasStorage";
|
||||||
|
type OrigemLista = "visiveis" | "invisiveis";
|
||||||
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||||
|
aberto: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
rotulosColunas: {
|
||||||
|
type: PropType<string[]>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
configInicial: {
|
||||||
|
type: PropType<EliTabelaColunasConfig>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
}>, {
|
||||||
|
visiveisLocal: import("vue").Ref<string[], string[]>;
|
||||||
|
invisiveisLocal: import("vue").Ref<string[], string[]>;
|
||||||
|
emitFechar: () => void;
|
||||||
|
emitSalvar: () => void;
|
||||||
|
onDragStart: (e: DragEvent, rotulo: string, origem: OrigemLista, index: number) => void;
|
||||||
|
onDropItem: (e: DragEvent, destino: OrigemLista, index: number) => void;
|
||||||
|
onDropLista: (e: DragEvent, destino: OrigemLista, _index: number | null) => void;
|
||||||
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||||
|
fechar(): true;
|
||||||
|
salvar(_config: EliTabelaColunasConfig): true;
|
||||||
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||||
|
aberto: {
|
||||||
|
type: BooleanConstructor;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
rotulosColunas: {
|
||||||
|
type: PropType<string[]>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
configInicial: {
|
||||||
|
type: PropType<EliTabelaColunasConfig>;
|
||||||
|
required: true;
|
||||||
|
};
|
||||||
|
}>> & Readonly<{
|
||||||
|
onFechar?: (() => any) | undefined;
|
||||||
|
onSalvar?: ((_config: EliTabelaColunasConfig) => any) | undefined;
|
||||||
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||||
|
declare const _default: typeof __VLS_export;
|
||||||
|
export default _default;
|
||||||
10
dist/types/components/eli/EliTabela/colunasStorage.d.ts
vendored
Normal file
10
dist/types/components/eli/EliTabela/colunasStorage.d.ts
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
export type EliTabelaColunasConfig = {
|
||||||
|
/** Rotulos das colunas visiveis (em ordem). */
|
||||||
|
visiveis: string[];
|
||||||
|
/** Rotulos das colunas invisiveis. */
|
||||||
|
invisiveis: string[];
|
||||||
|
};
|
||||||
|
export declare function storageKeyColunas(nomeTabela: string): string;
|
||||||
|
export declare function carregarConfigColunas(nomeTabela: string): EliTabelaColunasConfig;
|
||||||
|
export declare function salvarConfigColunas(nomeTabela: string, config: EliTabelaColunasConfig): void;
|
||||||
|
export declare function limparConfigColunas(nomeTabela: string): void;
|
||||||
|
|
@ -63,6 +63,8 @@ export type EliTabelaAcao<T> = {
|
||||||
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
||||||
*/
|
*/
|
||||||
export type EliTabelaConsulta<T> = {
|
export type EliTabelaConsulta<T> = {
|
||||||
|
/** nome da tabela, um identificador unico */
|
||||||
|
nome: string;
|
||||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
||||||
mostrarCaixaDeBusca?: boolean;
|
mostrarCaixaDeBusca?: boolean;
|
||||||
/** Lista de colunas da tabela. */
|
/** Lista de colunas da tabela. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "eli-vue",
|
"name": "eli-vue",
|
||||||
"version": "0.1.45",
|
"version": "0.1.48",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "./dist/eli-vue.umd.js",
|
"main": "./dist/eli-vue.umd.js",
|
||||||
"module": "./dist/eli-vue.es.js",
|
"module": "./dist/eli-vue.es.js",
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,20 @@
|
||||||
:valorBusca="valorBusca"
|
:valorBusca="valorBusca"
|
||||||
:acoesCabecalho="acoesCabecalho"
|
:acoesCabecalho="acoesCabecalho"
|
||||||
@buscar="atualizarBusca"
|
@buscar="atualizarBusca"
|
||||||
|
@colunas="abrirModalColunas"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EliTabelaModalColunas
|
||||||
|
:aberto="modalColunasAberto"
|
||||||
|
:rotulosColunas="rotulosColunas"
|
||||||
|
:configInicial="configColunas"
|
||||||
|
@fechar="fecharModalColunas"
|
||||||
|
@salvar="salvarModalColunas"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<table class="eli-tabela__table">
|
<table class="eli-tabela__table">
|
||||||
<EliTabelaHead
|
<EliTabelaHead
|
||||||
:colunas="tabela.colunas"
|
:colunas="colunasEfetivas"
|
||||||
:temAcoes="temAcoes"
|
:temAcoes="temAcoes"
|
||||||
:colunaOrdenacao="colunaOrdenacao"
|
:colunaOrdenacao="colunaOrdenacao"
|
||||||
:direcaoOrdenacao="direcaoOrdenacao"
|
:direcaoOrdenacao="direcaoOrdenacao"
|
||||||
|
|
@ -28,7 +37,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EliTabelaBody
|
<EliTabelaBody
|
||||||
:colunas="tabela.colunas"
|
:colunas="colunasEfetivas"
|
||||||
:linhas="linhas"
|
:linhas="linhas"
|
||||||
:temAcoes="temAcoes"
|
:temAcoes="temAcoes"
|
||||||
:menuAberto="menuAberto"
|
:menuAberto="menuAberto"
|
||||||
|
|
@ -83,8 +92,14 @@ import EliTabelaHead from "./EliTabelaHead.vue";
|
||||||
import EliTabelaBody from "./EliTabelaBody.vue";
|
import EliTabelaBody from "./EliTabelaBody.vue";
|
||||||
import EliTabelaMenuAcoes from "./EliTabelaMenuAcoes.vue";
|
import EliTabelaMenuAcoes from "./EliTabelaMenuAcoes.vue";
|
||||||
import EliTabelaPaginacao from "./EliTabelaPaginacao.vue";
|
import EliTabelaPaginacao from "./EliTabelaPaginacao.vue";
|
||||||
|
import EliTabelaModalColunas from "./EliTabelaModalColunas.vue";
|
||||||
/** Tipos da configuração/contrato da tabela */
|
/** Tipos da configuração/contrato da tabela */
|
||||||
import type { EliTabelaConsulta } from "./types-eli-tabela";
|
import type { EliTabelaConsulta } from "./types-eli-tabela";
|
||||||
|
import {
|
||||||
|
carregarConfigColunas,
|
||||||
|
salvarConfigColunas,
|
||||||
|
type EliTabelaColunasConfig,
|
||||||
|
} from "./colunasStorage";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "EliTabela",
|
name: "EliTabela",
|
||||||
|
|
@ -97,6 +112,7 @@ export default defineComponent({
|
||||||
EliTabelaBody,
|
EliTabelaBody,
|
||||||
EliTabelaMenuAcoes,
|
EliTabelaMenuAcoes,
|
||||||
EliTabelaPaginacao,
|
EliTabelaPaginacao,
|
||||||
|
EliTabelaModalColunas,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
/** Configuração principal da tabela (colunas, consulta e ações) */
|
/** Configuração principal da tabela (colunas, consulta e ações) */
|
||||||
|
|
@ -136,6 +152,58 @@ export default defineComponent({
|
||||||
const acoesCabecalho = computed(() => props.tabela.acoesTabela ?? []);
|
const acoesCabecalho = computed(() => props.tabela.acoesTabela ?? []);
|
||||||
const temAcoesCabecalho = computed(() => acoesCabecalho.value.length > 0);
|
const temAcoesCabecalho = computed(() => acoesCabecalho.value.length > 0);
|
||||||
|
|
||||||
|
/** Colunas: visibilidade/ordem com persistência */
|
||||||
|
const modalColunasAberto = ref(false);
|
||||||
|
const configColunas = ref<EliTabelaColunasConfig>(
|
||||||
|
carregarConfigColunas(props.tabela.nome)
|
||||||
|
);
|
||||||
|
|
||||||
|
const rotulosColunas = computed(() => props.tabela.colunas.map((c) => c.rotulo));
|
||||||
|
|
||||||
|
const colunasEfetivas = computed(() => {
|
||||||
|
const colunas = props.tabela.colunas;
|
||||||
|
const todosRotulos = rotulosColunas.value;
|
||||||
|
const invisiveisSet = new Set(configColunas.value.invisiveis ?? []);
|
||||||
|
|
||||||
|
// default: todas visiveis; so some se estiver explicitamente em invisiveis
|
||||||
|
const visiveisBaseRotulos = todosRotulos.filter((r) => !invisiveisSet.has(r));
|
||||||
|
const visiveisSet = new Set(visiveisBaseRotulos);
|
||||||
|
|
||||||
|
// aplica ordem salva; novas (sem definicao) entram no fim, respeitando ordem original
|
||||||
|
const ordemSalva = configColunas.value.visiveis ?? [];
|
||||||
|
const ordemFinal: string[] = [];
|
||||||
|
|
||||||
|
for (const r of ordemSalva) {
|
||||||
|
if (visiveisSet.has(r)) ordemFinal.push(r);
|
||||||
|
}
|
||||||
|
for (const r of visiveisBaseRotulos) {
|
||||||
|
if (!ordemFinal.includes(r)) ordemFinal.push(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapeia rótulo -> coluna, preservando duplicatas (se existirem) pelo primeiro match.
|
||||||
|
// OBS: pressupoe rotulo unico; se repetir, comportamento fica indefinido.
|
||||||
|
const mapa = new Map<string, any>();
|
||||||
|
for (const c of colunas) {
|
||||||
|
if (!mapa.has(c.rotulo)) mapa.set(c.rotulo, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ordemFinal.map((r) => mapa.get(r)).filter(Boolean);
|
||||||
|
});
|
||||||
|
|
||||||
|
function abrirModalColunas() {
|
||||||
|
modalColunasAberto.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fecharModalColunas() {
|
||||||
|
modalColunasAberto.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function salvarModalColunas(cfg: EliTabelaColunasConfig) {
|
||||||
|
configColunas.value = cfg;
|
||||||
|
salvarConfigColunas(props.tabela.nome, cfg);
|
||||||
|
modalColunasAberto.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Registros por consulta (normaliza para inteiro positivo) */
|
/** Registros por consulta (normaliza para inteiro positivo) */
|
||||||
const registrosPorConsulta = computed(() => {
|
const registrosPorConsulta = computed(() => {
|
||||||
const valor = props.tabela.registros_por_consulta;
|
const valor = props.tabela.registros_por_consulta;
|
||||||
|
|
@ -453,6 +521,8 @@ export default defineComponent({
|
||||||
colunaOrdenacao.value = null;
|
colunaOrdenacao.value = null;
|
||||||
direcaoOrdenacao.value = "asc";
|
direcaoOrdenacao.value = "asc";
|
||||||
valorBusca.value = "";
|
valorBusca.value = "";
|
||||||
|
modalColunasAberto.value = false;
|
||||||
|
configColunas.value = carregarConfigColunas(props.tabela.nome);
|
||||||
if (paginaAtual.value !== 1) {
|
if (paginaAtual.value !== 1) {
|
||||||
paginaAtual.value = 1;
|
paginaAtual.value = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -499,6 +569,14 @@ export default defineComponent({
|
||||||
acoesCabecalho,
|
acoesCabecalho,
|
||||||
temAcoesCabecalho,
|
temAcoesCabecalho,
|
||||||
temAcoes,
|
temAcoes,
|
||||||
|
colunasEfetivas,
|
||||||
|
rotulosColunas,
|
||||||
|
modalColunasAberto,
|
||||||
|
configColunas,
|
||||||
|
|
||||||
|
abrirModalColunas,
|
||||||
|
fecharModalColunas,
|
||||||
|
salvarModalColunas,
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
alternarOrdenacao,
|
alternarOrdenacao,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="eli-tabela__cabecalho">
|
<div class="eli-tabela__cabecalho">
|
||||||
<!-- Caixa de busca: emite @buscar com o termo digitado -->
|
<!-- Grupo de busca: botão de colunas (à esquerda) + input de busca -->
|
||||||
<EliTabelaCaixaDeBusca v-if="exibirBusca" :modelo="valorBusca" @buscar="emitBuscar" />
|
<div v-if="exibirBusca" class="eli-tabela__busca-grupo">
|
||||||
|
<button
|
||||||
|
v-if="exibirBotaoColunas"
|
||||||
|
type="button"
|
||||||
|
class="eli-tabela__acoes-cabecalho-botao eli-tabela__acoes-cabecalho-botao--colunas"
|
||||||
|
@click="emitColunas"
|
||||||
|
>
|
||||||
|
Colunas
|
||||||
|
</button>
|
||||||
|
<EliTabelaCaixaDeBusca :modelo="valorBusca" @buscar="emitBuscar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Ações do cabeçalho: ações globais da tabela -->
|
<!-- Ações do cabeçalho: ações globais da tabela -->
|
||||||
<div v-if="temAcoesCabecalho" class="eli-tabela__acoes-cabecalho">
|
<div v-if="temAcoesCabecalho" class="eli-tabela__acoes-cabecalho">
|
||||||
|
|
@ -38,6 +48,11 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
exibirBotaoColunas: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
valorBusca: {
|
valorBusca: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -58,6 +73,9 @@ export default defineComponent({
|
||||||
buscar(valor: string) {
|
buscar(valor: string) {
|
||||||
return typeof valor === "string";
|
return typeof valor === "string";
|
||||||
},
|
},
|
||||||
|
colunas() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const temAcoesCabecalho = computed(() => props.acoesCabecalho.length > 0);
|
const temAcoesCabecalho = computed(() => props.acoesCabecalho.length > 0);
|
||||||
|
|
@ -66,7 +84,20 @@ export default defineComponent({
|
||||||
emit("buscar", texto);
|
emit("buscar", texto);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { temAcoesCabecalho, emitBuscar };
|
function emitColunas() {
|
||||||
|
emit("colunas");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { temAcoesCabecalho, emitBuscar, emitColunas };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.eli-tabela__busca-grupo {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
394
src/components/eli/EliTabela/EliTabelaModalColunas.vue
Normal file
394
src/components/eli/EliTabela/EliTabelaModalColunas.vue
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="aberto" class="eli-tabela-modal-colunas__overlay" role="presentation" @click.self="emitFechar">
|
||||||
|
<div
|
||||||
|
class="eli-tabela-modal-colunas__modal"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-label="Configurar colunas"
|
||||||
|
>
|
||||||
|
<header class="eli-tabela-modal-colunas__header">
|
||||||
|
<h3 class="eli-tabela-modal-colunas__titulo">Colunas</h3>
|
||||||
|
<button type="button" class="eli-tabela-modal-colunas__fechar" aria-label="Fechar" @click="emitFechar">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="eli-tabela-modal-colunas__conteudo">
|
||||||
|
<div class="eli-tabela-modal-colunas__coluna">
|
||||||
|
<div class="eli-tabela-modal-colunas__coluna-titulo">Visíveis</div>
|
||||||
|
<div
|
||||||
|
class="eli-tabela-modal-colunas__lista"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="(e) => onDropLista(e, 'visiveis', null)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(rotulo, idx) in visiveisLocal"
|
||||||
|
:key="`vis-${rotulo}`"
|
||||||
|
class="eli-tabela-modal-colunas__item"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="(e) => onDragStart(e, rotulo, 'visiveis', idx)"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="(e) => onDropItem(e, 'visiveis', idx)"
|
||||||
|
>
|
||||||
|
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||||
|
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="eli-tabela-modal-colunas__coluna">
|
||||||
|
<div class="eli-tabela-modal-colunas__coluna-titulo">Invisíveis</div>
|
||||||
|
<div
|
||||||
|
class="eli-tabela-modal-colunas__lista"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="(e) => onDropLista(e, 'invisiveis', null)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(rotulo, idx) in invisiveisLocal"
|
||||||
|
:key="`inv-${rotulo}`"
|
||||||
|
class="eli-tabela-modal-colunas__item"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="(e) => onDragStart(e, rotulo, 'invisiveis', idx)"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="(e) => onDropItem(e, 'invisiveis', idx)"
|
||||||
|
>
|
||||||
|
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||||
|
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="eli-tabela-modal-colunas__footer">
|
||||||
|
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--sec" @click="emitFechar">
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--prim" @click="emitSalvar">
|
||||||
|
Salvar
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, PropType, ref, watch } from "vue";
|
||||||
|
import type { EliTabelaColunasConfig } from "./colunasStorage";
|
||||||
|
|
||||||
|
type OrigemLista = "visiveis" | "invisiveis";
|
||||||
|
|
||||||
|
type DragPayload = {
|
||||||
|
rotulo: string;
|
||||||
|
origem: OrigemLista;
|
||||||
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DRAG_MIME = "application/x-eli-tabela-coluna";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "EliTabelaModalColunas",
|
||||||
|
props: {
|
||||||
|
aberto: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
rotulosColunas: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
configInicial: {
|
||||||
|
type: Object as PropType<EliTabelaColunasConfig>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: {
|
||||||
|
fechar() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
salvar(_config: EliTabelaColunasConfig) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const visiveisLocal = ref<string[]>([]);
|
||||||
|
const invisiveisLocal = ref<string[]>([]);
|
||||||
|
|
||||||
|
function sincronizarEstado() {
|
||||||
|
const todos = props.rotulosColunas;
|
||||||
|
const invisiveisSet = new Set(props.configInicial.invisiveis ?? []);
|
||||||
|
|
||||||
|
// default: todas visíveis
|
||||||
|
const baseVisiveis = todos.filter((r) => !invisiveisSet.has(r));
|
||||||
|
|
||||||
|
// ordenação: aplica ordem salva (visiveis) e adiciona novas ao final
|
||||||
|
const ordemSalva = props.configInicial.visiveis ?? [];
|
||||||
|
const setVis = new Set(baseVisiveis);
|
||||||
|
const ordenadas: string[] = [];
|
||||||
|
|
||||||
|
for (const r of ordemSalva) {
|
||||||
|
if (setVis.has(r)) ordenadas.push(r);
|
||||||
|
}
|
||||||
|
for (const r of baseVisiveis) {
|
||||||
|
if (!ordenadas.includes(r)) ordenadas.push(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
visiveisLocal.value = ordenadas;
|
||||||
|
|
||||||
|
// invisíveis: somente as que existem na tabela
|
||||||
|
invisiveisLocal.value = todos.filter((r) => invisiveisSet.has(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.aberto, props.rotulosColunas, props.configInicial] as const,
|
||||||
|
() => {
|
||||||
|
if (props.aberto) sincronizarEstado();
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
function emitFechar() {
|
||||||
|
emit("fechar");
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitSalvar() {
|
||||||
|
emit("salvar", {
|
||||||
|
visiveis: [...visiveisLocal.value],
|
||||||
|
invisiveis: [...invisiveisLocal.value],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeDragData(e: DragEvent, payload: DragPayload) {
|
||||||
|
try {
|
||||||
|
e.dataTransfer?.setData(DRAG_MIME, JSON.stringify(payload));
|
||||||
|
e.dataTransfer?.setData("text/plain", payload.rotulo);
|
||||||
|
e.dataTransfer!.effectAllowed = "move";
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDragData(e: DragEvent): DragPayload | null {
|
||||||
|
try {
|
||||||
|
const raw = e.dataTransfer?.getData(DRAG_MIME);
|
||||||
|
if (!raw) return null;
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (!parsed || typeof parsed.rotulo !== "string" || (parsed.origem !== "visiveis" && parsed.origem !== "invisiveis")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parsed as DragPayload;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removerDaOrigem(payload: DragPayload) {
|
||||||
|
const origemArr = payload.origem === "visiveis" ? visiveisLocal.value : invisiveisLocal.value;
|
||||||
|
const idx = origemArr.indexOf(payload.rotulo);
|
||||||
|
if (idx >= 0) origemArr.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inserirNoDestino(destino: OrigemLista, rotulo: string, index: number | null) {
|
||||||
|
const arr = destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value;
|
||||||
|
// remove duplicatas
|
||||||
|
const existing = arr.indexOf(rotulo);
|
||||||
|
if (existing >= 0) arr.splice(existing, 1);
|
||||||
|
|
||||||
|
if (index === null || index < 0 || index > arr.length) {
|
||||||
|
arr.push(rotulo);
|
||||||
|
} else {
|
||||||
|
arr.splice(index, 0, rotulo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDragStart(e: DragEvent, rotulo: string, origem: OrigemLista, index: number) {
|
||||||
|
writeDragData(e, { rotulo, origem, index });
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDropItem(e: DragEvent, destino: OrigemLista, index: number) {
|
||||||
|
const payload = readDragData(e);
|
||||||
|
if (!payload) return;
|
||||||
|
|
||||||
|
// remove da origem e insere no destino na posição do item
|
||||||
|
removerDaOrigem(payload);
|
||||||
|
inserirNoDestino(destino, payload.rotulo, index);
|
||||||
|
|
||||||
|
// garante que uma coluna não fique nos 2 lados
|
||||||
|
if (destino === "visiveis") {
|
||||||
|
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo);
|
||||||
|
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1);
|
||||||
|
} else {
|
||||||
|
const idxVis = visiveisLocal.value.indexOf(payload.rotulo);
|
||||||
|
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDropLista(e: DragEvent, destino: OrigemLista, _index: number | null) {
|
||||||
|
const payload = readDragData(e);
|
||||||
|
if (!payload) return;
|
||||||
|
|
||||||
|
removerDaOrigem(payload);
|
||||||
|
inserirNoDestino(destino, payload.rotulo, null);
|
||||||
|
|
||||||
|
if (destino === "visiveis") {
|
||||||
|
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo);
|
||||||
|
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1);
|
||||||
|
} else {
|
||||||
|
const idxVis = visiveisLocal.value.indexOf(payload.rotulo);
|
||||||
|
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
visiveisLocal,
|
||||||
|
invisiveisLocal,
|
||||||
|
emitFechar,
|
||||||
|
emitSalvar,
|
||||||
|
onDragStart,
|
||||||
|
onDropItem,
|
||||||
|
onDropLista,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.eli-tabela-modal-colunas__overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(15, 23, 42, 0.35);
|
||||||
|
z-index: 4000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__modal {
|
||||||
|
width: min(860px, 100%);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid rgba(15, 23, 42, 0.1);
|
||||||
|
box-shadow: 0 18px 60px rgba(15, 23, 42, 0.25);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-bottom: 1px solid rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__titulo {
|
||||||
|
font-size: 1rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__fechar {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 1;
|
||||||
|
color: rgba(15, 23, 42, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__fechar:hover,
|
||||||
|
.eli-tabela-modal-colunas__fechar:focus-visible {
|
||||||
|
background: rgba(15, 23, 42, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__conteudo {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__coluna-titulo {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__lista {
|
||||||
|
min-height: 260px;
|
||||||
|
border: 1px solid rgba(15, 23, 42, 0.12);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
background: rgba(15, 23, 42, 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid rgba(15, 23, 42, 0.08);
|
||||||
|
background: #fff;
|
||||||
|
cursor: grab;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__item + .eli-tabela-modal-colunas__item {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__item:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__item-handle {
|
||||||
|
color: rgba(15, 23, 42, 0.55);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__item-texto {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-top: 1px solid rgba(15, 23, 42, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__botao {
|
||||||
|
height: 34px;
|
||||||
|
padding: 0 14px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid rgba(15, 23, 42, 0.12);
|
||||||
|
background: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__botao--sec:hover,
|
||||||
|
.eli-tabela-modal-colunas__botao--sec:focus-visible {
|
||||||
|
background: rgba(15, 23, 42, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__botao--prim {
|
||||||
|
border: none;
|
||||||
|
background: rgba(37, 99, 235, 0.95);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eli-tabela-modal-colunas__botao--prim:hover,
|
||||||
|
.eli-tabela-modal-colunas__botao--prim:focus-visible {
|
||||||
|
background: rgba(37, 99, 235, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.eli-tabela-modal-colunas__conteudo {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
src/components/eli/EliTabela/colunasStorage.ts
Normal file
49
src/components/eli/EliTabela/colunasStorage.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
export type EliTabelaColunasConfig = {
|
||||||
|
/** Rotulos das colunas visiveis (em ordem). */
|
||||||
|
visiveis: string[];
|
||||||
|
/** Rotulos das colunas invisiveis. */
|
||||||
|
invisiveis: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const STORAGE_PREFIX = "eli:tabela";
|
||||||
|
|
||||||
|
export function storageKeyColunas(nomeTabela: string) {
|
||||||
|
return `${STORAGE_PREFIX}:${nomeTabela}:colunas`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizarConfig(valor: unknown): EliTabelaColunasConfig {
|
||||||
|
if (!valor || typeof valor !== "object") {
|
||||||
|
return { visiveis: [], invisiveis: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const v = valor as any;
|
||||||
|
const visiveis = Array.isArray(v.visiveis) ? v.visiveis.filter((x: any) => typeof x === "string") : [];
|
||||||
|
const invisiveis = Array.isArray(v.invisiveis) ? v.invisiveis.filter((x: any) => typeof x === "string") : [];
|
||||||
|
return { visiveis, invisiveis };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function carregarConfigColunas(nomeTabela: string): EliTabelaColunasConfig {
|
||||||
|
try {
|
||||||
|
const raw = window.localStorage.getItem(storageKeyColunas(nomeTabela));
|
||||||
|
if (!raw) return { visiveis: [], invisiveis: [] };
|
||||||
|
return normalizarConfig(JSON.parse(raw));
|
||||||
|
} catch {
|
||||||
|
return { visiveis: [], invisiveis: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function salvarConfigColunas(nomeTabela: string, config: EliTabelaColunasConfig) {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(storageKeyColunas(nomeTabela), JSON.stringify(normalizarConfig(config)));
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function limparConfigColunas(nomeTabela: string) {
|
||||||
|
try {
|
||||||
|
window.localStorage.removeItem(storageKeyColunas(nomeTabela));
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,6 +85,8 @@ export type EliTabelaAcao<T> = {
|
||||||
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
||||||
*/
|
*/
|
||||||
export type EliTabelaConsulta<T> = {
|
export type EliTabelaConsulta<T> = {
|
||||||
|
/** nome da tabela, um identificador unico */
|
||||||
|
nome: string
|
||||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
||||||
mostrarCaixaDeBusca?: boolean;
|
mostrarCaixaDeBusca?: boolean;
|
||||||
/** Lista de colunas da tabela. */
|
/** Lista de colunas da tabela. */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue