菜单管理实现

在这里插入图片描述

菜单列表(menu.html)

<!DOCTYPE html>
<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<meta charset="utf-8">
<head th:include="include :: header"></head>
<body class="gray-bg">
	<div class="wrapper wrapper-content ">
		<div class="col-sm-12">
			<div class="ibox">
				<div class="ibox-body">
					<div id="exampleToolbar" role="group" class="t-bar">
						<button shiro:hasPermission="sys:menu:add" type="button"
							class="btn btn-primary" title="在根节点下添加菜单" onclick="add('0')">
							<i class="fa fa-plus" aria-hidden="true"></i>添加
						</button>
						<button shiro:hasPermission="sys:menu:batchRemove" type="button"
							class="btn btn-danger" onclick="batchRemove()">
							<i class="fa fa-trash" aria-hidden="true"></i>删除
						</button>
					</div>
					<table id="exampleTable" data-mobile-responsive="true">
					</table>
				</div>
			</div>
		</div>
		<!--shiro控制bootstraptable行内按钮可见性 来自StudentBoot的创新方案 -->
		<div>
			<script type="text/javascript">
				var s_add_h = 'hidden';
				var s_edit_h = 'hidden';
				var s_remove_h = 'hidden';
			</script>
		</div>
		<div shiro:hasPermission="sys:menu:add">
			<script type="text/javascript">
				s_add_h = '';
			</script>
		</div>
		<div shiro:hasPermission="sys:menu:edit">
			<script type="text/javascript">
				s_edit_h = '';
			</script>
		</div>
		<div shiro:hasPermission="sys:menu:remove">
			<script type="text/javascript">
				var s_remove_h = '';
			</script>
		</div>
	</div>
	<div th:include="include::footer"></div>
	<script src="/app/sys/menu/menu.js"></script>
</body>

</html>

菜单列表(menu.js)

var prefix = "/sys/menu"
$(document).ready(function () {
    load();
});
var load = function () {
    $('#exampleTable')
        .bootstrapTable(
            {
                idField: 'menuId',
                code: 'menuId',
                method: "GET", // 请求数据的ajax类型
                url: prefix + '/list', // 请求数据的ajax的url
                queryParams: {sort:'order_num'}, // 请求数据的ajax的data属性
                striped: true, // 是否各行渐变色
                //cache: false,
                toolbar : '#exampleToolbar',
                showColumns: true,                  //是否显示所有的列(选择显示的列)
                showRefresh: true,                  //是否显示刷新按钮
                //clickToSelect: true,                //是否启用点击选中行
                columns: [
                    {
                        field: 'ck',
                        checkbox: true
                    },
                    {
                        title: '编号',
                        field: 'menuId',
                        visible: false,
                        align: 'center',
                        valign: 'center',
                    },
                    {
                        title: '名称',
                        valign: 'center',
                        field: 'name',
                    },

                    {
                        title: '图标',
                        field: 'icon',
                        align: 'center',
                        valign: 'center',
                        width : '5%',
                        formatter: function (value, row, index) {
                            return value == null ? ''
                                : '<i class="' + value
                                + ' fa-lg"></i>';
                        }
                    },
                    {
                        title: '类型',
                        field: 'type',
                        align: 'center',
                        valign: 'center',
                        formatter: function (value, row, index) {
                            if (value === 0) {
                                return '<span class="label label-primary">目录</span>';
                            }
                            if (value === 1) {
                                return '<span class="label label-success">菜单</span>';
                            }
                            if (value === 2) {
                                return '<span class="label label-warning">按钮</span>';
                            }
                        }
                    },
                    {
                        title: '地址',
                        valign: 'center',
                        field: 'url'
                    },
                    {
                        title: '序号',
                        valign: 'center',
                        field: 'orderNum'
                    },
                    {
                        title: '权限标识',
                        valign: 'center',
                        field: 'perms'
                    },
                    {
                        title: '操作',
                        field: 'id',
                        align: 'center',
                        valign: 'center',
                        formatter: function (value, row, index) {
                            var e = '<a class="btn btn-primary btn-sm '
                                + s_edit_h
                                + '" href="#" mce_href="#" title="编辑" οnclick="edit(\''
                                + row.menuId
                                + '\')"><i class="fa fa-edit"></i></a> ';
                            var p = '<a class="btn btn-primary btn-sm '
                                + s_add_h
                                + '" href="#" mce_href="#" title="添加下级" οnclick="add(\''
                                + row.menuId
                                + '\')"><i class="fa fa-plus"></i></a> ';
                            var d = '<a class="btn btn-warning btn-sm '
                                + s_remove_h
                                + '" href="#" title="删除"  mce_href="#" οnclick="remove(\''
                                + row.menuId
                                + '\')"><i class="fa fa-remove"></i></a> ';
                            return e + d + p;
                        }
                    }],
                treeShowField: 'name',
                parentIdField: 'parentId',
                onPostBody: function() {
                    $('#exampleTable').treegrid({
                        initialState: 'collapsed',//收缩
                        treeColumn: 1,//指明第几列数据改为树形
                        expanderExpandedClass: 'glyphicon glyphicon-triangle-bottom',
                        expanderCollapsedClass: 'glyphicon glyphicon-triangle-right',
                        onChange: function() {
                            $('#exampleTable').bootstrapTable('resetWidth');
                        }
                    })
                }
            });
}

