import { computed, toRaw } from 'vue'; import type { AppRouteRecordRaw, RouteMeta } from '/@/router/types.d'; import { unref } from 'vue'; import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators'; import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; import { PageEnum } from '/@/enums/pageEnum'; import { appStore } from '/@/store/modules/app'; import store from '/@/store'; import router from '/@/router'; import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant'; type CacheName = string | symbol | null | undefined; /** * @description: vuex Tab模块 */ // declare namespace TabsStore { export interface TabItem { path: string; name?: CacheName; meta?: RouteMeta; } const NAME = 'tab'; hotModuleUnregisterModule(NAME); const getOpenKeepAliveRef = computed(() => appStore.getProjectConfig.openKeepAlive); @Module({ namespaced: true, name: NAME, dynamic: true, store }) class Tab extends VuexModule { // tab列表 tabsState: TabItem[] = []; // 缓存列表 keepAliveTabsState: CacheName[] = []; currentContextMenuIndexState = -1; currentContextMenuState: TabItem | null = null; /** * @description: 获取tabs */ get getTabsState() { return this.tabsState; } get getCurrentContextMenuIndexState() { return this.currentContextMenuIndexState; } get getCurrentContextMenuState() { return this.currentContextMenuState; } /** * @description: 获取缓存的tab列表 */ get getKeepAliveTabsState() { return this.keepAliveTabsState; } get getCurrentTab(): TabItem { const route = unref(router.currentRoute); return this.tabsState.find((item) => item.path === route.path)!; } @Mutation commitClearCache(): void { this.keepAliveTabsState = []; } @Mutation commitCurrentContextMenuIndexState(index: number): void { this.currentContextMenuIndexState = index; } @Mutation commitCurrentContextMenuState(item: TabItem): void { this.currentContextMenuState = item; } /** * @description: add tab */ @Mutation commitAddTab(route: AppRouteRecordRaw | TabItem): void { const { path, name, meta } = route; // 404 页面不需要添加tab if (path === PageEnum.ERROR_PAGE) { return; } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) { return; } // 已经存在的页面,不重复添加tab const hasTab = this.tabsState.some((tab) => { return tab.path === path; }); if (hasTab) return; this.tabsState.push({ path, name, meta }); if (unref(getOpenKeepAliveRef) && name) { const noKeepAlive = meta && meta.ignoreKeepAlive; const hasName = this.keepAliveTabsState.includes(name); !noKeepAlive && !hasName && this.keepAliveTabsState.push(name); } } /** * @description: close tab */ @Mutation commitCloseTab(route: AppRouteRecordRaw | TabItem): void { try { const { path, name, meta: { affix } = {} } = route; if (affix) return; const index = this.tabsState.findIndex((item) => item.path === path); index !== -1 && this.tabsState.splice(index, 1); if (unref(getOpenKeepAliveRef) && name) { const i = this.keepAliveTabsState.findIndex((item) => item === name); i !== -1 && this.keepAliveTabsState.splice(i, 1); } } catch (error) {} } @Mutation commitCloseTabKeepAlive(route: AppRouteRecordRaw | TabItem): void { const { name } = route; if (unref(getOpenKeepAliveRef) && name) { const i = this.keepAliveTabsState.findIndex((item) => item === name); i !== -1 && toRaw(this.keepAliveTabsState).splice(i, 1); } } @Mutation commitCloseAllTab(): void { this.tabsState = this.tabsState.filter((item) => { return item.meta && item.meta.affix; }); const names = this.tabsState.map((item) => item.name); this.keepAliveTabsState = names as string[]; } @Mutation commitResetState(): void { this.tabsState = []; this.currentContextMenuState = null; this.currentContextMenuIndexState = -1; this.keepAliveTabsState = []; } @Mutation closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void { this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.path)); if (unref(getOpenKeepAliveRef) && nameList) { this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter( (item) => !nameList.includes(item as string) ); } } @Action closeLeftTabAction(route: AppRouteRecordRaw | TabItem): void { const index = this.tabsState.findIndex((item) => item.path === route.path); if (index > 0) { const leftTabs = this.tabsState.slice(0, index); const pathList: string[] = []; const nameList: string[] = []; for (const item of leftTabs) { const affix = item.meta ? item.meta.affix : false; if (!affix) { pathList.push(item.path); nameList.push(item.name as string); } } this.closeMultipleTab({ pathList, nameList }); } } @Action closeRightTabAction(route: AppRouteRecordRaw | TabItem): void { const index = this.tabsState.findIndex((item) => item.path === route.path); if (index >= 0 && index < this.tabsState.length - 1) { const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length); const pathList: string[] = []; const nameList: string[] = []; for (const item of rightTabs) { const affix = item.meta ? item.meta.affix : false; if (!affix) { pathList.push(item.path); nameList.push(item.name as string); } } this.closeMultipleTab({ pathList, nameList }); } } @Action closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void { const closePathList = this.tabsState.map((item) => item.path); const pathList: string[] = []; const nameList: string[] = []; closePathList.forEach((path) => { if (path !== route.path) { const closeItem = this.tabsState.find((item) => item.path === path); if (!closeItem) return; const affix = closeItem.meta ? closeItem.meta.affix : false; if (!affix) { pathList.push(closeItem.path); nameList.push(closeItem.name as string); } } }); this.closeMultipleTab({ pathList, nameList }); } } export { Tab }; export const tabStore = getModule(Tab);