import React, { useState, useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Button, Form, Typography, Banner, Tabs, TabPane, Card, Input, InputNumber, Switch, TextArea, Row, Col, Divider, } from '@douyinfe/semi-ui'; import { IconCode, IconPlus, IconDelete, IconRefresh, } from '@douyinfe/semi-icons'; const { Text } = Typography; const JSONEditor = ({ value = '', onChange, field, label, placeholder, extraText, extraFooter, showClear = true, template, templateLabel, editorType = 'keyValue', rules = [], formApi = null, ...props }) => { const { t } = useTranslation(); // 初始化JSON数据 const [jsonData, setJsonData] = useState(() => { // 初始化时解析JSON数据 if (typeof value === 'string' && value.trim()) { try { const parsed = JSON.parse(value); return parsed; } catch (error) { return {}; } } if (typeof value === 'object' && value !== null) { return value; } return {}; }); // 手动模式下的本地文本缓冲,避免无效 JSON 时被外部值重置 const [manualText, setManualText] = useState(() => { if (typeof value === 'string') return value; if (value && typeof value === 'object') return JSON.stringify(value, null, 2); return ''; }); // 根据键数量决定默认编辑模式 const [editMode, setEditMode] = useState(() => { // 如果初始JSON数据的键数量大于10个,则默认使用手动模式 if (typeof value === 'string' && value.trim()) { try { const parsed = JSON.parse(value); const keyCount = Object.keys(parsed).length; return keyCount > 10 ? 'manual' : 'visual'; } catch (error) { // JSON无效时默认显示手动编辑模式 return 'manual'; } } return 'visual'; }); const [jsonError, setJsonError] = useState(''); // 数据同步 - 当value变化时总是更新jsonData(如果JSON有效) useEffect(() => { try { let parsed = {}; if (typeof value === 'string' && value.trim()) { parsed = JSON.parse(value); } else if (typeof value === 'object' && value !== null) { parsed = value; } setJsonData(parsed); setJsonError(''); } catch (error) { console.log('JSON解析失败:', error.message); setJsonError(error.message); // JSON格式错误时不更新jsonData } }, [value]); // 外部 value 变化时,若不在手动模式,则同步手动文本;在手动模式下不打断用户输入 useEffect(() => { if (editMode !== 'manual') { if (typeof value === 'string') setManualText(value); else if (value && typeof value === 'object') setManualText(JSON.stringify(value, null, 2)); else setManualText(''); } }, [value, editMode]); // 处理可视化编辑的数据变化 const handleVisualChange = useCallback((newData) => { setJsonData(newData); setJsonError(''); const jsonString = Object.keys(newData).length === 0 ? '' : JSON.stringify(newData, null, 2); // 通过formApi设置值(如果提供的话) if (formApi && field) { formApi.setValue(field, jsonString); } onChange?.(jsonString); }, [onChange, formApi, field]); // 处理手动编辑的数据变化(无效 JSON 不阻断输入,也不立刻回传上游) const handleManualChange = useCallback((newValue) => { setManualText(newValue); if (newValue && newValue.trim()) { try { JSON.parse(newValue); setJsonError(''); onChange?.(newValue); } catch (error) { setJsonError(error.message); // 无效 JSON 时不回传,避免外部值把输入重置 } } else { setJsonError(''); onChange?.(''); } }, [onChange]); // 切换编辑模式 const toggleEditMode = useCallback(() => { if (editMode === 'visual') { // 从可视化模式切换到手动模式 setManualText(Object.keys(jsonData).length === 0 ? '' : JSON.stringify(jsonData, null, 2)); setEditMode('manual'); } else { // 从手动模式切换到可视化模式,需要验证JSON try { let parsed = {}; if (manualText && manualText.trim()) { parsed = JSON.parse(manualText); } else if (typeof value === 'string' && value.trim()) { parsed = JSON.parse(value); } else if (typeof value === 'object' && value !== null) { parsed = value; } setJsonData(parsed); setJsonError(''); setEditMode('visual'); } catch (error) { setJsonError(error.message); // JSON格式错误时不切换模式 return; } } }, [editMode, value, manualText, jsonData]); // 添加键值对 const addKeyValue = useCallback(() => { const newData = { ...jsonData }; const keys = Object.keys(newData); let counter = 1; let newKey = `field_${counter}`; while (newData.hasOwnProperty(newKey)) { counter += 1; newKey = `field_${counter}`; } newData[newKey] = ''; handleVisualChange(newData); }, [jsonData, handleVisualChange]); // 删除键值对 const removeKeyValue = useCallback((keyToRemove) => { const newData = { ...jsonData }; delete newData[keyToRemove]; handleVisualChange(newData); }, [jsonData, handleVisualChange]); // 更新键名 const updateKey = useCallback((oldKey, newKey) => { if (oldKey === newKey || !newKey) return; const newData = {}; Object.entries(jsonData).forEach(([k, v]) => { if (k === oldKey) { newData[newKey] = v; } else { newData[k] = v; } }); handleVisualChange(newData); }, [jsonData, handleVisualChange]); // 更新值 const updateValue = useCallback((key, newValue) => { const newData = { ...jsonData }; newData[key] = newValue; handleVisualChange(newData); }, [jsonData, handleVisualChange]); // 填入模板 const fillTemplate = useCallback(() => { if (template) { const templateString = JSON.stringify(template, null, 2); // 通过formApi设置值(如果提供的话) if (formApi && field) { formApi.setValue(field, templateString); } // 同步内部与外部值,避免出现杂字符 setManualText(templateString); setJsonData(template); onChange?.(templateString); // 清除错误状态 setJsonError(''); } }, [template, onChange, editMode, formApi, field]); // 渲染键值对编辑器 const renderKeyValueEditor = () => { if (typeof jsonData !== 'object' || jsonData === null) { return (