diff --git a/controller/misc.go b/controller/misc.go
index 5f2987f..067b4a4 100644
--- a/controller/misc.go
+++ b/controller/misc.go
@@ -117,6 +117,8 @@ func GetStatus(c *gin.Context) {
// 模块管理配置
"HeaderNavModules": common.OptionMap["HeaderNavModules"],
+ "HeaderShowThemeToggle": common.OptionMap["HeaderShowThemeToggle"] != "false",
+ "HeaderShowLanguageSelector": common.OptionMap["HeaderShowLanguageSelector"] != "false",
"SidebarModulesByRole": common.OptionMap["SidebarModulesByRole"],
"oidc_enabled": system_setting.GetOIDCSettings().Enabled,
diff --git a/model/option.go b/model/option.go
index a0ec28a..d1be35f 100644
--- a/model/option.go
+++ b/model/option.go
@@ -290,6 +290,9 @@ func InitOptionMap() {
common.OptionMap[k] = v
}
+ common.OptionMap["HeaderShowThemeToggle"] = strconv.FormatBool(true)
+ common.OptionMap["HeaderShowLanguageSelector"] = strconv.FormatBool(true)
+
common.OptionMapRWMutex.Unlock()
loadOptionsFromDatabase()
}
diff --git a/web/src/components/layout/headerbar/ActionButtons.jsx b/web/src/components/layout/headerbar/ActionButtons.jsx
index 5e32f28..84becd7 100644
--- a/web/src/components/layout/headerbar/ActionButtons.jsx
+++ b/web/src/components/layout/headerbar/ActionButtons.jsx
@@ -35,6 +35,8 @@ const ActionButtons = ({
isLoading,
isMobile,
isSelfUseMode,
+ showThemeToggle = true,
+ showLanguageSelector = true,
logout,
navigate,
t,
@@ -51,12 +53,16 @@ const ActionButtons = ({
/>
)}
-
+ {showThemeToggle && (
+
+ )}
-
+ {showLanguageSelector && (
+
+ )}
{
docsNav,
isDemoSiteMode,
isConsoleRoute,
+ showThemeToggle,
+ showLanguageSelector,
theme,
headerNavModules,
pricingRequireAuth,
@@ -134,6 +136,8 @@ const HeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
isLoading={isLoading}
isMobile={isMobile}
isSelfUseMode={isSelfUseMode}
+ showThemeToggle={showThemeToggle}
+ showLanguageSelector={showLanguageSelector}
logout={logout}
navigate={navigate}
t={t}
diff --git a/web/src/hooks/common/useHeaderBar.js b/web/src/hooks/common/useHeaderBar.js
index f0b31da..2ff669f 100644
--- a/web/src/hooks/common/useHeaderBar.js
+++ b/web/src/hooks/common/useHeaderBar.js
@@ -107,6 +107,10 @@ export const useHeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
const isConsoleRoute = location.pathname.startsWith('/console');
+ // 读取顶栏主题切换和语言选择器开关配置
+ const showThemeToggle = statusState?.status?.HeaderShowThemeToggle !== false;
+ const showLanguageSelector = statusState?.status?.HeaderShowLanguageSelector !== false;
+
const theme = useTheme();
const actualTheme = useActualTheme();
const setTheme = useSetTheme();
@@ -251,6 +255,8 @@ export const useHeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
docsNav,
isDemoSiteMode,
isConsoleRoute,
+ showThemeToggle,
+ showLanguageSelector,
theme,
drawerOpen,
headerNavModules,
diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index df2217d..057d9c3 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -5691,6 +5691,10 @@
"支持模型": "Supported Models",
"速率限制": "Rate Limits",
"常见问题": "FAQ",
- "本页目录": "On this page"
+ "本页目录": "On this page",
+ "主题切换": "Theme Toggle",
+ "顶栏显示主题切换按钮,允许用户切换亮色/暗色模式": "Show theme toggle in header bar, allowing users to switch between light/dark mode",
+ "语言选择器": "Language Selector",
+ "顶栏显示语言选择器,允许用户切换界面语言": "Show language selector in header bar, allowing users to switch interface language"
}
}
\ No newline at end of file
diff --git a/web/src/i18n/locales/zh-CN.json b/web/src/i18n/locales/zh-CN.json
index 0250766..ae8ed1d 100644
--- a/web/src/i18n/locales/zh-CN.json
+++ b/web/src/i18n/locales/zh-CN.json
@@ -5550,6 +5550,10 @@
"支持模型": "支持模型",
"速率限制": "速率限制",
"常见问题": "常见问题",
- "本页目录": "本页目录"
+ "本页目录": "本页目录",
+ "主题切换": "主题切换",
+ "顶栏显示主题切换按钮,允许用户切换亮色/暗色模式": "顶栏显示主题切换按钮,允许用户切换亮色/暗色模式",
+ "语言选择器": "语言选择器",
+ "顶栏显示语言选择器,允许用户切换界面语言": "顶栏显示语言选择器,允许用户切换界面语言"
}
}
\ No newline at end of file
diff --git a/web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx b/web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx
index 8d0e742..9967336 100644
--- a/web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx
+++ b/web/src/pages/Setting/Operation/SettingsHeaderNavModules.jsx
@@ -54,6 +54,8 @@ export default function SettingsHeaderNavModules(props) {
benchmark: true,
docs: true,
});
+ const [showThemeToggle, setShowThemeToggle] = useState(true);
+ const [showLanguageSelector, setShowLanguageSelector] = useState(true);
// 处理顶栏模块配置变更
function handleHeaderNavModuleChange(moduleKey) {
@@ -127,6 +129,52 @@ export default function SettingsHeaderNavModules(props) {
})();
}
+ // 处理主题切换开关变更(即时保存)
+ 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) => {
@@ -224,6 +272,17 @@ export default function SettingsHeaderNavModules(props) {
}
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 {
@@ -547,6 +606,118 @@ export default function SettingsHeaderNavModules(props) {
))}
+
+ {/* 主题切换开关 */}
+
+
+
+
+
+ {t('主题切换')}
+
+
+ {t('顶栏显示主题切换按钮,允许用户切换亮色/暗色模式')}
+
+
+
+
+
+
+
+
+
+ {/* 语言选择器开关 */}
+
+
+
+
+
+ {t('语言选择器')}
+
+
+ {t('顶栏显示语言选择器,允许用户切换界面语言')}
+
+
+
+
+
+
+
+