vue-vben-admin/src/store/modules/tab.ts

331 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { toRaw } from 'vue';
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 store from '/@/store';
import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
import { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { getRoute } from '/@/router/helper/routeHelper';
import { useGo, useRedo } from '/@/hooks/web/usePage';
import { cloneDeep } from 'lodash-es';
const NAME = 'tab';
hotModuleUnregisterModule(NAME);
export const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';
function isGotoPage() {
const go = useGo();
go(unref(router.currentRoute).path, true);
}
@Module({ namespaced: true, name: NAME, dynamic: true, store })
class Tab extends VuexModule {
cachedMapState = new Map<string, string[]>();
// tab list
tabsState: RouteLocationNormalized[] = [];
lastDragEndIndexState = 0;
get getTabsState() {
return this.tabsState;
}
get getCurrentTab(): RouteLocationNormalized {
const route = unref(router.currentRoute);
return this.tabsState.find((item) => item.path === route.path)!;
}
get getCachedMapState(): Map<string, string[]> {
return this.cachedMapState;
}
get getLastDragEndIndexState(): number {
return this.lastDragEndIndexState;
}
@Mutation
commitClearCache(): void {
this.cachedMapState = new Map();
}
@Mutation
goToPage() {
const go = useGo();
const len = this.tabsState.length;
const { path } = unref(router.currentRoute);
let toPath: PageEnum | string = PageEnum.BASE_HOME;
if (len > 0) {
const page = this.tabsState[len - 1];
const p = page.fullPath || page.path;
if (p) {
toPath = p;
}
}
// Jump to the current page and report an error
path !== toPath && go(toPath as PageEnum, true);
}
@Mutation
commitCachedMapState(): void {
const cacheMap = new Map<string, string[]>();
const pageCacheSet = new Set<string>();
this.tabsState.forEach((tab) => {
const item = getRoute(tab);
const needCache = !item.meta?.ignoreKeepAlive;
if (!needCache) return;
if (item.meta?.affix) {
const name = item.name as string;
pageCacheSet.add(name);
} else if (item.matched && needCache) {
const matched = item.matched;
const len = matched.length;
if (len < 2) return;
for (let i = 0; i < matched.length; i++) {
const key = matched[i].name as string;
if (i < 2) {
pageCacheSet.add(key);
}
if (i < len - 1) {
const { meta, name } = matched[i + 1];
if (meta && (meta.affix || needCache)) {
const mapList = cacheMap.get(key) || [];
if (!mapList.includes(name as string)) {
mapList.push(name as string);
}
cacheMap.set(key, mapList);
}
}
}
}
});
cacheMap.set(PAGE_LAYOUT_KEY, Array.from(pageCacheSet));
this.cachedMapState = cacheMap;
}
@Mutation
commitTabRoutesState(route: RouteLocationNormalized) {
const { path, fullPath, params, query } = route;
let updateIndex = -1;
// 已经存在的页面不重复添加tab
const hasTab = this.tabsState.some((tab, index) => {
updateIndex = index;
return (tab.fullPath || tab.path) === (fullPath || path);
});
if (hasTab) {
const curTab = toRaw(this.tabsState)[updateIndex];
if (!curTab) return;
curTab.params = params || curTab.params;
curTab.query = query || curTab.query;
curTab.fullPath = fullPath || curTab.fullPath;
this.tabsState.splice(updateIndex, 1, curTab);
return;
}
this.tabsState = cloneDeep([...this.tabsState, route]);
}
/**
* @description: close tab
*/
@Mutation
commitCloseTab(route: RouteLocationNormalized): void {
const { fullPath, meta: { affix } = {} } = route;
if (affix) return;
const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
index !== -1 && this.tabsState.splice(index, 1);
}
@Mutation
commitCloseAllTab(): void {
this.tabsState = this.tabsState.filter((item) => {
return item.meta && item.meta.affix;
});
}
@Mutation
commitResetState(): void {
this.tabsState = [];
this.cachedMapState = new Map();
}
@Mutation
commitSortTabs({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }): void {
const currentTab = this.tabsState[oldIndex];
this.tabsState.splice(oldIndex, 1);
this.tabsState.splice(newIndex, 0, currentTab);
this.lastDragEndIndexState = this.lastDragEndIndexState + 1;
}
@Mutation
closeMultipleTab({ pathList }: { pathList: string[] }): void {
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
}
@Action
addTabAction(route: RouteLocationNormalized) {
const { path, name } = route;
// 404 页面不需要添加tab
if (
path === PageEnum.ERROR_PAGE ||
!name ||
[REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
) {
return;
}
this.commitTabRoutesState(getRoute(route));
this.commitCachedMapState();
}
@Mutation
async commitRedoPage() {
const route = router.currentRoute.value;
for (const [key, value] of this.cachedMapState) {
const index = value.findIndex((item) => item === (route.name as string));
if (index === -1) {
continue;
}
if (value.length === 1) {
this.cachedMapState.delete(key);
continue;
}
value.splice(index, 1);
this.cachedMapState.set(key, value);
}
const redo = useRedo();
await redo();
}
@Action
closeAllTabAction() {
this.commitCloseAllTab();
this.commitClearCache();
this.goToPage();
}
@Action
closeTabAction(tab: RouteLocationNormalized) {
function getObj(tabItem: RouteLocationNormalized) {
const { params, path, query } = tabItem;
return {
params: params || {},
path,
query: query || {},
};
}
const { currentRoute, replace } = router;
const { path } = unref(currentRoute);
if (path !== tab.path) {
// Closed is not the activation tab
this.commitCloseTab(tab);
return;
}
// Closed is activated atb
let toObj: RouteLocationRaw = {};
const index = this.getTabsState.findIndex((item) => item.path === path);
// If the current is the leftmost tab
if (index === 0) {
// There is only one tab, then jump to the homepage, otherwise jump to the right tab
if (this.getTabsState.length === 1) {
toObj = PageEnum.BASE_HOME;
} else {
// Jump to the right tab
const page = this.getTabsState[index + 1];
toObj = getObj(page);
}
} else {
// Close the current tab
const page = this.getTabsState[index - 1];
toObj = getObj(page);
}
this.commitCloseTab(currentRoute.value);
replace(toObj);
}
@Action
closeTabByKeyAction(key: string) {
const index = this.tabsState.findIndex((item) => (item.fullPath || item.path) === key);
index !== -1 && this.closeTabAction(this.tabsState[index]);
}
@Action
closeLeftTabAction(route: RouteLocationNormalized): void {
const index = this.tabsState.findIndex((item) => item.path === route.path);
if (index > 0) {
const leftTabs = this.tabsState.slice(0, index);
const pathList: string[] = [];
for (const item of leftTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.closeMultipleTab({ pathList });
}
this.commitCachedMapState();
isGotoPage();
}
@Action
closeRightTabAction(route: RouteLocationNormalized): void {
const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
if (index >= 0 && index < this.tabsState.length - 1) {
const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
const pathList: string[] = [];
for (const item of rightTabs) {
const affix = item.meta ? item.meta.affix : false;
if (!affix) {
pathList.push(item.fullPath);
}
}
this.closeMultipleTab({ pathList });
}
this.commitCachedMapState();
isGotoPage();
}
@Action
closeOtherTabAction(route: RouteLocationNormalized): void {
const closePathList = this.tabsState.map((item) => item.fullPath);
const pathList: string[] = [];
closePathList.forEach((path) => {
if (path !== route.fullPath) {
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.fullPath);
}
}
});
this.closeMultipleTab({ pathList });
this.commitCachedMapState();
isGotoPage();
}
}
export const tabStore = getModule<Tab>(Tab);