231 lines
6.6 KiB
TypeScript
231 lines
6.6 KiB
TypeScript
import type { Router, RouteLocationNormalizedLoaded } from 'vue-router';
|
|
import { defineStore } from 'pinia';
|
|
import { useRouterPush } from '@/composables';
|
|
import { getTabRoutes, clearTabRoutes } from '@/utils';
|
|
import { useThemeStore } from '../theme';
|
|
import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes, getIndexInTabRoutesByRouteName } from './helpers';
|
|
|
|
interface TabState {
|
|
/** 多页签数据 */
|
|
tabs: GlobalTabRoute[];
|
|
/** 多页签首页 */
|
|
homeTab: GlobalTabRoute;
|
|
/** 当前激活状态的页签(路由fullPath) */
|
|
activeTab: string;
|
|
}
|
|
|
|
export const useTabStore = defineStore('tab-store', {
|
|
state: (): TabState => ({
|
|
tabs: [],
|
|
homeTab: {
|
|
name: 'root',
|
|
fullPath: '/',
|
|
meta: {
|
|
title: 'Root'
|
|
},
|
|
scrollPosition: {
|
|
left: 0,
|
|
top: 0
|
|
}
|
|
},
|
|
activeTab: ''
|
|
}),
|
|
getters: {
|
|
/** 当前激活状态的页签索引 */
|
|
activeTabIndex(state) {
|
|
const { tabs, activeTab } = state;
|
|
return tabs.findIndex(tab => tab.fullPath === activeTab);
|
|
}
|
|
},
|
|
actions: {
|
|
/** 重置Tab状态 */
|
|
resetTabStore() {
|
|
clearTabRoutes();
|
|
this.$reset();
|
|
},
|
|
/**
|
|
* 设置当前路由对应的页签为激活状态
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
setActiveTab(fullPath: string) {
|
|
this.activeTab = fullPath;
|
|
},
|
|
/**
|
|
* 设置当前路由对应的页签title
|
|
* @param title - tab名称
|
|
*/
|
|
setActiveTabTitle(title: string) {
|
|
const item = this.tabs.find(tab => tab.fullPath === this.activeTab);
|
|
if (item) {
|
|
item.meta.title = title;
|
|
}
|
|
},
|
|
/**
|
|
* 初始化首页页签路由
|
|
* @param routeHomeName - 路由首页的name
|
|
* @param router - 路由实例
|
|
*/
|
|
initHomeTab(routeHomeName: string, router: Router) {
|
|
const routes = router.getRoutes();
|
|
const findHome = routes.find(item => item.name === routeHomeName);
|
|
if (findHome && !findHome.children.length) {
|
|
// 有子路由的不能作为Tab
|
|
this.homeTab = getTabRouteByVueRoute(findHome);
|
|
}
|
|
},
|
|
/**
|
|
* 添加多页签
|
|
* @param route - 路由
|
|
*/
|
|
addTab(route: RouteLocationNormalizedLoaded) {
|
|
const tab = getTabRouteByVueRoute(route);
|
|
|
|
if (isInTabRoutes(this.tabs, tab.fullPath)) {
|
|
return;
|
|
}
|
|
|
|
const index = getIndexInTabRoutesByRouteName(this.tabs, route.name as string);
|
|
|
|
if (index === -1) {
|
|
this.tabs.push(tab);
|
|
return;
|
|
}
|
|
|
|
const { multiTab = false } = route.meta;
|
|
if (!multiTab) {
|
|
this.tabs.splice(index, 1, tab);
|
|
return;
|
|
}
|
|
|
|
this.tabs.push(tab);
|
|
},
|
|
/**
|
|
* 删除多页签
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
removeTab(fullPath: string) {
|
|
const { routerPush } = useRouterPush(false);
|
|
|
|
const isActive = this.activeTab === fullPath;
|
|
const updateTabs = this.tabs.filter(tab => tab.fullPath !== fullPath);
|
|
this.tabs = updateTabs;
|
|
if (isActive && updateTabs.length) {
|
|
const activePath = updateTabs[updateTabs.length - 1].fullPath;
|
|
this.setActiveTab(activePath);
|
|
routerPush(activePath);
|
|
}
|
|
},
|
|
/**
|
|
* 清空多页签(多页签首页保留)
|
|
* @param excludes - 保留的多页签path
|
|
*/
|
|
clearTab(excludes: string[] = []) {
|
|
const { routerPush } = useRouterPush(false);
|
|
|
|
const homePath = this.homeTab.fullPath;
|
|
const remain = [homePath, ...excludes];
|
|
const hasActive = remain.includes(this.activeTab);
|
|
const updateTabs = this.tabs.filter(tab => remain.includes(tab.fullPath));
|
|
this.tabs = updateTabs;
|
|
if (!hasActive && updateTabs.length) {
|
|
const activePath = updateTabs[updateTabs.length - 1].fullPath;
|
|
this.setActiveTab(activePath);
|
|
routerPush(activePath);
|
|
}
|
|
},
|
|
/**
|
|
* 清除左边多页签
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
clearLeftTab(fullPath: string) {
|
|
const index = getIndexInTabRoutes(this.tabs, fullPath);
|
|
if (index > -1) {
|
|
const excludes = this.tabs.slice(index).map(item => item.fullPath);
|
|
this.clearTab(excludes);
|
|
}
|
|
},
|
|
/**
|
|
* 清除右边多页签
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
clearRightTab(fullPath: string) {
|
|
const index = getIndexInTabRoutes(this.tabs, fullPath);
|
|
if (index > -1) {
|
|
const excludes = this.tabs.slice(0, index + 1).map(item => item.fullPath);
|
|
this.clearTab(excludes);
|
|
}
|
|
},
|
|
/** 清除所有多页签 */
|
|
clearAllTab() {
|
|
this.clearTab();
|
|
},
|
|
/**
|
|
* 点击单个tab
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
handleClickTab(fullPath: string) {
|
|
const { routerPush } = useRouterPush(false);
|
|
|
|
const isActive = this.activeTab === fullPath;
|
|
if (!isActive) {
|
|
this.setActiveTab(fullPath);
|
|
routerPush(fullPath);
|
|
}
|
|
},
|
|
/**
|
|
* 记录tab滚动位置
|
|
* @param fullPath - 路由fullPath
|
|
* @param position - tab当前页的滚动位置
|
|
*/
|
|
recordTabScrollPosition(fullPath: string, position: { left: number; top: number }) {
|
|
const index = getIndexInTabRoutes(this.tabs, fullPath);
|
|
if (index > -1) {
|
|
this.tabs[index].scrollPosition = position;
|
|
}
|
|
},
|
|
/**
|
|
* 获取tab滚动位置
|
|
* @param fullPath - 路由fullPath
|
|
*/
|
|
getTabScrollPosition(fullPath: string) {
|
|
const position = {
|
|
left: 0,
|
|
top: 0
|
|
};
|
|
const index = getIndexInTabRoutes(this.tabs, fullPath);
|
|
if (index > -1) {
|
|
Object.assign(position, this.tabs[index].scrollPosition);
|
|
}
|
|
return position;
|
|
},
|
|
/** 初始化Tab状态 */
|
|
iniTabStore(currentRoute: RouteLocationNormalizedLoaded) {
|
|
const theme = useThemeStore();
|
|
|
|
const tabs: GlobalTabRoute[] = theme.tab.isCache ? getTabRoutes() : [];
|
|
|
|
const hasHome = getIndexInTabRoutesByRouteName(tabs, this.homeTab.name as string) > -1;
|
|
if (!hasHome && this.homeTab.name !== 'root') {
|
|
tabs.unshift(this.homeTab);
|
|
}
|
|
|
|
const isHome = currentRoute.fullPath === this.homeTab.fullPath;
|
|
const index = getIndexInTabRoutesByRouteName(tabs, currentRoute.name as string);
|
|
if (!isHome) {
|
|
const currentTab = getTabRouteByVueRoute(currentRoute);
|
|
if (!currentRoute.meta.multiTab) {
|
|
tabs.splice(index, 1, currentTab);
|
|
} else {
|
|
const hasCurrent = isInTabRoutes(tabs, currentRoute.fullPath);
|
|
if (!hasCurrent) {
|
|
tabs.push(currentTab);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.tabs = tabs;
|
|
this.setActiveTab(currentRoute.fullPath);
|
|
}
|
|
}
|
|
});
|