From bd11ebdbd572651ed4d750ecf6c2bdb3cd6189d7 Mon Sep 17 00:00:00 2001 From: fawney19 Date: Wed, 17 Dec 2025 17:50:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=E6=B7=B1=E8=89=B2=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E5=88=87=E6=8D=A2=E5=90=8E=E5=88=B7=E6=96=B0=E5=A4=B1?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 前端使用 useDarkMode composable 统一主题切换逻辑 - 后端支持 system 主题值(之前只支持 auto) - 主题以本地 localStorage 为准,避免刷新时被服务端旧值覆盖 Fixes #22 --- frontend/src/views/user/Settings.vue | 39 ++++++++++++++-------------- src/services/user/preference.py | 4 +-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/frontend/src/views/user/Settings.vue b/frontend/src/views/user/Settings.vue index 80f22db..74333a4 100644 --- a/frontend/src/views/user/Settings.vue +++ b/frontend/src/views/user/Settings.vue @@ -62,6 +62,7 @@ @@ -107,6 +108,7 @@ @@ -320,6 +322,7 @@ import { ref, onMounted } from 'vue' import { useAuthStore } from '@/stores/auth' import { meApi, type Profile } from '@/api/me' +import { useDarkMode, type ThemeMode } from '@/composables/useDarkMode' import Card from '@/components/ui/card.vue' import Button from '@/components/ui/button.vue' import Badge from '@/components/ui/badge.vue' @@ -338,6 +341,7 @@ import { log } from '@/utils/logger' const authStore = useAuthStore() const { success, error: showError } = useToast() +const { setThemeMode } = useDarkMode() const profile = ref(null) @@ -375,20 +379,8 @@ function handleThemeChange(value: string) { themeSelectOpen.value = false updatePreferences() - // 应用主题 - if (value === 'dark') { - document.documentElement.classList.add('dark') - } else if (value === 'light') { - document.documentElement.classList.remove('dark') - } else { - // system: 跟随系统 - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches - if (prefersDark) { - document.documentElement.classList.add('dark') - } else { - document.documentElement.classList.remove('dark') - } - } + // 使用 useDarkMode 统一切换主题 + setThemeMode(value as ThemeMode) } function handleLanguageChange(value: string) { @@ -418,10 +410,16 @@ async function loadProfile() { async function loadPreferences() { try { const prefs = await meApi.getPreferences() + + // 主题以本地 localStorage 为准(useDarkMode 在应用启动时已初始化) + // 这样可以避免刷新页面时主题被服务端旧值覆盖 + const { themeMode: currentThemeMode } = useDarkMode() + const localTheme = currentThemeMode.value + preferencesForm.value = { avatar_url: prefs.avatar_url || '', bio: prefs.bio || '', - theme: prefs.theme || 'light', + theme: localTheme, // 使用本地主题,而非服务端返回值 language: prefs.language || 'zh-CN', timezone: prefs.timezone || 'Asia/Shanghai', notifications: { @@ -431,11 +429,12 @@ async function loadPreferences() { } } - // 应用主题 - if (preferencesForm.value.theme === 'dark') { - document.documentElement.classList.add('dark') - } else if (preferencesForm.value.theme === 'light') { - document.documentElement.classList.remove('dark') + // 如果本地主题和服务端不一致,同步到服务端(静默更新,不提示用户) + const serverTheme = prefs.theme || 'light' + if (localTheme !== serverTheme) { + meApi.updatePreferences({ theme: localTheme }).catch(() => { + // 静默失败,不影响用户体验 + }) } } catch (error) { log.error('加载偏好设置失败:', error) diff --git a/src/services/user/preference.py b/src/services/user/preference.py index 8ca2874..7adc603 100644 --- a/src/services/user/preference.py +++ b/src/services/user/preference.py @@ -71,8 +71,8 @@ class PreferenceService: raise NotFoundException("Provider not found or inactive") preferences.default_provider_id = default_provider_id if theme is not None: - if theme not in ["light", "dark", "auto"]: - raise ValueError("Invalid theme. Must be 'light', 'dark', or 'auto'") + if theme not in ["light", "dark", "auto", "system"]: + raise ValueError("Invalid theme. Must be 'light', 'dark', 'auto', or 'system'") preferences.theme = theme if language is not None: preferences.language = language