在业务系统的后台中,通常需要根据用户的角色给予对应的权限。 必要功能:
- 增删改查权限配置
- 对应接口配置(用与后端权限判断)
- 自定义权限配置
- 名称,图标,路由修改
- 是否外链
- 是否显示
- 排序
配置对应页面文件 综上考虑使用动态配置页面,
声明路由节点对象:
/**
* 路由项接口定义
* 描述单个路由节点的完整结构和权限信息
*/
interface RouterItem {
/** 是否有新增权限 */
add: boolean
/** 新增操作相关的 API 接口列表 */
addApi: string[]
/** 是否需要认证 */
auth: boolean
/** 路由分类标识 */
classify: number
/** 组件文件路径,用于动态导入组件 */
componentName: string
/** Vue 组件实例 */
component: any
/** 创建时间戳 */
createTime: number
/** 是否有删除权限 */
del: boolean
/** 删除操作相关的 API 接口列表 */
delApi: string[]
/** 是否有编辑权限 */
edit: boolean
/** 编辑操作相关的 API 接口列表 */
editApi: string[]
/** 路由唯一标识 */
id: number
/** 是否有列表查看权限 */
list: boolean
/** 列表查询相关的 API 接口列表 */
listApi: string[]
/** 路由名称,用于路由跳转 */
name: string
/** 父级路由 ID,用于构建层级关系 */
parentId: number
/** 路由路径 */
path: string
/** 排序权重,数值越小越靠前 */
sort: number
/** 路由状态:1-启用,0-禁用 */
state: number
/** 路由显示标题 */
title: string
/** 子路由列表 */
children: Array<RouterItem>
}
数据库结果与上一致,树状数据结构
用户账号——》角色关联——》目录结构
通过代码添加到路由中
import { useRouter } from 'vue-router'
const router = useRouter()
router.addRoute(pageRoutes)
通过嵌套组件渲染菜单结构
<template>
<template v-for="item, index in prop.data">
<el-sub-menu index="1" v-if="item.children && item.children.length > 0">
<template #title>
<Icon v-if="item.icon" :name="item.icon"></Icon>
<span>{{ t(item.title) }}</span>
</template>
<MenuItem :data="item.children">
</MenuItem>
</el-sub-menu>
<el-menu-item :index="item.path" v-else>
<Icon v-if="item.icon" :name="item.icon"></Icon>
<template #title>{{ t(item.title) }}</template>
</el-menu-item>
</template>
</template>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n()
const prop = defineProps({
data: {
type: Array<any>,
default: []
}
})
</script>
<template>
<div class="menu-box">
<el-icon v-show="!isCollapse" @click="() => isCollapse = true">
<CaretLeft />
</el-icon>
<el-icon v-show="isCollapse" @click="() => isCollapse = false">
<CaretRight />
</el-icon>
</div>
<el-menu style="height: 100%;" router :default-active="route.path" class="el-menu-vertical-demo"
:collapse="isCollapse" @open="handleOpen" @close="handleClose">
<MenuItem :data="pageRoutes.children" />
</el-menu>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import {
CaretLeft,
CaretRight
} from '@element-plus/icons-vue'
import { useRoute } from 'vue-router'
import MenuItem from '@/components/MenuItem.vue'
import initEachRouter from '@/utils/router'
const route = useRoute()
const permission = JSON.parse(localStorage.getItem('permission') || '[]')
const pageRoutes = initEachRouter(permission)
const { menu } = defineProps({
menu: {
type: Array,
default: () => []
}
})
console.log(menu)
const isCollapse = ref(false)
const handleOpen = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
console.log(key, keyPath)
}
</script>
<style>
.menu-box {
position: absolute;
top: 50vh;
width: 28px;
height: 28px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
font-size: 20px;
right: -14px;
z-index: 1000;
box-shadow: 0 0 3px #aaa;
background-color: #fff;
}
</style>