function refresh() {
    $("#exampleTable").bootstrapTable("refresh");
}

function add(pId) {
    layer.open({
        type: 2,
        title: '增加菜单',
        maxmin: true,
        shadeClose: false, // 点击遮罩关闭层
        area: ['800px', '520px'],
        content: prefix + '/add/' + pId // iframe的url
    });
}

function remove(id) {
    layer.confirm('确定要删除选中的记录?', {
        btn: ['确定', '取消']
    }, function () {
        $.ajax({
            url: prefix + "/remove",
            type: "post",
            data: {
                'id': id
            },
            success: function (data) {
                if (data.code == 0) {
                    layer.msg("删除成功");
                    refresh();
                } else {
                    layer.msg(data.msg);
                }
            }
        });
    })
}

function edit(id) {
    layer.open({
        type: 2,
        title: '菜单修改',
        maxmin: true,
        shadeClose: false, // 点击遮罩关闭层
        area: ['800px', '520px'],
        content: prefix + '/edit/' + id // iframe的url
    });
}

function batchRemove() {
    // var rows = $('#exampleTable').bootstrapTable('getSelections');

}

菜单添加(add.html)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<meta charset="utf-8">
<head th:include="include :: header"></head>
<body class="gray-bg">
	<div class="wrapper wrapper-content">
		<div class="row">
			<div class="col-sm-12">
				<div class="ibox float-e-margins">
					<div class="ibox-content">
						<form class="form-horizontal m-t" id="signupForm">
							<input id="parentId" name="parentId" type="hidden"
								th:value="${pId}">
							<div class="form-group">
								<label class="col-sm-3 control-label">上级菜单:</label>
								<div class="col-sm-8">
									<input id="" name="" class="form-control" type="text"
										th:value="${pName}" readonly>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">菜单类型:</label>
								<div class="col-sm-8">
									<label class="radio-inline"> <input type="radio"
										name="type" value="0" /> 目录
									</label> <label class="radio-inline"> <input type="radio"
										name="type" value="1" /> 菜单
									</label> <label class="radio-inline"> <input type="radio"
										name="type" value="2" /> 按钮
									</label>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">菜单名称:</label>
								<div class="col-sm-8">
									<input id="name" name="name" class="form-control" type="text">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">链接地址:</label>
								<div class="col-sm-8">
									<input id="url" name="url" class="form-control" type="text">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">权限标识:</label>
								<div class="col-sm-8">
									<input id="perms" name="perms" class="form-control" type="text">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">排序号:</label>
								<div class="col-sm-8">
									<input id="orderNum" name="orderNum" class="form-control"
										type="text">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">图标:</label>
								<div class="col-sm-6">
									<input id="icon" name="icon" class="form-control" type="text"
										placeholder="例如:fa fa-circle-o">
								</div>
								<input id="ico-btn" class="btn btn-warning" type="button" value="选择图标">
							</div>


							<div class="form-group">
								<div class="col-sm-8 col-sm-offset-3">
									<button type="submit" class="btn btn-primary">提交</button>
								</div>
							</div>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div th:include="include::footer"></div>
	<script src="/app/sys/menu/add.js"></script>
