generator-routers.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import { getMenus } from '@/api/system/menu'
  2. import { constantRouterIcon } from './router-icons'
  3. import { RouteRecordRaw } from 'vue-router'
  4. import { asyncRoutes } from '@/router/constant'
  5. import { BaseRoute } from '@/router/base'
  6. import type { AppRouteRecordRaw } from '@/router/types'
  7. import deepClone from '@/utils/deep.clone'
  8. import CourseKnowledgePoint from '@/views/teaching-manage/courseware-manage/model/CourseKnowledgePoint'
  9. import { PageEnum } from '@/enums/pageEnum'
  10. const Iframe = () => import('@/views/iframe/index.vue')
  11. const LayoutMap = new Map<string, () => Promise<typeof import('*.vue')>>()
  12. LayoutMap.set('LAYOUT', asyncRoutes.Layout)
  13. LayoutMap.set('IFRAME', Iframe)
  14. /**
  15. * 格式化 后端 结构信息并递归生成层级路由表
  16. * @param routerMap
  17. * @param parent
  18. * @returns {*}
  19. */
  20. export const routerGenerator = (routerMap: any, parent?: any): any[] => {
  21. const asyncRoute: any = asyncRoutes
  22. const constantRouterI: any = constantRouterIcon
  23. return routerMap.map((item: any) => {
  24. if (item.type === 1) {
  25. return
  26. }
  27. const currentRouter: any = {
  28. // 路由地址 动态拼接生成如 /dashboard/workplace
  29. path:
  30. item.path.indexOf('/') > -1 ? item.path : `${(parent && parent.path) || ''}/${item.path}`,
  31. // 路由名称,建议唯一
  32. name: item.path || '',
  33. // 该路由对应页面的 组件
  34. component: asyncRoute[item.component],
  35. // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
  36. show: item.hidden === 0 ? true : false,
  37. parent: item.parent,
  38. meta: {
  39. ...item.meta,
  40. label: item.name,
  41. title: item.name,
  42. id: item.id,
  43. icon: constantRouterI[item.icon] || null,
  44. parentPermission: item.parentPermission || null
  45. // permissions: item.meta.permissions || null,
  46. },
  47. props: true
  48. }
  49. // console.log(item.name, '格式化路由')
  50. // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
  51. currentRouter.path = currentRouter.path.replace('//', '/')
  52. // 重定向
  53. item.redirect && (currentRouter.redirect = item.redirect)
  54. // 是否有子菜单,并递归处理
  55. if (item.children && item.children.length > 0) {
  56. //如果未定义 redirect 默认第一个子路由为 redirect
  57. // !item.redirect && (currentRouter.redirect = `${item.path}/${item.children[0].path}`)
  58. // Recursion
  59. currentRouter.children = routerGenerator(item.children, currentRouter)
  60. }
  61. return currentRouter
  62. })
  63. }
  64. // 格式化路由
  65. export const routerFormat = (routerMap: any) => {
  66. const newArr: any[] = []
  67. for (let i = 0; i < routerMap.length; i++) {
  68. if (routerMap[i].type == 1) {
  69. continue
  70. }
  71. const { children, ...res } = routerMap[i]
  72. const currentRouter: any = {
  73. ...res
  74. }
  75. // 是否有子菜单,并递归处理
  76. if (children && children.length > 0) {
  77. const tempChildren = routerFormat(children)
  78. // console.log(children, 'children', tempChildren)
  79. currentRouter.children = tempChildren
  80. }
  81. // console.log(currentRouter, 'currentRouter')
  82. newArr.push(currentRouter)
  83. }
  84. return newArr
  85. }
  86. // 格式化菜单
  87. export const menuFormat = (menuMap: any, parent?: any) => {
  88. const newArr: any[] = []
  89. for (let i = 0; i < menuMap.length; i++) {
  90. if (menuMap[i].type == 1) {
  91. continue
  92. }
  93. const { children, ...res } = menuMap[i]
  94. const currentRouter: any = {
  95. ...res,
  96. parent: parent ? parent.name : null
  97. }
  98. // 是否有子菜单,并递归处理
  99. if (children && children.length > 0) {
  100. // let flag = false;
  101. children.forEach((item: any) => {
  102. if (item.type == 0 && !item.hidden) {
  103. item.children = null
  104. }
  105. })
  106. const tempChildren = menuFormat(children, currentRouter)
  107. currentRouter.children = tempChildren
  108. }
  109. newArr.push(currentRouter)
  110. }
  111. return newArr
  112. }
  113. /**
  114. * 路由多级嵌套数组处理成一维数组
  115. * @param arr 传入路由菜单数据数组
  116. * @returns 返回处理后的一维路由菜单数组
  117. */
  118. export function formatFlatteningRoutes(arr: any) {
  119. if (arr.length <= 0) return false
  120. for (let i = 0; i < arr.length; i++) {
  121. if (arr[i].children) {
  122. arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1))
  123. }
  124. }
  125. return arr
  126. }
  127. function getFirstMenu(routes: any) {
  128. // 可能没有权限 提示管理
  129. if (routes && routes.length > 0) {
  130. let firstMenu: any = null
  131. routes.forEach((item: any) => {
  132. // 判断是否有首页菜单
  133. if (!firstMenu) {
  134. if (item.children?.length > 0 && !item.hidden) {
  135. firstMenu = pathErgodic(item)
  136. }
  137. }
  138. })
  139. if (checkPathUrl(firstMenu)) {
  140. return firstMenu
  141. } else {
  142. return '/' + firstMenu
  143. }
  144. }
  145. }
  146. function pathErgodic(item: any) {
  147. // console.log(item)
  148. let firstMenu: any = null
  149. item.children.forEach((i: any) => {
  150. if (!firstMenu && i.children?.length > 0 && !i.hidden) {
  151. let isChildrenList = false
  152. i.children.forEach((ii: any) => {
  153. if (!ii.hidden && ii.type) {
  154. isChildrenList = true
  155. }
  156. })
  157. if (isChildrenList) {
  158. firstMenu = pathErgodic(i)
  159. } else {
  160. if (!firstMenu && checkPathUrl(i.path)) {
  161. firstMenu = i.path
  162. } else {
  163. if (!firstMenu && !i.hidden) {
  164. firstMenu = item.path + '/' + i.path
  165. }
  166. }
  167. }
  168. } else {
  169. if (!firstMenu && checkPathUrl(i.path)) {
  170. firstMenu = i.path
  171. } else {
  172. if (!firstMenu && !i.hidden) {
  173. firstMenu = item.path + '/' + i.path
  174. }
  175. }
  176. }
  177. })
  178. return firstMenu
  179. }
  180. // 判断path有没有带/,并且是第一个位置
  181. function checkPathUrl(path: any) {
  182. return path.indexOf('/') === 0 ? true : false
  183. }
  184. let tempArr: Array<any> = []
  185. /**
  186. * 动态生成菜单
  187. * @returns {Promise<Router>}
  188. */
  189. export const generatorDynamicRouter = (): any => {
  190. return new Promise((resolve, reject) => {
  191. getMenus({ delFlag: false })
  192. .then((result) => {
  193. // 设置路由
  194. setAuthList(result.data)
  195. const t = menuFormat(deepClone(result.data))
  196. const routers = routerFormat(deepClone(result.data))
  197. // 讲多级路由转化1级路由
  198. // 格式化路由
  199. BaseRoute.children = formatFlatteningRoutes(routerGenerator(routers))
  200. const menu = routerGenerator(t)
  201. const firstMenu = getFirstMenu(routers)
  202. // console.log(firstMenu, 'firstMenu', BaseRoute)
  203. PageEnum.BASE_HOME = firstMenu
  204. // 同步 异步路由
  205. resolve({
  206. routes: BaseRoute,
  207. authList: tempArr,
  208. menu: menu
  209. })
  210. })
  211. .catch((err) => {
  212. reject(err)
  213. })
  214. })
  215. }
  216. /**
  217. * 设置所有的权限集合
  218. * @returns
  219. */
  220. export const setAuthList = (arr: any) => {
  221. arr.map((item: any) => {
  222. tempArr.push(item.permission + item.id)
  223. if (item.children && item.children.length > 0) {
  224. setAuthList(item.children)
  225. }
  226. })
  227. }
  228. /**
  229. *
  230. * @param routes: any
  231. * @param component
  232. * @returns 格式化后带顶部的路由
  233. */
  234. export function addTopMenu(routes: any) {
  235. if (routes.length > 0) {
  236. let newArr = []
  237. for (let i = 0; i < routes.length; i++) {
  238. if (routes[i].type == 1) {
  239. continue
  240. }
  241. let obj = routes[i]
  242. obj.belongTopMenu = obj.path
  243. if (routes[i].sysMenus && routes[i].sysMenus.length > 0) {
  244. obj.sysMenus = setTopMenu(routes[i].sysMenus, obj)
  245. }
  246. newArr.push(obj)
  247. }
  248. return newArr
  249. }
  250. }
  251. /**
  252. *
  253. * @param routes: any
  254. * @param 递归给每一层菜单附上一个 belongTopMenu
  255. * @returns
  256. */
  257. export function setTopMenu(arr: any, topParentArr: any) {
  258. let newArr = []
  259. for (let i = 0; i < arr.length; i++) {
  260. let obj = arr[i]
  261. obj.belongTopMenu = topParentArr.path
  262. if (arr[i].sysMenus && arr[i].sysMenus.length > 0) {
  263. obj.sysMenus = setTopMenu(arr[i].sysMenus, topParentArr)
  264. }
  265. newArr.push(obj)
  266. }
  267. return newArr
  268. }