mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-03-30 05:41:37 +00:00
* wip ionet integrate * wip ionet integrate * wip ionet integrate * ollama wip * wip * feat: ionet integration & ollama manage * fix merge conflict * wip * fix: test conn cors * wip * fix ionet * fix ionet * wip * fix model select * refactor: Remove `pkg/ionet` test files and update related Go source and web UI model deployment components. * feat: Enhance model deployment UI with styling improvements, updated text, and a new description component. * Revert "feat: Enhance model deployment UI with styling improvements, updated text, and a new description component." This reverts commit 8b75cb5bf0d1a534b339df8c033be9a6c7df7964.
427 lines
12 KiB
JavaScript
427 lines
12 KiB
JavaScript
/*
|
|
Copyright (C) 2025 QuantumNous
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
For commercial licensing, please contact support@quantumnous.com
|
|
*/
|
|
|
|
import React, { useState, useEffect, useContext } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
Card,
|
|
Form,
|
|
Button,
|
|
Switch,
|
|
Row,
|
|
Col,
|
|
Typography,
|
|
} from '@douyinfe/semi-ui';
|
|
import { API, showSuccess, showError } from '../../../helpers';
|
|
import { StatusContext } from '../../../context/Status';
|
|
|
|
const { Text } = Typography;
|
|
|
|
export default function SettingsSidebarModulesAdmin(props) {
|
|
const { t } = useTranslation();
|
|
const [loading, setLoading] = useState(false);
|
|
const [statusState, statusDispatch] = useContext(StatusContext);
|
|
|
|
// 左侧边栏模块管理状态(管理员全局控制)
|
|
const [sidebarModulesAdmin, setSidebarModulesAdmin] = useState({
|
|
chat: {
|
|
enabled: true,
|
|
playground: true,
|
|
chat: true,
|
|
},
|
|
console: {
|
|
enabled: true,
|
|
detail: true,
|
|
token: true,
|
|
log: true,
|
|
midjourney: true,
|
|
task: true,
|
|
},
|
|
personal: {
|
|
enabled: true,
|
|
topup: true,
|
|
personal: true,
|
|
},
|
|
admin: {
|
|
enabled: true,
|
|
channel: true,
|
|
models: true,
|
|
deployment: true,
|
|
redemption: true,
|
|
user: true,
|
|
setting: true,
|
|
},
|
|
});
|
|
|
|
// 处理区域级别开关变更
|
|
function handleSectionChange(sectionKey) {
|
|
return (checked) => {
|
|
const newModules = {
|
|
...sidebarModulesAdmin,
|
|
[sectionKey]: {
|
|
...sidebarModulesAdmin[sectionKey],
|
|
enabled: checked,
|
|
},
|
|
};
|
|
setSidebarModulesAdmin(newModules);
|
|
};
|
|
}
|
|
|
|
// 处理功能级别开关变更
|
|
function handleModuleChange(sectionKey, moduleKey) {
|
|
return (checked) => {
|
|
const newModules = {
|
|
...sidebarModulesAdmin,
|
|
[sectionKey]: {
|
|
...sidebarModulesAdmin[sectionKey],
|
|
[moduleKey]: checked,
|
|
},
|
|
};
|
|
setSidebarModulesAdmin(newModules);
|
|
};
|
|
}
|
|
|
|
// 重置为默认配置
|
|
function resetSidebarModules() {
|
|
const defaultModules = {
|
|
chat: {
|
|
enabled: true,
|
|
playground: true,
|
|
chat: true,
|
|
},
|
|
console: {
|
|
enabled: true,
|
|
detail: true,
|
|
token: true,
|
|
log: true,
|
|
midjourney: true,
|
|
task: true,
|
|
},
|
|
personal: {
|
|
enabled: true,
|
|
topup: true,
|
|
personal: true,
|
|
},
|
|
admin: {
|
|
enabled: true,
|
|
channel: true,
|
|
models: true,
|
|
deployment: true,
|
|
redemption: true,
|
|
user: true,
|
|
setting: true,
|
|
},
|
|
};
|
|
setSidebarModulesAdmin(defaultModules);
|
|
showSuccess(t('已重置为默认配置'));
|
|
}
|
|
|
|
// 保存配置
|
|
async function onSubmit() {
|
|
setLoading(true);
|
|
try {
|
|
const res = await API.put('/api/option/', {
|
|
key: 'SidebarModulesAdmin',
|
|
value: JSON.stringify(sidebarModulesAdmin),
|
|
});
|
|
const { success, message } = res.data;
|
|
if (success) {
|
|
showSuccess(t('保存成功'));
|
|
|
|
// 立即更新StatusContext中的状态
|
|
statusDispatch({
|
|
type: 'set',
|
|
payload: {
|
|
...statusState.status,
|
|
SidebarModulesAdmin: JSON.stringify(sidebarModulesAdmin),
|
|
},
|
|
});
|
|
|
|
// 刷新父组件状态
|
|
if (props.refresh) {
|
|
await props.refresh();
|
|
}
|
|
} else {
|
|
showError(message);
|
|
}
|
|
} catch (error) {
|
|
showError(t('保存失败,请重试'));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
// 从 props.options 中获取配置
|
|
if (props.options && props.options.SidebarModulesAdmin) {
|
|
try {
|
|
const modules = JSON.parse(props.options.SidebarModulesAdmin);
|
|
setSidebarModulesAdmin(modules);
|
|
} catch (error) {
|
|
// 使用默认配置
|
|
const defaultModules = {
|
|
chat: { enabled: true, playground: true, chat: true },
|
|
console: {
|
|
enabled: true,
|
|
detail: true,
|
|
token: true,
|
|
log: true,
|
|
midjourney: true,
|
|
task: true,
|
|
},
|
|
personal: { enabled: true, topup: true, personal: true },
|
|
admin: {
|
|
enabled: true,
|
|
channel: true,
|
|
models: true,
|
|
deployment: true,
|
|
redemption: true,
|
|
user: true,
|
|
setting: true,
|
|
},
|
|
};
|
|
setSidebarModulesAdmin(defaultModules);
|
|
}
|
|
}
|
|
}, [props.options]);
|
|
|
|
// 区域配置数据
|
|
const sectionConfigs = [
|
|
{
|
|
key: 'chat',
|
|
title: t('聊天区域'),
|
|
description: t('操练场和聊天功能'),
|
|
modules: [
|
|
{
|
|
key: 'playground',
|
|
title: t('操练场'),
|
|
description: t('AI模型测试环境'),
|
|
},
|
|
{ key: 'chat', title: t('聊天'), description: t('聊天会话管理') },
|
|
],
|
|
},
|
|
{
|
|
key: 'console',
|
|
title: t('控制台区域'),
|
|
description: t('数据管理和日志查看'),
|
|
modules: [
|
|
{ key: 'detail', title: t('数据看板'), description: t('系统数据统计') },
|
|
{ key: 'token', title: t('令牌管理'), description: t('API令牌管理') },
|
|
{ key: 'log', title: t('使用日志'), description: t('API使用记录') },
|
|
{
|
|
key: 'midjourney',
|
|
title: t('绘图日志'),
|
|
description: t('绘图任务记录'),
|
|
},
|
|
{ key: 'task', title: t('任务日志'), description: t('系统任务记录') },
|
|
],
|
|
},
|
|
{
|
|
key: 'personal',
|
|
title: t('个人中心区域'),
|
|
description: t('用户个人功能'),
|
|
modules: [
|
|
{ key: 'topup', title: t('钱包管理'), description: t('余额充值管理') },
|
|
{
|
|
key: 'personal',
|
|
title: t('个人设置'),
|
|
description: t('个人信息设置'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
key: 'admin',
|
|
title: t('管理员区域'),
|
|
description: t('系统管理功能'),
|
|
modules: [
|
|
{ key: 'channel', title: t('渠道管理'), description: t('API渠道配置') },
|
|
{ key: 'models', title: t('模型管理'), description: t('AI模型配置') },
|
|
{ key: 'deployment', title: t('模型部署'), description: t('模型部署管理') },
|
|
{
|
|
key: 'redemption',
|
|
title: t('兑换码管理'),
|
|
description: t('兑换码生成管理'),
|
|
},
|
|
{ key: 'user', title: t('用户管理'), description: t('用户账户管理') },
|
|
{
|
|
key: 'setting',
|
|
title: t('系统设置'),
|
|
description: t('系统参数配置'),
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Card>
|
|
<Form.Section
|
|
text={t('侧边栏管理(全局控制)')}
|
|
extraText={t(
|
|
'全局控制侧边栏区域和功能显示,管理员隐藏的功能用户无法启用',
|
|
)}
|
|
>
|
|
{sectionConfigs.map((section) => (
|
|
<div key={section.key} style={{ marginBottom: '32px' }}>
|
|
{/* 区域标题和总开关 */}
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: '16px',
|
|
padding: '12px 16px',
|
|
backgroundColor: 'var(--semi-color-fill-0)',
|
|
borderRadius: '8px',
|
|
border: '1px solid var(--semi-color-border)',
|
|
}}
|
|
>
|
|
<div>
|
|
<div
|
|
style={{
|
|
fontWeight: '600',
|
|
fontSize: '16px',
|
|
color: 'var(--semi-color-text-0)',
|
|
marginBottom: '4px',
|
|
}}
|
|
>
|
|
{section.title}
|
|
</div>
|
|
<Text
|
|
type='secondary'
|
|
size='small'
|
|
style={{
|
|
fontSize: '12px',
|
|
color: 'var(--semi-color-text-2)',
|
|
lineHeight: '1.4',
|
|
}}
|
|
>
|
|
{section.description}
|
|
</Text>
|
|
</div>
|
|
<Switch
|
|
checked={sidebarModulesAdmin[section.key]?.enabled}
|
|
onChange={handleSectionChange(section.key)}
|
|
size='default'
|
|
/>
|
|
</div>
|
|
|
|
{/* 功能模块网格 */}
|
|
<Row gutter={[16, 16]}>
|
|
{section.modules.map((module) => (
|
|
<Col key={module.key} xs={24} sm={12} md={8} lg={6} xl={6}>
|
|
<Card
|
|
bodyStyle={{ padding: '16px' }}
|
|
hoverable
|
|
style={{
|
|
opacity: sidebarModulesAdmin[section.key]?.enabled
|
|
? 1
|
|
: 0.5,
|
|
transition: 'opacity 0.2s',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
height: '100%',
|
|
}}
|
|
>
|
|
<div style={{ flex: 1, textAlign: 'left' }}>
|
|
<div
|
|
style={{
|
|
fontWeight: '600',
|
|
fontSize: '14px',
|
|
color: 'var(--semi-color-text-0)',
|
|
marginBottom: '4px',
|
|
}}
|
|
>
|
|
{module.title}
|
|
</div>
|
|
<Text
|
|
type='secondary'
|
|
size='small'
|
|
style={{
|
|
fontSize: '12px',
|
|
color: 'var(--semi-color-text-2)',
|
|
lineHeight: '1.4',
|
|
display: 'block',
|
|
}}
|
|
>
|
|
{module.description}
|
|
</Text>
|
|
</div>
|
|
<div style={{ marginLeft: '16px' }}>
|
|
<Switch
|
|
checked={
|
|
sidebarModulesAdmin[section.key]?.[module.key]
|
|
}
|
|
onChange={handleModuleChange(section.key, module.key)}
|
|
size='default'
|
|
disabled={!sidebarModulesAdmin[section.key]?.enabled}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
))}
|
|
</Row>
|
|
</div>
|
|
))}
|
|
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
gap: '12px',
|
|
justifyContent: 'flex-start',
|
|
alignItems: 'center',
|
|
paddingTop: '8px',
|
|
borderTop: '1px solid var(--semi-color-border)',
|
|
}}
|
|
>
|
|
<Button
|
|
size='default'
|
|
type='tertiary'
|
|
onClick={resetSidebarModules}
|
|
style={{
|
|
borderRadius: '6px',
|
|
fontWeight: '500',
|
|
}}
|
|
>
|
|
{t('重置为默认')}
|
|
</Button>
|
|
<Button
|
|
size='default'
|
|
type='primary'
|
|
onClick={onSubmit}
|
|
loading={loading}
|
|
style={{
|
|
borderRadius: '6px',
|
|
fontWeight: '500',
|
|
minWidth: '100px',
|
|
}}
|
|
>
|
|
{t('保存设置')}
|
|
</Button>
|
|
</div>
|
|
</Form.Section>
|
|
</Card>
|
|
);
|
|
}
|