feat(projects): 迁移多页签

This commit is contained in:
Soybean
2022-01-20 00:56:59 +08:00
parent cc290accc2
commit 28efbdbc70
26 changed files with 868 additions and 20 deletions

View File

@ -1,4 +1,5 @@
export * from './app';
export * from './theme';
export * from './auth';
export * from './tab';
export * from './route';

View File

@ -3,10 +3,13 @@ import { defineStore } from 'pinia';
import { fetchUserRoutes } from '@/service';
import { transformAuthRouteToMenu, transformAuthRoutesToVueRoutes } from '@/utils';
import type { GlobalMenuOption } from '@/interface';
import { useTabStore } from '../tab';
interface RouteState {
/** 是否添加过动态路由 */
isAddedDynamicRoute: boolean;
/** 路由首页name */
routeHomeName: AuthRoute.RouteKey;
/** 菜单 */
menus: GlobalMenuOption[];
}
@ -14,6 +17,7 @@ interface RouteState {
export const useRouteStore = defineStore('route-store', {
state: (): RouteState => ({
isAddedDynamicRoute: false,
routeHomeName: 'dashboard_analysis',
menus: []
}),
actions: {
@ -22,8 +26,11 @@ export const useRouteStore = defineStore('route-store', {
* @param router - 路由实例
*/
async initDynamicRoute(router: Router) {
const { initHomeTab } = useTabStore();
const { data } = await fetchUserRoutes();
if (data) {
this.routeHomeName = data.home;
this.menus = transformAuthRouteToMenu(data.routes);
const vueRoutes = transformAuthRoutesToVueRoutes(data.routes);
@ -31,6 +38,7 @@ export const useRouteStore = defineStore('route-store', {
router.addRoute(route);
});
initHomeTab(data.home, router);
this.isAddedDynamicRoute = true;
}
}

View File

@ -0,0 +1,33 @@
import type { RouteRecordNormalized, RouteLocationNormalizedLoaded } from 'vue-router';
import type { GlobalTabRoute } from '@/interface';
/**
* 根据vue路由获取tab路由
* @param route
*/
export function getTabRouteByVueRoute(route: RouteRecordNormalized | RouteLocationNormalizedLoaded) {
const tabRoute: GlobalTabRoute = {
name: route.name,
path: route.path,
meta: route.meta
};
return tabRoute;
}
/**
* 获取该页签在多页签数据中的索引
* @param tabs - 多页签数据
* @param path - 该页签的路径
*/
export function getIndexInTabRoutes(tabs: GlobalTabRoute[], path: string) {
return tabs.findIndex(tab => tab.path === path);
}
/**
* 判断该页签是否在多页签数据中
* @param tabs - 多页签数据
* @param path - 该页签的路径
*/
export function isInTabRoutes(tabs: GlobalTabRoute[], path: string) {
return getIndexInTabRoutes(tabs, path) > -1;
}

View File

@ -0,0 +1,153 @@
import type { Router, RouteLocationNormalizedLoaded } from 'vue-router';
import { defineStore } from 'pinia';
import { useRouterPush } from '@/composables';
import { getTabRoutes } from '@/utils';
import type { GlobalTabRoute } from '@/interface';
import { useThemeStore } from '../theme';
import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes } from './helpers';
interface TabState {
/** 多页签数据 */
tabs: GlobalTabRoute[];
/** 多页签首页 */
homeTab: GlobalTabRoute;
/** 当前激活状态的页签(路由path) */
activeTab: string;
}
export const useTabStore = defineStore('tab-store', {
state: (): TabState => ({
tabs: [],
homeTab: {
name: 'root',
path: '/',
meta: {
title: 'root'
}
},
activeTab: ''
}),
getters: {
/** 当前激活状态的页签索引 */
activeTabIndex(state) {
const { tabs, activeTab } = state;
return tabs.findIndex(tab => tab.path === activeTab);
}
},
actions: {
/**
* 设置当前路由对应的页签为激活状态
* @param path - 路由path
*/
setActiveTab(path: string) {
this.activeTab = path;
},
/**
* 初始化首页页签路由
* @param routeHomeName - 路由首页的name
* @param router - 路由实例
*/
initHomeTab(routeHomeName: string, router: Router) {
const routes = router.getRoutes();
const findHome = routes.find(item => item.name === routeHomeName);
if (findHome) {
this.homeTab = getTabRouteByVueRoute(findHome);
}
},
/**
* 添加多页签
* @param route - 路由
*/
addTab(route: RouteLocationNormalizedLoaded) {
if (!isInTabRoutes(this.tabs, route.path)) {
this.tabs.push(getTabRouteByVueRoute(route));
}
},
/**
* 删除多页签
* @param path - 路由path
*/
removeTab(path: string) {
const { routerPush } = useRouterPush(false);
const isActive = this.activeTab === path;
const updateTabs = this.tabs.filter(tab => tab.path !== path);
this.tabs = updateTabs;
if (isActive && updateTabs.length) {
const activePath = updateTabs[updateTabs.length - 1].path;
this.setActiveTab(activePath);
routerPush(activePath);
}
},
/**
* 清空多页签(多页签首页保留)
* @param excludes - 保留的多页签path
*/
clearTab(excludes: string[] = []) {
const { routerPush } = useRouterPush(false);
const homePath = this.homeTab.path;
const remain = [homePath, ...excludes];
const hasActive = remain.includes(this.activeTab);
const updateTabs = this.tabs.filter(tab => remain.includes(tab.path));
this.tabs = updateTabs;
if (!hasActive && updateTabs.length) {
const activePath = updateTabs[updateTabs.length - 1].path;
this.setActiveTab(activePath);
routerPush(activePath);
}
},
/**
* 清除左边多页签
* @param path - 路由path
*/
clearLeftTab(path: string) {
const index = getIndexInTabRoutes(this.tabs, path);
if (index > -1) {
const excludes = this.tabs.slice(index).map(item => item.path);
this.clearTab(excludes);
}
},
/**
* 清除右边多页签
* @param path - 路由path
*/
clearRightTab(path: string) {
const index = getIndexInTabRoutes(this.tabs, path);
if (index > -1) {
const excludes = this.tabs.slice(0, index + 1).map(item => item.path);
this.clearTab(excludes);
}
},
/**
* 点击单个tab
* @param path - 路由path
*/
handleClickTab(path: string) {
const { routerPush } = useRouterPush(false);
const isActive = this.activeTab === path;
if (!isActive) {
this.setActiveTab(path);
routerPush(path);
}
},
/** 初始化Tab状态 */
iniTabStore(currentRoute: RouteLocationNormalizedLoaded) {
const theme = useThemeStore();
const isHome = currentRoute.path === this.homeTab.path;
const tabs: GlobalTabRoute[] = theme.tab.isCache ? getTabRoutes() : [];
const hasHome = isInTabRoutes(tabs, this.homeTab.path);
const hasCurrent = isInTabRoutes(tabs, currentRoute.path);
if (!hasHome) {
tabs.unshift(this.homeTab);
}
if (!isHome && !hasCurrent) {
tabs.push(getTabRouteByVueRoute(currentRoute));
}
this.tabs = tabs;
this.setActiveTab(currentRoute.path);
}
}
});