index.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /**
  2. * Copyright [2022] [https://www.xiaonuo.vip]
  3. * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
  4. * 1.请不要删除和修改根目录下的LICENSE文件。
  5. * 2.请不要删除和修改Snowy源码头部的版权声明。
  6. * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
  7. * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
  8. * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
  9. * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
  10. */
  11. import { createRouter, createWebHistory } from 'vue-router'
  12. import { notification } from 'ant-design-vue'
  13. import NProgress from 'nprogress'
  14. import 'nprogress/nprogress.css'
  15. import systemRouter from './systemRouter'
  16. import { afterEach, beforeEach } from './scrollBehavior'
  17. import whiteListRouters from './whiteList'
  18. import portal from './portal'
  19. import userRoutes from '@/config/route'
  20. import tool from '@/utils/tool'
  21. import fullPageTool from './fullPageTool'
  22. import { cloneDeep } from 'lodash-es'
  23. const modules = import.meta.glob('/src/views/**/**.vue')
  24. import { globalStore, searchStore } from '@/store'
  25. // 进度条配置
  26. NProgress.configure({ showSpinner: false, speed: 500 })
  27. // 系统特殊路由
  28. const routes_404 = [
  29. {
  30. path: '/:pathMatch(.*)*',
  31. hidden: true,
  32. component: () => import('@/layout/other/404.vue')
  33. }
  34. ]
  35. // 系统路由
  36. const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
  37. const router = createRouter({
  38. history: createWebHistory(),
  39. routes
  40. })
  41. // 设置标题
  42. // document.title = sysBaseConfig.SNOWY_SYS_NAME
  43. // 判断是否已加载过动态/静态路由
  44. const isGetRouter = ref(false)
  45. // 白名单校验
  46. const exportWhiteListFromRouter = (router) => {
  47. const res = []
  48. for (const item of router) res.push(item.path)
  49. return res
  50. }
  51. const whiteList = exportWhiteListFromRouter(whiteListRouters)
  52. router.beforeEach(async (to, from, next) => {
  53. NProgress.start()
  54. const store = globalStore()
  55. const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.sysBaseConfig
  56. // 动态标题
  57. document.title = to.meta.title
  58. ? `${to.meta.title} - ${sysBaseConfig.SNOWY_SYS_NAME}`
  59. : `${sysBaseConfig.SNOWY_SYS_NAME}`
  60. // 过滤白名单
  61. if (whiteList.includes(to.path)) {
  62. next()
  63. // NProgress.done()
  64. return false
  65. }
  66. const token = tool.data.get('TOKEN')
  67. if (to.path === '/login') {
  68. // 当用户输入了login路由,将其跳转首页即可
  69. if (token) {
  70. next({
  71. path: '/'
  72. })
  73. return false
  74. }
  75. // 删除路由(替换当前layout路由)
  76. router.addRoute(routes[0])
  77. isGetRouter.value = false
  78. next()
  79. return false
  80. } else {
  81. if (token) {
  82. // 有token的时候才保存登录之前要访问的页面
  83. tool.data.set('LAST_VIEWS_PATH', to.fullPath)
  84. }
  85. fullPageTool.check(to)
  86. }
  87. if (!token) {
  88. next({
  89. path: '/login'
  90. })
  91. return false
  92. }
  93. // 整页路由处理
  94. if (to.meta.fullpage) {
  95. to.matched = [to.matched[to.matched.length - 1]]
  96. }
  97. // 加载动态/静态路由
  98. if (!isGetRouter.value) {
  99. const apiMenu = tool.data.get('MENU') || []
  100. if (apiMenu.length === 0) {
  101. // 创建默认模块,显示默认菜单
  102. apiMenu[0] = cloneDeep(userRoutes.module[0])
  103. }
  104. const childrenApiMenu = apiMenu[0].children
  105. apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
  106. let menuRouter = filterAsyncRouter(apiMenu)
  107. menuRouter = flatAsyncRoutes(menuRouter)
  108. menuRouter.forEach((item) => {
  109. router.addRoute('layout', item)
  110. })
  111. const search_store = searchStore()
  112. search_store.init(menuRouter)
  113. isGetRouter.value = true
  114. next({ ...to, replace: true })
  115. return false
  116. }
  117. beforeEach(to, from)
  118. next()
  119. })
  120. router.afterEach((to, from) => {
  121. afterEach(to, from)
  122. NProgress.done()
  123. })
  124. router.onError((error) => {
  125. NProgress.done()
  126. notification.error({
  127. message: '路由错误',
  128. description: error.message
  129. })
  130. })
  131. // 入侵追加自定义方法、对象
  132. router.getMenu = () => {
  133. let apiMenu = tool.data.get('MENU') || []
  134. // 增加固定路由
  135. if (apiMenu.length === 0) {
  136. // 创建默认模块,显示默认菜单
  137. apiMenu[0] = cloneDeep(userRoutes.module[0])
  138. }
  139. const childrenApiMenu = apiMenu[0].children
  140. apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
  141. return filterUrl(apiMenu)
  142. }
  143. const filterUrl = (map) => {
  144. const newMap = []
  145. const traverse = (maps) => {
  146. maps &&
  147. maps.forEach((item) => {
  148. item.meta = item.meta ? item.meta : {}
  149. // 处理iframe
  150. if (item.meta.type === 'iframe') {
  151. item.path = `/${item.name}`
  152. }
  153. // 递归循环
  154. if (item.children && item.children.length > 0) {
  155. item.children = filterUrl(item.children)
  156. }
  157. newMap.push(item)
  158. })
  159. }
  160. traverse(map)
  161. return newMap
  162. }
  163. // 转换
  164. const filterAsyncRouter = (routerMap) => {
  165. const accessedRouters = []
  166. routerMap.forEach((item) => {
  167. item.meta = item.meta ? item.meta : {}
  168. // 处理外部链接特殊路由
  169. if (item.meta.type === 'iframe') {
  170. item.meta.url = item.path
  171. item.path = `/${item.name}`
  172. }
  173. // MAP转路由对象
  174. const route = {
  175. path: item.path,
  176. name: item.name,
  177. meta: item.meta,
  178. redirect: item.redirect,
  179. children: item.children ? filterAsyncRouter(item.children) : null,
  180. component: loadComponent(item.component)
  181. }
  182. // console.log('看看', route)
  183. accessedRouters.push(route)
  184. })
  185. return accessedRouters
  186. }
  187. const loadComponent = (component) => {
  188. if (component) {
  189. if (component.includes('/')) {
  190. return modules[`/src/views/${component}.vue`]
  191. }
  192. return modules[`/src/views/${component}/index.vue`]
  193. } else {
  194. return () => import(/* @vite-ignore */ `/src/layout/other/empty.vue`)
  195. }
  196. }
  197. // 路由扁平化
  198. const flatAsyncRoutes = (routes, breadcrumb = []) => {
  199. const res = []
  200. routes.forEach((route) => {
  201. const tmp = { ...route }
  202. if (tmp.children) {
  203. const childrenBreadcrumb = [...breadcrumb]
  204. childrenBreadcrumb.push(route)
  205. const tmpRoute = { ...route }
  206. tmpRoute.meta.breadcrumb = childrenBreadcrumb
  207. delete tmpRoute.children
  208. res.push(tmpRoute)
  209. const childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb)
  210. childrenRoutes.map((item) => {
  211. res.push(item)
  212. })
  213. } else {
  214. const tmpBreadcrumb = [...breadcrumb]
  215. tmpBreadcrumb.push(tmp)
  216. tmp.meta.breadcrumb = tmpBreadcrumb
  217. res.push(tmp)
  218. }
  219. })
  220. return res
  221. }
  222. export default router