forked from verdnatura/salix-front
feat: refs #6825 VnTableFilter and VnPanelFilter init
This commit is contained in:
parent
0fe957db80
commit
b76b2fd8a0
|
@ -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
|
||||||
|
icon="filter_alt"
|
||||||
|
title="asd"
|
||||||
|
class="bg-dark q-ml-md"
|
||||||
|
dense
|
||||||
|
@click="stateStore.toggleRightDrawer()"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<!-- VnTableColumn¿?-->
|
|
||||||
<template #header-cell="{ col }">
|
<template #header-cell="{ col }">
|
||||||
<QTh auto-width>
|
<QTh auto-width style="min-width: 100px">
|
||||||
<div class="q-pa-sm" :class="`text-${col.align ?? 'left'}`">
|
<VnTableFilter
|
||||||
{{ col.label }}
|
:column="col"
|
||||||
</div>
|
:show-title="true"
|
||||||
<hr class="q-ma-none divisor-line" />
|
:data-key="$attrs['data-key']"
|
||||||
<QInput
|
v-model="filters[col.field]"
|
||||||
v-if="columnSearch"
|
|
||||||
dense
|
|
||||||
:type="col.component == 'number' ? 'number' : 'text'"
|
|
||||||
class="q-px-md q-pb-xs"
|
|
||||||
/>
|
/>
|
||||||
</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,41 +189,51 @@ 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"
|
||||||
<div
|
:class="
|
||||||
v-if="
|
mode == 'list' || $q.screen.lt.md
|
||||||
col.cardVisible &&
|
? 'grid-three'
|
||||||
!col.isId &&
|
: 'grid-one'
|
||||||
col.field != 'tableActions'
|
"
|
||||||
"
|
>
|
||||||
>
|
<div v-for="col of columnsCard(colsMap)" :key="col.field">
|
||||||
<VnLv :label="`${col.label}:`">
|
<div
|
||||||
<template #value>
|
v-if="
|
||||||
<VnTableColumn :column="col" :row />
|
col.cardVisible &&
|
||||||
</template>
|
!col.isId &&
|
||||||
</VnLv>
|
col.field != 'tableActions'
|
||||||
</div>
|
"
|
||||||
|
>
|
||||||
|
<VnLv :label="`${col.label}:`">
|
||||||
|
<template #value>
|
||||||
|
<VnTableColumn :column="col" :row />
|
||||||
|
</template>
|
||||||
|
</VnLv>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="colsMap.tableActions" class="column">
|
|
||||||
<QBtn
|
|
||||||
v-for="(btn, index) of colsMap.tableActions
|
|
||||||
.actions"
|
|
||||||
:key="index"
|
|
||||||
:title="btn.title"
|
|
||||||
:icon="btn.icon"
|
|
||||||
:outline="!btn.isPrimary"
|
|
||||||
size="sm"
|
|
||||||
class="q-pa-sm q-mb-sm"
|
|
||||||
:class="{ 'bg-primary-light': btn.isPrimary }"
|
|
||||||
@click.stop="btn.action(row)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
</QCard>
|
</QCardSection>
|
||||||
</TransitionGroup>
|
<!-- Actions -->
|
||||||
|
<QCardSection
|
||||||
|
v-if="colsMap.tableActions"
|
||||||
|
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
|
||||||
|
>
|
||||||
|
<QBtn
|
||||||
|
v-for="(btn, index) of colsMap.tableActions.actions"
|
||||||
|
:key="index"
|
||||||
|
:title="btn.title"
|
||||||
|
:icon="btn.icon"
|
||||||
|
:outline="!btn.isPrimary"
|
||||||
|
size="sm"
|
||||||
|
class="q-pa-sm"
|
||||||
|
:class="{ 'bg-primary-light': btn.isPrimary }"
|
||||||
|
@click.stop="btn.action(row)"
|
||||||
|
/>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<!-- </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>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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"
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Reference in New Issue