mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-22 19:46:38 +08:00
fix(projects): 修复权限切换路由数据未更新的问题
This commit is contained in:
parent
3590b65e22
commit
60f912508b
@ -77,7 +77,7 @@
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"husky": "^8.0.0",
|
||||
"husky": "^8.0.1",
|
||||
"lint-staged": "^12.4.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"patch-package": "^6.4.7",
|
||||
@ -89,7 +89,7 @@
|
||||
"typescript": "^4.6.4",
|
||||
"unocss": "^0.33.2",
|
||||
"unplugin-icons": "^0.14.3",
|
||||
"unplugin-vue-components": "0.19.3",
|
||||
"unplugin-vue-components": "0.19.5",
|
||||
"unplugin-vue-define-options": "^0.6.1",
|
||||
"vite": "^2.9.8",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
|
@ -38,7 +38,7 @@ specifiers:
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
eslint-plugin-vue: ^8.7.1
|
||||
form-data: ^4.0.0
|
||||
husky: ^8.0.0
|
||||
husky: ^8.0.1
|
||||
lint-staged: ^12.4.1
|
||||
lodash-es: ^4.17.21
|
||||
mockjs: ^1.1.0
|
||||
@ -57,7 +57,7 @@ specifiers:
|
||||
ua-parser-js: ^1.0.2
|
||||
unocss: ^0.33.2
|
||||
unplugin-icons: ^0.14.3
|
||||
unplugin-vue-components: 0.19.3
|
||||
unplugin-vue-components: 0.19.5
|
||||
unplugin-vue-define-options: ^0.6.1
|
||||
vditor: ^3.8.13
|
||||
vite: ^2.9.8
|
||||
@ -123,7 +123,7 @@ devDependencies:
|
||||
eslint-plugin-import: 2.26.0_eslint@8.15.0
|
||||
eslint-plugin-prettier: 4.0.0_440b30a60bbe5bb6e3ad0057150b2782
|
||||
eslint-plugin-vue: 8.7.1_eslint@8.15.0
|
||||
husky: 8.0.0
|
||||
husky: 8.0.1
|
||||
lint-staged: 12.4.1
|
||||
mockjs: 1.1.0
|
||||
patch-package: 6.4.7
|
||||
@ -135,7 +135,7 @@ devDependencies:
|
||||
typescript: 4.6.4
|
||||
unocss: 0.33.2_vite@2.9.8
|
||||
unplugin-icons: 0.14.3_vite@2.9.8
|
||||
unplugin-vue-components: 0.19.3_vite@2.9.8+vue@3.2.33
|
||||
unplugin-vue-components: 0.19.5_vite@2.9.8+vue@3.2.33
|
||||
unplugin-vue-define-options: 0.6.1_vite@2.9.8+vue@3.2.33
|
||||
vite: 2.9.8_sass@1.51.0
|
||||
vite-plugin-compression: 0.5.1_vite@2.9.8
|
||||
@ -3729,8 +3729,8 @@ packages:
|
||||
engines: {node: '>=10.17.0'}
|
||||
dev: true
|
||||
|
||||
/husky/8.0.0:
|
||||
resolution: {integrity: sha512-4qbE/5dzNDNxFEkX9MNRPKl5+omTXQzdILCUWiqG/lWIAioiM5vln265/l6I2Zx8gpW8l1ukZwGQeCFbBZ6+6w==}
|
||||
/husky/8.0.1:
|
||||
resolution: {integrity: sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@ -5922,8 +5922,8 @@ packages:
|
||||
- webpack
|
||||
dev: true
|
||||
|
||||
/unplugin-vue-components/0.19.3_vite@2.9.8+vue@3.2.33:
|
||||
resolution: {integrity: sha512-z/kpYJnqrJuWglDNs7fy0YRHr41oLc07y2TkP3by6DqPb1GG9xGC9SFigeFwd4J7GVTqyFVsnjoeup7uK7I2dA==}
|
||||
/unplugin-vue-components/0.19.5_vite@2.9.8+vue@3.2.33:
|
||||
resolution: {integrity: sha512-cIC+PdQEXmG+B1gmZGk4hws2xP+00C6pg3FD6ixEgRyW+WF+QXQW/60pc+hUhtDYs1PFE+23K3NY7yvYTnDDTA==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@babel/parser': ^7.15.8
|
||||
@ -5944,7 +5944,7 @@ packages:
|
||||
magic-string: 0.26.1
|
||||
minimatch: 5.0.1
|
||||
resolve: 1.22.0
|
||||
unplugin: 0.6.2_vite@2.9.8
|
||||
unplugin: 0.6.3_vite@2.9.8
|
||||
vue: 3.2.33
|
||||
transitivePeerDependencies:
|
||||
- esbuild
|
||||
@ -5994,6 +5994,29 @@ packages:
|
||||
webpack-virtual-modules: 0.4.3
|
||||
dev: true
|
||||
|
||||
/unplugin/0.6.3_vite@2.9.8:
|
||||
resolution: {integrity: sha512-CoW88FQfCW/yabVc4bLrjikN9HC8dEvMU4O7B6K2jsYMPK0l6iAnd9dpJwqGcmXJKRCU9vwSsy653qg+RK0G6A==}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.13'
|
||||
rollup: ^2.50.0
|
||||
vite: ^2.3.0
|
||||
webpack: 4 || 5
|
||||
peerDependenciesMeta:
|
||||
esbuild:
|
||||
optional: true
|
||||
rollup:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
chokidar: 3.5.3
|
||||
vite: 2.9.8_sass@1.51.0
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.3
|
||||
dev: true
|
||||
|
||||
/uri-js/4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
dependencies:
|
||||
|
@ -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>
|
||||
|
@ -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路由捕获,等待权限路由加载好了,回到之前的路由
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
// 外链路由, 从新标签打开,返回上一个路由
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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 - 单个权限路由
|
||||
|
Loading…
Reference in New Issue
Block a user