refactor: Improve responsive design across multiple setting pages

This commit is contained in:
1808837298@qq.com
2025-03-10 21:05:22 +08:00
parent 627f95b034
commit 94549f9687
15 changed files with 49 additions and 332 deletions

View File

@@ -7,7 +7,6 @@ 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 SettingsMagnification from '../pages/Setting/Operation/SettingsMagnification.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';

View File

@@ -1,16 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Card, Spin, Tabs } 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';
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 SettingsMagnification from '../pages/Setting/Operation/SettingsMagnification.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';

View File

@@ -88,7 +88,7 @@ export default function SettingClaudeModel(props) {
>
<Form.Section text={t('Claude设置')}>
<Row>
<Col span={16}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.TextArea
label={t('Claude请求头覆盖')}
field={'claude.model_headers_settings'}
@@ -108,7 +108,7 @@ export default function SettingClaudeModel(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.TextArea
label={t('缺省 MaxTokens')}
field={'claude.default_max_tokens'}
@@ -145,7 +145,7 @@ export default function SettingClaudeModel(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('思考适配 BudgetTokens 百分比')}
field={'claude.thinking_adapter_budget_tokens_percentage'}

View File

@@ -86,7 +86,7 @@ export default function SettingGeminiModel(props) {
>
<Form.Section text={t('Gemini设置')}>
<Row>
<Col span={16}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.TextArea
label={t('Gemini安全设置')}
placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_SETTING_EXAMPLE, null, 2)}
@@ -106,7 +106,7 @@ export default function SettingGeminiModel(props) {
</Col>
</Row>
<Row>
<Col span={16}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.TextArea
label={t('Gemini版本设置')}
placeholder={t('为一个 JSON 文本,例如:') + '\n' + JSON.stringify(GEMINI_VERSION_EXAMPLE, null, 2)}

View File

@@ -86,7 +86,7 @@ export default function GroupRatioSettings(props) {
>
<Form.Section text={t('分组设置')}>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('分组倍率')}
placeholder={t('为一个 JSON 文本,键为分组名称,值为倍率')}
@@ -105,7 +105,7 @@ export default function GroupRatioSettings(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('用户可选分组')}
placeholder={t('为一个 JSON 文本,键为分组名称,值为分组描述')}

View File

@@ -102,7 +102,7 @@ export default function ModelRatioSettings(props) {
>
<Form.Section>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('模型固定价格')}
extraText={t('一次调用消耗多少刀,优先级大于模型倍率')}
@@ -122,7 +122,7 @@ export default function ModelRatioSettings(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('模型倍率')}
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')}
@@ -141,7 +141,7 @@ export default function ModelRatioSettings(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('提示缓存倍率')}
placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')}
@@ -160,7 +160,7 @@ export default function ModelRatioSettings(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('模型补全倍率(仅对自定义模型有效)')}
extraText={t('仅对自定义模型有效')}

View File

@@ -76,7 +76,7 @@ export default function SettingsCreditLimit(props) {
>
<Form.Section text={t('额度设置')}>
<Row gutter={16}>
<Col span={6}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('新用户初始额度')}
field={'QuotaForNewUser'}
@@ -92,7 +92,7 @@ export default function SettingsCreditLimit(props) {
}
/>
</Col>
<Col span={6}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('请求预扣费额度')}
field={'PreConsumedQuota'}
@@ -109,7 +109,7 @@ export default function SettingsCreditLimit(props) {
}
/>
</Col>
<Col span={6}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('邀请新用户奖励额度')}
field={'QuotaForInviter'}
@@ -126,7 +126,9 @@ export default function SettingsCreditLimit(props) {
}
/>
</Col>
<Col span={6}>
</Row>
<Row>
<Col xs={24} sm={12} md={8} lg={8} xl={6}>
<Form.InputNumber
label={t('新用户使用邀请码奖励额度')}
field={'QuotaForInvitee'}

View File

