Просмотр исходного кода

refactor: preference manager and export (#7068)

* fix: preferences drawer outline z-index

* refactor: preferencesManager and exports
ppxb 5 месяцев назад
Родитель
Сommit
24d20ca9ee

+ 9 - 25
packages/@core/preferences/src/index.ts

@@ -2,33 +2,17 @@ import type { Preferences } from './types';
 
 import { preferencesManager } from './preferences';
 
-// 偏好设置(带有层级关系)
-const preferences: Preferences =
-  preferencesManager.getPreferences.apply(preferencesManager);
-
-// 更新偏好设置
-const updatePreferences =
-  preferencesManager.updatePreferences.bind(preferencesManager);
-
-// 重置偏好设置
-const resetPreferences =
-  preferencesManager.resetPreferences.bind(preferencesManager);
-
-const clearPreferencesCache =
-  preferencesManager.clearCache.bind(preferencesManager);
+export const {
+  getPreferences,
+  updatePreferences,
+  resetPreferences,
+  clearCache,
+  initPreferences,
+} = preferencesManager;
 
-// 初始化偏好设置
-const initPreferences =
-  preferencesManager.initPreferences.bind(preferencesManager);
+export const preferences: Preferences = getPreferences();
 
-export {
-  clearPreferencesCache,
-  initPreferences,
-  preferences,
-  preferencesManager,
-  resetPreferences,
-  updatePreferences,
-};
+export { preferencesManager };
 
 export * from './constants';
 export type * from './types';

+ 95 - 96
packages/@core/preferences/src/preferences.ts

@@ -16,168 +16,167 @@ import {
 import { defaultPreferences } from './config';
 import { updateCSSVariables } from './update-css-variables';
 
-const STORAGE_KEY = 'preferences';
-const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
-const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;
+const STORAGE_KEYS = {
+  MAIN: 'preferences',
+  LOCALE: 'preferences-locale',
+  THEME: 'preferences-theme',
+} as const;
 
 class PreferenceManager {
-  private cache: null | StorageManager = null;
-  // private flattenedState: Flatten<Preferences>;
+  private cache: StorageManager;
+  private debouncedSave: (preference: Preferences) => void;
   private initialPreferences: Preferences = defaultPreferences;
-  private isInitialized: boolean = false;
-  private savePreferences: (preference: Preferences) => void;
-  private state: Preferences = reactive<Preferences>({
-    ...this.loadPreferences(),
-  });
+  private isInitialized = false;
+  private state: Preferences;
+
   constructor() {
     this.cache = new StorageManager();
-
-    // 避免频繁的操作缓存
-    this.savePreferences = useDebounceFn(
-      (preference: Preferences) => this._savePreferences(preference),
+    this.state = reactive<Preferences>(
+      this.loadFromCache() || { ...defaultPreferences },
+    );
+    this.debouncedSave = useDebounceFn(
+      (preference) => this.saveToCache(preference),
       150,
     );
   }
 
-  clearCache() {
-    [STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => {
-      this.cache?.removeItem(key);
-    });
-  }
+  /**
+   * 清除所有缓存的偏好设置
+   */
+  clearCache = () => {
+    Object.values(STORAGE_KEYS).forEach((key) => this.cache.removeItem(key));
+  };
 
-  public getInitialPreferences() {
+  /**
+   * 获取初始化偏好设置
+   */
+  getInitialPreferences = () => {
     return this.initialPreferences;
-  }
+  };
 
-  public getPreferences() {
+  /**
+   * 获取当前偏好设置(只读)
+   */
+  getPreferences = () => {
     return readonly(this.state);
-  }
+  };
 
   /**
-   * 覆盖偏好设置
-   * overrides  要覆盖的偏好设
-   * namespace  命名空间
+   * 初始化偏好设置
+   * @param namespace - 命名空间,用于隔离不同应用的配
+   * @param overrides - 要覆盖的偏好设置
    */
-  public async initPreferences({ namespace, overrides }: InitialOptions) {
-    // 是否初始化过
+  initPreferences = async ({ namespace, overrides }: InitialOptions) => {
+    // 防止重复初始化
     if (this.isInitialized) {
       return;
     }
-    // 初始化存储管理器
+
+    // 使用命名空间初始化存储管理器
     this.cache = new StorageManager({ prefix: namespace });
+
     // 合并初始偏好设置
     this.initialPreferences = merge({}, overrides, defaultPreferences);
 
-    // 加载并合并当前存储的偏好设置
+    // 加载缓存的偏好设置并与初始配置合并
+    const cachedPreferences = this.loadFromCache() || {};
     const mergedPreference = merge(
       {},
-      // overrides,
-      this.loadCachedPreferences() || {},
+      cachedPreferences,
       this.initialPreferences,
     );
 
     // 更新偏好设置
     this.updatePreferences(mergedPreference);
 
+    // 设置监听器
     this.setupWatcher();
 
+    // 初始化平台标识
     this.initPlatform();
-    // 标记为已初始化
+
     this.isInitialized = true;
-  }
+  };
 
   /**
-   * 重置偏好设置
-   * 偏好设置将被重置为初始值,并从 localStorage 中移除。
-   *
-   * @example
-   * 假设 initialPreferences 为 { theme: 'light', language: 'en' }
-   * 当前 state 为 { theme: 'dark', language: 'fr' }
-   * this.resetPreferences();
-   * 调用后,state 将被重置为 { theme: 'light', language: 'en' }
-   * 并且 localStorage 中的对应项将被移除
+   * 重置偏好设置到初始状态
    */
-  resetPreferences() {
+  resetPreferences = () => {
     // 将状态重置为初始偏好设置
     Object.assign(this.state, this.initialPreferences);
-    // 保存重置后的偏好设置
-    this.savePreferences(this.state);
-    // 从存储中移除偏好设置项
-    [STORAGE_KEY, STORAGE_KEY_THEME, STORAGE_KEY_LOCALE].forEach((key) => {
-      this.cache?.removeItem(key);
-    });
-    this.updatePreferences(this.state);
-  }
+
+    // 保存偏好设置至缓存
+    this.saveToCache(this.state);
+
+    // 直接触发 UI 更新
+    this.handleUpdates(this.state);
+  };
 
   /**
    * 更新偏好设置
    * @param updates - 要更新的偏好设置
    */
-  public updatePreferences(updates: DeepPartial<Preferences>) {
+  updatePreferences = (updates: DeepPartial<Preferences>) => {
+    // 深度合并更新内容和当前状态
     const mergedState = merge({}, updates, markRaw(this.state));
-
     Object.assign(this.state, mergedState);
 
-    // 根据更新的键值执行相应的操作
+    // 根据更新的值执行更新
     this.handleUpdates(updates);
-    this.savePreferences(this.state);
-  }
 
-  /**
-   * 保存偏好设置
-   * @param {Preferences} preference - 需要保存的偏好设置
-   */
-  private _savePreferences(preference: Preferences) {
-    this.cache?.setItem(STORAGE_KEY, preference);
-    this.cache?.setItem(STORAGE_KEY_LOCALE, preference.app.locale);
-    this.cache?.setItem(STORAGE_KEY_THEME, preference.theme.mode);
-  }
+    // 保存到缓存
+    this.debouncedSave(this.state);
+  };
 
   /**
-   * 处理更新的键值
-   * 根据更新的键值执行相应的操作。
-   * @param {DeepPartial<Preferences>} updates - 部分更新的偏好设置
+   * 处理更新
+   * @param updates - 更新的偏好设置
    */
   private handleUpdates(updates: DeepPartial<Preferences>) {
-    const themeUpdates = updates.theme || {};
-    const appUpdates = updates.app || {};
+    const { theme, app } = updates;
+
     if (
-      (themeUpdates && Object.keys(themeUpdates).length > 0) ||
-      Reflect.has(themeUpdates, 'fontSize')
+      theme &&
+      (Object.keys(theme).length > 0 || Reflect.has(theme, 'fontSize'))
     ) {
       updateCSSVariables(this.state);
     }
 
     if (
-      Reflect.has(appUpdates, 'colorGrayMode') ||
-      Reflect.has(appUpdates, 'colorWeakMode')
+      app &&
+      (Reflect.has(app, 'colorGrayMode') || Reflect.has(app, 'colorWeakMode'))
     ) {
       this.updateColorMode(this.state);
     }
   }
 
+  /**
+   * 初始化平台标识
+   */
   private initPlatform() {
-    const dom = document.documentElement;
-    dom.dataset.platform = isMacOs() ? 'macOs' : 'window';
+    document.documentElement.dataset.platform = isMacOs() ? 'macOs' : 'window';
   }
 
   /**
-   *  从缓存中加载偏好设置。如果缓存中没有找到对应的偏好设置,则返回默认偏好设置。
+   * 从缓存加载偏好设置
+   * @returns 缓存的偏好设置,如果不存在则返回 null
    */
-  private loadCachedPreferences() {
-    return this.cache?.getItem<Preferences>(STORAGE_KEY);
+  private loadFromCache(): null | Preferences {
+    return this.cache.getItem<Preferences>(STORAGE_KEYS.MAIN);
   }
 
   /**
-   * 加载偏好设置
-   * @returns {Preferences} 加载的偏好设置
+   * 保存偏好设置到缓存
+   * @param preference - 要保存的偏好设置
    */
-  private loadPreferences(): Preferences {
-    return this.loadCachedPreferences() || { ...defaultPreferences };
+  private saveToCache(preference: Preferences) {
+    this.cache.setItem(STORAGE_KEYS.MAIN, preference);
+    this.cache.setItem(STORAGE_KEYS.LOCALE, preference.app.locale);
+    this.cache.setItem(STORAGE_KEYS.THEME, preference.theme.mode);
   }
 
   /**
-   * 监听状态和系统偏好设置的变化
+   * 监听状态和系统偏好设置的变化
    */
   private setupWatcher() {
     if (this.isInitialized) {
@@ -187,6 +186,7 @@ class PreferenceManager {
     // 监听断点,判断是否移动端
     const breakpoints = useBreakpoints(breakpointsTailwind);
     const isMobile = breakpoints.smaller('md');
+
     watch(
       () => isMobile.value,
       (val) => {
@@ -201,12 +201,13 @@ class PreferenceManager {
     window
       .matchMedia('(prefers-color-scheme: dark)')
       .addEventListener('change', ({ matches: isDark }) => {
-        // 如果偏好设置中主题模式为auto,则跟随系统更新
+        // 仅在自动模式下跟随系统主题
         if (this.state.theme.mode === 'auto') {
+          // 先应用实际的主题
           this.updatePreferences({
             theme: { mode: isDark ? 'dark' : 'light' },
           });
-          // 恢复为auto模式
+          // 恢复为 auto 模式,保持跟随系统的状态
           this.updatePreferences({
             theme: { mode: 'auto' },
           });
@@ -216,19 +217,17 @@ class PreferenceManager {
 
   /**
    * 更新页面颜色模式(灰色、色弱)
-   * @param preference
+   * @param preference - 偏好设置
    */
   private updateColorMode(preference: Preferences) {
-    if (preference.app) {
-      const { colorGrayMode, colorWeakMode } = preference.app;
-      const dom = document.documentElement;
-      const COLOR_WEAK = 'invert-mode';
-      const COLOR_GRAY = 'grayscale-mode';
-      dom.classList.toggle(COLOR_WEAK, colorWeakMode);
-      dom.classList.toggle(COLOR_GRAY, colorGrayMode);
-    }
+    const { colorGrayMode, colorWeakMode } = preference.app;
+    const dom = document.documentElement;
+
+    dom.classList.toggle('invert-mode', colorWeakMode);
+    dom.classList.toggle('grayscale-mode', colorGrayMode);
   }
 }
 
 const preferencesManager = new PreferenceManager();
+
 export { PreferenceManager, preferencesManager };

+ 2 - 2
packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue

@@ -19,7 +19,7 @@ import { computed, ref } from 'vue';
 import { Copy, Pin, PinOff, RotateCw } from '@vben/icons';
 import { $t, loadLocaleMessages } from '@vben/locales';
 import {
-  clearPreferencesCache,
+  clearCache,
   preferences,
   resetPreferences,
   usePreferences,
@@ -228,7 +228,7 @@ async function handleCopy() {
 
 async function handleClearCache() {
   resetPreferences();
-  clearPreferencesCache();
+  clearCache();
   emit('clearPreferencesAndLogout');
 }