From bd0bbc96749cd274661b5b9d157495dae5070122 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Thu, 15 May 2025 20:57:28 +0800 Subject: [PATCH] :bug: fixed configuration override issue --- frontend/src/i18n/index.ts | 11 ++++ frontend/src/stores/configStore.ts | 67 +++++++++++++------- frontend/src/stores/logStore.ts | 97 +++++++++++++++++++++++------ internal/services/config_service.go | 22 ++++--- 4 files changed, 146 insertions(+), 51 deletions(-) diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 12c7e45..cb97600 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -2,6 +2,7 @@ import {createI18n} from 'vue-i18n'; import messages from './locales'; import { ConfigService } from '@/../bindings/voidraft/internal/services'; import { LanguageType } from '@/../bindings/voidraft/internal/models'; +import { useConfigStore } from '@/stores/configStore'; // 定义支持的语言类型 export type SupportedLocaleType = 'zh-CN' | 'en-US'; @@ -59,6 +60,16 @@ export const setLocale = (locale: SupportedLocaleType) => { .then(() => { i18n.global.locale = locale; document.documentElement.setAttribute('lang', locale); + + // 同时更新configStore中的语言设置 + try { + const configStore = useConfigStore(); + if (configStore.configLoaded) { + configStore.config.language = locale as LanguageType; + } + } catch (error) { + console.error('Failed to update configStore language:', error); + } }) .catch(error => { console.error('Failed to set language:', error); diff --git a/frontend/src/stores/configStore.ts b/frontend/src/stores/configStore.ts index 9179442..7894f8a 100644 --- a/frontend/src/stores/configStore.ts +++ b/frontend/src/stores/configStore.ts @@ -40,80 +40,98 @@ export const useConfigStore = defineStore('config', () => { // 配置是否已从后端加载 const configLoaded = ref(false); + + // 配置是否正在从后端加载 + const isLoading = ref(false); // 从后端加载配置 async function loadConfigFromBackend() { + if (isLoading.value) return; + + isLoading.value = true; try { - config.value = await ConfigService.GetEditorConfig(); + const loadedConfig = await ConfigService.GetEditorConfig(); - // 验证并纠正配置 - validateAndFixConfig(); + // 深拷贝配置以避免直接引用 + config.value = new EditorConfig(JSON.parse(JSON.stringify(loadedConfig))); - configLoaded.value = true; - logStore.info(t('config.loadSuccess')); + // 验证并纠正配置,不自动保存 + validateAndFixConfig(false); + + // 等待下一个事件循环,确保watch不会在初始加载时触发 + setTimeout(() => { + configLoaded.value = true; + isLoading.value = false; + logStore.info(t('config.loadSuccess')); + }, 0); } catch (error) { console.error('Failed to load configuration:', error); logStore.error(t('config.loadFailed')); + isLoading.value = false; } } // 验证配置是否在合理范围内,并修正无效值 - function validateAndFixConfig() { + function validateAndFixConfig(autoSave = true) { let hasChanges = false; // 验证字体大小 if (config.value.fontSize < CONFIG_LIMITS.fontSize.min || config.value.fontSize > CONFIG_LIMITS.fontSize.max) { - const oldValue = config.value.fontSize; - config.value.fontSize = oldValue < CONFIG_LIMITS.fontSize.min ? CONFIG_LIMITS.fontSize.min : - oldValue > CONFIG_LIMITS.fontSize.max ? CONFIG_LIMITS.fontSize.max : - CONFIG_LIMITS.fontSize.default; + config.value.fontSize = config.value.fontSize < CONFIG_LIMITS.fontSize.min + ? CONFIG_LIMITS.fontSize.min + : CONFIG_LIMITS.fontSize.max; logStore.warning(t('config.fontSizeFixed')); - hasChanges = true; } // 验证Tab大小 if (config.value.tabSize < CONFIG_LIMITS.tabSize.min || config.value.tabSize > CONFIG_LIMITS.tabSize.max) { - const oldValue = config.value.tabSize; - config.value.tabSize = oldValue < CONFIG_LIMITS.tabSize.min ? CONFIG_LIMITS.tabSize.min : - oldValue > CONFIG_LIMITS.tabSize.max ? CONFIG_LIMITS.tabSize.max : - CONFIG_LIMITS.tabSize.default; + config.value.tabSize = config.value.tabSize < CONFIG_LIMITS.tabSize.min + ? CONFIG_LIMITS.tabSize.min + : CONFIG_LIMITS.tabSize.max; logStore.warning(t('config.tabSizeFixed')); - hasChanges = true; } // 验证TabType是否合法 if (!CONFIG_LIMITS.tabType.values.includes(config.value.tabType)) { - const oldValue = config.value.tabType; config.value.tabType = CONFIG_LIMITS.tabType.default; - logStore.warning(t('config.tabTypeFixed')); hasChanges = true; } - // 如果配置被修正,保存回后端 - if (hasChanges && configLoaded.value) { + // 如果配置被修正且需要自动保存,保存回后端 + if (hasChanges && autoSave && configLoaded.value) { saveConfigToBackend(); } } // 使用防抖保存配置到后端 const saveConfigToBackend = useDebounceFn(async () => { + if (!configLoaded.value || isLoading.value) return; + try { + // 首先获取后端当前的语言设置 + const currentLanguage = await ConfigService.GetLanguage(); + + // 确保我们使用当前的语言设置,避免被默认值覆盖 + if (currentLanguage && currentLanguage !== config.value.language) { + config.value.language = currentLanguage; + } + await ConfigService.UpdateEditorConfig(config.value); logStore.info(t('config.saveSuccess')); } catch (error) { console.error('Failed to save configuration:', error); logStore.error(t('config.saveFailed')); } - }, 500); // 500ms防抖 + }, 500); // 监听配置变化,自动保存到后端 watch(() => config.value, async () => { - if (configLoaded.value) { + if (configLoaded.value && !isLoading.value) { await saveConfigToBackend(); } }, {deep: true}); @@ -165,13 +183,17 @@ export const useConfigStore = defineStore('config', () => { // 重置为默认配置 async function resetToDefaults() { + if (isLoading.value) return; + try { + isLoading.value = true; await ConfigService.ResetConfig(); await loadConfigFromBackend(); logStore.info(t('config.resetSuccess')); } catch (error) { console.error('Failed to reset configuration:', error); logStore.error(t('config.resetFailed')); + isLoading.value = false; } } @@ -179,6 +201,7 @@ export const useConfigStore = defineStore('config', () => { // 状态 config, configLoaded, + isLoading, // 常量 MIN_FONT_SIZE, diff --git a/frontend/src/stores/logStore.ts b/frontend/src/stores/logStore.ts index e31ad6a..76dce45 100644 --- a/frontend/src/stores/logStore.ts +++ b/frontend/src/stores/logStore.ts @@ -14,29 +14,76 @@ export interface LogItem { level: LogLevel; message: string; timestamp: Date; + shown: boolean; // 是否已显示过 } export const useLogStore = defineStore('log', () => { // 日志列表 const logs = ref([]); + // 显示队列 - 存储待显示的日志 + const displayQueue = ref([]); + + // 当前显示的日志 + const currentLog = ref(null); + // 最近一条日志,用于在工具栏显示 const latestLog = ref(null); // 是否显示日志 - const showLog = ref(true); + const showLog = ref(false); // 自动隐藏计时器 let hideTimer: number | null = null; + + // 根据日志级别获取显示时间 + function getDisplayTimeByLevel(level: LogLevel): number { + switch(level) { + case LogLevel.ERROR: + return 8000; // 错误显示更长时间 + case LogLevel.WARNING: + return 6000; // 警告显示中等时间 + case LogLevel.INFO: + default: + return 4000; // 信息显示较短时间 + } + } + + // 显示下一条日志 + function showNextLog() { + if (hideTimer) { + window.clearTimeout(hideTimer); + hideTimer = null; + } + + // 如果队列为空,则不显示 + if (displayQueue.value.length === 0) { + showLog.value = false; + currentLog.value = null; + return; + } + + // 取出队列中第一条日志显示 + const nextLog = displayQueue.value.shift()!; + currentLog.value = nextLog; + showLog.value = true; + + // 设置自动隐藏和切换到下一条 + const displayTime = getDisplayTimeByLevel(nextLog.level); + hideTimer = window.setTimeout(() => { + showNextLog(); + }, displayTime); + } // 添加日志 - function addLog(level: LogLevel, message: string, autoHideDelay = 5000) { + function addLog(level: LogLevel, message: string, autoHideDelay = 0) { const id = Date.now(); const logItem: LogItem = { id, level, message, - timestamp: new Date() + timestamp: new Date(), + shown: false }; // 添加到日志列表 @@ -49,52 +96,63 @@ export const useLogStore = defineStore('log', () => { // 设置最新日志 latestLog.value = logItem; - showLog.value = true; - // 设置自动隐藏 - if (hideTimer) { - window.clearTimeout(hideTimer); - } + // 添加到显示队列 + displayQueue.value.push(logItem); - if (autoHideDelay > 0) { - hideTimer = window.setTimeout(() => { - showLog.value = false; - }, autoHideDelay); + // 如果当前没有显示日志,则开始显示 + if (!currentLog.value && !hideTimer) { + showNextLog(); } return id; } // 添加不同级别的日志的便捷方法 - function info(message: string, autoHideDelay = 5000) { - return addLog(LogLevel.INFO, message, autoHideDelay); + function info(message: string) { + return addLog(LogLevel.INFO, message); } - function warning(message: string, autoHideDelay = 5000) { - return addLog(LogLevel.WARNING, message, autoHideDelay); + function warning(message: string) { + return addLog(LogLevel.WARNING, message); } - function error(message: string, autoHideDelay = 5000) { - return addLog(LogLevel.ERROR, message, autoHideDelay); + function error(message: string) { + return addLog(LogLevel.ERROR, message); } // 清除日志 function clearLogs() { logs.value = []; + displayQueue.value = []; latestLog.value = null; + currentLog.value = null; showLog.value = false; + + if (hideTimer) { + window.clearTimeout(hideTimer); + hideTimer = null; + } } // 手动隐藏当前日志 function hideCurrentLog() { + if (hideTimer) { + window.clearTimeout(hideTimer); + hideTimer = null; + } showLog.value = false; + currentLog.value = null; + displayQueue.value = []; // 清空队列 } return { // 状态 logs, latestLog, + currentLog, showLog, + displayQueue, // 方法 addLog, @@ -102,6 +160,7 @@ export const useLogStore = defineStore('log', () => { warning, error, clearLogs, - hideCurrentLog + hideCurrentLog, + showNextLog }; }); \ No newline at end of file diff --git a/internal/services/config_service.go b/internal/services/config_service.go index 7af0f65..57b17b1 100644 --- a/internal/services/config_service.go +++ b/internal/services/config_service.go @@ -146,7 +146,7 @@ func (cs *ConfigService) mergeWithDefaults(config *models.AppConfig) error { defaultConfig := models.NewDefaultAppConfig() // 使用mergo库合并配置 - if err := mergo.Merge(config, defaultConfig, mergo.WithOverrideEmptySlice, mergo.WithOverwriteWithEmptyValue); err != nil { + if err := mergo.Merge(config, defaultConfig, mergo.WithOverrideEmptySlice); err != nil { return err } @@ -182,9 +182,7 @@ func (cs *ConfigService) loadConfig() (models.AppConfig, error) { // isValidConfig 检查配置是否有效 func isValidConfig(config models.AppConfig) bool { // 检查关键字段 - if config.Metadata.Version == "" || - config.Metadata.LastUpdated.IsZero() || - config.Paths.DataPath == "" { + if config.Metadata.Version == "" { return false } return true @@ -230,12 +228,6 @@ func (cs *ConfigService) GetConfig() (*models.AppConfig, error) { return defaultConfig, nil } - - // 合并默认配置 - if err := cs.mergeWithDefaults(&config); err != nil { - return &config, &ConfigError{Operation: "get_merge_defaults", Err: err} - } - return &config, nil } @@ -259,7 +251,17 @@ func (cs *ConfigService) UpdateEditorConfig(editorConfig models.EditorConfig) er return err } + // 保存当前的语言设置 + currentLanguage := config.Editor.Language + + // 更新编辑器配置 config.Editor = editorConfig + + // 如果更新后的语言设置为空,则使用之前的语言设置 + if editorConfig.Language == "" { + config.Editor.Language = currentLanguage + } + return cs.SaveConfig(config) }