112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
/**
|
||
* 采集引擎入口 - 扫描当前页面
|
||
* 从 docs/extension/plan.md §6.7 移植(组装各模块)
|
||
*
|
||
* 淘宝/天猫优先从 SSR JSON 提取(window.__ICE_APP_CONTEXT__),
|
||
* 提取失败时降级到 DOM 采集。
|
||
*/
|
||
import { matchProfile } from '../profiles';
|
||
import { waitForAny } from './dom';
|
||
import { collectImages, type ImageMaterial } from './image';
|
||
import { collectTexts, type TextMaterial } from './text';
|
||
import { extractSSRData } from './ssr';
|
||
import { buildFromSSR } from './ssr-builder';
|
||
|
||
export type { ImageMaterial, TextMaterial };
|
||
|
||
export interface ScanResult {
|
||
platform: string;
|
||
itemId: string | null;
|
||
url: string;
|
||
texts: TextMaterial[];
|
||
images: ImageMaterial[];
|
||
scannedAt: number;
|
||
stats: Record<string, number>; // 分组统计
|
||
warnings: string[]; // 警告(如详情图为 0)
|
||
}
|
||
|
||
export type { ImageMaterial, TextMaterial };
|
||
|
||
export async function scanCurrentPage(): Promise<ScanResult | null> {
|
||
const profile = matchProfile(location.href);
|
||
if (!profile) {
|
||
console.warn('[Seller Helper] 当前页面不支持采集:', location.href);
|
||
return null;
|
||
}
|
||
|
||
console.log('[Seller Helper] 开始采集:', profile.name, location.href);
|
||
|
||
// ★ 淘宝/天猫优先从 SSR JSON 提取
|
||
const ssrData = extractSSRData();
|
||
if (ssrData) {
|
||
console.log('[Seller Helper] 使用 SSR 数据(JSON)');
|
||
const result = buildFromSSR(ssrData, profile);
|
||
console.log('[Seller Helper] SSR 采集完成:', {
|
||
texts: result.texts.length,
|
||
images: result.images.length,
|
||
stats: result.stats,
|
||
warnings: result.warnings
|
||
});
|
||
return result;
|
||
}
|
||
|
||
// 降级到 DOM 采集
|
||
console.log('[Seller Helper] SSR 数据不可用,降级到 DOM 采集');
|
||
|
||
// 等待页面就绪
|
||
const anchor = await waitForAny(profile.readySelectors, profile.readyTimeoutMs ?? 10_000);
|
||
if (!anchor) {
|
||
console.warn('[Seller Helper] 等待页面就绪超时');
|
||
// 不 return,页面可能部分可用,继续尝试
|
||
}
|
||
|
||
// 提取文本
|
||
const { materials: texts, missingRequired } = collectTexts(profile);
|
||
|
||
// 提取图片
|
||
const images = collectImages(profile);
|
||
|
||
// 统计各组数量
|
||
const stats: Record<string, number> = {};
|
||
for (const img of images) {
|
||
stats[img.groupKey] = (stats[img.groupKey] ?? 0) + 1;
|
||
}
|
||
|
||
// 生成警告
|
||
const warnings: string[] = [];
|
||
if (missingRequired.length > 0) {
|
||
warnings.push(`缺少必需字段: ${missingRequired.join(', ')}`);
|
||
}
|
||
if (images.length === 0) {
|
||
warnings.push('未扫描到任何图片/视频');
|
||
}
|
||
if (stats.detail === 0) {
|
||
warnings.push('详情图为 0 张,请滚动到页面底部后重新采集');
|
||
}
|
||
|
||
console.log('[Seller Helper] 采集完成:', {
|
||
texts: texts.length,
|
||
images: images.length,
|
||
stats,
|
||
warnings
|
||
});
|
||
|
||
return {
|
||
platform: profile.id,
|
||
itemId: profile.extractItemId(location.href),
|
||
url: location.href,
|
||
texts,
|
||
images,
|
||
scannedAt: Date.now(),
|
||
stats,
|
||
warnings
|
||
};
|
||
}
|
||
|
||
// 暴露到全局供 side panel 调用
|
||
if (typeof window !== 'undefined') {
|
||
(window as any).__SellerHelper = {
|
||
scan: scanCurrentPage
|
||
};
|
||
}
|