Commit 96d529ad authored by tyn's avatar tyn

动态路由

parent a0054d24
<template>
<div class="child-item">
<el-submenu :index="children.path">
<template slot="title">
<div class="menu-item-title">
<img :src="require(`@/${children.meta.icon}`)" alt="" v-if="children.meta.icon">
<span>{{children.meta.title}}</span>
</div>
</template>
<template v-for="(child, index) in children.children">
<template v-if="child.meta.inSideBar && child.children">
<child-item :children="child" :key="child.path"></child-item>
</template>
<el-menu-item v-else-if="child.meta.inSideBar && !child.children" :key="child.path" :index="child.path">
<template slot="title">
<div class="menu-item-title">
<img :src="require(`@/${child.meta.icon}`)" alt="" v-if="child.meta.icon">
<span>{{child.meta.title}}</span>
</div>
</template>
</el-menu-item>
</template>
</el-submenu>
</div>
</template>
<script>
export default {
name: "childItem",
props: {
children: {
type: Object,
}
},
data() {
return {
};
},
//可访问data属性
created() {
},
//计算集
computed: {
},
//方法集
methods: {
},
}
</script>
<style lang="scss" scoped>
</style>
<template >
<router-view />
</template>
......@@ -7,35 +7,20 @@
<!-- 菜单 -->
<div class="menu">
<el-menu mode="vertical" default-active="/home/index" :collapse="collapseStatus" :unique-opened="true" @select="selectMenu">
<template v-for="(item, subIndex) of menus">
<el-menu-item v-if="item.show" :index="item.path" :key="item.path">
{{item.title}}
</el-menu-item>
</template>
<el-submenu v-for="(subItem, index) of subMenu" :index="subItem.path" :key="subItem.path">
<template slot="title">{{subItem.meta.title}}</template>
<template v-if="subItem.children">
<el-menu-item v-for="(item, subIndex) of subItem.children" :index="item.path" :key="item.path">
{{item.meta.title}}
</el-menu-item>
</template>
</el-submenu>
<el-menu mode="vertical" default-active="/certificationManagement" :collapse="collapseStatus" :unique-opened="true" @select="selectMenu">
<side-bar-item v-for="item of sideBarData" :item-data="item" :key="item.path"></side-bar-item>
</el-menu>
</div>
</div>
</template>
<script>
import { routes } from "@/router/";
import SideBarItem from "@/components/SideBarItem";
export default {
name: "sideBar",
components: {
SideBarItem
},
data() {
return {
menus: [],
......@@ -45,38 +30,16 @@ export default {
},
//可访问data属性
created() {
this.createMenu();
console.log(this.sideBarData);
},
//计算集
computed: {
sideBarData() {
return this.$store.state.routerModule.sideBarRoutes;
}
},
//方法集
methods: {
createMenu() {
routes.forEach(item => {
if (item.path === "/home") {
if (item.children && item.children.length > 0) {
let temp = item.children;
temp.forEach(child => {
if (child.children && child.children.length > 0) {
this.subMenu.push(child);
} else {
this.menus.push({
path: child.path,
name: child.name,
title: child.meta?.title,
show: child.meta?.show
});
}
});
}
}
});
},
selectMenu(path, pathName) {
if (this.$route.path === path) return;
this.$router.push({ path });
......@@ -99,11 +62,25 @@ export default {
align-items: center;
background: #fff;
border-bottom: 1px solid #eeeeee;
box-sizing: border-box;
}
// 菜单
.menu {
width: 100%;
height: calc(100% - 60px);
::v-deep .el-menu {
height: 100%;
border-right: unset;
.menu-item-title {
display: flex;
& > img {
margin-right: 15px;
}
}
}
}
}
</style>
<template>
<div class="side-bar-item" v-if="itemData.meta.inSideBar">
<!-- 有子菜单 -->
<child-item v-if="itemData.children && itemData.children.length" :key="itemData.path" :children="itemData"></child-item>
<!-- 无子菜单 -->
<el-menu-item v-else :key="itemData.path" :index="itemData.path">
<template slot="title">
<div class="menu-item-title">
<img :src="require(`@/${itemData.meta.icon}`)" alt="" v-if="itemData.meta.icon">
<span>{{itemData.meta.title}}</span>
</div>
</template>
</el-menu-item>
</div>
</template>
<script>
import ChildItem from "@/components/ChildItem";
export default {
name: "sideBarItem",
components: {
ChildItem
},
props: {
itemData: {
type: Object,
}
},
data() {
return {
};
},
//可访问data属性
created() {
},
//计算集
computed: {
},
//方法集
methods: {
},
}
</script>
<style lang="scss" scoped>
</style>
......@@ -24,7 +24,7 @@
<script>
import SideBar from "@/components/SideBar";
export default {
name: "home",
name: "Home",
components: {
SideBar
},
......
import Vue from 'vue';
import VueRouter from 'vue-router';
import { defaultRoutes } from "./routes-config";
Vue.use(VueRouter);
......@@ -14,59 +15,10 @@ VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err);
};
const routes = [
{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: 'login',
component: () => import('@/login'),
meta: {
title: "登录页",
needToken: false
}
},
{
path: '/register',
name: 'register',
component: () => import('@/register'),
meta: {
title: "注册页",
needToken: false
}
},
{
path: '/home',
redirect: "/home/index",
name: 'Home',
component: () => import(/* webpackChunkName: "Home" */"@/home"),
meta: {
title: "首页",
needToken: true
},
children: [
{
path: '/home/index',
name: 'HomeIndex',
component: () => import(/* webpackChunkName: "Home" */"@/views/certificationManagement"),
meta: {
title: "认证管理",
needToken: true,
show: true
},
}
]
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
routes: defaultRoutes
});
export default router;
export { routes };
......@@ -7,6 +7,8 @@ import {
getToken
} from '@/utils/auth';
const whiteRoutes = ["/login", "/redirect", "/register"];
// 路由前置守卫
router.beforeEach((to, from, next) => {
to.meta?.title && (document.title = to.meta.title);
......@@ -17,10 +19,18 @@ router.beforeEach((to, from, next) => {
* 是重定向
* 否则根据用户基本信息 获取当前状态
*/
// 跳转拉取用户基本信息
// 没有用户身份id 拉取信息 有则 是否去往登录页 是则重定向
if (!store.state.user.userInfo?.userId) {
store.dispatch("user/getUserInfo").then(() => {
next({path : "/home"});
store.dispatch("user/getUserInfo").then(res => {
store.dispatch("routerModule/createRouter", "1").then(routes => {
routes.forEach(route => {
router.addRoute(route);
});
next({
...to,
replace: true
});
});
})
.catch(err => {
Message.error(err.msg || "获取用户信息失败!");
......@@ -29,17 +39,23 @@ router.beforeEach((to, from, next) => {
});
});
} else {
next();
if (to.path === "/login") {
next({ path: "/home", replace: true });
} else {
next();
}
}
} else {
/**
* 判断当前前往页面是否需要token
* 不匹配 以及 未带token重定向到登录页
*/
if (to.meta?.needToken === false) {
if (whiteRoutes.includes(to.path)) {
next();
} else {
next();
next({
path: "/login"
});
}
}
});
\ No newline at end of file
// 基础路由 //TIP:未登陆前开放路由可写入该数组
export const defaultRoutes = [
{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: 'login',
component: () => import('@/login'),
meta: {
title: "登录页",
}
},
{
path: '/register',
name: 'register',
component: () => import('@/register'),
meta: {
title: "注册页",
}
},
];
/**
* TIP : 规则 除开基础配置以外 roles代表角色 permission是权限节点
* TIP : meta icon 图标地址 inSideBar 是否在侧边栏菜单显示 inBread是否在面包削显示 cache是否缓存 取的是组件export 对象里的name
*/
// 动态生成路由 //TIP:登录后的路由请务必写入该数组 /home为全局父组件 其他组件需嵌套在该组件children下
export const rolesOfRoutes = [
{
path: '/home',
redirect: "/certificationManagement",
name: 'Home',
component: "home",
meta: {
permission: [],
roles: ["normal"],
inSideBar: true
},
children: [
{
path: '/certificationManagement',
name: 'certificationManagement',
component: "views/certificationManagement",
meta: {
title: "认证管理",
icon: "",
menuType: "C",
inSideBar: true,
inBread: true,
cache: false,
permission: [],
roles: ["normal"],
},
},
{
path: '/test1',
name: 'test1',
component: "catalogue",
meta: {
title: "测试目录1",
icon: "",
menuType: "M",
inSideBar: true,
inBread: true,
cache: false,
permission: [],
roles: ["normal"],
},
children: [
{
path: '/test2',
name: 'test2',
component: "views/test2",
meta: {
title: "测试菜单2",
icon: "",
menuType: "C",
inSideBar: true,
inBread: true,
cache: false,
permission: [],
roles: ["normal"],
}
}
]
},
]
},
];
\ No newline at end of file
import Vue from 'vue';
import Vuex from 'vuex';
import userModule from "./modules/user-module";
import routerModule from "./modules/router-module";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user: userModule
user: userModule,
routerModule
}
});
import { defaultRoutes, rolesOfRoutes } from "@/router/routes-config";
import { createAsyncRoutes } from "@/utils/router-generator";
const state = {
// 侧边栏菜单
sideBarRoutes: [],
// 顶部面包屑
topBarRoutes: [],
// 生成后路由
routes: []
};
const actions = {
createRouter({ commit }, payload) {
// 生成路由
return new Promise((resolve, reject) => {
// 侧边栏
const sList = JSON.parse(JSON.stringify(rolesOfRoutes));
const rList = JSON.parse(JSON.stringify(rolesOfRoutes));
// 生成后侧边栏
const sideBarRoutes = createAsyncRoutes(sList[0].children, payload);
const routes = createAsyncRoutes(rList, payload);
commit("setSideBar", sideBarRoutes);
console.log(sideBarRoutes);
resolve(routes);
});
}
};
const mutations = {
setSideBar(state, payload) {
state.sideBarRoutes = payload;
}
};
const getters = {
};
export default {
namespaced: true,
state,
actions,
mutations,
getters
};
\ No newline at end of file
import { userRolesDict } from "@/utils/user-roles";
import Catalogue from "@/components/ParentView";
export const createAsyncRoutes = (routerList, role) => {
return routerList.filter(route => {
route.component && (route.component = componentsFormat(route.component));
if (route.children && route.children.length > 0) {
route.children = createAsyncRoutes(route.children, role);
}
return route.meta.roles.includes(userRolesDict[role]);
});
};
// 动态引用
const componentsFormat = (component) => {
if (component === "catalogue") {
return Catalogue;
}
return () => import(/* webpackChunkName: "[request]" */`@/${component}`);
};
\ No newline at end of file
export const userRolesDict = {
"1" : "normal"
};
\ No newline at end of file
<template>
<div class="test1">
111
</div>
</template>
<script>
export default {
name : "test1",
data() {
return {
}
},
//可访问data属性
created(){
},
//计算集
computed:{
},
//方法集
methods:{
},
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div class="test2">
22
</div>
</template>
<script>
export default {
name : "test2",
data() {
return {
}
},
//可访问data属性
created(){
},
//计算集
computed:{
},
//方法集
methods:{
},
}
</script>
<style lang="scss" scoped>
</style>
......@@ -86,7 +86,7 @@ module.exports = defineConfig({
},
// 本地代理服务器
devServer: {
host: 'localhost',
host: '0.0.0.0',
port: "8866",
open: true,
proxy: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment