fix(products): absolutize image URLs and preserve them on SSE merge
Relative full_src now uses node_server, and empty live-list file payloads no longer wipe catalog images. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import mokaabImg from '@/assets/img/mokaabImg.svg'
|
||||
import sekkeImg from '@/assets/img/sekkeImg.svg'
|
||||
import parsianImg from '@/assets/img/parsianImg.svg'
|
||||
import venusImg from '@/assets/img/venousImg.svg'
|
||||
import { getConfigApp } from '@/utils/config'
|
||||
|
||||
export type ProductImageSource = {
|
||||
file?: { id?: number | null; src?: string | null; full_src?: string | null; url?: string | null } | null
|
||||
@@ -18,6 +19,14 @@ function isUsableImageSrc(src?: string | null): boolean {
|
||||
return value !== '' && value !== 'null' && value !== 'undefined'
|
||||
}
|
||||
|
||||
function absolutizeImageUrl(url: string): string {
|
||||
if (/^https?:\/\//i.test(url)) return url
|
||||
const base = String(getConfigApp('node_server') || '').replace(/\/$/, '')
|
||||
const path = url.replace(/^\//, '')
|
||||
if (!base) return url.startsWith('/') ? url : `/${url}`
|
||||
return `${base}/${path}`
|
||||
}
|
||||
|
||||
export function getProductFallbackImage(product?: ProductImageSource): string {
|
||||
const type = (product?.group_type ?? '').trim()
|
||||
if (!type) return defaultImg
|
||||
@@ -47,7 +56,7 @@ export function getProductFallbackImage(product?: ProductImageSource): string {
|
||||
export function resolveProductImageSrc(product?: ProductImageSource): string {
|
||||
const remoteSrc = product?.file?.full_src || product?.file?.url || product?.file?.src
|
||||
if (isUsableImageSrc(remoteSrc)) {
|
||||
const url = remoteSrc!.trim()
|
||||
const url = absolutizeImageUrl(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))}`
|
||||
|
||||
@@ -57,22 +57,45 @@ function productFileId(product: Product): number {
|
||||
return Number(product.file_id ?? (product.file as { id?: number } | undefined)?.id ?? 0)
|
||||
}
|
||||
|
||||
function productHasDisplayImage(product: Product): boolean {
|
||||
const file = product.file as { full_src?: string; url?: string; src?: string } | null | undefined
|
||||
if (file && (file.full_src || file.url || file.src)) {
|
||||
return true
|
||||
}
|
||||
return !!(product.img && /^https?:\/\//i.test(product.img))
|
||||
}
|
||||
|
||||
/** استریم گاهی file خالی با همان file_id میفرستد — عکس خوب HTTP را پاک نکن. */
|
||||
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
|
||||
if (!prev) return item
|
||||
|
||||
const prevId = productFileId(prev)
|
||||
const nextId = productFileId(item)
|
||||
|
||||
if (!productHasDisplayImage(item) && productHasDisplayImage(prev)) {
|
||||
return {
|
||||
...item,
|
||||
file: prev.file,
|
||||
file_id: prev.file_id ?? (prev.file as { id?: number } | undefined)?.id ?? item.file_id,
|
||||
img: prev.img,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
file: prev.file,
|
||||
file_id: prev.file_id,
|
||||
img: prev.img,
|
||||
if (prevId > nextId) {
|
||||
return {
|
||||
...item,
|
||||
file: prev.file,
|
||||
file_id: prev.file_id,
|
||||
img: prev.img,
|
||||
}
|
||||
}
|
||||
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user