| import React from 'react'; | |
| import { | |
| Card, | |
| Select, | |
| Typography, | |
| Button, | |
| Switch, | |
| } from '@douyinfe/semi-ui'; | |
| import { | |
| Sparkles, | |
| Users, | |
| ToggleLeft, | |
| X, | |
| Settings, | |
| } from 'lucide-react'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { renderGroupOption } from '../../helpers'; | |
| import ParameterControl from './ParameterControl'; | |
| import ImageUrlInput from './ImageUrlInput'; | |
| import ConfigManager from './ConfigManager'; | |
| import CustomRequestEditor from './CustomRequestEditor'; | |
| const SettingsPanel = ({ | |
| inputs, | |
| parameterEnabled, | |
| models, | |
| groups, | |
| styleState, | |
| showDebugPanel, | |
| customRequestMode, | |
| customRequestBody, | |
| onInputChange, | |
| onParameterToggle, | |
| onCloseSettings, | |
| onConfigImport, | |
| onConfigReset, | |
| onCustomRequestModeChange, | |
| onCustomRequestBodyChange, | |
| previewPayload, | |
| messages, | |
| }) => { | |
| const { t } = useTranslation(); | |
| const currentConfig = { | |
| inputs, | |
| parameterEnabled, | |
| showDebugPanel, | |
| customRequestMode, | |
| customRequestBody, | |
| }; | |
| return ( | |
| <Card | |
| className="h-full flex flex-col" | |
| bordered={false} | |
| bodyStyle={{ | |
| padding: styleState.isMobile ? '16px' : '24px', | |
| height: '100%', | |
| display: 'flex', | |
| flexDirection: 'column' | |
| }} | |
| > | |
| {/* 标题区域 - 与调试面板保持一致 */} | |
| <div className="flex items-center justify-between mb-6 flex-shrink-0"> | |
| <div className="flex items-center"> | |
| <div className="w-10 h-10 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 flex items-center justify-center mr-3"> | |
| <Settings size={20} className="text-white" /> | |
| </div> | |
| <Typography.Title heading={5} className="mb-0"> | |
| {t('模型配置')} | |
| </Typography.Title> | |
| </div> | |
| {styleState.isMobile && onCloseSettings && ( | |
| <Button | |
| icon={<X size={16} />} | |
| onClick={onCloseSettings} | |
| theme="borderless" | |
| type="tertiary" | |
| size="small" | |
| className="!rounded-lg" | |
| /> | |
| )} | |
| </div> | |
| {/* 移动端配置管理 */} | |
| {styleState.isMobile && ( | |
| <div className="mb-4 flex-shrink-0"> | |
| <ConfigManager | |
| currentConfig={currentConfig} | |
| onConfigImport={onConfigImport} | |
| onConfigReset={onConfigReset} | |
| styleState={{ ...styleState, isMobile: false }} | |
| messages={messages} | |
| /> | |
| </div> | |
| )} | |
| <div className="space-y-6 overflow-y-auto flex-1 pr-2 model-settings-scroll"> | |
| {/* 自定义请求体编辑器 */} | |
| <CustomRequestEditor | |
| customRequestMode={customRequestMode} | |
| customRequestBody={customRequestBody} | |
| onCustomRequestModeChange={onCustomRequestModeChange} | |
| onCustomRequestBodyChange={onCustomRequestBodyChange} | |
| defaultPayload={previewPayload} | |
| /> | |
| {/* 分组选择 */} | |
| <div className={customRequestMode ? 'opacity-50' : ''}> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <Users size={16} className="text-gray-500" /> | |
| <Typography.Text strong className="text-sm"> | |
| {t('分组')} | |
| </Typography.Text> | |
| {customRequestMode && ( | |
| <Typography.Text className="text-xs text-orange-600"> | |
| (已在自定义模式中忽略) | |
| </Typography.Text> | |
| )} | |
| </div> | |
| <Select | |
| placeholder={t('请选择分组')} | |
| name='group' | |
| required | |
| selection | |
| onChange={(value) => onInputChange('group', value)} | |
| value={inputs.group} | |
| autoComplete='new-password' | |
| optionList={groups} | |
| renderOptionItem={renderGroupOption} | |
| style={{ width: '100%' }} | |
| dropdownStyle={{ width: '100%', maxWidth: '100%' }} | |
| className="!rounded-lg" | |
| disabled={customRequestMode} | |
| /> | |
| </div> | |
| {/* 模型选择 */} | |
| <div className={customRequestMode ? 'opacity-50' : ''}> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <Sparkles size={16} className="text-gray-500" /> | |
| <Typography.Text strong className="text-sm"> | |
| {t('模型')} | |
| </Typography.Text> | |
| {customRequestMode && ( | |
| <Typography.Text className="text-xs text-orange-600"> | |
| (已在自定义模式中忽略) | |
| </Typography.Text> | |
| )} | |
| </div> | |
| <Select | |
| placeholder={t('请选择模型')} | |
| name='model' | |
| required | |
| selection | |
| searchPosition='dropdown' | |
| filter | |
| onChange={(value) => onInputChange('model', value)} | |
| value={inputs.model} | |
| autoComplete='new-password' | |
| optionList={models} | |
| style={{ width: '100%' }} | |
| dropdownStyle={{ width: '100%', maxWidth: '100%' }} | |
| className="!rounded-lg" | |
| disabled={customRequestMode} | |
| /> | |
| </div> | |
| {/* 图片URL输入 */} | |
| <div className={customRequestMode ? 'opacity-50' : ''}> | |
| <ImageUrlInput | |
| imageUrls={inputs.imageUrls} | |
| imageEnabled={inputs.imageEnabled} | |
| onImageUrlsChange={(urls) => onInputChange('imageUrls', urls)} | |
| onImageEnabledChange={(enabled) => onInputChange('imageEnabled', enabled)} | |
| disabled={customRequestMode} | |
| /> | |
| </div> | |
| {/* 参数控制组件 */} | |
| <div className={customRequestMode ? 'opacity-50' : ''}> | |
| <ParameterControl | |
| inputs={inputs} | |
| parameterEnabled={parameterEnabled} | |
| onInputChange={onInputChange} | |
| onParameterToggle={onParameterToggle} | |
| disabled={customRequestMode} | |
| /> | |
| </div> | |
| {/* 流式输出开关 */} | |
| <div className={customRequestMode ? 'opacity-50' : ''}> | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center gap-2"> | |
| <ToggleLeft size={16} className="text-gray-500" /> | |
| <Typography.Text strong className="text-sm"> | |
| 流式输出 | |
| </Typography.Text> | |
| {customRequestMode && ( | |
| <Typography.Text className="text-xs text-orange-600"> | |
| (已在自定义模式中忽略) | |
| </Typography.Text> | |
| )} | |
| </div> | |
| <Switch | |
| checked={inputs.stream} | |
| onChange={(checked) => onInputChange('stream', checked)} | |
| checkedText="开" | |
| uncheckedText="关" | |
| size="small" | |
| disabled={customRequestMode} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| {/* 桌面端的配置管理放在底部 */} | |
| {!styleState.isMobile && ( | |
| <div className="flex-shrink-0 pt-3"> | |
| <ConfigManager | |
| currentConfig={currentConfig} | |
| onConfigImport={onConfigImport} | |
| onConfigReset={onConfigReset} | |
| styleState={styleState} | |
| messages={messages} | |
| /> | |
| </div> | |
| )} | |
| </Card> | |
| ); | |
| }; | |
| export default SettingsPanel; |