|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
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, |
|
|
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('保存成功')); |
|
|
|
|
|
|
|
|
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(() => { |
|
|
|
|
|
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, |
|
|
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: '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> |
|
|
); |
|
|
} |
|
|
|