1.router.js 文件组装路由并组装菜单
2.main.js 做全局路由守卫 判断 是否有访问权限
3.点击组装菜单导航 router-link :to="item.path" 跳转 到 router-viewe 坑位
router.js 文件
import Vue from 'vue'
/**=====================================================================================
* 公共模板组件
*======================================================================================*/
const Layout = () => import('./views/layout.vue')
/**=====================================================================================
* 登录
*======================================================================================*/
const Login = () => import(/* webpackChunckName: "group-login" */ './views/login.vue')
/**=====================================================================================
* 首页
*======================================================================================*/
const Index = () => import(/* webpackChunckName: "group-index" */ './views/index.vue')
/**=====================================================================================
* 任务中心
*======================================================================================*/
const taskList = () => import(/* webpackChunckName: "group-taskList" */ './views/task/taskList.vue')
const taskDetail = () => import(/* webpackChunckName: "group-taskDetail" */ './views/task/taskDetail.vue')
const taskDetailDetail = () => import(/* webpackChunckName: "group-taskDetailDetail" */ './views/task/taskDetailDetail.vue')
/**=====================================================================================
* 结算中心
*======================================================================================*/
const settlementList = () => import(/* webpackChunckName: "group-settlementList" */ './views/settlement/settlementList.vue')
const settlementDetail = () => import(/* webpackChunckName: "group-settlementDetail" */ './views/settlement/settlementDetail.vue')
/**=====================================================================================
* 结算批次
*======================================================================================*/
const settlementBatchList = () => import(/* webpackChunckName: "group-settlementBatchList" */ './views/settlementBatch/settlementBatchList.vue')
const settlementBatchDetail = () => import(/* webpackChunckName: "group-settlementBatchDetail" */ './views/settlementBatch/settlementBatchDetail.vue')
/**=====================================================================================
* 结算统计
*======================================================================================*/
const settlementStatisticsList = () => import(/* webpackChunckName: "group-settlementStatisticsList" */ './views/settlementStatistics/settlementStatisticsList.vue')
const settlementStatisticsDetail = () => import(/* webpackChunckName: "group-settlementStatisticsDetail" */ './views/settlementStatistics/settlementStatisticsDetail.vue')
/**=====================================================================================
* 签约管理
*======================================================================================*/
const contractList = () => import(/* webpackChunckName: "group-list" */ './views/contract/contractList.vue')
const contractAddContract = () => import(/* webpackChunckName: "group-addContract" */ './views/contract/addContract.vue')
/**=====================================================================================
* 合同模板管理
*======================================================================================*/
const contractTemplateList = () => import(/* webpackChunckName: "group-templateList" */ './views/contractTemplate/templateList.vue')
const contractTemplateDetail = () => import(/* webpackChunckName: "group-templateDetail" */ './views/contractTemplate/templateDetail.vue')
export default {
routes: [
/**=====================================================================================
* 登录
*======================================================================================*/
{
path: '/login',
name: '登录',
component: Login,
meta: {
noAuth: true
}
},
/**=====================================================================================
* 首页
*======================================================================================*/
{
path: '/',
name: '首页',
component: Index,
meta: {
alias: 'index'
}
}
],
/**
* [getRoutesList description] 根据权限组装路由
* @param {[type]} ids [description] isLogin接口返回的权限id列表
* @return {[type]} [description]
*/
getRoutesList: function (ids) {
let navs = [],
list = [],
sublist = [];
/**=====================================================================================
* 任务中心 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(4101) > -1) {
list.push({
path: '/task/taskList',
name: '任务中心',
component: taskList,
meta: {
parent: 'user'
}
});
list.push({
path: '/task/taskDetail',
name: '任务详情',
component: taskDetail,
meta: {
parent: 'user'
}
});
list.push({
path: '/task/taskDetailDetail',
name: '结算批次详情',
component: taskDetailDetail,
meta: {
parent: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '任务中心',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
/**=====================================================================================
* 结算中心 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(9201) > -1) {
list.push({
path: '/settlement/settlementList',
name: '结算中心',
component: settlementList,
meta: {
alias: 'user'
}
});
list.push({
path: '/settlement/settlementDetail',
name: '结算详情',
component: settlementDetail,
meta: {
alias: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '结算中心',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
/**=====================================================================================
* 结算批次 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(9201) > -1) {
list.push({
path: '/settlementBatch/settlementBatchList',
name: '结算批次',
component: settlementBatchList,
meta: {
alias: 'user'
}
});
list.push({
path: '/settlementBatch/settlementBatchDetail',
name: '结算详情',
component: settlementBatchDetail,
meta: {
alias: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '结算批次',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
/**=====================================================================================
* 结算统计 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(2001) > -1) {
list.push({
path: '/settlementStatistics/settlementStatisticsList',
name: '结算批次',
component: settlementStatisticsList,
meta: {
alias: 'user'
}
});
list.push({
path: '/settlementStatistics/settlementStatisticsDetail',
name: '统计详情',
component: settlementStatisticsDetail,
meta: {
alias: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '结算统计',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
/**=====================================================================================
* 签约管理 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(4201) > -1) {
list.push({
path: '/Contract/contractList',
name: '签约管理',
component: contractList,
meta: {
alias: 'user'
}
});
list.push({
path: '/Contract/addContract',
name: '新增签约企业',
component: contractAddContract,
meta: {
alias: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '签约管理',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
/**=====================================================================================
* 合同模板管理 User
* 2001 -> 查看
* 2002 -> 编辑
*======================================================================================*/
list = [];
if (ids.indexOf(9101) > -1) {
list.push({
path: '/contractTemplate/templateList',
name: '合同模板管理',
component: contractTemplateList,
meta: {
alias: 'user'
}
});
list.push({
path: '/contractTemplate/templateDetail',
name: '新增服务协议',
component: contractTemplateDetail,
meta: {
alias: 'user'
}
});
}
if (list.length > 0) {
navs.push({
path: list[0].path,
name: '合同模板管理',
component: Layout,
meta: {
alias: 'user'
},
children: list
});
}
this.setRoutesStorage(navs);
return navs;
},
/**
* [setRoutesStorage description] 将完整的route结构存本地,供左侧导航渲染使用
* @param {[type]} list [description]
*/
setRoutesStorage: function (list) {
let lists = this.routes.concat(list);
localStorage.setItem('routes', JSON.stringify(lists));
},
/**
* [hasPermission description] 判断是否具有对应权限
* @param {[type]} toPath [description] 目标路由
* @return {Boolean} [description]
*/
hasPermission: function (toPath) {
let lists = JSON.parse(localStorage.getItem('routes')),
paths = [];
lists.forEach(navItem => {
if (paths.indexOf(navItem.path) == -1) {
paths.push(navItem.path);
}
if (navItem.children && navItem.children.length > 0) {
navItem.children.forEach(listItem => {
if (paths.indexOf(listItem.path) == -1) {
paths.push(listItem.path);
}
if (listItem.children && listItem.children.length > 0) {
listItem.children.forEach(subListItem => {
if (paths.indexOf(subListItem.path) == -1) {
paths.push(subListItem.path);
}
if (subListItem.children && subListItem.children.length > 0) {
subListItem.children.forEach(dynamicItem => {
if (paths.indexOf(dynamicItem.path) == -1) {
dynamicItem.path = dynamicItem.path.replace(/\/:\w+/g, '');
paths.push(subListItem.path + '/' + dynamicItem.path);
}
if (dynamicItem.children && dynamicItem.children.length > 0) {
dynamicItem.children.forEach(dynamicGrandparents => {
if (paths.indexOf(dynamicGrandparents.path) == -1) {
dynamicItem.path = dynamicItem.path.replace(/\/:\w+/g, '');
dynamicGrandparents.path = dynamicGrandparents.path.replace(/\/:\w+/g, '');
paths.push(subListItem.path + '/' + dynamicItem.path + '/' + dynamicGrandparents.path);
}
})
}
})
}
});
}
});
}
});
if (paths.join(',').indexOf(toPath) > -1) {
return true;
} else {
return false;
}
}
}
main.js 文件
// router
import routers from './router'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: routers.routes
})
// ====================================== axios
axios.interceptors.request.use((config) => {
// let token = localStorage.getItem('token') || '';
// token = token.replaceAll('"', '');
// if(token) {
// config.headers['token'] = token;
// }
return config
}, function (error) {
console.log('request -> error', error)
return Promise.reject(error)
});
axios.interceptors.response.use(function (response) {
let {code, msg} = response.data;
if (code == 10001) { // 参数验证失败
Message.error(msg);
} else if (code == 30001) { // 业务错误报告
Message.error(msg);
} else if (code == 401) { // 登陆过期或未登陆
Message.error(msg);
// =重定向到登录页面
// router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } })
router.replace({path: '/login'});
} else if (code == 403) { // 权限不足
Message.error(msg);
}
return response
}, function (error) {
// Do something with response error
Message.error(error);
return Promise.reject(error)
});
// ======================================== beforeEach
router.beforeEach((to, from, next) => {
if (!to.matched.some(record => record.meta.noAuth)) {
NProgress.start();
// 验证是否已登录
commonApi.COMMON.api('/perms', {}).then(res => {
NProgress.done();
let {code, data} = res;
if (code == 0) {
// 权限id数组
let ids = data || [];
// 判断接口返回的权限 和 本地存储的权限 是否一致
if (localStorage.getItem('ids') == ids) { // 权限无变化
// 判断当前路径是否在routes里面
if (routers.hasPermission(to.path.replace(/\/\d+/g, ''))) {
next();
} else {
Message.error('您没有权限访问这个页面,请联系管理员');
next({path: '/'})
}
} else { // 权限变化
localStorage.setItem('ids', ids);
// 更新route
router.addRoutes(routers.getRoutesList(ids));
// 判断当前路径是否在routes里面
// 不能写成next(), 不然addRoutes不起作用
// to.path 会造成刷新页面的时候 query 所带参数丢失
if (routers.hasPermission(to.path.replace(/\/\d+/g, ''))) {
next({path: to.fullPath});
} else {
Message.error('您没有权限访问这个页面,请联系管理员');
next({path: '/'})
}
}
}
}).catch(error => {
console.log(error);
NProgress.done();
Message.error('服务器异常');
next({
path: '/login'
})
});
} else {
next()
}
});
new Vue({
router,
render: h => h(App),
/**
* [created description] vue实例被销毁的时候(如:页面刷新),清除routes、ids的数据,使isLogin的时候能更新route
* @return {[type]} [description]
*/
created: function () {
localStorage.removeItem('ids');
localStorage.removeItem('routes');
}
}).$mount('#app')
Nav.vue 导航
<template>
<aside class="app-aside">
<div class="logo-container">
<div class="logo">logo</div>
</div>
<nav role="main" class="main-nav">
<ul class="nav-list">
<li class="list-item" v-for="(item, index) in routes" v-if="item.meta.alias">
<router-link :to="item.path" class="main-link" :class="{ 'active' : mainIndex == index }">
<icon-font :type="'icon-' + item.meta.alias"/>
<span class="main-name">{{ item.name }}</span>
</router-link>
</li>
</ul>
</nav>
</aside>
</template>
<script>
import {Icon} from 'ant-design-vue';
const IconFont = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2252332_t0hzfw2rgi8.js',
});
export default {
components: {
IconFont
},
data() {
return {
'route': {}, //当前路由
'routes': [], //路由列表
'mainIndex': '' //一级列表下标
}
},
watch: {
/**
* [description] 监听路由变化
* @param {[type]} val [description] 当前路由
* @return {[type]} [description]
*/
'$route': function (val) {
this.route = this.$route;
this.routes = localStorage.getItem('routes') ? JSON.parse(localStorage.getItem('routes')) : this.$router.options.routes;
this.mainIndex = '';
for (let i = 0; i < this.routes.length; i++) {
let routeItem = this.routes[i];
if (routeItem.meta.alias && (routeItem.meta.alias == this.route.meta.parent || routeItem.meta.alias == this.route.meta.alias)) {
this.mainIndex = i;
this.$emit('subNavShow', false);
break;
}
}
}
},
methods: {}
}
</script>
app.vue 文件 router-view路由坑位
<template>
<div id="app">
<Header v-show="!hideNav" :pageTitle="pageTitle"></Header>
<Nav v-show="!hideNav"></Nav>
<div class="app-container">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
</div>
</div>
</template>
<script>
import Nav from '@/components/Nav.vue'
import Header from '@/components/Header.vue'
export default {
components: {
Nav,
Header
},
data() {
return {
hideNav: true,
pageTitle: ''
}
},
watch: {
'$route': function () {
this.pageTitle = this.$route.name
if (this.$route.fullPath == '/login' || this.$route.path == '/login') {
this.hideNav = true;
} else {
this.hideNav = false;
}
}
},
methods: {},
}
</script>