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