feat(VnTable): add visibleColumns #536
|
@ -13,6 +13,7 @@ import VnLv from 'components/ui/VnLv.vue';
|
||||||
import VnTableColumn from 'components/VnTable/VnColumn.vue';
|
import VnTableColumn from 'components/VnTable/VnColumn.vue';
|
||||||
import VnTableFilter from 'components/VnTable/VnFilter.vue';
|
import VnTableFilter from 'components/VnTable/VnFilter.vue';
|
||||||
import VnTableChip from 'components/VnTable/VnChip.vue';
|
import VnTableChip from 'components/VnTable/VnChip.vue';
|
||||||
|
import TableVisibleColumns from 'src/components/VnTable/VnVisibleColumn.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
columns: {
|
columns: {
|
||||||
|
@ -67,6 +68,10 @@ const $props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({ card: false, table: false }),
|
default: () => ({ card: false, table: false }),
|
||||||
},
|
},
|
||||||
|
tableCode: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
table: {
|
table: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -119,6 +124,14 @@ watch(
|
||||||
(val) => setUserParams(val)
|
(val) => setUserParams(val)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rowClickFunction = computed(() => {
|
||||||
|
if ($props.rowClick) return $props.rowClick;
|
||||||
|
if ($props.redirect) return ({ id }) => redirectFn(id);
|
||||||
|
return () => {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
||||||
|
|
||||||
function setUserParams(watchedParams) {
|
function setUserParams(watchedParams) {
|
||||||
if (!watchedParams) return;
|
if (!watchedParams) return;
|
||||||
|
|
||||||
|
@ -162,12 +175,6 @@ function splitColumns(columns) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowClickFunction = computed(() => {
|
|
||||||
if ($props.rowClick) return $props.rowClick;
|
|
||||||
if ($props.redirect) return ({ id }) => redirectFn(id);
|
|
||||||
return () => {};
|
|
||||||
});
|
|
||||||
|
|
||||||
function redirectFn(id) {
|
function redirectFn(id) {
|
||||||
router.push({ path: `/${$props.redirect}/${id}` });
|
router.push({ path: `/${$props.redirect}/${id}` });
|
||||||
}
|
}
|
||||||
|
@ -240,7 +247,7 @@ defineExpose({
|
||||||
:limit="20"
|
:limit="20"
|
||||||
ref="CrudModelRef"
|
ref="CrudModelRef"
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
:disable-infinite-scroll="mode == TABLE_MODE"
|
:disable-infinite-scroll="isTableMode"
|
||||||
@save-changes="reload"
|
@save-changes="reload"
|
||||||
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
||||||
>
|
>
|
||||||
|
@ -258,11 +265,11 @@ defineExpose({
|
||||||
:columns="splittedColumns.columns"
|
:columns="splittedColumns.columns"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
v-model:selected="selected"
|
v-model:selected="selected"
|
||||||
:grid="mode != TABLE_MODE"
|
:grid="!isTableMode"
|
||||||
table-header-class="bg-header"
|
table-header-class="bg-header"
|
||||||
card-container-class="grid-three"
|
card-container-class="grid-three"
|
||||||
flat
|
flat
|
||||||
:style="mode == TABLE_MODE && 'max-height: 90vh'"
|
:style="isTableMode && 'max-height: 90vh'"
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
@virtual-scroll="
|
@virtual-scroll="
|
||||||
(event) =>
|
(event) =>
|
||||||
|
@ -276,13 +283,12 @@ defineExpose({
|
||||||
<slot name="top-left"></slot>
|
<slot name="top-left"></slot>
|
||||||
</template>
|
</template>
|
||||||
<template #top-right>
|
<template #top-right>
|
||||||
<!-- <QBtn
|
<TableVisibleColumns
|
||||||
icon="visibility"
|
v-if="isTableMode"
|
||||||
title="asd"
|
v-model="splittedColumns.columns"
|
||||||
class="bg-vn-section-color q-mr-md"
|
:table-code="tableCode ?? route.name"
|
||||||
dense
|
class="q-mr-md"
|
||||||
v-if="mode == 'table'"
|
/>
|
||||||
/> -->
|
|
||||||
<QBtnToggle
|
<QBtnToggle
|
||||||
v-model="mode"
|
v-model="mode"
|
||||||
toggle-color="primary"
|
toggle-color="primary"
|
||||||
|
@ -302,7 +308,7 @@ defineExpose({
|
||||||
<QTh
|
<QTh
|
||||||
auto-width
|
auto-width
|
||||||
style="min-width: 100px"
|
style="min-width: 100px"
|
||||||
v-if="$props.columnSearch"
|
v-if="$props.columnSearch && col.visible"
|
||||||
>
|
>
|
||||||
<VnTableFilter
|
<VnTableFilter
|
||||||
:column="col"
|
:column="col"
|
||||||
|
@ -334,6 +340,7 @@ defineExpose({
|
||||||
auto-width
|
auto-width
|
||||||
class="no-margin q-px-xs"
|
class="no-margin q-px-xs"
|
||||||
:class="getColAlign(col)"
|
:class="getColAlign(col)"
|
||||||
|
v-if="col.visible"
|
||||||
>
|
>
|
||||||
<slot :name="`column-${col.name}`" :col="col" :row="row">
|
<slot :name="`column-${col.name}`" :col="col" :row="row">
|
||||||
<VnTableColumn
|
<VnTableColumn
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import axios from 'axios';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
|
||||||
|
const columns = defineModel({ type: Object, default: [] });
|
||||||
|
const $props = defineProps({
|
||||||
|
tableCode: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser();
|
||||||
|
const popupProxyRef = ref();
|
||||||
|
const initialUserConfigViewData = ref();
|
||||||
|
const localColumns = ref([]);
|
||||||
|
|
||||||
|
const areAllChecksMarked = computed(() => {
|
||||||
|
return localColumns.value.every((col) => col.visible);
|
||||||
|
});
|
||||||
|
|
||||||
|
function setUserConfigViewData(data, isLocal) {
|
||||||
|
if (!data) return;
|
||||||
|
// Importante: El name de las columnas de la tabla debe conincidir con el name de las variables que devuelve la view config
|
||||||
|
if (!isLocal) localColumns.value = [];
|
||||||
|
for (let column of columns.value) {
|
||||||
|
const { label, name } = column;
|
||||||
|
column.visible = data[name] ?? true;
|
||||||
|
if (!isLocal) localColumns.value.push({ name, label, visible: column.visible });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMarkAll(val) {
|
||||||
|
localColumns.value.forEach((col) => (col.visible = val));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getConfig(url, filter) {
|
||||||
|
const response = await axios.get(url, {
|
||||||
|
params: { filter: filter },
|
||||||
|
});
|
||||||
|
return response.data && response.data.length > 0 ? response.data[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchViewConfigData() {
|
||||||
|
try {
|
||||||
|
const defaultFilter = {
|
||||||
|
where: { tableCode: $props.tableCode },
|
||||||
|
};
|
||||||
|
|
||||||
|
const userConfig = await getConfig('UserConfigViews', {
|
||||||
|
where: {
|
||||||
|
...defaultFilter.where,
|
||||||
|
...{ userFk: user.id },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (userConfig) {
|
||||||
|
initialUserConfigViewData.value = userConfig;
|
||||||
|
setUserConfigViewData(userConfig.configuration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultConfig = await getConfig('DefaultViewConfigs', defaultFilter);
|
||||||
|
if (defaultConfig) {
|
||||||
|
setUserConfigViewData(defaultConfig.columns);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.err('Error fetching config view data', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveConfig() {
|
||||||
|
const configuration = {};
|
||||||
|
for (const { name, visible } of localColumns.value)
|
||||||
|
configuration[name] = visible ?? true;
|
||||||
|
setUserConfigViewData(configuration, true);
|
||||||
|
if (!$props.tableCode) return popupProxyRef.value.hide();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {};
|
||||||
|
// Si existe una view config del usuario hacemos un update si no la creamos
|
||||||
|
if (initialUserConfigViewData.value) {
|
||||||
|
params.updates = [
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
configuration,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: initialUserConfigViewData.value.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
params.creates = [
|
||||||
|
{
|
||||||
|
userFk: user.value.id,
|
||||||
|
tableCode: $props.tableCode,
|
||||||
|
tableConfig: $props.tableCode,
|
||||||
|
configuration,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post('UserConfigViews/crud', params);
|
||||||
|
if (response.data && response.data[0]) {
|
||||||
|
initialUserConfigViewData.value = response.data[0];
|
||||||
|
}
|
||||||
|
notify('globals.dataSaved', 'positive');
|
||||||
|
popupProxyRef.value.hide();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error saving user view config', err);
|
||||||
|
notify('errors.writeRequest', 'negative');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
setUserConfigViewData({});
|
||||||
|
await fetchViewConfigData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<QBtn icon="vn:visible_columns" class="bg-vn-section-color q-mr-md" dense>
|
||||||
|
<QPopupProxy ref="popupProxyRef">
|
||||||
|
<QCard class="column q-pa-md">
|
||||||
|
<QIcon name="info" size="sm" class="info-icon">
|
||||||
|
<QTooltip>{{ t('Check the columns you want to see') }}</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<span class="text-body1 q-mb-sm">{{ t('Visible columns') }}</span>
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('Tick all')"
|
||||||
|
:model-value="areAllChecksMarked"
|
||||||
|
@update:model-value="toggleMarkAll($event)"
|
||||||
|
class="q-mb-sm"
|
||||||
|
/>
|
||||||
|
<div v-if="columns.length > 0" class="checks-layout">
|
||||||
|
<QCheckbox
|
||||||
|
v-for="col in localColumns"
|
||||||
|
:key="col.name"
|
||||||
|
:label="col.label"
|
||||||
|
v-model="col.visible"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<QBtn
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
color="primary"
|
||||||
|
@click="saveConfig()"
|
||||||
|
:label="t('globals.save')"
|
||||||
|
/>
|
||||||
|
</QCard>
|
||||||
|
</QPopupProxy>
|
||||||
|
<QTooltip>{{ t('Visible columns') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.info-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checks-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 200px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Check the columns you want to see: Marca las columnas que quieres ver
|
||||||
|
Visible columns: Columnas visibles
|
||||||
|
Tick all: Marcar todas
|
||||||
|
</i18n>
|
Loading…
Reference in New Issue