fix(projects): 修复权限切换路由数据未更新的问题

This commit is contained in:
Soybean
2022-05-09 23:51:19 +08:00
parent 3590b65e22
commit 60f912508b
9 changed files with 159 additions and 73 deletions

View File

@ -4,11 +4,13 @@
class="h-full bg-[#f6f9f8] dark:bg-[#101014] transition duration-300 ease-in-out"
>
<router-view v-slot="{ Component, route }">
<transition :name="theme.page.animate ? theme.page.animateMode : undefined" mode="out-in" appear>
<keep-alive :include="routeStore.cacheRoutes">
<component :is="Component" v-if="app.reloadFlag" :key="route.path" />
</keep-alive>
</transition>
<div class="h-full">
<transition :name="theme.page.animate ? theme.page.animateMode : undefined" mode="out-in" appear>
<keep-alive :include="routeStore.cacheRoutes">
<component :is="Component" v-if="app.reloadFlag" :key="route.path" />
</keep-alive>
</transition>
</div>
</router-view>
</div>
</template>

View File

@ -1,4 +1,4 @@
import type { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import type { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import { routeName } from '@/router';
import { useRouteStore } from '@/store';
import { getToken } from '@/utils';
@ -9,8 +9,7 @@ import { getToken } from '@/utils';
export async function createDynamicRouteGuard(
to: RouteLocationNormalized,
_from: RouteLocationNormalized,
next: NavigationGuardNext,
router: Router
next: NavigationGuardNext
) {
const route = useRouteStore();
const isLogin = Boolean(getToken());
@ -28,7 +27,7 @@ export async function createDynamicRouteGuard(
return false;
}
await route.initAuthRoute(router);
await route.initAuthRoute();
if (to.name === routeName('not-found-page')) {
// 动态路由没有加载导致被not-found-page路由捕获等待权限路由加载好了回到之前的路由

View File

@ -11,7 +11,7 @@ export function createRouterGuard(router: Router) {
// 开始 loadingBar
window.$loadingBar?.start();
// 页面跳转权限处理
await createPermissionGuard(to, from, next, router);
await createPermissionGuard(to, from, next);
});
router.afterEach(to => {
// 设置document title

View File

@ -1,4 +1,4 @@
import type { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import type { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
import { routeName } from '@/router';
import { useAuthStore } from '@/store';
import { exeStrategyActions, getToken } from '@/utils';
@ -8,11 +8,10 @@ import { createDynamicRouteGuard } from './dynamic';
export async function createPermissionGuard(
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext,
router: Router
next: NavigationGuardNext
) {
// 动态路由
const permission = await createDynamicRouteGuard(to, from, next, router);
const permission = await createDynamicRouteGuard(to, from, next);
if (!permission) return;
// 外链路由, 从新标签打开,返回上一个路由

View File

@ -1,6 +1,6 @@
import { unref, nextTick } from 'vue';
import { unref } from 'vue';
import { defineStore } from 'pinia';
import { router as globalRouter } from '@/router';
import { router } from '@/router';
import { useRouterPush } from '@/composables';
import { fetchLogin, fetchUserInfo } from '@/service';
import { getUserInfo, getToken, setUserInfo, setToken, setRefreshToken, clearAuthStorage } from '@/utils';
@ -34,26 +34,50 @@ export const useAuthStore = defineStore('auth-store', {
const { toLogin } = useRouterPush(false);
const { resetTabStore } = useTabStore();
const { resetRouteStore } = useRouteStore();
const route = unref(globalRouter.currentRoute);
const route = unref(router.currentRoute);
clearAuthStorage();
this.$reset();
resetTabStore();
resetRouteStore();
if (route.meta.requiresAuth) {
toLogin();
}
},
/**
* 处理登录后成功或失败的逻辑
* @param backendToken - 返回的token
*/
async handleActionAfterLogin(backendToken: ApiAuth.Token) {
const { toLoginRedirect } = useRouterPush(false);
nextTick(() => {
resetTabStore();
resetRouteStore();
});
const loginSuccess = await this.loginByToken(backendToken);
if (loginSuccess) {
// 跳转登录后的地址
toLoginRedirect();
// 登录成功弹出欢迎提示
window.$notification?.success({
title: '登录成功!',
content: `欢迎回来,${this.userInfo.userName}!`,
duration: 3000
});
return;
}
// 不成功则重置状态
this.resetAuthStore();
},
/**
* 根据token进行登录
* @param backendToken - 返回的token
*/
async loginByToken(backendToken: ApiAuth.Token) {
const { toLoginRedirect } = useRouterPush(false);
let successFlag = false;
// 先把token存储到缓存中(后面接口的请求头需要token)
const { token, refreshToken } = backendToken;
@ -70,19 +94,10 @@ export const useAuthStore = defineStore('auth-store', {
this.userInfo = data;
this.token = token;
// 跳转登录后的地址
toLoginRedirect();
// 登录成功弹出欢迎提示
window.$notification?.success({
title: '登录成功!',
content: `欢迎回来,${data.userName}!`,
duration: 3000
});
} else {
// 不成功则重置状态
this.resetAuthStore();
successFlag = true;
}
return successFlag;
},
/**
* 登录
@ -93,12 +108,38 @@ export const useAuthStore = defineStore('auth-store', {
this.loginLoading = true;
const { data } = await fetchLogin(userName, password);
if (data) {
await this.loginByToken(data);
await this.handleActionAfterLogin(data);
}
this.loginLoading = false;
},
updateUserRole(userRole: Auth.RoleType) {
this.userInfo.userRole = userRole;
/**
* 更换用户权限(切换账号)
* @param userRole
*/
async updateUserRole(userRole: Auth.RoleType) {
const { resetRouteStore, initAuthRoute } = useRouteStore();
const accounts: Record<Auth.RoleType, { userName: string; password: string }> = {
super: {
userName: 'Super',
password: 'super123'
},
admin: {
userName: 'Admin',
password: 'admin123'
},
user: {
userName: 'User01',
password: 'user01123'
}
};
const { userName, password } = accounts[userRole];
const { data } = await fetchLogin(userName, password);
if (data) {
await this.loginByToken(data);
resetRouteStore();
initAuthRoute();
}
}
}
});

View File

@ -1,6 +1,5 @@
import type { Router } from 'vue-router';
import { defineStore } from 'pinia';
import { routes as staticRoutes } from '@/router';
import { router, constantRoutes, routes as staticRoutes } from '@/router';
import { fetchUserRoutes } from '@/service';
import {
getUserInfo,
@ -9,7 +8,8 @@ import {
transformAuthRoutesToSearchMenus,
getCacheRoutes,
filterAuthRoutesByUserPermission,
transformRoutePathToRouteName
transformRoutePathToRouteName,
getConstantRouteNames
} from '@/utils';
import { useAuthStore } from '../auth';
import { useTabStore } from '../tab';
@ -44,14 +44,25 @@ export const useRouteStore = defineStore('route-store', {
}),
actions: {
resetRouteStore() {
this.resetRoutes();
this.$reset();
},
/** 重置路由数据,保留固定路由 */
resetRoutes() {
const routes = router.getRoutes();
const constantRouteNames = getConstantRouteNames(constantRoutes);
routes.forEach(route => {
const name: AuthRoute.RouteKey = (route.name || 'root') as AuthRoute.RouteKey;
if (!constantRouteNames.includes(name)) {
router.removeRoute(name);
}
});
},
/**
* 处理权限路由
* @param routes - 权限路由
* @param router - 路由实例
*/
handleAuthRoutes(routes: AuthRoute.Route[], router: Router) {
handleAuthRoutes(routes: AuthRoute.Route[]) {
this.menus = transformAuthRouteToMenu(routes);
this.searchMenus = transformAuthRoutesToSearchMenus(routes);
@ -63,32 +74,23 @@ export const useRouteStore = defineStore('route-store', {
this.cacheRoutes = getCacheRoutes(vueRoutes);
},
/**
* 初始化动态路由
* @param router - 路由实例
*/
async initDynamicRoute(router: Router) {
/** 初始化动态路由 */
async initDynamicRoute() {
const { userId } = getUserInfo();
const { data } = await fetchUserRoutes(userId);
if (data) {
this.routeHomeName = data.home;
this.handleAuthRoutes(data.routes, router);
this.handleAuthRoutes(data.routes);
}
},
/**
* 初始化静态路由
* @param router - 路由实例
*/
async initStaticRoute(router: Router) {
/** 初始化静态路由 */
async initStaticRoute() {
const auth = useAuthStore();
const routes = filterAuthRoutesByUserPermission(staticRoutes, auth.userInfo.userRole);
this.handleAuthRoutes(routes, router);
this.handleAuthRoutes(routes);
},
/**
* 初始化权限路由
* @param router - 路由实例
*/
async initAuthRoute(router: Router) {
/** 初始化权限路由 */
async initAuthRoute() {
const { initHomeTab } = useTabStore();
const { userId } = getUserInfo();
@ -96,9 +98,9 @@ export const useRouteStore = defineStore('route-store', {
const isDynamicRoute = this.authRouteMode === 'dynamic';
if (isDynamicRoute) {
await this.initDynamicRoute(router);
await this.initDynamicRoute();
} else {
await this.initStaticRoute(router);
await this.initStaticRoute();
}
initHomeTab(this.routeHomeName, router);

View File

@ -2,7 +2,13 @@ import type { RouteRecordRaw } from 'vue-router';
import { consoleError } from '../common';
import { getLayoutComponent, getViewComponent } from './component';
type ComponentAction = Record<AuthRoute.RouteComponent, () => void>;
/**
* 获取所有固定路由的名称集合
* @param routes - 固定路由
*/
export function getConstantRouteNames(routes: AuthRoute.Route[]) {
return routes.map(route => getConstantRouteName(route)).flat(1);
}
/**
* 将权限路由转换成vue路由
@ -59,6 +65,20 @@ export function transformRoutePathToRouteName(
return name;
}
/**
* 获取所有固定路由的名称集合
* @param route - 固定路由
*/
function getConstantRouteName(route: AuthRoute.Route) {
const names = [route.name];
if (hasChildren(route)) {
names.push(...route.children!.map(item => getConstantRouteName(item)).flat(1));
}
return names;
}
type ComponentAction = Record<AuthRoute.RouteComponent, () => void>;
/**
* 将单个权限路由转换成vue路由
* @param item - 单个权限路由