zoukankan      html  css  js  c++  java
  • 我的权限系统设计实现MVC4 + WebAPI + EasyUI + Knockout(四)授权代码维护

    一、前言
    权限系统设计中,授权代码是用来控制数据访问权限的。授权代码说白了只是一树型结构的数据,没有什么其它的业务意义。那么这个页面的功能也就非常简单授权代码维护:新增、修改、删除授权代码数据

    二、正文
    我们实际上就是要实现一个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中的代码,是不是每个方法只有两行代码,而且已经实现了很复杂的操作。
    正是得利于我框架的这一点,才把我从后台中解放出来,有更多的时间精力去研究前端。

    三、效果图
    简单的几句代码就搞定了这个功能,我们来看看实现的效果
    image

    新增、修改、删除测试都ok

    image

    五、后述
    如果你觉得不错就帮我【推荐】一下吧,你的支持才是我能坚持写完这个系列文章的动力。
    技术交流QQ群:群一:328510073(已满),群二:167813846,欢迎大家来交流。

    系列博客链接:

    我的权限系统设计实现MVC4 + WebAPI + EasyUI + Knockout(三)图形化机构树

    我的权限系统设计实现MVC4 + WebAPI + EasyUI + Knockout(二)菜单导航

    我的权限系统设计实现MVC4 + WebAPI + EasyUI + Knockout(一)

  • 相关阅读:
    [leetcode]5最长回文子串
    [leetcode]4寻找两个有序数组的中位数
    [leetcode]3无重复字符的最长字串
    [leetcode]2两数相加
    [leetcode]1两数之和
    [学习记录]堆
    [学习记录]平衡树
    [学习记录]二叉树删除
    [学习记录]排序算法总结
    创建mysql数据库
  • 原文地址:https://www.cnblogs.com/xqin/p/3309115.html
Copyright © 2011-2022 走看看