0
0
Fork 0

Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6553-workerBusiness

This commit is contained in:
Carlos Satorres 2024-06-21 12:42:19 +02:00
commit 8363f813de
17 changed files with 545 additions and 399 deletions

View File

@ -83,6 +83,10 @@ const $props = defineProps({
default: '', default: '',
description: 'It is used for redirect on click "save and continue"', description: 'It is used for redirect on click "save and continue"',
}, },
reload: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(['onFetch', 'onDataSaved']); const emit = defineEmits(['onFetch', 'onDataSaved']);
const modelValue = computed( const modelValue = computed(
@ -201,6 +205,7 @@ async function save() {
if ($props.urlCreate) notify('globals.dataCreated', 'positive'); if ($props.urlCreate) notify('globals.dataCreated', 'positive');
updateAndEmit('onDataSaved', formData.value, response?.data); updateAndEmit('onDataSaved', formData.value, response?.data);
if ($props.reload) await arrayData.fetch({});
} catch (err) { } catch (err) {
console.error(err); console.error(err);
notify('errors.writeRequest', 'negative'); notify('errors.writeRequest', 'negative');

View File

@ -0,0 +1,60 @@
<script setup>
import { ref, computed, onMounted } from 'vue';
import { useSession } from 'src/composables/useSession';
const $props = defineProps({
collection: {
type: [String, Number],
default: 'Images',
},
size: {
type: String,
default: '200x200',
},
zoomSize: {
type: String,
required: true,
default: 'lg',
},
id: {
type: Boolean,
default: false,
},
});
const show = ref(false);
const token = useSession().getTokenMultimedia();
const timeStamp = ref(`timestamp=${Date.now()}`);
const url = computed(
() =>
`/api/${$props.collection}/catalog/${$props.size}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
);
const emits = defineEmits(['refresh']);
const reload = (emit = false) => {
timeStamp.value = `timestamp=${Date.now()}`;
};
defineExpose({
reload,
});
onMounted(() => {});
</script>
<template>
<QImg :src="url" v-bind="$attrs" @click="show = !show" spinner-color="primary" />
<QDialog v-model="show" v-if="$props.zoomSize">
<QImg :src="url" class="img_zoom" v-bind="$attrs" spinner-color="primary" />
</QDialog>
</template>
<style lang="scss" scoped>
.q-img {
cursor: zoom-in;
}
.rounded {
border-radius: 50%;
}
.img_zoom {
width: 100%;
height: auto;
border-radius: 0%;
}
</style>

View File

@ -17,26 +17,6 @@ const { t } = useI18n();
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia(); const token = getTokenMultimedia();
const claimFilter = {
fields: [
'id',
'clientFk',
'created',
'workerFk',
'claimStateFk',
'packages',
'pickup',
],
include: [
{
relation: 'client',
scope: {
fields: ['name'],
},
},
],
};
const claimStates = ref([]); const claimStates = ref([]);
const claimStatesCopy = ref([]); const claimStatesCopy = ref([]);
const optionsList = ref([]); const optionsList = ref([]);
@ -87,11 +67,10 @@ const statesFilter = {
/> />
<FetchData url="ClaimStates" @on-fetch="setClaimStates" auto-load /> <FetchData url="ClaimStates" @on-fetch="setClaimStates" auto-load />
<FormModel <FormModel
:url="`Claims/${route.params.id}`" model="Claim"
:url-update="`Claims/updateClaim/${route.params.id}`" :url-update="`Claims/updateClaim/${route.params.id}`"
:filter="claimFilter"
model="claim"
auto-load auto-load
:reload="true"
> >
<template #form="{ data, validate, filter }"> <template #form="{ data, validate, filter }">
<VnRow class="row q-gutter-md q-mb-md"> <VnRow class="row q-gutter-md q-mb-md">

View File

@ -2,6 +2,7 @@
import VnCard from 'components/common/VnCard.vue'; import VnCard from 'components/common/VnCard.vue';
import ClaimDescriptor from './ClaimDescriptor.vue'; import ClaimDescriptor from './ClaimDescriptor.vue';
import ClaimFilter from '../ClaimFilter.vue'; import ClaimFilter from '../ClaimFilter.vue';
import filter from './ClaimFilter.js';
</script> </script>
<template> <template>
<VnCard <VnCard
@ -13,5 +14,6 @@ import ClaimFilter from '../ClaimFilter.vue';
search-url="Claims/filter" search-url="Claims/filter"
searchbar-label="Search claim" searchbar-label="Search claim"
searchbar-info="You can search by claim id or customer name" searchbar-info="You can search by claim id or customer name"
:filter="filter"
/> />
</template> </template>

View File

@ -12,6 +12,7 @@ import useCardDescription from 'src/composables/useCardDescription';
import VnUserLink from 'src/components/ui/VnUserLink.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { getUrl } from 'src/composables/getUrl'; import { getUrl } from 'src/composables/getUrl';
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue'; import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
import filter from './ClaimFilter.js';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -29,49 +30,6 @@ const entityId = computed(() => {
return $props.id || route.params.id; return $props.id || route.params.id;
}); });
const filter = {
include: [
{
relation: 'client',
scope: {
include: [
{ relation: 'salesPersonUser' },
{
relation: 'claimsRatio',
scope: {
fields: ['claimingRate'],
limit: 1,
},
},
],
},
},
{
relation: 'claimState',
},
{
relation: 'ticket',
scope: {
include: [
{ relation: 'zone' },
{
relation: 'address',
scope: {
include: { relation: 'province' },
},
},
],
},
},
{
relation: 'worker',
scope: {
include: { relation: 'user' },
},
},
],
};
const STATE_COLOR = { const STATE_COLOR = {
pending: 'warning', pending: 'warning',
incomplete: 'info', incomplete: 'info',
@ -101,7 +59,7 @@ onMounted(async () => {
:title="data.title" :title="data.title"
:subtitle="data.subtitle" :subtitle="data.subtitle"
@on-fetch="setData" @on-fetch="setData"
data-key="claimData" data-key="Claim"
> >
<template #menu="{ entity }"> <template #menu="{ entity }">
<ClaimDescriptorMenu :claim="entity" /> <ClaimDescriptorMenu :claim="entity" />

View File

@ -0,0 +1,52 @@
export default {
fields: [
'id',
'clientFk',
'created',
'workerFk',
'claimStateFk',
'packages',
'pickup',
'ticketFk',
],
include: [
{
relation: 'client',
scope: {
include: [
{ relation: 'salesPersonUser' },
{
relation: 'claimsRatio',
scope: {
fields: ['claimingRate'],
limit: 1,
},
},
],
},
},
{
relation: 'claimState',
},
{
relation: 'ticket',
scope: {
include: [
{ relation: 'zone' },
{
relation: 'address',
scope: {
include: { relation: 'province' },
},
},
],
},
},
{
relation: 'worker',
scope: {
include: { relation: 'user' },
},
},
],
};

View File

@ -22,7 +22,7 @@ const balanceDueTotal = ref(0);
const selected = ref([]); const selected = ref([]);
const tableColumnComponents = { const tableColumnComponents = {
client: { clientFk: {
component: QBtn, component: QBtn,
props: () => ({ flat: true, class: 'link', noCaps: true }), props: () => ({ flat: true, class: 'link', noCaps: true }),
event: () => {}, event: () => {},
@ -40,7 +40,7 @@ const tableColumnComponents = {
props: () => ({ flat: true, class: 'link', noCaps: true }), props: () => ({ flat: true, class: 'link', noCaps: true }),
event: () => {}, event: () => {},
}, },
department: { departmentName: {
component: 'span', component: 'span',
props: () => {}, props: () => {},
event: () => {}, event: () => {},
@ -102,12 +102,12 @@ const columns = computed(() => [
align: 'left', align: 'left',
field: 'clientName', field: 'clientName',
label: t('Client'), label: t('Client'),
name: 'client', name: 'clientFk',
sortable: true, sortable: true,
}, },
{ {
align: 'left', align: 'left',
field: 'isWorker', field: ({ isWorker }) => Boolean(isWorker),
label: t('Is worker'), label: t('Is worker'),
name: 'isWorker', name: 'isWorker',
}, },
@ -122,7 +122,7 @@ const columns = computed(() => [
align: 'left', align: 'left',
field: 'departmentName', field: 'departmentName',
label: t('Department'), label: t('Department'),
name: 'department', name: 'departmentName',
sortable: true, sortable: true,
}, },
{ {
@ -204,48 +204,24 @@ const viewAddObservation = (rowsSelected) => {
}); });
}; };
const departments = ref(new Map());
const onFetch = async (data) => { const onFetch = async (data) => {
const salesPersonFks = data.map((item) => item.salesPersonFk);
const departmentNames = salesPersonFks.map(async (salesPersonFk) => {
try {
const { data: workerDepartment } = await axios.get(
`WorkerDepartments/${salesPersonFk}`
);
const { data: department } = await axios.get(
`Departments/${workerDepartment.departmentFk}`
);
departments.value.set(salesPersonFk, department.name);
} catch (error) {
console.error('Err: ', error);
}
});
const recoveryData = await axios.get('Recoveries'); const recoveryData = await axios.get('Recoveries');
const recoveries = recoveryData.data.map(({ clientFk, finished }) => ({ const recoveries = recoveryData.data.map(({ clientFk, finished }) => ({
clientFk, clientFk,
finished, finished,
})); }));
await Promise.all(departmentNames);
data.forEach((item) => { data.forEach((item) => {
item.departmentName = departments.value.get(item.salesPersonFk);
item.isWorker = item.businessTypeFk === 'worker';
const recovery = recoveries.find(({ clientFk }) => clientFk === item.clientFk); const recovery = recoveries.find(({ clientFk }) => clientFk === item.clientFk);
item.finished = recovery?.finished === null; item.finished = recovery?.finished === null;
}); });
for (const element of data) element.isWorker = element.businessTypeFk === 'worker';
balanceDueTotal.value = data.reduce((acc, { amount = 0 }) => acc + amount, 0); balanceDueTotal.value = data.reduce((acc, { amount = 0 }) => acc + amount, 0);
}; };
function exprBuilder(param, value) { function exprBuilder(param, value) {
switch (param) { switch (param) {
case 'clientFk': case 'clientFk':
return { [`d.${param}`]: value?.id }; return { [`d.${param}`]: value };
case 'creditInsurance': case 'creditInsurance':
case 'amount': case 'amount':
case 'workerFk': case 'workerFk':

View File

@ -1,7 +1,6 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
@ -16,14 +15,13 @@ const props = defineProps({
}, },
}); });
const clients = ref();
const salespersons = ref(); const salespersons = ref();
const countries = ref(); const countries = ref();
const authors = ref(); const authors = ref();
const departments = ref();
</script> </script>
<template> <template>
<FetchData @on-fetch="(data) => (clients = data)" auto-load url="Clients" />
<FetchData <FetchData
:filter="{ where: { role: 'salesPerson' } }" :filter="{ where: { role: 'salesPerson' } }"
@on-fetch="(data) => (salespersons = data)" @on-fetch="(data) => (salespersons = data)"
@ -36,6 +34,7 @@ const authors = ref();
auto-load auto-load
url="Workers/activeWithInheritedRole" url="Workers/activeWithInheritedRole"
/> />
<FetchData @on-fetch="(data) => (departments = data)" auto-load url="Departments" />
<VnFilterPanel :data-key="props.dataKey" :search-button="true"> <VnFilterPanel :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
@ -47,29 +46,22 @@ const authors = ref();
<template #body="{ params, searchFn }"> <template #body="{ params, searchFn }">
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="clients"> <VnSelect
<VnSelect :label="t('Client')"
:label="t('Client')" url="Clients"
:options="clients" dense
dense option-label="name"
emit-value option-value="id"
hide-selected outlined
map-options rounded
option-label="name" emit-value
option-value="id" hide-selected
outlined map-options
rounded v-model="params.clientFk"
use-input use-input
v-model="params.clientFk" @update:model-value="searchFn()"
@update:model-value="searchFn()" />
auto-load
/>
</QItemSection>
<QItemSection v-else>
<QSkeleton class="full-width" type="QInput" />
</QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="salespersons"> <QItemSection v-if="salespersons">
<VnSelect <VnSelect
@ -93,6 +85,29 @@ const authors = ref();
<QSkeleton class="full-width" type="QInput" /> <QSkeleton class="full-width" type="QInput" />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm">
<QItemSection v-if="departments">
<VnSelect
:input-debounce="0"
:label="t('Departments')"
:options="departments"
dense
emit-value
hide-selected
map-options
option-label="name"
option-value="id"
outlined
rounded
use-input
v-model="params.departmentFk"
@update:model-value="searchFn()"
/>
</QItemSection>
<QItemSection v-else>
<QSkeleton class="full-width" type="QInput" />
</QItemSection>
</QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="countries"> <QItemSection v-if="countries">

View File

@ -11,9 +11,9 @@ import VnInput from 'src/components/common/VnInput.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import VnConfirm from 'components/ui/VnConfirm.vue'; import VnConfirm from 'components/ui/VnConfirm.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
import axios from 'axios'; import axios from 'axios';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
@ -22,7 +22,6 @@ const quasar = useQuasar();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore();
const { notify } = useNotify(); const { notify } = useNotify();
const rowsSelected = ref([]); const rowsSelected = ref([]);
@ -312,20 +311,22 @@ const lockIconType = (groupingMode, mode) => {
auto-load auto-load
@on-fetch="(data) => (packagingsOptions = data)" @on-fetch="(data) => (packagingsOptions = data)"
/> />
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()"> <VnSubToolbar>
<QBtnGroup push style="column-gap: 10px"> <template #st-actions>
<slot name="moreBeforeActions" /> <QBtnGroup push style="column-gap: 10px">
<QBtn <slot name="moreBeforeActions" />
:label="t('globals.remove')" <QBtn
color="primary" :label="t('globals.remove')"
icon="delete" color="primary"
flat icon="delete"
@click="openRemoveDialog()" flat
:disable="!rowsSelected?.length" @click="openRemoveDialog()"
:title="t('globals.remove')" :disable="!rowsSelected?.length"
/> :title="t('globals.remove')"
</QBtnGroup> />
</Teleport> </QBtnGroup>
</template>
</VnSubToolbar>
<VnPaginate <VnPaginate
ref="entryBuysPaginateRef" ref="entryBuysPaginateRef"
data-key="EntryBuys" data-key="EntryBuys"

View File

@ -3,8 +3,7 @@ import { ref, onMounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import EditPictureForm from 'components/EditPictureForm.vue'; import EditPictureForm from 'components/EditPictureForm.vue';
import VnImg from 'src/components/ui/VnImg.vue';
import { useSession } from 'src/composables/useSession';
import axios from 'axios'; import axios from 'axios';
const $props = defineProps({ const $props = defineProps({
@ -27,19 +26,12 @@ const $props = defineProps({
}); });
const { t } = useI18n(); const { t } = useI18n();
const { getTokenMultimedia } = useSession();
const image = ref(null); const image = ref(null);
const editPhotoFormDialog = ref(null); const editPhotoFormDialog = ref(null);
const showEditPhotoForm = ref(false); const showEditPhotoForm = ref(false);
const warehouseName = ref(null); const warehouseName = ref(null);
const getItemAvatar = async () => {
const token = getTokenMultimedia();
const timeStamp = `timestamp=${Date.now()}`;
image.value = `/api/Images/catalog/200x200/${$props.entityId}/download?access_token=${token}&${timeStamp}`;
};
const toggleEditPictureForm = () => { const toggleEditPictureForm = () => {
showEditPhotoForm.value = !showEditPhotoForm.value; showEditPhotoForm.value = !showEditPhotoForm.value;
}; };
@ -62,14 +54,17 @@ const getWarehouseName = async (warehouseFk) => {
}; };
onMounted(async () => { onMounted(async () => {
getItemAvatar();
getItemConfigs(); getItemConfigs();
}); });
const handlePhotoUpdated = (evt = false) => {
image.value.reload(evt);
};
</script> </script>
<template> <template>
<div class="relative-position"> <div class="relative-position">
<QImg :src="image" spinner-color="primary" style="min-height: 256px"> <VnImg ref="image" :id="$props.entityId" @refresh="handlePhotoUpdated(true)">
<template #error> <template #error>
<div class="absolute-full picture text-center q-pa-md flex flex-center"> <div class="absolute-full picture text-center q-pa-md flex flex-center">
<div> <div>
@ -82,7 +77,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
</template> </template>
</QImg> </VnImg>
<QBtn <QBtn
v-if="showEditButton" v-if="showEditButton"
color="primary" color="primary"
@ -97,7 +92,7 @@ onMounted(async () => {
collection="catalog" collection="catalog"
:id="entityId" :id="entityId"
@close-form="toggleEditPictureForm()" @close-form="toggleEditPictureForm()"
@on-photo-uploaded="getItemAvatar()" @on-photo-uploaded="handlePhotoUpdated"
/> />
</QDialog> </QDialog>
</QBtn> </QBtn>

View File

@ -3,14 +3,15 @@ import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import axios from 'axios'; import axios from 'axios';
import VnInput from 'components/common/VnInput.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue'; import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
import { useValidator } from 'src/composables/useValidator';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const props = defineProps({ const props = defineProps({
dataKey: { dataKey: {
@ -21,32 +22,34 @@ const props = defineProps({
type: Array, type: Array,
required: true, required: true,
}, },
tagValue: {
type: Array,
required: true,
},
}); });
const categoryList = ref(null); const categoryList = ref(null);
const selectedCategoryFk = ref(null); const selectedCategoryFk = ref(null);
const typeList = ref(null); const typeList = ref(null);
const selectedTypeFk = ref(null); const selectedTypeFk = ref(null);
const validationsStore = useValidator();
const selectedOrder = ref(null);
const selectedOrderField = ref(null);
const moreFields = ref([]);
const moreFieldsOrder = ref([]);
const createValue = (val, done) => {
if (val.length > 2) {
if (!tagOptions.value.includes(val)) {
done(tagOptions.value, 'add-unique');
}
tagValues.value.push({ value: val });
}
};
const resetCategory = () => { const resetCategory = () => {
selectedCategoryFk.value = null; selectedCategoryFk.value = null;
typeList.value = null; 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) => { const clearFilter = (key) => {
if (key === 'categoryFk') { if (key === 'categoryFk') {
resetCategory(); resetCategory();
@ -72,21 +75,6 @@ const loadTypes = async (categoryFk) => {
typeList.value = data; 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;
}
if (params.orderBy) {
orderByParam.value = JSON.parse(params.orderBy);
selectedOrder.value = orderByParam.value?.way;
selectedOrderField.value = orderByParam.value?.field;
}
};
const selectedCategory = computed(() => const selectedCategory = computed(() =>
(categoryList.value || []).find( (categoryList.value || []).find(
(category) => category?.id === selectedCategoryFk.value (category) => category?.id === selectedCategoryFk.value
@ -109,10 +97,7 @@ function exprBuilder(param, value) {
const selectedTag = ref(null); const selectedTag = ref(null);
const tagValues = ref([{}]); const tagValues = ref([{}]);
const tagOptions = ref(null); const tagOptions = ref([]);
const isButtonDisabled = computed(
() => !selectedTag.value || tagValues.value.some((item) => !item.value)
);
const applyTagFilter = (params, search) => { const applyTagFilter = (params, search) => {
if (!tagValues.value?.length) { if (!tagValues.value?.length) {
@ -125,12 +110,12 @@ const applyTagFilter = (params, search) => {
} }
params.tagGroups.push( params.tagGroups.push(
JSON.stringify({ JSON.stringify({
values: tagValues.value, values: tagValues.value.filter((obj) => Object.keys(obj).length > 0),
tagSelection: { tagSelection: {
...selectedTag.value, ...selectedTag.value,
orgShowField: selectedTag.value.name, orgShowField: selectedTag?.value?.name,
}, },
tagFk: selectedTag.value.tagFk, tagFk: selectedTag?.value?.tagFk,
}) })
); );
search(); search();
@ -147,20 +132,52 @@ const removeTagChip = (selection, params, search) => {
search(); search();
}; };
const orderByParam = ref(null); const onOrderChange = (value, params) => {
const tagObj = JSON.parse(params.orderBy);
const onOrderFieldChange = (value, params, search) => { tagObj.way = value.name;
const orderBy = Object.assign({}, orderByParam.value, { field: value.field }); params.orderBy = JSON.stringify(tagObj);
params.orderBy = JSON.stringify(orderBy);
search();
}; };
const onOrderChange = (value, params, search) => { const onOrderFieldChange = (value, params) => {
const orderBy = Object.assign({}, orderByParam.value, { way: value.way }); const tagObj = JSON.parse(params.orderBy); // esto donde va
params.orderBy = JSON.stringify(orderBy); const fields = {
search(); Relevancy: (value) => value + ' DESC, name',
ColorAndPrice: 'showOrder, price',
Name: 'name',
Price: 'price',
};
let tagField = fields[value];
if (!tagField) return;
if (typeof tagField === 'function') tagField = tagField(value);
tagObj.field = tagField;
params.orderBy = JSON.stringify(tagObj);
switch (value) {
case 'Relevancy':
tagObj.field = value + ' DESC, name';
params.orderBy = JSON.stringify(tagObj);
console.log('params: ', params);
break;
case 'ColorAndPrice':
tagObj.field = 'showOrder, price';
params.orderBy = JSON.stringify(tagObj);
console.log('params: ', params);
break;
case 'Name':
tagObj.field = 'name';
params.orderBy = JSON.stringify(tagObj);
console.log('params: ', params);
break;
case 'Price':
tagObj.field = 'price';
params.orderBy = JSON.stringify(tagObj);
console.log('params: ', params);
break;
}
}; };
const _moreFields = ['ASC', 'DESC'];
const _moreFieldsTypes = ['Relevancy', 'ColorAndPrice', 'Name', 'Price'];
const setCategoryList = (data) => { const setCategoryList = (data) => {
categoryList.value = (data || []) categoryList.value = (data || [])
.filter((category) => category.display) .filter((category) => category.display)
@ -168,6 +185,8 @@ const setCategoryList = (data) => {
...category, ...category,
icon: `vn:${(category.icon || '').split('-')[1]}`, icon: `vn:${(category.icon || '').split('-')[1]}`,
})); }));
moreFields.value = useLang(_moreFields);
moreFieldsOrder.value = useLang(_moreFieldsTypes);
}; };
const getCategoryClass = (category, params) => { const getCategoryClass = (category, params) => {
@ -175,6 +194,20 @@ const getCategoryClass = (category, params) => {
return 'active'; return 'active';
} }
}; };
const useLang = (values) => {
const { models } = validationsStore;
const properties = models.Item?.properties || {};
return values.map((name) => {
let prop = properties[name];
const label = t(`params.${name}`);
return {
name,
label,
type: prop ? prop.type : null,
};
});
};
</script> </script>
<template> <template>
@ -182,9 +215,9 @@ const getCategoryClass = (category, params) => {
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:hidden-tags="['orderFk', 'orderBy']" :hidden-tags="['orderFk', 'orderBy']"
:unremovable-params="['orderFk', 'orderBy']"
:expr-builder="exprBuilder" :expr-builder="exprBuilder"
:custom-tags="['tagGroups']" :custom-tags="['tagGroups']"
@init="onFilterInit"
@remove="clearFilter" @remove="clearFilter"
> >
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
@ -274,40 +307,29 @@ const getCategoryClass = (category, params) => {
<QItem class="q-my-md"> <QItem class="q-my-md">
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="t('params.order')" :label="t('Order')"
v-model="selectedOrder" v-model="selectedOrder"
:options="orderList || []" :options="moreFields"
option-value="way" option-label="label"
option-label="name"
dense dense
outlined outlined
rounded rounded
:emit-value="false" @update:model-value="(value) => onOrderChange(value, params)"
use-input
:is-clearable="false"
@update:model-value="
(value) => onOrderChange(value, params, searchFn)
"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-md"> <QItem class="q-mb-md">
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="t('params.order')" :label="t('Order by')"
v-model="selectedOrderField" v-model="selectedOrderField"
:options="OrderFields || []" :options="moreFieldsOrder"
option-value="field" option-label="label"
option-label="name" option-value="name"
dense dense
outlined outlined
rounded rounded
:emit-value="false" @update:model-value="(value) => onOrderFieldChange(value, params)"
use-input
:is-clearable="false"
@update:model-value="
(value) => onOrderFieldChange(value, params, searchFn)
"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -333,15 +355,30 @@ const getCategoryClass = (category, params) => {
:key="value" :key="value"
class="q-mt-md filter-value" class="q-mt-md filter-value"
> >
<VnInput <FetchData
v-if="selectedTag?.isFree" v-if="selectedTag"
v-model="value.value" :url="`Tags/${selectedTag}/filterValue`"
:label="t('params.value')" limit="30"
is-outlined auto-load
class="filter-input" @on-fetch="(data) => (tagOptions = data)"
/> />
<VnSelect <VnSelect
v-else v-if="!selectedTag"
:label="t('params.value')"
v-model="value.value"
:options="tagValue || []"
option-value="value"
option-label="value"
dense
outlined
rounded
emit-value
use-input
class="filter-input"
@new-value="createValue"
/>
<VnSelect
v-else-if="selectedTag === 1"
:label="t('params.value')" :label="t('params.value')"
v-model="value.value" v-model="value.value"
:options="tagOptions || []" :options="tagOptions || []"
@ -352,18 +389,18 @@ const getCategoryClass = (category, params) => {
rounded rounded
emit-value emit-value
use-input use-input
:disable="!selectedTag" class="filter-input"
@new-value="createValue"
/>
<VnInput
v-else
:label="t('params.value')"
v-model="value.value"
dense
outlined
rounded
class="filter-input" class="filter-input"
/> />
<FetchData
v-if="selectedTag && !selectedTag.isFree"
:url="`Tags/${selectedTag?.id}/filterValue`"
limit="30"
auto-load
@on-fetch="(data) => (tagOptions = data)"
/>
<QIcon <QIcon
name="delete" name="delete"
class="filter-icon" class="filter-icon"
@ -388,7 +425,6 @@ const getCategoryClass = (category, params) => {
rounded rounded
type="button" type="button"
unelevated unelevated
:disable="isButtonDisabled"
@click.stop="applyTagFilter(params, searchFn)" @click.stop="applyTagFilter(params, searchFn)"
/> />
</QItemSection> </QItemSection>
@ -453,6 +489,12 @@ en:
tag: Tag tag: Tag
value: Value value: Value
order: Order order: Order
ASC: Ascendant
DESC: Descendant
Relevancy: Relevancy
ColorAndPrice: Color and price
Name: Name
Price: Price
es: es:
params: params:
type: Tipo type: Tipo
@ -460,6 +502,14 @@ es:
tag: Etiqueta tag: Etiqueta
value: Valor value: Valor
order: Orden order: Orden
ASC: Ascendiente
DESC: Descendiente
Relevancy: Relevancia
ColorAndPrice: Color y precio
Name: Nombre
Price: Precio
Order: Orden
Order by: Ordenar por
Plant: Planta Plant: Planta
Flower: Flor Flower: Flor
Handmade: Confección Handmade: Confección

View File

@ -3,16 +3,14 @@ import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import VnImg from 'src/components/ui/VnImg.vue';
import OrderCatalogItemDialog from 'pages/Order/Card/OrderCatalogItemDialog.vue'; import OrderCatalogItemDialog from 'pages/Order/Card/OrderCatalogItemDialog.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { useSession } from 'composables/useSession';
import toCurrency from '../../../filters/toCurrency'; import toCurrency from '../../../filters/toCurrency';
const DEFAULT_PRICE_KG = 0; const DEFAULT_PRICE_KG = 0;
const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia();
const { t } = useI18n(); const { t } = useI18n();
defineProps({ defineProps({
@ -29,14 +27,7 @@ const dialog = ref(null);
<div class="container order-catalog-item overflow-hidden"> <div class="container order-catalog-item overflow-hidden">
<QCard class="card shadow-6"> <QCard class="card shadow-6">
<div class="img-wrapper"> <div class="img-wrapper">
<QImg <VnImg :id="item.id" class="image" />
:src="`/api/Images/catalog/200x200/${item.id}/download?access_token=${token}`"
spinner-color="primary"
:ratio="1"
height="192"
width="192"
class="image"
/>
<div v-if="item.hex" class="item-color-container"> <div v-if="item.hex" class="item-color-container">
<div <div
class="item-color" class="item-color"
@ -59,7 +50,10 @@ const dialog = ref(null);
</template> </template>
<div class="footer"> <div class="footer">
<div class="price"> <div class="price">
<p>{{ item.available }} {{ t('to') }} {{ item.price }}</p> <p>
{{ item.available }} {{ t('to') }}
{{ toCurrency(item.price) }}
</p>
<QIcon name="add_circle" class="icon"> <QIcon name="add_circle" class="icon">
<QTooltip>{{ t('globals.add') }}</QTooltip> <QTooltip>{{ t('globals.add') }}</QTooltip>
<QPopupProxy ref="dialog"> <QPopupProxy ref="dialog">

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { useRoute } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
@ -16,6 +16,7 @@ const route = useRoute();
const state = useState(); const state = useState();
const ORDER_MODEL = 'order'; const ORDER_MODEL = 'order';
const router = useRouter();
const isNew = Boolean(!route.params.id); const isNew = Boolean(!route.params.id);
const initialFormState = reactive({ const initialFormState = reactive({
clientFk: null, clientFk: null,
@ -26,22 +27,19 @@ const initialFormState = reactive({
const clientList = ref([]); const clientList = ref([]);
const agencyList = ref([]); const agencyList = ref([]);
const addressList = ref([]); const addressList = ref([]);
const clientId = ref(null);
const onClientsFetched = async (data) => { const onClientsFetched = (data) => {
try { clientList.value = data;
clientList.value = data; initialFormState.clientFk = Number(route.query?.clientFk) || null;
initialFormState.clientFk = Number(route.query?.clientFk) || null; clientId.value = initialFormState.clientFk;
if (initialFormState.clientFk) { const client = clientList.value.find(
const { defaultAddressFk } = clientList.value.find( (client) => client.id === initialFormState.clientFk
(client) => client.id === initialFormState.clientFk );
); if (!client?.defaultAddressFk)
throw new Error(t(`No default address found for the client`));
if (defaultAddressFk) await fetchAddressList(defaultAddressFk); fetchAddressList(client.defaultAddressFk);
}
} catch (err) {
console.error('Error fetching clients', err);
}
}; };
const fetchAddressList = async (addressId) => { const fetchAddressList = async (addressId) => {
@ -55,7 +53,6 @@ const fetchAddressList = async (addressId) => {
}, },
}); });
addressList.value = data; addressList.value = data;
// Set address by default
if (addressList.value?.length === 1) { if (addressList.value?.length === 1) {
state.get(ORDER_MODEL).addressFk = addressList.value[0].id; state.get(ORDER_MODEL).addressFk = addressList.value[0].id;
} }
@ -121,6 +118,21 @@ const orderFilter = {
}, },
], ],
}; };
const onClientChange = async (clientId) => {
try {
const { data } = await axios.get(`Clients/${clientId}`);
console.log('info cliente: ', data);
await fetchAddressList(data.defaultAddressFk);
} catch (error) {
console.error('Error al cambiar el cliente:', error);
}
};
async function onDataSaved(data) {
await router.push({ path: `/order/${data}/catalog` });
}
</script> </script>
<template> <template>
@ -134,13 +146,15 @@ const orderFilter = {
<div class="q-pa-md"> <div class="q-pa-md">
<FormModel <FormModel
:url="!isNew ? `Orders/${route.params.id}` : null" :url="!isNew ? `Orders/${route.params.id}` : null"
:url-create="isNew ? 'Orders/new' : null" url-create="Orders/new"
@on-data-saved="onDataSaved"
:model="ORDER_MODEL" :model="ORDER_MODEL"
:form-initial-data="isNew ? initialFormState : null" :form-initial-data="isNew ? initialFormState : null"
:observe-form-changes="!isNew" :observe-form-changes="!isNew"
:mapper="isNew ? orderMapper : null" :mapper="isNew ? orderMapper : null"
:filter="orderFilter" :filter="orderFilter"
@on-fetch="fetchOrderDetails" @on-fetch="fetchOrderDetails"
auto-load
> >
<template #form="{ data }"> <template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md"> <VnRow class="row q-gutter-md q-mb-md">
@ -151,9 +165,7 @@ const orderFilter = {
option-value="id" option-value="id"
option-label="name" option-label="name"
hide-selected hide-selected
@update:model-value=" @update:model-value="onClientChange"
(client) => fetchAddressList(client.defaultAddressFk)
"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -170,12 +182,10 @@ const orderFilter = {
v-model="data.addressFk" v-model="data.addressFk"
:options="addressList" :options="addressList"
option-value="id" option-value="id"
option-label="nickname" option-label="street"
hide-selected hide-selected
:disable="!addressList?.length" :disable="!addressList?.length"
@update:model-value=" @update:model-value="onAddressChange"
() => fetchAgencyList(data.landed, data.addressFk)
"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -216,3 +226,8 @@ const orderFilter = {
</FormModel> </FormModel>
</div> </div>
</template> </template>
<i18n>
es:
No default address found for the client: No hay ninguna dirección asociada a este cliente.
</i18n>

View File

@ -4,7 +4,6 @@ import { useRoute } from 'vue-router';
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n'; 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 OrderCatalogItem from 'pages/Order/Card/OrderCatalogItem.vue'; import OrderCatalogItem from 'pages/Order/Card/OrderCatalogItem.vue';
import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue'; import OrderCatalogFilter from 'pages/Order/Card/OrderCatalogFilter.vue';
@ -35,38 +34,31 @@ function extractTags(items) {
}); });
}); });
tags.value = resultTags; tags.value = resultTags;
extractValueTags(items);
}
const tagValue = ref([]);
function extractValueTags(items) {
const resultValueTags = items.flatMap((x) =>
Object.keys(x)
.filter((k) => /^value\d+$/.test(k))
.map((v) => x[v])
.filter((v) => v)
.sort()
);
tagValue.value = resultValueTags;
} }
</script> </script>
<template> <template>
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
<VnSearchbar
data-key="OrderCatalogList"
url="Orders/CatalogFilter"
:limit="50"
:user-params="catalogParams"
:static-params="['orderFk', 'orderBy']"
:redirect="false"
/>
</Teleport>
<Teleport v-if="stateStore.isHeaderMounted()" to="#actions-append">
<div class="row q-gutter-x-sm">
<QBtn
flat
@click.stop="stateStore.toggleRightDrawer()"
round
dense
icon="menu"
>
<QTooltip bottom anchor="bottom right">
{{ t('globals.collapseMenu') }}
</QTooltip>
</QBtn>
</div>
</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 class="fit text-grey-8">
<OrderCatalogFilter data-key="OrderCatalogList" :tags="tags" /> <OrderCatalogFilter
data-key="OrderCatalogList"
:tag-value="tagValue"
:tags="tags"
/>
</QScrollArea> </QScrollArea>
</QDrawer> </QDrawer>
<QPage class="column items-center q-pa-md"> <QPage class="column items-center q-pa-md">

View File

@ -7,19 +7,17 @@ import { useQuasar } from 'quasar';
import VnPaginate from 'components/ui/VnPaginate.vue'; import VnPaginate from 'components/ui/VnPaginate.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import CardList from 'components/ui/CardList.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import VnConfirm from 'components/ui/VnConfirm.vue'; import VnConfirm from 'components/ui/VnConfirm.vue';
import VnImg from 'components/ui/VnImg.vue';
import { toCurrency, toDate } from 'src/filters'; import { toCurrency, toDate } from 'src/filters';
import { useSession } from 'composables/useSession';
import axios from 'axios'; import axios from 'axios';
import ItemDescriptorProxy from '../Item/Card/ItemDescriptorProxy.vue';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const { getTokenMultimedia } = useSession();
const quasar = useQuasar(); const quasar = useQuasar();
const token = getTokenMultimedia();
const orderSummary = ref({ const orderSummary = ref({
total: null, total: null,
vat: null, vat: null,
@ -61,6 +59,56 @@ async function confirmOrder() {
type: 'positive', type: 'positive',
}); });
} }
const detailsColumns = ref([
{
name: 'img',
label: '',
field: (row) => row?.item?.id,
},
{
name: 'item',
label: t('order.summary.item'),
field: (row) => row?.item?.id,
sortable: true,
},
{
name: 'description',
label: t('globals.description'),
field: (row) => row?.item?.name,
},
{
name: 'warehouse',
label: t('warehouse'),
field: (row) => row?.warehouse?.name,
sortable: true,
},
{
name: 'shipped',
label: t('shipped'),
field: (row) => toDate(row?.shipped),
},
{
name: 'quantity',
label: t('order.summary.quantity'),
field: (row) => row?.quantity,
},
{
name: 'price',
label: t('order.summary.price'),
field: (row) => toCurrency(row?.price),
},
{
name: 'amount',
label: t('order.summary.amount'),
field: (row) => toCurrency(row?.quantity * row?.price),
},
{
name: 'actions',
label: '',
field: (row) => row?.id,
},
]);
</script> </script>
<template> <template>
@ -83,30 +131,33 @@ async function confirmOrder() {
auto-load auto-load
/> />
<QPage :key="componentKey" class="column items-center q-pa-md"> <QPage :key="componentKey" class="column items-center q-pa-md">
<div class="vn-card-list"> <div class="order-list full-width">
<div v-if="!orderSummary.total" class="no-result"> <div v-if="!orderSummary.total" class="no-result">
{{ t('globals.noResults') }} {{ t('globals.noResults') }}
</div> </div>
<QCard v-else class="order-lines-summary q-pa-lg">
<p class="header text-right block"> <QDrawer side="right" :width="270" show-if-above>
{{ t('summary') }} <QCard class="order-lines-summary q-pa-lg">
</p> <p class="header text-right block">
<VnLv {{ t('summary') }}
v-if="orderSummary.vat && orderSummary.total" </p>
:label="t('subtotal')" <VnLv
:value="toCurrency(orderSummary.total - orderSummary.vat)" v-if="orderSummary.vat && orderSummary.total"
/> :label="t('subtotal')"
<VnLv :value="toCurrency(orderSummary.total - orderSummary.vat)"
v-if="orderSummary.vat" />
:label="t('VAT')" <VnLv
:value="toCurrency(orderSummary?.vat)" v-if="orderSummary.vat"
/> :label="t('VAT')"
<VnLv :value="toCurrency(orderSummary?.vat)"
v-if="orderSummary.total" />
:label="t('total')" <VnLv
:value="toCurrency(orderSummary?.total)" v-if="orderSummary.total"
/> :label="t('total')"
</QCard> :value="toCurrency(orderSummary?.total)"
/>
</QCard>
</QDrawer>
<VnPaginate <VnPaginate
data-key="OrderLines" data-key="OrderLines"
url="OrderRows" url="OrderRows"
@ -125,74 +176,71 @@ async function confirmOrder() {
}" }"
> >
<template #body="{ rows }"> <template #body="{ rows }">
<div class="catalog-list q-mt-xl"> <div class="q-pa-md">
<CardList <QTable
v-for="row in rows" :columns="detailsColumns"
:key="row.id" :rows="rows"
:id="row.id" flat
:title="row?.item?.name" class="full-width"
class="cursor-inherit" style="text-align: center"
> >
<template #title> <template #header="props">
<div class="flex items-center"> <QTr class="tr-header" :props="props">
<div class="image-wrapper q-mr-md"> <QTh
<QImg v-for="col in props.cols"
:src="`/api/Images/catalog/50x50/${row?.item?.id}/download?access_token=${token}`" :key="col.name"
spinner-color="primary" :props="props"
:ratio="1" style="text-align: center"
height="50"
width="50"
class="image"
/>
</div>
<div
class="title text-primary text-weight-bold text-h5"
> >
{{ row?.item?.name }} {{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #body-cell-img="{ value }">
<QTd>
<div class="image-wrapper">
<VnImg :id="value" class="rounded" />
</div> </div>
<QChip class="q-chip-color" outline size="sm"> </QTd>
{{ t('ID') }}: {{ row.id }}
</QChip>
</div>
</template> </template>
<template #list-items> <template #body-cell-item="{ value }">
<div class="q-mb-sm"> <QTd class="item">
<span class="text-uppercase subname"> <span class="link">
{{ row.item.subName }} <QBtn flat>
{{ value }}
</QBtn>
<ItemDescriptorProxy :id="value" />
</span> </span>
<FetchedTags :item="row.item" :max-length="5" /> </QTd>
</div>
<VnLv :label="t('item')" :value="String(row.item.id)" />
<VnLv
:label="t('warehouse')"
:value="row.warehouse.name"
/>
<VnLv
:label="t('shipped')"
:value="toDate(row.shipped)"
/>
<VnLv
:label="t('quantity')"
:value="String(row.quantity)"
/>
<VnLv
:label="t('price')"
:value="toCurrency(row.price)"
/>
<VnLv
:label="t('amount')"
:value="toCurrency(row.price * row.quantity)"
/>
</template> </template>
<template #actions v-if="!order?.isConfirmed"> <template #body-cell-description="{ row, value }">
<QBtn <QTd>
:label="t('remove')" <div
@click.stop="confirmRemove(row)" class="row column full-width justify-between items-start"
color="primary" >
style="margin-top: 15px" {{ value }}
/> <div v-if="value" class="subName">
{{ value.toUpperCase() }}
</div>
</div>
<FetchedTags :item="row.item" :max-length="6" />
</QTd>
</template> </template>
</CardList>
<template #body-cell-actions="{ value }">
<QTd>
<QIcon
name="delete"
color="primary"
size="sm"
class="cursor-pointer"
@click.stop="confirmRemove(value)"
>
<QTooltip>{{ t('Remove thermograph') }}</QTooltip>
</QIcon>
</QTd>
</template>
</QTable>
</div> </div>
</template> </template>
</VnPaginate> </VnPaginate>
@ -239,14 +287,7 @@ async function confirmOrder() {
.image-wrapper { .image-wrapper {
height: 50px; height: 50px;
width: 50px; width: 50px;
margin-left: 30%;
.image {
border-radius: 50%;
}
}
.subname {
color: var(--vn-label-color);
} }
.no-result { .no-result {
@ -255,6 +296,11 @@ async function confirmOrder() {
color: var(--vn-label-color); color: var(--vn-label-color);
text-align: center; text-align: center;
} }
.subName {
text-transform: uppercase;
color: var(--vn-label-color);
}
</style> </style>
<i18n> <i18n>
en: en:

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onBeforeMount, computed, ref } from 'vue'; import { onBeforeMount, onMounted, computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Notify } from 'quasar'; import { Notify } from 'quasar';
import axios from 'axios'; import axios from 'axios';
@ -10,10 +10,12 @@ import CmrFilter from './CmrFilter.vue';
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import { useStateStore } from 'src/stores/useStateStore';
const { t } = useI18n(); const { t } = useI18n();
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia(); const token = getTokenMultimedia();
const state = useStateStore();
const selected = ref([]); const selected = ref([]);
const warehouses = ref([]); const warehouses = ref([]);
@ -81,6 +83,9 @@ onBeforeMount(async () => {
const { data } = await axios.get('Warehouses'); const { data } = await axios.get('Warehouses');
warehouses.value = data; warehouses.value = data;
}); });
onMounted(() => (state.rightDrawer = true));
function getApiUrl() { function getApiUrl() {
return new URL(window.location).origin; return new URL(window.location).origin;
} }

View File

@ -20,8 +20,8 @@ const { t } = useI18n();
const quasar = useQuasar(); const quasar = useQuasar();
const entityId = computed(() => $props.id || route.params.id); const entityId = computed(() => $props.id || route.params.id);
const URL_KEY = 'NotificationSubscriptions'; const URL_KEY = 'NotificationSubscriptions';
const active = ref(); const active = ref(new Map());
const available = ref(); const available = ref(new Map());
async function toggleNotification(notification) { async function toggleNotification(notification) {
try { try {
@ -56,6 +56,7 @@ const swapEntry = (from, to, key) => {
}; };
function setNotifications(data) { function setNotifications(data) {
console.log('data: ', data);
active.value = new Map(data.active); active.value = new Map(data.active);
available.value = new Map(data.available); available.value = new Map(data.available);
} }