若依框架动态路由,通过新增菜单实现侧边栏打开新标签页(看板大屏),免登陆、页面全屏显示
一、新增菜单增加:是否打开新窗口参数
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item label="是否打开新窗口" prop="openNewWindow" label-width="120px">
<el-radio-group v-model="form.openNewWindow">
<el-radio value="1">是</el-radio>
<el-radio value="0">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
二、 在store/modules/permission.js 的GenerateRoutes方法中提取打开新窗口的路由
//设置新窗口路由
setNewWindowRoutes(routes) {
this.newWindowRoutes = routes
},
generateRoutes(roles) {
return new Promise((resolve) => {
// 向后端请求路由数据
getRouters({
systemIdentifier: activeTopNav.value
}).then((res) => {
const sdata = JSON.parse(JSON.stringify(res.data))
const rdata = JSON.parse(JSON.stringify(res.data))
const defaultData = JSON.parse(JSON.stringify(res.data))
// 提取需要新窗口打开的路由路径
const newWindowRoutePaths = extractNewWindowRoutes(res.data)
console.log(newWindowRoutePaths)
this.setNewWindowRoutes(newWindowRoutePaths)
// 提取"openNewWindow": "1"的路由,生成指定格式, 然后动态添加到路由中,覆盖原配置的路由
const newWindowRoutes = generateNewWindowRoutes(res.data)
newWindowRoutes.forEach((route) => {
router.addRoute(route)
})
const sidebarRoutes = filterAsyncRouter(sdata)
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
const defaultRoutes = filterAsyncRouter(defaultData)
const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
asyncRoutes.forEach((route) => {
router.addRoute(route)
})
this.setRoutes(rewriteRoutes)
this.setSidebarRouters(sidebarRoutes)
this.setDefaultRoutes(sidebarRoutes)
this.setTopbarRoutes(defaultRoutes)
resolve(rewriteRoutes)
})
})
},
跟在route/index.js,将看板大屏页面配置加到路由constantRoutes中的效果一样,通过generateNewWindowRoutes 方法动态生成以下的格式,并添加动态到路由中:
{
path: '/chronic_datav',
component: () => import('@/views/chronic/DataV/chronic/index.vue'),
hidden: true
},
对应方法的逻辑
// 提取需要新窗口打开的路由路径
function extractNewWindowRoutes(routes, parentPath = '') {
const newWindowPaths = []
routes.forEach((route) => {
const currentPath = parentPath ? `${parentPath}/${route.path}` : route.path
// 检查当前路由是否需要新窗口打开
if (route.openNewWindow === '1') {
newWindowPaths.push(currentPath)
}
// 递归检查子路由
if (route.children && route.children.length > 0) {
const childPaths = extractNewWindowRoutes(route.children, currentPath)
newWindowPaths.push(...childPaths)
}
})
return newWindowPaths
}
// 生成新窗口路由的函数
function generateNewWindowRoutes(routes, parentPath = '') {
const newWindowRoutes = []
routes.forEach((route) => {
const currentPath = parentPath ? `${parentPath}/${route.path}` : route.path
// 检查当前路由是否需要新窗口打开
if (route.openNewWindow === '1') {
const newRoute = {
path: currentPath.startsWith('/') ? currentPath : `/${currentPath}`,
component: loadView(route.component),
hidden: true
}
newWindowRoutes.push(newRoute)
}
// 递归检查子路由
if (route.children && route.children.length > 0) {
const childRoutes = generateNewWindowRoutes(route.children, currentPath)
newWindowRoutes.push(...childRoutes)
}
})
return newWindowRoutes
}
三、免登陆: 找到项目目录下src/permission.js, 判断免登陆
//白名单
const baseWhiteList = ['/login', '/register', '/iconset/index']
// 检查是否在白名单中(包括新窗口路由)
function isInWhiteList(path) {
// 检查基础白名单
if (baseWhiteList.includes(path)) {
return true
}
//检查新窗口路由,如果存在,则返回true
try {
const permissionStore = usePermissionStore()
if (permissionStore && permissionStore.newWindowRoutes) {
return permissionStore.newWindowRoutes.includes(path)
}
} catch (error) {
// 如果 store 还未初始化,只检查基础白名单
console.log('Permission store not initialized yet')
}
return false
}
//使用
if (isInWhiteList(to.path)) {
// 在免登录白名单,直接进入
next()
}
四、打开新标签页: 项目文件路径下src/layout/components/Sidebar/Link.vue文件,新增跳转方法
<template>
<component :is="type" v-bind="linkProps()">
<slot />
</component>
</template>
<script setup>
import { isExternal } from '@/utils/validate'
import usePermissionStore from '@/store/modules/permission'
const props = defineProps({
to: {
type: [String, Object],
required: true
}
})
const isExt = computed(() => {
return isExternal(props.to)
})
const type = computed(() => {
if (isExt.value) {
return 'a'
}
// 如果是新窗口路由,也使用 a 标签
if (isNewWindow()) {
return 'a'
}
return 'router-link'
})
// 使用计算属性动态获取新窗口路由
const newWindowRoutes = computed(() => {
try {
const permissionStore = usePermissionStore()
return permissionStore?.newWindowRoutes || []
} catch (error) {
return []
}
})
// 判断是否为新窗口打开
function isNewWindow() {
try {
const routes = newWindowRoutes.value
if (!routes || routes.length === 0) {
return false
}
// 简化路径获取逻辑
let routePath = ''
if (typeof props.to === 'string') {
routePath = props.to
} else if (props.to && typeof props.to === 'object' && props.to.path) {
routePath = props.to.path
} else {
return false
}
return routes.includes(routePath)
} catch (error) {
return false
}
}
function linkProps() {
// 判断是否为外链
if (isExt.value) {
return {
href: props.to,
target: '_blank',
rel: 'noopener'
}
}
// 判断是否为新窗口打开
if (isNewWindow()) {
const routePath = typeof props.to === 'string' ? props.to : props.to.path
return {
href: routePath,
target: '_blank',
rel: 'noopener'
}
}
return {
to: props.to
}
}
</script>