业务侧-路由管理器-RouterLoader

89 阅读2分钟

设计思路:

系统应用级别,目前简单的路由方式,无法满足平台级别的应用。

对路由管理的一种集中式管理和驱动。

设计动机:

  • 注册动态路由

  • 动态路由数据的存取

  • 进入页面前/中/后的逻辑注入

  • 多端路由访问和拦截

API

名称含义
loader路由加载主入口
registerDynamicRoutes注册动态路由
redirectEntry路由拦截异常跳转
redirectNextApp路由跳转

代码实践:

/*
 * @Description: 路由管理器
 * @Author: ffzheng
 */

import { cache } from '@basic-utils'
import { Config, BaseStore, Service} from '@basic-library'
import { EduMessage } from '@components'
import LoginLoader from "./Login";

/**
* registerDynamicRoutes 注册动态路由
* @param {*} router 路由
* 场景: 刷新页面
*/
function registerDynamicRoutes(router){
    Window._EDU_SYSTEM_ROUTERS = router.getRoutes()
	const _AUTH_STORE = cache.getCache('_AUTH_STORE_','session') || []
	_AUTH_STORE.forEach( menus => {
        const routerName = menus.path?.substr(1)
        if(routerName && !router.hasRoute(routerName)){
            router.addRoute('home',{
                path: menus.path,
                name: routerName,
                meta: {
                  id:  menus.pageId,
                  title: menus.pageName,
                  isAsync: true,
                  icon: menus.icon || 'icon-wenjian'
                },
                component: ()=> import(`@/${menus.component}`)
            })
        }
	})
}

/**
* loaderAuthData 从内存中加载路由
* @param {*} router 路由
* 场景: 刷新页面
*/
function loaderAuthData(){
    const _AUTH_STORE = cache.getCache('_AUTH_STORE_','session')
    if(_AUTH_STORE){
        BaseStore.auth.initAuthData(_AUTH_STORE)
    }else{
        console.warn('获取功能权限失效!')
    }
}

const pathFill = (url) => {
    let path = url
    if(path.indexOf('/') !== 0)  path  = `/${path}`
    if(path.lastIndexOf('/') !== path.length -1)  path  = `${path}/`
    if(path.indexOf('/') == -1)  path = `/${path}/`
    return path
}

/**应用路径拼装--斜杠路径补全
 * @param {*} url 
 * @returns 
 */
 const getMicroUrl = (url) => {
    const protocol = window.location.protocol
    const host = window.location.host
    const path = pathFill(url)
    return `${protocol}//${host}${path}`
}

const redirectEntry = () => {
    const url = window._IS_RUN_MICRO_MODE ? getMicroUrl('main')  : '/login'
    window.location.href = url
}

const redirectNextApp = (next) => {
    window._IS_RUN_MICRO_MODE ? (window.location.href = getMicroUrl('main')) : next()
}

/**
* registerPageMount 全局页面挂载监听
* @param {*} router 路由
* 场景: 
* 1、页面内获取接口请求标记-内置全局实例
* 2、页面内错误捕获
*/
function registerPageMount(router){
    // 进入页面
    router.beforeResolve(async(to, from, next) => {
        document.title = Config.BSConfig.systemName || '';
        try {
            if(Config.BSConfig?.IS_AUTH_INTERFACE){
                const cItem= BaseStore.auth.getInfoByRoute(to.path)
                if(cItem){
                    const result = await Service.useHttp('interfaceService',`pageId=${cItem.pageId}`)
                    cache.setCache('_EDU_CUR_PAGE_INFO',cItem,'session')
                    if(result?.success){
                        cache.setCache('_EDU_CUR_INTERFACE_INFO',result?.returnObj,'session')
                        Service.initData(result?.returnObj)
                    }else{
                        console.warn(`当前页面${cItem.pageId}接口未授权!`)
                    }
                }
            }
            next()
        } catch (error) {
            console.warn(error)
            next()
        }
    });
}

const getExtEle = (list, field) => {
    return list.reduce((prev, next) => prev.concat(pathFill(next[field])), [])
}
const logoutAction = () => {
	LoginLoader.logout().then(() => LoginLoader.redirect())
}

const entryClietInspection = () => {
  if(!window._IS_RUN_MICRO_MODE) return
  const BaseUrl = process.env.BASE_URL
  const subSystemList = LoginLoader.getSubApps()
  const extPaths = getExtEle(subSystemList,"path")?.join('|')
  if(extPaths.indexOf(BaseUrl) == -1){
    // 不存在当前系统中,进行提醒,非法访问
    EduMessage({
        type: 'error',
        message: '非法访问!'
    })
    logoutAction()
  }
}

/**
 * 业务路由加载器
 * @param {*} router 路由
 */
function loader(router){
    entryClietInspection()
    loaderAuthData()
    registerDynamicRoutes(router)
    registerPageMount(router)
}

export default{
    loader,
    registerDynamicRoutes,
    redirectEntry,
    redirectNextApp
}

核心解读:

entryClietInspection 子系统拦截

从登录管理器LoginLoader.getSubApps获取当前用户的子系统,根据访问的目标路径,进行匹配命中,如果异常就进行拦截提醒,停止进入。

registerDynamicRoutes 注册动态路由
从本地缓存cache.getCache('_AUTH_STORE_','session')获取菜单信息,根据约定的菜单规则

  • 路由判断
  • addRoute 路由注册

registerPageMount 全局页面挂载监听
进入页面后,目前的设计逻辑是,根据进入页面的ID,从后端接口发送请求,获取到当前页面所拥有的接口权限。

主要目的:

控制页面接口权限

loaderAuthData 加载权限数据

主要场景是,刷新页面后,获取当菜单路由信息

然后进行BaseStore.auth.initAuthData(_AUTH_STORE) 进行注册

这个感觉好像在应用管理器 AppLoader里面有这个逻辑。 重复了。我看看去。

设计完毕,期望你的指点....

针对Loader管理器的一系列,请看下方:

业务侧-Loader设计
业务侧-系统应用加载器-AppLoader
业务侧-登录管理器-LoginLoader
业务侧-异常拦截管理器-ErrorLoader