import { Box, Typography, Container, List, ListItem, ListItemText, IconButton, Switch, Divider, Paper, Button, Chip, Snackbar, Alert, alpha, } from '@mui/material'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import RefreshIcon from '@mui/icons-material/Refresh'; import VisibilityIcon from '@mui/icons-material/Visibility'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import CancelIcon from '@mui/icons-material/Cancel'; import { useEffect, useState, useCallback } from 'react'; import { storageUtil } from '@/utils/chromeStorage'; import { FormMapEntry } from '@/types/storage'; import PageHeader from '@/components/PageHeader'; import { globalStyles, formMappingPageStyles } from '@/config/pageTheme.ts'; import { MockDataGenerator } from '@/utils/formMapping/smartInjector'; export default function FormFillPage() { const [entries, setEntries] = useState([]); const [previewData, setPreviewData] = useState>(new Map()); const [injectResults, setInjectResults] = useState>(new Map()); const [isInjecting, setIsInjecting] = useState(false); const [showSuccess, setShowSuccess] = useState(false); const [showError, setShowError] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const generatePreviewData = useCallback((items: FormMapEntry[]) => { const preview = new Map(); items.forEach((entry) => { const value = MockDataGenerator.generate(entry.action_logic, entry); preview.set(entry.id, value); }); setPreviewData(preview); setInjectResults(new Map()); }, []); useEffect(() => { const loadEntries = async () => { const data = (await storageUtil.get('active_form_map')) as FormMapEntry[]; setEntries(data || []); generatePreviewData(data || []); }; loadEntries(); const listener = (changes: { [key: string]: chrome.storage.StorageChange }, area: string) => { if (area === 'local' && changes['active_form_map']) { loadEntries(); } }; chrome.storage.onChanged.addListener(listener); return () => chrome.storage.onChanged.removeListener(listener); }, [generatePreviewData]); const refreshPreview = () => { generatePreviewData(entries); }; const injectAllFields = async () => { if (entries.length === 0) { setErrorMessage('没有可填充的字段'); setShowError(true); return; } setIsInjecting(true); const results = new Map(); try { // 发送消息到 content script 执行注入 const response = await chrome.tabs.query({ active: true, currentWindow: true }); if (response.length === 0) { throw new Error('无法获取当前标签页'); } const tabId = response[0].id; if (!tabId) { throw new Error('标签页ID无效'); } // 准备注入数据 const injectData = entries.map((entry) => ({ entry, mockValue: previewData.get(entry.id) || '', })); // 执行注入 const result = await chrome.tabs.sendMessage(tabId, { type: 'FORM_INJECT', data: injectData, }); if (result && result.success) { result.results.forEach((r: { id: string; success: boolean }) => { results.set(r.id, r.success); }); setInjectResults(results); setShowSuccess(true); } else { throw new Error(result?.error || '注入失败'); } } catch (error) { console.error('注入失败:', error); setErrorMessage( error instanceof Error ? error.message : '注入失败,请确保已在网页中打开表单', ); setShowError(true); } finally { setIsInjecting(false); } }; const getFieldTypeLabel = (type: string) => { const labels: Record = { text: '文本', select: '下拉框', checkbox: '复选框', radio: '单选框', }; return labels[type] || type; }; const getStrategyLabel = (strategy: string) => { const labels: Record = { fixed: '固定值', random: '随机', sequence: '序列', }; return labels[strategy] || strategy; }; return ( } /> {/* 操作区域 */} 填充控制 点击"开始填充"后,将根据映射配置向网页表单注入数据。 {/* 字段列表 */} 映射字段 ({entries.length}) {entries.length === 0 ? ( ) : ( entries.map((entry, index) => ( {index > 0 && } } sx={{ py: 1.5 }} > {entry.label_display} } secondary={ {entry.fingerprint.selector} 预览: {previewData.get(entry.id) || '---'} {injectResults.has(entry.id) && (injectResults.get(entry.id) ? ( ) : ( ))} } /> )) )} {/* 统计信息 */} {injectResults.size > 0 && ( {Array.from(injectResults.values()).filter(Boolean).length} 成功注入 {Array.from(injectResults.values()).filter((v) => !v).length} 注入失败 )} {/* 提示消息 */} setShowSuccess(false)} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} > 填充完成! setShowError(false)} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} > {errorMessage} ); }