一、前言
權限系統設計中,授權代碼是用來控制數據訪問權限的。授權代碼說白了只是一樹型結構的數據,沒有什么其它的業務意義。那么這個頁面的功能也就非常簡單授權代碼維護:新增、修改、刪除授權代碼數據。
二、正文
我們實際上就是要實現一個treegrid的增刪改的功能,技術上很容易實現。
1、新建控制器 PermissionControlle.cs
public class PermissionController : Controller { public ActionResult Index() { return View(); } }
mvc控制器中不需要寫任何的代碼,就這樣就ok
2、創建view
@{ ViewBag.Title = "授權代碼"; Layout = "~/Views/Shared/_Layout.cshtml"; } @section scripts{ <script src="~/Areas/Sys/ViewModels/Permission.js"></script> <script type="text/javascript">
using(['combotree'],easyuifix.datagrid_editor_extend); ko.bindingViewModel(new viewModel()); var formatterParent = function (value, row) { return row.ParentName }; </script> } <div class="z-toolbar"> <a id="a_refresh" href="#" plain="true" class="easyui-linkbutton" icon="icon-arrow_refresh" title="刷新" data-bind="click:refreshClick">刷新</a> <a id="a_add" href="#" plain="true" class="easyui-linkbutton" icon="icon-add" title="新增" data-bind="click:addClick">新增</a> <a id="a_edit" href="#" plain="true" class="easyui-linkbutton" icon="icon-edit" data-bind="click:editClick" title="編輯">編輯</a> <a id="a_del" href="#" plain="true" class="easyui-linkbutton" icon="icon-cross" title="刪除" data-bind="click:deleteClick">刪除</a> <a id="a_save" href="#" plain="true" class="easyui-linkbutton" icon="icon-save" data-bind="click:saveClick" title="保存">保存</a> </div> <table data-bind="treegrid:grid"> <thead> <tr> <th field="_id" hidden="true"></th> <th field="PermissionName" align="left" width="150" editor="{type:'validatebox',options:{required: true }}">授權名稱 </th> <th field="PermissionCode" align="left" width="80" editor="{type:'validatebox',options:{required: true }}">授權代碼 </th> <th field="ParentCode" align="left" width="150" editor="combotree" formatter="formatterParent">上級授權 </th> </tr> </thead> </table>
這個view相對於其它頁面來說也是相當的簡潔了
3、前端的實現,主要是實現easyui treegrid的在線編輯功能及按鈕的交互邏輯
/** * 模塊名:mms viewModel * 程序名: Permission.js * Copyright(c) 2013-2015 liuhuisheng [ liuhuisheng.xm@gmail.com ] **/ function viewModel() { var self = this; this.grid = { size: { w: 4, h: 40 }, url: '/api/sys/permission', idField: '_id', queryParams: ko.observable(), treeField: 'PermissionName', loadFilter: function (d) { d = utils.copyProperty(d.rows || d, ["PermissionCode"], ["_id"], false); return utils.toTreeData(d, '_id', 'ParentCode', "children"); } }; this.refreshClick = function () { window.location.reload(); }; this.addClick = function () { if (self.grid.onClickRow()) { var row = { _id: utils.uuid(), PermissionCode: '', PermissionName: '' }; self.grid.treegrid('append', { parent: '', data: [row] }); self.grid.treegrid('select', row._id); self.grid.$element().data("datagrid").insertedRows.push(row); self.editClick(); } }; this.editClick = function () { var row = self.grid.treegrid('getSelected'); if (row) { //取得父節點數據 var treeData = JSON.parse(JSON.stringify(self.grid.treegrid('getData')).replace(/_id/g, "id").replace(/PermissionName/g, "text")); treeData.unshift({ "id": 0, "text": "" }); //設置上級菜單下拉樹 var gridOpt = $.data(self.grid.$element()[0], "datagrid").options; var col = $.grep(gridOpt.columns[0], function (n) { return n.field == 'ParentCode' })[0]; col.editor = { type: 'combotree', options: { data: treeData } }; col.editor.options.onBeforeSelect = function (node) { var isChild = utils.isInChild(treeData, row._id, node.id); com.messageif(isChild, 'warning', '不能將自己或下級設為上級節點'); return !isChild; }; //開始編輯行數據 self.grid.treegrid('beginEdit', row._id); self.edit_id = row._id; } }; this.grid.OnBeforeDestroyEditor = function (editors, row) { row.ParentName = editors['ParentCode'].target.combotree('getText'); }; this.deleteClick = function () { var row = self.grid.treegrid('getSelected'); if (row) { self.grid.$element().treegrid('remove', row._id); self.grid.$element().data("datagrid").deletedRows.push(row); } }; this.grid.onDblClickRow = self.editClick; this.grid.onClickRow = function () { var edit_id = self.edit_id; if (!!edit_id) { if (self.grid.treegrid('validateRow', edit_id)) { //通過驗證 self.grid.treegrid('endEdit', edit_id); self.edit_id = undefined; } else { //未通過驗證 self.grid.treegrid('select', edit_id); return false; } } return true; }; this.saveClick = function () { self.grid.onClickRow(); var post = {}; post.list = new com.editTreeGridViewModel(self.grid).getChanges(['_id', 'PermissionCode', 'PermissionName', 'ParentCode']); if (self.grid.onClickRow() && post.list._changed) { com.ajax({ url: '/api/sys/permission/edit', data: ko.toJSON(post), success: function (d) { com.message('success', '保存成功!'); self.grid.treegrid('acceptChanges'); self.grid.queryParams({}); } }); } }; }
4、現在大家看我的東西都覺得是在看前端文章,實際上我在后台框架也做的很強大。現在重點放在后台,請大家注意我后端的寫法,我們現在看web api中的處理。我這里用到了兩個web api
1、取得授權代碼數據: GET /api/sys/permission
2、保存treegrid中的修改(包括新增、修改、刪除的數據) POST /api/sys/permission
大家注意下WebApi實現,超級簡潔的代碼實現
public class PermissionApiController : ApiController { //創建數據服務實例 sys_permissionService service = new sys_permissionService(); public IEnumerable<dynamic> Get() { //構建查詢參數 var pQuery = ParamQuery.Instance() .Select("A.*,B.PermissionName as ParentName") .From(@"sys_permission A left join sys_permission B on B.PermissionCode = A.ParentCode"); //調用服務基類中的共通方法返回查詢結果 return service.GetDynamicList(pQuery); } [HttpPost] public void Edit(dynamic data) { //構建編輯的參數 傳入的數據結構為data={deleted:[...],inserted:[...],updated:[...]}; var listWrapper = RequestWrapper.Instance().LoadSettingXmlString(@" <settings> <table>sys_permission</table> <where> <field name='PermissionCode' cp='equal' variable='_id'></field> </where> </settings>"); //調用服務基類中的共通方法處理保存 service.Edit(null, listWrapper, data); } }
以上的兩個方法就已經實現了全部的功能了,這里我們好像覺得都是調用service中的方法,那我們再看看service類
public class sys_permissionService : ServiceBase<sys_permission> { }
這個數據服務類是空的,沒有任何方法,只是繼承了我的service基類,擁有了基類中定義的方法。
這里再簡單的介紹下我的服務基類,只要服務類繼承了服務基類后,就擁有以下方法
//服務構造函數 public ServiceBase(); public ServiceBase(string moduleName); //查詢方法: public List<dynamic> GetDynamicList(ParamQuery param = null); //取得動態數據列表 public dynamic GetDynamicListWithPaging(ParamQuery param = null); //取得動態數據列表(帶分頁) public List<T> GetModelList(ParamQuery param = null); //取得Model列表數據 public dynamic GetModelListWithPaging(ParamQuery param = null); //取得Model列表數據(帶分頁) public T GetModel(ParamQuery param); //取得單model數據 public dynamic GetDynamic(ParamQuery param); //取得動態對象 public TField GetField<TField>(ParamQuery param); //取得字段的值 //數據插入:提供數據插入前后事件定義 protected virtual bool OnBeforeInsert(InsertEventArgs arg); public int Insert(ParamInsert param); protected virtual void OnAfterInsert(InsertEventArgs arg); //數據更新: protected virtual bool OnBeforeUpdate(UpdateEventArgs arg); public int Update(ParamUpdate param); protected virtual void OnAfterUpdate(UpdateEventArgs arg); //數據刪除: protected virtual bool OnBeforeDelete(DeleteEventArgs arg); public int Delete(ParamDelete param); protected virtual void OnAfterDelete(DeleteEventArgs arg); //存儲過程執行: public int StoredProcedure(ParamSP param); //數據編輯(主從表在同一個事務中保存): protected virtual bool OnBeforEdit(EditEventArgs arg); protected virtual bool OnBeforEditMaster(EditEventArgs arg); protected virtual bool OnBeforEditDetail(EditEventArgs arg); public int Edit(RequestWrapper formWrapper, RequestWrapper listWrapper, JObject data); protected virtual void OnAfterEdit(EditEventArgs arg); protected virtual void OnAfterEditMaster(EditEventArgs arg); protected virtual void OnAfterEditDetail(EditEventArgs arg);
查詢、新增、修改、刪除、存儲過程等每一個對象我都對應一個參數構造器,查詢對應的是ParamQuery,每一個寫法都可以像linq一樣,比較方簡潔。
好了,回過頭再看看我的webapi中的代碼,是不是每個方法只有兩行代碼,而且已經實現了很復雜的操作。
正是得利於我框架的這一點,才把我從后台中解放出來,有更多的時間精力去研究前端。
三、效果圖
簡單的幾句代碼就搞定了這個功能,我們來看看實現的效果 
新增、修改、刪除測試都ok
五、后述
如果你覺得不錯就幫我【推薦】一下吧,你的支持才是我能堅持寫完這個系列文章的動力。
技術交流QQ群:群一:328510073(已滿),群二:167813846,歡迎大家來交流。
系列博客鏈接:
我的權限系統設計實現MVC4 + WebAPI + EasyUI + Knockout(三)圖形化機構樹

