184 lines
5.6 KiB
TypeScript
184 lines
5.6 KiB
TypeScript
import { createRoot } from 'react-dom/client';
|
|
import { useState } from 'react';
|
|
import type { ScanResult } from '../../src/collector/scan';
|
|
|
|
function App() {
|
|
const [status, setStatus] = useState<string>('准备就绪');
|
|
const [result, setResult] = useState<ScanResult | null>(null);
|
|
const [error, setError] = useState<string>('');
|
|
|
|
const handleScan = async () => {
|
|
setStatus('采集中...');
|
|
setError('');
|
|
setResult(null);
|
|
|
|
try {
|
|
// 获取当前活跃 tab
|
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
if (!tab?.id) {
|
|
setError('无法获取当前标签页');
|
|
setStatus('准备就绪');
|
|
return;
|
|
}
|
|
|
|
// 执行采集(调用 content script 暴露的全局函数)
|
|
const scanResult = await chrome.scripting.executeScript({
|
|
target: { tabId: tab.id },
|
|
func: () => (window as any).__SellerHelper?.scan()
|
|
});
|
|
|
|
const data = scanResult[0]?.result;
|
|
if (!data) {
|
|
setError('当前页面不支持采集(仅支持 1688/淘宝商品详情页)');
|
|
setStatus('准备就绪');
|
|
return;
|
|
}
|
|
|
|
setResult(data);
|
|
setStatus('采集完成');
|
|
} catch (err) {
|
|
setError(`采集失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
setStatus('准备就绪');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div style={{ padding: '1rem', fontFamily: 'system-ui', width: '360px' }}>
|
|
<h2 style={{ margin: 0, fontSize: '1.25rem' }}>Seller Helper</h2>
|
|
<p style={{ margin: '0.25rem 0', fontSize: '0.875rem', color: '#666' }}>
|
|
1688/淘宝 商品采集
|
|
</p>
|
|
|
|
<div style={{
|
|
marginTop: '1rem',
|
|
padding: '0.5rem',
|
|
background: status === '采集完成' ? '#f0fff0' : '#f0f0f0',
|
|
borderRadius: '4px',
|
|
fontSize: '0.875rem'
|
|
}}>
|
|
状态: {status}
|
|
</div>
|
|
|
|
{error && (
|
|
<div style={{
|
|
marginTop: '0.5rem',
|
|
padding: '0.5rem',
|
|
background: '#fff0f0',
|
|
border: '1px solid #ffcccc',
|
|
borderRadius: '4px',
|
|
fontSize: '0.875rem',
|
|
color: '#cc0000'
|
|
}}>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
style={{
|
|
width: '100%',
|
|
padding: '0.75rem',
|
|
marginTop: '1rem',
|
|
background: '#1890ff',
|
|
color: 'white',
|
|
border: 'none',
|
|
borderRadius: '4px',
|
|
cursor: 'pointer',
|
|
fontSize: '1rem',
|
|
fontWeight: 500
|
|
}}
|
|
onClick={handleScan}
|
|
disabled={status === '采集中...'}
|
|
>
|
|
{status === '采集中...' ? '采集中...' : '开始采集'}
|
|
</button>
|
|
|
|
{result && (
|
|
<div style={{ marginTop: '1rem', fontSize: '0.875rem' }}>
|
|
<div style={{
|
|
padding: '0.5rem',
|
|
background: '#fafafa',
|
|
borderRadius: '4px',
|
|
marginBottom: '0.5rem'
|
|
}}>
|
|
<div><strong>{result.platform}</strong> · {result.itemId}</div>
|
|
<div style={{ fontSize: '0.75rem', color: '#999', marginTop: '0.25rem' }}>
|
|
{new Date(result.scannedAt).toLocaleString()}
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ marginTop: '0.75rem' }}>
|
|
<h3 style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem' }}>文本 ({result.texts.length})</h3>
|
|
{result.texts.map((t, i) => (
|
|
<div key={i} style={{
|
|
padding: '0.25rem 0.5rem',
|
|
background: '#f9f9f9',
|
|
borderLeft: '3px solid #1890ff',
|
|
marginBottom: '0.25rem',
|
|
fontSize: '0.75rem'
|
|
}}>
|
|
<strong>{t.kind}</strong>: {t.content.substring(0, 50)}...
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div style={{ marginTop: '0.75rem' }}>
|
|
<h3 style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem' }}>图片 ({result.images.length})</h3>
|
|
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
|
|
{Object.entries(result.stats).map(([group, count]) => (
|
|
<div key={group} style={{
|
|
padding: '0.25rem 0.5rem',
|
|
background: '#e6f7ff',
|
|
borderRadius: '4px',
|
|
fontSize: '0.75rem'
|
|
}}>
|
|
{group}: {count}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{result.warnings.length > 0 && (
|
|
<div style={{ marginTop: '0.75rem' }}>
|
|
<h3 style={{ margin: '0 0 0.5rem 0', fontSize: '0.875rem', color: '#ff6600' }}>
|
|
⚠️ 警告
|
|
</h3>
|
|
{result.warnings.map((w, i) => (
|
|
<div key={i} style={{
|
|
padding: '0.25rem 0.5rem',
|
|
background: '#fff7e6',
|
|
borderLeft: '3px solid #ff6600',
|
|
marginBottom: '0.25rem',
|
|
fontSize: '0.75rem'
|
|
}}>
|
|
{w}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div style={{
|
|
marginTop: '1rem',
|
|
padding: '0.5rem',
|
|
background: '#f9f9f9',
|
|
borderRadius: '4px',
|
|
fontSize: '0.75rem',
|
|
color: '#666'
|
|
}}>
|
|
<div>💡 使用说明:</div>
|
|
<ol style={{ margin: '0.25rem 0 0 1.25rem', padding: 0 }}>
|
|
<li>打开 1688 或淘宝商品详情页</li>
|
|
<li>滚动到页面底部(加载详情图)</li>
|
|
<li>点击"开始采集"按钮</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const root = createRoot(document.getElementById('root')!);
|
|
root.render(<App />);
|
|
|
|
export default App;
|