yinghe-lowcode-zln
Version:
基于vue、ant-design-vue,datagrid的低代码平台
311 lines (293 loc) • 8.29 kB
JavaScript
import * as loginService from '@/api/material/login'
import { asyncRouterMap } from '@/config/router.config'
// 布局页面路由生成器
const layoutRouterDirectory = {}
const generatorLayoutRouter = context => {
const routerComponents = {}
const dirKeyRegex = /^.*\/([^/]+)\.vue$/
const replaceKeyRegex = /^.*(\/[^/]+)\.vue$/
context.keys().forEach(item => {
const dir = item.replace(dirKeyRegex, '$1')
const key = item.replace(replaceKeyRegex, '$1')
if (!layoutRouterDirectory[dir]) {
layoutRouterDirectory[dir] = key
}
routerComponents[key] = context(item).default
})
return routerComponents
}
// 业务页面路由生成器
const viewsRouterDirectory = []
const generatorViewsRouter = context => {
const routerComponents = {}
const dirKeyRegex = /^\.{0,2}(\/[^/]+)\/(([^/]+\/?)+)\.vue$/
const replaceKeyRegex = /^\.{0,2}(\/([^/]+\/?)+)\.vue$/
const replaceValueRegex = /^\.{0,2}\/(([^/]+\/?)+)\.vue$/
context.keys().forEach(item => {
const dir = item.replace(dirKeyRegex, '$1')
const key = item.replace(replaceKeyRegex, '$1')
const path = item.replace(replaceValueRegex, '$1')
if (!viewsRouterDirectory.includes(dir)) {
viewsRouterDirectory.push(dir)
}
routerComponents[key] = () => import(`@/views/${path}`)
})
return routerComponents
}
// 前端路由汇总表
const constantRouterComponents = {
// 布局基础页面
...generatorLayoutRouter(
// 过滤layouts下以_开头的文件夹的资源
require.context('@/layouts', false, /^((\.{0,2}\/(?!_\w*\/?))[^/]+)+\.vue$/i)
),
// 业务相关页面
...generatorViewsRouter(
// 过滤views下非modules目录或者以_开头的文件夹的资源
require.context('@/views', true, /^((\.{0,2}\/(?!modules\/|_\w*\/?))[^/]+)+\.vue$/i)
)
}
// 前端未找到页面路由
const notFoundRouter = [
{
path: '/404',
name: '404',
// component: () => import(`@/views/page/404`),
meta: {
title: '404',
componentName: '404',
hiddenHeaderContent: true,
noCache: false
},
hidden: true
},
{
path: '*',
name: '*',
redirect: '/404',
hidden: true
}
]
// 默认外部链接路由
const externalRouter = {
key: 'External',
name: 'External',
path: '/external',
// component: () => import(`@/layouts/PageView`),
redirect: '/external/link',
meta: {
title: '外部链接',
componentName: 'External',
hiddenHeaderContent: true,
noCache: false
},
children: [
{
key: 'ExternalLink',
name: 'ExternalLink',
path: '/external/link',
// component: () => import(`@/layouts/PageFrame`),
meta: {
title: '外部链接',
match: 'external',
external: 'www.baidu.com',
componentName: 'ExternalLink',
hiddenHeaderContent: true,
noCache: false
}
}
],
hidden: true
}
// 根级菜单
const rootRouter = {
key: 'Basic',
name: 'Basic',
path: '/',
component: 'BasicLayout',
redirect: '/index',
meta: {
title: '首页'
},
children: []
}
/**
* 转换树形结构
* @param list 源数组
* @param tree 树
* @param parentId 父ID
*/
const listToTree = (list, tree, parentId) => {
list.forEach(item => {
// 判断是否为父级菜单
if (item.parentId === parentId) {
// 创建 route
const route = {
...item,
key: item.key || item.name,
children: []
}
// 迭代 list,找到符合的子菜单
listToTree(list, route.children, item.id)
// 删掉不存在 children 属性
if (route.children.length <= 0) {
delete route.children
}
// push route
tree.push(route)
}
})
}
/**
* 动态生成菜单
* @param token
* @returns {Promise<Router>}
*/
export const generatorDynamicRouter = token => {
return new Promise((resolve, reject) => {
loginService
.getCurrentUserNav(token)
.then(res => {
if (res.code !== '0000') {
reject(res)
return
}
let children = []
const { result = [] } = res
// 后端数据, 根级树数组,根级 PID
listToTree(result, children, '1593523388247740416')
children = asyncRouterMap.concat(children)
const routers = generator([{
...rootRouter,
children
}])
// 添加静态路由
routers[0].children.unshift(externalRouter)
routers.push(...notFoundRouter)
resolve(routers)
})
.catch(err => {
reject(err)
})
})
}
/**
* 动态生成路由路径
*
* @param parent
* @param item
* @returns {路由路径}
*/
export const generatorDynamicPath = (parent = {}, item = {}) => {
// 正则
const format = '/$1'
const regex = /^\/*([^/].*)/
// 路由路径
const keyPath = item.key || ''
const itemPath = item.path || ''
const parentPath = parent.path || ''
const isNotIframeView = item.component !== 'PageFrame'
return (
!(isNotIframeView && itemPath)
? (parentPath + '/' + keyPath).replace(regex, format)
: itemPath
)
}
/**
* 动态加载路由对应页面的组件
*
* @param parent
* @param item
* @returns { 组件 }
*/
export const loadDynamicComponent = (parent = {}, item = {}) => {
// 组件路径
const itemPath = item.path || ''
const parentPath = parent.path || ''
const componentPath = item.component || ''
const isNotIframeView = item.component !== 'PageFrame'
let currentPath = (
!(isNotIframeView && itemPath)
?'/' + componentPath
: itemPath
).replace(/^\/*([^/].*)/, '/$1')
if (itemPath === '/index') {
currentPath = '/' + componentPath
}
// layout组件
for (const directoryPath in layoutRouterDirectory) {
if (componentPath === directoryPath) {
return constantRouterComponents[layoutRouterDirectory[directoryPath]]
}
}
// views组件
for (const directoryPath of viewsRouterDirectory) {
if (constantRouterComponents[directoryPath + currentPath]) {
return constantRouterComponents[directoryPath + currentPath]
}
}
// 默认组件
return () => import(`@/views/${currentPath.slice(1)}`)
}
/**
* 格式化树形结构数据 生成 vue-router 层级路由表
*
* @param routerMap
* @param parent
* @returns {*}
*/
export const generator = (routerMap, parent = {}) => {
return routerMap.map(item => {
const { title, show, noCache, hideChildren, hiddenHeaderContent, target, icon, pageId } = item.meta || {}
const isNotIframeView = item.component !== 'PageFrame'
const match = isNotIframeView ? 'path' : 'external'
const currentRouter = {
// 路由path
path: generatorDynamicPath(parent, item),
// 路由名称
name: item.name || item.key || '',
// 路由组件
component: loadDynamicComponent(parent, item),
// 路由meta
meta: {
icon: icon,
show: show,
keepAlive: true,
match: match,
title: title,
target: target,
pageId: item.pageId,
noCache: false,
external: !isNotIframeView && item.path || '',
componentName: item.component || item.name || item.key || '',
hiddenHeaderContent: hiddenHeaderContent !== undefined ? hiddenHeaderContent !== false : (parent.meta || {}).hiddenHeaderContent !== false,
permission: [item.name || item.key || '']
}
}
// 是否设置了隐藏菜单
if (show === false) {
currentRouter.hidden = true
}
// 是否设置了隐藏子菜单
if (hideChildren) {
currentRouter.hideChildrenInMenu = true
}
// PageFrame 使用别名
if (!isNotIframeView) {
currentRouter.alias = currentRouter.path + '/*'
}
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
if (!currentRouter.path.startsWith('http')) {
currentRouter.path = currentRouter.path.replace('//', '/')
}
// 重定向
if (item.redirect) {
currentRouter.redirect = item.redirect
}
// 是否有子菜单,并递归处理
if (item.children && item.children.length > 0) {
currentRouter.children = generator(item.children, currentRouter)
}
return currentRouter
})
}