/** * 商品图统一解析:优先英文 SKU 本地缓存。 * * 约定目录:frontend/public/images/products/{sku}.webp * 同步:cd backend && go run ./cmd/sync_product_images */ export type ProductImageInput = { sku?: string | null /** 上游缩略图 URL(乐玩/DLC);仅在无本地 SKU 图时作 image-proxy 回退 */ url?: string | null } function trim(value?: string | null): string { return String(value || '').trim() } /** 按商户英文 SKU 取本地缓存图。 */ export function resolveProductImageBySku(sku?: string | null): string { const normalized = trim(sku) if (!normalized) return '' return `/images/products/${normalized}.webp` } /** * 解析展示用商品图: * 1. 有 sku → `/images/products/{sku}.webp` * 2. 其它外链 → image-proxy(运行时落盘到 data/uploads/products,仅兜底) */ export function resolveProductImage(input?: string | ProductImageInput | null): string { if (input == null) return '' let sku = '' let url = '' if (typeof input === 'string') { url = trim(input) } else { sku = trim(input.sku) url = trim(input.url) } if (sku) { return resolveProductImageBySku(sku) } if (!url) return '' if (url.startsWith('/')) return url return `/api/delivery/v1/image-proxy?url=${encodeURIComponent(url)}` }