feat: 开发采集插件

This commit is contained in:
R524809
2026-08-11 17:09:23 +08:00
parent 6c4356de24
commit b27e42dc75
148 changed files with 6898 additions and 9691 deletions
+183
View File
@@ -0,0 +1,183 @@
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;
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seller Helper</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./App.tsx"></script>
</body>
</html>