0
0
Fork 0

feat: refs #6825 VnTableFilter and VnPanelFilter init

This commit is contained in:
Alex Moreno 2024-05-03 15:03:54 +02:00
parent 0fe957db80
commit b76b2fd8a0
6 changed files with 280 additions and 72 deletions

View File

@ -1,11 +1,17 @@
<script setup> <script setup>
import { ref, onMounted, computed } from 'vue'; import { ref, onMounted, computed } from 'vue';
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import { useStateStore } from 'stores/useStateStore';
import VnPaginate from 'components/ui/VnPaginate.vue'; import VnPaginate from 'components/ui/VnPaginate.vue';
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
import VnLv from 'components/ui/VnLv.vue';
import VnBreadcrumbs from 'components/common/VnBreadcrumbs.vue'; import VnBreadcrumbs from 'components/common/VnBreadcrumbs.vue';
import VnTableColumn from 'src/components/common/VnTableColumn.vue'; import VnTableColumn from 'components/common/VnTableColumn.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnTableFilter from 'components/common/VnTableFilter.vue';
const $props = defineProps({ const $props = defineProps({
columns: { columns: {
@ -35,8 +41,11 @@ const $props = defineProps({
}); });
const { t } = useI18n(); const { t } = useI18n();
const $q = useQuasar(); const $q = useQuasar();
const stateStore = useStateStore();
const mode = ref('list'); const mode = ref('list');
const selected = ref([]); const selected = ref([]);
const filters = ref({});
const tableModes = computed(() => { const tableModes = computed(() => {
const modes = [ const modes = [
{ {
@ -60,25 +69,38 @@ const tableModes = computed(() => {
return modes; return modes;
}); });
// {
// isId: Boolean
// align: 'left',
// field: 'hasFile',
// label: t('globals.original'),
// name: 'hasFile',
// component: QCheckbox ?? span,
// cardVisible: Boolean
// props: (prop) => ({
// disable: true,
// 'model-value': Boolean(prop.value),
// }),
// },
// vnTableOpitons y hacer bucle
onMounted(() => { onMounted(() => {
mode.value = $props.defaultMode; mode.value = $props.defaultMode;
stateStore.rightDrawer = true;
}); });
function columnsCard(cols) {
return Object.values(cols).filter(
(col) => col.cardVisible && !col.isId && col.field != 'tableActions'
);
}
</script> </script>
<template> <template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<VnFilterPanel
:data-key="$attrs['data-key']"
:search-button="true"
:params="filters"
>
<template #body>
<VnTableFilter
:column="col"
:data-key="$attrs['data-key']"
v-for="col of columns"
:key="col.id"
v-model="filters[col.field]"
/>
</template>
</VnFilterPanel>
</QScrollArea>
</QDrawer>
<VnPaginate v-bind="$attrs" class="q-px-md"> <VnPaginate v-bind="$attrs" class="q-px-md">
<template #body="{ rows }"> <template #body="{ rows }">
<!-- :grid="($q.screen.lt.md && reponsive) || mode != 'table'" --> <!-- :grid="($q.screen.lt.md && reponsive) || mode != 'table'" -->
@ -118,42 +140,45 @@ onMounted(() => {
dense dense
:options="tableModes" :options="tableModes"
/> />
<QBtn icon="filter_alt" title="asd" class="bg-dark q-ml-md" dense /> <QBtn
</template> icon="filter_alt"
<!-- VnTableColumn¿?--> title="asd"
<template #header-cell="{ col }"> class="bg-dark q-ml-md"
<QTh auto-width>
<div class="q-pa-sm" :class="`text-${col.align ?? 'left'}`">
{{ col.label }}
</div>
<hr class="q-ma-none divisor-line" />
<QInput
v-if="columnSearch"
dense dense
:type="col.component == 'number' ? 'number' : 'text'" @click="stateStore.toggleRightDrawer()"
class="q-px-md q-pb-xs" />
</template>
<template #header-cell="{ col }">
<QTh auto-width style="min-width: 100px">
<VnTableFilter
:column="col"
:show-title="true"
:data-key="$attrs['data-key']"
v-model="filters[col.field]"
/> />
</QTh> </QTh>
</template> </template>
<template #body-cell="{ row, col }"> <template #body-cell="{ col, row }">
<!-- Columns -->
<QTd auto-width :class="`text-${col.align ?? 'left'}`"> <QTd auto-width :class="`text-${col.align ?? 'left'}`">
<VnTableColumn :column="col" :row /> <VnTableColumn :column="col" :row="row" />
</QTd> </QTd>
</template> </template>
<template #item="{ row, colsMap }"> <template #item="{ row, colsMap }">
<TransitionGroup name="grid" tag="div" class="grid"> <!-- <TransitionGroup name="grid" tag="div" class="grid"> -->
<QCard bordered flat> <QCard bordered flat class="row no-wrap justify-between">
<QCardSection horizontal> <QCardSection vertical class="no-margin no-padding w-80">
<span v-for="(col, index) of colsMap" :key="col.field"> <!-- Chips -->
{{ index }} <QCardSection horizontal class="w-80">
<span v-for="col of colsMap" :key="col.field">
<QChip <QChip
:class=" :class="
col.color col.color
? col.color(row) ? col.color(row)
: col.isId == 1 : col.isId == 1
? 'bg-primary-light' ? 'bg-primary-light'
: 'bg-secondary' : 'bg-chip-secondary'
" "
square square
v-if="col.isId" v-if="col.isId"
@ -164,9 +189,16 @@ onMounted(() => {
</QChip> </QChip>
</span> </span>
</QCardSection> </QCardSection>
<QCardSection class="row justify-between q-pa-sm"> <!-- Fields -->
<div> <QCardSection
<div v-for="col of colsMap" :key="col.field"> class="q-pa-sm w-80"
:class="
mode == 'list' || $q.screen.lt.md
? 'grid-three'
: 'grid-one'
"
>
<div v-for="col of columnsCard(colsMap)" :key="col.field">
<div <div
v-if=" v-if="
col.cardVisible && col.cardVisible &&
@ -181,24 +213,27 @@ onMounted(() => {
</VnLv> </VnLv>
</div> </div>
</div> </div>
</div> </QCardSection>
<div v-if="colsMap.tableActions" class="column"> </QCardSection>
<!-- Actions -->
<QCardSection
v-if="colsMap.tableActions"
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
>
<QBtn <QBtn
v-for="(btn, index) of colsMap.tableActions v-for="(btn, index) of colsMap.tableActions.actions"
.actions"
:key="index" :key="index"
:title="btn.title" :title="btn.title"
:icon="btn.icon" :icon="btn.icon"
:outline="!btn.isPrimary" :outline="!btn.isPrimary"
size="sm" size="sm"
class="q-pa-sm q-mb-sm" class="q-pa-sm"
:class="{ 'bg-primary-light': btn.isPrimary }" :class="{ 'bg-primary-light': btn.isPrimary }"
@click.stop="btn.action(row)" @click.stop="btn.action(row)"
/> />
</div>
</QCardSection> </QCardSection>
</QCard> </QCard>
</TransitionGroup> <!-- </TransitionGroup> -->
</template> </template>
</QTable> </QTable>
</template> </template>
@ -213,7 +248,7 @@ onMounted(() => {
color: var(--vn-section-color); color: var(--vn-section-color);
} }
.bg-secondary { .bg-chip-secondary {
background-color: var(--vn-page-color); background-color: var(--vn-page-color);
color: var(--vn-text-colo); color: var(--vn-text-colo);
} }
@ -308,4 +343,12 @@ onMounted(() => {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.w-80 {
width: 80%;
}
.w-20 {
width: 20%;
}
</style> </style>

View File

@ -0,0 +1,108 @@
<template>
<div
v-if="showTitle && column"
class="q-pt-sm q-px-sm ellipsis"
:class="`text-${column.align ?? 'left'}`"
>
{{ column.label }}
</div>
<div
v-if="columnFilter !== false && column.field != 'tableActions'"
class="row no-wrap"
>
<hr class="q-ma-none divisor-line" v-if="showTitle" />
<component
v-if="columnFilter?.component"
:is="isBasicComponent?.component ?? columnFilter.component"
v-model="model"
v-bind="columnFilter.attrs"
v-on="isBasicComponent?.event ?? columnFilter.event"
dense
/>
<span v-else class="full-width">
<QInput
v-model="model"
dense
class="q-px-sm q-pb-xs q-pt-none"
:label="showTitle ? '' : column.label"
@keyup.enter="addFilter"
>
<template #append> </template>
</QInput>
</span>
</div>
<div v-else-if="showTitle" style="height: 45px"><!-- fixme! --></div>
</template>
<script setup>
import { markRaw, computed, defineModel } from 'vue';
import { QCheckbox } from 'quasar';
import { useArrayData } from 'composables/useArrayData';
/* basic input */
import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
const $props = defineProps({
column: {
type: Object,
required: true,
},
showTitle: {
type: Boolean,
default: false,
},
dataKey: {
type: String,
required: true,
},
addModel: {
type: Object,
default: () => {},
},
});
const model = defineModel();
const arrayData = useArrayData($props.dataKey);
const columnFilter = computed(() => $props.column?.columnFilter);
const isBasicComponent = computed(
() => components[$props.column?.columnFilter?.component]
);
const updateEvent = { 'update:modelValue': addFilter };
const enterEvent = { 'keyup.enter': addFilter };
const components = {
input: {
component: markRaw(VnInput),
event: enterEvent,
},
number: {
component: markRaw(VnInput),
event: enterEvent,
},
date: {
component: markRaw(VnInputDate),
event: updateEvent,
},
checkbox: {
component: markRaw(QCheckbox),
event: updateEvent,
},
select: {
component: markRaw(VnSelect),
event: updateEvent,
},
};
async function addFilter() {
const value = model.value == '' ? null : model.value;
const prefix = columnFilter.value?.inWhere?.prefix;
let field = columnFilter.value?.field ?? $props.column.field;
field = prefix ? prefix + '.' + field : field;
const toFilter = { [field]: value };
const filter = columnFilter.value?.inWhere
? { filter: { where: toFilter } }
: { params: toFilter };
await arrayData.addFilter(filter);
}
</script>

View File

@ -0,0 +1,13 @@
<template>
<QSelect dense icon="filter_alt" flat size="xs" :options="filterOptions"> </QSelect>
</template>
<script setup>
const model = defineModel();
const filterOptions = [{ label: '%' }, { label: '<' }, { label: '>' }];
async function encapsulate(field) {
// ejemplo
// si es % que te ponga {like: `%${field}%`}
}
</script>

View File

@ -0,0 +1,33 @@
// {
// isId: Boolean
// align: 'left',
// field: 'hasFile',
// label: t('globals.original'),
// name: 'hasFile',
// component: QCheckbox ?? span,
// cardVisible: Boolean
// isId: 1/2
// color: function
// props: (prop) => ({
// disable: true,
// 'model-value': Boolean(prop.value),
// }),
// tableActions: {
// field: 'tableActions',
// name: 'tableActions',
// actions: [
// {
// title: t('Client ticket list'),
// icon: 'vn:ticket',
// action: redirectToCreateView,
// isPrimary: true,
// },
// {
// title: t('Client ticket list'),
// icon: 'preview',
// action: (row) => viewSummary(row.id, CustomerSummary),
// },
// ],
// },
// },
// tableActions y hacer bucle

View File

@ -62,6 +62,8 @@ onMounted(() => {
if (Object.keys(store.userParams).length > 0) { if (Object.keys(store.userParams).length > 0) {
userParams.value = JSON.parse(JSON.stringify(store.userParams)); userParams.value = JSON.parse(JSON.stringify(store.userParams));
} }
console.log('userParams.value: ', userParams.value);
emit('init', { params: userParams.value }); emit('init', { params: userParams.value });
}); });
@ -165,7 +167,7 @@ function formatValue(value) {
</script> </script>
<template> <template>
<QForm @submit="search" id="filterPanelForm"> <div id="filterPanelForm">
<QList dense> <QList dense>
<QItem class="q-mt-xs"> <QItem class="q-mt-xs">
<QItemSection top> <QItemSection top>
@ -255,7 +257,7 @@ function formatValue(value) {
</QItem> </QItem>
<QSeparator /> <QSeparator />
</template> </template>
</QForm> </div>
<QInnerLoading <QInnerLoading
:label="t('globals.pleaseWait')" :label="t('globals.pleaseWait')"
:showing="isLoading" :showing="isLoading"

View File

@ -265,6 +265,7 @@ const columns = computed(() => [
field: 'customerStatus', field: 'customerStatus',
label: 'customerStatus', label: 'customerStatus',
name: 'customerStatus', name: 'customerStatus',
columnFilter: false,
}, },
{ {
align: 'left', align: 'left',
@ -272,6 +273,9 @@ const columns = computed(() => [
label: t('customer.extendedList.tableVisibleColumns.id'), label: t('customer.extendedList.tableVisibleColumns.id'),
name: 'id', name: 'id',
isId: 1, isId: 1,
columnFilter: {
field: 'search',
},
}, },
{ {
align: 'left', align: 'left',
@ -279,6 +283,11 @@ const columns = computed(() => [
label: t('customer.extendedList.tableVisibleColumns.name'), label: t('customer.extendedList.tableVisibleColumns.name'),
name: 'name', name: 'name',
isId: 2, isId: 2,
columnFilter: {
inWhere: {
prefix: 'c',
},
},
}, },
{ {
align: 'left', align: 'left',