import React, { useState, useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { Space, Button, Form, Card, Typography, Banner, Row, Col, InputNumber, Switch, Select, Input, } from '@douyinfe/semi-ui'; import { IconCode, IconEdit, IconPlus, IconDelete, IconSetting, } from '@douyinfe/semi-icons'; const { Text } = Typography; const JSONEditor = ({ value = '', onChange, field, label, placeholder, extraText, showClear = true, template, templateLabel, editorType = 'keyValue', // keyValue, object, region autosize = true, rules = [], formApi = null, ...props }) => { const { t } = useTranslation(); // 初始化JSON数据 const [jsonData, setJsonData] = useState(() => { // 初始化时解析JSON数据 if (value && value.trim()) { try { const parsed = JSON.parse(value); return parsed; } catch (error) { return {}; } } return {}; }); // 根据键数量决定默认编辑模式 const [editMode, setEditMode] = useState(() => { // 如果初始JSON数据的键数量大于10个,则默认使用手动模式 if (value && 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 { const parsed = value && value.trim() ? JSON.parse(value) : {}; setJsonData(parsed); setJsonError(''); } catch (error) { console.log('JSON解析失败:', error.message); setJsonError(error.message); // JSON格式错误时不更新jsonData } }, [value]); // 处理可视化编辑的数据变化 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]); // 处理手动编辑的数据变化 const handleManualChange = useCallback((newValue) => { onChange?.(newValue); // 验证JSON格式 if (newValue && newValue.trim()) { try { const parsed = JSON.parse(newValue); setJsonError(''); // 预先准备可视化数据,但不立即应用 // 这样切换到可视化模式时数据已经准备好了 } catch (error) { setJsonError(error.message); } } else { setJsonError(''); } }, [onChange]); // 切换编辑模式 const toggleEditMode = useCallback(() => { if (editMode === 'visual') { // 从可视化模式切换到手动模式 setEditMode('manual'); } else { // 从手动模式切换到可视化模式,需要验证JSON try { const parsed = value && value.trim() ? JSON.parse(value) : {}; setJsonData(parsed); setJsonError(''); setEditMode('visual'); } catch (error) { setJsonError(error.message); // JSON格式错误时不切换模式 return; } } }, [editMode, value]); // 添加键值对 const addKeyValue = useCallback(() => { const newData = { ...jsonData }; const keys = Object.keys(newData); let newKey = 'key'; let counter = 1; while (newData.hasOwnProperty(newKey)) { newKey = `key${counter}`; 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) return; const newData = { ...jsonData }; const value = newData[oldKey]; delete newData[oldKey]; newData[newKey] = value; 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); } // 无论哪种模式都要更新值 onChange?.(templateString); // 如果是可视化模式,同时更新jsonData if (editMode === 'visual') { setJsonData(template); } // 清除错误状态 setJsonError(''); } }, [template, onChange, editMode, formApi, field]); // 渲染键值对编辑器 const renderKeyValueEditor = () => { if (typeof jsonData !== 'object' || jsonData === null) { return (
{t('无效的JSON数据,请检查格式')}
); } const entries = Object.entries(jsonData); return (
{entries.length === 0 && (
{t('暂无数据,点击下方按钮添加键值对')}
)} {entries.map(([key, value], index) => (
{t('键名')} updateKey(key, newKey)} size="small" />
{t('值')} updateValue(key, newValue)} size="small" />
))}
); }; // 渲染对象编辑器(用于复杂JSON) const renderObjectEditor = () => { const entries = Object.entries(jsonData); return (
{entries.length === 0 && (
{t('暂无参数,点击下方按钮添加请求参数')}
)} {entries.map(([key, value], index) => (
{t('参数名')} updateKey(key, newKey)} size="small" />
{t('参数值')} ({typeof value}) {renderValueInput(key, value)}
))}
); }; // 渲染参数值输入控件 const renderValueInput = (key, value) => { const valueType = typeof value; if (valueType === 'boolean') { return (
updateValue(key, newValue)} size="small" /> {value ? t('true') : t('false')}
); } if (valueType === 'number') { return ( updateValue(key, newValue)} size="small" style={{ width: '100%' }} step={key === 'temperature' ? 0.1 : 1} precision={key === 'temperature' ? 2 : 0} placeholder={t('输入数字')} /> ); } // 字符串类型或其他类型 return ( { // 尝试转换为适当的类型 let convertedValue = newValue; if (newValue === 'true') convertedValue = true; else if (newValue === 'false') convertedValue = false; else if (!isNaN(newValue) && newValue !== '' && newValue !== '0') { convertedValue = Number(newValue); } updateValue(key, convertedValue); }} size="small" /> ); }; // 渲染区域编辑器(特殊格式) const renderRegionEditor = () => { const entries = Object.entries(jsonData); const defaultEntry = entries.find(([key]) => key === 'default'); const modelEntries = entries.filter(([key]) => key !== 'default'); return (
{/* 默认区域 */}
{t('默认区域')}
updateValue('default', value)} size="small" />
{/* 模型专用区域 */}
{t('模型专用区域')} {modelEntries.map(([modelName, region], index) => (
{t('模型名称')} updateKey(modelName, newKey)} size="small" />
{t('区域')} updateValue(modelName, newValue)} size="small" />
))}
); }; // 渲染可视化编辑器 const renderVisualEditor = () => { switch (editorType) { case 'region': return renderRegionEditor(); case 'object': return renderObjectEditor(); case 'keyValue': default: return renderKeyValueEditor(); } }; const hasJsonError = jsonError && jsonError.trim() !== ''; return (
{/* Label统一显示在上方 */} {label && (
{label}
)} {/* 编辑模式切换 */}
{editMode === 'visual' && ( {t('可视化模式')} )} {editMode === 'manual' && ( {t('手动编辑模式')} )}
{template && templateLabel && ( )}
{/* JSON错误提示 */} {hasJsonError && ( )} {/* 编辑器内容 */} {editMode === 'visual' ? (
{renderVisualEditor()} {/* 可视化模式下的额外文本显示在下方 */} {extraText && (
{extraText}
)} {/* 隐藏的Form字段用于验证和数据绑定 */}
) : ( )} {/* 额外文本在手动编辑模式下显示 */} {extraText && editMode === 'manual' && (
{extraText}
)}
); }; export default JSONEditor;