Grid mode
This commit is contained in:
parent
ff0d2db8fe
commit
72cd9e6cd6
|
@ -104,10 +104,7 @@ onMounted(async () => {
|
|||
</QBtn>
|
||||
</Teleport>
|
||||
<QPage class="vn-w-sm">
|
||||
<QList
|
||||
class="rounded-borders shadow-1 shadow-transition"
|
||||
separator
|
||||
>
|
||||
<QList class="rounded-borders shadow-1 shadow-transition" separator>
|
||||
<CardList
|
||||
v-for="(address, index) in addresses"
|
||||
:key="index"
|
||||
|
|
|
@ -1,40 +1,37 @@
|
|||
<script setup>
|
||||
import { onMounted } from 'vue';
|
||||
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: () => {} }
|
||||
item: { type: Object, default: () => {} },
|
||||
viewMode: { type: String, default: 'grid' }
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
onMounted(async () => {});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QCard v-ripple class="catalog-card">
|
||||
<QCard v-if="viewMode === 'grid'" v-ripple class="catalog-card">
|
||||
<div style="height: 210px">
|
||||
<VnImg
|
||||
storage="catalog"
|
||||
size="200x200"
|
||||
:id="item.image"
|
||||
width="80px"
|
||||
height="80px"
|
||||
rounded="bottom"
|
||||
class="full-height full-width"
|
||||
/>
|
||||
</div>
|
||||
<div class="column" style="height: 205px; padding: 10px">
|
||||
<div class="column" style="margin-bottom: auto">
|
||||
<div class="text-subtitle2">
|
||||
<div class="text-subtitle2 ellipsis-2-lines">
|
||||
{{ item.item }}
|
||||
</div>
|
||||
<div
|
||||
class="row justify-between sub-name text-uppercase text-subtitle1 text-grey-7"
|
||||
class="row justify-between text-uppercase text-subtitle1 text-grey-7"
|
||||
>
|
||||
<span class="text-subtitle2">
|
||||
{{ item.subName }}
|
||||
|
@ -42,29 +39,15 @@ onMounted(async () => {});
|
|||
<span> #{{ item.id }}</span>
|
||||
</div>
|
||||
<div class="tags q-pt-xs text-caption">
|
||||
<div class="full-width row">
|
||||
<div
|
||||
v-for="(tag, index) in item.previewTags"
|
||||
:key="index"
|
||||
class="full-width row"
|
||||
>
|
||||
<span class="text-grey-7 col">
|
||||
{{ item.tag5 }}
|
||||
{{ tag.name }}
|
||||
</span>
|
||||
<span class="col">{{ item.value5 }}</span>
|
||||
</div>
|
||||
<div class="full-width row">
|
||||
<span class="text-grey-7 col">
|
||||
{{ item.tag6 }}
|
||||
</span>
|
||||
<span class="col">{{ item.value6 }}</span>
|
||||
</div>
|
||||
<div class="full-width row">
|
||||
<span class="text-grey-7 col">
|
||||
{{ item.tag7 }}
|
||||
</span>
|
||||
<span class="col">{{ item.value7 }}</span>
|
||||
</div>
|
||||
<div class="full-width row">
|
||||
<span class="text-grey-7 col">
|
||||
{{ item.tag8 }}
|
||||
</span>
|
||||
<span class="col">{{ item.value8 }}</span>
|
||||
<span class="col ellipsis">{{ tag.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -103,6 +86,71 @@ onMounted(async () => {});
|
|||
</div>
|
||||
</div>
|
||||
</QCard>
|
||||
<CardList v-else class="vn-w-sm">
|
||||
<template #prepend>
|
||||
<div style="min-height: 105px; min-width: 105px" class="q-mr-md">
|
||||
<VnImg
|
||||
storage="catalog"
|
||||
size="200x200"
|
||||
:id="item.image"
|
||||
rounded="bottom"
|
||||
class="full-height full-width"
|
||||
/>
|
||||
</div>
|
||||
</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
|
||||
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 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>
|
||||
|
@ -118,12 +166,17 @@ onMounted(async () => {});
|
|||
<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>
|
||||
|
|
|
@ -20,20 +20,28 @@
|
|||
/>
|
||||
</template>
|
||||
</QInput> -->
|
||||
<!-- <QBtn
|
||||
:icon="$t(viewMode == 'list' ? 'view_list' : 'grid_on')"
|
||||
:label="$t(viewMode == 'list' ? 'listView' : 'gridView')"
|
||||
<QBtn
|
||||
:icon="viewTypeButtonContent.icon"
|
||||
:label="viewTypeButtonContent.label"
|
||||
@click="onViewModeClick()"
|
||||
rounded
|
||||
no-caps
|
||||
/> -->
|
||||
>
|
||||
<QTooltip>
|
||||
{{ viewTypeButtonContent.label }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
icon="shopping_cart_checkout"
|
||||
:label="t('shoppingCart')"
|
||||
:to="{ name: 'basket' }"
|
||||
rounded
|
||||
no-caps
|
||||
/>
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('shoppingCart') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</Teleport>
|
||||
<div style="padding-bottom: 5em">
|
||||
<QDrawer v-model="rightDrawerOpen" side="right" :width="250">
|
||||
|
@ -214,7 +222,13 @@
|
|||
</div> -->
|
||||
</QDrawer>
|
||||
<QInfiniteScroll>
|
||||
<div class="q-pa-md row justify-center q-gutter-md">
|
||||
<div
|
||||
:class="
|
||||
viewMode === 'grid'
|
||||
? 'q-pa-md row justify-center q-gutter-md'
|
||||
: 'column items-center'
|
||||
"
|
||||
>
|
||||
<QSpinner
|
||||
v-if="loading"
|
||||
color="primary"
|
||||
|
@ -233,6 +247,7 @@
|
|||
v-for="_item in items"
|
||||
:key="_item.id"
|
||||
:item="_item"
|
||||
:view-mode="viewMode"
|
||||
@click="showItem(_item)"
|
||||
/>
|
||||
</div>
|
||||
|
@ -354,6 +369,7 @@ const selectedItem = ref(null);
|
|||
const showItemDialog = ref(false);
|
||||
const loading = ref(false);
|
||||
const isGuest = ref(false); // TODO: Integrate isGuest logic
|
||||
const viewMode = ref('grid');
|
||||
|
||||
// Filters options
|
||||
const categories = ref([]);
|
||||
|
@ -423,10 +439,10 @@ const selectedCategory = computed({
|
|||
category.value = value;
|
||||
router.push({ params: { category: category.value, type: null } });
|
||||
onCategoryChange();
|
||||
refreshTitle();
|
||||
if (!value) return;
|
||||
getFilters();
|
||||
getItems();
|
||||
refreshTitle();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -511,7 +527,7 @@ const queryFilter = computed(() => {
|
|||
|
||||
// Filtro principal
|
||||
if (selectedCategory.value) {
|
||||
filters.push(`t.categoryFk = ${selectedCategory.value}`);
|
||||
filters.push(`(t.categoryFk = ${selectedCategory.value})`);
|
||||
}
|
||||
|
||||
const otherFilters = {
|
||||
|
@ -524,7 +540,7 @@ const queryFilter = computed(() => {
|
|||
// Añadir solo aquellos filtros que tengan valor
|
||||
Object.entries(otherFilters).forEach(([key, value]) => {
|
||||
if (value) {
|
||||
filters.push(`${key} = ${value}`);
|
||||
filters.push(`(${key} = ${value})`);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -542,6 +558,13 @@ const isSomeFilterSelected = computed(() => {
|
|||
);
|
||||
});
|
||||
|
||||
const viewTypeButtonContent = computed(() => {
|
||||
return {
|
||||
label: t(viewMode.value === 'list' ? 'listView' : 'gridView'),
|
||||
icon: viewMode.value === 'list' ? 'view_list' : 'grid_on'
|
||||
};
|
||||
});
|
||||
|
||||
const getOrder = async () => {
|
||||
try {
|
||||
const [data] = await jApi.query(
|
||||
|
@ -619,10 +642,26 @@ const getItemColors = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
const onItemsFetched = async () => {
|
||||
items.value.forEach(item => {
|
||||
const previewTags = [
|
||||
{ name: item.tag5, value: item.value5 },
|
||||
{ name: item.tag6, value: item.value6 },
|
||||
{ name: item.tag7, value: item.value7 }
|
||||
];
|
||||
item.previewTags = previewTags;
|
||||
});
|
||||
};
|
||||
|
||||
const getItems = async () => {
|
||||
try {
|
||||
if (
|
||||
!selectedCategory.value ||
|
||||
!basketOrderId.value ||
|
||||
!isSomeFilterSelected.value
|
||||
)
|
||||
return;
|
||||
loading.value = true;
|
||||
if (!selectedCategory.value || !basketOrderId.value) return;
|
||||
|
||||
const res = await jApi.execQuery(
|
||||
`DROP TEMPORARY TABLE IF EXISTS tmp.item;
|
||||
|
@ -656,11 +695,10 @@ const getItems = async () => {
|
|||
{ orderId: basketOrderId.value }
|
||||
);
|
||||
items.value = res.results[3].data;
|
||||
console.log('get items: ', items.value);
|
||||
await onItemsFetched();
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
console.error('Error getting items:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -709,13 +747,14 @@ const getSubcategories = async () => {
|
|||
try {
|
||||
const res = await jApi.execQuery(
|
||||
`CALL myOrder_getAvailable(#orderId);
|
||||
SELECT DISTINCT i.category, i.category
|
||||
SELECT DISTINCT i.category
|
||||
FROM vn.item i
|
||||
JOIN vn.itemType t ON t.id = i.typeFk
|
||||
JOIN tmp.itemAvailable a ON a.id = i.id
|
||||
WHERE #filter
|
||||
WHERE (${queryFilter.value})
|
||||
ORDER BY category;
|
||||
DROP TEMPORARY TABLE tmp.itemAvailable;`
|
||||
DROP TEMPORARY TABLE tmp.itemAvailable;`,
|
||||
{ orderId: basketOrderId.value }
|
||||
);
|
||||
itemSubcategories.value = res.results[1].data;
|
||||
} catch (error) {
|
||||
|
@ -739,12 +778,11 @@ const showItem = async item => {
|
|||
if (isGuest.value) return;
|
||||
|
||||
const itemLots = await calcItem(item.id);
|
||||
const tags = await getItemTags(item.id);
|
||||
item.tags = tags;
|
||||
const tags = getItemTags(item.id);
|
||||
item.lots = itemLots;
|
||||
item.tags = tags;
|
||||
showItemDialog.value = true;
|
||||
selectedItem.value = item;
|
||||
console.log('selected item: ', selectedItem.value);
|
||||
};
|
||||
|
||||
const removeCategory = () => {
|
||||
|
@ -759,7 +797,6 @@ const onCategoryChange = () => {
|
|||
selectedOrigin.value = null;
|
||||
selectedSubcategory.value = null;
|
||||
items.value = [];
|
||||
router.push({ params: { category: null, type: null } });
|
||||
};
|
||||
|
||||
const getItemTags = async itemFk => {
|
||||
|
@ -891,7 +928,6 @@ const refreshTitle = () => {
|
|||
const _category = categories.value.find(
|
||||
i => i.id === selectedCategory.value
|
||||
);
|
||||
|
||||
if (_category) {
|
||||
title = _category.name;
|
||||
|
||||
|
@ -899,7 +935,6 @@ const refreshTitle = () => {
|
|||
const _type = itemFamilies.value.find(
|
||||
i => i.id === selectedType.value
|
||||
);
|
||||
|
||||
if (_type) {
|
||||
subtitle = title;
|
||||
title = _type.name;
|
||||
|
@ -911,6 +946,10 @@ const refreshTitle = () => {
|
|||
appStore.$patch({ title, subtitle });
|
||||
};
|
||||
|
||||
const onViewModeClick = () => {
|
||||
viewMode.value = viewMode.value === 'list' ? 'grid' : 'list';
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
if (!isGuest.value) {
|
||||
await appStore.check('catalog');
|
||||
|
@ -924,8 +963,9 @@ onBeforeMount(async () => {
|
|||
await getOrder();
|
||||
await getCategories();
|
||||
|
||||
if (route.params.category) selectedCategory.value = route.params.category;
|
||||
if (route.params.type) selectedType.value = route.params.type;
|
||||
if (route.params.category)
|
||||
selectedCategory.value = Number(route.params.category);
|
||||
if (route.params.type) selectedType.value = Number(route.params.type);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -977,12 +1017,11 @@ en-US:
|
|||
higherSize: Higher size
|
||||
lowerPrice: Lower price
|
||||
higherPrice: Higher price
|
||||
minGrouping: Minimum packing
|
||||
add: Add
|
||||
added: Added
|
||||
listView: List view
|
||||
gridView: Grid view
|
||||
es-ES:
|
||||
gridView: Vista de rejilla
|
||||
listView: Vista de lista
|
||||
warehouse: Almacén
|
||||
agency: Agencia
|
||||
modify: Modificar
|
||||
|
@ -1002,9 +1041,10 @@ es-ES:
|
|||
higherSize: Medida más grande
|
||||
lowerPrice: Precio más bajo
|
||||
higherPrice: Precio más alto
|
||||
minGrouping: Cantidad mínima
|
||||
add: Añadir
|
||||
added: Añadido
|
||||
listView: Vista de lista
|
||||
gridView: Vista de rejilla
|
||||
ca-ES:
|
||||
category: Categoría
|
||||
deleteFilter: Eliminar filtro
|
||||
|
@ -1020,8 +1060,9 @@ ca-ES:
|
|||
higherSize: Mida més gran
|
||||
lowerPrice: Preu més baix
|
||||
higherPrice: Preu més alt
|
||||
minGrouping: Empaquetament mínim
|
||||
add: Afegir
|
||||
listView: Vista de llista
|
||||
gridView: Vista de graella
|
||||
fr-FR:
|
||||
category: Catégorie
|
||||
deleteFilter: Supprimer le filtre
|
||||
|
@ -1037,8 +1078,9 @@ fr-FR:
|
|||
higherSize: Taille le plus élevé
|
||||
lowerPrice: Prix le plus bas
|
||||
higherPrice: Prix le plus élevé
|
||||
minGrouping: Emballage minimum
|
||||
add: Ajouter
|
||||
listView: Vue en liste
|
||||
gridView: Vue en grille
|
||||
pt-PT:
|
||||
category: Categoria
|
||||
deleteFilter: Apagar filtro
|
||||
|
@ -1054,6 +1096,7 @@ pt-PT:
|
|||
higherSize: Tamanho maior
|
||||
lowerPrice: Preço mais baixo
|
||||
higherPrice: Preço mais alto
|
||||
minGrouping: Embalagem mínima
|
||||
add: Adicionar
|
||||
listView: Vista de lista
|
||||
gridView: Vista de grade
|
||||
</i18n>
|
||||
|
|
Loading…
Reference in New Issue