Catalog view #87
|
@ -28,13 +28,9 @@ const props = defineProps({
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
rounded: {
|
roundedBorders: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: false
|
default: 'none'
|
||||||
},
|
|
||||||
fullRounded: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -70,6 +66,17 @@ const showEditForm = ref(false);
|
||||||
const url = computed(() => {
|
const url = computed(() => {
|
||||||
return `${props.baseURL ?? app.imageUrl}/${props.storage}/${props.size}/${props.id}`;
|
return `${props.baseURL ?? app.imageUrl}/${props.storage}/${props.size}/${props.id}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const rounded = computed(() => {
|
||||||
|
const roundedMap = {
|
||||||
|
none: '',
|
||||||
|
default: 'rounded',
|
||||||
|
full: 'full-rounded',
|
||||||
|
top: 'top-rounded',
|
||||||
|
bottom: 'bottom-rounded'
|
||||||
|
};
|
||||||
|
return roundedMap[props.roundedBorders];
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="relative-position main-image-container">
|
<div class="relative-position main-image-container">
|
||||||
|
@ -85,11 +92,7 @@ const url = computed(() => {
|
||||||
<QTooltip>{{ t('addOrEditImage') }}</QTooltip>
|
<QTooltip>{{ t('addOrEditImage') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QImg
|
<QImg
|
||||||
:class="{
|
:class="[rounded, { zoomIn: props.zoomSize }]"
|
||||||
zoomIn: props.zoomSize,
|
|
||||||
rounded: props.rounded,
|
|
||||||
'full-rounded': props.fullRounded
|
|
||||||
}"
|
|
||||||
class="main-image"
|
class="main-image"
|
||||||
:src="url"
|
:src="url"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
@ -161,9 +164,19 @@ const url = computed(() => {
|
||||||
.rounded {
|
.rounded {
|
||||||
border-radius: 0.6em;
|
border-radius: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-rounded {
|
.full-rounded {
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rounded-bottom {
|
||||||
|
border-radius: 0.6em 0.6em 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-top {
|
||||||
|
border-radius: 0 0 0.6em 0.6em;
|
||||||
|
}
|
||||||
|
|
||||||
.img_zoom {
|
.img_zoom {
|
||||||
border-radius: 0%;
|
border-radius: 0%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Search'
|
default: ''
|
||||||
},
|
},
|
||||||
sqlQuery: {
|
sqlQuery: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
||||||
user: 'Usuari',
|
user: 'Usuari',
|
||||||
password: 'Contrasenya',
|
password: 'Contrasenya',
|
||||||
modify: 'Modificar',
|
modify: 'Modificar',
|
||||||
|
shoppingCart: 'Cistella de la compra',
|
||||||
|
available: 'Disponible',
|
||||||
|
minQuantity: 'Quantitat mínima',
|
||||||
// Image related translations
|
// Image related translations
|
||||||
'Cant lock cache': 'No es pot bloquejar la memòria cau',
|
'Cant lock cache': 'No es pot bloquejar la memòria cau',
|
||||||
'Bad file format': 'Format de fitxer no reconegut',
|
'Bad file format': 'Format de fitxer no reconegut',
|
||||||
|
|
|
@ -136,6 +136,9 @@ export default {
|
||||||
remindMe: 'Remember me',
|
remindMe: 'Remember me',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
modify: 'Modify',
|
modify: 'Modify',
|
||||||
|
shoppingCart: 'Shopping cart',
|
||||||
|
available: 'Available',
|
||||||
|
minQuantity: 'Minimum quantity',
|
||||||
// Image related translations
|
// Image related translations
|
||||||
'Cant lock cache': 'The cache could not be blocked',
|
'Cant lock cache': 'The cache could not be blocked',
|
||||||
'Bad file format': 'Unrecognized file format',
|
'Bad file format': 'Unrecognized file format',
|
||||||
|
|
|
@ -135,6 +135,9 @@ export default {
|
||||||
cancel: 'Cancelar',
|
cancel: 'Cancelar',
|
||||||
of: 'de',
|
of: 'de',
|
||||||
modify: 'Modificar',
|
modify: 'Modificar',
|
||||||
|
shoppingCart: 'Cesta de la compra',
|
||||||
|
available: 'Disponible',
|
||||||
|
minQuantity: 'Cantidad mínima',
|
||||||
// Image related translations
|
// Image related translations
|
||||||
'Cant lock cache': 'La caché no pudo ser bloqueada',
|
'Cant lock cache': 'La caché no pudo ser bloqueada',
|
||||||
'Bad file format': 'Formato de archivo no reconocido',
|
'Bad file format': 'Formato de archivo no reconocido',
|
||||||
|
|
|
@ -103,6 +103,9 @@ export default {
|
||||||
user: 'Utilisateur',
|
user: 'Utilisateur',
|
||||||
password: 'Mot de passe',
|
password: 'Mot de passe',
|
||||||
modify: 'Modifier',
|
modify: 'Modifier',
|
||||||
|
shoppingCart: 'Panier',
|
||||||
|
available: 'Disponible',
|
||||||
|
minQuantity: 'Quantité minimum',
|
||||||
// Image related translations
|
// Image related translations
|
||||||
'Cant lock cache': "Le cache n'a pas pu être verrouillé",
|
'Cant lock cache': "Le cache n'a pas pu être verrouillé",
|
||||||
'Bad file format': 'Format de fichier non reconnu',
|
'Bad file format': 'Format de fichier non reconnu',
|
||||||
|
|
|
@ -101,6 +101,9 @@ export default {
|
||||||
user: 'Utilizador',
|
user: 'Utilizador',
|
||||||
password: 'Senha',
|
password: 'Senha',
|
||||||
modify: 'Modificar',
|
modify: 'Modificar',
|
||||||
|
shoppingCart: 'Cesta da compra',
|
||||||
|
available: 'Disponível',
|
||||||
|
minQuantity: 'Quantidade mínima',
|
||||||
// Image related translations
|
// Image related translations
|
||||||
'Cant lock cache': 'O cache não pôde ser bloqueado',
|
'Cant lock cache': 'O cache não pôde ser bloqueado',
|
||||||
'Bad file format': 'Formato de arquivo inválido',
|
'Bad file format': 'Formato de arquivo inválido',
|
||||||
|
|
|
@ -104,10 +104,7 @@ onMounted(async () => {
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
<QPage class="vn-w-sm">
|
<QPage class="vn-w-sm">
|
||||||
<QList
|
<QList class="rounded-borders shadow-1 shadow-transition" separator>
|
||||||
class="rounded-borders shadow-1 shadow-transition"
|
|
||||||
separator
|
|
||||||
>
|
|
||||||
<CardList
|
<CardList
|
||||||
v-for="(address, index) in addresses"
|
v-for="(address, index) in addresses"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|
|
@ -33,9 +33,9 @@ const onSearch = data => (items.value = data || []);
|
||||||
<template>
|
<template>
|
||||||
<Teleport v-if="isHeaderMounted" to="#actions">
|
<Teleport v-if="isHeaderMounted" to="#actions">
|
||||||
<VnSearchBar
|
<VnSearchBar
|
||||||
:sqlQuery="query"
|
:sql-query="query"
|
||||||
@onSearch="onSearch"
|
@on-search="onSearch"
|
||||||
@onSearchError="items = []"
|
@on-search-error="items = []"
|
||||||
/>
|
/>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
<QPage class="vn-w-xs">
|
<QPage class="vn-w-xs">
|
||||||
|
@ -66,8 +66,8 @@ const onSearch = data => (items.value = data || []);
|
||||||
class="q-mr-md"
|
class="q-mr-md"
|
||||||
rounded
|
rounded
|
||||||
editable
|
editable
|
||||||
editSchema="catalog"
|
edit-schema="catalog"
|
||||||
:editImageName="item.image"
|
:edit-image-name="item.image"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
|
|
@ -1,706 +0,0 @@
|
||||||
<template>
|
|
||||||
<Teleport v-if="isHeaderMounted" to="#actions">
|
|
||||||
<QInput
|
|
||||||
:placeholder="$t('search')"
|
|
||||||
v-model="search"
|
|
||||||
debounce="500"
|
|
||||||
class="search q-mr-sm"
|
|
||||||
rounded
|
|
||||||
dark
|
|
||||||
dense
|
|
||||||
standout
|
|
||||||
>
|
|
||||||
<template #prepend>
|
|
||||||
<QIcon v-if="search === ''" name="search" />
|
|
||||||
<QIcon
|
|
||||||
v-else
|
|
||||||
name="clear"
|
|
||||||
class="cursor-pointer"
|
|
||||||
@click="search = ''"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</QInput>
|
|
||||||
<QBtn
|
|
||||||
:icon="$t(viewMode == 'list' ? 'view_list' : 'grid_on')"
|
|
||||||
:label="$t(viewMode == 'list' ? 'listView' : 'gridView')"
|
|
||||||
@click="onViewModeClick()"
|
|
||||||
rounded
|
|
||||||
no-caps
|
|
||||||
/>
|
|
||||||
</Teleport>
|
|
||||||
<div style="padding-bottom: 5em">
|
|
||||||
<QDrawer v-model="$app.rightDrawerOpen" side="right" :width="250">
|
|
||||||
<div class="q-pa-md">
|
|
||||||
<div class="basket-info">
|
|
||||||
<p>{{ date(new Date()) }}</p>
|
|
||||||
<p>
|
|
||||||
{{ $t('warehouse') }}
|
|
||||||
{{ 'Algemesi' }}
|
|
||||||
</p>
|
|
||||||
<QBtn
|
|
||||||
flat
|
|
||||||
rounded
|
|
||||||
no-caps
|
|
||||||
:to="{
|
|
||||||
name: 'checkout',
|
|
||||||
params: { id: appStore.basketOrderId },
|
|
||||||
query: { continue: 'catalog' }
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ $t('modify') }}
|
|
||||||
</QBtn>
|
|
||||||
</div>
|
|
||||||
<div class="q-mt-md">
|
|
||||||
<div class="q-mb-xs text-grey-7">
|
|
||||||
{{ $t('category') }}
|
|
||||||
<QIcon
|
|
||||||
v-if="category"
|
|
||||||
style="font-size: 1.3em"
|
|
||||||
name="cancel"
|
|
||||||
class="cursor-pointer"
|
|
||||||
:title="$t('deleteFilter')"
|
|
||||||
@click="
|
|
||||||
$router.push({ params: { category: null } })
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="categories">
|
|
||||||
<QBtn
|
|
||||||
flat
|
|
||||||
round
|
|
||||||
class="category q-pa-sm"
|
|
||||||
v-for="cat in categories"
|
|
||||||
:class="{ active: category == cat.id }"
|
|
||||||
:key="cat.id"
|
|
||||||
:title="cat.name"
|
|
||||||
:to="{ params: { category: cat.id, type: null } }"
|
|
||||||
>
|
|
||||||
<img :src="`statics/category/${cat.code}.svg`" />
|
|
||||||
</QBtn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="q-mt-md" v-if="category || search">
|
|
||||||
<div class="q-mb-xs text-grey-7">
|
|
||||||
{{ $t('filterBy') }}
|
|
||||||
</div>
|
|
||||||
<QSelect
|
|
||||||
v-model="type"
|
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
:options="types"
|
|
||||||
:disable="!category"
|
|
||||||
clearable
|
|
||||||
:label="$t('family')"
|
|
||||||
@filter="filterType"
|
|
||||||
@input="
|
|
||||||
$router.push({ params: { type: type && type.id } })
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<QSelect
|
|
||||||
v-model="order"
|
|
||||||
input-debounce="0"
|
|
||||||
:options="orderOptions"
|
|
||||||
:label="$t('orderBy')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="q-pa-md" v-if="typeId || search">
|
|
||||||
<div class="q-mb-md" v-for="tag in tags" :key="tag.uid">
|
|
||||||
<div class="q-mb-xs text-caption text-grey-7">
|
|
||||||
{{ tag.name }}
|
|
||||||
<QIcon
|
|
||||||
v-if="tag.hasFilter"
|
|
||||||
style="font-size: 1.3em"
|
|
||||||
name="cancel"
|
|
||||||
:title="$t('deleteFilter')"
|
|
||||||
class="cursor-pointer"
|
|
||||||
@click="onResetTagFilterClick(tag)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-if="!tag.useRange">
|
|
||||||
<div
|
|
||||||
v-for="value in tag.values.slice(0, tag.showCount)"
|
|
||||||
:key="value"
|
|
||||||
>
|
|
||||||
<QCheckbox
|
|
||||||
v-model="tag.filter"
|
|
||||||
:dense="true"
|
|
||||||
:val="value"
|
|
||||||
:label="value"
|
|
||||||
@input="onCheck(tag)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div v-if="tag.values.length > tag.showCount">
|
|
||||||
<span
|
|
||||||
class="cursor-pointer text-blue"
|
|
||||||
@click="tag.showCount = Infinity"
|
|
||||||
>
|
|
||||||
<QIcon name="keyboard_arrow_down" />
|
|
||||||
{{ $t('viewMore') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="tag.showCount == Infinity">
|
|
||||||
<span
|
|
||||||
class="cursor-pointer text-blue"
|
|
||||||
@click="tag.showCount = tag.initialCount"
|
|
||||||
>
|
|
||||||
<QIcon name="keyboard_arrow_up" />
|
|
||||||
{{ $t('viewLess') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="q-mx-md">
|
|
||||||
<QRange
|
|
||||||
class="q-mt-lg"
|
|
||||||
v-if="tag.useRange"
|
|
||||||
v-model="tag.filter"
|
|
||||||
:min="tag.min"
|
|
||||||
:max="tag.max"
|
|
||||||
:step="tag.step"
|
|
||||||
:color="tag.hasFilter ? 'primary' : 'grey-6'"
|
|
||||||
@input="onRangeChange(tag, true)"
|
|
||||||
@change="onRangeChange(tag)"
|
|
||||||
label-always
|
|
||||||
markers
|
|
||||||
snap
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</QDrawer>
|
|
||||||
<QInfiniteScroll
|
|
||||||
@load="onLoad"
|
|
||||||
scroll-taget="html"
|
|
||||||
:offset="800"
|
|
||||||
:disable="disableScroll"
|
|
||||||
>
|
|
||||||
<div class="q-pa-md row justify-center q-gutter-md">
|
|
||||||
<QSpinner v-if="isLoading" color="primary" size="50px" />
|
|
||||||
<div
|
|
||||||
v-if="items && !items.length"
|
|
||||||
class="text-subtitle1 text-grey-7 q-pa-md"
|
|
||||||
>
|
|
||||||
{{ $t('noItemsFound') }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="!items && !isLoading"
|
|
||||||
class="text-subtitle1 text-grey-7 q-pa-md"
|
|
||||||
>
|
|
||||||
{{ $t('pleaseSetFilter') }}
|
|
||||||
</div>
|
|
||||||
<QCard class="my-card" v-for="_item in items" :key="_item.id">
|
|
||||||
<img
|
|
||||||
:src="`${$imageBase}/catalog/200x200/${_item.image}`"
|
|
||||||
/>
|
|
||||||
<QCardSection>
|
|
||||||
<div class="name text-subtitle1">
|
|
||||||
{{ _item.longName }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="sub-name text-uppercase text-subtitle1 text-grey-7 ellipsize q-pt-xs"
|
|
||||||
>
|
|
||||||
{{ _item.subName }}
|
|
||||||
</div>
|
|
||||||
<div class="tags q-pt-xs">
|
|
||||||
<div v-for="tag in _item.tags" :key="tag.tagFk">
|
|
||||||
<span class="text-grey-7">{{
|
|
||||||
tag.tag.name
|
|
||||||
}}</span>
|
|
||||||
{{ tag.value }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</QCardSection>
|
|
||||||
<QCardActions class="actions justify-between">
|
|
||||||
<div class="q-pl-sm">
|
|
||||||
<span class="available bg-green text-white">{{
|
|
||||||
_item.available
|
|
||||||
}}</span>
|
|
||||||
{{ $t('from') }}
|
|
||||||
<span class="price">{{
|
|
||||||
currency(_item.buy?.price3)
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
<QBtn
|
|
||||||
icon="add_shopping_cart"
|
|
||||||
:title="$t('buy')"
|
|
||||||
@click="showItem(_item)"
|
|
||||||
flat
|
|
||||||
/>
|
|
||||||
</QCardActions>
|
|
||||||
</QCard>
|
|
||||||
</div>
|
|
||||||
<template #loading>
|
|
||||||
<div class="row justify-center q-my-md">
|
|
||||||
<QSpinner color="primary" name="dots" size="40px" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</QInfiniteScroll>
|
|
||||||
<QDialog v-model="showItemDialog">
|
|
||||||
<QCard style="width: 25em">
|
|
||||||
<QImg
|
|
||||||
:src="`${$imageBase}/catalog/200x200/${item.image}`"
|
|
||||||
:ratio="5 / 3"
|
|
||||||
>
|
|
||||||
<div class="absolute-bottom text-center q-pa-xs">
|
|
||||||
<div class="text-subtitle1">
|
|
||||||
{{ item.longName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</QImg>
|
|
||||||
<QCardSection>
|
|
||||||
<div
|
|
||||||
class="text-uppercase text-subtitle1 text-grey-7 ellipsize"
|
|
||||||
>
|
|
||||||
{{ item.subName }}
|
|
||||||
</div>
|
|
||||||
<div class="text-grey-7">#{{ item.id }}</div>
|
|
||||||
</QCardSection>
|
|
||||||
<QCardSection>
|
|
||||||
<div v-for="tag in item.tags" :key="tag.tagFk">
|
|
||||||
<span class="text-grey-7">{{ tag.tag.name }}</span>
|
|
||||||
{{ tag.value }}
|
|
||||||
</div>
|
|
||||||
</QCardSection>
|
|
||||||
<QCardActions align="right">
|
|
||||||
<QBtn @click="showItemDialog = false" flat>
|
|
||||||
{{ $t('cancel') }}
|
|
||||||
</QBtn>
|
|
||||||
<QBtn @click="showItemDialog = false" flat>
|
|
||||||
{{ $t('accept') }}
|
|
||||||
</QBtn>
|
|
||||||
</QCardActions>
|
|
||||||
</QCard>
|
|
||||||
</QDialog>
|
|
||||||
<QPageSticky>
|
|
||||||
<QBtn
|
|
||||||
fab
|
|
||||||
to="/ecomerce/basket"
|
|
||||||
icon="shopping_cart"
|
|
||||||
color="accent"
|
|
||||||
:title="$t('shoppingCart')"
|
|
||||||
/>
|
|
||||||
</QPageSticky>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.search {
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
.basket-info {
|
|
||||||
background-color: #8cc63f;
|
|
||||||
color: white;
|
|
||||||
padding: 17px 28px;
|
|
||||||
border-radius: 7px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
& > p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.4em 0;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.categories {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 220px;
|
|
||||||
|
|
||||||
.category {
|
|
||||||
width: 55px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
& > img {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.tags {
|
|
||||||
max-height: 4.6em;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.available {
|
|
||||||
padding: 0.15em;
|
|
||||||
border-radius: 0.2em;
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
.price {
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
.my-card {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 17.5em;
|
|
||||||
height: 32.5em;
|
|
||||||
overflow: hidden;
|
|
||||||
.name,
|
|
||||||
.sub-name {
|
|
||||||
line-height: 1.3em;
|
|
||||||
}
|
|
||||||
.ellipsize {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.description {
|
|
||||||
height: 40px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { date, currency, formatDate } from 'src/lib/filters.js';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { useAppStore } from 'stores/app';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
|
|
||||||
const CancelToken = axios.CancelToken;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'HederaCatalog',
|
|
||||||
setup() {
|
|
||||||
const appStore = useAppStore();
|
|
||||||
const { isHeaderMounted } = storeToRefs(appStore);
|
|
||||||
return { isHeaderMounted, appStore };
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
uid: 0,
|
|
||||||
search: '',
|
|
||||||
orderDate: formatDate(new Date(), 'YYYY/MM/DD'),
|
|
||||||
category: null,
|
|
||||||
categories: [],
|
|
||||||
type: null,
|
|
||||||
typeId: null,
|
|
||||||
types: [],
|
|
||||||
orgTypes: [],
|
|
||||||
item: {},
|
|
||||||
showItemDialog: false,
|
|
||||||
tags: [],
|
|
||||||
isLoading: false,
|
|
||||||
items: null,
|
|
||||||
limit: null,
|
|
||||||
pageSize: 30,
|
|
||||||
maxTags: 5,
|
|
||||||
disableScroll: true,
|
|
||||||
viewMode: 'list',
|
|
||||||
order: {
|
|
||||||
label: this.$t('relevancy'),
|
|
||||||
value: 'relevancy DESC, longName'
|
|
||||||
},
|
|
||||||
orderOptions: [
|
|
||||||
{
|
|
||||||
label: this.$t('relevancy'),
|
|
||||||
value: 'relevancy DESC, longName'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('name'),
|
|
||||||
value: 'longName'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('siceAsc'),
|
|
||||||
value: 'size ASC'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('sizeDesc'),
|
|
||||||
value: 'size DESC'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('priceAsc'),
|
|
||||||
value: 'price ASC'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('priceDesc'),
|
|
||||||
value: 'price DESC'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: this.$t('available'),
|
|
||||||
value: 'available'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.$app.useRightDrawer = true;
|
|
||||||
},
|
|
||||||
async beforeMount() {
|
|
||||||
const isGuest = false; // TODO: Integrate isGuest logic
|
|
||||||
if (!isGuest) {
|
|
||||||
this.appStore.check('catalog');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
this.categories = await this.$jApi.query(
|
|
||||||
`SELECT c.id, l.name, c.color, c.code
|
|
||||||
FROM vn.itemCategory c
|
|
||||||
JOIN vn.itemCategoryL10n l ON l.id = c.id
|
|
||||||
WHERE c.display
|
|
||||||
ORDER BY display`
|
|
||||||
);
|
|
||||||
this.onRouteChange(this.$route);
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
this.clearTimeoutAndRequest();
|
|
||||||
},
|
|
||||||
beforeRouteUpdate(to, from, next) {
|
|
||||||
this.onRouteChange(to);
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
categories() {
|
|
||||||
this.refreshTitle();
|
|
||||||
},
|
|
||||||
orgTypes() {
|
|
||||||
this.refreshTitle();
|
|
||||||
},
|
|
||||||
order() {
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
date() {
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
async category(value) {
|
|
||||||
this.orgTypes = [];
|
|
||||||
if (!value) return;
|
|
||||||
|
|
||||||
const res = await this.$jApi.execQuery(
|
|
||||||
`CALL myOrder_getAvailable(${this.appStore.basketOrderId});
|
|
||||||
SELECT DISTINCT t.id, l.name
|
|
||||||
FROM vn.item i
|
|
||||||
JOIN vn.itemType t ON t.id = i.typeFk
|
|
||||||
JOIN tmp.itemAvailable a ON a.id = i.id
|
|
||||||
JOIN vn.itemTypeL10n l ON l.id = t.id
|
|
||||||
WHERE t.\`order\` >= 0
|
|
||||||
AND t.categoryFk = #category
|
|
||||||
ORDER BY t.\`order\`, l.name;
|
|
||||||
DROP TEMPORARY TABLE tmp.itemAvailable;`,
|
|
||||||
{ category: value }
|
|
||||||
);
|
|
||||||
res.fetch();
|
|
||||||
this.orgTypes = res.fetchData();
|
|
||||||
},
|
|
||||||
search(value) {
|
|
||||||
const location = { params: this.$route.params };
|
|
||||||
if (value) location.query = { search: value };
|
|
||||||
this.$router.push(location);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
date,
|
|
||||||
currency,
|
|
||||||
onViewModeClick() {
|
|
||||||
this.viewMode = this.viewMode === 'list' ? 'grid' : 'list';
|
|
||||||
},
|
|
||||||
onRouteChange(route) {
|
|
||||||
let { category, type } = route.params;
|
|
||||||
|
|
||||||
category = parseInt(category) || null;
|
|
||||||
type = parseInt(type) || null;
|
|
||||||
|
|
||||||
this.category = category;
|
|
||||||
this.typeId = category ? type : null;
|
|
||||||
this.search = route.query.search || '';
|
|
||||||
this.tags = [];
|
|
||||||
|
|
||||||
this.refreshTitle();
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
refreshTitle() {
|
|
||||||
let title = this.$t(this.$router.currentRoute.value.name);
|
|
||||||
let subtitle;
|
|
||||||
|
|
||||||
if (this.category) {
|
|
||||||
const category =
|
|
||||||
this.categories.find(i => i.id === this.category) || {};
|
|
||||||
title = category.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.typeId) {
|
|
||||||
this.type = this.orgTypes.find(i => i.id === this.typeId);
|
|
||||||
subtitle = title;
|
|
||||||
title = this.type && this.type.name;
|
|
||||||
} else {
|
|
||||||
this.type = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$app.$patch({ title, subtitle });
|
|
||||||
},
|
|
||||||
clearTimeoutAndRequest() {
|
|
||||||
if (this.timeout) {
|
|
||||||
clearTimeout(this.timeout);
|
|
||||||
this.timeout = null;
|
|
||||||
}
|
|
||||||
if (this.source) {
|
|
||||||
this.source.cancel();
|
|
||||||
this.source = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadItemsDelayed() {
|
|
||||||
this.clearTimeoutAndRequest();
|
|
||||||
this.timeout = setTimeout(() => this.loadItems(), 500);
|
|
||||||
},
|
|
||||||
loadItems() {
|
|
||||||
this.items = null;
|
|
||||||
this.isLoading = true;
|
|
||||||
this.limit = this.pageSize;
|
|
||||||
this.disableScroll = false;
|
|
||||||
this.isLoading = false;
|
|
||||||
// this.loadItemsBase().finally(() => (this.isLoading = false))
|
|
||||||
},
|
|
||||||
onLoad(index, done) {
|
|
||||||
if (this.isLoading) return done();
|
|
||||||
this.limit += this.pageSize;
|
|
||||||
done();
|
|
||||||
// this.loadItemsBase().finally(done)
|
|
||||||
},
|
|
||||||
loadItemsBase() {
|
|
||||||
this.clearTimeoutAndRequest();
|
|
||||||
|
|
||||||
if (!(this.category || this.typeId || this.search)) {
|
|
||||||
this.tags = [];
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagFilter = [];
|
|
||||||
|
|
||||||
for (const tag of this.tags) {
|
|
||||||
if (tag.hasFilter) {
|
|
||||||
tagFilter.push({
|
|
||||||
tagFk: tag.id,
|
|
||||||
values: tag.filter
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.source = CancelToken.source();
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
dated: this.orderDate,
|
|
||||||
typeFk: this.typeId,
|
|
||||||
categoryFk: this.category,
|
|
||||||
search: this.search,
|
|
||||||
order: this.order.value,
|
|
||||||
limit: this.limit,
|
|
||||||
tagFilter
|
|
||||||
};
|
|
||||||
const config = {
|
|
||||||
params,
|
|
||||||
cancelToken: this.source.token
|
|
||||||
};
|
|
||||||
return this.$axios
|
|
||||||
.get('Items/catalog', config)
|
|
||||||
.then(res => this.onItemsGet(res))
|
|
||||||
.catch(err => this.onItemsError(err))
|
|
||||||
.finally(() => (this.cancel = null));
|
|
||||||
},
|
|
||||||
onItemsError(err) {
|
|
||||||
if (err.__CANCEL__) return;
|
|
||||||
this.disableScroll = true;
|
|
||||||
throw err;
|
|
||||||
},
|
|
||||||
onItemsGet(res) {
|
|
||||||
for (const tag of res.data.tags) {
|
|
||||||
tag.uid = this.uid++;
|
|
||||||
|
|
||||||
if (tag.filter) {
|
|
||||||
tag.hasFilter = true;
|
|
||||||
tag.useRange = tag.filter.max || tag.filter.min;
|
|
||||||
} else {
|
|
||||||
tag.useRange =
|
|
||||||
tag.isQuantitative && tag.values.length > this.maxTags;
|
|
||||||
this.resetTagFilter(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag.values) {
|
|
||||||
tag.initialCount = this.maxTags;
|
|
||||||
if (Array.isArray(tag.filter)) {
|
|
||||||
tag.initialCount = Math.max(
|
|
||||||
tag.initialCount,
|
|
||||||
tag.filter.length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
tag.showCount = tag.initialCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.items = res.data.items;
|
|
||||||
this.tags = res.data.tags;
|
|
||||||
this.disableScroll = this.items.length < this.limit;
|
|
||||||
},
|
|
||||||
onRangeChange(tag, delay) {
|
|
||||||
tag.hasFilter = true;
|
|
||||||
|
|
||||||
if (!delay) this.loadItems();
|
|
||||||
else this.loadItemsDelayed();
|
|
||||||
},
|
|
||||||
onCheck(tag) {
|
|
||||||
tag.hasFilter = tag.filter.length > 0;
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
resetTagFilter(tag) {
|
|
||||||
tag.hasFilter = false;
|
|
||||||
|
|
||||||
if (tag.useRange) {
|
|
||||||
tag.filter = {
|
|
||||||
min: tag.min,
|
|
||||||
max: tag.max
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
tag.filter = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onResetTagFilterClick(tag) {
|
|
||||||
this.resetTagFilter(tag);
|
|
||||||
this.loadItems();
|
|
||||||
},
|
|
||||||
filterType(val, update) {
|
|
||||||
if (val === '') {
|
|
||||||
update(() => {
|
|
||||||
this.types = this.orgTypes;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
update(() => {
|
|
||||||
const needle = val.toLowerCase();
|
|
||||||
this.types = this.orgTypes.filter(
|
|
||||||
type => type.name.toLowerCase().indexOf(needle) > -1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showItem(item) {
|
|
||||||
this.item = item;
|
|
||||||
this.showItemDialog = true;
|
|
||||||
|
|
||||||
const conf = this.$state.catalogConfig;
|
|
||||||
const params = {
|
|
||||||
dated: this.orderDate,
|
|
||||||
addressFk: conf.addressFk,
|
|
||||||
agencyModeFk: conf.agencyModeFk
|
|
||||||
};
|
|
||||||
this.$axios
|
|
||||||
.get(`Items/${item.id}/calcCatalog`, { params })
|
|
||||||
.then(res => (this.lots = res.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<i18n lang="yaml">
|
|
||||||
es-ES:
|
|
||||||
gridView: Vista de rejilla
|
|
||||||
listView: Vista de lista
|
|
||||||
shoppingCart: Cesta de la compra
|
|
||||||
warehouse: Almacén
|
|
||||||
agency: Agencia
|
|
||||||
modify: Modificar
|
|
||||||
category: Categoría
|
|
||||||
deleteFilter: Quitar filtro
|
|
||||||
filterBy: Filtrar por
|
|
||||||
family: Familia
|
|
||||||
orderBy: Ordernar por
|
|
||||||
pleaseSetFilter: Elige un filtro en el menú de la derecha
|
|
||||||
search: Buscar
|
|
||||||
</i18n>
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import VnImg from 'src/components/ui/VnImg.vue';
|
||||||
|
import CardList from 'src/components/ui/CardList.vue';
|
||||||
|
|
||||||
|
import { currency } from 'src/lib/filters.js';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
item: { type: Object, default: () => {} },
|
||||||
|
viewMode: { type: String, default: 'grid' }
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QCard v-if="viewMode === 'grid'" v-ripple class="catalog-card">
|
||||||
|
<VnImg
|
||||||
|
storage="catalog"
|
||||||
|
size="200x200"
|
||||||
|
:id="item.image"
|
||||||
|
height="210px"
|
||||||
|
rounded="bottom"
|
||||||
|
/>
|
||||||
|
<div class="column" style="height: 205px; padding: 10px">
|
||||||
|
<div class="column" style="margin-bottom: auto">
|
||||||
|
<div class="text-subtitle2 ellipsis-2-lines">
|
||||||
|
{{ item.item }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="row justify-between text-uppercase text-subtitle1 text-grey-7"
|
||||||
|
>
|
||||||
|
<span class="text-subtitle2">
|
||||||
|
{{ item.subName }}
|
||||||
|
</span>
|
||||||
|
<span> #{{ item.id }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tags q-pt-xs text-caption">
|
||||||
|
<div
|
||||||
|
v-for="(tag, index) in item.previewTags"
|
||||||
|
|||||||
|
:key="index"
|
||||||
|
class="full-width row"
|
||||||
|
>
|
||||||
|
<span class="text-grey-7 col">
|
||||||
|
{{ tag.name }}
|
||||||
|
</span>
|
||||||
|
<span class="col ellipsis">{{ tag.value }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="item.minQuantity" class="row justify-end">
|
||||||
|
<QIcon
|
||||||
|
name="production_quantity_limits"
|
||||||
|
size="xs"
|
||||||
|
color="negative"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('minQuantity') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<span class="text-negative text-caption">{{
|
||||||
|
item.minQuantity
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-between items-cente q-gutter-x-xs">
|
||||||
|
<QBadge
|
||||||
|
:label="`x${item.grouping}`"
|
||||||
|
color="grey"
|
||||||
|
class="col-2 justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('minGrouping') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
<QBadge
|
||||||
|
outline
|
||||||
|
:label="item.available"
|
||||||
|
color="accent"
|
||||||
|
text-color="black"
|
||||||
|
class="col justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('available') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
<QBadge
|
||||||
|
outline
|
||||||
|
:label="currency(item.price)"
|
||||||
|
color="accent"
|
||||||
|
text-color="black"
|
||||||
|
class="col justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('groupingPrice') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</QCard>
|
||||||
|
<CardList v-else class="vn-w-sm">
|
||||||
|
<template #prepend>
|
||||||
|
<VnImg
|
||||||
|
storage="catalog"
|
||||||
|
size="200x200"
|
||||||
|
:id="item.image"
|
||||||
|
width="105px"
|
||||||
|
height="105px"
|
||||||
|
rounded-borders="full"
|
||||||
|
class="q-mr-md"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<span class="ellipsis-2-lines">
|
||||||
|
{{ item.item }}
|
||||||
|
</span>
|
||||||
|
<div class="row justify-between text-uppercase text-grey-7">
|
||||||
|
<span>{{ item.subName }}</span>
|
||||||
|
<span>#{{ item.id }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="full-width row">
|
||||||
|
<span
|
||||||
|
v-for="(tag, index) in item.previewTags"
|
||||||
|
:key="index"
|
||||||
|
class="text-grey-7 text-caption q-mr-sm"
|
||||||
|
>
|
||||||
|
{{ tag.value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="item.minQuantity" class="row justify-end">
|
||||||
|
<QIcon
|
||||||
|
name="production_quantity_limits"
|
||||||
|
size="xs"
|
||||||
|
color="negative"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('minQuantity') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QIcon>
|
||||||
|
<span class="text-negative text-caption">{{
|
||||||
|
item.minQuantity
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-end items-center q-gutter-x-xs q-mt-sm">
|
||||||
|
<QBadge
|
||||||
|
:label="`x${item.grouping}`"
|
||||||
|
color="grey"
|
||||||
|
class="col-2 justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('minGrouping') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
<QBadge
|
||||||
|
outline
|
||||||
|
:label="item.available"
|
||||||
|
color="accent"
|
||||||
|
text-color="black"
|
||||||
|
class="col-3 justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('available') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
<QBadge
|
||||||
|
outline
|
||||||
|
:label="currency(item.price)"
|
||||||
|
color="accent"
|
||||||
|
text-color="black"
|
||||||
|
class="col-3 justify-end text-body2"
|
||||||
|
>
|
||||||
|
<QTooltip>
|
||||||
|
{{ t('groupingPrice') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBadge>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CardList>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.catalog-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 210px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<i18n lang="yaml">
|
||||||
|
en-US:
|
||||||
|
groupingPrice: Price per group
|
||||||
|
minGrouping: Minimum packing
|
||||||
|
es-ES:
|
||||||
|
groupingPrice: Precio por grupo
|
||||||
|
minGrouping: Cantidad mínima
|
||||||
|
ca-ES:
|
||||||
|
groupingPrice: Preu per grup
|
||||||
|
minGrouping: Empaquetament mínim
|
||||||
|
fr-FR:
|
||||||
|
groupingPrice: Prix par groupe
|
||||||
|
minGrouping: Emballage minimum
|
||||||
|
pt-PT:
|
||||||
|
groupingPrice: Preço por grupo
|
||||||
|
minGrouping: Embalagem mínima
|
||||||
|
</i18n>
|
File diff suppressed because it is too large
Load Diff
|
@ -174,7 +174,6 @@ en-US:
|
||||||
startOrder: Start order
|
startOrder: Start order
|
||||||
noOrdersFound: No orders found
|
noOrdersFound: No orders found
|
||||||
makePayment: Make payment
|
makePayment: Make payment
|
||||||
shoppingCart: Shopping cart
|
|
||||||
balance: 'Balance:'
|
balance: 'Balance:'
|
||||||
paymentInfo: >-
|
paymentInfo: >-
|
||||||
The amount shown is your slope (negative) or favorable balance today, it
|
The amount shown is your slope (negative) or favorable balance today, it
|
||||||
|
@ -187,7 +186,6 @@ es-ES:
|
||||||
startOrder: Empezar pedido
|
startOrder: Empezar pedido
|
||||||
noOrdersFound: No se encontrado pedidos
|
noOrdersFound: No se encontrado pedidos
|
||||||
makePayment: Realizar pago
|
makePayment: Realizar pago
|
||||||
shoppingCart: Cesta de la compra
|
|
||||||
balance: 'Saldo:'
|
balance: 'Saldo:'
|
||||||
paymentInfo: >-
|
paymentInfo: >-
|
||||||
La cantidad mostrada es tu saldo pendiente (negativa) o favorable a día de
|
La cantidad mostrada es tu saldo pendiente (negativa) o favorable a día de
|
||||||
|
@ -201,7 +199,6 @@ ca-ES:
|
||||||
startOrder: Començar encàrrec
|
startOrder: Començar encàrrec
|
||||||
noOrdersFound: No s'han trobat comandes
|
noOrdersFound: No s'han trobat comandes
|
||||||
makePayment: Realitzar pagament
|
makePayment: Realitzar pagament
|
||||||
shoppingCart: Cistella de la compra
|
|
||||||
balance: 'Saldo:'
|
balance: 'Saldo:'
|
||||||
paymentInfo: >-
|
paymentInfo: >-
|
||||||
La quantitat mostrada és el teu saldo pendent (negatiu) o favorable a dia
|
La quantitat mostrada és el teu saldo pendent (negatiu) o favorable a dia
|
||||||
|
@ -215,7 +212,6 @@ fr-FR:
|
||||||
startOrder: Acheter
|
startOrder: Acheter
|
||||||
noOrdersFound: Aucune commande trouvée
|
noOrdersFound: Aucune commande trouvée
|
||||||
makePayment: Effectuer un paiement
|
makePayment: Effectuer un paiement
|
||||||
shoppingCart: Panier
|
|
||||||
balance: 'Balance:'
|
balance: 'Balance:'
|
||||||
paymentInfo: >-
|
paymentInfo: >-
|
||||||
Le montant indiqué est votre pente (négative) ou balance favorable
|
Le montant indiqué est votre pente (négative) ou balance favorable
|
||||||
|
@ -229,7 +225,6 @@ pt-PT:
|
||||||
startOrder: Iniciar encomenda
|
startOrder: Iniciar encomenda
|
||||||
noOrdersFound: Nenhum pedido encontrado
|
noOrdersFound: Nenhum pedido encontrado
|
||||||
makePayment: Realizar pagamento
|
makePayment: Realizar pagamento
|
||||||
shoppingCart: Cesta da compra
|
|
||||||
balance: 'Saldo:'
|
balance: 'Saldo:'
|
||||||
paymentInfo: >-
|
paymentInfo: >-
|
||||||
A quantidade mostrada é seu saldo pendente (negativo) ou favorável a dia de
|
A quantidade mostrada é seu saldo pendente (negativo) ou favorável a dia de
|
||||||
|
|
|
@ -66,7 +66,7 @@ const deleteRow = id => {
|
||||||
<template>
|
<template>
|
||||||
<QCard class="vn-w-sm" style="padding: 32px">
|
<QCard class="vn-w-sm" style="padding: 32px">
|
||||||
<QCardSection class="no-padding q-mb-md">
|
<QCardSection class="no-padding q-mb-md">
|
||||||
<div class="text-h6">#{{ ticket.id }}</div>
|
<div class="text-h6 text-bold">#{{ ticket.id }}</div>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="no-padding q-mb-md q-gutter-y-xs">
|
<QCardSection class="no-padding q-mb-md q-gutter-y-xs">
|
||||||
<div class="text-subtitle1 text-bold">
|
<div class="text-subtitle1 text-bold">
|
||||||
|
|
|
@ -41,12 +41,23 @@ onMounted(() => {
|
||||||
password.value.focus();
|
password.value.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
async function onLogin() {
|
|
||||||
await userStore.login(email.value, password.value, remember.value);
|
const onLogin = async () => {
|
||||||
await userStore.fetchUser();
|
await userStore.fetchUser();
|
||||||
await userStore.updateUserLang(selectedLocaleValue.value);
|
await userStore.updateUserLang(selectedLocaleValue.value);
|
||||||
await router.push('/');
|
await router.push('/');
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const login = async () => {
|
||||||
|
await userStore.login(email.value, password.value, remember.value);
|
||||||
|
await onLogin();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loginAsGuest = async () => {
|
||||||
|
userStore.isGuest = true;
|
||||||
|
localStorage.setItem('hederaGuest', true);
|
||||||
|
await onLogin();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -56,7 +67,7 @@ async function onLogin() {
|
||||||
<img src="statics/logo.svg" alt="Verdnatura" class="block" />
|
<img src="statics/logo.svg" alt="Verdnatura" class="block" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<QForm @submit="onLogin" class="q-gutter-y-md">
|
<QForm @submit="login()" class="q-gutter-y-md">
|
||||||
<div class="q-gutter-y-sm">
|
<div class="q-gutter-y-sm">
|
||||||
<QInput v-model="email" :label="$t('user')" autofocus />
|
<QInput v-model="email" :label="$t('user')" autofocus />
|
||||||
<QInput
|
<QInput
|
||||||
|
@ -106,7 +117,7 @@ async function onLogin() {
|
||||||
</div>
|
</div>
|
||||||
<div class="justify-center">
|
<div class="justify-center">
|
||||||
<QBtn
|
<QBtn
|
||||||
to="/"
|
@click="loginAsGuest()"
|
||||||
:label="$t('logInAsGuest')"
|
:label="$t('logInAsGuest')"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|
|
@ -75,7 +75,7 @@ const routes = [
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Catalog'
|
title: 'Catalog'
|
||||||
},
|
},
|
||||||
component: () => import('pages/Ecomerce/Catalog.vue')
|
component: () => import('pages/Ecomerce/CatalogView.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'basket',
|
name: 'basket',
|
||||||
|
|
|
@ -139,6 +139,11 @@ export const useAppStore = defineStore('hedera', {
|
||||||
unloadOrder() {
|
unloadOrder() {
|
||||||
localStorage.removeItem(storageOrderName);
|
localStorage.removeItem(storageOrderName);
|
||||||
this.basketOrderId = null;
|
this.basketOrderId = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
onLogout() {
|
||||||
|
this.unloadOrder();
|
||||||
|
this.menuEssentialLinks = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia';
|
||||||
import { api, jApi } from 'boot/axios';
|
import { api, jApi } from 'boot/axios';
|
||||||
import { i18n } from 'src/boot/i18n';
|
import { i18n } from 'src/boot/i18n';
|
||||||
import useNotify from 'src/composables/useNotify.js';
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
import { useAppStore } from 'src/stores/app.js';
|
||||||
|
|
||||||
const { t } = i18n.global;
|
const { t } = i18n.global;
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
|
@ -35,6 +36,7 @@ export const useUserStore = defineStore('user', {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
async init() {
|
async init() {
|
||||||
|
this.isGuest = localStorage.getItem('hederaGuest') || false;
|
||||||
await this.fetchUser();
|
await this.fetchUser();
|
||||||
await this.supplantInit();
|
await this.supplantInit();
|
||||||
this.updateSiteLocale();
|
this.updateSiteLocale();
|
||||||
|
@ -71,6 +73,8 @@ export const useUserStore = defineStore('user', {
|
||||||
sessionStorage.removeItem('vnToken');
|
sessionStorage.removeItem('vnToken');
|
||||||
}
|
}
|
||||||
this.$reset();
|
this.$reset();
|
||||||
|
localStorage.removeItem('hederaGuest');
|
||||||
|
useAppStore().onLogout();
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchUser(userType = 'user') {
|
async fetchUser(userType = 'user') {
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export default function debounce(callback, delay) {
|
||||||
|
let timeoutId;
|
||||||
|
return (...args) => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
callback(...args);
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Echo en falta el carro en rojo que representa la cantidad mínima
x1, representa el empaquetado mínimo. Esta traducción no está presente en el componente vue
minQuantity handleado.
Commit:
0f5014088d