@@ -86,7 +86,7 @@ export default function DataDashboard(props) {
>
<Form.Section text={t('数据看板设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DataExportEnabled'}
label={t('启用数据看板(实验性)')}
@@ -103,7 +103,7 @@ export default function DataDashboard(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('数据看板更新间隔')}
step={1}
@@ -120,7 +120,7 @@ export default function DataDashboard(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Select
label={t('数据看板默认时间粒度')}
optionList={optionsDataExportDefaultTime}

View File

@@ -80,7 +80,7 @@ export default function SettingsDrawing(props) {
>
<Form.Section text={t('绘图设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DrawingEnabled'}
label={t('启用绘图功能')}
@@ -95,7 +95,7 @@ export default function SettingsDrawing(props) {
}}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'MjNotifyEnabled'}
label={t('允许回调(会泄露服务器 IP 地址)')}
@@ -110,7 +110,7 @@ export default function SettingsDrawing(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'MjAccountFilterEnabled'}
label={t('允许 AccountFilter 参数')}
@@ -125,7 +125,7 @@ export default function SettingsDrawing(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'MjForwardUrlEnabled'}
label={t('开启之后将上游地址替换为服务器地址')}
@@ -140,7 +140,7 @@ export default function SettingsDrawing(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'MjModeClearEnabled'}
label={
@@ -160,7 +160,7 @@ export default function SettingsDrawing(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'MjActionCheckSuccessEnabled'}
label={t('检测必须等待绘图成功才能进行放大等操作')}

View File

@@ -92,7 +92,7 @@ export default function GeneralSettings(props) {
>
<Form.Section text={t('通用设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Input
field={'TopUpLink'}
label={t('充值链接')}
@@ -102,7 +102,7 @@ export default function GeneralSettings(props) {
showClear
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Input
field={'general_setting.docs_link'}
label={t('文档地址')}
@@ -112,7 +112,7 @@ export default function GeneralSettings(props) {
showClear
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Input
field={'QuotaPerUnit'}
label={t('单位美元额度')}
@@ -123,7 +123,7 @@ export default function GeneralSettings(props) {
onClick={() => setShowQuotaWarning(true)}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Input
field={'RetryTimes'}
label={t('失败重试次数')}
@@ -135,7 +135,7 @@ export default function GeneralSettings(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DisplayInCurrencyEnabled'}
label={t('以货币形式显示额度')}
@@ -150,7 +150,7 @@ export default function GeneralSettings(props) {
}}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DisplayTokenStatEnabled'}
label={t('额度查询接口返回令牌额度而非用户额度')}
@@ -165,7 +165,7 @@ export default function GeneralSettings(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DefaultCollapseSidebar'}
label={t('默认折叠侧边栏')}
@@ -182,7 +182,7 @@ export default function GeneralSettings(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'DemoSiteEnabled'}
label={t('演示站点模式')}
@@ -197,7 +197,7 @@ export default function GeneralSettings(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'SelfUseModeEnabled'}
label={t('自用模式')}

View File

@@ -100,7 +100,7 @@ export default function SettingsLog(props) {
>
<Form.Section text={t('日志设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'LogConsumeEnabled'}
label={t('启用额度消费日志记录')}
@@ -115,7 +115,7 @@ export default function SettingsLog(props) {
}}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Spin spinning={loadingCleanHistoryLog}>
<Form.DatePicker
label={t('日志记录时间')}

View File

@@ -1,273 +0,0 @@
import React, { useEffect, useState, useRef } from 'react';
import { Button, Col, Form, Popconfirm, Row, Space, Spin } from '@douyinfe/semi-ui';
import {
compareObjects,
API,
showError,
showSuccess,
showWarning,
verifyJSON,
verifyJSONPromise
} from '../../../helpers';
export default function SettingsMagnification(props) {
const [loading, setLoading] = useState(false);
const [inputs, setInputs] = useState({
ModelPrice: '',
ModelRatio: '',
CompletionRatio: '',
GroupRatio: '',
UserUsableGroups: ''
});
const refForm = useRef();
const [inputsRow, setInputsRow] = useState(inputs);
async function onSubmit() {
try {
console.log('Starting validation...');
await refForm.current.validate().then(() => {
console.log('Validation passed');
const updateArray = compareObjects(inputs, inputsRow);
if (!updateArray.length) return showWarning('你似乎并没有修改什么');
const requestQueue = updateArray.map((item) => {
let value = '';
if (typeof inputs[item.key] === 'boolean') {
value = String(inputs[item.key]);
} else {
value = inputs[item.key];
}
return API.put('/api/option/', {
key: item.key,
value
});
});
setLoading(true);
Promise.all(requestQueue)
.then((res) => {
if (requestQueue.length === 1) {
if (res.includes(undefined)) return;
} else if (requestQueue.length > 1) {
if (res.includes(undefined))
return showError('部分保存失败,请重试');
}
for (let i = 0; i < res.length; i++) {
if (!res[i].data.success) {
return showError(res[i].data.message)
}
}
showSuccess('保存成功');
props.refresh();
})
.catch(error => {
console.error('Unexpected error in Promise.all:', error);
showError('保存失败,请重试');
})
.finally(() => {
setLoading(false);
});
}).catch((error) => {
console.error('Validation failed:', error);
showError('请检查输入');
});
} catch (error) {
showError('请检查输入');
console.error(error);
}
}
async function resetModelRatio() {
try {
let res = await API.post(`/api/option/rest_model_ratio`);
// return {success, message}
if (res.data.success) {
showSuccess(res.data.message);
props.refresh();
} else {
showError(res.data.message);
}
} catch (error) {
showError(error);
}
}
useEffect(() => {
const currentInputs = {};
for (let key in props.options) {
if (Object.keys(inputs).includes(key)) {
currentInputs[key] = props.options[key];
}
}
setInputs(currentInputs);
setInputsRow(structuredClone(currentInputs));
refForm.current.setValues(currentInputs);
}, [props.options]);
return (
<Spin spinning={loading}>
<Form
values={inputs}
getFormApi={(formAPI) => (refForm.current = formAPI)}
style={{ marginBottom: 15 }}
>
<Form.Section text={'倍率设置'}>
<Row gutter={16}>
<Col span={16}>
<Form.TextArea
label={'模型固定价格'}
extraText={'一次调用消耗多少刀,优先级大于模型倍率'}
placeholder={
'为一个 JSON 文本,键为模型名称,值为一次调用消耗多少刀,比如 "gpt-4-gizmo-*": 0.1一次消耗0.1刀'
}
field={'ModelPrice'}
autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur'
stopValidateWithError
rules={[
{
validator: (rule, value) => {
return verifyJSON(value);
},
message: '不是合法的 JSON 字符串'
}
]}
onChange={(value) =>
setInputs({
...inputs,
ModelPrice: value
})
}
/>
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Form.TextArea
label={'模型倍率'}
extraText={''}
placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
field={'ModelRatio'}
autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur'
stopValidateWithError
rules={[
{
validator: (rule, value) => {
return verifyJSON(value);
},
message: '不是合法的 JSON 字符串'
}
]}
onChange={(value) =>
setInputs({
...inputs,
ModelRatio: value
})
}
/>
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Form.TextArea
label={'模型补全倍率(仅对自定义模型有效)'}
extraText={'仅对自定义模型有效'}
placeholder={'为一个 JSON 文本,键为模型名称,值为倍率'}
field={'CompletionRatio'}
autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur'
stopValidateWithError
rules={[
{
validator: (rule, value) => {
return verifyJSON(value);
},
message: '不是合法的 JSON 字符串'
}
]}
onChange={(value) =>
setInputs({
...inputs,
CompletionRatio: value
})
}
/>
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Form.TextArea
label={'分组倍率'}
extraText={''}
placeholder={'为一个 JSON 文本,键为分组名称,值为倍率'}
field={'GroupRatio'}
autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur'
stopValidateWithError
rules={[
{
validator: (rule, value) => {
return verifyJSON(value);
},
message: '不是合法的 JSON 字符串'
}
]}
onChange={(value) =>
setInputs({
...inputs,
GroupRatio: value
})
}
/>
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Form.TextArea
label={'用户可选分组'}
extraText={''}
placeholder={'为一个 JSON 文本,键为分组名称,值为倍率'}
field={'UserUsableGroups'}
autosize={{ minRows: 6, maxRows: 12 }}
trigger='blur'
stopValidateWithError
rules={[
{
validator: (rule, value) => {
return verifyJSON(value);
},
message: '不是合法的 JSON 字符串'
}
]}
onChange={(value) =>
setInputs({
...inputs,
UserUsableGroups: value
})
}
/>
</Col>
</Row>
</Form.Section>
</Form>
<Space>
<Button onClick={onSubmit}>
保存倍率设置
</Button>
<Popconfirm
title='确定重置模型倍率吗?'
content='此修改将不可逆'
okType={'danger'}
position={'top'}
onConfirm={() => {
resetModelRatio();
}}
>
<Button type={'danger'}>
重置模型倍率
</Button>
</Popconfirm>
</Space>
</Spin>
);
}

View File

@@ -78,7 +78,7 @@ export default function SettingsMonitoring(props) {
>
<Form.Section text={t('监控设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('测试所有渠道的最长响应时间')}
step={1}
@@ -95,7 +95,7 @@ export default function SettingsMonitoring(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('额度提醒阈值')}
step={1}
@@ -114,7 +114,7 @@ export default function SettingsMonitoring(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'AutomaticDisableChannelEnabled'}
label={t('失败时自动禁用通道')}
@@ -129,7 +129,7 @@ export default function SettingsMonitoring(props) {
}}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'AutomaticEnableChannelEnabled'}
label={t('成功时自动启用通道')}
@@ -146,7 +146,7 @@ export default function SettingsMonitoring(props) {
</Col>
</Row>
<Row gutter={16}>
<Col span={16}>
<Col xs={24} sm={16}>
<Form.TextArea
label={t('自动禁用关键词')}
placeholder={t('一行一个,不区分大小写')}

View File

@@ -75,7 +75,7 @@ export default function SettingsSensitiveWords(props) {
>
<Form.Section text={t('屏蔽词过滤设置')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'CheckSensitiveEnabled'}
label={t('启用屏蔽词过滤功能')}
@@ -90,7 +90,7 @@ export default function SettingsSensitiveWords(props) {
}}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'CheckSensitiveOnPromptEnabled'}
label={t('启用 Prompt 检查')}
@@ -107,7 +107,7 @@ export default function SettingsSensitiveWords(props) {
</Col>
</Row>
<Row>
<Col span={16}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.TextArea
label={t('屏蔽词列表')}
extraText={t('一行一个屏蔽词,不需要符号分割')}

View File

@@ -78,7 +78,7 @@ export default function RequestRateLimit(props) {
>
<Form.Section text={t('模型请求速率限制')}>
<Row gutter={16}>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.Switch
field={'ModelRequestRateLimitEnabled'}
label={t('启用用户模型请求速率限制(可能会影响高并发性能)')}
@@ -95,7 +95,7 @@ export default function RequestRateLimit(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('限制周期')}
step={1}
@@ -113,7 +113,7 @@ export default function RequestRateLimit(props) {
</Col>
</Row>
<Row>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('用户每周期最多请求次数')}
step={1}
@@ -129,7 +129,7 @@ export default function RequestRateLimit(props) {
}
/>
</Col>
<Col span={8}>
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Form.InputNumber
label={t('用户每周期最多请求完成次数')}
step={1}