From 87fc681df3f1152e472f701d5335b54ee75c870e Mon Sep 17 00:00:00 2001 From: "Apple\\Apple" Date: Wed, 18 Jun 2025 01:29:35 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20feat(ui):=20isolate=20ratio=20co?= =?UTF-8?q?nfigurations=20into=20dedicated=20=E2=80=9CRatio=E2=80=9D=20tab?= =?UTF-8?q?=20and=20refactor=20settings=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary • Added new Ratio tab in Settings for managing all ratio-related configurations (group & model multipliers). • Created `RatioSetting` component to host GroupRatio, ModelRatio, Visual Editor and Unset-Models panels. • Moved ratio components to `web/src/pages/Setting/Ratio/` directory: – `GroupRatioSettings.js` – `ModelRatioSettings.js` – `ModelSettingsVisualEditor.js` – `ModelRationNotSetEditor.js` • Updated imports in `RatioSetting.js` to use the new path. • Updated main Settings router (`web/src/pages/Setting/index.js`) to include the new “Ratio Settings” tab. • Pruned `OperationSetting.js`: – Removed ratio-specific cards, tabs and unused imports. – Reduced state to only the keys required by its child components. – Deleted obsolete fields (`StreamCacheQueueLength`, `CheckSensitiveOnCompletionEnabled`, `StopOnSensitiveEnabled`). • Added boolean handling simplification in `OperationSetting.js`. • Adjusted helper import list and removed unused translation hook. Why Separating ratio-related settings improves UX clarity, reduces cognitive load in the Operation Settings panel and keeps the codebase modular and easier to maintain. BREAKING CHANGE The file paths for ratio components have changed. Any external imports referencing the old `Operation` directory must update to the new `Ratio` path. --- .../components/settings/OperationSetting.js | 104 ++++++----------- web/src/components/settings/RatioSetting.js | 109 ++++++++++++++++++ web/src/i18n/locales/en.json | 2 +- .../GroupRatioSettings.js | 6 +- .../ModelRatioSettings.js | 0 .../ModelRationNotSetEditor.js | 0 .../ModelSettingsVisualEditor.js | 0 web/src/pages/Setting/index.js | 8 +- 8 files changed, 154 insertions(+), 75 deletions(-) create mode 100644 web/src/components/settings/RatioSetting.js rename web/src/pages/Setting/{Operation => Ratio}/GroupRatioSettings.js (99%) rename web/src/pages/Setting/{Operation => Ratio}/ModelRatioSettings.js (100%) rename web/src/pages/Setting/{Operation => Ratio}/ModelRationNotSetEditor.js (100%) rename web/src/pages/Setting/{Operation => Ratio}/ModelSettingsVisualEditor.js (100%) diff --git a/web/src/components/settings/OperationSetting.js b/web/src/components/settings/OperationSetting.js index 7bd9bf62..f6786f95 100644 --- a/web/src/components/settings/OperationSetting.js +++ b/web/src/components/settings/OperationSetting.js @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Card, Spin, Tabs } from '@douyinfe/semi-ui'; +import { Card, Spin } from '@douyinfe/semi-ui'; import SettingsGeneral from '../../pages/Setting/Operation/SettingsGeneral.js'; import SettingsDrawing from '../../pages/Setting/Operation/SettingsDrawing.js'; import SettingsSensitiveWords from '../../pages/Setting/Operation/SettingsSensitiveWords.js'; @@ -7,63 +7,58 @@ import SettingsLog from '../../pages/Setting/Operation/SettingsLog.js'; import SettingsDataDashboard from '../../pages/Setting/Operation/SettingsDataDashboard.js'; import SettingsMonitoring from '../../pages/Setting/Operation/SettingsMonitoring.js'; import SettingsCreditLimit from '../../pages/Setting/Operation/SettingsCreditLimit.js'; -import ModelSettingsVisualEditor from '../../pages/Setting/Operation/ModelSettingsVisualEditor.js'; -import GroupRatioSettings from '../../pages/Setting/Operation/GroupRatioSettings.js'; -import ModelRatioSettings from '../../pages/Setting/Operation/ModelRatioSettings.js'; - -import { API, showError, showSuccess } from '../../helpers'; import SettingsChats from '../../pages/Setting/Operation/SettingsChats.js'; -import { useTranslation } from 'react-i18next'; -import ModelRatioNotSetEditor from '../../pages/Setting/Operation/ModelRationNotSetEditor.js'; +import { API, showError } from '../../helpers'; const OperationSetting = () => { - const { t } = useTranslation(); let [inputs, setInputs] = useState({ + /* 额度相关 */ QuotaForNewUser: 0, + PreConsumedQuota: 0, QuotaForInviter: 0, QuotaForInvitee: 0, - QuotaRemindThreshold: 0, - PreConsumedQuota: 0, - StreamCacheQueueLength: 0, - ModelRatio: '', - CacheRatio: '', - CompletionRatio: '', - ModelPrice: '', - GroupRatio: '', - GroupGroupRatio: '', - AutoGroups: '', - DefaultUseAutoGroup: false, - UserUsableGroups: '', + + /* 通用设置 */ TopUpLink: '', 'general_setting.docs_link': '', - // ChatLink2: '', // 添加的新状态变量 QuotaPerUnit: 0, - AutomaticDisableChannelEnabled: false, - AutomaticEnableChannelEnabled: false, - ChannelDisableThreshold: 0, - LogConsumeEnabled: false, + RetryTimes: 0, DisplayInCurrencyEnabled: false, DisplayTokenStatEnabled: false, - CheckSensitiveEnabled: false, - CheckSensitiveOnPromptEnabled: false, - CheckSensitiveOnCompletionEnabled: '', - StopOnSensitiveEnabled: '', - SensitiveWords: '', + DefaultCollapseSidebar: false, + DemoSiteEnabled: false, + SelfUseModeEnabled: false, + + /* 绘图设置 */ + DrawingEnabled: false, MjNotifyEnabled: false, MjAccountFilterEnabled: false, - MjModeClearEnabled: false, MjForwardUrlEnabled: false, + MjModeClearEnabled: false, MjActionCheckSuccessEnabled: false, - DrawingEnabled: false, + + /* 敏感词设置 */ + CheckSensitiveEnabled: false, + CheckSensitiveOnPromptEnabled: false, + SensitiveWords: '', + + /* 日志设置 */ + LogConsumeEnabled: false, + + /* 数据看板 */ DataExportEnabled: false, DataExportDefaultTime: 'hour', DataExportInterval: 5, - DefaultCollapseSidebar: false, // 默认折叠侧边栏 - RetryTimes: 0, - Chats: '[]', - DemoSiteEnabled: false, - SelfUseModeEnabled: false, + + /* 监控设置 */ + ChannelDisableThreshold: 0, + QuotaRemindThreshold: 0, + AutomaticDisableChannelEnabled: false, + AutomaticEnableChannelEnabled: false, AutomaticDisableKeywords: '', + + /* 聊天设置 */ + Chats: '[]', }); let [loading, setLoading] = useState(false); @@ -74,22 +69,9 @@ const OperationSetting = () => { if (success) { let newInputs = {}; data.forEach((item) => { - if ( - item.key === 'ModelRatio' || - item.key === 'GroupRatio' || - item.key === 'GroupGroupRatio' || - item.key === 'AutoGroups' || - item.key === 'UserUsableGroups' || - item.key === 'CompletionRatio' || - item.key === 'ModelPrice' || - item.key === 'CacheRatio' - ) { - item.value = JSON.stringify(JSON.parse(item.value), null, 2); - } if ( item.key.endsWith('Enabled') || - ['DefaultCollapseSidebar'].includes(item.key) || - ['DefaultUseAutoGroup'].includes(item.key) + ['DefaultCollapseSidebar'].includes(item.key) ) { newInputs[item.key] = item.value === 'true' ? true : false; } else { @@ -153,24 +135,6 @@ const OperationSetting = () => { - {/* 分组倍率设置 */} - - - - {/* 合并模型倍率设置和可视化倍率设置 */} - - - - - - - - - - - - - ); diff --git a/web/src/components/settings/RatioSetting.js b/web/src/components/settings/RatioSetting.js new file mode 100644 index 00000000..bf97282c --- /dev/null +++ b/web/src/components/settings/RatioSetting.js @@ -0,0 +1,109 @@ +import React, { useEffect, useState } from 'react'; +import { Card, Spin, Tabs } from '@douyinfe/semi-ui'; +import { useTranslation } from 'react-i18next'; + +import GroupRatioSettings from '../../pages/Setting/Ratio/GroupRatioSettings.js'; +import ModelRatioSettings from '../../pages/Setting/Ratio/ModelRatioSettings.js'; +import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVisualEditor.js'; +import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor.js'; + +import { API, showError } from '../../helpers'; + +const RatioSetting = () => { + const { t } = useTranslation(); + + let [inputs, setInputs] = useState({ + ModelPrice: '', + ModelRatio: '', + CacheRatio: '', + CompletionRatio: '', + GroupRatio: '', + GroupGroupRatio: '', + AutoGroups: '', + DefaultUseAutoGroup: false, + UserUsableGroups: '', + }); + + const [loading, setLoading] = useState(false); + + const getOptions = async () => { + const res = await API.get('/api/option/'); + const { success, message, data } = res.data; + if (success) { + let newInputs = {}; + data.forEach((item) => { + if ( + item.key === 'ModelRatio' || + item.key === 'GroupRatio' || + item.key === 'GroupGroupRatio' || + item.key === 'AutoGroups' || + item.key === 'UserUsableGroups' || + item.key === 'CompletionRatio' || + item.key === 'ModelPrice' || + item.key === 'CacheRatio' + ) { + try { + item.value = JSON.stringify(JSON.parse(item.value), null, 2); + } catch (e) { + // 如果后端返回的不是合法 JSON,直接展示 + } + } + if (['DefaultUseAutoGroup'].includes(item.key)) { + newInputs[item.key] = item.value === 'true' ? true : false; + } else { + newInputs[item.key] = item.value; + } + }); + setInputs(newInputs); + } else { + showError(message); + } + }; + + const onRefresh = async () => { + try { + setLoading(true); + await getOptions(); + } catch (error) { + showError('刷新失败'); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + onRefresh(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + {/* 分组倍率设置 */} + + + + {/* 模型倍率设置以及可视化编辑器 */} + + + + + + + + + + + + + + + ); +}; + +export default RatioSetting; \ No newline at end of file diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index b456fff5..fc80f9c1 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1588,7 +1588,7 @@ "性能指标": "Performance Indicators", "模型数据分析": "Model Data Analysis", "搜索无结果": "No results found", - "仪表盘配置": "Dashboard Configuration", + "仪表盘设置": "Dashboard Settings", "API信息管理,可以配置多个API地址用于状态展示和负载均衡(最多50个)": "API information management, you can configure multiple API addresses for status display and load balancing (maximum 50)", "线路描述": "Route description", "颜色": "Color", diff --git a/web/src/pages/Setting/Operation/GroupRatioSettings.js b/web/src/pages/Setting/Ratio/GroupRatioSettings.js similarity index 99% rename from web/src/pages/Setting/Operation/GroupRatioSettings.js rename to web/src/pages/Setting/Ratio/GroupRatioSettings.js index 4a51a98c..3c7c754b 100644 --- a/web/src/pages/Setting/Operation/GroupRatioSettings.js +++ b/web/src/pages/Setting/Ratio/GroupRatioSettings.js @@ -184,16 +184,16 @@ export default function GroupRatioSettings(props) { if (!value || value.trim() === '') { return true; // Allow empty values } - + // First check if it's valid JSON try { const parsed = JSON.parse(value); - + // Check if it's an array if (!Array.isArray(parsed)) { return false; } - + // Check if every element is a string return parsed.every(item => typeof item === 'string'); } catch (error) { diff --git a/web/src/pages/Setting/Operation/ModelRatioSettings.js b/web/src/pages/Setting/Ratio/ModelRatioSettings.js similarity index 100% rename from web/src/pages/Setting/Operation/ModelRatioSettings.js rename to web/src/pages/Setting/Ratio/ModelRatioSettings.js diff --git a/web/src/pages/Setting/Operation/ModelRationNotSetEditor.js b/web/src/pages/Setting/Ratio/ModelRationNotSetEditor.js similarity index 100% rename from web/src/pages/Setting/Operation/ModelRationNotSetEditor.js rename to web/src/pages/Setting/Ratio/ModelRationNotSetEditor.js diff --git a/web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js b/web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.js similarity index 100% rename from web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js rename to web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.js diff --git a/web/src/pages/Setting/index.js b/web/src/pages/Setting/index.js index dc48c8dc..5572e540 100644 --- a/web/src/pages/Setting/index.js +++ b/web/src/pages/Setting/index.js @@ -10,6 +10,7 @@ import OperationSetting from '../../components/settings/OperationSetting.js'; import RateLimitSetting from '../../components/settings/RateLimitSetting.js'; import ModelSetting from '../../components/settings/ModelSetting.js'; import DashboardSetting from '../../components/settings/DashboardSetting.js'; +import RatioSetting from '../../components/settings/RatioSetting.js'; const Setting = () => { const { t } = useTranslation(); @@ -24,6 +25,11 @@ const Setting = () => { content: , itemKey: 'operation', }); + panes.push({ + tab: t('倍率设置'), + content: , + itemKey: 'ratio', + }); panes.push({ tab: t('速率限制设置'), content: , @@ -45,7 +51,7 @@ const Setting = () => { itemKey: 'other', }); panes.push({ - tab: t('仪表盘配置'), + tab: t('仪表盘设置'), content: , itemKey: 'dashboard', });