feat(search): improvement search cache (#44)
This commit is contained in:
@@ -17,6 +17,13 @@ export const useSearchStore = defineStore('search', {
|
||||
isLoadingMore: false,
|
||||
isSearchPerformed: false,
|
||||
hasMore: false,
|
||||
|
||||
// Placeholder товары для пустого состояния поиска
|
||||
placeholderProducts: {
|
||||
data: [],
|
||||
total: 0,
|
||||
},
|
||||
isLoadingPlaceholder: false,
|
||||
}),
|
||||
|
||||
actions: {
|
||||
@@ -91,6 +98,35 @@ export const useSearchStore = defineStore('search', {
|
||||
this.isSearchPerformed = true;
|
||||
}
|
||||
},
|
||||
|
||||
async loadSearchPlaceholder() {
|
||||
// Если данные уже есть в store, возвращаем их
|
||||
if (this.placeholderProducts.data.length > 0) {
|
||||
return {
|
||||
data: this.placeholderProducts.data,
|
||||
meta: {
|
||||
total: this.placeholderProducts.total,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
this.isLoadingPlaceholder = true;
|
||||
// Иначе загружаем с сервера
|
||||
const response = await ftch('productsSearchPlaceholder');
|
||||
this.placeholderProducts.data = response.data.slice(0, 3);
|
||||
this.placeholderProducts.total = response?.meta?.total || 0;
|
||||
|
||||
return {
|
||||
data: this.placeholderProducts.data,
|
||||
meta: {
|
||||
total: this.placeholderProducts.total,
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
this.isLoadingPlaceholder = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -79,25 +79,38 @@
|
||||
class="flex flex-col items-center justify-center text-center py-16 px-10"
|
||||
>
|
||||
<div class="avatar-group -space-x-6 mb-4">
|
||||
<template v-for="product in preloadedProducts" :key="product.id">
|
||||
<div v-if="product.image" class="avatar">
|
||||
<div class="w-12">
|
||||
<img :src="product.image" :alt="product.name"/>
|
||||
</div>
|
||||
<!-- Skeleton при загрузке -->
|
||||
<template v-if="searchStore.isLoadingPlaceholder">
|
||||
<div v-for="n in 3" :key="n" class="avatar">
|
||||
<div class="w-12 skeleton rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<div v-else class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12 rounded-full">
|
||||
<span class="text-3xl">{{ product.name.charAt(0).toUpperCase() }}</span>
|
||||
</div>
|
||||
<div class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12 skeleton"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12">
|
||||
<span>{{ renderSmartNumber(productsTotal) }}</span>
|
||||
<!-- Товары после загрузки -->
|
||||
<template v-else>
|
||||
<template v-for="product in preloadedProducts" :key="product.id">
|
||||
<div v-if="product.image" class="avatar">
|
||||
<div class="w-12">
|
||||
<img :src="product.image" :alt="product.name"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12 rounded-full">
|
||||
<span class="text-3xl">{{ product.name.charAt(0).toUpperCase() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="avatar avatar-placeholder">
|
||||
<div class="bg-neutral text-neutral-content w-12">
|
||||
<span>{{ renderSmartNumber(productsTotal) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold mb-2">Поиск товаров</h2>
|
||||
<p class="text-sm mb-4">Введите запрос, чтобы отобразить подходящие товары.</p>
|
||||
@@ -185,8 +198,8 @@ const handleHideKeyboardClick = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const preloadedProducts = ref([]);
|
||||
const productsTotal = ref(0);
|
||||
const preloadedProducts = computed(() => searchStore.placeholderProducts.data);
|
||||
const productsTotal = computed(() => searchStore.placeholderProducts.total);
|
||||
|
||||
const searchWrapperStyle = computed(() => {
|
||||
const safeTop = getComputedStyle(document.documentElement)
|
||||
@@ -208,8 +221,6 @@ onMounted(async () => {
|
||||
});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_SEARCH);
|
||||
|
||||
const response = await searchStore.fetchProducts('', 1, 3);
|
||||
productsTotal.value = response?.meta?.total || 0;
|
||||
preloadedProducts.value = response.data.splice(0, 3);
|
||||
await searchStore.loadSearchPlaceholder();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user