122 lines
4.7 KiB
TypeScript
122 lines
4.7 KiB
TypeScript
// Author: fruit.com.cn
|
||
|
||
import router, { resetRouter } from './router'
|
||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||
import type { RouteRecordRaw } from 'vue-router'
|
||
import { useTitle } from '@/hooks/web/useTitle'
|
||
import { useNProgress } from '@/hooks/web/useNProgress'
|
||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||
import { usePageLoading } from '@/hooks/web/usePageLoading'
|
||
import { NO_REDIRECT_WHITE_LIST } from '@/constants'
|
||
import { useUserStoreWithOut } from '@/store/modules/user'
|
||
import { getAdminRoleApi, getProfileApi } from '@/api/login'
|
||
import { landingPath } from '@/utils/landing'
|
||
import { supplementLocalAdminRoutes } from '@/router/localRoutes'
|
||
|
||
const { start, done } = useNProgress()
|
||
|
||
const { loadStart, loadDone } = usePageLoading()
|
||
|
||
router.beforeEach(async (to, from, next) => {
|
||
start()
|
||
loadStart()
|
||
const permissionStore = usePermissionStoreWithOut()
|
||
const appStore = useAppStoreWithOut()
|
||
const userStore = useUserStoreWithOut()
|
||
if (userStore.getUserInfo) {
|
||
if (to.path === '/login') {
|
||
next({ path: '/' })
|
||
} else {
|
||
if (permissionStore.getIsAddRouters) {
|
||
// 已加过路由:只有还是同一个账号才能直接放行。
|
||
// 换账号时(例如超管退出后创作者登录)必须重建,否则侧边栏/路由会残留上一个账号的
|
||
const username = userStore.getUserInfo?.username || ''
|
||
if (permissionStore.getRoutersOwner === username) {
|
||
next()
|
||
return
|
||
}
|
||
// 摘掉上一个账号动态加进去的路由,避免两套菜单并存
|
||
resetRouter()
|
||
permissionStore.setIsAddRouters(false)
|
||
}
|
||
|
||
const username = userStore.getUserInfo?.username || ''
|
||
const ownerChanged = permissionStore.getRoutersOwner !== username
|
||
|
||
// 开发者可根据实际情况进行修改
|
||
const roleRouters = userStore.getRoleRouters || []
|
||
|
||
// 是否使用动态路由
|
||
if (appStore.getDynamicRouter) {
|
||
if (appStore.serverDynamicRouter) {
|
||
// 每次进入应用都重新拉菜单与权限:后台改了菜单或角色权限,刷新即可生效,不必重新登录
|
||
let routers = (userStore.getRoleRouters || []) as AppCustomRouteRecordRaw[]
|
||
try {
|
||
const [profileRes, menuRes] = await Promise.all([
|
||
getProfileApi(),
|
||
getAdminRoleApi({ roleName: username })
|
||
])
|
||
if (profileRes?.data) {
|
||
userStore.setUserInfo({ ...userStore.getUserInfo, ...profileRes.data })
|
||
}
|
||
if (menuRes?.data?.length) {
|
||
routers = menuRes.data
|
||
userStore.setRoleRouters(routers)
|
||
} else if (ownerChanged) {
|
||
// 换账号后菜单拉不到就别沿用上一个账号的缓存,宁可先给空菜单
|
||
routers = []
|
||
}
|
||
} catch {
|
||
// 拉取失败时退回上次缓存的菜单,不阻塞进入
|
||
}
|
||
const permissions = Array.isArray(userStore.getUserInfo?.permissions)
|
||
? userStore.getUserInfo.permissions
|
||
: []
|
||
routers = supplementLocalAdminRoutes(routers, permissions)
|
||
await permissionStore.generateRoutes('server', routers)
|
||
} else {
|
||
await permissionStore.generateRoutes('frontEnd', roleRouters as string[])
|
||
}
|
||
} else {
|
||
await permissionStore.generateRoutes('static')
|
||
}
|
||
|
||
permissionStore.getAddRouters.forEach((route) => {
|
||
router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
|
||
})
|
||
permissionStore.setRoutersOwner(username)
|
||
|
||
// 根路径按"这个账号能进的第一个菜单"落地:路由表里写死的 redirect 是 /dashboard/index,
|
||
// 创作者没有运营后台权限,访问 '/' 会直接掉 404
|
||
if (to.path === '/') {
|
||
permissionStore.setIsAddRouters(true)
|
||
next({ path: landingPath(), replace: true })
|
||
return
|
||
}
|
||
|
||
const redirectPath = from.query.redirect || to.path
|
||
const redirect = decodeURIComponent(redirectPath as string)
|
||
// 只按路径重进。刷新时动态路由还没注册,先被兜底路由接住;
|
||
// 若把当时匹配到的 name 带回去,会一直停在 404。
|
||
const nextData =
|
||
to.path === redirect
|
||
? { path: to.path, query: to.query, hash: to.hash, replace: true }
|
||
: { path: redirect, replace: true }
|
||
permissionStore.setIsAddRouters(true)
|
||
next(nextData)
|
||
}
|
||
} else {
|
||
if (NO_REDIRECT_WHITE_LIST.indexOf(to.path) !== -1) {
|
||
next()
|
||
} else {
|
||
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
|
||
}
|
||
}
|
||
})
|
||
|
||
router.afterEach((to) => {
|
||
useTitle(to?.meta?.title as string)
|
||
done() // 结束Progress
|
||
loadDone()
|
||
})
|