import { useEffect, useMemo, useState } from 'react'; import { Box, Button, FormControlLabel, FormHelperText, Stack, Switch, TextField, Typography, } from '@mui/material'; import { useTranslation } from 'react-i18next'; import { formatJson, validateJson, type JsonFormatOptions, type JsonFormatResult, } from '@/utils/jsonFormatter'; import { formatByteSize } from '@/utils/textStatistics'; import { useSnackbar } from '@/components/GlobalSnackbar'; import { jsonDiffPageStyles } from '@/config/pageTheme'; import CopyButton from '@/components/CopyButton'; import SwitchButtonGroup from '@/components/SwitchButtonGroup'; /** 缩进大小选项 */ const INDENT_OPTIONS = [2, 4, 6, 8] as const; /** * JSON 格式化工具区域组件 * * 提供输入区域、格式化选项(缩进大小、键名排序)和格式化结果展示, * 支持一键复制格式化后的 JSON。 */ export default function JsonFormatSection() { const { t } = useTranslation(['jsonFormat']); const { showMessage } = useSnackbar(); const [input, setInput] = useState(''); const [error, setError] = useState(null); const [indentSize, setIndentSize] = useState(2); const [sortKeys, setSortKeys] = useState(false); const [result, setResult] = useState(null); // 防抖校验输入 useEffect(() => { const handle = setTimeout(() => { setError(validateJson(input)); }, 300); return () => clearTimeout(handle); }, [input]); const canFormat = useMemo(() => { return input.trim() !== '' && !error; }, [input, error]); const handleFormat = () => { const validationError = validateJson(input); if (validationError) { setError(validationError); setResult(null); return; } try { const options: JsonFormatOptions = { indentSize, sortKeys }; const formatResult = formatJson(input, options); setResult(formatResult); } catch (e) { setError(e instanceof SyntaxError ? e.message : String(e)); setResult(null); } }; const handleClear = () => { setInput(''); setError(null); setResult(null); }; return ( {/* 工具栏 */} {/* 缩进选择 */} {t('jsonFormat:indentSize')} setIndentSize(v)} options={INDENT_OPTIONS.map((size) => ({ value: size, label: String(size) }))} sx={{ width: 'auto', mb: 0, flexShrink: 0 }} size="small" /> {/* 键名排序开关 */} setSortKeys(e.target.checked)} /> } label={ {t('jsonFormat:sortKeys')} } sx={{ ml: 1 }} /> {/* 输入区 */} setInput(e.target.value)} error={Boolean(error)} sx={jsonDiffPageStyles.INPUT_STYLE} /> {error && ( {t('jsonFormat:invalidJson')} )} {/* 格式化结果 */} {result && result.formatted ? ( {/* 结果头部 */} theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.03)' : 'grey.50', }} > {t('jsonFormat:outputLabel')} {t('jsonFormat:originalSize')}: {formatByteSize(result.originalBytes)} {t('jsonFormat:formattedSize')}: {formatByteSize(result.formattedBytes)} {/* 格式化内容 */} {result.formatted} ) : ( theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.03)' : 'grey.50', border: '1px dashed', borderColor: (theme) => theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.15)' : 'grey.300', textAlign: 'center', }} > {t('jsonFormat:emptyHint')} )} ); }