feat(modules/permission.ts): 动态路由完成
This commit is contained in:
parent
1d21c6b098
commit
2e787ec921
|
|
@ -29,7 +29,10 @@ export default defineComponent({
|
|||
setup(props) {
|
||||
const router = useRouter()
|
||||
const push = () => {
|
||||
router.push(props.to)
|
||||
console.log(props.to)
|
||||
router.push(props.to).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
return {
|
||||
push,
|
||||
|
|
|
|||
|
|
@ -1,41 +1,49 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="!item.meta ||!item.meta.hidden">
|
||||
<!-- 非嵌套路由 -->
|
||||
<template>
|
||||
<div v-if="!item.meta || !item.meta.hidden" >
|
||||
<template
|
||||
v-if="!item.children||item.children.length==0">
|
||||
<app-link v-if="item.meta" :to="resolvePath(item.path)">
|
||||
<el-menu-item :index="resolvePath(item.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<svg-icon v-if="item.meta && item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
|
||||
<span v-if="item.meta && item.meta.title">{{ item.meta.title }}</span>
|
||||
v-if="!alwaysShowRootMenu && theOnlyOneChild && !theOnlyOneChild.children"
|
||||
>
|
||||
<AppLink
|
||||
v-if="theOnlyOneChild.meta"
|
||||
:to="resolvePath(theOnlyOneChild.path)"
|
||||
>
|
||||
<el-menu-item
|
||||
:index="resolvePath(theOnlyOneChild.path)"
|
||||
:class="{'submenu-title-noDropdown': isFirstLevel}"
|
||||
>
|
||||
<svg-icon v-if="theOnlyOneChild.meta&&theOnlyOneChild.meta.icon" :icon-class="theOnlyOneChild.meta.icon"></svg-icon>
|
||||
<span v-if="theOnlyOneChild.meta && theOnlyOneChild.meta.title">{{ theOnlyOneChild.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</AppLink>
|
||||
</template>
|
||||
|
||||
<!-- 嵌套路由 -->
|
||||
<el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
|
||||
<el-sub-menu
|
||||
v-else
|
||||
:index="resolvePath(item.path)"
|
||||
>
|
||||
<!-- popper-append-to-body -->
|
||||
<template #title>
|
||||
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
|
||||
<span v-if="item.meta && item.meta.title">{{ item.meta.title }}</span>
|
||||
</template>
|
||||
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:is-nest="true"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
<template v-if="item.children">
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:item="child"
|
||||
:is-collapse="isCollapse"
|
||||
:is-first-level="false"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import path from 'path-browserify'
|
||||
import {defineComponent, PropType} from "vue";
|
||||
import {defineComponent, PropType, reactive,computed } from "vue";
|
||||
import {RouteRecordRaw} from 'vue-router'
|
||||
import {isExternal} from '@utils/validate'
|
||||
import AppLink from './Link.vue'
|
||||
|
|
@ -43,23 +51,67 @@ import SvgIcon from '@/components/SvgIcon/index.vue';
|
|||
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SidebarItem',
|
||||
components: {SvgIcon, AppLink},
|
||||
props: {
|
||||
item: {
|
||||
type: Object as PropType<RouteRecordRaw>,
|
||||
required: true
|
||||
},
|
||||
isNest: {
|
||||
isCollapse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
required: false
|
||||
},
|
||||
isFirstLevel: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
required: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AppLink,
|
||||
SvgIcon
|
||||
},
|
||||
setup(props) {
|
||||
const alwaysShowRootMenu = computed(() => {
|
||||
if (props.item.meta && props.item.meta.alwaysShow) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
const showingChildNumber = computed(() => {
|
||||
if (props.item.children) {
|
||||
const showingChildren = props.item.children.filter((item) => {
|
||||
if (item.meta && item.meta.hidden) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
return showingChildren.length
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
const theOnlyOneChild = computed(() => {
|
||||
if (showingChildNumber.value > 1) {
|
||||
return null
|
||||
}
|
||||
if (props.item.children) {
|
||||
for (const child of props.item.children) {
|
||||
if (!child.meta || !child.meta.hidden) {
|
||||
return child
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there is no children, return itself with path removed,
|
||||
// because this.basePath already conatins item's path information
|
||||
return { ...props.item, path: '' }
|
||||
})
|
||||
|
||||
const resolvePath = (routePath: string) => {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
|
|
@ -67,11 +119,13 @@ export default defineComponent({
|
|||
if (isExternal(props.basePath)) {
|
||||
return props.basePath
|
||||
}
|
||||
console.log(props.basePath,routePath)
|
||||
return path.resolve(props.basePath, routePath)
|
||||
}
|
||||
|
||||
return {
|
||||
alwaysShowRootMenu,
|
||||
showingChildNumber,
|
||||
theOnlyOneChild,
|
||||
resolvePath
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
:item="route"
|
||||
:key="route.path"
|
||||
:base-path="route.path"
|
||||
:is-collapse="isCollapse"
|
||||
/>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ export const constantRoutes: Array<RouteRecordRaw> = [
|
|||
path: '/',
|
||||
component: Layout,
|
||||
redirect: '/dashboard',
|
||||
meta:{hidden:true},
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ import {Module} from "vuex";
|
|||
import {PermissionState, RootStateTypes} from "@store/interface";
|
||||
import {RouteRecordRaw} from 'vue-router'
|
||||
import {constantRoutes} from '@/router'
|
||||
import {getRouteList} from "@api/system/menu";
|
||||
import {getRouteList} from "@/api/system/menu";
|
||||
|
||||
const modules = import.meta.glob("../../views/**/**.vue");
|
||||
import Layout from '@/layout/index.vue'
|
||||
|
||||
const hasPermission = (roles: string[], route: RouteRecordRaw) => {
|
||||
// 超级管理员放行
|
||||
|
|
@ -26,10 +28,21 @@ export const filterAsyncRoutes = (routes: RouteRecordRaw[], roles: string[]) =>
|
|||
routes.forEach(route => {
|
||||
const tmp = {...route}
|
||||
if (hasPermission(roles, tmp)) {
|
||||
if (tmp.component == 'Layout') {
|
||||
tmp.component = Layout
|
||||
} else {
|
||||
const component = modules[`../../views/${tmp.component}.vue`] as any;
|
||||
if (component) {
|
||||
tmp.component = modules[`../../views/${tmp.component}.vue`];
|
||||
} else {
|
||||
tmp.component = modules[`../../views/error-page/404.vue`];
|
||||
}
|
||||
}
|
||||
res.push(tmp)
|
||||
|
||||
if (tmp.children) {
|
||||
tmp.children = filterAsyncRoutes(tmp.children, roles)
|
||||
}
|
||||
res.push(tmp)
|
||||
}
|
||||
})
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div>
|
||||
123
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue