new-api / web /src /pages /Setting /Operation /SettingsHeaderNavModules.jsx
liuzhao521
Deploy New API v0.9.25+ (commit b47cf4ef) to HuggingFace Spaces
4674012
/*
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, { useEffect, useState, useContext } from 'react';
import {
Button,
Card,
Col,
Form,
Row,
Switch,
Typography,
} from '@douyinfe/semi-ui';
import { API, showError, showSuccess } from '../../../helpers';
import { useTranslation } from 'react-i18next';
import { StatusContext } from '../../../context/Status';
const { Text } = Typography;
export default function SettingsHeaderNavModules(props) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [statusState, statusDispatch] = useContext(StatusContext);
// 顶栏模块管理状态
const [headerNavModules, setHeaderNavModules] = useState({
home: true,
console: true,
pricing: {
enabled: true,
requireAuth: false, // 默认不需要登录鉴权
},
docs: true,
about: true,
});
// 处理顶栏模块配置变更
function handleHeaderNavModuleChange(moduleKey) {
return (checked) => {
const newModules = { ...headerNavModules };
if (moduleKey === 'pricing') {
// 对于pricing模块,只更新enabled属性
newModules[moduleKey] = {
...newModules[moduleKey],
enabled: checked,
};
} else {
newModules[moduleKey] = checked;
}
setHeaderNavModules(newModules);
};
}
// 处理模型广场权限控制变更
function handlePricingAuthChange(checked) {
const newModules = { ...headerNavModules };
newModules.pricing = {
...newModules.pricing,
requireAuth: checked,
};
setHeaderNavModules(newModules);
}
// 重置顶栏模块为默认配置
function resetHeaderNavModules() {
const defaultModules = {
home: true,
console: true,
pricing: {
enabled: true,
requireAuth: false,
},
docs: true,
about: true,
};
setHeaderNavModules(defaultModules);
showSuccess(t('已重置为默认配置'));
}
// 保存配置
async function onSubmit() {
setLoading(true);
try {
const res = await API.put('/api/option/', {
key: 'HeaderNavModules',
value: JSON.stringify(headerNavModules),
});
const { success, message } = res.data;
if (success) {
showSuccess(t('保存成功'));
// 立即更新StatusContext中的状态
statusDispatch({
type: 'set',
payload: {
...statusState.status,
HeaderNavModules: JSON.stringify(headerNavModules),
},
});
// 刷新父组件状态
if (props.refresh) {
await props.refresh();
}
} else {
showError(message);
}
} catch (error) {
showError(t('保存失败,请重试'));
} finally {
setLoading(false);
}
}
useEffect(() => {
// 从 props.options 中获取配置
if (props.options && props.options.HeaderNavModules) {
try {
const modules = JSON.parse(props.options.HeaderNavModules);
// 处理向后兼容性:如果pricing是boolean,转换为对象格式
if (typeof modules.pricing === 'boolean') {
modules.pricing = {
enabled: modules.pricing,
requireAuth: false, // 默认不需要登录鉴权
};
}
setHeaderNavModules(modules);
} catch (error) {
// 使用默认配置
const defaultModules = {
home: true,
console: true,
pricing: {
enabled: true,
requireAuth: false,
},
docs: true,
about: true,
};
setHeaderNavModules(defaultModules);
}
}
}, [props.options]);
// 模块配置数据
const moduleConfigs = [
{
key: 'home',
title: t('首页'),
description: t('用户主页,展示系统信息'),
},
{
key: 'console',
title: t('控制台'),
description: t('用户控制面板,管理账户'),
},
{
key: 'pricing',
title: t('模型广场'),
description: t('模型定价,需要登录访问'),
hasSubConfig: true, // 标识该模块有子配置
},
{
key: 'docs',
title: t('文档'),
description: t('系统文档和帮助信息'),
},
{
key: 'about',
title: t('关于'),
description: t('关于系统的详细信息'),
},
];
return (
<Card>
<Form.Section
text={t('顶栏管理')}
extraText={t('控制顶栏模块显示状态全局生效')}
>
<Row gutter={[16, 16]} style={{ marginBottom: '24px' }}>
{moduleConfigs.map((module) => (
<Col key={module.key} xs={24} sm={12} md={6} lg={6} xl={6}>
<Card
style={{
borderRadius: '8px',
border: '1px solid var(--semi-color-border)',
transition: 'all 0.2s ease',
background: 'var(--semi-color-bg-1)',
minHeight: '80px',
}}
bodyStyle={{ padding: '16px' }}
hoverable
>
<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={
module.key === 'pricing'
? headerNavModules[module.key]?.enabled
: headerNavModules[module.key]
}
onChange={handleHeaderNavModuleChange(module.key)}
size='default'
/>
</div>
</div>
{/* 为模型广场添加权限控制子开关 */}
{module.key === 'pricing' &&
(module.key === 'pricing'
? headerNavModules[module.key]?.enabled
: headerNavModules[module.key]) && (
<div
style={{
borderTop: '1px solid var(--semi-color-border)',
marginTop: '12px',
paddingTop: '12px',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div style={{ flex: 1, textAlign: 'left' }}>
<div
style={{
fontWeight: '500',
fontSize: '12px',
color: 'var(--semi-color-text-1)',
marginBottom: '2px',
}}
>
{t('需要登录访问')}
</div>
<Text
type='secondary'
size='small'
style={{
fontSize: '11px',
color: 'var(--semi-color-text-2)',
lineHeight: '1.4',
display: 'block',
}}
>
{t('开启后未登录用户无法访问模型广场')}
</Text>
</div>
<div style={{ marginLeft: '16px' }}>
<Switch
checked={
headerNavModules.pricing?.requireAuth || false
}
onChange={handlePricingAuthChange}
size='default'
/>
</div>
</div>
</div>
)}
</Card>
</Col>
))}
</Row>
<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={resetHeaderNavModules}
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>
);
}