forked from verdnatura/salix-front
Add catalog filter
This commit is contained in:
parent
ecad464366
commit
af5f87a6a1
|
@ -31,11 +31,21 @@ const props = defineProps({
|
||||||
description:
|
description:
|
||||||
'Algunos filtros vienen con parametros de búsqueda por default y necesitan tener si o si un valor, por eso de ser necesario, esta prop nos sirve para saber que filtros podemos remover y cuales no',
|
'Algunos filtros vienen con parametros de búsqueda por default y necesitan tener si o si un valor, por eso de ser necesario, esta prop nos sirve para saber que filtros podemos remover y cuales no',
|
||||||
},
|
},
|
||||||
|
exprBuilder: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
hiddenTags: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['refresh', 'clear', 'search']);
|
const emit = defineEmits(['refresh', 'clear', 'search', 'init']);
|
||||||
|
|
||||||
const arrayData = useArrayData(props.dataKey);
|
const arrayData = useArrayData(props.dataKey, {
|
||||||
|
exprBuilder: props.exprBuilder,
|
||||||
|
});
|
||||||
const store = arrayData.store;
|
const store = arrayData.store;
|
||||||
const userParams = ref({});
|
const userParams = ref({});
|
||||||
|
|
||||||
|
@ -44,9 +54,11 @@ 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));
|
||||||
}
|
}
|
||||||
|
emit('init', { params: userParams.value });
|
||||||
});
|
});
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
const params = { ...userParams.value };
|
const params = { ...userParams.value };
|
||||||
|
@ -93,17 +105,12 @@ async function clearFilters() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = computed(() => {
|
const tags = computed(() => {
|
||||||
const params = [];
|
return Object.entries(userParams.value)
|
||||||
|
.filter(([key, value]) => value && !(props.hiddenTags || []).includes(key))
|
||||||
for (const param in userParams.value) {
|
.map(([key, value]) => ({
|
||||||
if (!userParams.value[param]) continue;
|
label: key,
|
||||||
params.push({
|
value: value,
|
||||||
label: param,
|
}));
|
||||||
value: userParams.value[param],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function remove(key) {
|
async function remove(key) {
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const props = defineProps({
|
||||||
|
dataKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const categoryList = ref(null);
|
||||||
|
const selectedCategoryFk = ref(null);
|
||||||
|
const typeList = ref(null);
|
||||||
|
const selectedTypeFk = ref(null);
|
||||||
|
|
||||||
|
const selectCategory = (params, category) => {
|
||||||
|
if (params.categoryFk === category?.id) {
|
||||||
|
selectedCategoryFk.value = null;
|
||||||
|
params.categoryFk = null;
|
||||||
|
typeList.value = null;
|
||||||
|
} else {
|
||||||
|
selectedCategoryFk.value = category?.id;
|
||||||
|
params.categoryFk = category?.id;
|
||||||
|
loadTypes(category?.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadTypes = async (categoryFk) => {
|
||||||
|
const { data } = await axios.get(`Orders/${route.params.id}/getItemTypeAvailable`, {
|
||||||
|
params: { itemCategoryId: categoryFk },
|
||||||
|
});
|
||||||
|
typeList.value = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onFilterInit = async ({ params }) => {
|
||||||
|
if (params.typeFk) {
|
||||||
|
selectedTypeFk.value = params.typeFk;
|
||||||
|
}
|
||||||
|
if (params.categoryFk) {
|
||||||
|
await loadTypes(params.categoryFk);
|
||||||
|
selectedCategoryFk.value = params.categoryFk;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedCategory = computed(() =>
|
||||||
|
(categoryList.value || []).find(
|
||||||
|
(category) => category?.id === selectedCategoryFk.value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedType = computed(() => {
|
||||||
|
return (typeList.value || []).find((type) => type?.id === selectedTypeFk.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
function exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'categoryFk':
|
||||||
|
case 'typeFk':
|
||||||
|
return { [param]: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="ItemCategories"
|
||||||
|
limit="30"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="
|
||||||
|
(data) => {
|
||||||
|
categoryList = (data || [])
|
||||||
|
.filter((category) => category.display)
|
||||||
|
.map((category) => ({
|
||||||
|
...category,
|
||||||
|
icon: `vn:${(category.icon || '').split('-')[1]}`,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<VnFilterPanel
|
||||||
|
:data-key="props.dataKey"
|
||||||
|
:search-button="true"
|
||||||
|
:hidden-tags="['orderFk', 'orderBy']"
|
||||||
|
:expr-builder="exprBuilder"
|
||||||
|
@init="onFilterInit"
|
||||||
|
>
|
||||||
|
<template #tags="{ tag, formatFn }">
|
||||||
|
<strong v-if="tag.label === 'categoryFk'">
|
||||||
|
{{ t(selectedCategory?.name || '') }}
|
||||||
|
</strong>
|
||||||
|
<strong v-else-if="tag.label === 'typeFk'">
|
||||||
|
{{ t(selectedType?.name || '') }}
|
||||||
|
</strong>
|
||||||
|
<div v-else class="q-gutter-x-xs">
|
||||||
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #body="{ params }">
|
||||||
|
<QList dense>
|
||||||
|
<QItem class="category-filter q-mt-md">
|
||||||
|
<div
|
||||||
|
v-for="category in categoryList"
|
||||||
|
:key="category.name"
|
||||||
|
:class="[
|
||||||
|
'category',
|
||||||
|
category.id === params?.categoryFk && 'active',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<QIcon
|
||||||
|
:name="category.icon"
|
||||||
|
class="category-icon"
|
||||||
|
@click="selectCategory(params, category)"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t(category.name) }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
</div>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelectFilter
|
||||||
|
:label="t('params.type')"
|
||||||
|
v-model="params.typeFk"
|
||||||
|
:options="typeList"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
emit-value
|
||||||
|
use-input
|
||||||
|
:disable="!selectedCategoryFk"
|
||||||
|
@update:model-value="(value) => (selectedTypeFk = value)"
|
||||||
|
>
|
||||||
|
<template #option="{ itemProps, opt }">
|
||||||
|
<QItem v-bind="itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||||
|
<QItemLabel caption>
|
||||||
|
{{ opt.categoryName }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelectFilter>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</QList>
|
||||||
|
</template>
|
||||||
|
</VnFilterPanel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.category-filter {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.category {
|
||||||
|
flex: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.category-icon {
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-icon {
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--vn-label);
|
||||||
|
font-size: 2.6rem;
|
||||||
|
padding: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
params:
|
||||||
|
type: Type
|
||||||
|
orderBy: Order By
|
||||||
|
es:
|
||||||
|
params:
|
||||||
|
type: Tipo
|
||||||
|
orderBy: Ordenar por
|
||||||
|
Plant: Planta
|
||||||
|
Flower: Flor
|
||||||
|
Handmade: Confección
|
||||||
|
Green: Verde
|
||||||
|
Accessories: Complemento
|
||||||
|
Fruit: Fruta
|
||||||
|
</i18n>
|
|
@ -6,6 +6,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
import OrderCatalogItem from 'pages/Order/Card/OrderCatalogItem.vue';
|
import OrderCatalogItem from 'pages/Order/Card/OrderCatalogItem.vue';
|
||||||
|
import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
@ -54,7 +55,9 @@ function exprBuilder(param, value) {
|
||||||
</div>
|
</div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||||
<QScrollArea class="fit text-grey-8"></QScrollArea>
|
<QScrollArea class="fit text-grey-8">
|
||||||
|
<OrderCatalogFilter data-key="OrderCatalogList" />
|
||||||
|
</QScrollArea>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
<QPage class="column items-center q-pa-md">
|
<QPage class="column items-center q-pa-md">
|
||||||
<div class="card-list">
|
<div class="card-list">
|
||||||
|
|
Loading…
Reference in New Issue