feat(VnTable): add visibleColumns #536
|
@ -13,6 +13,7 @@ import VnLv from 'components/ui/VnLv.vue';
|
|||
import VnTableColumn from 'components/VnTable/VnColumn.vue';
|
||||
import VnTableFilter from 'components/VnTable/VnFilter.vue';
|
||||
import VnTableChip from 'components/VnTable/VnChip.vue';
|
||||
import TableVisibleColumns from 'src/components/VnTable/VnVisibleColumn.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
columns: {
|
||||
|
@ -67,6 +68,10 @@ const $props = defineProps({
|
|||
type: Object,
|
||||
default: () => ({ card: false, table: false }),
|
||||
},
|
||||
tableCode: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
table: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
|
@ -119,6 +124,14 @@ watch(
|
|||
(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) {
|
||||
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) {
|
||||
router.push({ path: `/${$props.redirect}/${id}` });
|
||||
}
|
||||
|
@ -240,7 +247,7 @@ defineExpose({
|
|||
:limit="20"
|
||||
ref="CrudModelRef"
|
||||
:search-url="searchUrl"
|
||||
:disable-infinite-scroll="mode == TABLE_MODE"
|
||||
:disable-infinite-scroll="isTableMode"
|
||||
@save-changes="reload"
|
||||
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
||||
>
|
||||
|
@ -258,11 +265,11 @@ defineExpose({
|
|||
:columns="splittedColumns.columns"
|
||||
:rows="rows"
|
||||
v-model:selected="selected"
|
||||
:grid="mode != TABLE_MODE"
|
||||
:grid="!isTableMode"
|
||||
table-header-class="bg-header"
|
||||
card-container-class="grid-three"
|
||||
flat
|
||||
:style="mode == TABLE_MODE && 'max-height: 90vh'"
|
||||
:style="isTableMode && 'max-height: 90vh'"
|
||||
virtual-scroll
|
||||
@virtual-scroll="
|
||||
(event) =>
|
||||
|
@ -276,13 +283,12 @@ defineExpose({
|
|||
<slot name="top-left"></slot>
|
||||
</template>
|
||||
<template #top-right>
|
||||
<!-- <QBtn
|
||||
icon="visibility"
|
||||
title="asd"
|
||||
class="bg-vn-section-color q-mr-md"
|
||||
dense
|
||||
v-if="mode == 'table'"
|
||||
/> -->
|
||||
<TableVisibleColumns
|
||||
v-if="isTableMode"
|
||||
v-model="splittedColumns.columns"
|
||||
:table-code="tableCode ?? route.name"
|
||||
class="q-mr-md"
|
||||
/>
|
||||
<QBtnToggle
|
||||
v-model="mode"
|
||||
toggle-color="primary"
|
||||
|
@ -302,7 +308,7 @@ defineExpose({
|
|||
<QTh
|
||||
auto-width
|
||||
style="min-width: 100px"
|
||||
v-if="$props.columnSearch"
|
||||
v-if="$props.columnSearch && col.visible"
|
||||
>
|
||||
<VnTableFilter
|
||||
:column="col"
|
||||
|
@ -334,6 +340,7 @@ defineExpose({
|
|||
auto-width
|
||||
class="no-margin q-px-xs"
|
||||
:class="getColAlign(col)"
|
||||
v-if="col.visible"
|
||||
>
|
||||
<slot :name="`column-${col.name}`" :col="col" :row="row">
|
||||
<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