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.
253 lines
8.6 KiB
253 lines
8.6 KiB
import { toRaw } from 'vue' |
|
import { defineStore } from 'pinia' |
|
|
|
import { useUserStore } from './user' |
|
import { useAppStoreWithOut } from './app' |
|
import { store } from '@/store' |
|
import type { AppRouteRecordRaw, Menu } from '@/router/types' |
|
import { asyncRoutes } from '@/router/routes' |
|
import about from '@/router/routes/modules/about' |
|
import dashboard from '@/router/routes/modules/dashboard' |
|
import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic' |
|
import { transformRouteToMenu } from '@/router/helper/menuHelper' |
|
import { flatMultiLevelRoutes, transformObjToRoute } from '@/router/helper/routeHelper' |
|
import { useI18n } from '@/hooks/web/useI18n' |
|
import { useMessage } from '@/hooks/web/useMessage' |
|
import { filter } from '@/utils/helper/treeHelper' |
|
import projectSetting from '@/settings/projectSetting' |
|
import { PageEnum } from '@/enums/pageEnum' |
|
import { PermissionModeEnum } from '@/enums/appEnum' |
|
|
|
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 |
|
}, |
|
getBackMenuList(state): Menu[] { |
|
return state.backMenuList |
|
}, |
|
getFrontMenuList(state): Menu[] { |
|
return state.frontMenuList |
|
}, |
|
getLastBuildMenuTime(state): number { |
|
return state.lastBuildMenuTime |
|
}, |
|
getIsDynamicAddedRoute(state): boolean { |
|
return state.isDynamicAddedRoute |
|
}, |
|
}, |
|
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 |
|
}, |
|
changePermissionCode(codeList: string[]) { |
|
this.setPermCodeList(codeList) |
|
}, |
|
|
|
// 构建路由 |
|
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) || {} |
|
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 根据设置的首页path,修正routes中的affix标记(固定首页) |
|
* */ |
|
const patchHomeAffix = (routes: AppRouteRecordRaw[]) => { |
|
if (!routes || routes.length === 0) |
|
return |
|
let homePath: string = PageEnum.BASE_HOME |
|
|
|
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) { |
|
// 已处理完毕跳出循环 |
|
} |
|
} |
|
|
|
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 = userInfo.menus as AppRouteRecordRaw[] |
|
} |
|
catch (error) { |
|
console.error(error) |
|
} |
|
// Dynamically introduce components |
|
// 动态引入组件 |
|
routeList = transformObjToRoute(routeList) |
|
// Background routing to menu structure |
|
// 后台路由到菜单结构 |
|
const backMenuList = transformRouteToMenu([dashboard, ...routeList, about]) |
|
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, about] |
|
break |
|
} |
|
|
|
// 从用户中获取权限 |
|
if (userInfo) |
|
this.setPermCodeList(userInfo.permissions) |
|
|
|
patchHomeAffix(routes) |
|
return routes |
|
}, |
|
}, |
|
}) |
|
|
|
// Need to be used outside the setup |
|
// 需要在设置之外使用 |
|
export function usePermissionStoreWithOut() { |
|
return usePermissionStore(store) |
|
}
|
|
|