import { Box, Typography, Container, List, ListItem, ListItemText, IconButton, Switch, Divider, Paper, Chip, } 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 { formMappingPageStyles } from '@/config/pageTheme.ts'; import { MockDataGenerator } from '@/utils/formMapping/smartInjector'; import { Button } from '@/components/Button'; import { FormInjectResult, MessageAction, sendMessage } from '@/utils/messages'; import { useSnackbar as useGlobalSnackbar } from '@/components/SnackbarProvider'; 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 { showMessage } = useGlobalSnackbar({ autoHideDuration: 3000 }); 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().catch((r) => console.error(r)); const listener = (changes: { [key: string]: chrome.storage.StorageChange }, area: string) => { if (area === 'local' && changes['active_form_map']) { loadEntries().catch((r) => console.error(r)); } }; chrome.storage.onChanged.addListener(listener); return () => chrome.storage.onChanged.removeListener(listener); }, [generatePreviewData]); const refreshPreview = () => { generatePreviewData(entries); }; const injectAllFields = async () => { if (entries.length === 0) { showMessage('没有可填充的字段', { severity: 'error' }); 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) || '', })); // 执行注入 (使用 type-safe sendMessage) const result = await sendMessage(MessageAction.FORM_INJECT, { data: injectData }, tabId); if (result && result.success) { result.results?.forEach((r: FormInjectResult) => { results.set(r.id, r.success); }); setInjectResults(results); showMessage('填充成功!', { severity: 'success' }); } else { throw new Error(result?.error || result?.message || '注入失败'); } } catch (error) { console.error('注入失败:', error); showMessage(error instanceof Error ? error.message : '注入失败,请确保已在网页中打开表单'); showMessage(error instanceof Error ? error.message : '注入失败,请确保已在网页中打开表单', { severity: 'error', }); } 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} 注入失败 )} ); }