From 29579f80d3b983e05d3bad743b442f3fa4d737e1 Mon Sep 17 00:00:00 2001 From: mohammad sedighi Date: Tue, 25 Aug 2026 16:14:49 +0330 Subject: [PATCH] fix(products): keep newly uploaded image when SSE list is stale The live product stream was replacing the catalog with an older payload, so the new photo flashed then jumped back. Keep the newer file_id and stop resetting the img on unrelated price ticks. Co-authored-by: Cursor --- src/components/ProductImage.vue | 18 ++++++++--- src/utils/productImage.ts | 13 ++++++-- .../composables/useProductsPageData.ts | 31 +++++++++++++++++-- 3 files changed, 53 insertions(+), 9 deletions(-) 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() {