Skip to content

Commit d744243

Browse files
committed
动态路由
1 parent 258945f commit d744243

File tree

9 files changed

+181
-36
lines changed

9 files changed

+181
-36
lines changed

muenu-server.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const express = require('express');
2+
3+
const app = express();
4+
app.all('*', (req, res, next) => {
5+
res.header('Access-Control-Allow-Origin', '*');
6+
res.header('Access-Control-Allow-Headers', 'Content-Type,token');
7+
res.header('Access-Control-Allow-Methods', '*');
8+
res.header('Content-Type', 'application/json;charset=utf-8');
9+
next();
10+
});
11+
app.get('/category', (req, res) => {
12+
res.json({
13+
menuList: [
14+
// {
15+
// id: 0,
16+
// icon: 'el-icon-s-order',
17+
// index: 'table',
18+
// title: '基础表格',
19+
// pid: -1,
20+
// },
21+
{
22+
id: 1,
23+
icon: 'el-icon-s-marketing',
24+
index: 'tab',
25+
title: 'tab选项卡',
26+
pid: -1,
27+
},
28+
{
29+
id: 2,
30+
icon: 'el-icon-folder-opened',
31+
index: 'form',
32+
title: '表单相关',
33+
pid: -1,
34+
},
35+
{
36+
id: 3,
37+
index: 'base_form',
38+
title: '基本表单',
39+
icon: 'el-icon-s-data',
40+
pid: 2,
41+
},
42+
{
43+
id: 4,
44+
index: 'upload',
45+
title: '文件上传',
46+
pid: 2,
47+
}
48+
]
49+
});
50+
});
51+
app.listen(3000); // http://localhost:3000/category

