Newer
Older
safe_production_front / src / router / index.ts
import { createRouter, createWebHashHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { useNProgress } from '@vueuse/integrations/useNProgress'
import '@/assets/styles/nprogress.scss'
// 路由相关数据
import {
  asyncRoutes,
  asyncRoutesByFilesystem,
  constantRoutes,
  constantRoutesByFilesystem,
} from './routes'
import pinia from '@/store'
import useSettingsStore from '@/store/modules/settings'
import useKeepAliveStore from '@/store/modules/keepAlive'
import useUserStore from '@/store/modules/user'
import useMenuStore from '@/store/modules/menu'
import useRouteStore from '@/store/modules/route'
import { queryString, stripscript } from '@/utils/validate'

const { isLoading } = useNProgress()

const router = createRouter({
  history: createWebHashHistory(),
  routes:
    useSettingsStore(pinia).app.routeBaseOn === 'filesystem'
      ? constantRoutesByFilesystem
      : (constantRoutes as RouteRecordRaw[]),
})

router.beforeEach(async (to, from, next) => {
  if (to.name !== 'NoPage' && to.name !== 'SmGateway') {
    console.log('to:', to.path)
    const settingsStore = useSettingsStore()
    const userStore = useUserStore()
    const menuStore = useMenuStore()
    const routeStore = useRouteStore()
    settingsStore.app.enableProgress && (isLoading.value = true)
    // 是否已登录
    if (userStore.isLogin) {
      if (to.name === 'login') {
        // 如果还要进入登录页,直接跳转
        if (window.localStorage.getItem('systemType') === 'gm') {
          next()
        }
        else if (window.localStorage.getItem('systemType') === 'sm') {
          if (window.localStorage.getItem('useGateway') === 'true') {
            // sm走网关
            next({
              name: 'SmGateway',
              replace: true,
            })
          }
          else {
            next()
          }
        }
      }
      else {
        // 携带token 需要去掉
        const hrefIdx = window.location.href.indexOf('token') // url中是否携带token
        if (hrefIdx > -1) {
          const params = queryString(window.location.href)
          const token = stripscript(params.token)
          console.log('已登录状态设置新的Token:', token)
          localStorage.setItem('token', token)
          localStorage.setItem('tokenBak', 'true')
        }
        else {
          localStorage.setItem('tokenBak', 'false')
        }

        if (!userStore.hasUserInfo) {
          // 获取用户信息
          await userStore.getUserInfo()
        }
        // 是否已根据权限动态生成并注册路由
        if (routeStore.isGenerate) {
          // 导航栏如果不是 single 模式,则需要根据 path 定位主导航的选中状态
          settingsStore.menu.menuMode !== 'single'
            && menuStore.setActived(to.path)
          // 如果已登录状态下,进入登录页会强制跳转到控制台页面
          if (to.name === 'login') {
            console.log('跳转控制台')
            next({
              name: 'index',
              replace: true,
            })
          }
          // 如果未开启控制台,但进入的是控制台页面,则会进入侧边栏导航第一个模块
          else if (!settingsStore.dashboard.enable && to.name === 'dashboard') {
            if (menuStore.sidebarMenus.length > 0) {
              console.log(
                '如果未开启控制台,但进入的是控制台页面,则会进入侧边栏导航第一个模块',
              )
              next({
                path: menuStore.sidebarMenusFirstDeepestPath,
                replace: true,
              })
            }
            // 如果侧边栏导航第一个模块无法命中,则还是进入控制台页面
            else {
              console.log(
                '如果侧边栏导航第一个模块无法命中,则还是进入控制台页面',
              )
              next()
            }
          }
          // 正常访问页面
          else {
            next()
          }
        }
        else {
          // 生成动态路由

          switch (settingsStore.app.routeBaseOn) {
            case 'frontend':
              await routeStore.generateRoutesAtFront(asyncRoutes)
              break
            case 'backend':
              await routeStore.generateRoutesAtBack()
              break
            case 'filesystem':
              await routeStore.generateRoutesAtFilesystem(
                asyncRoutesByFilesystem,
              )
              // 文件系统生成的路由,需要手动生成导航数据
              switch (settingsStore.menu.baseOn) {
                case 'frontend':
                  await menuStore.generateMenusAtFront()
                  break
                case 'backend':
                  await menuStore.generateMenusAtBack()
                  break
              }
              break
          }
          // 注册并记录路由数据
          // 记录的数据会在登出时会使用到,不使用 router.removeRoute 是考虑配置的路由可能不一定有设置 name ,则通过调用 router.addRoute() 返回的回调进行删除
          const removeRoutes: Function[] = []
          routeStore.flatRoutes.forEach((route) => {
            if (!/^(https?:|mailto:|tel:)/.test(route.path)) {
              removeRoutes.push(router.addRoute(route as RouteRecordRaw))
            }
          })
          // 添加静态路由
          if (settingsStore.app.routeBaseOn !== 'filesystem') {
            routeStore.flatSystemRoutes.forEach((route) => {
              removeRoutes.push(router.addRoute(route as RouteRecordRaw))
            })
          }
          routeStore.setCurrentRemoveRoutes(removeRoutes)
          // 动态路由生成并注册后,重新进入当前路由
          next({
            path: to.path,
            query: to.query,
            replace: true,
          })
        }
      }
    }
    else {
      console.log('未登录')
      // 携带token 需要去掉

      const hrefIdx = window.location.href.indexOf('token') // url中是否携带token
      console.log('hrefIdx', hrefIdx)
      console.log('window.location.href', window.location.href)

      if (hrefIdx > -1) {
        const params = queryString(window.location.href)
        const token = stripscript(params.token)
        localStorage.setItem('token', token)
        console.log('url中携带token', token)
        localStorage.setItem('tokenBak', 'true')
      }
      else {
        localStorage.setItem('tokenBak', 'false')
      }
      if (localStorage.getItem('tokenBak') === 'true') {
        // 是否已根据权限动态生成并注册路由
        if (routeStore.isGenerate) {
          // 导航栏如果不是 single 模式,则需要根据 path 定位主导航的选中状态
          settingsStore.menu.menuMode !== 'single'
            && menuStore.setActived(to.path)
          // 如果已登录状态下,进入登录页会强制跳转到控制台页面
          if (to.name === 'login') {
            next({
              name: 'index',
              replace: true,
            })
          }
          // 如果未开启控制台,但进入的是控制台页面,则会进入侧边栏导航第一个模块
          else if (!settingsStore.dashboard.enable && to.name === 'dashboard') {
            if (menuStore.sidebarMenus.length > 0) {
              next({
                path: menuStore.sidebarMenusFirstDeepestPath,
                replace: true,
              })
            }
            // 如果侧边栏导航第一个模块无法命中,则还是进入控制台页面
            else {
              next()
            }
          }
          // 正常访问页面
          else {
            next()
          }
        }
        else {
          // 生成动态路由
          switch (settingsStore.app.routeBaseOn) {
            case 'frontend':
              await routeStore.generateRoutesAtFront(asyncRoutes)
              break
            case 'backend':
              await routeStore.generateRoutesAtBack()
              break
            case 'filesystem':
              await routeStore.generateRoutesAtFilesystem(
                asyncRoutesByFilesystem,
              )
              // 文件系统生成的路由,需要手动生成导航数据
              switch (settingsStore.menu.baseOn) {
                case 'frontend':
                  await menuStore.generateMenusAtFront()
                  break
                case 'backend':
                  await menuStore.generateMenusAtBack()
                  break
              }
              break
          }
          // 注册并记录路由数据
          // 记录的数据会在登出时会使用到,不使用 router.removeRoute 是考虑配置的路由可能不一定有设置 name ,则通过调用 router.addRoute() 返回的回调进行删除
          const removeRoutes: Function[] = []
          routeStore.flatRoutes.forEach((route) => {
            if (!/^(https?:|mailto:|tel:)/.test(route.path)) {
              removeRoutes.push(router.addRoute(route as RouteRecordRaw))
            }
          })
          // 添加静态路由
          if (settingsStore.app.routeBaseOn !== 'filesystem') {
            routeStore.flatSystemRoutes.forEach((route) => {
              removeRoutes.push(router.addRoute(route as RouteRecordRaw))
            })
          }
          routeStore.setCurrentRemoveRoutes(removeRoutes)
          // 动态路由生成并注册后,重新进入当前路由
          next({
            path: to.path,
            query: to.query,
            replace: true,
          })
        }
        await userStore.setToken(localStorage.getItem('token') as string)
      }

      if (to.name !== 'login') {
        if (localStorage.getItem('tokenBak') === 'true') {
          // url带token,验证token,token正确跳过登录
          console.log('未登录-url带token', localStorage.getItem('token'))
          const res = await userStore.getUserInfo()
          if (res !== '') {
            console.log('跳转实时监控')
            next({
              path: '/realTime/page',
              replace: true,
            })
            // next({
            //   path: menuStore.sidebarMenusFirstDeepestPath,
            //   replace: true
            // })
          }
          else {
            console.log('跳转noPage')
            next({
              name: '/noPage',
              replace: true,
            })
          }
        }
        else {
          if (window.localStorage.getItem('systemType') === 'gm') {
            next({
              name: 'login',
              query: {
                redirect: to.fullPath,
              },
            })
          }
          else if (window.localStorage.getItem('systemType') === 'sm') {
            if (window.localStorage.getItem('useGateway') === 'true') {
              // sm走网关
              next({
                name: 'SmGateway',
                replace: true,
              })
            }
            else {
              next({
                name: 'login',
                query: {
                  redirect: to.fullPath,
                },
              })
            }
          }
        }
      }
      else {
        // 未登录跳转到登录
        if (window.localStorage.getItem('systemType') === 'gm') {
          next()
        }
        else if (window.localStorage.getItem('systemType') === 'sm') {
          if (window.localStorage.getItem('useGateway') === 'true') {
            // sm走网关
            next({
              name: 'SmGateway',
              replace: true,
            })
          }
          else {
            next()
          }
        }
      }
    }
  }
  else {
    next()
  }
})

router.afterEach((to, from) => {
  const settingsStore = useSettingsStore()
  const keepAliveStore = useKeepAliveStore()
  settingsStore.app.enableProgress && (isLoading.value = false)
  // 设置页面 title
  to.meta.title
    && settingsStore.setTitle(
      typeof to.meta.title === 'function' ? to.meta.title() : to.meta.title,
    )
  // 判断当前页面是否开启缓存,如果开启,则将当前页面的 name 信息存入 keep-alive 全局状态
  if (to.meta.cache) {
    const componentName
      = to.matched[to.matched.length - 1].components?.default.name
    //
    if (componentName) {
      keepAliveStore.add(componentName)
    }
    else {
      console.warn('该页面组件未设置组件名,会导致缓存失效,请检查')
    }
  }
  // 判断离开页面是否开启缓存,如果开启,则根据缓存规则判断是否需要清空 keep-alive 全局状态里离开页面的 name 信息
  if (from.meta.cache) {
    const componentName
      = from.matched[to.matched.length - 1].components?.default.name
    if (componentName) {
      // 通过 meta.cache 判断针对哪些页面进行缓存
      switch (typeof from.meta.cache) {
        case 'string':
          if (from.meta.cache !== to.name) {
            keepAliveStore.remove(componentName)
          }
          break
        case 'object':
          if (!from.meta.cache.includes(to.name as string)) {
            keepAliveStore.remove(componentName)
          }
          break
      }
      // 如果进入的是 reload 页面,则也将离开页面的缓存清空
      if (to.name === 'reload') {
        keepAliveStore.remove(componentName)
      }
    }
  }
  document.documentElement.scrollTop = 0
  // 携带token 需要去掉
  // const hrefIdx = window.location.href.indexOf('token') // url中是否携带token
  // if (hrefIdx > -1) {
  //   const params = queryString(window.location.href)
  //   const token = stripscript(params.token)
  //   localStorage.setItem('token', token)
  //   localStorage.setItem('tokenBak', 'true')
  //   window.location.href = window.location.href.replace(`?token=${token}`, '')
  // }
})

export default router