diff --git a/web/src/pages/Setting/Chat/SettingsChats.jsx b/web/src/pages/Setting/Chat/SettingsChats.jsx index dec27bea..368a66f5 100644 --- a/web/src/pages/Setting/Chat/SettingsChats.jsx +++ b/web/src/pages/Setting/Chat/SettingsChats.jsx @@ -18,7 +18,25 @@ For commercial licensing, please contact support@quantumnous.com */ import React, { useEffect, useState, useRef } from 'react'; -import { Banner, Button, Form, Space, Spin } from '@douyinfe/semi-ui'; +import { + Banner, + Button, + Form, + Space, + Spin, + RadioGroup, + Radio, + Table, + Modal, + Input, + Divider, +} from '@douyinfe/semi-ui'; +import { + IconPlus, + IconEdit, + IconDelete, + IconSearch, +} from '@douyinfe/semi-icons'; import { compareObjects, API, @@ -37,6 +55,52 @@ export default function SettingsChats(props) { }); const refForm = useRef(); const [inputsRow, setInputsRow] = useState(inputs); + const [editMode, setEditMode] = useState('json'); + const [chatConfigs, setChatConfigs] = useState([]); + const [modalVisible, setModalVisible] = useState(false); + const [editingConfig, setEditingConfig] = useState(null); + const [isEdit, setIsEdit] = useState(false); + const [searchText, setSearchText] = useState(''); + const modalFormRef = useRef(); + + const jsonToConfigs = (jsonString) => { + try { + const configs = JSON.parse(jsonString); + return Array.isArray(configs) + ? configs.map((config, index) => ({ + id: index, + name: Object.keys(config)[0] || '', + url: Object.values(config)[0] || '', + })) + : []; + } catch (error) { + console.error('JSON parse error:', error); + return []; + } + }; + + const configsToJson = (configs) => { + const jsonArray = configs.map((config) => ({ + [config.name]: config.url, + })); + return JSON.stringify(jsonArray, null, 2); + }; + + const syncJsonToConfigs = () => { + const configs = jsonToConfigs(inputs.Chats); + setChatConfigs(configs); + }; + + const syncConfigsToJson = (configs) => { + const jsonString = configsToJson(configs); + setInputs((prev) => ({ + ...prev, + Chats: jsonString, + })); + if (refForm.current && editMode === 'json') { + refForm.current.setValues({ Chats: jsonString }); + } + }; async function onSubmit() { try { @@ -104,15 +168,145 @@ export default function SettingsChats(props) { setInputs(currentInputs); setInputsRow(structuredClone(currentInputs)); refForm.current.setValues(currentInputs); + + // 同步到可视化配置 + const configs = jsonToConfigs(currentInputs.Chats || '[]'); + setChatConfigs(configs); }, [props.options]); + useEffect(() => { + if (editMode === 'visual') { + syncJsonToConfigs(); + } + }, [inputs.Chats, editMode]); + + useEffect(() => { + if (refForm.current && editMode === 'json') { + refForm.current.setValues(inputs); + } + }, [editMode, inputs]); + + const handleAddConfig = () => { + setEditingConfig({ name: '', url: '' }); + setIsEdit(false); + setModalVisible(true); + setTimeout(() => { + if (modalFormRef.current) { + modalFormRef.current.setValues({ name: '', url: '' }); + } + }, 100); + }; + + const handleEditConfig = (config) => { + setEditingConfig({ ...config }); + setIsEdit(true); + setModalVisible(true); + setTimeout(() => { + if (modalFormRef.current) { + modalFormRef.current.setValues(config); + } + }, 100); + }; + + const handleDeleteConfig = (id) => { + const newConfigs = chatConfigs.filter((config) => config.id !== id); + setChatConfigs(newConfigs); + syncConfigsToJson(newConfigs); + showSuccess(t('删除成功')); + }; + + const handleModalOk = () => { + if (modalFormRef.current) { + modalFormRef.current + .validate() + .then((values) => { + if (isEdit) { + const newConfigs = chatConfigs.map((config) => + config.id === editingConfig.id + ? { ...editingConfig, name: values.name, url: values.url } + : config, + ); + setChatConfigs(newConfigs); + syncConfigsToJson(newConfigs); + } else { + const maxId = + chatConfigs.length > 0 + ? Math.max(...chatConfigs.map((c) => c.id)) + : -1; + const newConfig = { + id: maxId + 1, + name: values.name, + url: values.url, + }; + const newConfigs = [...chatConfigs, newConfig]; + setChatConfigs(newConfigs); + syncConfigsToJson(newConfigs); + } + setModalVisible(false); + setEditingConfig(null); + showSuccess(isEdit ? t('编辑成功') : t('添加成功')); + }) + .catch((error) => { + console.error('Modal form validation error:', error); + }); + } + }; + + const handleModalCancel = () => { + setModalVisible(false); + setEditingConfig(null); + }; + + const filteredConfigs = chatConfigs.filter( + (config) => + !searchText || + config.name.toLowerCase().includes(searchText.toLowerCase()), + ); + + const columns = [ + { + title: t('聊天应用名称'), + dataIndex: 'name', + key: 'name', + render: (text) => text || t('未命名'), + }, + { + title: t('URL链接'), + dataIndex: 'url', + key: 'url', + render: (text) => ( +