</body>

</html>

菜单添加(add.js)

var prefix = "/sys/menu"
$(function() {
	validateRule();
	//打开图标列表
    $("#ico-btn").click(function(){
        layer.open({
            type: 2,
			title:'图标列表',
            content: '/FontIcoList.html',
            area: ['480px', '90%'],
            success: function(layero, index){
                //var body = layer.getChildFrame('.ico-list', index);
                //console.log(layero, index);
            }
        });
    });
});
$.validator.setDefaults({
	submitHandler : function() {
		save();
	}
});
function save() {
	$.ajax({
		cache : true,
		type : "POST",
		url : prefix + "/save",
		data : $('#signupForm').serialize(),
		async : false,
		error : function(request) {
			layer.alert("Connection error");
		},
		success : function(data) {
			if (data.code == 0) {
				parent.layer.msg("保存成功");
				parent.refresh();
				var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引
				parent.layer.close(index);

			} else {
				layer.alert(data.msg)
			}
		}
	});
}

function validateRule() {
	var icon = "<i class='fa fa-times-circle'></i> ";
	$("#signupForm").validate({
		rules : {
			name : {
				required : true
			},
			type : {
				required : true
			}
		},
		messages : {
			name : {
				required : icon + "请输入菜单名"
			},
			type : {
				required : icon + "请选择菜单类型"
			}
		}
	})
}

菜单编辑(edit.html)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">


<title></title>
<meta name="keywords" content="">
<meta name="description" content="">
<link rel="shortcut icon" href="favicon.ico">
<link href="/bootstrap/bootstrap.css" rel="stylesheet">
<link href="/font-awesome/font-awesome.css" rel="stylesheet">
<link href="/animate/animate.css" rel="stylesheet">
<link href="/app/style.css" rel="stylesheet">
</head>
<body class="gray-bg">
	<div class="wrapper wrapper-content">
		<div class="row">
			<div class="col-sm-12">
				<div class="ibox float-e-margins">
					<div class="ibox-content">
						<form class="form-horizontal m-t" id="signupForm">
							<input id="parentId" name="parentId" type="hidden"
								th:value="${pId}" /> <input id="menuId" name="menuId"
								type="hidden" th:value="${menu.menuId}" />
							<div class="form-group">
								<label class="col-sm-3 control-label">上级菜单:</label>
								<div class="col-sm-8">
									<input id="" name="" class="form-control" type="text"
										th:value="${pName}" readonly>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">菜单类型:</label>
								<div class="col-sm-8">
									<label class="radio-inline"> <input type="radio"
										th:field="*{menu.type}" name="type" value="0" /> 目录
									</label> <label class="radio-inline"> <input type="radio"
										th:field="*{menu.type}" name="type" value="1" /> 菜单
									</label> <label class="radio-inline"> <input type="radio"
										th:field="*{menu.type}" name="type" value="2" /> 按钮
									</label>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">菜单名称:</label>
								<div class="col-sm-8">
									<input id="name" name="name" class="form-control" type="text"
										th:value="${menu.name}" required>
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">链接地址:</label>
								<div class="col-sm-8">
									<input id="url" name="url" class="form-control" type="text"
										th:value="${menu.url}">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">权限标识:</label>
								<div class="col-sm-8">
									<input id="perms" name="perms" class="form-control" type="text"
										th:value="${menu.perms}">
								</div>
							</div>
								<div class="form-group">
								<label class="col-sm-3 control-label">排序号:</label>
								<div class="col-sm-8">
									<input id="orderNum" name="orderNum" class="form-control"
										type="text" th:value="${menu.orderNum}">
								</div>
							</div>
							<div class="form-group">
								<label class="col-sm-3 control-label">图标:</label>
								<div class="col-sm-5">
									<input id="icon" name="icon" class="form-control" type="text"
										placeholder="例如:fa fa-circle-o" th:value="${menu.icon}">
								</div>
								<input id="ico-btn" class="btn btn-warning" type="button" value="选择图标">
							</div>
							<div class="form-group">
								<div class="col-sm-8 col-sm-offset-3">
									<button type="submit" class="btn btn-info">提交</button>
								</div>
							</div>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div th:include="include::footer"></div>
	<script src="/app/sys/menu/edit.js"></script>
