1.前端完成左侧菜单的递归调用
主页
<template>
<el-container>
<el-header>
<span id="logo" style="display: inline-block;width: 30%;height: 100%;float: left" >
<a href="https://www.bilibili.com/video/BV14g41197PY/"><img src="../assets/logo.png" height="100%" width="180px"></a>
</span>
<span id="avatar" style="float: right">
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link" style="margin-top: 10px; display: inline-block;">
<el-avatar ></el-avatar>
</span>
<el-dropdown-menu slot="dropdown" style="margin-top: -10px">
<el-dropdown-item command="info">个人信息</el-dropdown-item>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</span>
</el-header>
<el-container>
<el-aside width="200px">
<el-menu
:router="true"
:unique-opened="true"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="red">
<LeftMenu :menu-data="leftMenus"></LeftMenu>
</el-menu>
</el-aside>
<el-main>
<router-view/>
</el-main>
</el-container>
<el-footer>Footer</el-footer>
</el-container>
</template>
<script>
import LeftMenu from "@/components/LeftMenu";
export default {
name: "Home",
components: {LeftMenu},
data(){
return{
leftMenus:[],
}
},
created() {
this.initLeftMenu()
},
methods:{
initLeftMenu(){
this.$http.get("/system/permission/leftMenu").then(result=>{
if(result.data.code===2000){
this.leftMenus=result.data.data;
}
})
},
//下拉的触发事件
handleCommand(command) {
if (command === 'logout') {
this.$http.get("/system/logout").then(result => {
if (result.data.code === 2000) {
console.log("11111")
sessionStorage.clear();
//sessionStorage.removeItem("token");
this.$router.push("/login")
}
})
}
}
}
}
</script>
<!--当前vue有效-->
<style>
.menu-icon {
position: relative;
margin-right: 5px;
padding: 0 3px;
left: 0;
}
body, #app {
padding: 0px;
margin: 0px;
}
.el-container {
height: 100%;
}
.el-header, .el-footer {
background-color: #1F272F;
color: #333;
line-height: 60px;
}
.el-aside {
background-color: #545c64;
color: #333;
line-height: 560px;
height: 590px;
}
.el-aside > .el-menu {
border: none;
}
.el-main {
background-color: #E9EEF3;
color: #333;
height: 590px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
.el-tabs__nav .el-tabs__item:nth-child(1) span{
display: none;
}
</style>
1.1.创建一个菜单组件LeftMenu
<template>
<div class="navMenu">
<template v-for="navMenu in menuData">
<!-- 最后一级菜单 叶子菜单 -->
<el-menu-item v-if="navMenu.children.length==0"
:index="navMenu.path"
>
<i :class="navMenu.icon"></i>
<span slot="title">{{navMenu.name}}</span>
</el-menu-item>
<!-- 此菜单下还有子菜单 -->
<el-submenu v-if="navMenu.children.length!=0"
:index="navMenu.path">
<template slot="title">
<i :class="navMenu.icon"></i>
<span> {{navMenu.name}}</span>
</template>
<!-- 递归 -->
<LeftMenu :menu-data="navMenu.children"></LeftMenu>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'LeftMenu',
//接受使用者传递的数据
props: ['menu-data'],
data() {
return {
}
},
methods: {}
}
</script>
<style>
</style>
相当于把菜单内容拆分出来了,因为不知道有几级菜单,这里我们用到了递归
在父组件中使用子组件
1.2.角色管理的页面在home中渲染
(1)添加 :router="true"
此时他会找lefuMenu组件的index属性,这个path是从数据库查到的 跳转路径
(2)设置子路由
(3)渲染路由
(4)修改角色管理组件
<template>
<div>
<el-form :inline="true" :model="formRole" class="demo-form-inline">
<el-form-item label="角色名">
<el-input v-model="formRole.roleName" placeholder="请输入角色名"></el-input>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="formRole.startDate"
type="datetime"
format="yyyy 年 MM 月 dd 日 HH 小时 mm 分钟 ss 秒"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择日期时间"
default-time="12:00:00">
</el-date-picker>
<el-date-picker
v-model="formRole.endDate"
format="yyyy 年 MM 月 dd 日 HH 小时 mm 分钟 ss 秒"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
placeholder="选择日期时间"
default-time="12:00:00">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
<el-button type="text" @click="addRole">添加</el-button>
<el-table
:data="tableData"
height="450"
border
style="width: 100%">
<el-table-column
prop="id"
label="角色id"
>
</el-table-column>
<el-table-column
prop="roleName"
label="角色名称"
>
</el-table-column>
<el-table-column
prop="roleCode"
label="角色编码">
</el-table-column>
<el-table-column
prop="remark"
label="备注">
</el-table-column>
<el-table-column
prop="gmtCreate"
label="创建时间">
</el-table-column>
<el-table-column
prop="gmtModified"
label="更新时间">
</el-table-column>
<el-table-column
fixed="right"
label="操作"
>
<template slot-scope="scope">
<el-button @click="del(scope.row.id)" type="text" size="small">删除</el-button>
<el-button type="text" size="small" @click="edit(scope.row.id)">编辑</el-button>
<el-button type="text" size="small" @click="editPermissions(scope.row.id)">修改权限</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog title="添加角色" :visible.sync="addDialogFormVisible" width="30%" :close-on-click-modal="false">
<el-form :model="addForm">
<el-form-item label="角色名" label-width="80px" prop="roleName">
<el-input v-model="addForm.roleName" autocomplete="off" placeholder="请输入角色名"
style="width: 200px"></el-input>
</el-form-item>
<el-form-item label="角色描述" label-width="80px" prop="remark">
<el-input v-model="addForm.remark" autocomplete="off" placeholder="请输入角色描述"
style="width: 200px"></el-input>
</el-form-item>
<el-form-item label="角色编码" label-width="80px" prop="roleCode">
<el-input v-model="addForm.roleCode" autocomplete="off" placeholder="请输入角色编码"
style="width: 200px"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="addRecord">确 定</el-button>
<el-button @click="resetForm">重置</el-button>
</div>
</el-dialog>
<el-dialog title="修改角色" :visible.sync="editDialogFormVisible" width="30%" :close-on-click-modal="false">
<el-form :model="editForm">
<el-form-item label="角色名" label-width="80px" prop="roleName">
<el-input v-model="editForm.roleName" autocomplete="off" placeholder="请输入角色名"
style="width: 200px"></el-input>
</el-form-item>
<el-form-item label="角色描述" label-width="80px" prop="remark">
<el-input v-model="editForm.remark" autocomplete="off" placeholder="请输入角色描述"
style="width: 200px"></el-input>
</el-form-item>
<el-form-item label="角色编码" label-width="80px" prop="roleCode">
<el-input v-model="editForm.roleCode" autocomplete="off" placeholder="请输入角色编码"
style="width: 200px"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="editRecord">确 定</el-button>
<el-button @click="editCancel">取消</el-button>
</div>
</el-dialog>
<!--修改权限树型控件-->
<el-dialog title="修改权限" :visible.sync="dialogFormVisible" width="30%" :close-on-click-modal="false">
<el-tree
:data="data"
show-checkbox
node-key="id"
ref="tree"
highlight-current
:props="defaultProps">
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmPermission">确 定</el-button>
<el-button @click="dialogFormVisible = false">取消</el-button>
</div>
</el-dialog>
<!--分页插件-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="pageSizes"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</template>
<script>
export default {
name: "List.vue",
data() {
return {
formRole: {
roleName: '',
startDate: '',
endDate: ''
},
tableData: [],
//添加会话框显示隐藏
addDialogFormVisible: false,
//添加会话框表单绑定数据
addForm: {},
//修改会话框显示隐藏
editDialogFormVisible: false,
//修改会话框表单绑定数据
editForm: {},
//修改权限会话框显示隐藏
dialogFormVisible: false,
//树型菜单数据
data: [],
defaultProps: {
children: 'children',
label: 'name'
},
//被选中的角色id
roleid: 0,
//当前页数
currentPage: 1,
//每页显示个数选择器的选项设置
pageSizes: [1, 2, 3, 4, 5],
//每页显示个数
pageSize: 5,
//总条数
total: 0,
}
},
created() {
this.onSubmit();
},
methods: {
//每页显示条数切换时执行
handleSizeChange(val) {
this.currentPage = 1;
this.pageSize = val;
this.onSubmit();
},
//切换显示页数时执行
handleCurrentChange(val) {
this.currentPage = val;
this.onSubmit();
},
//在回显完成后,要记得清除一下Tree中的数据,不然后面点开的回显值会和第一次回显的值一样
clearTree() {
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys([])
})
},
//确认分配权限
confirmPermission() {
//获取所有被选中的节点--获取所有全选的节点
/* var checkedNodes = this.$refs.tree.getCheckedNodes();
var halfCheckedNodes = this.$refs.tree.getHalfCheckedNodes();*/
//声明一个数组存放被选中节点id
/* var menuids=[];
checkedNodes.forEach((item,index)=>{
menuids.push(item.id);
})
halfCheckedNodes.forEach((item,index)=>{
menuids.push(item.id);
})*/
//1.获取全选和半选的树
var checkedNodes = this.$refs.tree.getCheckedNodes(false, true);
//声明一个数组存放被选中节点id
var menuids = [];
checkedNodes.forEach(item => {
menuids.push(item.id);
})
this.$http.post("/system/rolePermission/confirmPermission/" + this.roleid, menuids).then(result => {
//关闭弹出层
this.dialogFormVisible = false;
this.$message.success(result.data.msg);
//刷新当前页面
this.$router.go(0)
this.clearTree();
})
},
//修改权限方法
editPermissions(roleid) {
this.dialogFormVisible = true;
this.roleid = roleid;
this.$http.get("/system/permission/allPermission/" + roleid).then(result => {
//console.log(result);
//查询所有的菜单
this.data = result.data.data.firstMenus;
//2.查询当前角色具有的菜单id.
var menuids = result.data.data.menuids;
setTimeout(() => {
menuids.forEach(value => {
var node = this.$refs.tree.getNode(value);//根据id 拿到 Tree 组件中的node的所有信息
if (node.isLeaf) {//node.isLeaf:判断当前节点是否为子节点
this.$refs.tree.setChecked(node, true);//如果是子节点,就把状态设置成选中
} else {
}
})
})
});
},
onSubmit() {
this.$http.post("/system/role/findRole/" + this.currentPage + "/" + this.pageSize, this.formRole).then(result => {
if (result.data.code === 2000) {
this.tableData = result.data.data.records;
this.total = result.data.data.total;
}
})
},
//删除
del(id) {
this.$http.get("/system/role/delete/" + id).then(result => {
if (result.data.code === 2000) {
this.$message.success(result.data.msg)
} else {
this.$message.error(result.data.msg)
}
this.onSubmit();
})
},
//重置添加角色表单
resetForm() {
this.addForm = {};
},
//单击新增角色
addRole() {
this.addDialogFormVisible = true;
},
//添加新增角色记录方法
addRecord() {
this.$http.post("/system/role/insert", this.addForm).then(result => {
if (result.data.code === 2000) {
this.$message({
showClose: true,
message: result.data.msg,
type: 'success'
});
}
this.addDialogFormVisible = false;//关闭会话框
this.onSubmit();//重新加载表格
this.addForm = {};
});
},
//修改方法
editRecord() {
this.$http.post("/system/role/update", this.editForm).then(result => {
if (result.data.code === 2000) {
this.$message({
showClose: true,
message: result.data.msg,
type: 'success'
});
}
this.editDialogFormVisible = false;//关闭会话框
this.onSubmit();//重新加载表格
});
},
//单击取消
editCancel() {
this.editDialogFormVisible = false;
},
//修改回显方法
edit(roleid) {
this.editDialogFormVisible = true;
this.$http.get("/system/role/echo/" + roleid).then(result => {
this.editForm = result.data.data;
});
},
}
}
</script>
<style scoped>
</style>
this.$router.go(0) 这里是刷新当前页面,包括父组件,这里是为了刷新权限的时候同时刷新父组件的左侧菜单
修改权限的service:
package com.wzh.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzh.system.entity.Permission;
import com.wzh.system.entity.RolePermission;
import com.wzh.system.entity.User;
import com.wzh.system.mapper.PermissionMapper;
import com.wzh.system.mapper.RolePermissionMapper;
import com.wzh.system.service.IPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzh.system.vo.CommonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 权限 服务实现类
* </p>
*
* @author 王振华
* @since 2022-08-09
*/
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {
@Autowired
private PermissionMapper permissionMapper;
@Autowired
private RolePermissionMapper rolePermissionMapper;
@Autowired
private RedisTemplate redisTemplate;
@Override
public CommonResult findPermissionByUserId(String token) {
//根据token获取用户信息
ValueOperations forValue = redisTemplate.opsForValue();
User user = (User) forValue.get(token);
//根据用户id查询该用户具有的权限。
List<Permission> permissionList = permissionMapper.selectByUserId(user.getId());
//设置层级关系
List<Permission> firstMenus = new ArrayList<>();
for (Permission firstMenu : permissionList){
if(firstMenu.getPid().equals("1")){
firstMenus.add(firstMenu);
}
}
List<Permission> collect = firstMenus.stream().sorted((p1, p2) -> {
return p1.getId().compareTo(p2.getId());
}).collect(Collectors.toList());
//为一级菜单设置二级菜单
for (Permission first : firstMenus){
//根据一级菜单id 查询 该菜单得二级菜单。如果出现不确定有几级菜单 那么我们可以使用方法得递归调用
first.setChildren(findChildren(permissionList, first.getId()));
}
return new CommonResult(2000,"查询成功",collect);
}
/**
* 查看所有权限
* @param id
* @return
*/
@Override
public CommonResult selectAllPermission(String id) {
//查询所有菜单
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("is_deleted",0);
List<Permission> permissionList = permissionMapper.selectList(wrapper);
//设置层级关系
List<Permission> firstMenus = new ArrayList<>();
for (Permission firstMenu : permissionList){
if(firstMenu.getPid().equals("1")){
firstMenus.add(firstMenu);
}
}
for(Permission first : firstMenus){
first.setChildren(findChildren(permissionList,first.getId()));
}
//查询当前角色具有的菜单id
QueryWrapper<RolePermission> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("role_id",id);
List<RolePermission> rolePermissions = rolePermissionMapper.selectList(queryWrapper);
List<String> menuids = rolePermissions.stream().map(item -> item.getPermissionId()).distinct().collect(Collectors.toList());
Map<String,Object> map = new HashMap<>();
map.put("firstMenus",firstMenus);
map.put("menuids",menuids);
return new CommonResult(2000,"查询成功",map);
}
//方法递归
private List<Permission> findChildren(List<Permission> permissionList, String pid) {
List<Permission> children = new ArrayList<>();
for (Permission p : permissionList){
if(p.getPid().equals(pid)){
children.add(p);
}
}
for(Permission child : children){
child.setChildren(findChildren(permissionList,child.getId()));
}
return children;
}
}
确认修改权限:
package com.wzh.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzh.system.entity.RolePermission;
import com.wzh.system.mapper.RolePermissionMapper;
import com.wzh.system.service.IRolePermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzh.system.vo.CommonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 角色权限 服务实现类
* </p>
*
* @author 王振华
* @since 2022-08-10
*/
@Service
public class RolePermissionServiceImpl extends ServiceImpl<RolePermissionMapper, RolePermission> implements IRolePermissionService {
@Autowired
private RolePermissionMapper rolePermissionMapper;
@Override
@Transactional
public CommonResult updatePermission(String roleid, String[] menuids) {
//删除roleid具有的权限
QueryWrapper<RolePermission> wrapper = new QueryWrapper<>();
wrapper.eq("role_id",roleid);
int delete = rolePermissionMapper.delete(wrapper);
//添加roleid具有的权限 动态sql
List<RolePermission> list = Arrays.stream(menuids).map(item -> new RolePermission(null, roleid, item, null, null, null)).collect(Collectors.toList());
/*if(menuids.length!=0) {
List<RolePermission> list = new ArrayList<>();
for(String s : menuids){
RolePermission rolePermission = new RolePermission();
rolePermission.setRoleId(roleid);
rolePermission.setPermissionId(s);
list.add(rolePermission);
}
}*/
boolean b = this.saveBatch(list);
return new CommonResult(2000,"分配成功",null);
}
}