mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 22:57:15 +08:00 
			
		
		
		
	refactor: 拆分并调整路由守卫,优化顶部进度条展示
This commit is contained in:
		| @@ -9,7 +9,7 @@ import ArcoVueIcon from '@arco-design/web-vue/es/icon' | ||||
| import App from './App.vue' | ||||
| import router from './router' | ||||
|  | ||||
| import '@/router/permission' | ||||
| import '@/router/guard' | ||||
|  | ||||
| // 使用动画库 | ||||
| import 'animate.css/animate.min.css' | ||||
|   | ||||
| @@ -6,7 +6,13 @@ import { getToken } from '@/utils/auth' | ||||
| import { isHttp } from '@/utils/validate' | ||||
| import 'nprogress/nprogress.css' | ||||
| 
 | ||||
| NProgress.configure({ showSpinner: false }) // NProgress Configuration
 | ||||
| NProgress.configure({ | ||||
|   easing: 'ease', // 动画方式
 | ||||
|   speed: 500, // 递增进度条的速度
 | ||||
|   showSpinner: false, // 是否显示圆圈加载
 | ||||
|   trickleSpeed: 200, // 自动递增间隔
 | ||||
|   minimum: 0.3, // 初始化时的最小百分比
 | ||||
| }) | ||||
| 
 | ||||
| // 版本更新
 | ||||
| let versionTag: string | null = null // 版本标识
 | ||||
| @@ -70,15 +76,14 @@ export const resetHasRouteFlag = () => { | ||||
| } | ||||
| 
 | ||||
