個人權限系統設計實現MVC4 + WebAPI + EasyUI + Knockout(四)受權代碼維護

1、前言
權限系統設計中,受權代碼是用來控制數據訪問權限的。受權代碼說白了只是一樹型結構的數據,沒有什麼其它的業務意義。那麼這個頁面的功能也就很是簡單受權代碼維護:新增、修改、刪除受權代碼數據javascript

2、正文
咱們實際上就是要實現一個treegrid的增刪改的功能,技術上很容易實現。
一、新建控制器 PermissionControlle.cs html

public class PermissionController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

mvc控制器中不須要寫任何的代碼,就這樣就ok前端

二、建立viewjava

@{
  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相對於其它頁面來講也是至關的簡潔了node

三、前端的實現,主要是實現easyui treegrid的在線編輯功能及按鈕的交互邏輯web

/**
* 模塊名: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({});
                }
            });
        }

    };
}


四、如今你們看個人東西都以爲是在看前端文章,實際上我在後臺框架也作的很強大。如今重點放在後臺,請你們注意我後端的寫法,咱們如今看web api中的處理。我這裏用到了兩個web api
一、取得受權代碼數據:                                            GET    /api/sys/permission
二、保存treegrid中的修改(包括新增、修改、刪除的數據)   POST  /api/sys/permissionajax

你們注意下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類api

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中的代碼,是否是每一個方法只有兩行代碼,並且已經實現了很複雜的操做。
正是得利於我框架的這一點,才把我從後臺中解放出來,有更多的時間精力去研究前端。

3、效果圖
簡單的幾句代碼就搞定了這個功能,咱們來看看實現的效果
image

新增、修改、刪除測試都ok

image

 

5、後述
若是你以爲不錯就幫我【推薦】一下吧,你的支持纔是我能堅持寫完這個系列文章的動力。
技術交流QQ羣:羣一:328510073(已滿),羣二:167813846,歡迎你們來交流。

系列博客連接:

個人權限系統設計實現MVC4 + WebAPI + EasyUI + Knockout(三)圖形化機構樹

個人權限系統設計實現MVC4 + WebAPI + EasyUI + Knockout(二)菜單導航

個人權限系統設計實現MVC4 + WebAPI + EasyUI + Knockout(一)

相關文章
相關標籤/搜索