在通用權限管理系統中,有不少數據結構是有父子關係的,如組織機構,部門,權限菜單等,在展現的時候,大多數是經過zTree樹的形式展示的,以下:前端
這種數據後臺輸出比較容易處理,參考以下獲取某個子系統的所有操做菜單:node
/// <summary> /// 獲取module樹結構數據 /// </summary> /// <param name="systemCode"></param> /// <returns></returns> public ActionResult GetModuleTree(string systemCode = null) { if (string.IsNullOrWhiteSpace(systemCode)) { systemCode = BaseSystemInfo.SystemCode; } string tableName = systemCode + "Module"; ; BaseModuleManager moduleManager = new BaseModuleManager(UserInfo, tableName); List<KeyValuePair<string, object>> parameters = new List<KeyValuePair<string, object>>(); parameters.Add(new KeyValuePair<string, object>(BaseModuleEntity.FieldEnabled, 1)); //parameters.Add(new KeyValuePair<string, object>(BaseModuleEntity.FieldDeletionStateCode, 0)); parameters.Add(new KeyValuePair<string, object>(BaseModuleEntity.FieldIsVisible, 1)); var entityList = moduleManager.GetList<BaseModuleEntity>(parameters, BaseModuleEntity.FieldSortCode); Hashtable hashTable = new Hashtable(); if (entityList != null) { var result = (from p in entityList select new { id = p.Id, parentId = p.ParentId, name = p.FullName }).ToList(); hashTable.Add("treeNodes", result); } else { hashTable.Add("treeNodes", null); } return Json(hashTable, JsonRequestBehavior.AllowGet); }
var _zTree; //獲取樹對象 function getTree() { return $.fn.zTree.getZTreeObj("tree-1"); } //刷新樹 function RefreshTree() { var systemCode = $("#systemCode").attr("relValue"); if (typeof (systemCode) != "undefined") { setting1.async.url = "/Module/GetModuleTree?systemCode=" + systemCode; $.fn.zTree.init($("#tree-1"), setting1); _zTree = $.fn.zTree.getZTreeObj("tree-1"); } } //過濾 function filter(treeNodes) { var filterName = $("#OrganizeName").attr("reltext"); if (filterName == "AAAA" || filterName == "") { return false; } return (treeNodes.name.indexOf(filterName) > -1); } //樹的設置 var setting1 = { async: { enable: true, dataType: 'JSON', //返回的JSON數據的名字 dataName: 'treeNodes', url: "/Module/GetModuleTree", autoParam: ["id", "name", "desc"], otherParam: { "otherParam1": "zTreeAsyncTest1", "otherParam2": "zTreeAsyncTest2" } //,傳回的數據格式不是ztree所須要的格式的時候,能夠對數據進行轉化。正常狀況下不須要實現dataFilter //dataFilter: filter }, view: { addHoverDom: addHoverDom, removeHoverDom: removeHoverDom, selectedMulti: true }, edit: { enable: true, showRemoveBtn: false, showRenameBtn: false, renameTitle: "修改", removeTitle: "刪除", drag: { isCopy: false, isMove: true } }, callback: { onClick: onClick, beforeDrop: function(treeId, treeNodes, targetNode, moveType) { return onDrop(treeId, treeNodes, targetNode, moveType); }, onAsyncSuccess: onAsyncSuccess } }; //轉移 function onDrop(treeId, treeNodes, targetNode, moveType) { debugger; // 當前節點不能移動到當前節點上 var node, newParent = targetNode; var nodeNames = "",nodeIds=""; for (var i = 0; i < treeNodes.length; i++) { node = treeNodes[i]; nodeNames += node.name + ","; nodeIds += node.id + ","; if (node.id == newParent.id) { top.Dialog.alert("不能將本身設爲本身的父級節點"); return false; }; } if (nodeIds.length>0) { nodeIds = nodeIds.substring(0, nodeIds.length - 1); } // 當前節點不能移動到本身的子節點上去 for (var i = 0; i < treeNodes.length; i++) { //debugger; // 交換測試 //newParent = treeNodes[0]; //node = targetNode; node = treeNodes[i]; var pid = newParent.getParentNode(); while (pid != null) { pid = pid.getParentNode(); if (node == pid) { top.Dialog.alert("當前節點不能移動到本身的子節點上去"); return false; } } } if (!confirm("你肯定要將{0}轉移到{1}名下嗎?".replace("{0}", '\'' + nodeNames + '\'').replace("{1}", '\'' + newParent.name + '\''))) { return false; } else { var systemCode = $("#systemCode").attr("relValue"); $.ajax({ url: '/Module/MoveTo', type: 'POST', data: { moduleIds: nodeIds, parentId: newParent.id, systemCode: systemCode }, success: function(response, options) { // 重載樹 top.Dialog.alert(response.StatusMessage, function() { RefreshTree(); } ); } }); return true; } }; //異步加載成功後 function onAsyncSuccess(event, treeId, treeNode, msg) { _zTree.expandNode(_zTree.getNodes()[0], true, false, false); } //初始化函數 function initComplete() { $("#layout1").layout({ leftWidth: 200, onEndResize: function() { //g.resetWidth(); } }); RefreshTree(); //綁定change事件 $("#systemCode").bind("change", function() { if (!$(this).attr("relValue")) { top.Dialog.alert("沒有選擇節點"); } else { //top.Dialog.alert("選中節點文本:" + $(this).attr("relText") + "<br/>選中節點值:" + $(this).attr("relValue")); setting1.async.url = "/Module/GetModuleTree?systemCode=" + $(this).attr("relValue"), $.fn.zTree.init($("#tree-1"), setting1); _zTree = $.fn.zTree.getZTreeObj("tree-1"); AddModule(); } }); } //點擊樹節點 function onClick(event, treeId, treeNode, clickFlag) { //設置表單的值 $("#frmContent").attr("src", "/Module/Edit?id=" + treeNode.id + "&systemCode=" + $("#systemCode").attr("relValue")); } var _treeNode; // 添加 function addHoverDom(treeId, treeNode) { if (treeNode.editNameFlag || $("#addBtn_" + treeNode.id).length > 0) return; var sObj = $("#" + treeNode.tId + "_span"); var addStr = "<span class='zbutton add' id='addBtn_" + treeNode.id + "' title='添加' onfocus='this.blur();'></span>"; sObj.append(addStr); var btn = $("#addBtn_" + treeNode.id); if (btn) { btn.bind("click", function() { _treeNode = treeNode; $("#frmContent").attr("src", "/Module/Add?id=" + treeNode.id + "&systemCode=" + $("#systemCode").attr("relValue")); return false; }); } }; function refreshFrmContent() { window.frames["frmContent"].location.reload(); }; function removeHoverDom(treeId, treeNode) { $("#addBtn_" + treeNode.id).unbind().remove(); }; //新增 function AddModule() { var systemCode = $("#systemCode").attr("relValue"); if (typeof (systemCode) != "undefined") { $("#frmContent").attr("src", "/Module/Add?systemCode=" + systemCode); } else { top.Dialog.alert("請選擇一個子系統。"); } }; // 權限設置 function permissionSet() { top.Dialog.open({ ID: "selectWin", URL: "/Module/Permission?systemCode=@ViewBag.SystemCode&moduleId=@moduleEntity.Id", //+ systemCode, Title: "權限設置", Width: 640, Height: 480 }); };
菜單移動的本質是改變菜單的父節點,在編輯時能夠經過修改菜單的父節點來實現菜單的移動,爲了操做快捷,大多數狀況下但願能經過拖動節點來實現菜單的移動,實現的截圖以下:ajax
單個菜單的移動,鼠標左鍵按住須要移動的菜單,拖動到要移動的目的位置,而後鬆開鼠標左鍵,此時會彈出確認提示,點擊肯定,將會執行移動程序處理,點擊取消將恢復到原始位置。數據結構
點擊肯定後,菜單移到的位置:app
菜單移動支持多個菜單同時移動某個目標位置,異步
如上圖,多個菜單同時移動時,按住Ctrl鍵,逐個點擊要移動的菜單,而後鬆開Ctrl,鼠標拖動菜單移到目標位置。接下來操做如上。async
後臺處理菜單的移動方法,包括檢查節點可否移動(不能將本身設爲本身的父級節點,當前節點不能移動到本身的子節點上去):函數
/// <summary> /// 節點移動 /// </summary> /// <param name="moduleIds"></param> /// <param name="parentId"></param> /// <param name="systemCode"></param> /// <returns></returns> public ActionResult MoveTo(string moduleIds, string parentId, string systemCode = null) { string[] ids = moduleIds.Split(','); if (string.IsNullOrWhiteSpace(systemCode)) { systemCode = BaseSystemInfo.SystemCode; } BaseResult baseResult = new BaseResult(); string message = string.Empty; if (!MoveCheck(ids, parentId, systemCode, out message)) { baseResult.Status = false; baseResult.StatusMessage = message; } else { string tableName = systemCode + "Module"; var manager = new BaseModuleManager(UserCenterDbHelper, OperateContext.Current.UserInfo, tableName); // 設置moduleId的父級節點爲parentId int result = 0; for (int i = 0; i < ids.Length; i++) { if (!string.IsNullOrWhiteSpace(ids[i])) { result += manager.SetProperty(ids[i], new KeyValuePair<string, object>(BaseModuleEntity.FieldParentId, parentId)); } } if (result > 0) { baseResult.Status = true; baseResult.StatusMessage = "移動成功。"; } else { baseResult.Status = false; baseResult.StatusMessage = "移動失敗。"; } } return Json(baseResult, JsonRequestBehavior.AllowGet); } /// <summary> /// 節點移動檢查 /// </summary> /// <param name="ids"></param> /// <param name="parentId"></param> /// <param name="systemCode"></param> /// <param name="message"></param> /// <returns></returns> private bool MoveCheck(string[] ids, string parentId, string systemCode, out string message) { message = string.Empty; // 不能將本身設爲本身的父級節點 for (int i = 0; i < ids.Length; i++) { if (string.Equals(ids[i], parentId, StringComparison.OrdinalIgnoreCase)) { message = "不能將本身設爲本身的父級節點。"; return false; } } string tableName = systemCode + "Module"; var manager = new BaseModuleManager(UserCenterDbHelper, OperateContext.Current.UserInfo, tableName); // 目標節點 BaseModuleEntity moduleEntity = manager.GetObject(parentId); // 當前節點不能移動到本身的子節點上去 for (int i = 0; i < ids.Length; i++) { while (!string.IsNullOrWhiteSpace(moduleEntity.ParentId)) { moduleEntity = manager.GetObject(moduleEntity.ParentId); if (string.Equals(ids[i], moduleEntity.Id, StringComparison.OrdinalIgnoreCase)) { message = "當前節點不能移動到本身的子節點上去。"; return false; } } } return true; }
相似的,其它父子類的數據參照這個就能夠很方便的處理展現和移動了。測試