基于easyUI实现权限管理系统(三)——角色管理
此文章是基于 EasyUI+Knockout实现经典表单的查看、编辑
一. 相关文件介绍
1. role.jsp:角色管理界面
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>角色管理</title> <%@ include file="/common/head.jsp"%> </head> <body> <div class="toolbar"> <a href="#" plain="true" class="easyui-linkbutton" icon="icon-arrow_refresh" title="刷新" data-bind="click:refreshClick">刷新</a> <a href="#" plain="true" class="easyui-linkbutton" icon="icon-add" title="新增" data-bind="click:addClick">新增</a> <a href="#" plain="true" class="easyui-linkbutton" icon="icon-edit" data-bind="click:editClick" title="编辑">编辑</a> <a href="#" plain="true" class="easyui-linkbutton" icon="icon-cross" title="删除" data-bind="click:deleteClick">删除</a> <a href="#" plain="true" class="easyui-linkbutton" icon="icon-save" data-bind="click:saveClick" title="保存">保存</a> </div> <table id="gridlist" data-bind="datagrid:grid"> <thead> <tr> <th field="id" hidden="true"></th> <th field="roleName" align="left" width="150" editor="{type:'validatebox',options:{required: true }}">角色名称</th> <th field="roleSeq" align="left" width="100" editor="text" >排序 </th> <th field="description" align="left" width="200" editor="text">描述 </th> <th field="permit" align="center" width="200" formatter="formatterPermit">操作 </th> </tr> </thead> </table> <script type="text/html" id="permission-template"> <div class="container" style="margin:5px;height:525px;"> <div> <span class="icon32 icon-group32" style="padding-left:48px;font-weight:bold; font-size:14px;color:#666;" data-bind="text:role.roleName">角色名称</span> <span data-bind="text:role.description" style="margin-left:10px;"></span> </div> <div class="easyui-tabs" data-bind="easyuiTabs:tab"> <div title="菜单权限" > <table id="gridlist" data-bind="treegrid:grid"> <thead> <tr> <th field="chk" checkbox="true"></th> <th field="menuName" align="left" width="150">菜单 </th> <!-- <th field="id" align="left" width="80" >编码 </th> --> <th field="description" align="left" width="200" >备注说明 </th> </tr> </thead> </table> </div> <div title="按钮权限"> <table data-bind="treegrid:grid2"></table> </div> </div> </div> <div style="text-align:center;clear:both"> <a class="easyui-linkbutton" data-options="iconCls:'icon-ok'" data-bind="click:confirmClick" href="javascript:void(0)" >确定</a> <a class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" data-bind="click:cancelClick" href="javascript:void(0)">取消</a> </div> </script> <script type="text/html" id="members-template"> <div style="margin:5px;"> <div style="border-bottom:1px solid #CCC; margin-bottom:5px;"> <span id="role_name" class="icon32 icon-group32" style="padding-left:48px;font-weight:bold; font-size:14px;color:#666;" data-bind="text:roleName">角色名称</span> </div> <div style="margin-bottom:10px;height:20px;"> <label>描述:</label><input data-bind="value:description" type="text" readonly=true class="z-txt" style="width:430px;color:#666;vertical-align:middle"> </div> <div> 成员:</div> <select id="user_groups" data-bind="options:members,optionsText:memberText ,value:selectValue" size="10" style="width:475px; line-height:30px;height:195px;padding:5px"></select> <div style="margin-top:2px;"> <a href="#" class="easyui-linkbutton" id="group_add" plain="true" iconCls="icon-group-add" data-bind="click:addClick">添加</a> <a href="#" class="easyui-linkbutton" id="group_delete" plain="true" iconcls="icon-group-delete" data-bind="click:deleteClick">删除</a> <a href="#" class="easyui-linkbutton" id="group_clear" plain="true" iconCls="icon-clear" data-bind="click:clearClick">清空</a> </div> </div> <div style="text-align:center;"> <a class="easyui-linkbutton" data-options="iconCls:'icon-ok'" data-bind="click:confirmClick" href="javascript:void(0)" >确定</a> <a class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" data-bind="click:cancelClick" href="javascript:void(0)">取消</a> </div> </script> <script type="text/html" id="choose-members-template"> <div style="margin:5px;height:425px;overflow:auto;"> <div style="border-bottom:1px solid #CCC; margin-bottom:5px;"> <span class="icon32 icon-org32" style="padding-left:48px;font-weight:bold; font-size:14px;color:#666;"> 机构成员<input type="checkbox" style="vertical-align:middle;margin-left:5px;" data-bind="checked:checkAllOrganize"/>全选</span> </div> <ul style="margin:0;padding:0;clear:both" data-bind="foreach:organizes"> <li style="float:left;list-style:none;margin:3px;"><input type="checkbox" data-bind="value:id,checked:checked" style="vertical-align:middle" /><label data-bind="text:organizeName" ></label></li> </ul> <div style="border-bottom:1px solid #CCC; margin-bottom:5px;clear:both"> <span class="icon32 icon-user32" style="padding-left:48px;font-weight:bold; font-size:14px;color:#666;"> 用户成员<input type="checkbox" style="vertical-align:middle;margin-left:5px;" data-bind="checked:checkAllUser"/>全选</span> </div> <ul style="margin:0;padding:0;clear:both" data-bind="foreach:users"> <li style="float:left;list-style:none;margin:3px;"><input type="checkbox" data-bind="value:id,checked:checked" style="vertical-align:middle"/><label data-bind="text:userName"></label></li> </ul> </div> <div style="text-align:center;clear:both"> <a class="easyui-linkbutton" data-options="iconCls:'icon-ok'" data-bind="click:confirmClick" href="javascript:void(0)" >确定</a> <a class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" data-bind="click:cancelClick" href="javascript:void(0)">取消</a> </div> </script> <%@ include file="/common/foot.jsp"%> <script src="viewModel/sys/role.js"></script> <script type="text/javascript"> using(['validatebox','messager','dialog']); var data = ${model}; ko.bindingViewModel(new viewModel(data)); var formatterPermit = function (value, row) { var html = '<a href="javascript:;" onclick=\'permissionTab(' + JSON.stringify(row) + ')\'><span class="icon icon-set1"> </span>[编辑权限]</a>'; html += '<a href="javascript:;" onclick=\'memberDialog(' + JSON.stringify(row) + ')\' style="margin-left:10px"><span class="icon icon-users "> </span>[管理成员]</a>'; return html; }; </script> </body> </html>
2. role.js:实现角色管理功能、列表,编辑权限、管理成员功能
function viewModel() { var self = this; this.grid = { size: { w: 4, h: 40 }, url: rootPath+'/sys/role!list.do', queryParams: ko.observable(), loadFilter: function (d) { return {rows:d,total:d.length}; } }; this.gridEdit = new com.editGridViewModel(self.grid); this.grid.onDblClickRow = self.gridEdit.begin; this.grid.onClickRow = self.gridEdit.ended; this.refreshClick = function () { window.location.reload(); }; this.addClick = function () { self.gridEdit.addnew({}); }; this.editClick = function () { var row = self.grid.datagrid('getSelected'); var index = self.grid.datagrid('getRowIndex', row); self.gridEdit.begin(index, row); }; this.deleteClick = self.gridEdit.deleterow; this.saveClick = function () { self.gridEdit.ended(); var post = {}; post.list = self.gridEdit.getChanges(['id', 'roleName', 'roleSeq', 'description']); if (self.gridEdit.ended() && post.list._changed) { com.ajax({ url: rootPath+'/sys/role!edit.do', data: ko.toJSON(post), success: function (d) { com.message('success', '保存成功!'); self.grid.queryParams({}); } }); } }; } var permissionTab = function (row) { com.dialog({ title: "角色授限", width: 800, height: 600, html: "#permission-template", viewModel: function (win) { var self = this; this.role = ko.mapping.fromJS(row); this.tab = { onSelect: function (title, index) { if (title == '按钮权限') { //取得菜单权限中的选中行,并重新加开到按钮权限列表中 var temp = {},data = [],panel = self.grid2.treegrid('getPanel'); utils.eachTreeRow(self.grid.treegrid('getData'), function (node) { if (node.checked) { data.push(utils.filterProperties(node, ['children', 'description'], true)); temp[node.id] = node; } }); self.grid2.treegrid('loadData', data); //checkbox点击处理函数 var checkHandler = function (obj,value) { if (!obj.length) return; var map = { "0": rootPath+"/content/images/checknomark.gif", "1": rootPath+"/content/images/checkmark.gif" }; obj.attr("src", map[value]).attr("value", value); temp[obj.attr("menuId")]["btn_" + obj.attr("buttonId")] = parseInt(obj.attr("value")); }; //注册checkbox点击事件 panel.find("td[field]").unbind("click").click(function () { var img = $(this).find("img"), value = img.attr("value") == "1" ? "0" : "1"; checkHandler(img, value); if (img.attr("buttonId")== "_checkall") panel.find("img[menuId=" + img.attr("menuId") + "]").each(function () { checkHandler($(this), value); }); }); //注册全选checkbox的事件 panel.find(".datagrid-header .icon-chk_unchecked").unbind("click").click(function () { var chk = $(this), value = chk.hasClass("icon-chk_checked") ? "0" : "1", iconcls = chk.hasClass("icon-chk_checked") ? "icon-chk_unchecked" : "icon-chk_checked"; chk.removeClass("icon-chk_unchecked").removeClass("icon-chk_checked").addClass(iconcls); panel.find("img").each(function () { checkHandler($(this), value); }); }); } } }; this.grid = { height: 460, width: 774, url: rootPath+'/sys/menu!getEnabled.do?roleId='+row.id, idField: 'id', queryParams: ko.observable(), treeField: 'menuName', singleSelect: false, onCheck: function (node) { node.checked = true; }, onUncheck: function (node) { node.checked = false; }, onCheckAll:function(rows){ utils.eachTreeRow(rows, function (node) { node.checked = true; }); }, onUncheckAll: function (rows) { utils.eachTreeRow(rows, function (node) { node.checked = false; }); }, loadFilter: function (d) { var formatterChk = function (buttonId) { return function (value, row) { if (value >= 0) return '<img menuId="' + row.id + '" buttonId="' + buttonId + '" value="' + value + '" src="' + rootPath + '/content/images/' + (value ? "checkmark.gif" : "checknomark.gif") + '"/>'; }; } var cols = [[]]; for (var i in d.buttons) cols[0].push({ field: 'btn_'+d.buttons[i].id, width: 50, align: 'center', title: utils.formatString('<span class="icon {1}">{0}</span>', d.buttons[i].buttonName, d.buttons[i].buttonIcon), formatter: formatterChk(d.buttons[i].id) }); self.grid2.columns(cols); return utils.toTreeData(d.menus, 'id', 'parentId', "children"); } }; this.grid2 = { height: 460, width: 774, idField: 'id', treeField: 'menuName', frozenColumns: [[ { field: 'menuName', width: 150, title: '菜单' }, { field: 'btn__checkall', width: 50, align: 'center', title: '<span class="icon icon-chk_unchecked">全选</span>', formatter: function (v, r) { for (var i in r) { if (i.indexOf("btn_") > -1 && r[i] > -1) { return '<img menuId="' + r.id + '" buttonId="_checkall" src="' + rootPath + '/content/images/' + (v ? "checkmark.gif" : "checknomark.gif") + '"/>'; } } } } ]], columns: ko.observableArray(), loadFilter: function (d) { return utils.toTreeData(d, 'id', 'parentId', "children"); } }; this.confirmClick = function () { var post = {menus:[],buttons:[]}; utils.eachTreeRow(self.grid.treegrid('getData'),function(node){ if (node.checked) { //1 取得菜单权限数据 post.menus.push({ menuId: node.id }); //2 取得按钮权限数据 for (var btn in node) if (btn.substr(0, 4) == 'btn_' && node[btn] == '1' && btn != 'btn__checkall') post.buttons.push({ menuId: node.id, buttonId: btn.split('_')[1]}); } }); com.ajax({ url: rootPath+'/sys/role!editPermission.do?roleId=' + row.id, data: ko.toJSON(post), success: function (d) { self.cancelClick(); com.message('success', '保存成功!'); } }); }; this.cancelClick = function () { win.dialog('close'); }; } }) } var memberDialog = function (row) { var users = data.users; var organizes = data.organizes; com.dialog({ title: "管理成员", width: 500, height: 400, html: "#members-template", viewModel: function (win) { var self = this; this.members = ko.observableArray([]); this.memberText = function (item) { return utils.formatString('[{0}] {1}', item.memberType == 'user' ? '用户' : '机构', item.memberName); }; com.ajax({ type: 'GET', url: rootPath+'/sys/role!getRoleMembers.do?roleId=' + row.id, success: function (d) { self.members(d); } }); this.roleName = utils.formatString("{0}", row.roleName); this.description = row.description || " "; this.addClick = function () { com.dialog({ title: "选择成员", width: 600, height: 500, html: "#choose-members-template", viewModel: function (w) { var that = this; for (var i in users) users[i].checked = false; for (var i in organizes) organizes[i].checked = false; this.users = ko.mapping.fromJS(users); this.organizes = ko.mapping.fromJS(organizes); this.checkAllUser = ko.observable(false); this.checkAllUser.subscribe(function (b) { var list = that.users(); for (var i in list) list[i].checked(b); }); this.checkAllOrganize = ko.observable(false); this.checkAllOrganize.subscribe(function (b) { var list = that.organizes(); for (var i in list) list[i].checked(b); }); this.confirmClick = function () { var userlist = this.users(),organizelist=this.organizes(),memberMap = {},members = ko.toJS(self.members); for (var j in members) memberMap[members[j].memberType + '|' + members[j].memberId] = true; for (var i in userlist) if (userlist[i].checked()) { var item = { memberName: userlist[i].userName(), memberId: userlist[i].id(), memberType: 'user' }; if (!memberMap[item.memberType + '|' +item.memberId]) self.members.push(item); } for (var i in organizelist) if (organizelist[i].checked()) { var item = { memberName: organizelist[i].organizeName(), memberId: organizelist[i].id(), memberType: 'organize' }; if (!memberMap[item.memberType + '|' +item.memberId]) self.members.push(item); } this.cancelClick(); }; this.cancelClick = function () { w.dialog('close'); }; } }); }; this.selectValue = ko.observable(); this.deleteClick = function () { if (this.selectValue()) { self.members.remove(this.selectValue()); } }; this.clearClick = function () { self.members([]); }; this.confirmClick = function () { com.ajax({ url: rootPath+'/sys/role!editRoleMembers.do?roleId=' + row.id, data: ko.toJSON(self.members), success: function (d) { com.message('success', '保存成功!'); self.cancelClick(); } }); }; this.cancelClick = function () { win.dialog('close'); }; } }); };
二. 效果图
1. 访问:http://localhost:8080/ims/sys/role.do,角色管理界面
2. 点击 编辑权限,菜单权限
3. 按钮权限
4. 点击 管理成员