Files
ozon-seller-kit/extension-v1/src/collector/ssr-builder.ts
T

156 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 从 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<string, number>;
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<string, number> = {};
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
};
}