Report Layout
Resumo
O LxReportLayout é um layout padrão para telas de relatório. Ele fornece uma estrutura consistente com cabeçalho, barra de ações e área de tabela, integrando opcionalmente sidebar de filtros, personalização de colunas e gestão de preferências salvas via LxReportPresets.
Todos os blocos estruturais possuem slots de override total: ao fornecer o slot correspondente (header, content, toolbar, extra), o conteúdo padrão é completamente substituído pelo fornecido.
Relatório de Produtos
Consulte e filtre os produtos cadastrados no sistema.
Clique para visualizar o código
vue
<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { LxReportLayout, LxDataTable, LxDataTableColumn, LxDateRangePicker, LxMultiSelect, LxInputText, LxButton, LxToast } from '@lde/lxcomponents';
import { PresetTypeEnum } from '@/components/LxReportPresets';
import { useToast } from '@/components/LxToast/useToast.js';
import type { HostPresetPayload, ReportPreset, SavedFilter, ViewLists } from '@/components/LxReportPresets/types';
import type { Row, Totalizadores, CategoryOption, StatusOption, PortalUser } from './types';
const formatCurrency = (value: number): string => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value);
const toast = useToast();
const rows = ref<Row[]>([
{ id: 1, produto: 'Teclado mecânico', categoria: 'Periféricos', quantidade: 12, valor: 349.9 },
{ id: 2, produto: 'Monitor 27"', categoria: 'Monitores', quantidade: 5, valor: 1899.0 },
{ id: 3, produto: 'Headset gamer', categoria: 'Periféricos', quantidade: 20, valor: 279.9 },
{ id: 4, produto: 'Cadeira ergonômica', categoria: 'Mobiliário', quantidade: 3, valor: 2100.0 },
{ id: 5, produto: 'Webcam HD', categoria: 'Periféricos', quantidade: 8, valor: 199.9 }
]);
const onExport = (): void => {
toast?.add({ status: 'success', title: 'Exportando dados...', time: 2500 });
};
const onGenerate = (): void => {
toast?.add({ status: 'success', title: 'Gerando relatório...', time: 2500 });
};
const mockUsers = ref<PortalUser[]>([
{ Id: 1, Nome: 'Ana Souza' },
{ Id: 2, Nome: 'Bruno Lima' },
{ Id: 3, Nome: 'Carlos Pereira' }
]);
const DEFAULT_COLUMNS = ['id', 'produto', 'categoria', 'quantidade', 'valor'] as const;
const DEFAULT_FILTERS = {
periodo: { firstDate: null as null, lastDate: null as null, presetDate: 3 /* CurrentMonth */ },
categoria: [] as string[],
produto: '',
status: [] as string[]
};
const FILTER_IDS = {
PERIODO: 1,
CATEGORIA: 2,
PRODUTO: 3,
STATUS: 4
} as const;
const toSelectValues = (value: unknown): string[] => (Array.isArray(value) ? value.map((item) => String(item)) : []);
const periodo = ref({ ...DEFAULT_FILTERS.periodo });
const filterPeriodo = ref({ ...DEFAULT_FILTERS.periodo });
const filterCategoria = ref<string[]>([...DEFAULT_FILTERS.categoria]);
const filterProduto = ref(DEFAULT_FILTERS.produto);
const filterStatus = ref<string[]>([...DEFAULT_FILTERS.status]);
const currentColumns = computed(() => [...DEFAULT_COLUMNS]);
const currentFilters = computed<SavedFilter[]>(() => {
const activeFilters: SavedFilter[] = [];
if (filterPeriodo.value.firstDate || filterPeriodo.value.lastDate || filterPeriodo.value.presetDate) {
activeFilters.push({
FiltroId: FILTER_IDS.PERIODO,
Valor: {
firstDate: filterPeriodo.value.firstDate,
lastDate: filterPeriodo.value.lastDate,
presetDate: filterPeriodo.value.presetDate
}
});
}
if (filterCategoria.value.length > 0) {
activeFilters.push({ FiltroId: FILTER_IDS.CATEGORIA, Valor: [...filterCategoria.value] });
}
if (filterProduto.value.trim()) {
activeFilters.push({ FiltroId: FILTER_IDS.PRODUTO, Valor: filterProduto.value.trim() });
}
if (filterStatus.value.length > 0) {
activeFilters.push({ FiltroId: FILTER_IDS.STATUS, Valor: [...filterStatus.value] });
}
return activeFilters;
});
const createPreset = (preset: Partial<ReportPreset> & { Id: number; Nome: string; Tipo: ReportPreset['Tipo'] }): ReportPreset => ({
Id: preset.Id,
Nome: preset.Nome,
Tipo: preset.Tipo,
Padrao: preset.Padrao ?? false,
Aplicada: preset.Aplicada ?? false,
UsuarioCriadorId: preset.UsuarioCriadorId ?? 1,
PodeEditar: preset.PodeEditar ?? true,
Colunas: preset.Colunas ?? [...DEFAULT_COLUMNS],
Filtros: preset.Filtros ?? [],
Administradores: preset.Administradores ?? [],
IgnorarDatas: preset.IgnorarDatas ?? true,
IgnorarEmpresas: preset.IgnorarEmpresas ?? true
});
const viewLists = reactive<ViewLists>({
privadas: [
createPreset({
Id: 1,
Nome: 'Somente periféricos',
Tipo: PresetTypeEnum.PRIVATE,
Padrao: true,
Aplicada: true,
Filtros: [
{ FiltroId: FILTER_IDS.CATEGORIA, Valor: ['perifericos'] },
{ FiltroId: FILTER_IDS.STATUS, Valor: ['ativo'] }
]
})
],
publicas: [
createPreset({
Id: 2,
Nome: 'Dashboard da equipe',
Tipo: PresetTypeEnum.PUBLIC,
Padrao: false,
PodeEditar: true,
UsuarioCriadorId: 2,
Administradores: [1, 2],
Filtros: [{ FiltroId: FILTER_IDS.STATUS, Valor: ['ativo', 'pendente'] }]
}),
createPreset({
Id: 3,
Nome: 'Somente leitura',
Tipo: PresetTypeEnum.PUBLIC,
Padrao: false,
PodeEditar: false,
UsuarioCriadorId: 2,
Filtros: [{ FiltroId: FILTER_IDS.PRODUTO, Valor: 'monitor' }]
})
],
modelos: []
});
const appliedView = ref<ReportPreset | null>(viewLists.privadas?.[0] ?? null);
const presetsLoading = ref(false);
let nextPresetId = 10;
const allViews = computed<ReportPreset[]>(() => [...(viewLists.privadas ?? []), ...(viewLists.publicas ?? []), ...(viewLists.modelos ?? [])]);
const syncAppliedFlags = (viewId: number | null): void => {
allViews.value.forEach((view) => {
(view as { Aplicada: boolean }).Aplicada = view.Id === viewId;
});
};
const findListByType = (type: ReportPreset['Tipo']): ReportPreset[] => {
if (type === PresetTypeEnum.PUBLIC) {
return (viewLists.publicas ??= []);
}
if (type === PresetTypeEnum.TEMPLATE) {
return (viewLists.modelos ??= []);
}
return (viewLists.privadas ??= []);
};
const applyFiltersFromView = (view: ReportPreset): void => {
const periodoFilter = view.Filtros.find((item) => item.FiltroId === FILTER_IDS.PERIODO);
const categoriaFilter = view.Filtros.find((item) => item.FiltroId === FILTER_IDS.CATEGORIA);
const produtoFilter = view.Filtros.find((item) => item.FiltroId === FILTER_IDS.PRODUTO);
const statusFilter = view.Filtros.find((item) => item.FiltroId === FILTER_IDS.STATUS);
if (periodoFilter && typeof periodoFilter.Valor === 'object' && periodoFilter.Valor !== null) {
const periodoValue = periodoFilter.Valor as { firstDate?: null; lastDate?: null; presetDate?: number | null };
filterPeriodo.value = {
firstDate: periodoValue.firstDate ?? null,
lastDate: periodoValue.lastDate ?? null,
presetDate: periodoValue.presetDate ?? null
};
} else {
filterPeriodo.value = { ...DEFAULT_FILTERS.periodo };
}
filterCategoria.value = toSelectValues(categoriaFilter?.Valor);
filterProduto.value = typeof produtoFilter?.Valor === 'string' ? produtoFilter.Valor : '';
filterStatus.value = toSelectValues(statusFilter?.Valor);
periodo.value = { ...filterPeriodo.value };
};
const configPresets = computed(() => ({
appliedView: appliedView.value,
viewLists,
currentColumns: currentColumns.value,
currentFilters: currentFilters.value,
viewPageId: 1,
showTabPrivates: true,
showTabPublics: true,
showTabModels: false,
showCheckboxPublic: true,
showCheckboxDates: true,
showCheckboxCompanies: true,
canAddPublicView: true,
usersList: mockUsers.value
}));
const onApplyView = (view: ReportPreset): void => {
appliedView.value = view;
syncAppliedFlags(view.Id);
applyFiltersFromView(view);
toast?.add({ status: 'success', title: `Preferência aplicada: ${view.Nome}`, time: 3000 });
};
const onDeactivateView = (view: ReportPreset): void => {
appliedView.value = null;
syncAppliedFlags(null);
toast?.add({ status: 'success', title: `Preferência desativada: ${view.Nome}`, time: 3000 });
};
const onSavePreset = (payload: HostPresetPayload): void => {
const targetList = findListByType(payload.Tipo);
if (payload.Padrao) {
targetList.forEach((item) => ((item as { Padrao: boolean }).Padrao = false));
}
const createdView = createPreset({
Id: ++nextPresetId,
Nome: payload.Descricao,
Tipo: payload.Tipo,
Padrao: payload.Padrao,
Aplicada: true,
Colunas: payload.ColunasConfiguracao.map((coluna) => coluna.Id),
Filtros: payload.Filtros.map((filtro) => ({ FiltroId: Number(filtro.Id), Valor: filtro.Valor })),
Administradores: payload.IdsUsuarios,
IgnorarDatas: payload.IgnorarDatas,
IgnorarEmpresas: payload.IgnorarEmpresas
});
targetList.push(createdView);
appliedView.value = createdView;
syncAppliedFlags(createdView.Id);
applyFiltersFromView(createdView);
toast?.add({ status: 'success', title: `Preferência criada: ${createdView.Nome}`, time: 3000 });
};
const onUpdatePreset = (payload: { id: number; data: HostPresetPayload }): void => {
const currentView = allViews.value.find((view) => view.Id === payload.id);
if (!currentView) return;
const targetList = findListByType(currentView.Tipo);
const targetIndex = targetList.findIndex((item) => item.Id === payload.id);
if (targetIndex === -1) return;
if (payload.data.Padrao) {
targetList.forEach((item) => ((item as { Padrao: boolean }).Padrao = false));
}
targetList[targetIndex] = createPreset({
...currentView,
Id: payload.id,
Nome: payload.data.Descricao,
Tipo: payload.data.Tipo,
Padrao: payload.data.Padrao,
Aplicada: appliedView.value?.Id === payload.id,
Colunas: payload.data.ColunasConfiguracao.map((coluna) => coluna.Id),
Filtros: payload.data.Filtros.map((filtro) => ({ FiltroId: Number(filtro.Id), Valor: filtro.Valor })),
Administradores: payload.data.IdsUsuarios,
IgnorarDatas: payload.data.IgnorarDatas,
IgnorarEmpresas: payload.data.IgnorarEmpresas
});
if (appliedView.value?.Id === payload.id) {
appliedView.value = targetList[targetIndex];
applyFiltersFromView(targetList[targetIndex]);
}
toast?.add({ status: 'success', title: `Preferência atualizada: ${payload.data.Descricao}`, time: 3000 });
};
const onDeletePreset = (payload: { id: number }): void => {
const privateIndex = (viewLists.privadas ?? []).findIndex((item) => item.Id === payload.id);
if (privateIndex !== -1) {
viewLists.privadas?.splice(privateIndex, 1);
}
const publicIndex = (viewLists.publicas ?? []).findIndex((item) => item.Id === payload.id);
if (publicIndex !== -1) {
viewLists.publicas?.splice(publicIndex, 1);
}
if (appliedView.value?.Id === payload.id) {
appliedView.value = null;
syncAppliedFlags(null);
}
toast?.add({ status: 'success', title: `Preferência removida: ID ${payload.id}`, time: 3000 });
};
const totais = ref<Totalizadores>({ valor: 4828.6 });
const categoriaOptions = ref<CategoryOption[]>([
{ id: 'perifericos', label: 'Periféricos' },
{ id: 'monitores', label: 'Monitores' },
{ id: 'mobiliario', label: 'Mobiliário' }
]);
const statusOptions = ref<StatusOption[]>([
{ id: 'ativo', label: 'Ativo' },
{ id: 'inativo', label: 'Inativo' },
{ id: 'pendente', label: 'Pendente' }
]);
const tableStyle = ref('small');
const toolbarConfig = computed(() => ({
showFilter: true,
showColumns: false,
showExport: true,
showGenerate: true,
scrollable: true,
enableStyleSelector: true,
enableTableExpand: true
}));
</script>
<template>
<LxToast />
<LxReportLayout
id="example-report"
title="Relatório de Produtos"
description="Consulte e filtre os produtos cadastrados no sistema."
docs-url="https://github.com"
:toolbar-config="toolbarConfig"
:config-presets="configPresets"
@export="onExport"
@generate="onGenerate"
@update:tableStyle="tableStyle = $event"
@apply:view="onApplyView"
@deactivate:view="onDeactivateView"
@update:loading="presetsLoading = $event"
@insert:preset="onSavePreset"
@update:preset="onUpdatePreset"
@delete:preset="onDeletePreset"
>
<template #filters>
<div class="example-filter-group">
<LxDateRangePicker id="example-periodo" label="Período" v-model="periodo" size="sm" />
</div>
</template>
<template #filters-body>
<div class="example-advanced-filters">
<div class="example-filter-group">
<LxDateRangePicker id="adv-periodo" v-model="filterPeriodo" label="Período" />
</div>
<div class="example-filter-group">
<LxMultiSelect
id="adv-categoria"
v-model="filterCategoria"
:options="categoriaOptions"
track-by="id"
options-label="label"
label="Categoria"
placeholder="Selecione categorias..."
/>
</div>
<div class="example-filter-group">
<LxMultiSelect
id="adv-status"
v-model="filterStatus"
:options="statusOptions"
track-by="id"
options-label="label"
label="Status"
placeholder="Selecione status..."
/>
</div>
<div class="example-filter-group">
<LxInputText id="adv-produto" v-model="filterProduto" label="Produto" placeholder="Buscar produto..." />
</div>
</div>
</template>
<template #filters-footer="{ close }">
<LxButton id="adv-filter-apply-btn" severity="primary" @click="close">Filtrar relatório</LxButton>
</template>
<template #table="{ loading, tableStyle }">
<LxDataTable :value="rows" :loading="loading" :show-footer="true" :visualization-config="{ size: tableStyle }">
<LxDataTableColumn field="id" header="ID" />
<LxDataTableColumn field="produto" header="Produto" />
<LxDataTableColumn field="categoria" header="Categoria" />
<LxDataTableColumn field="quantidade" header="Quantidade" />
<LxDataTableColumn field="valor" header="Valor (R$)" header-style="text-align:right" body-style="text-align:right" footer-style="text-align:right">
<template #body="{ data }">
{{ formatCurrency(data.valor) }}
</template>
<template #footer>
<strong>{{ formatCurrency(totais.valor) }}</strong>
</template>
</LxDataTableColumn>
</LxDataTable>
</template>
</LxReportLayout>
</template>
<style scoped>
.example-filter-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.example-filter-label {
font-size: 0.75rem;
font-weight: 500;
color: var(--lx-text-secondary, #6c757d);
}
.example-filter-actions {
display: flex;
gap: 0.5rem;
}
.example-advanced-filters {
display: flex;
flex-direction: column;
gap: 1rem;
margin: 1rem;
}
</style>Propriedades
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| id | Identificador base do layout | String | 'lx-report-layout' |
| title | ⚠️ obr Nome do relatório exibido no cabeçalho | String | — |
| description | Descrição breve exibida abaixo do título | String | — |
| docsUrl | URL da documentação. Quando informada, exibe o botão de ajuda no cabeçalho | String | '' |
| loading | Repassa o estado de carregamento para o slot table | Boolean | false |
| textConfig | Permite sobrescrever os textos padrão dos botões e rótulos auxiliares. Ver ReportLayoutTextConfig | ReportLayoutTextConfig | {} |
| toolbarConfig | Controla a visibilidade dos botões da toolbar. Ver ToolbarConfig | ToolbarConfig | {} |
| filterSidebarConfig | Configuração do sidebar de filtros avançados. Ver FilterSidebarConfig | FilterSidebarConfig | {} |
| columnsSidebarConfig | Configuração do sidebar de personalização de colunas. Ver ColumnsSidebarConfig | ColumnsSidebarConfig | {} |
| configPresets | Quando informado, exibe o botão de preferências na barra de ações. Ver ReportPresetsTriggerConfig | ReportPresetsTriggerConfig | — |
ReportLayoutTextConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| docs | Texto do botão de documentação | String | 'Abrir documentação' |
| filter | Texto do botão de filtros avançados | String | 'Filtros avançados' |
| columns | Texto do botão de colunas | String | 'Colunas' |
| export | Texto do botão de exportação | String | 'Exportar' |
| generate | Texto do botão de geração | String | 'Gerar relatório' |
| expandSection | Texto usado no botão para expandir a tabela | String | 'Expandir tabela' |
| collapseSection | Texto usado no botão para recolher a tabela | String | 'Recolher tabela' |
| closeSection | Texto usado no botão interno de fechar da área expandida | String | 'Recolher tabela' |
| filterSidebarTitle | Título padrão do sidebar de filtros quando filterSidebarConfig.title não é informado | String | 'Filtros avançados' |
| columnsSidebarTitle | Título padrão do sidebar de colunas quando columnsSidebarConfig.title não é informado | String | 'Personalizar colunas' |
ToolbarConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| showFilter | Exibe o botão "Filtros avançados" | Boolean | true |
| showColumns | Exibe o botão "Colunas" | Boolean | false |
| showExport | Exibe o botão "Exportar" | Boolean | true |
| showGenerate | Exibe o botão "Gerar relatório" | Boolean | true |
| scrollable | Controla se a área de filtros na toolbar usa scroll horizontal quando houver overflow | Boolean | true |
| size | Define o tamanho dos controles padrão da toolbar | 'sm' | 'md' | 'lg' | 'sm' |
| enableStyleSelector | Habilita renderização do LxDataTableStyleSelector no final da lista de ações | Boolean | false |
| enableTableExpand | Habilita o botão de expandir tabela e o uso interno do LxExpandableContainer na área de conteúdo | Boolean | false |
| expandTeleportTo | Define o seletor CSS do alvo de Teleport usado quando a tabela é expandida | String | 'body' |
Quando toolbarConfig.enableTableExpand está ativo, o LxReportLayout usa internamente o LxExpandableContainer para focar a área de tabela (${id}-content). Durante a expansão, a toolbar é ocultada e o recolhimento é feito pelo controle interno do próprio container. Os textos de ação podem ser sobrescritos por textConfig e o título do container expandido reutiliza o title do relatório. Por padrão, o conteúdo expandido é teleportado para body (full page), mas você pode alterar o destino com toolbarConfig.expandTeleportTo.
FilterSidebarConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| title | Título exibido no cabeçalho do sidebar de filtros | String | 'Filtros avançados' |
ColumnsSidebarConfig
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| title | Título exibido no cabeçalho do sidebar de colunas | String | 'Personalizar colunas' |
| items | Lista de colunas disponíveis para personalização | LxDataTableColumnDef[] | [] |
ReportPresetsTriggerConfig
configPresets usa a mesma interface do LxReportPresetsTrigger, e o LxReportLayout monta internamente um settingsPresets com defaults para campos opcionais.
| Nome | Descrição | Tipo | Padrão |
|---|---|---|---|
| appliedView | Preferência atualmente aplicada; controla ícone e título do botão | ReportPreset | null | — |
| viewLists | Listas de preferências privadas, públicas e modelos | ViewLists | — |
| currentColumns | Colunas ativas no momento (para salvar na preferência) | ColumnsConfig | [] |
| currentFilters | Filtros ativos no momento (para salvar na preferência) | SavedFilter[] | [] |
| viewPageId | ID da página de preferências no sistema de preferências | Number | 0 |
| showTabPrivates | Exibe a aba de preferências privadas | Boolean | true |
| showTabPublics | Exibe a aba de preferências públicas | Boolean | true |
| showTabModels | Exibe a aba de modelos | Boolean | false |
| showCheckboxPublic | Exibe a opção de tornar a preferência pública | Boolean | false |
| showCheckboxDates | Exibe a opção de ignorar datas ao aplicar | Boolean | false |
| showCheckboxCompanies | Exibe a opção de ignorar empresas ao aplicar | Boolean | false |
| canAddPublicView | Permite criar preferências públicas na aba de públicas | Boolean | false |
| usersList | Lista de usuários exibida para seleção de administradores | PortalUser[] | — |
| size | Define o tamanho do botão gatilho de preferências | 'sm' | 'md' | 'lg' | 'sm' |
Eventos
| Nome | Descrição | Payload |
|---|---|---|
| export | Emitido ao clicar em "Exportar" | — |
| generate | Emitido ao clicar em "Gerar relatório" | — |
| update:tableStyle | Emitido ao alterar o estilo no LxDataTableStyleSelector | 'small' | 'large' |
| update:expandSection | Emitido ao alterar o estado expandido do botão de seção | boolean |
| expand:section | Emitido ao expandir região (mantendo alvo + trigger visíveis) | { targetId: string | null } |
| collapse:section | Emitido ao recolher seção e restaurar visibilidade | { targetId: string | null } |
| save:columns | Emitido ao salvar a configuração de colunas no sidebar | unknown[] |
| apply:view | Emitido ao aplicar uma preferência salva | ReportPreset |
| deactivate:view | Emitido ao desativar a preferência aplicada | ReportPreset |
| update:loading | Emitido durante operações assíncronas do painel de preferências | boolean |
| insert:preset | Emitido ao criar uma nova preferência | HostPresetPayload |
| update:preset | Emitido ao atualizar uma preferência existente | { id: number; data: HostPresetPayload } |
| delete:preset | Emitido ao excluir uma preferência | { id: number } |
Slots
Slots de override total
Quando fornecidos, substituem completamente o bloco padrão correspondente do LxBaseLayout.
| Nome | Escopo | Descrição |
|---|---|---|
| header | — | Substitui todo o cabeçalho padrão (título + ações) |
| content | — | Substitui toda a área de conteúdo (toolbar + tabela) |
| footer | — | Substitui o rodapé padrão. Só é renderizado quando o slot é fornecido |
| extra | — | Substitui a área de extras (sidebars de filtros e colunas) |
Slots de composição interna
Funcionam quando os slots de override acima não são fornecidos, permitindo customização pontual dentro do layout padrão.
| Nome | Escopo | Descrição |
|---|---|---|
| header-actions | — | Ações extras no cabeçalho, à esquerda do botão de ajuda |
| toolbar | — | Override total da toolbar; substitui todo o bloco de filtros + ações quando fornecido |
| filters | — | Inputs de filtros básicos na toolbar (ex: período, empresa) |
| filters-body | — | Conteúdo do sidebar de filtros avançados |
| filters-footer | { close } | Rodapé do sidebar de filtros; close() fecha o sidebar |
| table | { loading, tableStyle } | Conteúdo da área de tabela; loading repassa o estado da prop homônima e tableStyle expõe o estilo atual (small/large) |
Dependência do slot table
Quando você usa o slot table, o LxReportLayout deixa de renderizar uma tabela interna e passa a responsabilidade para o componente consumidor.
Por isso, o slot recebe dados de escopo que devem ser usados explicitamente na tabela renderizada:
loading: sincroniza o estado de carregamento do layout com a tabela.tableStyle: sincroniza o estilo selecionado noLxDataTableStyleSelector(smalloularge).
Se tableStyle não for aplicado no componente de tabela, mudar o seletor visual não terá efeito prático na renderização.
Exemplo de uso recomendado:
vue
<template #table="{ loading, tableStyle }">
<LxDataTable
:value="rows"
:loading="loading"
:visualization-config="{ size: tableStyle }"
>
...
</LxDataTable>
</template>Observações:
- O valor inicial de
tableStylenoLxReportLayoutésmall. - O evento
update:tableStyleé emitido comsmalloulargepara quem precisar persistir esse estado fora do layout.
LxComponents