src/components/menus/Menus.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<script>
2525
import MenuItem from './MenuItem.vue';
2626
import { mapState } from 'vuex';
27+
import { getTreeList } from '@/utils';
2728
2829
export default {
2930
data () {
@@ -32,9 +33,17 @@ export default {
3233
},
3334
computed: {
3435
...mapState({
35-
menuList: state => state.view.menuList,
36+
authMenuList: state => state.menus.authMenuList,
3637
isCollapse: state => state.view.sidebarOpened,
3738
}),
39+
// 对菜单进行格式化
40+
menuList () {
41+
try {
42+
return getTreeList(this.authMenuList);
43+
} catch (e) {
44+
return [];
45+
}
46+
},
3847
onRoutes () {
3948
return this.$route.path.replace('/', '');
4049
}

src/router/router.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import Vue from 'vue'
2-
import VueRouter from 'vue-router'
1+
import Vue from 'vue';
2+
import VueRouter from 'vue-router';
3+
import store from '@/store';
34
import home from './shared/home';
45
import login from './shared/login';
6+
import { constantRoutes } from './constant-routes';
57
import { setTitle, storage } from '@/utils';
68
import { authToken } from '@/config';
7-
import { constantRoutes } from './constant-routes';
89
Vue.use(VueRouter)
910

1011
const routes = [
@@ -48,12 +49,23 @@ const auth = (to, from, next) => {
4849
next({ name: 'login', query: { backUrl: to.fullPath } });
4950
}
5051
}
52+
53+
const authRoutes = async (to, from, next) => {
54+
if (!store.state.hasPermission) {
55+
const routes = await store.dispatch('getAuthRoutes');
56+
// router.options.routes[0].children.push(...routes);
57+
router.addRoutes(routes);
58+
console.log(routes, '////', router.options.routes)
59+
next({ ...to, replace: true });
60+
} else {
61+
next();
62+
}
63+
}
5164
/********************************路由拦截配置 start********************************/
5265
router.beforeEach((to, from, next) => {
66+
authRoutes(to, from, next);
5367
// 校验是否登录
5468
auth(to, from, next);
55-
// 动态生成路由
56-
// mergeRoute();
5769
setTitle(to.meta.title);
5870
next();
5971
});

src/services/menu.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import axios from 'axios';
2+
3+
class MenuService {
4+
// 获取菜单的接口
5+
async getMenuList () {
6+
return await axios.get('http://localhost:3000/category');
7+
}
8+
}
9+
10+
export default new MenuService();

src/store/modules/menus.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import MenuService from '@/services/menu';
2+
import { constantRoutes } from '@/router/constant-routes';
3+
4+
/**
5+
* @Author: 水痕
6+
* @Date: 2020-06-02 09:57:15
7+
* @LastEditors: 水痕
8+
* @Description: 根据服务器返回的路由文件过滤本地的路由文件数据
9+
* @param {type}
10+
* @return:
11+
*/
12+
const getRoutes = (authList) => {
13+
const auth = authList.map(item => item.index);
14+
// 对当前本地的路由文件进行过滤
15+
const filterRoutes = (authRoutes) => {
16+
return authRoutes.filter(route => {
17+
if (auth.includes(route.name)) {
18+
// 递归遍历子菜单
19+
if (route.children) {
20+
route.children = filterRoutes(route.children);
21+
}
22+
return route;
23+
}
24+
})
25+
}
26+
return filterRoutes(constantRoutes);
27+
}
28+
29+
export default {
30+
state: {
31+
hasPermission: false, // 判断是否有权限
32+
authMenuList: [], // 授权的菜单列表
33+
},
34+
mutations: {
35+
setPermission (state) {
36+
state.hasPermission = true;
37+
},
38+
setAuthMenuList (state, payload) {
39+
state.authMenuList = payload;
40+
}
41+
},
42+
actions: {
43+
// 获取菜单的api
44+
async getMenuListApi ({ commit }) {
45+
const { menuList } = await MenuService.getMenuList();
46+
commit('setAuthMenuList', menuList);
47+
commit('setPermission');
48+
return menuList;
49+
},
50+
// 根据获取的菜单,动态添加路由到本地路由文件
51+
async getAuthRoutes ({ dispatch }) {
52+
const authList = await dispatch('getMenuListApi');
53+
return getRoutes(authList);
54+
}
55+
}
56+
}

src/store/modules/view.js

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,7 @@ import * as types from '../mutation-types';
22
const state = {
33
sidebarOpened: true,
44
title: '主页',
5-
menuList: [
6-
{
7-
icon: 'el-icon-s-order',
8-
index: 'table',
9-
title: '基础表格'
10-
},
11-
{
12-
icon: 'el-icon-s-marketing',
13-
index: 'tab',
14-
title: 'tab选项卡'
15-
},
16-
{
17-
icon: 'el-icon-folder-opened',
18-
index: 'form',
19-
title: '表单相关',
20-
children: [
21-
{
22-
index: 'base_form',
23-
title: '基本表单',
24-
icon: 'el-icon-s-data',
25-
},
26-
{
27-
index: 'upload',
28-
title: '文件上传'
29-
}
30-
]
31-
}
32-
],
5+
menuList: [],
336
};
347

358
const getters = {

src/utils/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './http';
22
export * from './storage';
33
export * from './str';
4-
export * from './set-title';
4+
export * from './set-title';
5+
export * from './menu';

src/utils/menu.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @Author: 水痕
3+
* @Date: 2020-06-02 10:37:18
4+
* @LastEditors: 水痕
5+
* @Description: 定义一个方法将获取的数组数据转换为树结构数据
6+
* @param {type}
7+
* @return:
8+
*/
9+
export const getTreeList = (dataList) => {
10+
if (!Array.isArray(dataList)) {
11+
throw new TypeError(`${dataList}不是数组`);
12+
}
13+
// 第一次是将全部的permissionId作为对象的key重组成一个对象
14+
let formatObj = dataList.reduce((pre, cur) => {
15+
return { ...pre, [cur['id']]: cur }
16+
}, {});
17+
18+
let formatArray = dataList.reduce((arr, cur) => {
19+
let pid = cur.pid ? cur.pid : 0;
20+
let parent = formatObj[pid];
21+
if (parent) {
22+
parent.children ? parent.children.push(cur) : parent.children = [cur];
23+
} else {
24+
arr.push(cur)
25+
}
26+
return arr;
27+
}, []);
28+
console.log(formatArray);
29+
return formatArray;
30+
};
31+

src/views/shared/app/Index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<template>
22
<div id="app">
3-
<router-view />
3+
<keep-alive>
4+
<router-view />
5+
</keep-alive>
46
</div>
57
</template>
68

0 commit comments

Comments
 (0)