import {defineStore} from 'pinia'; import {computed, reactive} from 'vue'; import {ConfigService, StartupService} from '@/../bindings/voidraft/internal/services'; import { AppConfig, AppearanceConfig, AuthMethod, EditingConfig, GeneralConfig, GitBackupConfig, LanguageType, SystemThemeType, TabType, UpdatesConfig } from '@/../bindings/voidraft/internal/models/models'; import {useI18n} from 'vue-i18n'; import {ConfigUtils} from '@/common/utils/configUtils'; import {FONT_OPTIONS} from '@/common/constant/fonts'; import {SUPPORTED_LOCALES} from '@/common/constant/locales'; import { APPEARANCE_CONFIG_KEY_MAP, BACKUP_CONFIG_KEY_MAP, CONFIG_LIMITS, DEFAULT_CONFIG, EDITING_CONFIG_KEY_MAP, GENERAL_CONFIG_KEY_MAP, NumberConfigKey, UPDATES_CONFIG_KEY_MAP } from '@/common/constant/config'; import * as runtime from '@wailsio/runtime'; export const useConfigStore = defineStore('config', () => { const {locale} = useI18n(); // 响应式状态 const state = reactive({ config: {...DEFAULT_CONFIG} as AppConfig, isLoading: false, configLoaded: false }); // Font options (no longer localized) const fontOptions = computed(() => FONT_OPTIONS); // 计算属性 - 使用工厂函数简化 const createLimitComputed = (key: NumberConfigKey) => computed(() => CONFIG_LIMITS[key]); const limits = Object.fromEntries( (['fontSize', 'tabSize', 'lineHeight'] as const).map(key => [key, createLimitComputed(key)]) ) as Record>; // 通用配置更新方法 const updateGeneralConfig = async (key: K, value: GeneralConfig[K]): Promise => { // 确保配置已加载 if (!state.configLoaded && !state.isLoading) { await initConfig(); } const backendKey = GENERAL_CONFIG_KEY_MAP[key]; if (!backendKey) { throw new Error(`No backend key mapping found for general.${key.toString()}`); } await ConfigService.Set(backendKey, value); state.config.general[key] = value; }; const updateEditingConfig = async (key: K, value: EditingConfig[K]): Promise => { // 确保配置已加载 if (!state.configLoaded && !state.isLoading) { await initConfig(); } const backendKey = EDITING_CONFIG_KEY_MAP[key]; if (!backendKey) { throw new Error(`No backend key mapping found for editing.${key.toString()}`); } await ConfigService.Set(backendKey, value); state.config.editing[key] = value; }; const updateAppearanceConfig = async (key: K, value: AppearanceConfig[K]): Promise => { // 确保配置已加载 if (!state.configLoaded && !state.isLoading) { await initConfig(); } const backendKey = APPEARANCE_CONFIG_KEY_MAP[key]; if (!backendKey) { throw new Error(`No backend key mapping found for appearance.${key.toString()}`); } await ConfigService.Set(backendKey, value); state.config.appearance[key] = value; }; const updateUpdatesConfig = async (key: K, value: UpdatesConfig[K]): Promise => { // 确保配置已加载 if (!state.configLoaded && !state.isLoading) { await initConfig(); } const backendKey = UPDATES_CONFIG_KEY_MAP[key]; if (!backendKey) { throw new Error(`No backend key mapping found for updates.${key.toString()}`); } await ConfigService.Set(backendKey, value); state.config.updates[key] = value; }; const updateBackupConfig = async (key: K, value: GitBackupConfig[K]): Promise => { // 确保配置已加载 if (!state.configLoaded && !state.isLoading) { await initConfig(); } const backendKey = BACKUP_CONFIG_KEY_MAP[key]; if (!backendKey) { throw new Error(`No backend key mapping found for backup.${key.toString()}`); } await ConfigService.Set(backendKey, value); state.config.backup[key] = value; }; // 加载配置 const initConfig = async (): Promise => { if (state.isLoading) return; state.isLoading = true; try { const appConfig = await ConfigService.GetConfig(); if (appConfig) { // 合并配置 if (appConfig.general) Object.assign(state.config.general, appConfig.general); if (appConfig.editing) Object.assign(state.config.editing, appConfig.editing); if (appConfig.appearance) Object.assign(state.config.appearance, appConfig.appearance); if (appConfig.updates) Object.assign(state.config.updates, appConfig.updates); if (appConfig.backup) Object.assign(state.config.backup, appConfig.backup); if (appConfig.metadata) Object.assign(state.config.metadata, appConfig.metadata); } state.configLoaded = true; } finally { state.isLoading = false; } }; // 通用数值调整器工厂 const createAdjuster = (key: T) => { const limit = CONFIG_LIMITS[key]; const clamp = (value: number) => ConfigUtils.clamp(value, limit.min, limit.max); return { increase: async () => await updateEditingConfig(key, clamp(state.config.editing[key] + 1)), decrease: async () => await updateEditingConfig(key, clamp(state.config.editing[key] - 1)), set: async (value: number) => await updateEditingConfig(key, clamp(value)), reset: async () => await updateEditingConfig(key, limit.default) }; }; const createEditingToggler = (key: T) => async () => await updateEditingConfig(key, !state.config.editing[key] as EditingConfig[T]); // 枚举值切换器 const createEnumToggler = (key: 'tabType', values: readonly T[]) => async () => { const currentIndex = values.indexOf(state.config.editing[key] as T); const nextIndex = (currentIndex + 1) % values.length; return await updateEditingConfig(key, values[nextIndex]); }; // 重置配置 const resetConfig = async (): Promise => { if (state.isLoading) return; state.isLoading = true; try { await ConfigService.ResetConfig(); const appConfig = await ConfigService.GetConfig(); if (appConfig) { state.config = JSON.parse(JSON.stringify(appConfig)) as AppConfig; } } finally { state.isLoading = false; } }; // 语言设置方法 const setLanguage = async (language: LanguageType): Promise => { await updateAppearanceConfig('language', language); // 同步更新前端语言 const frontendLocale = ConfigUtils.backendLanguageToFrontend(language); locale.value = frontendLocale as any; }; // 系统主题设置方法 const setSystemTheme = async (systemTheme: SystemThemeType): Promise => { await updateAppearanceConfig('systemTheme', systemTheme); }; // 当前主题设置方法 const setCurrentTheme = async (themeName: string): Promise => { await updateAppearanceConfig('currentTheme', themeName); }; // 初始化语言设置 const initializeLanguage = async (): Promise => { try { // 如果配置未加载,先加载配置 if (!state.configLoaded) { await initConfig(); } // 同步前端语言设置 const frontendLocale = ConfigUtils.backendLanguageToFrontend(state.config.appearance.language); locale.value = frontendLocale as any; } catch (_error) { const browserLang = SUPPORTED_LOCALES[0].code; locale.value = browserLang as any; } }; // 创建数值调整器实例 const adjusters = { fontSize: createAdjuster('fontSize'), tabSize: createAdjuster('tabSize'), lineHeight: createAdjuster('lineHeight') }; // 创建切换器实例 const togglers = { tabIndent: createEditingToggler('enableTabIndent'), alwaysOnTop: async () => { await updateGeneralConfig('alwaysOnTop', !state.config.general.alwaysOnTop); // 立即应用窗口置顶状态 await runtime.Window.SetAlwaysOnTop(state.config.general.alwaysOnTop); }, tabType: createEnumToggler('tabType', CONFIG_LIMITS.tabType.values) }; // 字符串配置设置器 const setters = { fontFamily: async (value: string) => await updateEditingConfig('fontFamily', value), fontWeight: async (value: string) => await updateEditingConfig('fontWeight', value), dataPath: async (value: string) => await updateGeneralConfig('dataPath', value), autoSaveDelay: async (value: number) => await updateEditingConfig('autoSaveDelay', value) }; return { // 状态 config: computed(() => state.config), configLoaded: computed(() => state.configLoaded), isLoading: computed(() => state.isLoading), fontOptions, // 限制常量 ...limits, // 核心方法 initConfig, resetConfig, // 语言相关方法 setLanguage, initializeLanguage, // 主题相关方法 setSystemTheme, setCurrentTheme, // 字体大小操作 ...adjusters.fontSize, increaseFontSize: adjusters.fontSize.increase, decreaseFontSize: adjusters.fontSize.decrease, resetFontSize: adjusters.fontSize.reset, setFontSize: adjusters.fontSize.set, // Tab操作 toggleTabIndent: togglers.tabIndent, setEnableTabIndent: (value: boolean) => updateEditingConfig('enableTabIndent', value), ...adjusters.tabSize, increaseTabSize: adjusters.tabSize.increase, decreaseTabSize: adjusters.tabSize.decrease, setTabSize: adjusters.tabSize.set, toggleTabType: togglers.tabType, // 行高操作 setLineHeight: adjusters.lineHeight.set, // 窗口操作 toggleAlwaysOnTop: togglers.alwaysOnTop, setAlwaysOnTop: (value: boolean) => updateGeneralConfig('alwaysOnTop', value), // 字体操作 setFontFamily: setters.fontFamily, setFontWeight: setters.fontWeight, // 路径操作 setDataPath: setters.dataPath, // 保存配置相关方法 setAutoSaveDelay: setters.autoSaveDelay, // 热键配置相关方法 setEnableGlobalHotkey: (value: boolean) => updateGeneralConfig('enableGlobalHotkey', value), setGlobalHotkey: (hotkey: any) => updateGeneralConfig('globalHotkey', hotkey), // 系统托盘配置相关方法 setEnableSystemTray: (value: boolean) => updateGeneralConfig('enableSystemTray', value), // 开机启动配置相关方法 setStartAtLogin: async (value: boolean) => { // 先更新配置文件 await updateGeneralConfig('startAtLogin', value); // 再调用系统设置API await StartupService.SetEnabled(value); }, // 窗口吸附配置相关方法 setEnableWindowSnap: async (value: boolean) => await updateGeneralConfig('enableWindowSnap', value), // 加载动画配置相关方法 setEnableLoadingAnimation: async (value: boolean) => await updateGeneralConfig('enableLoadingAnimation', value), // 标签页配置相关方法 setEnableTabs: async (value: boolean) => await updateGeneralConfig('enableTabs', value), // 更新配置相关方法 setAutoUpdate: async (value: boolean) => await updateUpdatesConfig('autoUpdate', value), // 备份配置相关方法 setEnableBackup: async (value: boolean) => { await updateBackupConfig('enabled', value); }, setAutoBackup: async (value: boolean) => { await updateBackupConfig('auto_backup', value); }, setRepoUrl: async (value: string) => await updateBackupConfig('repo_url', value), setAuthMethod: async (value: AuthMethod) => await updateBackupConfig('auth_method', value), setUsername: async (value: string) => await updateBackupConfig('username', value), setPassword: async (value: string) => await updateBackupConfig('password', value), setToken: async (value: string) => await updateBackupConfig('token', value), setSshKeyPath: async (value: string) => await updateBackupConfig('ssh_key_path', value), setSshKeyPassphrase: async (value: string) => await updateBackupConfig('ssh_key_passphrase', value), setBackupInterval: async (value: number) => await updateBackupConfig('backup_interval', value), }; });