From 26b6109ca08a28c37355474bf8593f2e2b741ef6 Mon Sep 17 00:00:00 2001 From: vben Date: Wed, 25 Nov 2020 21:26:10 +0800 Subject: [PATCH] feat: add permissionCacheType setting --- src/enums/cacheEnum.ts | 5 ++ src/hooks/core/useTimeout.ts | 2 +- src/hooks/setting/useTransitionSetting.ts | 2 +- src/hooks/web/useLockPage.ts | 2 +- src/layouts/default/multitabs/index.less | 7 --- src/layouts/default/multitabs/index.tsx | 49 +++++-------------- src/layouts/default/multitabs/useAffixTabs.ts | 35 +++++++++++++ .../default/multitabs/useTabDropdown.ts | 1 + src/router/guard/index.ts | 2 +- src/settings/projectSetting.ts | 6 ++- src/setup/App.ts | 18 +++---- src/store/modules/app.ts | 2 +- src/store/modules/user.ts | 40 +++++++++------ src/types/config.d.ts | 4 +- src/utils/helper/persistent.ts | 35 ++++++++----- 15 files changed, 123 insertions(+), 87 deletions(-) create mode 100644 src/layouts/default/multitabs/useAffixTabs.ts diff --git a/src/enums/cacheEnum.ts b/src/enums/cacheEnum.ts index 77cfdbdd..4e6f43ec 100644 --- a/src/enums/cacheEnum.ts +++ b/src/enums/cacheEnum.ts @@ -18,3 +18,8 @@ export const BASE_LOCAL_CACHE_KEY = 'LOCAL__CACHE__KEY__'; // base global session key export const BASE_SESSION_CACHE_KEY = 'SESSION__CACHE__KEY__'; + +export enum CacheTypeEnum { + SESSION, + LOCAL, +} diff --git a/src/hooks/core/useTimeout.ts b/src/hooks/core/useTimeout.ts index 4fcc19a8..119cbe7e 100644 --- a/src/hooks/core/useTimeout.ts +++ b/src/hooks/core/useTimeout.ts @@ -23,7 +23,7 @@ export function useTimeoutFn(handle: Fn, wait: number) { export function useTimeoutRef(wait: number) { const readyRef = ref(false); - let timer: ReturnType | undefined; + let timer: TimeoutHandle; function stop(): void { readyRef.value = false; timer && window.clearTimeout(timer); diff --git a/src/hooks/setting/useTransitionSetting.ts b/src/hooks/setting/useTransitionSetting.ts index 17039f8b..ce7f759e 100644 --- a/src/hooks/setting/useTransitionSetting.ts +++ b/src/hooks/setting/useTransitionSetting.ts @@ -7,7 +7,7 @@ import { appStore } from '/@/store/modules/app'; export function useTransitionSetting() { const getTransitionSetting = computed(() => appStore.getProjectConfig.transitionSetting); - const getEnableTransition = computed(() => unref(getTransitionSetting).enable); + const getEnableTransition = computed(() => unref(getTransitionSetting)?.enable); const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress); diff --git a/src/hooks/web/useLockPage.ts b/src/hooks/web/useLockPage.ts index 1988b4e3..c315e670 100644 --- a/src/hooks/web/useLockPage.ts +++ b/src/hooks/web/useLockPage.ts @@ -5,7 +5,7 @@ import { appStore } from '/@/store/modules/app'; import { userStore } from '/@/store/modules/user'; export function useLockPage() { - let timeId: ReturnType; + let timeId: TimeoutHandle; function clear(): void { window.clearTimeout(timeId); diff --git a/src/layouts/default/multitabs/index.less b/src/layouts/default/multitabs/index.less index 1e052ab8..ff636b0e 100644 --- a/src/layouts/default/multitabs/index.less +++ b/src/layouts/default/multitabs/index.less @@ -40,12 +40,9 @@ height: 12px; font-size: 12px; color: inherit; - visibility: hidden; transition: none; &:hover { - visibility: visible; - svg { width: 0.8em; } @@ -72,10 +69,6 @@ display: none; } - .ant-tabs-close-x { - visibility: visible; - } - svg { width: 0.7em; fill: @white; diff --git a/src/layouts/default/multitabs/index.tsx b/src/layouts/default/multitabs/index.tsx index 8b00f610..4defffd5 100644 --- a/src/layouts/default/multitabs/index.tsx +++ b/src/layouts/default/multitabs/index.tsx @@ -1,10 +1,11 @@ +import './index.less'; + import type { TabContentProps } from './tab.data'; import type { TabItem } from '/@/store/modules/tab'; import type { AppRouteRecordRaw } from '/@/router/types'; -import { defineComponent, watch, computed, unref, toRaw } from 'vue'; +import { defineComponent, watch, computed, unref } from 'vue'; import { useRouter } from 'vue-router'; -import router from '/@/router'; import { Tabs } from 'ant-design-vue'; import TabContent from './TabContent'; @@ -18,12 +19,12 @@ import { userStore } from '/@/store/modules/user'; import { closeTab } from './useTabDropdown'; import { useTabs } from '/@/hooks/web/useTabs'; +import { initAffixTabs } from './useAffixTabs'; -import './index.less'; export default defineComponent({ - name: 'MultiTabs', + name: 'MultipleTabs', setup() { - let isAddAffix = false; + initAffixTabs(); const go = useGo(); @@ -36,11 +37,6 @@ export default defineComponent({ watch( () => tabStore.getLastChangeRouteState, () => { - if (!isAddAffix) { - addAffixTabs(); - isAddAffix = true; - } - const lastChangeRoute = unref(tabStore.getLastChangeRouteState); if (!lastChangeRoute || !userStore.getTokenState) return; @@ -56,39 +52,15 @@ export default defineComponent({ } ); - /** - * @description: 过滤所有固定路由 - */ - function filterAffixTabs(routes: AppRouteRecordRaw[]) { - const tabs: TabItem[] = []; - routes && - routes.forEach((route) => { - if (route.meta && route.meta.affix) { - tabs.push(toRaw(route) as TabItem); - } - }); - return tabs; - } - - /** - * @description: 设置固定tabs - */ - function addAffixTabs(): void { - const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]); - for (const tab of affixTabs) { - tabStore.commitAddTab(tab); - } - } - // tab切换 function handleChange(activeKey: any) { activeKeyRef.value = activeKey; go(activeKey, false); } - // 关闭当前ab + // 关闭当前tab function handleEdit(targetKey: string) { - // 新增操作隐藏,目前只使用删除操作 + // Added operation to hide, currently only use delete operation const index = unref(getTabsState).findIndex( (item) => (item.fullPath || item.path) === targetKey ); @@ -107,12 +79,13 @@ export default defineComponent({ ); } + function renderTabs() { return unref(getTabsState).map((item: TabItem) => { const key = item.query ? item.fullPath : item.path; - + const closable = !(item && item.meta && item.meta.affix); return ( - + {{ tab: () => , }} diff --git a/src/layouts/default/multitabs/useAffixTabs.ts b/src/layouts/default/multitabs/useAffixTabs.ts new file mode 100644 index 00000000..24cb4bac --- /dev/null +++ b/src/layouts/default/multitabs/useAffixTabs.ts @@ -0,0 +1,35 @@ +import { toRaw } from 'vue'; +import router from '/@/router'; +import { AppRouteRecordRaw } from '/@/router/types'; +import { TabItem, tabStore } from '/@/store/modules/tab'; + +export function initAffixTabs() { + /** + * @description: Filter all fixed routes + */ + function filterAffixTabs(routes: AppRouteRecordRaw[]) { + const tabs: TabItem[] = []; + routes && + routes.forEach((route) => { + if (route.meta && route.meta.affix) { + tabs.push(toRaw(route) as TabItem); + } + }); + return tabs; + } + + /** + * @description: Set fixed tabs + */ + function addAffixTabs(): void { + const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]); + for (const tab of affixTabs) { + tabStore.commitAddTab(tab); + } + } + let isAddAffix = false; + if (!isAddAffix) { + addAffixTabs(); + isAddAffix = true; + } +} diff --git a/src/layouts/default/multitabs/useTabDropdown.ts b/src/layouts/default/multitabs/useTabDropdown.ts index bfa03503..7fb893bf 100644 --- a/src/layouts/default/multitabs/useTabDropdown.ts +++ b/src/layouts/default/multitabs/useTabDropdown.ts @@ -203,6 +203,7 @@ export function closeTab(closedTab: TabItem | AppRouteRecordRaw) { const getTabsState = computed(() => { return tabStore.getTabsState; }); + const { path } = unref(currentRoute); if (path !== closedTab.path) { // 关闭的不是激活tab diff --git a/src/router/guard/index.ts b/src/router/guard/index.ts index 6143d41d..98bf6177 100644 --- a/src/router/guard/index.ts +++ b/src/router/guard/index.ts @@ -14,9 +14,9 @@ import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel'; import { tabStore } from '/@/store/modules/tab'; +const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting(); const globSetting = useGlobSetting(); export function createGuard(router: Router) { - const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting(); let axiosCanceler: AxiosCanceler | null; if (removeAllHttpPending) { axiosCanceler = new AxiosCanceler(); diff --git a/src/settings/projectSetting.ts b/src/settings/projectSetting.ts index 6562e72e..9a4156d0 100644 --- a/src/settings/projectSetting.ts +++ b/src/settings/projectSetting.ts @@ -1,6 +1,7 @@ import type { ProjectConfig } from '/@/types/config'; import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; +import { CacheTypeEnum } from '/@/enums/cacheEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { primaryColor } from '../../build/config/lessModifyVars'; import { isProdMode } from '/@/utils/env'; @@ -13,6 +14,9 @@ const setting: ProjectConfig = { // Permission mode permissionMode: PermissionModeEnum.ROLE, + // Permission-related cache is stored in sessionStorage or localStorage + permissionCacheType: CacheTypeEnum.LOCAL, + // color // TODO Theme color themeColor: primaryColor, @@ -130,7 +134,7 @@ const setting: ProjectConfig = { openPageLoading: true, // Whether to open the top progress bar - openNProgress: true, + openNProgress: false, }, // Whether to enable KeepAlive cache is best to close during development, otherwise the cache needs to be cleared every time diff --git a/src/setup/App.ts b/src/setup/App.ts index 1028159b..3ab0db9b 100644 --- a/src/setup/App.ts +++ b/src/setup/App.ts @@ -20,6 +20,7 @@ import { } from '/@/setup/theme'; import { appStore } from '/@/store/modules/app'; +import { deepMerge } from '../utils/index'; // Used to share global app instances let app: App; @@ -50,16 +51,15 @@ export function useThemeMode(mode: ThemeModeEnum) { // Initial project configuration export function initAppConfigStore() { let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig; - if (!projCfg) { - projCfg = projectSetting; - } - const { - colorWeak, - grayMode, - headerSetting: { bgColor: headerBgColor }, - menuSetting: { bgColor }, - } = projCfg; + projCfg = deepMerge(projectSetting, projCfg || {}); + try { + const { + colorWeak, + grayMode, + headerSetting: { bgColor: headerBgColor } = {}, + menuSetting: { bgColor } = {}, + } = projCfg; // if ( // themeColor !== primaryColor && // themeColor && diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 6be45f8a..b4b6d61f 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -26,7 +26,7 @@ export interface LockInfo { isLock: boolean; } -let timeId: ReturnType; +let timeId: TimeoutHandle; const NAME = 'app'; hotModuleUnregisterModule(NAME); @Module({ dynamic: true, namespaced: true, store, name: NAME }) diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index c037681f..fe4bc975 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -11,7 +11,7 @@ import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; import { PageEnum } from '/@/enums/pageEnum'; import { RoleEnum } from '/@/enums/roleEnum'; -import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; +import { CacheTypeEnum, ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum'; import { useMessage } from '/@/hooks/web/useMessage'; @@ -19,13 +19,29 @@ import router from '/@/router'; import { loginApi, getUserInfoById } from '/@/api/sys/user'; -import { setLocal, getLocal } from '/@/utils/helper/persistent'; -// import { FULL_PAGE_NOT_FOUND_ROUTE } from '/@/router/constant'; +import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent'; +import { useProjectSetting } from '/@/hooks/setting'; export type UserInfo = Omit; const NAME = 'user'; hotModuleUnregisterModule(NAME); + +const { permissionCacheType } = useProjectSetting(); + +function getCache(key: string) { + const fn = permissionCacheType === CacheTypeEnum.LOCAL ? getLocal : getSession; + return fn(key) as T; +} + +function setCache(USER_INFO_KEY: string, info: any) { + if (!info) return; + // const fn = permissionCacheType === CacheTypeEnum.LOCAL ? setLocal : setSession; + setLocal(USER_INFO_KEY, info, true); + // TODO + setSession(USER_INFO_KEY, info, true); +} + @Module({ namespaced: true, name: NAME, dynamic: true, store }) class User extends VuexModule { // user info @@ -38,15 +54,15 @@ class User extends VuexModule { private roleListState: RoleEnum[] = []; get getUserInfoState(): UserInfo { - return this.userInfoState || (getLocal(USER_INFO_KEY) as UserInfo) || {}; + return this.userInfoState || getCache(USER_INFO_KEY) || {}; } get getTokenState(): string { - return this.tokenState || (getLocal(TOKEN_KEY) as string); + return this.tokenState || getCache(TOKEN_KEY); } get getRoleListState(): RoleEnum[] { - return this.roleListState.length > 0 ? this.roleListState : (getLocal(ROLES_KEY) as RoleEnum[]); + return this.roleListState.length > 0 ? this.roleListState : getCache(ROLES_KEY); } @Mutation @@ -59,25 +75,19 @@ class User extends VuexModule { @Mutation commitUserInfoState(info: UserInfo): void { this.userInfoState = info; - if (info) { - setLocal(USER_INFO_KEY, info, true); - } + setCache(USER_INFO_KEY, info); } @Mutation commitRoleListState(roleList: RoleEnum[]): void { this.roleListState = roleList; - if (roleList) { - setLocal(ROLES_KEY, roleList, true); - } + setCache(ROLES_KEY, roleList); } @Mutation commitTokenState(info: string): void { this.tokenState = info; - if (info) { - setLocal(TOKEN_KEY, info, true); - } + setCache(TOKEN_KEY, info); } /** diff --git a/src/types/config.d.ts b/src/types/config.d.ts index 2a80b23c..43d465bd 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -1,6 +1,6 @@ -// 左侧菜单, 顶部菜单 import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; +import { CacheTypeEnum } from '/@/enums/cacheEnum'; import type { LocaleType } from '/@/locales/types'; export interface MenuSetting { @@ -76,6 +76,8 @@ export interface TransitionSetting { export interface ProjectConfig { locale: LocaleSetting; + permissionCacheType: CacheTypeEnum; + // 是否显示配置按钮 showSettingButton: boolean; // 权限模式 diff --git a/src/utils/helper/persistent.ts b/src/utils/helper/persistent.ts index 62449d1c..46f99c81 100644 --- a/src/utils/helper/persistent.ts +++ b/src/utils/helper/persistent.ts @@ -29,8 +29,12 @@ function initCache() { initCache(); export function setLocal(key: string, value: any, immediate = false) { - cacheStore.local[BASE_LOCAL_CACHE_KEY] = cacheStore.local[BASE_LOCAL_CACHE_KEY] || {}; + const local = ls.get(BASE_LOCAL_CACHE_KEY)?.[BASE_LOCAL_CACHE_KEY] || {}; + + cacheStore.local[BASE_LOCAL_CACHE_KEY] = + { ...local, ...cacheStore.local[BASE_LOCAL_CACHE_KEY] } || {}; cacheStore.local[BASE_LOCAL_CACHE_KEY][key] = value; + if (immediate) { ls.set(BASE_LOCAL_CACHE_KEY, cacheStore.local); } @@ -50,16 +54,21 @@ export function removeLocal(key: string) { } } -export function clearLocal() { +export function clearLocal(immediate = false) { cacheStore.local = {}; + immediate && ls.remove(BASE_LOCAL_CACHE_KEY); } export function setSession(key: string, value: any, immediate = false) { - cacheStore.session[BASE_SESSION_CACHE_KEY] = cacheStore.session[BASE_SESSION_CACHE_KEY] || {}; + const session = ss.get(BASE_SESSION_CACHE_KEY)?.[BASE_SESSION_CACHE_KEY] || {}; + + cacheStore.session[BASE_SESSION_CACHE_KEY] = + { ...session, ...cacheStore.session[BASE_SESSION_CACHE_KEY] } || {}; + cacheStore.session[BASE_SESSION_CACHE_KEY][key] = value; + if (immediate) { - const cache = cacheStore.session; - ss.set(BASE_SESSION_CACHE_KEY, cache); + ss.set(BASE_SESSION_CACHE_KEY, cacheStore.session); } } @@ -77,8 +86,9 @@ export function getSession(key: string): T | null { } } -export function clearSession() { +export function clearSession(immediate = false) { cacheStore.session = {}; + immediate && ss.remove(BASE_SESSION_CACHE_KEY); } export function clearAll() { @@ -86,14 +96,17 @@ export function clearAll() { clearSession(); } +export function persistentCache() { + const localCache = cacheStore.local; + const sessionCache = cacheStore.session; + ls.set(BASE_LOCAL_CACHE_KEY, localCache); + ss.set(BASE_SESSION_CACHE_KEY, sessionCache); +} + (() => { // /** Write to local before closing window */ window.addEventListener('beforeunload', () => { - const localCache = cacheStore.local; - const sessionCache = cacheStore.session; - - ls.set(BASE_LOCAL_CACHE_KEY, localCache); - ss.set(BASE_SESSION_CACHE_KEY, sessionCache); + persistentCache(); }); function storageChange(e: any) { -- GitLab