diff --git a/README.md b/README.md index 06fa86de8..8aae93e96 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Soybean Admin 是一个基于 Vue3、Vite、TypeScript、Naive UI 的免费中 - [x] 引入ECharts替换AntV G2Plot - [x] 图表示例:ECharts、AntV G2 - [x] 多页签:支持query、hash等参数,同一页面支持多个Tab -- [ ] 缓存主题配置 +- [x] 缓存主题配置 - [ ] 添加锁屏组件、全局Iframe组件 - [ ] 示例页面完善 - [ ] 表单、表格示例 diff --git a/src/App.vue b/src/App.vue index eff8cb3a5..49b41aea5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -15,10 +15,12 @@ diff --git a/src/composables/events.ts b/src/composables/events.ts new file mode 100644 index 000000000..886ab305b --- /dev/null +++ b/src/composables/events.ts @@ -0,0 +1,14 @@ +import { useEventListener } from '@vueuse/core'; +import { useThemeStore, useTabStore } from '@/store'; + +/** 全局事件 */ +export function useGlobalEvents() { + const theme = useThemeStore(); + const tab = useTabStore(); + + /** 页面离开时缓存多页签数据 */ + useEventListener(window, 'beforeunload', () => { + theme.cacheThemeSettings(); + tab.cacheTabRoutes(); + }); +} diff --git a/src/composables/index.ts b/src/composables/index.ts index c5107972e..274f90e7d 100644 --- a/src/composables/index.ts +++ b/src/composables/index.ts @@ -1,4 +1,5 @@ export * from './system'; export * from './router'; export * from './layout'; +export * from './events'; export * from './echarts'; diff --git a/src/enum/common.ts b/src/enum/common.ts index 49b3f7326..e33c896f8 100644 --- a/src/enum/common.ts +++ b/src/enum/common.ts @@ -15,6 +15,8 @@ export enum EnumStorageKey { 'refresh-token' = '__REFRESH_TOKEN__', /** 用户信息 */ 'user-info' = '__USER_INFO__', + /** 主题配置 */ + 'theme-settings' = '__THEME_SETTINGS__', /** 多页签路由信息 */ 'multi-tab-routes' = '__MULTI_TAB_ROUTES__' } diff --git a/src/layouts/common/GlobalHeader/components/SettingButton.vue b/src/layouts/common/GlobalHeader/components/SettingButton.vue new file mode 100644 index 000000000..22cf1d04f --- /dev/null +++ b/src/layouts/common/GlobalHeader/components/SettingButton.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/src/layouts/common/GlobalHeader/components/index.ts b/src/layouts/common/GlobalHeader/components/index.ts index 3ddf1d03c..6eed72990 100644 --- a/src/layouts/common/GlobalHeader/components/index.ts +++ b/src/layouts/common/GlobalHeader/components/index.ts @@ -6,5 +6,16 @@ import FullScreen from './FullScreen.vue'; import ThemeMode from './ThemeMode.vue'; import UserAvatar from './UserAvatar.vue'; import SystemMessage from './SystemMessage.vue'; +import SettingButton from './SettingButton.vue'; -export { MenuCollapse, GlobalBreadcrumb, HeaderMenu, GithubSite, FullScreen, ThemeMode, UserAvatar, SystemMessage }; +export { + MenuCollapse, + GlobalBreadcrumb, + HeaderMenu, + GithubSite, + FullScreen, + ThemeMode, + UserAvatar, + SystemMessage, + SettingButton +}; diff --git a/src/layouts/common/GlobalHeader/index.vue b/src/layouts/common/GlobalHeader/index.vue index 2fdf0d76e..c25acdde5 100644 --- a/src/layouts/common/GlobalHeader/index.vue +++ b/src/layouts/common/GlobalHeader/index.vue @@ -12,6 +12,7 @@ + @@ -29,7 +30,8 @@ import { FullScreen, ThemeMode, UserAvatar, - SystemMessage + SystemMessage, + SettingButton } from './components'; interface Props { @@ -44,6 +46,8 @@ interface Props { defineProps(); const theme = useThemeStore(); + +const isProd = import.meta.env.PROD; diff --git a/src/layouts/common/SettingDrawer/index.vue b/src/layouts/common/SettingDrawer/index.vue index 31657c31f..0e46a133a 100644 --- a/src/layouts/common/SettingDrawer/index.vue +++ b/src/layouts/common/SettingDrawer/index.vue @@ -9,7 +9,7 @@ - + diff --git a/src/store/modules/tab/helpers.ts b/src/store/modules/tab/helpers.ts index 1eccf9a92..5347a2347 100644 --- a/src/store/modules/tab/helpers.ts +++ b/src/store/modules/tab/helpers.ts @@ -1,4 +1,6 @@ import type { RouteRecordNormalized, RouteLocationNormalizedLoaded } from 'vue-router'; +import { EnumStorageKey } from '@/enum'; +import { setLocal, getLocal } from '@/utils'; /** * 根据vue路由获取tab路由 @@ -55,3 +57,30 @@ function hasFullPath( ): route is RouteLocationNormalizedLoaded { return Boolean((route as RouteLocationNormalizedLoaded).fullPath); } + +/** 缓存多页签数据 */ +export function setTabRoutes(data: GlobalTabRoute[]) { + setLocal(EnumStorageKey['multi-tab-routes'], data); +} + +/** 获取缓存的多页签数据 */ +export function getTabRoutes() { + const routes: GlobalTabRoute[] = []; + const data = getLocal(EnumStorageKey['multi-tab-routes']); + if (data) { + const defaultTabRoutes = data.map(item => ({ + ...item, + scrollPosition: { + left: 0, + top: 0 + } + })); + routes.push(...defaultTabRoutes); + } + return routes; +} + +/** 清空多页签数据 */ +export function clearTabRoutes() { + setTabRoutes([]); +} diff --git a/src/store/modules/tab/index.ts b/src/store/modules/tab/index.ts index 118989444..ce8056e14 100644 --- a/src/store/modules/tab/index.ts +++ b/src/store/modules/tab/index.ts @@ -1,9 +1,16 @@ import type { Router, RouteLocationNormalizedLoaded } from 'vue-router'; import { defineStore } from 'pinia'; import { useRouterPush } from '@/composables'; -import { getTabRoutes, clearTabRoutes } from '@/utils'; import { useThemeStore } from '../theme'; -import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes, getIndexInTabRoutesByRouteName } from './helpers'; +import { + getTabRouteByVueRoute, + isInTabRoutes, + getIndexInTabRoutes, + getIndexInTabRoutesByRouteName, + setTabRoutes, + getTabRoutes, + clearTabRoutes +} from './helpers'; interface TabState { /** 多页签数据 */ @@ -43,6 +50,10 @@ export const useTabStore = defineStore('tab-store', { clearTabRoutes(); this.$reset(); }, + /** 缓存页签路由数据 */ + cacheTabRoutes() { + setTabRoutes(this.tabs); + }, /** * 设置当前路由对应的页签为激活状态 * @param fullPath - 路由fullPath diff --git a/src/store/modules/theme/helpers.ts b/src/store/modules/theme/helpers.ts index 1614c5780..ac0b9f737 100644 --- a/src/store/modules/theme/helpers.ts +++ b/src/store/modules/theme/helpers.ts @@ -1,10 +1,18 @@ import type { GlobalThemeOverrides } from 'naive-ui'; import { cloneDeep } from 'lodash-es'; import { themeSetting } from '@/settings'; -import { getThemeColor, getColorPalette, addColorAlpha } from '@/utils'; +import { EnumStorageKey } from '@/enum'; +import { getThemeColor, getColorPalette, addColorAlpha, setLocal, getLocal, removeLocal } from '@/utils'; + +/** 初始化主题配置 */ +export function initThemeSettings() { + const isProd = import.meta.env.PROD; + // 生产环境才缓存主题配置,本地开发实时调整配置更改配置的json + const storageSettings = getThemeSettings(); + if (isProd && storageSettings) { + return storageSettings; + } -/** 获取主题配置 */ -export function getThemeSettings() { const themeColor = getThemeColor() || themeSetting.themeColor; const info = themeSetting.isCustomizeInfoColor ? themeSetting.otherColor.info : getColorPalette(themeColor, 7); const otherColor = { ...themeSetting.otherColor, info }; @@ -70,3 +78,18 @@ export function getNaiveThemeOverrides(colors: Record): Globa } }; } + +/** 获取缓存中的主题配置 */ +function getThemeSettings() { + return getLocal(EnumStorageKey['theme-settings']); +} + +/** 获取缓存中的主题配置 */ +export function setThemeSettings(settings: Theme.Setting) { + return setLocal(EnumStorageKey['theme-settings'], settings); +} + +/** 清除缓存配置 */ +export function clearThemeSettings() { + removeLocal(EnumStorageKey['theme-settings']); +} diff --git a/src/store/modules/theme/index.ts b/src/store/modules/theme/index.ts index 98849056d..70e3f8182 100644 --- a/src/store/modules/theme/index.ts +++ b/src/store/modules/theme/index.ts @@ -1,11 +1,11 @@ import { defineStore } from 'pinia'; import { darkTheme } from 'naive-ui'; -import { getThemeSettings, getNaiveThemeOverrides } from './helpers'; +import { initThemeSettings, getNaiveThemeOverrides, setThemeSettings, clearThemeSettings } from './helpers'; type ThemeState = Theme.Setting; export const useThemeStore = defineStore('theme-store', { - state: (): ThemeState => getThemeSettings(), + state: (): ThemeState => initThemeSettings(), getters: { /** naiveUI的主题配置 */ naiveThemeOverrides(state) { @@ -24,8 +24,16 @@ export const useThemeStore = defineStore('theme-store', { actions: { /** 重置theme状态 */ resetThemeStore() { + clearThemeSettings(); this.$reset(); }, + /** 缓存主题配置 */ + cacheThemeSettings() { + const isProd = import.meta.env.PROD; + if (isProd) { + setThemeSettings(this.$state); + } + }, /** 设置暗黑模式 */ setDarkMode(darkMode: boolean) { this.darkMode = darkMode; diff --git a/src/utils/router/index.ts b/src/utils/router/index.ts index 72b575bf2..f74f45384 100644 --- a/src/utils/router/index.ts +++ b/src/utils/router/index.ts @@ -4,5 +4,4 @@ export * from './cache'; export * from './auth'; export * from './menu'; export * from './breadcrumb'; -export * from './tab'; export * from './regexp'; diff --git a/src/utils/router/tab.ts b/src/utils/router/tab.ts deleted file mode 100644 index 986cccc59..000000000 --- a/src/utils/router/tab.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { EnumStorageKey } from '@/enum'; -import { setLocal, getLocal } from '../storage'; - -/** 缓存多页签数据 */ -export function setTabRoutes(data: GlobalTabRoute[]) { - setLocal(EnumStorageKey['multi-tab-routes'], data); -} - -/** 获取缓存的多页签数据 */ -export function getTabRoutes() { - const routes: GlobalTabRoute[] = []; - const data = getLocal(EnumStorageKey['multi-tab-routes']); - if (data) { - const defaultTabRoutes = data.map(item => ({ - ...item, - scrollPosition: { - left: 0, - top: 0 - } - })); - routes.push(...defaultTabRoutes); - } - return routes; -} - -/** 清空多页签数据 */ -export function clearTabRoutes() { - setTabRoutes([]); -}