You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

259 lines
8.7 KiB

2 years ago
import type { AppRouteRecordRaw, Menu } from '@/router/types'
import { toRaw } from 'vue'
2 years ago
import { defineStore } from 'pinia'
import { store } from '@/store'
2 years ago
import { useUserStore } from './user'
import { useAppStoreWithOut } from './app'
import { asyncRoutes } from '@/router/routes'
import about from '@/router/routes/modules/about'
import menu from '@/router/routes/modules/menu'
import dashboard from '@/router/routes/modules/dashboard'
import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic'
import { transformRouteToMenu } from '@/router/helper/menuHelper'
import { transformObjToRoute, flatMultiLevelRoutes } from '@/router/helper/routeHelper'
import { useI18n } from '@/hooks/web/useI18n'
2 years ago
import { useMessage } from '@/hooks/web/useMessage'
import { filter } from '@/utils/helper/treeHelper'
import projectSetting from '@/settings/projectSetting'
import { getMenuList } from '@/api/base/menu'
2 years ago
import { PageEnum } from '@/enums/pageEnum'
import { PermissionModeEnum } from '@/enums/appEnum'
2 years ago
interface PermissionState {
// Permission code list
// 权限代码列表
permCodeList: string[] | number[]
// Whether the route has been dynamically added
// 路由是否动态添加
isDynamicAddedRoute: boolean
// To trigger a menu update
// 触发菜单更新
lastBuildMenuTime: number
// Backstage menu list
// 后台菜单列表
backMenuList: Menu[]
// 菜单列表
frontMenuList: Menu[]
}
export const usePermissionStore = defineStore('app-permission', {
state: (): PermissionState => ({
// 权限代码列表
permCodeList: [],
// Whether the route has been dynamically added
// 路由是否动态添加
isDynamicAddedRoute: false,
// To trigger a menu update
// 触发菜单更新
lastBuildMenuTime: 0,
// Backstage menu list
// 后台菜单列表
backMenuList: [],
// menu List
// 菜单列表
frontMenuList: []
}),
getters: {
getPermCodeList(state): string[] | number[] {
return state.permCodeList
2 years ago
},
getBackMenuList(state): Menu[] {
return state.backMenuList
2 years ago
},
getFrontMenuList(state): Menu[] {
return state.frontMenuList
2 years ago
},
getLastBuildMenuTime(state): number {
return state.lastBuildMenuTime
2 years ago
},
getIsDynamicAddedRoute(state): boolean {
return state.isDynamicAddedRoute
2 years ago
}
},
actions: {
setPermCodeList(codeList: string[]) {
this.permCodeList = codeList
},
setBackMenuList(list: Menu[]) {
this.backMenuList = list
list?.length > 0 && this.setLastBuildMenuTime()
},
setFrontMenuList(list: Menu[]) {
this.frontMenuList = list
},
setLastBuildMenuTime() {
this.lastBuildMenuTime = new Date().getTime()
},
setDynamicAddedRoute(added: boolean) {
this.isDynamicAddedRoute = added
},
resetState(): void {
this.isDynamicAddedRoute = false
this.permCodeList = []
this.backMenuList = []
this.lastBuildMenuTime = 0
},
async changePermissionCode(codeList: string[]) {
2 years ago
this.setPermCodeList(codeList)
},
// 构建路由
async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
const { t } = useI18n()
const userStore = useUserStore()
const appStore = useAppStoreWithOut()
let routes: AppRouteRecordRaw[] = []
const roleList = toRaw(userStore.getRoleList) || []
const userInfo = toRaw(userStore.getUserInfo) || {}
2 years ago
const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig
// 路由过滤器 在 函数filter 作为回调传入遍历使用
const routeFilter = (route: AppRouteRecordRaw) => {
const { meta } = route
// 抽出角色
const { roles } = meta || {}
if (!roles) return true
// 进行角色权限判断
return roleList.some((role) => roles.includes(role))
}
const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => {
const { meta } = route
// ignoreRoute 为true 则路由仅用于菜单生成,不会在实际的路由表中出现
const { ignoreRoute } = meta || {}
// arr.filter 返回 true 表示该元素通过测试
return !ignoreRoute
}
/**
* @description pathroutes中的affix标记
* */
const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
if (!routes || routes.length === 0) return
let homePath: string = PageEnum.BASE_HOME
2 years ago
function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
if (parentPath) parentPath = parentPath + '/'
routes.forEach((route: AppRouteRecordRaw) => {
const { path, children, redirect } = route
const currentPath = path.startsWith('/') ? path : parentPath + path
if (currentPath === homePath) {
if (redirect) {
homePath = route.redirect! as string
} else {
route.meta = Object.assign({}, route.meta, { affix: true })
throw new Error('end')
}
}
children && children.length > 0 && patcher(children, currentPath)
})
}
try {
patcher(routes)
} catch (e) {
// 已处理完毕跳出循环
}
return
}
switch (permissionMode) {
// 角色权限
case PermissionModeEnum.ROLE:
// 对非一级路由进行过滤
routes = filter(asyncRoutes, routeFilter)
// 对一级路由根据角色权限过滤
routes = routes.filter(routeFilter)
// Convert multi-level routing to level 2 routing
// 将多级路由转换为 2 级路由
routes = flatMultiLevelRoutes(routes)
break
// 路由映射, 默认进入该case
case PermissionModeEnum.ROUTE_MAPPING:
// 对非一级路由进行过滤
routes = filter(asyncRoutes, routeFilter)
// 对一级路由再次根据角色权限过滤
routes = routes.filter(routeFilter)
// 将路由转换成菜单
const menuList = transformRouteToMenu(routes, true)
// 移除掉 ignoreRoute: true 的路由 非一级路由
routes = filter(routes, routeRemoveIgnoreFilter)
// 移除掉 ignoreRoute: true 的路由 一级路由;
routes = routes.filter(routeRemoveIgnoreFilter)
// 对菜单进行排序
menuList.sort((a, b) => {
return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0)
})
// 设置菜单列表
this.setFrontMenuList(menuList)
// Convert multi-level routing to level 2 routing
// 将多级路由转换为 2 级路由
routes = flatMultiLevelRoutes(routes)
break
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
// 如果确定不需要做后台动态权限,请在下方注释整个判断
case PermissionModeEnum.BACK:
const { createMessage } = useMessage()
createMessage.loading({
content: t('sys.app.menuLoading'),
duration: 1
})
// !Simulate to obtain permission codes from the background,
// 模拟从后台获取权限码,
// this function may only need to be executed once, and the actual project can be put at the right time by itself
// 这个功能可能只需要执行一次,实际项目可以自己放在合适的时间
let routeList: AppRouteRecordRaw[] = []
try {
routeList = (await getMenuList()) as AppRouteRecordRaw[]
} catch (error) {
console.error(error)
}
// Dynamically introduce components
// 动态引入组件
routeList = transformObjToRoute(routeList)
// Background routing to menu structure
// 后台路由到菜单结构
const backMenuList = transformRouteToMenu([dashboard, ...routeList, menu, about])
2 years ago
this.setBackMenuList(backMenuList)
// remove meta.ignoreRoute item
// 删除 meta.ignoreRoute 项
routeList = filter(routeList, routeRemoveIgnoreFilter)
routeList = routeList.filter(routeRemoveIgnoreFilter)
routeList = flatMultiLevelRoutes(routeList)
routes = [PAGE_NOT_FOUND_ROUTE, dashboard, ...routeList, menu, about]
2 years ago
break
}
// 从用户中获取权限
if (userInfo) {
this.setPermCodeList(userInfo.permissions)
}
2 years ago
patchHomeAffix(routes)
return routes
}
}
})
// Need to be used outside the setup
// 需要在设置之外使用
export function usePermissionStoreWithOut() {
return usePermissionStore(store)
}