问题描述(jeecg-boot vue2版本)
-
三级路由无法缓存
解决:查看JEECG技术论坛,找到了遇到同问题的帖子
permission.js文件,beforeEach中需要增加以下代码
router.beforeEach((to,from,next)=>{ if (to.matched && to.matched.length > 3) { to.matched.splice(2, to.matched.length - 3) } })
以上的代码解决了三级菜单无法缓存的问题,但是会引发另一个问题出现:配置菜单权限时,可以配置聚合路由,聚合路由的界面会显示异常,比如: 个人页——个人设置
-
聚合路由 界面显示异常问题
在代码中找到,是否为聚合路由是由 ‘alwaysShow’ 字段控制的,ture 是,false 否
user.js文件
获取用户信息接口中,拿到menuData数据,对menuData数据进行处理
原代码处理逻辑:
menuData.forEach((item, index) => { if (item['children']) { const hasChildrenMenu = item['children'].filter(i => { return !i.hidden || i.hidden === false }) if (hasChildrenMenu == null || hasChildrenMenu.length === 0) { // item['hidden'] = true item['children'].forEach(childrenItem => { menuData.push(childrenItem) }) item['children'] = null } } })
修改后的代码处理逻辑:
// 递归调用方法 const menuHandle = function(menuData) { menuData.forEach((item, index) => { if (item['children']) { // 返回子级菜单不是隐藏路由列表 const hasChildrenMenu = item['children'].filter(i => { return !i.hidden || i.hidden === false }) // 如果子级菜单全部是隐藏路由 if (hasChildrenMenu == null || hasChildrenMenu.length === 0) { item['children'].forEach(childrenItem => { // 隐藏路由无法定位,将父级的path赋值 childrenItem.selectedKeys = [item.path] // 子级路由增加字段“isAlwaysShow” childrenItem.meta.isAlwaysShow = item.alwaysShow menuData.push(childrenItem) }) item['children'] = null } else { // 如果子级菜单中有不是隐藏的路由 // 判断当前菜单是否是否为聚合路由,如果是给所有子级增加字段: ‘isAlwaysShow’ if (item.alwaysShow) { item['children'].forEach(childrenItem => { childrenItem.meta.isAlwaysShow = item.alwaysShow }) } menuHandle(item['children']) } } }) } menuHandle(menuData)
这样处理之后,发现在 router.beforeEach 中无法 拿到 isAlwaysShow字段。
在util.js 中 generateChildRouters() 方法中,生成路由
const menu = { path: item.path, name: item.name, redirect: item.redirect, component: componentPath, hidden: item.hidden, // component:()=> import(`@/views/${item.component}.vue`), meta: { title: item.meta.title, icon: item.meta.icon, url: item.meta.url, permissionList: item.meta.permissionList, keepAlive: item.meta.keepAlive, /* update_begin author:wuxianquan date:20190908 for:赋值 */ internalOrExternal: item.meta.internalOrExternal, /* update_end author:wuxianquan date:20190908 for:赋值 */ // 是否为隐藏路由 hidden: item.hidden, // 是否为聚合路由 isAlwaysShow: item.meta.isAlwaysShow, // 定位path selectedKeys: item.selectedKeys } }
然后在permission.js 中继续修改
// 截取的时候,过滤掉聚合路由信息 if (!to.meta.isAlwaysShow && to.matched && to.matched.length > 3) { to.matched.splice(2, to.matched.length - 3) }
原以为这样处理之后就万事大吉了,结果: 三级菜单无法展开,查看代码,因为在上面把to.matched数据截掉了,导致,在每次更新路由时,找不到展开的项
-
三级无法展开
在permission.js文件中,存下原有的 matched 数据
router.beforeEach((to,from,next)={ // 引用类型数据不能直接赋值 to.meta['matched'] = to.matched.filter(e => { return e }) if (!to.meta.isAlwaysShow && to.matched && to.matched.length > 3) { to.matched.splice(2, to.matched.length - 3) } })
这样改了之后,就需要在更新时,获取值的地方改一下数据来源
在 menu 文件夹下的index.js文件中
updateMenu() { // const routes = this.$route.matched.concat() // 原本获取展开的数据源 const routes = this.$route.meta['matched'] // 修改之后的数据来源 const { hidden, selectedKeys } = this.$route.meta // 如果当前路由是隐藏路由,就需要使用之前处理的 ‘selectedKeys’ if (hidden) { routes.pop() this.selectedKeys = selectedKeys } else { this.selectedKeys = [routes.pop().path] } const openKeys = [] if (this.mode === 'inline') { routes.forEach(item => { openKeys.push(item.path) }) } // 其他代码 },
-
三级隐藏路由,父级显示异常
与聚合问题一起处理的,原来代码逻辑是只处理了一层关系,没有处理多级,修改之后,使用递归处理更深层次。
‘selectedKeys’ 是处理定位关系。
// 递归调用方法 const menuHandle = function(menuData) { menuData.forEach((item, index) => { if (item['children']) { // 返回子级菜单不是隐藏路由列表 const hasChildrenMenu = item['children'].filter(i => { return !i.hidden || i.hidden === false }) // 如果子级菜单全部是隐藏路由 if (hasChildrenMenu == null || hasChildrenMenu.length === 0) { item['children'].forEach(childrenItem => { // 隐藏路由无法定位,将父级的path赋值 childrenItem.selectedKeys = [item.path] // 子级路由增加字段“isAlwaysShow” childrenItem.meta.isAlwaysShow = item.alwaysShow menuData.push(childrenItem) }) item['children'] = null } else { // 如果子级菜单中有不是隐藏的路由 // 判断当前菜单是否是否为聚合路由,如果是给所有子级增加字段: ‘isAlwaysShow’ if (item.alwaysShow) { item['children'].forEach(childrenItem => { childrenItem.meta.isAlwaysShow = item.alwaysShow }) } menuHandle(item['children']) } } }) } menuHandle(menuData)
这样处理之后,目前测试正常可用的
其他尝试:
看到jeecg-boot vue2版本 演示系统中三级是显示正常的,前端Vue2源码 发现处理方式不同:
premission.js文件
router.beforeEach((to, from, next) => {
//update-begin---author:scott ---date:2022-10-13 for:[jeecg-boot/issues/4091]多级路由缓存问题 #4091-----------
//解决三级菜单无法缓存问题
//参考: https://blog.csdn.net/qq_37322135/article/details/126013301
//参考: https://blog.csdn.net/cwin8951/article/details/106644118
if (to.matched && to.matched.length>3) {
to.matched.splice(2, to.matched.length - 3)
}
//update-end---author:scott ---date::2022-10-13 for:[jeecg-boot/issues/4091]多级路由缓存问题 #4091--------------
NProgress.start() // start progress bar
if (Vue.ls.get(ACCESS_TOKEN)) {
/* has token */
if (to.path === '/user/login' || to.path === OAUTH2_LOGIN_PAGE_PATH) {
next({ path: INDEX_MAIN_PAGE_PATH })
NProgress.done()
} else {
if (store.getters.permissionList.length === 0) {
store.dispatch('GetPermissionList').then(res => {
const menuData = res.result.menu;
//console.log(res.message)
if (menuData === null || menuData === "" || menuData === undefined) {
return;
}
let constRoutes = [];
constRoutes = generateIndexRouter(menuData);
// 添加主界面路由
store.dispatch('UpdateAppRouter', { constRoutes }).then(() => {
// 根据roles权限生成可访问的路由表
// 动态添加可访问路由表
router.addRoutes(store.getters.addRouters)
const redirect = decodeURIComponent(from.query.redirect || to.path)
if (to.path === redirect) {
// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
next({ ...to, replace: true })
} else {
// 跳转到目的路由
next({ path: redirect })
}
})
})
.catch(() => {
/* notification.error({
message: '系统提示',
description: '请求用户信息失败,请重试!'
})*/
store.dispatch('Logout').then(() => {
next({ path: '/user/login', query: { redirect: to.fullPath } })
})
})
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,如果进入的页面是login页面并且当前是OAuth2app环境,就进入OAuth2登录页面
if (to.path === '/user/login' && isOAuth2AppEnv()) {
next({path: OAUTH2_LOGIN_PAGE_PATH})
} else {
// 在免登录白名单,直接进入
next()
}
NProgress.done()
} else {
// 如果当前是在OAuth2APP环境,就跳转到OAuth2登录页面
let path = isOAuth2AppEnv() ? OAUTH2_LOGIN_PAGE_PATH : '/user/login'
next({ path: path, query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
看代码可以看到,这相当于是三级无法缓存的问题修复。
user.js 文件
// 获取用户信息
GetPermissionList({ commit }) {
return new Promise((resolve, reject) => {
queryPermissionsByUser().then(response => {
// update-begin----author:scott---date:20221018------for: 判断是否是 vue3 版本的菜单,给予提示 ---
let routeList = response.result.menu;
var findVue3Menu = routeList.find(item => {
return item.component === 'layouts/default/index';
});
if (findVue3Menu) {
console.error("启动失败: 检查到当前菜单表是Vue3版本,导致菜单加载异常,请切换到Vue2版菜单!参考:http://doc.jeecg.com/3075165")
Vue.prototype.$Jmessage.error('启动失败: 检查到当前菜单表是Vue3版本,导致菜单加载异常,请切换到Vue2版菜单!参考:http://doc.jeecg.com/3075165', 0)
}
// update-end----author:scott---date:20221018------for: 判断是否是 vue3 版本的菜单,给予提示 ---
const menuData = response.result.menu;
const authData = response.result.auth;
const allAuthData = response.result.allAuth;
//Vue.ls.set(USER_AUTH,authData);
sessionStorage.setItem(USER_AUTH,JSON.stringify(authData));
sessionStorage.setItem(SYS_BUTTON_AUTH,JSON.stringify(allAuthData));
if (menuData && menuData.length > 0) {
// //update--begin--autor:qinfeng-----date:20200109------for:JEECG-63 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
// menuData.forEach((item, index) => {
// if (item["children"]) {
// let hasChildrenMenu = item["children"].filter((i) => {
// return !i.hidden || i.hidden == false
// })
// if (hasChildrenMenu == null || hasChildrenMenu.length == 0) {
// item["hidden"] = true
// }
// }
// })
// //console.log(" menu show json ", menuData)
// //update--end--autor:qinfeng-----date:20200109------for:JEECG-63 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
commit('SET_PERMISSIONLIST', menuData)
// 设置系统安全模式
commit('SET_SYS_SAFE_MODE', response.result.sysSafeMode)
} else {
reject('getPermissionList: permissions must be a non-null array !')
}
resolve(response)
}).catch(error => {
reject(error)
})
})
},
上面的代码,没有对获取到的menu数据进行处理
menu文件夹下的index.js文件
updateMenu () {
const routes = this.$route.matched.concat()
const { hidden } = this.$route.meta
if (routes.length >= 3 && hidden) {
routes.pop()
this.selectedKeys = [routes[routes.length - 1].path]
} else {
this.selectedKeys = [routes.pop().path]
}
let openKeys = []
if (this.mode === 'inline') {
routes.forEach(item => {
openKeys.push(item.path)
})
}
// update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
// 包含冒号的是动态菜单
if (this.selectedKeys[0].includes(':')) {
let selectedKey = this.$route.fullPath
this.selectedKeys = [selectedKey]
let newOpenKeys = []
this.fullOpenKeys(this.menu, selectedKey, newOpenKeys)
if (newOpenKeys.length > 0) {
openKeys = newOpenKeys.reverse()
}
}
// update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
//update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
if(!this.selectedKeys || this.selectedKeys[0].indexOf(":")<0){
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
}
//update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
},
// update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
// 递归查找当前选中的菜单和父级菜单,填充openKeys
fullOpenKeys(menus, selectedKey, openKeys) {
for (let item of menus) {
if (item.path === selectedKey) {
openKeys.push(item.path)
this.$emit('updateMenuTitle', item)
return true
} else if (Array.isArray(item.children)) {
if (this.fullOpenKeys(item.children, selectedKey, openKeys)) {
openKeys.push(item.path)
return true
}
}
}
},
先拿到当前的路由信息,再去这是递归去处理,找展开项。
尝试过,这样处理之后,还是会有问题,二级隐藏路由会无法缓存,具体原因未查出,也无法在演示系统中增加隐藏路由。尝试之后还是无法满足我的需求,所以就果断放弃,使用自己方式。