import { Box, Typography, Container, List, ListItem, ListItemText, IconButton, Switch, Divider, Paper, } from '@mui/material'; import DeleteIcon from '@mui/icons-material/Delete'; import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; import FileDownloadIcon from '@mui/icons-material/FileDownload'; import { useEffect, useState } from 'react'; import { storageUtil } from '@/utils/chromeStorage'; import { FormMapEntry } from '@/types/storage'; import PageHeader from '@/components/PageHeader'; import Button from '@/components/Button'; import { useSnackbar as useGlobalSnackbar } from '@/components/SnackbarProvider'; export default function FormMappingPage() { const [entries, setEntries] = useState([]); const [isPicking, setIsPicking] = useState(false); const { showMessage } = useGlobalSnackbar({ autoHideDuration: 3000 }); useEffect(() => { const loadData = async () => { const data = (await storageUtil.get('active_form_map')) as FormMapEntry[]; setEntries(data || []); const picking = (await storageUtil.get('app/formMapping/isPicking')) as boolean; setIsPicking(picking || false); }; loadData().catch((r) => console.error(r)); const listener = (changes: { [key: string]: chrome.storage.StorageChange }, area: string) => { if (area === 'local') { if (changes['active_form_map']) { setEntries((changes['active_form_map'].newValue as FormMapEntry[]) || []); } if (changes['app/formMapping/isPicking']) { setIsPicking((changes['app/formMapping/isPicking'].newValue as boolean) || false); } } }; chrome.storage.onChanged.addListener(listener); return () => chrome.storage.onChanged.removeListener(listener); }, []); const togglePicking = async () => { await storageUtil.set('app/formMapping/isPicking', !isPicking); }; const deleteEntry = async (id: string) => { const newEntries = entries.filter((e) => e.id !== id); await storageUtil.set('active_form_map', newEntries); }; const toggleSelection = async (id: string) => { const newEntries = entries.map((e) => e.id === id ? { ...e, ui_state: { ...e.ui_state, is_selected: !e.ui_state.is_selected } } : e, ); await storageUtil.set('active_form_map', newEntries); }; const clearAll = async () => { await storageUtil.set('active_form_map', []); await storageUtil.set('app/formMapping/isPicking', false); }; const exportConfig = () => { try { if (entries.length === 0) { showMessage('没有可导出的配置数据', { severity: 'warning' }); return; } const jsonStr = JSON.stringify(entries, null, 2); const blob = new Blob([jsonStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const date = new Date(); const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; const filename = `form-mapping-config-${dateStr}.json`; const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('配置导出成功!', { severity: 'success' }); } catch (error) { console.error('导出配置失败:', error); showMessage(error instanceof Error ? error.message : '导出失败,请重试', { severity: 'error', }); } }; return ( } /> 状态控制 点击“开始拾取”后,直接在网页上点击想要映射的表单元素。 已拾取字段 ({entries.length}) {entries.length === 0 ? ( ) : ( entries.map((entry, index) => ( {index > 0 && } deleteEntry(entry.id)} sx={{ color: 'error.light' }} > } sx={{ py: 1.5 }} > toggleSelection(entry.id)} /> )) )} {entries.length > 0 && ( 映射配置导出 (JSON)
{JSON.stringify(entries, null, 2)}
)}
); }