</body>

</html>

菜单编辑(edit.js)

var prefix = "/sys/menu"
$(function() {
	validateRule();

	//打开图标列表
    $("#ico-btn").click(function(){
        layer.open({
            type: 2,
			title:'图标列表',
            content: '/FontIcoList.html',
            area: ['480px', '90%'],
            success: function(layero, index){
                //var body = layer.getChildFrame('.ico-list', index);
                //console.log(layero, index);
            }
        });
    });

});
$.validator.setDefaults({
	submitHandler : function() {
		update();
	}
});
function update() {
	$.ajax({
		cache : true,
		type : "POST",
		url : prefix + "/update",
		data : $('#signupForm').serialize(),// 你的formid
		async : false,
		error : function(request) {
			layer.alert("Connection error");
		},
		success : function(data) {
			if (data.code == 0) {
				parent.layer.msg("保存成功");
				parent.refresh();
				var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引
				parent.layer.close(index);

			} else {
				layer.alert(data.msg)
			}

		}
	});

}
function validate() {
	var icon = "<i class='fa fa-times-circle'></i> ";
	$("#signupForm").validate({
		rules : {
			name : {
				required : true
			},
			type : {
				required : true
			}
		},
		messages : {
			name : {
				required : icon + "请输入菜单名"
			},
			type : {
				required : icon + "请选择菜单类型"
			}
		}
	})
}
function validateRule() {
	var icon = "<i class='fa fa-times-circle'></i> ";
	$("#signupForm").validate({
		rules : {
			name : {
				required : true
			},
			type : {
				required : true
			}
		},
		messages : {
			name : {
				required : icon + "请输入菜单名"
			},
			type : {
				required : icon + "请选择菜单类型"
			}
		}
	})
}

菜单管理接口(Java)

package com.yangzc.studentboot.system.controller;

import com.yangzc.studentboot.common.config.Constant;
import com.yangzc.studentboot.common.controller.BaseController;
import com.yangzc.studentboot.common.domain.Tree;
import com.yangzc.studentboot.common.utils.R;
import com.yangzc.studentboot.system.domain.MenuDO;
import com.yangzc.studentboot.system.service.MenuService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * @author yangzc 876295854@qq.com
 */
@RequestMapping("/sys/menu")
@Controller
public class MenuController extends BaseController {
	String prefix = "/menu";
	@Autowired
	MenuService menuService;

	@RequiresPermissions("sys:menu:menu")
	@GetMapping()
	String menu(Model model) {
		return prefix+"/menu";
	}

	@RequiresPermissions("sys:menu:menu")
	@RequestMapping("/list")
	@ResponseBody
	List<MenuDO> list(@RequestParam Map<String, Object> params) {
		List<MenuDO> menus = menuService.list(params);
		return menus;
	}

	@RequiresPermissions("sys:menu:add")
	@GetMapping("/add/{pId}")
	String add(Model model, @PathVariable("pId") Long pId) {
		model.addAttribute("pId", pId);
		if (pId == 0) {
			model.addAttribute("pName", "根目录");
		} else {
			model.addAttribute("pName", menuService.get(pId).getName());
		}
		return prefix + "/add";
	}

	@RequiresPermissions("sys:menu:edit")
	@GetMapping("/edit/{id}")
	String edit(Model model, @PathVariable("id") Long id) {
		MenuDO mdo = menuService.get(id);
		Long pId = mdo.getParentId();
		model.addAttribute("pId", pId);
		if (pId == 0) {
			model.addAttribute("pName", "根目录");
		} else {
			model.addAttribute("pName", menuService.get(pId).getName());
		}
		model.addAttribute("menu", mdo);
		return prefix+"/edit";
	}

