后端实现
@RestController
@RequestMapping("/system/config")
public class SystemConfigController {
@Autowired
MenuService menuService;
@GetMapping("/menu")
public List<Menu> getMenusByHrId() {
return menuService.getMenusByHrId();
}
}
getMenusByHrId()的sql语句如下:(根据hr的id查找到所有的额menu)
select distinct m1.*,m2.`id` as id2,m2.`component` as component2,m2.`enabled` as enabled2,
m2.`iconCls` as iconCls2,m2.`keepAlive` as keepAlive2,m2.`name` as name2,
m2.`parentId` as parentId2,m2.`requireAuth` as requireAuth2,m2.`path` as path2
from menu m1,menu m2,hr_role hrr,menu_role mr
where m1.`id`=m2.`parentId` and hrr.`hrid`=3
and hrr.`rid`=mr.`rid` and mr.`mid`=m2.`id`
and m2.`enabled`=true
order by m1.`id`,m2.`id`
前端实现
在登录的时候,就访问后端并且拿到菜单数据存到store里,但是一刷新(f5)就没了,这时候有两种办法:
- 不存到store里,存到localStorage里。但是菜单资源非常敏感不建议保存到本地
- 在每个页面的mounted方法里都加载一次资源。但是这样工作量有点大。
所以使用导航守卫来简化方案2。下面是具体方法:
1.在store/index.js下配置store.state
2.在main.js里配置导航守卫
router.beforeEach((to, from, next) => {
if (to.path == '/') {
next();
} else {
if (window.sessionStorage.getItem("user")) {
initMenu(router, store);
next();
} else {
next('/?redirect=' + to.path);
}
}
})
3.在util/menus.js里
import {getRequest} from "./api";
export const initMenu = (router, store) => {
if (store.state.routes.length > 0) {
return;
}
getRequest("/system/config/menu").then(data => {
if (data) {
let fmtRoutes = formatRoutes(data);
router.addRoutes(fmtRoutes);
store.commit('initRoutes', fmtRoutes);
store.dispatch('connect');
}
})
}
export const formatRoutes = (routes) => {
let fmRoutes = [];
routes.forEach(router => {
let {
path,
component,
name,
meta,
iconCls,
children
} = router;
if (children && children instanceof Array) {
children = formatRoutes(children);
}
let fmRouter = {
path: path,
name: name,
iconCls: iconCls,
meta: meta,
children: children,
component(resolve) {
if (component.startsWith("Home")) {
require(['../views/' + component + '.vue'], resolve);
} else if (component.startsWith("Emp")) {
require(['../views/emp/' + component + '.vue'], resolve);
} else if (component.startsWith("Per")) {
require(['../views/per/' + component + '.vue'], resolve);
} else if (component.startsWith("Sal")) {
require(['../views/sal/' + component + '.vue'], resolve);
} else if (component.startsWith("Sta")) {
require(['../views/sta/' + component + '.vue'], resolve);
} else if (component.startsWith("Sys")) {
require(['../views/sys/' + component + '.vue'], resolve);
}
}
}
fmRoutes.push(fmRouter);
})
return fmRoutes;
}
4.最后在home.vue里面实现页面渲染
<template>
<div>
<el-container>
<el-header class="homeHeader">
<div class="title">微人事</div>
<div>
<el-button icon="el-icon-bell" type="text" style="margin-right: 8px;color: #000000;" size="normal"
@click="goChat"></el-button>
<el-dropdown class="userInfo" @command="commandHandler">
<span class="el-dropdown-link">
{{user.name}}<i><img :src="user.userface" alt=""></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="userinfo">个人中心</el-dropdown-item>
<el-dropdown-item command="setting">设置</el-dropdown-item>
<el-dropdown-item command="logout" divided>注销登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-header>
<el-container>
<el-aside width="200px">
<el-menu router unique-opened>
<el-submenu :index="index+''" v-for="(item,index) in routes" v-if="!item.hidden" :key="index">
<template slot="title">
<i style="color: #409eff;margin-right: 5px" :class="item.iconCls"></i>
<span>{{item.name}}</span>
</template>
<el-menu-item :index="child.path" v-for="(child,indexj) in item.children" :key="indexj">
{{child.name}}
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<el-breadcrumb separator-class="el-icon-arrow-right" v-if="this.$router.currentRoute.path!='/home'">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{this.$router.currentRoute.name}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="homeWelcome" v-if="this.$router.currentRoute.path=='/home'">
欢迎来到微人事!
</div>
<router-view class="homeRouterView"/>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: "Home",
data() {
return {
// user: JSON.parse(window.sessionStorage.getItem("user"))
}
},
computed: {
routes() {
return this.$store.state.routes;
},
user() {
return this.$store.state.currentHr;
}
},
methods: {
goChat() {
this.$router.push("/chat");
},
commandHandler(cmd) {
if (cmd == 'logout') {
this.$confirm('此操作将注销登录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.getRequest("/logout");
window.sessionStorage.removeItem("user")
this.$store.commit('initRoutes', []);
this.$router.replace("/");
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
} else if (cmd == 'userinfo') {
this.$router.push('/hrinfo');
}
}
}
}
</script>
<style>
.homeRouterView {
margin-top: 10px;
}
.homeWelcome {
text-align: center;
font-size: 30px;
font-family: 华文行楷;
color: #409eff;
padding-top: 50px;
}
.homeHeader {
background-color: #409eff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0px 15px;
box-sizing: border-box;
}
.homeHeader .title {
font-size: 30px;
font-family: 华文行楷;
color: #ffffff
}
.homeHeader .userInfo {
cursor: pointer;
}
.el-dropdown-link img {
width: 48px;
height: 48px;
border-radius: 24px;
margin-left: 8px;
}
.el-dropdown-link {
display: flex;
align-items: center;
}
</style>