Merge pull request 'Order Catalog Filter' (#59) from feature/order-catalog-filter into branch-PR-2
Reviewed-on: hyervoni/salix-front-mindshore#59
This commit is contained in:
commit
1f12609a05
|
@ -135,12 +135,11 @@ async function save() {
|
|||
await axios.patch($props.urlUpdate || $props.url, body);
|
||||
}
|
||||
emit('onDataSaved', formData.value);
|
||||
originalData.value = JSON.parse(JSON.stringify(formData.value));
|
||||
hasChanges.value = false;
|
||||
} catch (err) {
|
||||
notify('errors.create', 'negative');
|
||||
}
|
||||
|
||||
originalData.value = JSON.parse(JSON.stringify(formData.value));
|
||||
hasChanges.value = false;
|
||||
isLoading.value = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import { useI18n } from 'vue-i18n';
|
|||
import { useArrayData } from 'composables/useArrayData';
|
||||
import toDate from 'filters/toDate';
|
||||
|
||||
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
dataKey: {
|
||||
|
@ -39,6 +41,10 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
customTags: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']);
|
||||
|
@ -104,19 +110,26 @@ async function clearFilters() {
|
|||
emit('clear');
|
||||
}
|
||||
|
||||
const tags = computed(() => {
|
||||
return Object.entries(userParams.value)
|
||||
const tagsList = computed(() =>
|
||||
Object.entries(userParams.value)
|
||||
.filter(([key, value]) => value && !(props.hiddenTags || []).includes(key))
|
||||
.map(([key, value]) => ({
|
||||
label: key,
|
||||
value: value,
|
||||
}));
|
||||
});
|
||||
}))
|
||||
);
|
||||
|
||||
const tags = computed(() =>
|
||||
tagsList.value.filter((tag) => !(props.customTags || []).includes(tag.label))
|
||||
);
|
||||
const customTags = computed(() =>
|
||||
tagsList.value.filter((tag) => (props.customTags || []).includes(tag.label))
|
||||
);
|
||||
|
||||
async function remove(key) {
|
||||
userParams.value[key] = null;
|
||||
await search();
|
||||
emit('remove', key)
|
||||
emit('remove', key);
|
||||
}
|
||||
|
||||
function formatValue(value) {
|
||||
|
@ -172,21 +185,17 @@ function formatValue(value) {
|
|||
</QItem>
|
||||
<QItem class="q-mb-sm">
|
||||
<div
|
||||
v-if="tags.length === 0"
|
||||
v-if="tagsList.length === 0"
|
||||
class="text-grey font-xs text-center full-width"
|
||||
>
|
||||
{{ t(`No filters applied`) }}
|
||||
</div>
|
||||
<div>
|
||||
<QChip
|
||||
:key="chip.label"
|
||||
@remove="remove(chip.label)"
|
||||
class="text-dark"
|
||||
color="primary"
|
||||
icon="label"
|
||||
:removable="!unremovableParams.includes(chip.label)"
|
||||
size="sm"
|
||||
<VnFilterPanelChip
|
||||
v-for="chip of tags"
|
||||
:key="chip.label"
|
||||
:removable="!unremovableParams.includes(chip.label)"
|
||||
@remove="remove(chip.label)"
|
||||
>
|
||||
<slot name="tags" :tag="chip" :format-fn="formatValue">
|
||||
<div class="q-gutter-x-xs">
|
||||
|
@ -194,7 +203,15 @@ function formatValue(value) {
|
|||
<span>"{{ chip.value }}"</span>
|
||||
</div>
|
||||
</slot>
|
||||
</QChip>
|
||||
</VnFilterPanelChip>
|
||||
<slot
|
||||
v-if="$slots.customTags"
|
||||
name="customTags"
|
||||
:params="userParams"
|
||||
:tags="customTags"
|
||||
:format-fn="formatValue"
|
||||
:search-fn="search"
|
||||
/>
|
||||
</div>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<QChip class="text-dark" color="primary" icon="label" size="sm" v-bind="$attrs">
|
||||
<slot />
|
||||
</QChip>
|
||||
</template>
|
|
@ -1,12 +0,0 @@
|
|||
<script setup>
|
||||
import OrderForm from 'pages/Order/Card/OrderForm.vue';
|
||||
</script>
|
||||
<template>
|
||||
<QToolbar>
|
||||
<div id="st-data"></div>
|
||||
<QSpace />
|
||||
<div id="st-actions"></div>
|
||||
</QToolbar>
|
||||
<OrderForm />
|
||||
</template>
|
||||
<style lang="scss" scoped></style>
|
|
@ -15,9 +15,7 @@ const stateStore = useStateStore();
|
|||
</QDrawer>
|
||||
<QPageContainer>
|
||||
<QPage>
|
||||
<div class="q-pa-md">
|
||||
<RouterView></RouterView>
|
||||
</div>
|
||||
<RouterView></RouterView>
|
||||
</QPage>
|
||||
</QPageContainer>
|
||||
</template>
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import axios from 'axios';
|
||||
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
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';
|
||||
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
@ -14,6 +17,10 @@ const props = defineProps({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
tags: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const categoryList = ref(null);
|
||||
|
@ -26,6 +33,20 @@ const resetCategory = () => {
|
|||
typeList.value = null;
|
||||
};
|
||||
|
||||
const selectedOrder = ref(null);
|
||||
const orderList = [
|
||||
{ way: 'ASC', name: 'Ascendant' },
|
||||
{ way: 'DESC', name: 'Descendant' },
|
||||
];
|
||||
|
||||
const selectedOrderField = ref(null);
|
||||
const OrderFields = [
|
||||
{ field: 'relevancy DESC, name', name: 'Relevancy', priority: 999 },
|
||||
{ field: 'showOrder, price', name: 'Color and price', priority: 999 },
|
||||
{ field: 'name', name: 'Name', priority: 999 },
|
||||
{ field: 'price', name: 'Price', priority: 999 },
|
||||
];
|
||||
|
||||
const clearFilter = (key) => {
|
||||
if (key === 'categoryFk') {
|
||||
resetCategory();
|
||||
|
@ -59,6 +80,11 @@ const onFilterInit = async ({ params }) => {
|
|||
await loadTypes(params.categoryFk);
|
||||
selectedCategoryFk.value = params.categoryFk;
|
||||
}
|
||||
if (params.orderBy) {
|
||||
orderByParam.value = JSON.parse(params.orderBy);
|
||||
selectedOrder.value = orderByParam.value?.way;
|
||||
selectedOrderField.value = orderByParam.value?.field;
|
||||
}
|
||||
};
|
||||
|
||||
const selectedCategory = computed(() =>
|
||||
|
@ -81,6 +107,60 @@ function exprBuilder(param, value) {
|
|||
}
|
||||
}
|
||||
|
||||
const selectedTag = ref(null);
|
||||
const tagValues = ref([{}]);
|
||||
const tagOptions = ref(null);
|
||||
const isButtonDisabled = computed(
|
||||
() => !selectedTag.value || tagValues.value.some((item) => !item.value)
|
||||
);
|
||||
|
||||
const applyTagFilter = (params, search) => {
|
||||
if (!tagValues.value?.length) {
|
||||
params.tagGroups = null;
|
||||
search();
|
||||
return;
|
||||
}
|
||||
if (!params.tagGroups) {
|
||||
params.tagGroups = [];
|
||||
}
|
||||
params.tagGroups.push(
|
||||
JSON.stringify({
|
||||
values: tagValues.value,
|
||||
tagSelection: {
|
||||
...selectedTag.value,
|
||||
orgShowField: selectedTag.value.name,
|
||||
},
|
||||
tagFk: selectedTag.value.tagFk,
|
||||
})
|
||||
);
|
||||
search();
|
||||
selectedTag.value = null;
|
||||
tagValues.value = [{}];
|
||||
};
|
||||
|
||||
const removeTagChip = (selection, params, search) => {
|
||||
if (params.tagGroups) {
|
||||
params.tagGroups = (params.tagGroups || []).filter(
|
||||
(value) => value !== selection
|
||||
);
|
||||
}
|
||||
search();
|
||||
};
|
||||
|
||||
const orderByParam = ref(null);
|
||||
|
||||
const onOrderFieldChange = (value, params, search) => {
|
||||
const orderBy = Object.assign({}, orderByParam.value, { field: value.field });
|
||||
params.orderBy = JSON.stringify(orderBy);
|
||||
search();
|
||||
};
|
||||
|
||||
const onOrderChange = (value, params, search) => {
|
||||
const orderBy = Object.assign({}, orderByParam.value, { way: value.way });
|
||||
params.orderBy = JSON.stringify(orderBy);
|
||||
search();
|
||||
};
|
||||
|
||||
const setCategoryList = (data) => {
|
||||
categoryList.value = (data || [])
|
||||
.filter((category) => category.display)
|
||||
|
@ -103,6 +183,7 @@ const getCategoryClass = (category, params) => {
|
|||
:data-key="props.dataKey"
|
||||
:hidden-tags="['orderFk', 'orderBy']"
|
||||
:expr-builder="exprBuilder"
|
||||
:custom-tags="['tagGroups']"
|
||||
@init="onFilterInit"
|
||||
@remove="clearFilter"
|
||||
>
|
||||
|
@ -118,8 +199,27 @@ const getCategoryClass = (category, params) => {
|
|||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #customTags="{ tags: customTags, params, searchFn }">
|
||||
<template v-for="tag in customTags" :key="tag.label">
|
||||
<template v-if="tag.label === 'tagGroups'">
|
||||
<VnFilterPanelChip
|
||||
v-for="chip in tag.value"
|
||||
:key="chip"
|
||||
removable
|
||||
@remove="removeTagChip(chip, params, searchFn)"
|
||||
>
|
||||
<strong> {{ JSON.parse(chip).tagSelection?.name }}: </strong>
|
||||
<span>{{
|
||||
(JSON.parse(chip).values || [])
|
||||
.map((item) => item.value)
|
||||
.join(' | ')
|
||||
}}</span>
|
||||
</VnFilterPanelChip>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
<template #body="{ params, searchFn }">
|
||||
<QList dense>
|
||||
<QList dense style="max-width: 256px">
|
||||
<QItem class="category-filter q-mt-md">
|
||||
<div
|
||||
v-for="category in categoryList"
|
||||
|
@ -137,7 +237,7 @@ const getCategoryClass = (category, params) => {
|
|||
</QIcon>
|
||||
</div>
|
||||
</QItem>
|
||||
<QItem class="q-mt-md">
|
||||
<QItem class="q-my-md">
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.type')"
|
||||
|
@ -171,6 +271,130 @@ const getCategoryClass = (category, params) => {
|
|||
</VnSelectFilter>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem class="q-my-md">
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.order')"
|
||||
v-model="selectedOrder"
|
||||
:options="orderList || []"
|
||||
option-value="way"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
:emit-value="false"
|
||||
use-input
|
||||
:is-clearable="false"
|
||||
@update:model-value="
|
||||
(value) => onOrderChange(value, params, searchFn)
|
||||
"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-mb-md">
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.order')"
|
||||
v-model="selectedOrderField"
|
||||
:options="OrderFields || []"
|
||||
option-value="field"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
:emit-value="false"
|
||||
use-input
|
||||
:is-clearable="false"
|
||||
@update:model-value="
|
||||
(value) => onOrderFieldChange(value, params, searchFn)
|
||||
"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem class="q-mt-md">
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.tag')"
|
||||
v-model="selectedTag"
|
||||
:options="props.tags || []"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
:emit-value="false"
|
||||
use-input
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-for="(value, index) in tagValues"
|
||||
:key="value"
|
||||
class="q-mt-md filter-value"
|
||||
>
|
||||
<VnInput
|
||||
v-if="selectedTag?.isFree"
|
||||
v-model="value.value"
|
||||
:label="t('params.value')"
|
||||
is-outlined
|
||||
class="filter-input"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
v-else
|
||||
:label="t('params.value')"
|
||||
v-model="value.value"
|
||||
:options="tagOptions || []"
|
||||
option-value="value"
|
||||
option-label="value"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
emit-value
|
||||
use-input
|
||||
:disable="!selectedTag"
|
||||
class="filter-input"
|
||||
/>
|
||||
|
||||
<FetchData
|
||||
v-if="selectedTag && !selectedTag.isFree"
|
||||
:url="`Tags/${selectedTag?.id}/filterValue`"
|
||||
limit="30"
|
||||
auto-load
|
||||
@on-fetch="(data) => (tagOptions = data)"
|
||||
/>
|
||||
|
||||
<QIcon
|
||||
name="delete"
|
||||
class="filter-icon"
|
||||
@click="(tagValues || []).splice(index, 1)"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem class="q-mt-lg">
|
||||
<QIcon
|
||||
name="add_circle"
|
||||
class="filter-icon"
|
||||
@click="tagValues.push({})"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection class="q-py-sm">
|
||||
<QBtn
|
||||
:label="t('Search')"
|
||||
class="full-width"
|
||||
color="primary"
|
||||
dense
|
||||
icon="search"
|
||||
rounded
|
||||
type="button"
|
||||
unelevated
|
||||
:disable="isButtonDisabled"
|
||||
@click.stop="applyTagFilter(params, searchFn)"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
</QList>
|
||||
</template>
|
||||
</VnFilterPanel>
|
||||
|
@ -198,12 +422,29 @@ const getCategoryClass = (category, params) => {
|
|||
|
||||
.category-icon {
|
||||
border-radius: 50%;
|
||||
background-color: var(--vn-label);
|
||||
background-color: var(--vn-light-gray);
|
||||
font-size: 2.6rem;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
font-size: 24px;
|
||||
color: $primary;
|
||||
padding: 0 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.filter-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
|
@ -211,10 +452,16 @@ en:
|
|||
params:
|
||||
type: Type
|
||||
orderBy: Order By
|
||||
tag: Tag
|
||||
value: Value
|
||||
order: Order
|
||||
es:
|
||||
params:
|
||||
type: Tipo
|
||||
orderBy: Ordenar por
|
||||
tag: Etiqueta
|
||||
value: Valor
|
||||
order: Orden
|
||||
Plant: Planta
|
||||
Flower: Flor
|
||||
Handmade: Confección
|
||||
|
|
|
@ -24,7 +24,7 @@ const dialog = ref(null);
|
|||
|
||||
<template>
|
||||
<div class="container order-catalog-item overflow-hidden">
|
||||
<div class="card shadow-6 bg-dark">
|
||||
<QCard class="card shadow-6">
|
||||
<div class="img-wrapper">
|
||||
<QImg
|
||||
:src="`/api/Images/catalog/200x200/${item.id}/download?access_token=${token}`"
|
||||
|
@ -76,7 +76,7 @@ const dialog = ref(null);
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -51,13 +51,13 @@ async function remove() {
|
|||
|
||||
<i18n>
|
||||
en:
|
||||
deleteOrder: Delete order,
|
||||
confirmDeletion: Confirm deletion,
|
||||
deleteOrder: Delete order
|
||||
confirmDeletion: Confirm deletion
|
||||
confirmDeletionMessage: Are you sure you want to delete this order?
|
||||
|
||||
es:
|
||||
deleteOrder: Eliminar pedido,
|
||||
confirmDeletion: Confirmar eliminación,
|
||||
deleteOrder: Eliminar pedido
|
||||
confirmDeletion: Confirmar eliminación
|
||||
confirmDeletionMessage: Seguro que quieres eliminar este pedido?
|
||||
|
||||
</i18n>
|
||||
|
|
|
@ -65,8 +65,8 @@ const fetchAgencyList = async (landed, addressFk) => {
|
|||
};
|
||||
|
||||
const fetchOrderDetails = (order) => {
|
||||
fetchAddressList(order?.addressFk)
|
||||
fetchAgencyList(order?.landed, order?.addressFk)
|
||||
fetchAddressList(order?.addressFk);
|
||||
fetchAgencyList(order?.landed, order?.addressFk);
|
||||
};
|
||||
|
||||
const orderMapper = (order) => {
|
||||
|
@ -105,7 +105,7 @@ const orderFilter = {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<QToolbar>
|
||||
<QToolbar class="bg-vn-dark justify-end">
|
||||
<div id="st-data"></div>
|
||||
<QSpace />
|
||||
<div id="st-actions"></div>
|
||||
|
@ -116,94 +116,97 @@ const orderFilter = {
|
|||
:filter="{ fields: ['id', 'name', 'defaultAddressFk'] }"
|
||||
auto-load
|
||||
/>
|
||||
<FormModel
|
||||
:url="!isNew ? `Orders/${route.params.id}` : null"
|
||||
:url-create="isNew ? 'Orders/new' : null"
|
||||
:model="ORDER_MODEL"
|
||||
:form-initial-data="isNew ? initialFormState : null"
|
||||
:observe-form-changes="!isNew"
|
||||
:mapper="isNew ? orderMapper : null"
|
||||
:filter="orderFilter"
|
||||
@on-fetch="fetchOrderDetails"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.clientFk')"
|
||||
v-model="data.clientFk"
|
||||
:options="clientList"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="
|
||||
(client) => fetchAddressList(client.defaultAddressFk)
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.addressFk')"
|
||||
v-model="data.addressFk"
|
||||
:options="addressList"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
hide-selected
|
||||
:disable="!addressList?.length"
|
||||
@update:model-value="
|
||||
() => fetchAgencyList(data.landed, data.addressFk)
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{
|
||||
`${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}`
|
||||
}}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnInputDate
|
||||
placeholder="dd-mm-aaa"
|
||||
:label="t('order.form.landed')"
|
||||
v-model="data.landed"
|
||||
@update:model-value="
|
||||
() => fetchAgencyList(data.landed, data.addressFk)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.agencyModeFk')"
|
||||
v-model="data.agencyModeFk"
|
||||
:options="agencyList"
|
||||
option-value="agencyModeFk"
|
||||
option-label="agencyMode"
|
||||
hide-selected
|
||||
:disable="!agencyList?.length"
|
||||
>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
|
||||
<div class="q-pa-md">
|
||||
<FormModel
|
||||
:url="!isNew ? `Orders/${route.params.id}` : null"
|
||||
:url-create="isNew ? 'Orders/new' : null"
|
||||
:model="ORDER_MODEL"
|
||||
:form-initial-data="isNew ? initialFormState : null"
|
||||
:observe-form-changes="!isNew"
|
||||
:mapper="isNew ? orderMapper : null"
|
||||
:filter="orderFilter"
|
||||
@on-fetch="fetchOrderDetails"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.clientFk')"
|
||||
v-model="data.clientFk"
|
||||
:options="clientList"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="
|
||||
(client) => fetchAddressList(client.defaultAddressFk)
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.addressFk')"
|
||||
v-model="data.addressFk"
|
||||
:options="addressList"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
hide-selected
|
||||
:disable="!addressList?.length"
|
||||
@update:model-value="
|
||||
() => fetchAgencyList(data.landed, data.addressFk)
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{
|
||||
`${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}`
|
||||
}}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnInputDate
|
||||
placeholder="dd-mm-aaa"
|
||||
:label="t('order.form.landed')"
|
||||
v-model="data.landed"
|
||||
@update:model-value="
|
||||
() => fetchAgencyList(data.landed, data.addressFk)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('order.form.agencyModeFk')"
|
||||
v-model="data.agencyModeFk"
|
||||
:options="agencyList"
|
||||
option-value="agencyModeFk"
|
||||
option-label="agencyMode"
|
||||
hide-selected
|
||||
:disable="!agencyList?.length"
|
||||
>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -56,148 +56,161 @@ const detailsColumns = ref([
|
|||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
||||
<OrderSearchbar />
|
||||
</Teleport>
|
||||
<CardSummary ref="summary" :url="`Orders/${entityId}/summary`">
|
||||
<template #header="{ entity }">
|
||||
{{ t('order.summary.basket') }} #{{ entity?.id }} -
|
||||
{{ entity?.client?.name }} ({{ entity?.clientFk }})
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<QCard class="vn-one">
|
||||
<VnLv label="ID" :value="entity.id" />
|
||||
<VnLv :label="t('order.summary.nickname')" dash>
|
||||
<template #value>
|
||||
<span class="link">
|
||||
{{ dashIfEmpty(entity?.address?.nickname) }}
|
||||
<CustomerDescriptorProxy :id="entity?.clientFk" />
|
||||
</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('order.summary.company')"
|
||||
:value="entity?.address?.companyFk"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.confirmed')"
|
||||
:value="Boolean(entity?.isConfirmed)"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<VnLv
|
||||
:label="t('order.summary.created')"
|
||||
:value="toDateHour(entity?.created)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.confirmed')"
|
||||
:value="toDateHour(entity?.confirmed)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.landed')"
|
||||
:value="toDateHour(entity?.landed)"
|
||||
/>
|
||||
<VnLv :label="t('order.summary.phone')">
|
||||
<template #value>
|
||||
{{ dashIfEmpty(entity?.address?.phone) }}
|
||||
<a
|
||||
v-if="entity?.address?.phone"
|
||||
:href="`tel:${entity?.address?.phone}`"
|
||||
class="text-primary"
|
||||
>
|
||||
<QIcon name="phone" />
|
||||
</a>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('order.summary.createdFrom')"
|
||||
:value="entity?.sourceApp"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.address')"
|
||||
:value="`${entity?.address?.street} - ${entity?.address?.city} (${entity?.address?.province?.name})`"
|
||||
class="order-summary-address"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<p class="header">
|
||||
{{ t('order.summary.notes') }}
|
||||
</p>
|
||||
<p v-if="entity?.note" class="no-margin">
|
||||
{{ entity?.note }}
|
||||
</p>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.subtotal') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{ toCurrency(entity?.subTotal) }}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.vat') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{ toCurrency(entity?.VAT) }}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.total') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{ toCurrency(entity?.total) }}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
</QCard>
|
||||
<QCard>
|
||||
<p class="header">
|
||||
{{ t('order.summary.details') }}
|
||||
</p>
|
||||
<QTable
|
||||
:columns="detailsColumns"
|
||||
:rows="entity?.rows"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh auto-width>{{ t('order.summary.item') }}</QTh>
|
||||
<QTh>{{ t('order.summary.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.quantity') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.price') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.amount') }}</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
<template #body="props">
|
||||
<QTr :props="props">
|
||||
<QTd key="item" :props="props" class="item">
|
||||
{{ props.row.item?.id }}
|
||||
</QTd>
|
||||
<QTd key="description" :props="props" class="description">
|
||||
<div class="name">
|
||||
<span>{{ props.row.item.name }}</span>
|
||||
<span v-if="props.row.item.subName" class="subName">
|
||||
{{ props.row.item.subName }}
|
||||
</span>
|
||||
</div>
|
||||
<fetched-tags :item="props.row.item" :max-length="5" />
|
||||
</QTd>
|
||||
<QTd key="quantity" :props="props">
|
||||
{{ props.row.quantity }}
|
||||
</QTd>
|
||||
<QTd key="price" :props="props">
|
||||
{{ props.row.price }}
|
||||
</QTd>
|
||||
<QTd key="amount" :props="props">
|
||||
{{ toCurrency(props.row?.quantity * props.row?.price) }}
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</template>
|
||||
</CardSummary>
|
||||
|
||||
<div class="q-pa-md">
|
||||
<CardSummary ref="summary" :url="`Orders/${entityId}/summary`">
|
||||
<template #header="{ entity }">
|
||||
{{ t('order.summary.basket') }} #{{ entity?.id }} -
|
||||
{{ entity?.client?.name }} ({{ entity?.clientFk }})
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<QCard class="vn-one">
|
||||
<VnLv label="ID" :value="entity.id" />
|
||||
<VnLv :label="t('order.summary.nickname')" dash>
|
||||
<template #value>
|
||||
<span class="link">
|
||||
{{ dashIfEmpty(entity?.address?.nickname) }}
|
||||
<CustomerDescriptorProxy :id="entity?.clientFk" />
|
||||
</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('order.summary.company')"
|
||||
:value="entity?.address?.companyFk"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.confirmed')"
|
||||
:value="Boolean(entity?.isConfirmed)"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<VnLv
|
||||
:label="t('order.summary.created')"
|
||||
:value="toDateHour(entity?.created)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.confirmed')"
|
||||
:value="toDateHour(entity?.confirmed)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.landed')"
|
||||
:value="toDateHour(entity?.landed)"
|
||||
/>
|
||||
<VnLv :label="t('order.summary.phone')">
|
||||
<template #value>
|
||||
{{ dashIfEmpty(entity?.address?.phone) }}
|
||||
<a
|
||||
v-if="entity?.address?.phone"
|
||||
:href="`tel:${entity?.address?.phone}`"
|
||||
class="text-primary"
|
||||
>
|
||||
<QIcon name="phone" />
|
||||
</a>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('order.summary.createdFrom')"
|
||||
:value="entity?.sourceApp"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('order.summary.address')"
|
||||
:value="`${entity?.address?.street} - ${entity?.address?.city} (${entity?.address?.province?.name})`"
|
||||
class="order-summary-address"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<p class="header">
|
||||
{{ t('order.summary.notes') }}
|
||||
</p>
|
||||
<p v-if="entity?.note" class="no-margin">
|
||||
{{ entity?.note }}
|
||||
</p>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.subtotal') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{
|
||||
toCurrency(entity?.subTotal)
|
||||
}}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.vat') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{ toCurrency(entity?.VAT) }}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv>
|
||||
<template #label>
|
||||
<span class="text-h6">{{ t('order.summary.total') }}</span>
|
||||
</template>
|
||||
<template #value>
|
||||
<span class="text-h6">{{ toCurrency(entity?.total) }}</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
</QCard>
|
||||
<QCard>
|
||||
<p class="header">
|
||||
{{ t('order.summary.details') }}
|
||||
</p>
|
||||
<QTable
|
||||
:columns="detailsColumns"
|
||||
:rows="entity?.rows"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh auto-width>{{ t('order.summary.item') }}</QTh>
|
||||
<QTh>{{ t('order.summary.description') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.quantity') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.price') }}</QTh>
|
||||
<QTh auto-width>{{ t('order.summary.amount') }}</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
<template #body="props">
|
||||
<QTr :props="props">
|
||||
<QTd key="item" :props="props" class="item">
|
||||
{{ props.row.item?.id }}
|
||||
</QTd>
|
||||
<QTd key="description" :props="props" class="description">
|
||||
<div class="name">
|
||||
<span>{{ props.row.item.name }}</span>
|
||||
<span
|
||||
v-if="props.row.item.subName"
|
||||
class="subName"
|
||||
>
|
||||
{{ props.row.item.subName }}
|
||||
</span>
|
||||
</div>
|
||||
<fetched-tags
|
||||
:item="props.row.item"
|
||||
:max-length="5"
|
||||
/>
|
||||
</QTd>
|
||||
<QTd key="quantity" :props="props">
|
||||
{{ props.row.quantity }}
|
||||
</QTd>
|
||||
<QTd key="price" :props="props">
|
||||
{{ props.row.price }}
|
||||
</QTd>
|
||||
<QTd key="amount" :props="props">
|
||||
{{
|
||||
toCurrency(props.row?.quantity * props.row?.price)
|
||||
}}
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</template>
|
||||
</CardSummary>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.cardSummary .summaryBody .vn-label-value.order-summary-address {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import {onMounted, onUnmounted, ref} from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||
|
@ -20,6 +20,22 @@ const catalogParams = {
|
|||
orderBy: JSON.stringify({ field: 'relevancy DESC, name', way: 'ASC', isTag: false }),
|
||||
};
|
||||
|
||||
const tags = ref([])
|
||||
|
||||
function extractTags(items) {
|
||||
const resultTags = [];
|
||||
(items || []).forEach((item) => {
|
||||
(item.tags || []).forEach((tag) => {
|
||||
const index = resultTags.findIndex((item) => item.tagFk === tag.tagFk);
|
||||
if (index === -1) {
|
||||
resultTags.push({ ...tag, priority: 1 });
|
||||
} else {
|
||||
resultTags[index].priority += 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
tags.value = resultTags
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -50,7 +66,7 @@ const catalogParams = {
|
|||
</Teleport>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<OrderCatalogFilter data-key="OrderCatalogList" />
|
||||
<OrderCatalogFilter data-key="OrderCatalogList" :tags="tags" />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
|
@ -61,6 +77,7 @@ const catalogParams = {
|
|||
:limit="50"
|
||||
:user-params="catalogParams"
|
||||
auto-load
|
||||
@on-fetch="extractTags"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<div class="catalog-list">
|
||||
|
|
|
@ -25,6 +25,7 @@ const orderSummary = ref({
|
|||
vat: null,
|
||||
});
|
||||
const componentKey = ref(0);
|
||||
const order = ref(0);
|
||||
|
||||
const refresh = () => {
|
||||
componentKey.value += 1;
|
||||
|
@ -63,6 +64,12 @@ async function confirmOrder() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
:key="componentKey"
|
||||
:url="`Orders/${route.params.id}`"
|
||||
@on-fetch="(data) => (order = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
:key="componentKey"
|
||||
:url="`Orders/${route.params.id}/getTotal`"
|
||||
|
@ -177,7 +184,7 @@ async function confirmOrder() {
|
|||
:value="toCurrency(row.price * row.quantity)"
|
||||
/>
|
||||
</template>
|
||||
<template #actions>
|
||||
<template #actions v-if="!order?.isConfirmed">
|
||||
<QBtn
|
||||
:label="t('remove')"
|
||||
@click.stop="confirmRemove(row)"
|
||||
|
@ -190,7 +197,7 @@ async function confirmOrder() {
|
|||
</template>
|
||||
</VnPaginate>
|
||||
</div>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed">
|
||||
<QBtn fab icon="check" color="primary" @click="confirmOrder()" />
|
||||
<QTooltip>
|
||||
{{ t('confirm') }}
|
||||
|
|
Loading…
Reference in New Issue