permission.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import { defineStore } from 'pinia'
  2. import { asyncRouterMap, constantRouterMap } from '@/router'
  3. import { deepClone } from '@/utils'
  4. import { AppRouteRecordRaw } from '@/router/types'
  5. import { useCache } from '@/hooks/web/useCache'
  6. const { wsCache } = useCache()
  7. import { isExternal } from '@/utils/validate'
  8. import path from 'path-browserify'
  9. import { getParentLayout } from '@/router/utils'
  10. import { store } from '../index'
  11. import { useAppStoreWithOut } from '@/store/modules/app'
  12. const appStore = useAppStoreWithOut()
  13. const modules = import.meta.glob('../../views/**/*.vue')
  14. /* Layout */
  15. const Layout = () => import('@/layout/index.vue')
  16. export interface PermissionState {
  17. routers: AppRouteRecordRaw[]
  18. addRouters: AppRouteRecordRaw[]
  19. isAddRouters: boolean
  20. activeTab: string
  21. menuTabRouters: AppRouteRecordRaw[]
  22. }
  23. export const usePermissionStore = defineStore({
  24. id: 'permission',
  25. state: (): PermissionState => ({
  26. routers: [],
  27. addRouters: [],
  28. isAddRouters: false,
  29. menuTabRouters: [],
  30. activeTab: ''
  31. }),
  32. getters: {
  33. getRouters(): AppRouteRecordRaw[] {
  34. return this.routers
  35. },
  36. getAddRouters(): AppRouteRecordRaw[] {
  37. return this.addRouters
  38. },
  39. getIsAddRouters(): boolean {
  40. return this.isAddRouters
  41. },
  42. getActiveTab(): string {
  43. return this.activeTab
  44. },
  45. getMenuTabRouters(): AppRouteRecordRaw[] {
  46. return this.menuTabRouters
  47. }
  48. },
  49. actions: {
  50. generateRoutes(): Promise<unknown> {
  51. return new Promise<void>((resolve) => {
  52. // 路由权限控制
  53. let routerMap: AppRouteRecordRaw[] = []
  54. if (wsCache.get(appStore.getUserInfo).roleName === 'admin') {
  55. // 模拟前端控制权限
  56. routerMap = generateRoutesFn(deepClone(asyncRouterMap, ['component']))
  57. } else {
  58. // 模拟后端控制权限
  59. routerMap = getFilterRoutes(wsCache.get(appStore.getUserInfo).checkedNodes)
  60. }
  61. // const routerMap: AppRouteRecordRaw[] = generateRoutesFn(deepClone(asyncRouterMap, ['component']))
  62. // 动态路由,404一定要放到最后面
  63. this.addRouters = routerMap.concat([
  64. {
  65. path: '/:path(.*)*',
  66. redirect: '/404',
  67. name: '404',
  68. meta: {
  69. hidden: true,
  70. breadcrumb: false
  71. }
  72. }
  73. ])
  74. // 渲染菜单的所有路由
  75. this.routers = deepClone(constantRouterMap, ['component']).concat(routerMap)
  76. resolve()
  77. })
  78. },
  79. setIsAddRouters(state: boolean): void {
  80. this.isAddRouters = state
  81. },
  82. setMenuTabRouters(routers: AppRouteRecordRaw[]): void {
  83. this.menuTabRouters = routers
  84. },
  85. setAcitveTab(activeTab: string): void {
  86. this.activeTab = activeTab
  87. }
  88. }
  89. })
  90. // 路由过滤,主要用于权限控制
  91. function generateRoutesFn(routes: AppRouteRecordRaw[], basePath = '/'): AppRouteRecordRaw[] {
  92. const res: AppRouteRecordRaw[] = []
  93. for (const route of routes) {
  94. // skip some route
  95. if (route.meta && route.meta.hidden && !route.meta.showMainRoute) {
  96. console.log(route)
  97. continue
  98. }
  99. let onlyOneChild: Nullable<string> = null
  100. if (route.children && route.children.length === 1 && !route.meta.alwaysShow) {
  101. onlyOneChild = (
  102. isExternal(route.children[0].path)
  103. ? route.children[0].path
  104. : path.resolve(path.resolve(basePath, route.path), route.children[0].path)
  105. ) as string
  106. }
  107. let data: Nullable<IObj> = null
  108. // 如不需要路由权限,可注释以下逻辑
  109. // 权限过滤,通过获取登录信息里面的角色权限,动态的渲染菜单。
  110. const list = wsCache.get(appStore.getUserInfo).checkedNodes
  111. // 开发者可以根据实际情况进行扩展
  112. for (const item of list) {
  113. // 通过路径去匹配
  114. if (isExternal(item.path) && (onlyOneChild === item.path || route.path === item.path)) {
  115. data = Object.assign({}, route)
  116. } else {
  117. const routePath = path.resolve(basePath, onlyOneChild || route.path)
  118. if (routePath === item.path || (route.meta && route.meta.followRoute === item.path)) {
  119. data = Object.assign({}, route)
  120. }
  121. }
  122. }
  123. // 如不需要路由权限,解注释下面一行
  124. // data = Object.assign({}, route)
  125. // recursive child routes
  126. if (route.children && data) {
  127. data.children = generateRoutesFn(route.children, path.resolve(basePath, data.path))
  128. }
  129. if (data) {
  130. res.push(data as AppRouteRecordRaw)
  131. }
  132. }
  133. return res
  134. }
  135. // 模拟后端过滤路由
  136. function getFilterRoutes(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] {
  137. const res: AppRouteRecordRaw[] = []
  138. for (const route of routes) {
  139. const data: AppRouteRecordRaw | IObj = {
  140. path: route.path,
  141. name: route.name,
  142. redirect: route.redirect
  143. }
  144. data.meta = Object.assign({}, route.meta || {}, { title: route.meta.title })
  145. if (route.component) {
  146. // 动态加载路由文件,可根据实际情况进行自定义逻辑
  147. data.component = (
  148. (route.component as any) === '#'
  149. ? Layout
  150. : (route.component as any).includes('##')
  151. ? getParentLayout((route.component as any).split('##')[1])
  152. : modules[`../../${route.component}.vue`]
  153. ) as any
  154. }
  155. // recursive child routes
  156. if (route.children) {
  157. data.children = getFilterRoutes(route.children)
  158. }
  159. res.push(data as AppRouteRecordRaw)
  160. }
  161. return res
  162. }
  163. export function usePermissionStoreWithOut() {
  164. return usePermissionStore(store)
  165. }