/** * 从 SSR JSON 构建 ScanResult */ import { toOriginalUrl } from './url'; import type { SiteProfile } from '../profiles/types'; import type { SSRData } from './ssr'; // 直接定义类型避免循环依赖 interface TextMaterial { kind: 'title' | 'price' | 'params' | 'desc'; content: string; pairs?: Array<{ key: string; value: string }>; } interface ImageMaterial { key: string; groupKey: string; groupName: string; variantName?: string; url: string; thumbUrl: string; index: number; type: 'img' | 'video'; width?: number; height?: number; } interface ScanResult { platform: string; itemId: string | null; url: string; texts: TextMaterial[]; images: ImageMaterial[]; scannedAt: number; stats: Record; warnings: string[]; } export function buildFromSSR(data: SSRData, profile: SiteProfile): ScanResult { const texts: TextMaterial[] = []; const images: ImageMaterial[] = []; // 1. 标题(必需) texts.push({ kind: 'title', content: data.item.title }); // 2. 价格 if (data.price?.priceText) { texts.push({ kind: 'price', content: `¥${data.price.priceText}` }); } // 3. 参数表 const allParams = [ ...(data.params?.basicParamList || []), ...(data.params?.enhanceParamList || []) ]; if (allParams.length > 0) { const pairs = allParams .filter(p => p.propertyName && p.valueName) .map(p => ({ key: p.propertyName, value: p.valueName })); if (pairs.length > 0) { texts.push({ kind: 'params', content: pairs.map(p => `${p.key}: ${p.value}`).join('\n'), pairs }); } } // 4. 主图(item.images) let idx = 0; (data.item.images || []).forEach((url, i) => { if (!url) return; const origUrl = toOriginalUrl(url); images.push({ key: `main-${String(i + 1).padStart(3, '0')}`, groupKey: 'main', groupName: '主图', url: origUrl, thumbUrl: url, index: idx++, type: 'img' }); }); // 5. SKU 图(skuBase.props[0].values) // 淘宝/天猫通常只有一个规格维度(颜色分类),取 props[0] const skuProp = data.skuBase?.props?.[0]; if (skuProp?.values) { skuProp.values.forEach((v, i) => { if (!v.image) return; // 有些 SKU 没配图(如天猫那个 vid=43699206432) const origUrl = toOriginalUrl(v.image); images.push({ key: `sku-${String(i + 1).padStart(3, '0')}`, groupKey: 'sku', groupName: 'SKU图片', variantName: v.name || undefined, url: origUrl, thumbUrl: v.image, index: idx++, type: 'img' }); }); } // 6. 视频(item.videos) (data.item.videos || []).forEach((v, i) => { if (!v.url) return; images.push({ key: `video-${String(i + 1).padStart(3, '0')}`, groupKey: 'video', groupName: '视频', url: v.url, thumbUrl: v.videoThumbnailURL || v.url, index: idx++, type: 'video' }); }); // 统计各组数量 const stats: Record = {}; for (const img of images) { stats[img.groupKey] = (stats[img.groupKey] ?? 0) + 1; } // 生成警告 const warnings: string[] = []; if (texts.length === 0) { warnings.push('未提取到任何文本'); } if (images.length === 0) { warnings.push('未扫描到任何图片/视频'); } // SSR 数据里没有详情图,需要 DOM 补充 if (stats.detail === undefined) { warnings.push('详情图需 DOM 补充:请滚动到页面底部后重新采集'); } return { platform: profile.id, itemId: data.item.itemId, url: location.href, texts, images, scannedAt: Date.now(), stats, warnings }; }