1、完成图标功能
要实现图标功能,首先是后端建表
- 建dict表
DROP TABLE IF EXISTS `dict`;
CREATE TABLE `dict` (
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`value` varchar(255) DEFAULT NULL COMMENT '内容',
`type` varchar(255) DEFAULT NULL COMMENT '类型'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `dict`(`name`,`value`,`type`) values
('user','el-icon-user','icon'),
('house','el-icon-house','icon'),
('menu','el-icon-menu','icon'),
('s-custom','el-icon-s-custom','icon'),
('s-menu','el-icon-s-grid','icon'),
('file','el-icon-document','icon');
- Dict实体类
Dict.java
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("dict")
public class Dict {
private String name;
private String value;
private String type;
}
- DictMapper.java
@Repository
public interface DictMapper extends BaseMapper<Dict> {
}
- DictService.java
@Service
public class DictService extends ServiceImpl<DictMapper, Dict> {
}
- 图标功能是在菜单管理里面显示,所以实现功能写在MenuController中
MenuController.java
//查找图标信息
@GetMapping("/icons")
public Result getIcons(){
QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
//查询type为icon的数据
queryWrapper.eq("type", Constants.DICT_TYPE_ICON);
return Result.success(dictService.list(queryWrapper));
}
- 前端实现菜单管理里编辑,可以下拉选择图标,如
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GJscqE2B-1673355144545)(D:\桌面\Java学习\项目\管理系统–前后端分离\项目截图\46.jpg)]
- 前端实现角色管理页面,分配菜单的时候,同样显示图标出来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XbCYwnVm-1673355144546)(D:\桌面\Java学习\项目\管理系统–前后端分离\项目截图\47.jpg)]
<span class="custom-tree-node" slot-scope="{data}">
<span><i :class="data.icon"></i> {
{ data.name }}</span>
</span>
- 完整代码
Menu.vue
<template>
<div>
<div style="padding:10px 0">
<el-input style="width:200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin:10px 0">
<el-button type="primary" @click="handleAdd()">新增<i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除这些内容吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</div>
<el-table :data="tableData" border stripe :header-cell-calss-name="'headerBg'"
row-key="id" default-expand-all @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="name" label="名称" ></el-table-column>
<el-table-column prop="path" label="路径" ></el-table-column>
<el-table-column label="图标" class-name="fontSize18" align="center" label-class-name="fontSize12" >
<template slot-scope="scope">
<i :class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="description" label="描述" ></el-table-column>
<el-table-column label="操作" width="300" align="center">
<template slot-scope="scope" >
<!--没有路径(说明有子菜单)和没有父级(说明会有子菜单)才加新增子菜单的按钮 -->
<el-button type="primary" @click="handleMenuAdd(scope.row.id)" v-if="!scope.row.pid && !scope.row.path">新增子菜单 <i class="el-icon-plus"></i></el-button>
<el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" slot="reference">删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-dialog title="菜单信息" :visible.sync="dialogFormVisible" width="30%">
<el-form label-width="80px" size="small">
<el-form-item label="名称" >
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="路径" >
<el-input v-model="form.path" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标" >
<el-select clearable v-model="form.icon" placeholder="请选择" style="width:100%">
<el-option v-for="item in options" :key="item.name" :label="item.name" :value="item.value">
<i :class="item.value"/> {
{ item.name }}
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" >
<el-input v-model="form.description" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default{
name:"User",
data() {
return {
tableData:[],
total: 0 ,
pageNum:1,
pageSize:4,
name:"",
form:{},
dialogFormVisible:false,
multipleSelection:[],
options:[]
}
},
created(){
this.load()
},
methods:{
load(){
this.request.get("/menu",{
params:{
name:this.name
}
}).then(res=>{
this.tableData=res.data
})
},
save(){
this.request.post("/menu",this.form).then(res=>{
if(res.data){
this.$message.success("保存成功!")
this.dialogFormVisible=false
this.load()
}else{
this.$message.error("保存失败!")
}
})
},
handleAdd(){
this.dialogFormVisible=true
this.form={}
},
handleMenuAdd(pid){
this.dialogFormVisible=true
this.form={}
if(pid){
this.form.pid=pid
}
},
handleUpdate(row){
this.form= JSON.parse(JSON.stringify(row))
this.dialogFormVisible=true
//请求图标的数据
this.request.get("/menu/icons").then(res => {
this.options=res.data
})
},
handleDelete(id){
this.request.delete("/menu/" + id).then(res=>{
if(res.data){
this.$message.success("删除成功!")
this.load()
}else{
this.$message.error("删除失败!")
}
})
},
delBatch(){
let ids=this.multipleSelection.map(v => v.id) //把对象数组转化为id数组【1,2,3】
this.request.post("/menu/del/batch",ids).then(res=>{
if(res.data){
this.$message.success("批量删除成功!")
this.load()
}else{
this.$message.error("批量删除失败!")
}
})
},
handleSelectionChange(val){
this.multipleSelection=val
},
reset(){
this.name=""
this.load()
},
handleSizeChange(pageSize){
this.pageSize=pageSize
this.load()
},
handleCurrentChange(pageNum){
this.pageNum=pageNum
this.load()
}
}
}
</script>
<style>
.headerBg{
background: #eee!important;
}
.fontSize18{
font-size: 20px;
}
.fontSize12{
font-size: 12px;
}
</style>
Role.vue
<template>
<div>
<div style="padding:10px 0">
<el-input style="width:200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin:10px 0">
<el-button type="primary" @click="handleAdd">新增<i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除这些内容吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</div>
<el-table :data="tableData" border stripe :header-cell-calss-name="'headerBg'" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="name" label="名称" ></el-table-column>
<el-table-column prop="description" label="描述" ></el-table-column>
<el-table-column label="操作" width="280" align="center">
<template slot-scope="scope" >
<el-button type="info" @click="selectMenu(scope.row.id)">分配菜单<i class="el-icon-menu"></i></el-button>
<el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" slot="reference">删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding:10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[2, 4, 6, 10]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<el-dialog title="角色信息" :visible.sync="dialogFormVisible" width="30%">
<el-form label-width="80px" size="small">
<el-form-item label="名称" >
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="描述" >
<el-input v-model="form.description" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="分配菜单" :visible.sync="menuDialogVisable" width="30%">
<el-tree
:props="props"
:data="menuData"
show-checkbox
node-key="id"
ref="tree"
:default-expanded-keys="expands"
:default-checked-keys="checks">
<span class="custom-tree-node" slot-scope="{data}">
<span><i :class="data.icon"></i> {
{ data.name }}</span>
</span>
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button @click="menuDialogVisable = false">取 消</el-button>
<el-button type="primary" @click="saveRoleMenu">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { Tree } from 'element-ui'
export default{
name:"User",
data() {
return {
tableData:[],
total: 0 ,
pageNum:1,
pageSize:4,
name:"",
form:{},
dialogFormVisible:false,
menuDialogVisable:false,
multipleSelection:[],
menuData: [],
props:{
label:'name'
},
expands:[],
checks:[],
roleId:0
}
},
created(){
this.load()
},
methods:{
load(){
this.request.get("/role/page",{
params:{
pageNum:this.pageNum,
pageSize:this.pageSize,
name:this.name
}
}).then(res=>{
console.log(res)
this.tableData=res.data.records
this.total=res.data.total
})
},
save(){
this.request.post("/role",this.form).then(res=>{
if(res.data){
this.$message.success("保存成功!")
this.dialogFormVisible=false
this.load()
}else{
this.$message.error("保存失败!")
}
})
},
saveRoleMenu(){
this.request.post("/role/roleMenu/" + this.roleId,this.$refs.tree.getCheckedKeys()).then(res => {
if(res.code === '200') {
this.$message.success("绑定成功")
this.menuDialogVisable = false
}else{
this.$message.error(res.msg)
}
})
},
handleAdd(){
this.dialogFormVisible=true
this.form={}
},
handleUpdate(row){
this.form={...row}
this.dialogFormVisible=true
},
handleDelete(id){
this.request.delete("/role/" + id).then(res=>{
if(res.data){
this.$message.success("删除成功!")
this.load()
}else{
this.$message.error("删除失败!")
}
})
},
delBatch(){
let ids=this.multipleSelection.map(v => v.id) //把对象数组转化为id数组【1,2,3】
this.request.post("/role/del/batch",ids).then(res=>{
if(res.data){
this.$message.success("批量删除成功!")
this.load()
}else{
this.$message.error("批量删除失败!")
}
})
},
handleSelectionChange(val){
this.multipleSelection=val
},
reset(){
this.name=""
this.load()
},
handleSizeChange(pageSize){
this.pageSize=pageSize
this.load()
},
handleCurrentChange(pageNum){
this.pageNum=pageNum
this.load()
},
selectMenu(roleId){
this.menuDialogVisable=true;
this.roleId=roleId
//请求menu数据
this.request.get("/menu").then(res=>{
this.menuData=res.data
//把后台返回的菜单数据处理成 id数组
this.expands = this.menuData.map(v=>v.id)
})
this.request.get("/role/roleMenu/" + roleId).then(res => {
this.checks = res.data
})
}
}
}
</script>
<style>
.headerBg{
background: #eee!important;
}
</style>
2、实现菜单管理和角色管理关系
实现:角色管理中,分配菜单后,会出现一个role_id对应一个或者多个menu_id ,两者id之间的关系可以储存到数据库中,然后下次点开该角色的分配菜单时默认回显出来
- 建表Role_Menu表
USE `management`;
/*Table structure for table `role_menu` */
DROP TABLE IF EXISTS `role_menu`;
CREATE TABLE `role_menu` (
`role_id` int(11) NOT NULL COMMENT '角色id',
`menu_id` int(11) NOT NULL COMMENT '菜单id',
PRIMARY KEY (`role_id`,`menu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色菜单关系表';
- 注意,roleId和menuId都应该设置为主键
- 实体类RoleMenu.java
@Data
@TableName("role_menu")
public class RoleMenu {
private Integer roleId;
private Integer menuId;
}
和之前一样,把RoleMenuMapper和RoleMenuService建好,这里就省略
- 实现功能:不需要新建一个controller,因为这也算是role中的功能。
RoleController.java
//绑定角色和菜单的关系。一个角色id可以对应多个菜单id(一个角色可以有权限管理多个菜单)
//参数: roleId ,menuIds
@PostMapping("/roleMenu/{roleId}")
public Result roleMenu(@PathVariable Integer roleId, @RequestBody List<Integer> menuIds){
//复杂的sql操作,需要去service层写业务
roleService.setRoleMenu(roleId,menuIds);
return Result.success();
}
//从数据库中根据roleId查询出与这个角色关联的menuId
@GetMapping("/roleMenu/{roleId}")
public Result getRoleMenu(@PathVariable Integer roleId){
return Result.success(roleService.getRoleMenu(roleId));
}
- 在service层中实现业务
RoleService.java
@Service
public class RoleService extends ServiceImpl<RoleMapper, Role> {
@Autowired
private RoleMenuService roleMenuService;
@Autowired
private RoleMenuMapper roleMenuMapper;
//加上事务注解,两个操作同时成功才行
@Transactional
public void setRoleMenu(Integer roleId, List<Integer> menuIds) {
QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
//先删除当前角色id所有的绑定关系
queryWrapper.eq("role_id",roleId);
roleMenuService.remove(queryWrapper);
//再把前端传过来的菜单id数组绑定到当前这个角色id上去
for (Integer menuId:menuIds){
RoleMenu roleMenu = new RoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
roleMenuService.save(roleMenu);
}
}
//查询
public List<Integer> getRoleMenu(Integer roleId) {
return roleMenuMapper.selectByRoleId(roleId);
}
}
- RoleMenuMapper.java
@Repository
public interface RoleMenuMapper extends BaseMapper<RoleMenu> {
@Select("select menu_id from role_menu where role_id = #{roleId}")
List<Integer> selectByRoleId(@Param("roleId") Integer roleId);
}
- 在前端中实现
- 将前端勾选后的数据传给后端存入数据库
saveRoleMenu(){
this.request.post("/role/roleMenu/" + this.roleId,this.$refs.tree.getCheckedKeys()).then(res => {
if(res.code === '200') {
this.$message.success("绑定成功")
this.menuDialogVisable = false
}else{
this.$message.error(res.msg)
}
})
},
- 请求后端查询出存储的关系然后回显到前端(就是在再一次打开该角色的分配菜单时,要默认显示出之前已经勾选的)
this.request.get("/role/roleMenu/" + roleId).then(res => {
this.checks = res.data
})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YXBNwzKL-1673355144547)(D:\桌面\Java学习\项目\管理系统–前后端分离\项目截图\48.jpg)]
这次改动的前端代码就是Role.vue和Menu.vue两个页面,完整代码在前面已经给出了!
通过实现,完成这两个功能,就成功了!
今天的文章18—实现权限菜单管理(三)分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/64496.html