refactor: 调整 router 模块结构
This commit is contained in:
parent
c1290cdf28
commit
31b2a5ba82
@ -3,7 +3,6 @@ import App from "@/App.vue"
|
|||||||
import { pinia } from "@/pinia"
|
import { pinia } from "@/pinia"
|
||||||
import { router } from "@/router"
|
import { router } from "@/router"
|
||||||
import { createApp } from "vue"
|
import { createApp } from "vue"
|
||||||
import "@/router/permission"
|
|
||||||
// load
|
// load
|
||||||
import { loadDirectives } from "@/directives"
|
import { loadDirectives } from "@/directives"
|
||||||
import { loadPlugins } from "@/plugins"
|
import { loadPlugins } from "@/plugins"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { RouteRecordRaw } from "vue-router"
|
import type { RouteRecordRaw } from "vue-router"
|
||||||
import { routeSettings } from "@/config/route"
|
|
||||||
import { pinia } from "@/pinia"
|
import { pinia } from "@/pinia"
|
||||||
import { constantRoutes, dynamicRoutes } from "@/router"
|
import { constantRoutes, dynamicRoutes } from "@/router"
|
||||||
|
import { routerConfig } from "@/router/config"
|
||||||
import { flatMultiLevelRoutes } from "@/router/helper"
|
import { flatMultiLevelRoutes } from "@/router/helper"
|
||||||
import { defineStore } from "pinia"
|
import { defineStore } from "pinia"
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
@ -46,7 +46,7 @@ export const usePermissionStore = defineStore("permission", () => {
|
|||||||
// 统一设置
|
// 统一设置
|
||||||
const set = (accessedRoutes: RouteRecordRaw[]) => {
|
const set = (accessedRoutes: RouteRecordRaw[]) => {
|
||||||
routes.value = constantRoutes.concat(accessedRoutes)
|
routes.value = constantRoutes.concat(accessedRoutes)
|
||||||
addRoutes.value = routeSettings.thirdLevelRouteCache ? flatMultiLevelRoutes(accessedRoutes) : accessedRoutes
|
addRoutes.value = routerConfig.thirdLevelRouteCache ? flatMultiLevelRoutes(accessedRoutes) : accessedRoutes
|
||||||
}
|
}
|
||||||
|
|
||||||
return { routes, addRoutes, setRoutes, setAllRoutes }
|
return { routes, addRoutes, setRoutes, setAllRoutes }
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { LoginRequestData } from "@/http/apis/login/type"
|
import type { LoginRequestData } from "@/http/apis/login/type"
|
||||||
import { routeSettings } from "@/config/route"
|
|
||||||
import { getUserInfoApi, loginApi } from "@/http/apis/login"
|
import { getUserInfoApi, loginApi } from "@/http/apis/login"
|
||||||
import { pinia } from "@/pinia"
|
import { pinia } from "@/pinia"
|
||||||
import { resetRouter } from "@/router"
|
import { resetRouter } from "@/router"
|
||||||
|
import { routerConfig } from "@/router/config"
|
||||||
import { getToken, removeToken, setToken } from "@/utils/cache/cookies"
|
import { getToken, removeToken, setToken } from "@/utils/cache/cookies"
|
||||||
import { defineStore } from "pinia"
|
import { defineStore } from "pinia"
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
@ -29,7 +29,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
const { data } = await getUserInfoApi()
|
const { data } = await getUserInfoApi()
|
||||||
username.value = data.username
|
username.value = data.username
|
||||||
// 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
|
// 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
|
||||||
roles.value = data.roles?.length > 0 ? data.roles : routeSettings.defaultRoles
|
roles.value = data.roles?.length > 0 ? data.roles : routerConfig.defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模拟角色变化
|
// 模拟角色变化
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
|
import type { RouterHistory } from "vue-router"
|
||||||
|
import { createWebHashHistory, createWebHistory } from "vue-router"
|
||||||
|
|
||||||
/** 路由配置 */
|
/** 路由配置 */
|
||||||
interface RouteSettings {
|
interface RouterConfig {
|
||||||
|
/**
|
||||||
|
* @name 路由模式
|
||||||
|
* @description hash 模式和 html5 模式
|
||||||
|
*/
|
||||||
|
history: RouterHistory
|
||||||
/**
|
/**
|
||||||
* @name 是否开启动态路由功能
|
* @name 是否开启动态路由功能
|
||||||
* @description 1. 开启后需要后端配合,在查询用户详情接口返回当前用户可以用来判断并加载动态路由的字段(该项目用的是角色 roles 字段)
|
* @description 1. 开启后需要后端配合,在查询用户详情接口返回当前用户可以用来判断并加载动态路由的字段(该项目用的是角色 roles 字段)
|
||||||
@ -21,7 +29,12 @@ interface RouteSettings {
|
|||||||
thirdLevelRouteCache: boolean
|
thirdLevelRouteCache: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const routeSettings: RouteSettings = {
|
const VITE_ROUTER_HISTORY = import.meta.env.VITE_ROUTER_HISTORY
|
||||||
|
|
||||||
|
const VITE_PUBLIC_PATH = import.meta.env.VITE_PUBLIC_PATH
|
||||||
|
|
||||||
|
export const routerConfig: RouterConfig = {
|
||||||
|
history: VITE_ROUTER_HISTORY === "hash" ? createWebHashHistory(VITE_PUBLIC_PATH) : createWebHistory(VITE_PUBLIC_PATH),
|
||||||
dynamic: true,
|
dynamic: true,
|
||||||
defaultRoles: ["DEFAULT_ROLE"],
|
defaultRoles: ["DEFAULT_ROLE"],
|
||||||
thirdLevelRouteCache: false
|
thirdLevelRouteCache: false
|
58
src/router/guard.ts
Normal file
58
src/router/guard.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import type { Router } from "vue-router"
|
||||||
|
import { setRouteChange } from "@/composables/useRouteListener"
|
||||||
|
import { useTitle } from "@/composables/useTitle"
|
||||||
|
import { isWhiteList } from "@/config/white-list"
|
||||||
|
import { usePermissionStore } from "@/pinia/stores/permission"
|
||||||
|
import { useUserStore } from "@/pinia/stores/user"
|
||||||
|
import { routerConfig } from "@/router/config"
|
||||||
|
import { getToken } from "@/utils/cache/cookies"
|
||||||
|
import { ElMessage } from "element-plus"
|
||||||
|
import NProgress from "nprogress"
|
||||||
|
import "nprogress/nprogress.css"
|
||||||
|
|
||||||
|
NProgress.configure({ showSpinner: false })
|
||||||
|
const { setTitle } = useTitle()
|
||||||
|
|
||||||
|
export function registerNavigationGuard(router: Router) {
|
||||||
|
// 全局前置守卫
|
||||||
|
router.beforeEach(async (to, _from, next) => {
|
||||||
|
NProgress.start()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
// 如果没有登陆
|
||||||
|
if (!getToken()) {
|
||||||
|
// 如果在免登录的白名单中,则直接进入
|
||||||
|
if (isWhiteList(to)) return next()
|
||||||
|
// 其他没有访问权限的页面将被重定向到登录页面
|
||||||
|
return next("/login")
|
||||||
|
}
|
||||||
|
// 如果已经登录,并准备进入 Login 页面,则重定向到主页
|
||||||
|
if (to.path === "/login") return next({ path: "/" })
|
||||||
|
// 如果用户已经获得其权限角色
|
||||||
|
if (userStore.roles.length !== 0) return next()
|
||||||
|
// 否则要重新获取权限角色
|
||||||
|
try {
|
||||||
|
await userStore.getInfo()
|
||||||
|
// 注意:角色必须是一个数组! 例如: ["admin"] 或 ["developer", "editor"]
|
||||||
|
const roles = userStore.roles
|
||||||
|
// 生成可访问的 Routes
|
||||||
|
routerConfig.dynamic ? permissionStore.setRoutes(roles) : permissionStore.setAllRoutes()
|
||||||
|
// 将 "有访问权限的动态路由" 添加到 Router 中
|
||||||
|
permissionStore.addRoutes.forEach(route => router.addRoute(route))
|
||||||
|
// 设置 replace: true, 因此导航将不会留下历史记录
|
||||||
|
next({ ...to, replace: true })
|
||||||
|
} catch (error) {
|
||||||
|
// 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
|
||||||
|
userStore.resetToken()
|
||||||
|
ElMessage.error((error as Error).message || "路由守卫发生错误")
|
||||||
|
next("/login")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 全局后置钩子
|
||||||
|
router.afterEach((to) => {
|
||||||
|
setRouteChange(to)
|
||||||
|
setTitle(to.meta.title)
|
||||||
|
NProgress.done()
|
||||||
|
})
|
||||||
|
}
|
@ -1,11 +1,7 @@
|
|||||||
import type { Router, RouteRecordNormalized, RouteRecordRaw } from "vue-router"
|
import type { Router, RouteRecordNormalized, RouteRecordRaw } from "vue-router"
|
||||||
import { cloneDeep, omit } from "lodash-es"
|
import { cloneDeep, omit } from "lodash-es"
|
||||||
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router"
|
import { createRouter } from "vue-router"
|
||||||
|
import { routerConfig } from "./config"
|
||||||
/** 路由模式 */
|
|
||||||
export const history = import.meta.env.VITE_ROUTER_HISTORY === "hash"
|
|
||||||
? createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH)
|
|
||||||
: createWebHistory(import.meta.env.VITE_PUBLIC_PATH)
|
|
||||||
|
|
||||||
/** 路由降级(把三级及其以上的路由转化为二级路由) */
|
/** 路由降级(把三级及其以上的路由转化为二级路由) */
|
||||||
export function flatMultiLevelRoutes(routes: RouteRecordRaw[]) {
|
export function flatMultiLevelRoutes(routes: RouteRecordRaw[]) {
|
||||||
@ -29,7 +25,7 @@ function isMultipleRoute(route: RouteRecordRaw) {
|
|||||||
function promoteRouteLevel(route: RouteRecordRaw) {
|
function promoteRouteLevel(route: RouteRecordRaw) {
|
||||||
// 创建 router 实例是为了获取到当前传入的 route 的所有路由信息
|
// 创建 router 实例是为了获取到当前传入的 route 的所有路由信息
|
||||||
let router: Router | null = createRouter({
|
let router: Router | null = createRouter({
|
||||||
history,
|
history: routerConfig.history,
|
||||||
routes: [route]
|
routes: [route]
|
||||||
})
|
})
|
||||||
const routes = router.getRoutes()
|
const routes = router.getRoutes()
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import type { RouteRecordRaw } from "vue-router"
|
import type { RouteRecordRaw } from "vue-router"
|
||||||
import { routeSettings } from "@/config/route"
|
import { routerConfig } from "@/router/config"
|
||||||
|
import { registerNavigationGuard } from "@/router/guard"
|
||||||
import { createRouter } from "vue-router"
|
import { createRouter } from "vue-router"
|
||||||
import { flatMultiLevelRoutes, history } from "./helper"
|
import { flatMultiLevelRoutes } from "./helper"
|
||||||
|
|
||||||
const Layouts = () => import("@/layouts/index.vue")
|
const Layouts = () => import("@/layouts/index.vue")
|
||||||
|
|
||||||
@ -290,9 +291,10 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** 路由实例 */
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
history,
|
history: routerConfig.history,
|
||||||
routes: routeSettings.thirdLevelRouteCache ? flatMultiLevelRoutes(constantRoutes) : constantRoutes
|
routes: routerConfig.thirdLevelRouteCache ? flatMultiLevelRoutes(constantRoutes) : constantRoutes
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 重置路由 */
|
/** 重置路由 */
|
||||||
@ -310,3 +312,6 @@ export function resetRouter() {
|
|||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册路由导航守卫
|
||||||
|
registerNavigationGuard(router)
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import { setRouteChange } from "@/composables/useRouteListener"
|
|
||||||
import { useTitle } from "@/composables/useTitle"
|
|
||||||
import { routeSettings } from "@/config/route"
|
|
||||||
import { isWhiteList } from "@/config/white-list"
|
|
||||||
import { usePermissionStore } from "@/pinia/stores/permission"
|
|
||||||
import { useUserStore } from "@/pinia/stores/user"
|
|
||||||
import { router } from "@/router"
|
|
||||||
import { getToken } from "@/utils/cache/cookies"
|
|
||||||
import { ElMessage } from "element-plus"
|
|
||||||
import NProgress from "nprogress"
|
|
||||||
import "nprogress/nprogress.css"
|
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false })
|
|
||||||
const { setTitle } = useTitle()
|
|
||||||
|
|
||||||
router.beforeEach(async (to, _from, next) => {
|
|
||||||
NProgress.start()
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
// 如果没有登陆
|
|
||||||
if (!getToken()) {
|
|
||||||
// 如果在免登录的白名单中,则直接进入
|
|
||||||
if (isWhiteList(to)) return next()
|
|
||||||
// 其他没有访问权限的页面将被重定向到登录页面
|
|
||||||
return next("/login")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果已经登录,并准备进入 Login 页面,则重定向到主页
|
|
||||||
if (to.path === "/login") return next({ path: "/" })
|
|
||||||
|
|
||||||
// 如果用户已经获得其权限角色
|
|
||||||
if (userStore.roles.length !== 0) return next()
|
|
||||||
|
|
||||||
// 否则要重新获取权限角色
|
|
||||||
try {
|
|
||||||
await userStore.getInfo()
|
|
||||||
// 注意:角色必须是一个数组! 例如: ["admin"] 或 ["developer", "editor"]
|
|
||||||
const roles = userStore.roles
|
|
||||||
// 生成可访问的 Routes
|
|
||||||
routeSettings.dynamic ? permissionStore.setRoutes(roles) : permissionStore.setAllRoutes()
|
|
||||||
// 将 "有访问权限的动态路由" 添加到 Router 中
|
|
||||||
permissionStore.addRoutes.forEach(route => router.addRoute(route))
|
|
||||||
// 设置 replace: true, 因此导航将不会留下历史记录
|
|
||||||
next({ ...to, replace: true })
|
|
||||||
} catch (error) {
|
|
||||||
// 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
|
|
||||||
userStore.resetToken()
|
|
||||||
ElMessage.error((error as Error).message || "路由守卫发生错误")
|
|
||||||
next("/login")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
router.afterEach((to) => {
|
|
||||||
setRouteChange(to)
|
|
||||||
setTitle(to.meta.title)
|
|
||||||
NProgress.done()
|
|
||||||
})
|
|
Loading…
x
Reference in New Issue
Block a user