Commit 26b6109ca08a28c37355474bf8593f2e2b741ef6

Authored by vben
1 parent 6e03e050

feat: add permissionCacheType setting

src/enums/cacheEnum.ts
... ... @@ -18,3 +18,8 @@ export const BASE_LOCAL_CACHE_KEY = 'LOCAL__CACHE__KEY__';
18 18  
19 19 // base global session key
20 20 export const BASE_SESSION_CACHE_KEY = 'SESSION__CACHE__KEY__';
  21 +
  22 +export enum CacheTypeEnum {
  23 + SESSION,
  24 + LOCAL,
  25 +}
... ...
src/hooks/core/useTimeout.ts
... ... @@ -23,7 +23,7 @@ export function useTimeoutFn(handle: Fn<any>, wait: number) {
23 23 export function useTimeoutRef(wait: number) {
24 24 const readyRef = ref(false);
25 25  
26   - let timer: ReturnType<typeof setTimeout> | undefined;
  26 + let timer: TimeoutHandle;
27 27 function stop(): void {
28 28 readyRef.value = false;
29 29 timer && window.clearTimeout(timer);
... ...
src/hooks/setting/useTransitionSetting.ts
... ... @@ -7,7 +7,7 @@ import { appStore } from &#39;/@/store/modules/app&#39;;
7 7 export function useTransitionSetting() {
8 8 const getTransitionSetting = computed(() => appStore.getProjectConfig.transitionSetting);
9 9  
10   - const getEnableTransition = computed(() => unref(getTransitionSetting).enable);
  10 + const getEnableTransition = computed(() => unref(getTransitionSetting)?.enable);
11 11  
12 12 const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress);
13 13  
... ...
src/hooks/web/useLockPage.ts
... ... @@ -5,7 +5,7 @@ import { appStore } from &#39;/@/store/modules/app&#39;;
5 5 import { userStore } from '/@/store/modules/user';
6 6  
7 7 export function useLockPage() {
8   - let timeId: ReturnType<typeof setTimeout>;
  8 + let timeId: TimeoutHandle;
9 9  
10 10 function clear(): void {
11 11 window.clearTimeout(timeId);
... ...
src/layouts/default/multitabs/index.less
... ... @@ -40,12 +40,9 @@
40 40 height: 12px;
41 41 font-size: 12px;
42 42 color: inherit;
43   - visibility: hidden;
44 43 transition: none;
45 44  
46 45 &:hover {
47   - visibility: visible;
48   -
49 46 svg {
50 47 width: 0.8em;
51 48 }
... ... @@ -72,10 +69,6 @@
72 69 display: none;
73 70 }
74 71  
75   - .ant-tabs-close-x {
76   - visibility: visible;
77   - }
78   -
79 72 svg {
80 73 width: 0.7em;
81 74 fill: @white;
... ...
src/layouts/default/multitabs/index.tsx
  1 +import './index.less';
  2 +
1 3 import type { TabContentProps } from './tab.data';
2 4 import type { TabItem } from '/@/store/modules/tab';
3 5 import type { AppRouteRecordRaw } from '/@/router/types';
4 6  
5   -import { defineComponent, watch, computed, unref, toRaw } from 'vue';
  7 +import { defineComponent, watch, computed, unref } from 'vue';
6 8 import { useRouter } from 'vue-router';
7   -import router from '/@/router';
8 9  
9 10 import { Tabs } from 'ant-design-vue';
10 11 import TabContent from './TabContent';
... ... @@ -18,12 +19,12 @@ import { userStore } from &#39;/@/store/modules/user&#39;;
18 19  
19 20 import { closeTab } from './useTabDropdown';
20 21 import { useTabs } from '/@/hooks/web/useTabs';
  22 +import { initAffixTabs } from './useAffixTabs';
21 23  
22   -import './index.less';
23 24 export default defineComponent({
24   - name: 'MultiTabs',
  25 + name: 'MultipleTabs',
25 26 setup() {
26   - let isAddAffix = false;
  27 + initAffixTabs();
27 28  
28 29 const go = useGo();
29 30  
... ... @@ -36,11 +37,6 @@ export default defineComponent({
36 37 watch(
37 38 () => tabStore.getLastChangeRouteState,
38 39 () => {
39   - if (!isAddAffix) {
40   - addAffixTabs();
41   - isAddAffix = true;
42   - }
43   -
44 40 const lastChangeRoute = unref(tabStore.getLastChangeRouteState);
45 41  
46 42 if (!lastChangeRoute || !userStore.getTokenState) return;
... ... @@ -56,39 +52,15 @@ export default defineComponent({
56 52 }
57 53 );
58 54  
59   - /**
60   - * @description: 过滤所有固定路由
61   - */
62   - function filterAffixTabs(routes: AppRouteRecordRaw[]) {
63   - const tabs: TabItem[] = [];
64   - routes &&
65   - routes.forEach((route) => {
66   - if (route.meta && route.meta.affix) {
67   - tabs.push(toRaw(route) as TabItem);
68   - }
69   - });
70   - return tabs;
71   - }
72   -
73   - /**
74   - * @description: 设置固定tabs
75   - */
76   - function addAffixTabs(): void {
77   - const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]);
78   - for (const tab of affixTabs) {
79   - tabStore.commitAddTab(tab);
80   - }
81   - }
82   -
83 55 // tab切换
84 56 function handleChange(activeKey: any) {
85 57 activeKeyRef.value = activeKey;
86 58 go(activeKey, false);
87 59 }
88 60  
89   - // 关闭当前ab
  61 + // 关闭当前tab
90 62 function handleEdit(targetKey: string) {
91   - // 新增操作隐藏,目前只使用删除操作
  63 + // Added operation to hide, currently only use delete operation
92 64 const index = unref(getTabsState).findIndex(
93 65 (item) => (item.fullPath || item.path) === targetKey
94 66 );
... ... @@ -107,12 +79,13 @@ export default defineComponent({
107 79 </span>
108 80 );
109 81 }
  82 +
110 83 function renderTabs() {
111 84 return unref(getTabsState).map((item: TabItem) => {
112 85 const key = item.query ? item.fullPath : item.path;
113   -
  86 + const closable = !(item && item.meta && item.meta.affix);
114 87 return (
115   - <Tabs.TabPane key={key} closable={!(item && item.meta && item.meta.affix)}>
  88 + <Tabs.TabPane key={key} closable={closable}>
116 89 {{
117 90 tab: () => <TabContent tabItem={item} />,
118 91 }}
... ...
src/layouts/default/multitabs/useAffixTabs.ts 0 → 100644
  1 +import { toRaw } from 'vue';
  2 +import router from '/@/router';
  3 +import { AppRouteRecordRaw } from '/@/router/types';
  4 +import { TabItem, tabStore } from '/@/store/modules/tab';
  5 +
  6 +export function initAffixTabs() {
  7 + /**
  8 + * @description: Filter all fixed routes
  9 + */
  10 + function filterAffixTabs(routes: AppRouteRecordRaw[]) {
  11 + const tabs: TabItem[] = [];
  12 + routes &&
  13 + routes.forEach((route) => {
  14 + if (route.meta && route.meta.affix) {
  15 + tabs.push(toRaw(route) as TabItem);
  16 + }
  17 + });
  18 + return tabs;
  19 + }
  20 +
  21 + /**
  22 + * @description: Set fixed tabs
  23 + */
  24 + function addAffixTabs(): void {
  25 + const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as AppRouteRecordRaw[]);
  26 + for (const tab of affixTabs) {
  27 + tabStore.commitAddTab(tab);
  28 + }
  29 + }
  30 + let isAddAffix = false;
  31 + if (!isAddAffix) {
  32 + addAffixTabs();
  33 + isAddAffix = true;
  34 + }
  35 +}
... ...
src/layouts/default/multitabs/useTabDropdown.ts
... ... @@ -203,6 +203,7 @@ export function closeTab(closedTab: TabItem | AppRouteRecordRaw) {
203 203 const getTabsState = computed(() => {
204 204 return tabStore.getTabsState;
205 205 });
  206 +
206 207 const { path } = unref(currentRoute);
207 208 if (path !== closedTab.path) {
208 209 // 关闭的不是激活tab
... ...
src/router/guard/index.ts
... ... @@ -14,9 +14,9 @@ import { AxiosCanceler } from &#39;/@/utils/http/axios/axiosCancel&#39;;
14 14  
15 15 import { tabStore } from '/@/store/modules/tab';
16 16  
  17 +const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
17 18 const globSetting = useGlobSetting();
18 19 export function createGuard(router: Router) {
19   - const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
20 20 let axiosCanceler: AxiosCanceler | null;
21 21 if (removeAllHttpPending) {
22 22 axiosCanceler = new AxiosCanceler();
... ...
src/settings/projectSetting.ts
1 1 import type { ProjectConfig } from '/@/types/config';
2 2  
3 3 import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
  4 +import { CacheTypeEnum } from '/@/enums/cacheEnum';
4 5 import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
5 6 import { primaryColor } from '../../build/config/lessModifyVars';
6 7 import { isProdMode } from '/@/utils/env';
... ... @@ -13,6 +14,9 @@ const setting: ProjectConfig = {
13 14 // Permission mode
14 15 permissionMode: PermissionModeEnum.ROLE,
15 16  
  17 + // Permission-related cache is stored in sessionStorage or localStorage
  18 + permissionCacheType: CacheTypeEnum.LOCAL,
  19 +
16 20 // color
17 21 // TODO Theme color
18 22 themeColor: primaryColor,
... ... @@ -130,7 +134,7 @@ const setting: ProjectConfig = {
130 134 openPageLoading: true,
131 135  
132 136 // Whether to open the top progress bar
133   - openNProgress: true,
  137 + openNProgress: false,
134 138 },
135 139  
136 140 // Whether to enable KeepAlive cache is best to close during development, otherwise the cache needs to be cleared every time
... ...
src/setup/App.ts
... ... @@ -20,6 +20,7 @@ import {
20 20 } from '/@/setup/theme';
21 21  
22 22 import { appStore } from '/@/store/modules/app';
  23 +import { deepMerge } from '../utils/index';
23 24  
24 25 // Used to share global app instances
25 26 let app: App;
... ... @@ -50,16 +51,15 @@ export function useThemeMode(mode: ThemeModeEnum) {
50 51 // Initial project configuration
51 52 export function initAppConfigStore() {
52 53 let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig;
53   - if (!projCfg) {
54   - projCfg = projectSetting;
55   - }
56   - const {
57   - colorWeak,
58   - grayMode,
59   - headerSetting: { bgColor: headerBgColor },
60   - menuSetting: { bgColor },
61   - } = projCfg;
  54 + projCfg = deepMerge(projectSetting, projCfg || {});
  55 +
62 56 try {
  57 + const {
  58 + colorWeak,
  59 + grayMode,
  60 + headerSetting: { bgColor: headerBgColor } = {},
  61 + menuSetting: { bgColor } = {},
  62 + } = projCfg;
63 63 // if (
64 64 // themeColor !== primaryColor &&
65 65 // themeColor &&
... ...
src/store/modules/app.ts
... ... @@ -26,7 +26,7 @@ export interface LockInfo {
26 26 isLock: boolean;
27 27 }
28 28  
29   -let timeId: ReturnType<typeof setTimeout>;
  29 +let timeId: TimeoutHandle;
30 30 const NAME = 'app';
31 31 hotModuleUnregisterModule(NAME);
32 32 @Module({ dynamic: true, namespaced: true, store, name: NAME })
... ...
src/store/modules/user.ts
... ... @@ -11,7 +11,7 @@ import { hotModuleUnregisterModule } from &#39;/@/utils/helper/vuexHelper&#39;;
11 11  
12 12 import { PageEnum } from '/@/enums/pageEnum';
13 13 import { RoleEnum } from '/@/enums/roleEnum';
14   -import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
  14 +import { CacheTypeEnum, ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
15 15  
16 16 import { useMessage } from '/@/hooks/web/useMessage';
17 17  
... ... @@ -19,13 +19,29 @@ import router from &#39;/@/router&#39;;
19 19  
20 20 import { loginApi, getUserInfoById } from '/@/api/sys/user';
21 21  
22   -import { setLocal, getLocal } from '/@/utils/helper/persistent';
23   -// import { FULL_PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
  22 +import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent';
  23 +import { useProjectSetting } from '/@/hooks/setting';
24 24  
25 25 export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>;
26 26  
27 27 const NAME = 'user';
28 28 hotModuleUnregisterModule(NAME);
  29 +
  30 +const { permissionCacheType } = useProjectSetting();
  31 +
  32 +function getCache<T>(key: string) {
  33 + const fn = permissionCacheType === CacheTypeEnum.LOCAL ? getLocal : getSession;
  34 + return fn(key) as T;
  35 +}
  36 +
  37 +function setCache(USER_INFO_KEY: string, info: any) {
  38 + if (!info) return;
  39 + // const fn = permissionCacheType === CacheTypeEnum.LOCAL ? setLocal : setSession;
  40 + setLocal(USER_INFO_KEY, info, true);
  41 + // TODO
  42 + setSession(USER_INFO_KEY, info, true);
  43 +}
  44 +
29 45 @Module({ namespaced: true, name: NAME, dynamic: true, store })
30 46 class User extends VuexModule {
31 47 // user info
... ... @@ -38,15 +54,15 @@ class User extends VuexModule {
38 54 private roleListState: RoleEnum[] = [];
39 55  
40 56 get getUserInfoState(): UserInfo {
41   - return this.userInfoState || (getLocal(USER_INFO_KEY) as UserInfo) || {};
  57 + return this.userInfoState || getCache<UserInfo>(USER_INFO_KEY) || {};
42 58 }
43 59  
44 60 get getTokenState(): string {
45   - return this.tokenState || (getLocal(TOKEN_KEY) as string);
  61 + return this.tokenState || getCache<string>(TOKEN_KEY);
46 62 }
47 63  
48 64 get getRoleListState(): RoleEnum[] {
49   - return this.roleListState.length > 0 ? this.roleListState : (getLocal(ROLES_KEY) as RoleEnum[]);
  65 + return this.roleListState.length > 0 ? this.roleListState : getCache<RoleEnum[]>(ROLES_KEY);
50 66 }
51 67  
52 68 @Mutation
... ... @@ -59,25 +75,19 @@ class User extends VuexModule {
59 75 @Mutation
60 76 commitUserInfoState(info: UserInfo): void {
61 77 this.userInfoState = info;
62   - if (info) {
63   - setLocal(USER_INFO_KEY, info, true);
64   - }
  78 + setCache(USER_INFO_KEY, info);
65 79 }
66 80  
67 81 @Mutation
68 82 commitRoleListState(roleList: RoleEnum[]): void {
69 83 this.roleListState = roleList;
70   - if (roleList) {
71   - setLocal(ROLES_KEY, roleList, true);
72   - }
  84 + setCache(ROLES_KEY, roleList);
73 85 }
74 86  
75 87 @Mutation
76 88 commitTokenState(info: string): void {
77 89 this.tokenState = info;
78   - if (info) {
79   - setLocal(TOKEN_KEY, info, true);
80   - }
  90 + setCache(TOKEN_KEY, info);
81 91 }
82 92  
83 93 /**
... ...
src/types/config.d.ts
1   -// 左侧菜单, 顶部菜单
2 1 import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
3 2 import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
  3 +import { CacheTypeEnum } from '/@/enums/cacheEnum';
4 4 import type { LocaleType } from '/@/locales/types';
5 5  
6 6 export interface MenuSetting {
... ... @@ -76,6 +76,8 @@ export interface TransitionSetting {
76 76 export interface ProjectConfig {
77 77 locale: LocaleSetting;
78 78  
  79 + permissionCacheType: CacheTypeEnum;
  80 +
79 81 // 是否显示配置按钮
80 82 showSettingButton: boolean;
81 83 // 权限模式
... ...
src/utils/helper/persistent.ts
... ... @@ -29,8 +29,12 @@ function initCache() {
29 29 initCache();
30 30  
31 31 export function setLocal(key: string, value: any, immediate = false) {
32   - cacheStore.local[BASE_LOCAL_CACHE_KEY] = cacheStore.local[BASE_LOCAL_CACHE_KEY] || {};
  32 + const local = ls.get(BASE_LOCAL_CACHE_KEY)?.[BASE_LOCAL_CACHE_KEY] || {};
  33 +
  34 + cacheStore.local[BASE_LOCAL_CACHE_KEY] =
  35 + { ...local, ...cacheStore.local[BASE_LOCAL_CACHE_KEY] } || {};
33 36 cacheStore.local[BASE_LOCAL_CACHE_KEY][key] = value;
  37 +
34 38 if (immediate) {
35 39 ls.set(BASE_LOCAL_CACHE_KEY, cacheStore.local);
36 40 }
... ... @@ -50,16 +54,21 @@ export function removeLocal(key: string) {
50 54 }
51 55 }
52 56  
53   -export function clearLocal() {
  57 +export function clearLocal(immediate = false) {
54 58 cacheStore.local = {};
  59 + immediate && ls.remove(BASE_LOCAL_CACHE_KEY);
55 60 }
56 61  
57 62 export function setSession(key: string, value: any, immediate = false) {
58   - cacheStore.session[BASE_SESSION_CACHE_KEY] = cacheStore.session[BASE_SESSION_CACHE_KEY] || {};
  63 + const session = ss.get(BASE_SESSION_CACHE_KEY)?.[BASE_SESSION_CACHE_KEY] || {};
  64 +
  65 + cacheStore.session[BASE_SESSION_CACHE_KEY] =
  66 + { ...session, ...cacheStore.session[BASE_SESSION_CACHE_KEY] } || {};
  67 +
59 68 cacheStore.session[BASE_SESSION_CACHE_KEY][key] = value;
  69 +
60 70 if (immediate) {
61   - const cache = cacheStore.session;
62   - ss.set(BASE_SESSION_CACHE_KEY, cache);
  71 + ss.set(BASE_SESSION_CACHE_KEY, cacheStore.session);
63 72 }
64 73 }
65 74  
... ... @@ -77,8 +86,9 @@ export function getSession&lt;T&gt;(key: string): T | null {
77 86 }
78 87 }
79 88  
80   -export function clearSession() {
  89 +export function clearSession(immediate = false) {
81 90 cacheStore.session = {};
  91 + immediate && ss.remove(BASE_SESSION_CACHE_KEY);
82 92 }
83 93  
84 94 export function clearAll() {
... ... @@ -86,14 +96,17 @@ export function clearAll() {
86 96 clearSession();
87 97 }
88 98  
  99 +export function persistentCache() {
  100 + const localCache = cacheStore.local;
  101 + const sessionCache = cacheStore.session;
  102 + ls.set(BASE_LOCAL_CACHE_KEY, localCache);
  103 + ss.set(BASE_SESSION_CACHE_KEY, sessionCache);
  104 +}
  105 +
89 106 (() => {
90 107 // /** Write to local before closing window */
91 108 window.addEventListener('beforeunload', () => {
92   - const localCache = cacheStore.local;
93   - const sessionCache = cacheStore.session;
94   -
95   - ls.set(BASE_LOCAL_CACHE_KEY, localCache);
96   - ss.set(BASE_SESSION_CACHE_KEY, sessionCache);
  109 + persistentCache();
97 110 });
98 111  
99 112 function storageChange(e: any) {
... ...