	@RequiresPermissions("sys:menu:add")
	@PostMapping("/save")
	@ResponseBody
	R save(MenuDO menu) {
		if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
			return R.error(1, "演示系统不允许修改,完整体验请部署程序");
		}
		if (menuService.save(menu) > 0) {
			return R.ok();
		} else {
			return R.error(1, "保存失败");
		}
	}

	@RequiresPermissions("sys:menu:edit")
	@PostMapping("/update")
	@ResponseBody
	R update(MenuDO menu) {
		if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
			return R.error(1, "演示系统不允许修改,完整体验请部署程序");
		}
		if (menuService.update(menu) > 0) {
			return R.ok();
		} else {
			return R.error(1, "更新失败");
		}
	}

	@RequiresPermissions("sys:menu:remove")
	@PostMapping("/remove")
	@ResponseBody
	R remove(Long id) {
		if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
			return R.error(1, "演示系统不允许修改,完整体验请部署程序");
		}
		if (menuService.remove(id) > 0) {
			return R.ok();
		} else {
			return R.error(1, "删除失败");
		}
	}

	@GetMapping("/tree")
	@ResponseBody
	Tree<MenuDO> tree() {
		Tree<MenuDO>  tree = menuService.getTree();
		return tree;
	}

	@GetMapping("/tree/{roleId}")
	@ResponseBody
	Tree<MenuDO> tree(@PathVariable("roleId") Long roleId) {
		Tree<MenuDO> tree = menuService.getTree(roleId);
		return tree;
	}
}

github项目地址

https://github.com/yangzc23/studentboot

参考资料

[01] 弹层组件文档 - layui.layer
[02] bootstrap-table-examples
[03] 简单知识点实例之四:BootstrapTable新型树表格
[04] RuoYi开发文档
[05] RuoYi: 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观

微信扫一扫关注公众号
image.png
点击链接加入群聊

https://jq.qq.com/?_wv=1027&k=5eVEhfN
软件测试学习交流QQ群号:511619105

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现菜单管理布局,可以使用 Vue.js 和 Element UI 库。以下是一个简单的布局示例: ```html <template> <div class="container"> <div class="sidebar"> <el-menu :default-active="activeIndex" class="el-menu-vertical-demo" :collapse="isCollapse" @select="handleMenuSelect" > <el-menu-item index="1"> <i class="el-icon-s-home"></i> <span slot="title">首页</span> </el-menu-item> <el-submenu index="2"> <template slot="title"> <i class="el-icon-s-grid"></i> <span>菜单管理</span> </template> <el-menu-item index="2-1">菜单列表</el-menu-item> <el-menu-item index="2-2">添加菜单</el-menu-item> </el-submenu> <el-menu-item index="3"> <i class="el-icon-s-order"></i> <span slot="title">订单管理</span> </el-menu-item> <el-menu-item index="4"> <i class="el-icon-s-custom"></i> <span slot="title">客户管理</span> </el-menu-item> </el-menu> </div> <div class="main"> <el-button class="collapse-btn" @click="toggleCollapse"> <i :class="collapseIcon"></i> </el-button> <el-breadcrumb separator="/"> <el-breadcrumb-item>首页</el-breadcrumb-item> <el-breadcrumb-item>菜单管理</el-breadcrumb-item> <el-breadcrumb-item>菜单列表</el-breadcrumb-item> </el-breadcrumb> <div class="content"> <router-view /> </div> </div> </div> </template> <script> export default { data() { return { activeIndex: '1', isCollapse: false, }; }, methods: { handleMenuSelect(index) { this.activeIndex = index; }, toggleCollapse() { this.isCollapse = !this.isCollapse; }, }, computed: { collapseIcon() { return this.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'; }, }, }; </script> <style scoped> .container { display: flex; height: 100%; } .sidebar { width: 200px; background-color: #f0f2f5; padding: 20px; } .main { flex: 1; padding: 20px; background-color: #fff; position: relative; } .collapse-btn { position: absolute; top: 20px; right: 20px; } .content { margin-top: 20px; } </style> ``` 在这个示例中,我们使用了 `el-menu` 组件来创建菜单,使用 `el-breadcrumb` 组件来显示面包屑导航,使用 `router-view` 组件来显示子组件。我们还添加了一个按钮来切换侧边栏的展开和折叠状态。 你可以根据实际需求修改布局和菜单项。这个示例只是一个简单的开始,你可以添加更多的功能来满足你的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值