150 lines
4.8 KiB
TypeScript
150 lines
4.8 KiB
TypeScript
import { asyncRouterMap, constantRouterMap } from '_p/index/router'
|
||
import { deepClone } from '@/utils'
|
||
import store from '../index'
|
||
import { VuexModule, getModule, Module, Mutation, Action } from 'vuex-module-decorators'
|
||
import { AppRouteRecordRaw } from '_p/index/router/types'
|
||
import wsCache from '@/cache'
|
||
import { isExternal } from '@/utils/validate'
|
||
import path from 'path'
|
||
import { getParentLayout } from '_p/index/router/utils'
|
||
|
||
import { appStore } from '_p/index/store/modules/app'
|
||
|
||
/* Layout */
|
||
const Layout = () => import('_p/index/layout/index.vue')
|
||
|
||
export interface PermissionState {
|
||
routers: AppRouteRecordRaw[]
|
||
addRouters: AppRouteRecordRaw[]
|
||
isAddRouters: boolean
|
||
}
|
||
|
||
@Module({ dynamic: true, namespaced: true, store, name: 'permission' })
|
||
class Permission extends VuexModule implements PermissionState {
|
||
public routers = [] as any[]
|
||
public addRouters = [] as any[]
|
||
public isAddRouters = false
|
||
|
||
@Mutation
|
||
private SET_ROUTERS(routers: AppRouteRecordRaw[]): void {
|
||
// 动态路由,404一定要放到最后面
|
||
this.addRouters = routers.concat([{
|
||
path: '/:path(.*)*',
|
||
redirect: '/404',
|
||
name: '404',
|
||
meta: {
|
||
hidden: true,
|
||
breadcrumb: false
|
||
}
|
||
}])
|
||
// 渲染菜单的所有路由
|
||
this.routers = deepClone(constantRouterMap, ['component']).concat(routers)
|
||
}
|
||
@Mutation
|
||
private SET_ISADDROUTERS(state: boolean): void {
|
||
this.isAddRouters = state
|
||
}
|
||
|
||
@Action
|
||
public GenerateRoutes(): Promise<unknown> {
|
||
return new Promise(resolve => {
|
||
// 路由权限控制
|
||
let routerMap: AppRouteRecordRaw[] = []
|
||
if (wsCache.get(appStore.userInfo).roleName === 'admin') {
|
||
// 模拟前端控制权限
|
||
routerMap = generateRoutes(deepClone(asyncRouterMap, ['component']))
|
||
} else {
|
||
// 模拟后端控制权限
|
||
routerMap = getFilterRoutes(wsCache.get(appStore.userInfo).checkedNodes)
|
||
}
|
||
// const routerMap: AppRouteRecordRaw[] = generateRoutes(deepClone(asyncRouterMap, ['component']))
|
||
this.SET_ROUTERS(routerMap)
|
||
resolve()
|
||
})
|
||
}
|
||
@Action
|
||
public SetIsAddRouters(state: boolean): void {
|
||
this.SET_ISADDROUTERS(state)
|
||
}
|
||
}
|
||
|
||
// 路由过滤,主要用于权限控制
|
||
function generateRoutes(routes: AppRouteRecordRaw[], basePath = '/'): AppRouteRecordRaw[] {
|
||
const res: AppRouteRecordRaw[] = []
|
||
|
||
for (const route of routes) {
|
||
// skip some route
|
||
if (route.meta && route.meta.hidden && !route.meta.showMainRoute) {
|
||
continue
|
||
}
|
||
|
||
let onlyOneChild = null
|
||
|
||
if (route.children && route.children.length === 1 && !route.meta.alwaysShow) {
|
||
onlyOneChild = isExternal(route.children[0].path)
|
||
? route.children[0].path
|
||
: path.resolve(path.resolve(basePath, route.path), route.children[0].path)
|
||
}
|
||
|
||
let data: any = null
|
||
|
||
// 如不需要路由权限,可注释以下逻辑
|
||
// 权限过滤,通过获取登录信息里面的角色权限,动态的渲染菜单。
|
||
const list = wsCache.get(appStore.userInfo).checkedNodes
|
||
// 开发者可以根据实际情况进行扩展
|
||
for (const item of list) {
|
||
// 通过路径去匹配
|
||
if (isExternal(item.path) && (onlyOneChild === item.path || route.path === item.path)) {
|
||
data = Object.assign({}, route)
|
||
} else {
|
||
const routePath = path.resolve(basePath, onlyOneChild || route.path)
|
||
if (routePath === item.path || (route.meta && route.meta.followRoute === item.path)) {
|
||
data = Object.assign({}, route)
|
||
}
|
||
}
|
||
}
|
||
// 如不需要路由权限,解注释下面一行
|
||
// data = Object.assign({}, route)
|
||
|
||
// recursive child routes
|
||
if (route.children && data) {
|
||
data.children = generateRoutes(route.children, path.resolve(basePath, data.path))
|
||
}
|
||
if (data) {
|
||
res.push(data as AppRouteRecordRaw)
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
|
||
// 模拟后端过滤路由
|
||
function getFilterRoutes(routes: any[]): any[] {
|
||
const res = []
|
||
|
||
for (const route of routes) {
|
||
const data: any = {
|
||
path: route.path,
|
||
name: route.name,
|
||
redirect: route.redirect
|
||
}
|
||
data.meta = Object.assign({}, route.meta || {}, { title: route.title || route.meta.title })
|
||
if (route.component) {
|
||
// 动态加载路由文件,可根据实际情况进行自定义逻辑
|
||
data.component = route.component === '#'
|
||
? Layout
|
||
: (route.component.includes('##')
|
||
? getParentLayout(route.component.split('##')[1])
|
||
// 必须加'.vue'后缀,而不能直接把'.vue'后缀写在component中。否则会报出警告。。
|
||
: () => import('@/' + route.component + '.vue'))
|
||
}
|
||
// recursive child routes
|
||
if (route.children) {
|
||
data.children = getFilterRoutes(route.children)
|
||
}
|
||
res.push(data)
|
||
}
|
||
return res
|
||
}
|
||
|
||
export const permissionStore = getModule<Permission>(Permission)
|