| router.beforeEach(async (to, from, next) => { | ||||
|   NProgress.start() | ||||
|   const userStore = useUserStore() | ||||
|   const routeStore = useRouteStore() | ||||
|   NProgress.start() | ||||
|   // 判断该用户是否登录
 | ||||
|   if (getToken()) { | ||||
|     if (to.path === '/login') { | ||||
|       // 如果已经登录,并准备进入 Login 页面,则重定向到主页
 | ||||
|       next() | ||||
|       NProgress.done() | ||||
|     } else { | ||||
|       if (!hasRouteFlag) { | ||||
|         try { | ||||
| @@ -86,7 +91,6 @@ router.beforeEach(async (to, from, next) => { | ||||
|           if (userStore.userInfo.pwdExpired && to.path !== '/pwdExpired') { | ||||
|             Message.warning('密码已过期,请修改密码') | ||||
|             next('/pwdExpired') | ||||
|             NProgress.done() | ||||
|           } | ||||
|           const accessRoutes = await routeStore.generateRoutes() | ||||
|           accessRoutes.forEach((route) => { | ||||
| @@ -98,16 +102,13 @@ router.beforeEach(async (to, from, next) => { | ||||
|           // 确保添加路由已完成
 | ||||
|           // 设置 replace: true, 因此导航将不会留下历史记录
 | ||||
|           next({ ...to, replace: true }) | ||||
|           NProgress.done() | ||||
|         } catch (error: any) { | ||||
|           // 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
 | ||||
|           await userStore.logoutCallBack() | ||||
|           next(`/login?redirect=${to.path}`) | ||||
|           NProgress.done() | ||||
|         } | ||||
|       } else { | ||||
|         next() | ||||
|         NProgress.done() | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
| @@ -115,11 +116,9 @@ router.beforeEach(async (to, from, next) => { | ||||
|     if (whiteList.includes(to.path)) { | ||||
|       // 如果在免登录的白名单中,则直接进入
 | ||||
|       next() | ||||
|       NProgress.done() | ||||
|     } else { | ||||
|       // 其他没有访问权限的页面将被重定向到登录页面
 | ||||
|       next('/login') | ||||
|       NProgress.done() | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @@ -129,3 +128,11 @@ router.beforeEach(async (to, from, next) => { | ||||
|     await compareTag() | ||||
|   } | ||||
| }) | ||||
| 
 | ||||
| router.onError(() => { | ||||
|   NProgress.done() | ||||
| }) | ||||
| 
 | ||||
| router.afterEach(() => { | ||||
|   NProgress.done() | ||||
| }) | ||||
| @@ -1,94 +1,10 @@ | ||||
| import { type RouteRecordRaw, createRouter, createWebHistory } from 'vue-router' | ||||
| import { createRouter, createWebHistory } from 'vue-router' | ||||
| import { useRouteStore } from '@/stores' | ||||
|  | ||||
| /** 默认布局 */ | ||||
| const Layout = () => import('@/layout/index.vue') | ||||
|  | ||||
| /** 静态路由 */ | ||||
| export const constantRoutes: RouteRecordRaw[] = [ | ||||
|   { | ||||
|     path: '/redirect', | ||||
|     component: Layout, | ||||
|     meta: { hidden: true }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/redirect/:path(.*)', | ||||
|         component: () => import('@/views/default/redirect/index.vue'), | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     path: '/login', | ||||
|     name: 'Login', | ||||
|     component: () => import('@/views/login/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/:pathMatch(.*)*', | ||||
|     component: () => import('@/views/default/error/404.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/403', | ||||
|     component: () => import('@/views/default/error/403.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/', | ||||
|     name: 'Dashboard', | ||||
|     component: Layout, | ||||
|     redirect: '/dashboard/workplace', | ||||
|     meta: { title: '仪表盘', icon: 'dashboard', hidden: false }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/dashboard/workplace', | ||||
|         name: 'Workplace', | ||||
|         component: () => import('@/views/dashboard/workplace/index.vue'), | ||||
|         meta: { title: '工作台', icon: 'desktop', hidden: false, affix: true }, | ||||
|       }, | ||||
|       { | ||||
|         path: '/dashboard/analysis', | ||||
|         name: 'Analysis', | ||||
|         component: () => import('@/views/dashboard/analysis/index.vue'), | ||||
|         meta: { title: '分析页', icon: 'insert-chart', hidden: false }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     path: '/social/callback', | ||||
|     component: () => import('@/views/login/social/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/pwdExpired', | ||||
|     component: () => import('@/views/login/pwdExpired/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/setting', | ||||
|     name: 'Setting', | ||||
|     component: Layout, | ||||
|     meta: { hidden: true }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/setting/profile', | ||||
|         name: 'SettingProfile', | ||||
|         component: () => import('@/views/setting/profile/index.vue'), | ||||
|         meta: { title: '个人中心', showInTabs: false }, | ||||
|       }, | ||||
|       { | ||||
|         path: '/setting/message', | ||||
|         name: 'SettingMessage', | ||||
|         component: () => import('@/views/setting/message/index.vue'), | ||||
|         meta: { title: '消息中心', showInTabs: false }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
| ] | ||||
| import { constantRoutes, systemRoutes } from '@/router/route' | ||||
|  | ||||
| const router = createRouter({ | ||||
|   history: createWebHistory(import.meta.env.BASE_URL), | ||||
|   routes: constantRoutes, | ||||
|   routes: [...constantRoutes, ...systemRoutes], | ||||
|   scrollBehavior: () => ({ left: 0, top: 0 }), | ||||
| }) | ||||
|  | ||||
|   | ||||
							
								
								
									
										90
									
								
								src/router/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/router/route.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| import type { RouteRecordRaw } from 'vue-router' | ||||
|  | ||||
| /** 默认布局 */ | ||||
| const Layout = () => import('@/layout/index.vue') | ||||
|  | ||||
| /** 系统路由 */ | ||||
| export const systemRoutes: RouteRecordRaw[] = [ | ||||
|   { | ||||
|     path: '/login', | ||||
|     name: 'Login', | ||||
|     component: () => import('@/views/login/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/', | ||||
|     name: 'Dashboard', | ||||
|     component: Layout, | ||||
|     redirect: '/dashboard/workplace', | ||||
|     meta: { title: '仪表盘', icon: 'dashboard', hidden: false }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/dashboard/workplace', | ||||
|         name: 'Workplace', | ||||
|         component: () => import('@/views/dashboard/workplace/index.vue'), | ||||
|         meta: { title: '工作台', icon: 'desktop', hidden: false, affix: true }, | ||||
|       }, | ||||
|       { | ||||
|         path: '/dashboard/analysis', | ||||
|         name: 'Analysis', | ||||
|         component: () => import('@/views/dashboard/analysis/index.vue'), | ||||
|         meta: { title: '分析页', icon: 'insert-chart', hidden: false }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     path: '/social/callback', | ||||
|     component: () => import('@/views/login/social/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/pwdExpired', | ||||
|     component: () => import('@/views/login/pwdExpired/index.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/setting', | ||||
|     name: 'Setting', | ||||
|     component: Layout, | ||||
|     meta: { hidden: true }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/setting/profile', | ||||
|         name: 'SettingProfile', | ||||
|         component: () => import('@/views/setting/profile/index.vue'), | ||||
|         meta: { title: '个人中心', showInTabs: false }, | ||||
|       }, | ||||
|       { | ||||
|         path: '/setting/message', | ||||
|         name: 'SettingMessage', | ||||
|         component: () => import('@/views/setting/message/index.vue'), | ||||
|         meta: { title: '消息中心', showInTabs: false }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
| ] | ||||
|  | ||||
| // 固定路由(默认路由) | ||||
| export const constantRoutes: RouteRecordRaw[] = [ | ||||
|   { | ||||
|     path: '/redirect', | ||||
|     component: Layout, | ||||
|     meta: { hidden: true }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/redirect/:path(.*)', | ||||
|         component: () => import('@/views/default/redirect/index.vue'), | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     path: '/:pathMatch(.*)*', | ||||
|     component: () => import('@/views/default/error/404.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
|   { | ||||
|     path: '/403', | ||||
|     component: () => import('@/views/default/error/403.vue'), | ||||
|     meta: { hidden: true }, | ||||
|   }, | ||||
| ] | ||||
| @@ -3,7 +3,7 @@ import { defineStore } from 'pinia' | ||||
| import type { RouteRecordRaw } from 'vue-router' | ||||
| import { mapTree, toTreeArray } from 'xe-utils' | ||||
| import { cloneDeep, omit } from 'lodash-es' | ||||
| import { constantRoutes } from '@/router' | ||||
| import { constantRoutes, systemRoutes } from '@/router/route' | ||||
| import ParentView from '@/components/ParentView/index.vue' | ||||
| import { type RouteItem, getUserRoute } from '@/apis' | ||||
| import { transformPathToName } from '@/utils' | ||||
| @@ -103,7 +103,7 @@ const storeSetup = () => { | ||||
|  | ||||
|   // 合并路由 | ||||
|   const setRoutes = (data: RouteRecordRaw[]) => { | ||||
|     routes.value = constantRoutes.concat(data) | ||||
|     routes.value = [...constantRoutes, ...systemRoutes].concat(data) | ||||
|     asyncRoutes.value = data | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import { | ||||
|   socialLogin as socialLoginApi, | ||||
| } from '@/apis' | ||||
| import { clearToken, getToken, setToken } from '@/utils/auth' | ||||
| import { resetHasRouteFlag } from '@/router/permission' | ||||
| import { resetHasRouteFlag } from '@/router/guard' | ||||
|  | ||||
| const storeSetup = () => { | ||||
|   const userInfo = reactive<UserInfo>({ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user