/*
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 .
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: {
enabled: true,
blurPricing: false,
showCostPrice: false,
},
pricing: {
enabled: true,
requireAuth: false,
blurPricing: false,
},
console: true,
benchmark: true,
docs: true,
});
const [showThemeToggle, setShowThemeToggle] = useState(true);
const [showLanguageSelector, setShowLanguageSelector] = useState(true);
// 处理顶栏模块配置变更
function handleHeaderNavModuleChange(moduleKey) {
return (checked) => {
const newModules = { ...headerNavModules };
if (moduleKey === 'pricing' || moduleKey === 'home') {
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 handleShowCostPriceChange(checked) {
const newModules = { ...headerNavModules };
newModules.home = {
...newModules.home,
showCostPrice: checked,
};
setHeaderNavModules(newModules);
(async () => {
try {
const res = await API.put('/api/option/', {
key: 'HeaderNavModules',
value: JSON.stringify(newModules),
});
const { success, message } = res.data;
if (success) {
showSuccess(t('保存成功'));
statusDispatch({
type: 'set',
payload: {
...statusState.status,
HeaderNavModules: JSON.stringify(newModules),
},
});
if (props.refresh) {
await props.refresh();
}
} else {
showError(message);
newModules.home = {
...newModules.home,
showCostPrice: !checked,
};
setHeaderNavModules(newModules);
}
} catch {
showError(t('保存失败,请重试'));
newModules.home = {
...newModules.home,
showCostPrice: !checked,
};
setHeaderNavModules(newModules);
}
})();
}
// 处理主题切换开关变更(即时保存)
async function handleShowThemeToggleChange(checked) {
setShowThemeToggle(checked);
const key = 'HeaderShowThemeToggle';
const value = String(checked);
try {
const res = await API.put('/api/option/', { key, value });
if (res.data.success) {
showSuccess(t('保存成功'));
statusDispatch({
type: 'set',
payload: { ...statusState.status, [key]: value },
});
} else {
showError(res.data.message);
setShowThemeToggle(!checked);
}
} catch {
showError(t('保存失败,请重试'));
setShowThemeToggle(!checked);
}
}
// 处理语言选择器开关变更(即时保存)
async function handleShowLanguageSelectorChange(checked) {
setShowLanguageSelector(checked);
const key = 'HeaderShowLanguageSelector';
const value = String(checked);
try {
const res = await API.put('/api/option/', { key, value });
if (res.data.success) {
showSuccess(t('保存成功'));
statusDispatch({
type: 'set',
payload: { ...statusState.status, [key]: value },
});
} else {
showError(res.data.message);
setShowLanguageSelector(!checked);
}
} catch {
showError(t('保存失败,请重试'));
setShowLanguageSelector(!checked);
}
}
// 处理模糊价格开关变更(即时保存)
function handleBlurPricingChange(moduleKey) {
return async (checked) => {
const newModules = { ...headerNavModules };
newModules[moduleKey] = {
...newModules[moduleKey],
blurPricing: checked,
};
setHeaderNavModules(newModules);
try {
const res = await API.put('/api/option/', {
key: 'HeaderNavModules',
value: JSON.stringify(newModules),
});
const { success, message } = res.data;
if (success) {
showSuccess(t('保存成功'));
statusDispatch({
type: 'set',
payload: {
...statusState.status,
HeaderNavModules: JSON.stringify(newModules),
},
});
if (props.refresh) {
await props.refresh();
}
} else {
showError(message);
newModules[moduleKey] = { ...newModules[moduleKey], blurPricing: !checked };
setHeaderNavModules(newModules);
}
} catch {
showError(t('保存失败,请重试'));
newModules[moduleKey] = { ...newModules[moduleKey], blurPricing: !checked };
setHeaderNavModules(newModules);
}
};
}
// 重置顶栏模块为默认配置
function resetHeaderNavModules() {
const defaultModules = {
home: {
enabled: true,
blurPricing: false,
showCostPrice: false,
},
pricing: {
enabled: true,
requireAuth: false,
blurPricing: false,
},
console: true,
benchmark: true,
docs: 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) {
const themeVal = props.options.HeaderShowThemeToggle;
if (themeVal !== undefined && themeVal !== null) {
setShowThemeToggle(themeVal === 'true' || themeVal === true);
}
const langVal = props.options.HeaderShowLanguageSelector;
if (langVal !== undefined && langVal !== null) {
setShowLanguageSelector(langVal === 'true' || langVal === true);
}
}
// 从 props.options 中获取配置
if (props.options && props.options.HeaderNavModules) {
try {
const modules = JSON.parse(props.options.HeaderNavModules);
// 处理向后兼容性:如果home是boolean,转换为对象格式
if (typeof modules.home === 'boolean') {
modules.home = {
enabled: modules.home,
blurPricing: false,
showCostPrice: false,
};
}
// 处理向后兼容性:如果pricing是boolean,转换为对象格式
if (typeof modules.pricing === 'boolean') {
modules.pricing = {
enabled: modules.pricing,
requireAuth: false,
blurPricing: false,
};
}
// 确保 blurPricing 字段存在
if (typeof modules.home === 'object' && modules.home.blurPricing === undefined) {
modules.home.blurPricing = false;
}
if (typeof modules.home === 'object' && modules.home.showCostPrice === undefined) {
modules.home.showCostPrice = false;
}
if (typeof modules.pricing === 'object' && modules.pricing.blurPricing === undefined) {
modules.pricing.blurPricing = false;
}
setHeaderNavModules(modules);
} catch (error) {
// 使用默认配置
const defaultModules = {
home: {
enabled: true,
blurPricing: false,
showCostPrice: false,
},
pricing: {
enabled: true,
requireAuth: false,
blurPricing: false,
},
console: true,
benchmark: true,
docs: true,
};
setHeaderNavModules(defaultModules);
}
}
}, [props.options]);
// 获取模块是否启用
function getModuleEnabled(moduleKey) {
const val = headerNavModules[moduleKey];
if (typeof val === 'object' && val !== null) {
return val.enabled;
}
return !!val;
}
// 模块配置数据
const moduleConfigs = [
{
key: 'home',
title: t('首页'),
description: t('用户主页,展示系统信息'),
hasBlurPricing: true,
hasCostPrice: true,
},
{
key: 'pricing',
title: t('模型'),
description: t('模型定价,需要登录访问'),
hasSubConfig: true,
hasBlurPricing: true,
},
{
key: 'console',
title: t('控制台'),
description: t('用户控制面板,管理账户'),
},
{
key: 'benchmark',
title: t('评测'),
description: t('AI 模型评测与排行'),
},
{
key: 'docs',
title: t('文档'),
description: t('系统文档和帮助信息'),
},
];
return (
{moduleConfigs.map((module) => (
{module.title}
{module.description}
{/* 为模型广场添加权限控制子开关 */}
{module.key === 'pricing' && getModuleEnabled(module.key) && (
{t('需要登录访问')}
{t('开启后未登录用户无法访问模型广场')}
)}
{/* 未登录模糊价格子开关 */}
{module.hasBlurPricing && getModuleEnabled(module.key) && (
{t('未登录模糊价格')}
{t('开启后未登录用户看到的价格和供应商信息将模糊处理')}
)}
{/* 首页成本价展示子开关 */}
{module.hasCostPrice && getModuleEnabled(module.key) && (
{t('成本价')}
{t(
'开启后,供应商、代理商、管理员与超级管理员在首页模型详情侧栏「我的令牌」下方可查看各通道成本价',
)}
)}
))}
{/* 主题切换开关 */}
{t('主题切换')}
{t('顶栏显示主题切换按钮,允许用户切换亮色/暗色模式')}
{/* 语言选择器开关 */}
{t('语言选择器')}
{t('顶栏显示语言选择器,允许用户切换界面语言')}
);
}