diff --git a/src/components/ProductImage.vue b/src/components/ProductImage.vue index b4fd15f..21331c2 100644 --- a/src/components/ProductImage.vue +++ b/src/components/ProductImage.vue @@ -29,16 +29,26 @@ const props = withDefaults( } ) +function productImageKey(product?: ProductImageSource): string { + return [ + product?.file_id ?? '', + product?.file?.id ?? '', + product?.file?.full_src ?? '', + product?.file?.src ?? '', + product?.file?.url ?? '', + product?.img ?? '', + ].join('|') +} + const currentSrc = ref(resolveProductImageSrc(props.product)) const usingFallback = ref(false) watch( - () => props.product, - (product) => { + () => productImageKey(props.product), + () => { usingFallback.value = false - currentSrc.value = resolveProductImageSrc(product) + currentSrc.value = resolveProductImageSrc(props.product) }, - { deep: true } ) function handleError() { diff --git a/src/utils/productImage.ts b/src/utils/productImage.ts index b953b29..64af457 100644 --- a/src/utils/productImage.ts +++ b/src/utils/productImage.ts @@ -6,7 +6,9 @@ import parsianImg from '@/assets/img/parsianImg.svg' import venusImg from '@/assets/img/venousImg.svg' export type ProductImageSource = { - file?: { src?: string | null } | null + file?: { id?: number | null; src?: string | null; full_src?: string | null; url?: string | null } | null + file_id?: number | string | null + img?: string | null group_type?: string | null } | null | undefined @@ -43,9 +45,14 @@ export function getProductFallbackImage(product?: ProductImageSource): string { } export function resolveProductImageSrc(product?: ProductImageSource): string { - const remoteSrc = product?.file?.src + const remoteSrc = product?.file?.full_src || product?.file?.url || product?.file?.src if (isUsableImageSrc(remoteSrc)) { - return remoteSrc!.trim() + const url = remoteSrc!.trim() + const version = product?.file_id ?? product?.file?.id + if (version != null && version !== '' && Number(version) > 0 && /^https?:\/\//i.test(url) && !/[?&]v=/.test(url)) { + return `${url}${url.includes('?') ? '&' : '?'}v=${encodeURIComponent(String(version))}` + } + return url } return getProductFallbackImage(product) } diff --git a/src/views/base/products/composables/useProductsPageData.ts b/src/views/base/products/composables/useProductsPageData.ts index acf58c7..206cfa3 100644 --- a/src/views/base/products/composables/useProductsPageData.ts +++ b/src/views/base/products/composables/useProductsPageData.ts @@ -53,6 +53,29 @@ async function loadCategoryTabs() { } } +function productFileId(product: Product): number { + return Number(product.file_id ?? (product.file as { id?: number } | undefined)?.id ?? 0) +} + +function mergeLiveProductList(incoming: Product[], current?: Product[]): Product[] { + if (!current?.length) return incoming + + const currentById = new Map(current.map((item) => [item.id, item])) + return incoming.map((item) => { + const prev = currentById.get(item.id) + if (!prev || productFileId(prev) <= productFileId(item)) { + return item + } + + return { + ...item, + file: prev.file, + file_id: prev.file_id, + img: prev.img, + } + }) +} + function applyProductsList(products: Product[]) { const sorted = sortProductsByInventory(products) productsFirstItems.value = sorted @@ -76,8 +99,12 @@ export function applyProductsListFromSocket(products: Product[]) { return } - getProductsCatalogRef().value = products - applyProductsList(products) + const merged = mergeLiveProductList( + products, + getProductsCatalogRef().value.length ? getProductsCatalogRef().value : productsFirstItems.value, + ) + getProductsCatalogRef().value = merged + applyProductsList(merged) } function startProductListPolling() {