import { effectScope, nextTick, onScopeDispose, ref, watch } from 'vue'; import { defineStore } from 'pinia'; import { breakpointsTailwind, useBreakpoints, useEventListener, useTitle } from '@vueuse/core'; import { useBoolean } from '@sa/hooks'; import { SetupStoreId } from '@/enum'; import { router } from '@/router'; import { $t, setLocale } from '@/locales'; import { setDayjsLocale } from '@/locales/dayjs'; import { localStg } from '@/utils/storage'; import { useRouteStore } from '../route'; import { useTabStore } from '../tab'; import { useThemeStore } from '../theme'; export const useAppStore = defineStore(SetupStoreId.App, () => { const themeStore = useThemeStore(); const routeStore = useRouteStore(); const tabStore = useTabStore(); const scope = effectScope(); const breakpoints = useBreakpoints(breakpointsTailwind); const { bool: themeDrawerVisible, setTrue: openThemeDrawer, setFalse: closeThemeDrawer } = useBoolean(); const { bool: reloadFlag, setBool: setReloadFlag } = useBoolean(true); const { bool: fullContent, toggle: toggleFullContent } = useBoolean(); const { bool: contentXScrollable, setBool: setContentXScrollable } = useBoolean(); const { bool: siderCollapse, setBool: setSiderCollapse, toggle: toggleSiderCollapse } = useBoolean(); const { bool: mixSiderFixed, setBool: setMixSiderFixed, toggle: toggleMixSiderFixed } = useBoolean(localStg.get('mixSiderFixed') === 'Y'); /** Is mobile layout */ const isMobile = breakpoints.smaller('sm'); /** * Reload page * * @param duration Duration time */ async function reloadPage(duration = 300) { setReloadFlag(false); const d = themeStore.page.animate ? duration : 40; await new Promise(resolve => { setTimeout(resolve, d); }); setReloadFlag(true); if (themeStore.resetCacheStrategy === 'refresh') { routeStore.resetRouteCache(); } } const locale = ref(localStg.get('lang') || 'zh-CN'); const localeOptions: App.I18n.LangOption[] = [ { label: '中文', key: 'zh-CN' }, { label: 'English', key: 'en-US' } ]; function changeLocale(lang: App.I18n.LangType) { locale.value = lang; setLocale(lang); localStg.set('lang', lang); } /** Update document title by locale */ function updateDocumentTitleByLocale() { const { i18nKey, title } = router.currentRoute.value.meta; const documentTitle = i18nKey ? $t(i18nKey) : title; useTitle(documentTitle); } function init() { setDayjsLocale(locale.value); } // watch store scope.run(() => { // watch isMobile, if is mobile, collapse sider watch( isMobile, newValue => { if (newValue) { // backup theme setting before is mobile localStg.set('backupThemeSettingBeforeIsMobile', { layout: themeStore.layout.mode, siderCollapse: siderCollapse.value }); themeStore.setThemeLayout('vertical'); setSiderCollapse(true); } else { // when is not mobile, recover the backup theme setting const backup = localStg.get('backupThemeSettingBeforeIsMobile'); if (backup) { nextTick(() => { themeStore.setThemeLayout(backup.layout); setSiderCollapse(backup.siderCollapse); localStg.remove('backupThemeSettingBeforeIsMobile'); }); } } }, { immediate: true } ); // watch locale watch(locale, () => { // update document title by locale updateDocumentTitleByLocale(); // update global menus by locale routeStore.updateGlobalMenusByLocale(); // update tabs by locale tabStore.updateTabsByLocale(); // set dayjs locale setDayjsLocale(locale.value); }); }); // cache mixSiderFixed useEventListener(window, 'beforeunload', () => { localStg.set('mixSiderFixed', mixSiderFixed.value ? 'Y' : 'N'); }); /** On scope dispose */ onScopeDispose(() => { scope.stop(); }); // init init(); return { isMobile, reloadFlag, reloadPage, fullContent, locale, localeOptions, changeLocale, themeDrawerVisible, openThemeDrawer, closeThemeDrawer, toggleFullContent, contentXScrollable, setContentXScrollable, siderCollapse, setSiderCollapse, toggleSiderCollapse, mixSiderFixed, setMixSiderFixed, toggleMixSiderFixed }; });