From 3a949abdb4609921ad0e1bbd3e742dc7c7c36fd7 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Tue, 14 Apr 2026 13:44:24 +0800 Subject: [PATCH] fix: restore cached theme before personalization sync --- .../personalization/PersonalizationDrawer.vue | 29 +++++++++++++++++-- static/src/stores/personalization.ts | 23 ++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/static/src/components/personalization/PersonalizationDrawer.vue b/static/src/components/personalization/PersonalizationDrawer.vue index 917e7ca..ddcdccd 100644 --- a/static/src/components/personalization/PersonalizationDrawer.vue +++ b/static/src/components/personalization/PersonalizationDrawer.vue @@ -2003,7 +2003,7 @@ const openApiAdmin = () => { const { setTheme, loadTheme } = useTheme(); const themeOptions: Array<{ id: ThemeKey; label: string; desc: string; swatches: string[] }> = [ { - id: 'claude', + id: 'classic', label: '经典', desc: '米色质感,柔和高对比', swatches: ['#eeece2', '#f7f3ea', '#da7756'] @@ -2024,9 +2024,34 @@ const themeOptions: Array<{ id: ThemeKey; label: string; desc: string; swatches: const activeTheme = ref(loadTheme()); -const applyThemeOption = (theme: ThemeKey) => { +// 监听store中的theme变化,同步到activeTheme(用于从后端加载主题后更新UI) +watch(() => personalization.form.theme, (newTheme) => { + if (newTheme && newTheme !== activeTheme.value) { + activeTheme.value = newTheme as ThemeKey; + setTheme(newTheme as ThemeKey); + } +}, { immediate: true }); + +const applyThemeOption = async (theme: ThemeKey) => { activeTheme.value = theme; setTheme(theme); + + // 同步更新到store并保存到后端配置文件 + personalization.updateField({ key: 'theme', value: theme }); + + try { + const resp = await fetch('/api/personalization', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ theme }) + }); + const result = await resp.json(); + if (!resp.ok || !result.success) { + console.warn('保存主题到后端失败:', result.error); + } + } catch (error) { + console.warn('保存主题到后端失败:', error); + } }; diff --git a/static/src/stores/personalization.ts b/static/src/stores/personalization.ts index 96edac6..89cfffb 100644 --- a/static/src/stores/personalization.ts +++ b/static/src/stores/personalization.ts @@ -17,6 +17,7 @@ interface PersonalForm { skill_strict_run_command_background_enabled: boolean; silent_tool_disable: boolean; enhanced_tool_display: boolean; + enhanced_tool_display_categories: string[]; enabled_skills: string[]; self_identify: string; user_name: string; @@ -75,6 +76,15 @@ const DEFAULT_SHALLOW_COMPRESS_TRIGGER_TOKENS = 80000; const DEFAULT_DEEP_COMPRESS_TRIGGER_TOKENS = 150000; const RUN_MODE_OPTIONS: RunMode[] = ['fast', 'thinking', 'deep']; const EXPERIMENT_STORAGE_KEY = 'agents_personalization_experiments'; +const THEME_STORAGE_KEY = 'agents_ui_theme'; + +const loadCachedTheme = (): PersonalForm['theme'] => { + if (typeof window === 'undefined' || !window.localStorage) { + return 'classic'; + } + const saved = window.localStorage.getItem(THEME_STORAGE_KEY); + return saved === 'light' || saved === 'dark' || saved === 'classic' ? saved : 'classic'; +}; const defaultForm = (): PersonalForm => ({ enabled: false, @@ -88,6 +98,7 @@ const defaultForm = (): PersonalForm => ({ skill_strict_run_command_background_enabled: false, silent_tool_disable: false, enhanced_tool_display: true, + enhanced_tool_display_categories: [], enabled_skills: [], self_identify: '', user_name: '', @@ -112,7 +123,7 @@ const defaultForm = (): PersonalForm => ({ deep_compress_trigger_tokens: null, agents_md_auto_inject: false, allow_root_file_creation: false, - theme: 'classic' + theme: loadCachedTheme() }); const defaultExperimentState = (): ExperimentState => ({ @@ -228,6 +239,7 @@ export const usePersonalizationStore = defineStore('personalization', { (this.form && typeof this.form.default_model === 'string' ? this.form.default_model : null) || 'kimi-k2.5'; + const fallbackTheme = this.form?.theme || loadCachedTheme(); this.form = { enabled: !!data.enabled, communication_style: data.communication_style === 'human_like' ? 'human_like' : 'default', @@ -242,6 +254,9 @@ export const usePersonalizationStore = defineStore('personalization', { !!data.skill_strict_run_command_background_enabled, silent_tool_disable: !!data.silent_tool_disable, enhanced_tool_display: data.enhanced_tool_display !== false, + enhanced_tool_display_categories: Array.isArray(data.enhanced_tool_display_categories) + ? data.enhanced_tool_display_categories.filter((item: unknown) => typeof item === 'string') + : [], enabled_skills: Array.isArray(data.enabled_skills) ? data.enabled_skills.filter((item: unknown) => typeof item === 'string') : [], @@ -293,11 +308,11 @@ export const usePersonalizationStore = defineStore('personalization', { ), agents_md_auto_inject: !!data.agents_md_auto_inject, allow_root_file_creation: !!data.allow_root_file_creation, - theme: ['classic', 'light', 'dark'].includes(data.theme) ? data.theme : 'classic' + theme: ['classic', 'light', 'dark'].includes(data.theme) ? data.theme : fallbackTheme }; // 如果theme发生变化,应用到界面 const currentTheme = (typeof window !== 'undefined' && window.localStorage) - ? window.localStorage.getItem('agents_ui_theme') + ? window.localStorage.getItem(THEME_STORAGE_KEY) : null; if (this.form.theme !== currentTheme) { this.applyTheme(this.form.theme); @@ -307,7 +322,7 @@ export const usePersonalizationStore = defineStore('personalization', { applyTheme(theme: 'classic' | 'light' | 'dark') { if (typeof window === 'undefined') return; // 同步到localStorage - window.localStorage.setItem('agents_ui_theme', theme); + window.localStorage.setItem(THEME_STORAGE_KEY, theme); // 应用主题 const root = document.documentElement; root.setAttribute('data-theme', theme);