
前言
前一篇文章《通用权限管理设计 之 数据库设计方案》介绍了【主体】- 【领域】 - 【权限】( who、what、how问题原型 ) 的设计思想
本文将对这种设计思想作进一步的扩展,介绍数据权限的设计方案。
权限控制可以理解,分为这几种 :
【功能权限】:能做什么的问题,如增加产品。
【数据权限】:能看到哪些数据的问题,如查看本人的所有订单。
【字段权限】:能看到哪些信息的问题,如供应商账户,看不到角色、 部门等信息。
上面提到的那种设计就是【功能权限】,这种设计有一定的局限性,对于主体,只能明确地指定。对于不明确的,在这里可能就没办法处理。比如下面这几种情况:
数据仅当前部门及上级可见
数据仅当前用户(本人)可见
类似这样的就需要用到上面提的数据权限。
上一篇文章我用一个表五个字段完成了【功能权限】的设计思路
本文我将介绍如何利用一个表两个字段完成这个【数据权限】的设计思路
初步分析
【数据权限】是在【功能权限】的基础上面进一步的扩展,比如可以查看订单属于【功能权限】的范围,但是可以查看哪些订单就是【数据权限】的工作了。
在设计中,我们规定好如果没有设置了数据权限规则,那么视为允许查看全部的数据。
几个概念
【资源】:数据权限的控制对象,业务系统中的各种资源。比如订单单据、销售单等。属于上面提到的【领域】中的一种
【主体】:用户、部门、角色等。
【条件规则】:用于检索数据的条件定义
【数据规则】:用于【数据权限】的条件规则
应用场景
1,订单,可以由本人查看
2,销售单,可以由本人或上级领导查看
3,销售单,销售人员可以查看自己的,销售经理只查看 销售金额大于100,000的。
我们能想到直接的方法,在访问数据的入口加入SQL Where条件来实现,组织sql语句:
1,where UserID = {CurrentUserID}
2,where UserID = {CurrentUserID} or {CurrentUserID} in (领导)
3,where UserID = {CurrentUserID} or ({CurrentUserID} in (销售经理) and 销售金额 > 100000)
这些一个一个的"条件",本文简单理解为一个【数据规则】,通常会与原来我们前台的业务过滤条件合并再检索出数据。
这是一种最直接的实现方式,在【资源】上面加一个【数据规则】(比如上面的三点)。这样设计就是
【资源】 - 【数据规则】
我又觉得不同的人应该对应不同的规则,那么也可以理解为,一个用户对应不同的角色,每一个角色有不一样的【数据规则】,那么设计就变成
【资源】 - 【主体】 - 【数据规则】
根据提供者的不同,准备不同的权限应对策略。
这里可以简单地介绍一下,这个方案至少需要2张表,一个是 【资源,主体,规则关系表】、一个是【数据规则表】
关系表不能直接保存角色,因为你不确定什么时候业务需要按照【部门】或者【分公司】来定义数据规则
于是可以用 Master、MasterKey 类似这样的两个字段来确定一个【主体】
用XML方式的话是这样配置的(放在数据库也类似):
<?xml version="1.0" encoding="utf-8"?>
<settings>
<rule view="订单" role="销售人员">
销售员 = {CurrentUserID}
</rule>
<rule view="订单" role="总销售经理">
销售金额 > 100000
</rule>
<rule view="订单" role="区域销售经理">
销售金额 > 100000 and 区域 = {当前用户所属区域}
</rule>
</settings>
对于这种方式有兴趣的朋友也可以试一下,两种方式的【数据规则】是一样的,但是本文没有采用第二种设计方式,因为它多了一层处理逻辑,我以为应该设计越简单越好,就采用第一种方式:
【资源】 - 【数据规则】
当然,上面是用SQL的方式来确定条件规则的,我们当然不会这么做。SQL虽然灵活,但是我们很难去维护,也不知道SQL在我们的界面UI上面如何体现。难不成直接用一个文本框来显示。这样对应一个开发人员来说不是问题,可是对应系统管理员,很容易出问题。所以我们需要有另一方式来确定这一规则,并最终可以转换成我们的SQL语句。
我们的设计关键在于如何规范好这些【数据规则】 ,这个规则必须是对前端友好的,而且是对后台友好的,JSON显然是很好的方式。
规则说明:
1,数据权限规则总是:{属性 条件 允许值}
2,数据权限规则可以合并。比如 ( {当前用户 属于 销售人员} and {订单销售员 等于 当前用户} ) Or {当前用户 属于 销售经理}
3,最终我们会用JSON格式
在检索数据时会先判断有没有注册了某某【资源】的【条件规则】,如果有,那么加载这个【条件规则】并合并到我们前台的【搜索条件】(你的业务界面应该有一个搜索框吧)
如下图定义了客户信息的搜索框,我们搜索客户ID包括AN,我们组织成的规则将会是:
{"rules":[{"field":"CustomerID","op":"like","value":"AN","type":"string"}],"op":"and"}

为了更好地理解【数据规则】,这里介绍一下【通用查询机制】
【通用查询机制】
权限控制总离不开一些条件的限制(比如查看当前部门的单据),如果没有完善的通用查询规则机制,那么在做权限条件过滤的时候你会觉得很别扭。这里介绍一个通用查询方案,然后再介绍如何实现【数据规则】。
早些时候我写过一篇关于ligerGrid结合.net设计通用处理类的文章《 jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载) 》。里面提到的过滤信息是直接的SQL语句。这是不可靠,而且不安全的。
在前端传输给后台的过滤信息不应该是直接的SQL,而应该是一组过滤规则。在ligerui V1.1.8 已经加入了一个条件过滤器插件,这个插件组成的规则数据才是我受推荐的:
比如如下
{"rules":
[
{"field":"OrderDate","op":"less","value":"2012-01-01"},
{"field":"CustomerID","op":"equal","value":"VINET"}
]
,"op":"and"}
规则描述:
查找顾客VINET所有订单时间小于2011-01-01的单据
这样的数据是安全的,而且是通用的(你甚至可以再加一个OR子查询)。无论是在前端还是后台,无论你使用什么样的组件,都可以很好地利用。
通用后台的翻译,就可以生成这样SQL的参数:
Text:
([OrderDate] < @p1 and [CustomerID] = @p2)
Parameters:
p1:2012-01-01
p2:VINET
下面来点复杂的:查找 顾客VINET或者TOMSP,所有订单时间小于2011-01-01的单据
{
"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],
"groups":[
{"rules":[{"field":"CustomerID","op":"equal","value":"VINET"}, {"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
],
"op":"and"
}
翻译结果:
Text:([OrderDate] < @p1 and ([CustomerID] = @p2 or [CustomerID] = @p3))
Parameters:
p1:2012-01-01
p2:VINET
p3:TOMSP
这个过滤规则分为三个部分:【分组】、【规则】(字段、值、操作符)、【操作符】(and or),而自身就是一个分组。
这种简单的结构就可以满足全部的情况。
当然,上面提到的这些条件都是在前台定义(可能是用户在搜索框自己输入的)的,而在后台,我们可能会定义一下【隐藏条件】,比如说 【员工只能查看自己的】,要怎么做呢,其实很简单,只需要在后台接收到这个过滤条件(前台toJSON,后台解析JSON)以后,再加上一个过滤规则(隐藏条件):
{field:'EmployeeID',op:'equal',value:5}
可以将原来的过滤规则当做一个分组加入进行:
{op:'and',groups:[
{"rules":[{"field":"OrderDate","op":"less","value":"2012-01-01"}],
"groups":[
{"rules":[{"field":"CustomerID","op":"equal","value":"VINET"},{"field":"CustomerID","op":"equal","value":"TOMSP"}],"op":"or"}
],"op":"and"}
],rules:[{field:'EmployeeID',op:'equal',value:5}]
}
翻译如下:
Text:
([EmployeeID] = @p1 and ([OrderDate] < @p2 and ([CustomerID] = @p3 or [CustomerID] = @p4)))
Parameters:
p1:5
p2:2012-01-01
p3:VINET
p4:TOMSP
这样的【条件规则】才是我们想要的,不仅在前端可以很好地解析,也可以在后台进行处理。在后台我们会定义跟这种数据结构对应的类,那么再定义一个翻译成SQL的类:

数据权限规则
说了这些,可以开始介绍如何实现【数据规则】了:
上面提到的【隐藏条件】,就是我介绍的【数据规则】
试想一些,这样 前台的过滤规则,再加上我们之间定义好的 【数据权限】控制 过滤条件。不就达到目的了吗。
先看看我们在数据库里保存的这些【数据规则】:

看不明白?那来个清楚一点的:

规则描述
订单:【订单管理员和演示角色可以查看所有的】,【订单查看员】只能查看自己的
产品:【基础信息录入员和演示角色可以查看所有的】,【供应商】只能查看自己的
{CurrentEmployeeID}表示当前的员工。
实质上,我们还可以根据当前用户信息定义需要的参数,比如:
{CurrentUserID} 当前用户Id ,对应表【CF_User】
{CurrentRoleID} 当前角色Id ,对应表 【CF_Role】
{CurrentDeptID} 当前用户部门Id,对应表【CF_Department】
{CurrentEmployeeID} 当前用户员工Id,对应表【Employees】(CF_User.EmployeeID)
{CurrentSupplierID} 当前用户供应商Id,对应表【Suppliers】(CF_User.SupplierID)
在数据库中我们直接保存这些用户参数,在“翻译”规则成为SQL时,会替换掉:

比如查看订单,我们得到的SQL,可能是这样的:
Text: SELECT * FROM (SELECT TOP 20 * FROM (SELECT TOP 40 * FROM [Orders] WHERE ( 1=1 and ((@p1 in (@p2,@p3)) or (@p4 = @p5 and [EmployeeID] = @p6))) ORDER BY OrderID ASC) AS tmptableinner ORDER BY OrderID DESC) AS tmptableouter ORDER BY OrderID ASC
Parameters:
@p1[Int32] = 7
@p2[Int32] = 2
@p3[Int32] = 6
@p4[Int32] = 7
@p5[Int32] = 7
@p6[Int32] = 1
{CurrentRuleID} 替换为 7
{CurrentEmployeeID} 替换为1
下图是我们设计【数据权限】的界面,可以选择所有的字段,包括几个用户信息:

这些字段不仅仅只是在文本框中输入值,那么可以自定义数据来源:
var fieldEditors = {};
fieldEditors['Orders'] = {
'ShipCity': { type: 'combobox',
options: {
width: 200,
url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
}
}
};
效果界面:

实际应用
既然是数据权限控制,如果有一个统一的数据接收入口,我们倒是可以利用这个入口做一些工作。
比如【ligerRM权限管理系统】统一使用 grid.ashx 这个数据处理程序作为列表数据的接收入口。
有了统一的接口,方便做权限的控制,使用过 ligerGrid Javascript表格,或者类似插件的朋友,应该比较清楚服务器的交互原理。
在grid.ashx中,我们会通过
【视图/表名 】、 【排序信息】、【分页信息】、【过滤信息】
这几个指标来获取指定的数据。
而在实际的业务中,可能会引入权限的控制。比如某某【资源】,只能由当前用户自身才能查看,或者只能由当前用户部门及上级部门才能查看。对于这些控制,我们采用对这些可能做权限控制的【资源】注册一组【条件规则】的方式来进行。

我们将找到view定义好的【数据权限规则】,然后和用户在前台搜索框输入的【搜索规则】合并:

上面的代码就是数据条件合并的例子,这样便得到了我们最终需要的 过滤规则。
结语
本文提出了数据权限的一种实现思路,只是本人在做一个web应用时构思的方案,谈不上规范,欢迎提出你的建议意见。
可以在http://case.ligerui.com体验实际的应用效果。

阅读目录
简介
ligerRM V2是基于 ligerui的web应用系统。以权限管理作为设计重点,引入Northwind作为主要的数据演示模块。权限方面,在上一个版本的基础上面加多了数据权限控制。后台方面采用dot net 3.5框架开发。
- 系统演示:http://case.ligerui.com
- 前台插件:jQuery、jQuery.ligerui、jQuery.form.js、jquery.validation
- 数据交互:liger.Data(一个小型的ORM组件)
- 源码下载:ligerRMV2
演示账户:
|
账户
|
名字
|
头衔
|
密码
|
|
test3
|
录入员1
|
基础数据录入员1
|
1
|
|
test2
|
录入员2
|
客户数据录入员2
|
1
|
|
test1
|
高级演示账号1
|
高级演示账号1
|
1
|
|
test4
|
订单查看员1
|
订单查看员1 - Sales Representative
|
1
|
|
test5
|
供应商1
|
供应商1 - Exotic Liquids44
|
1
|
系统特色
1,不采用code-behind机制,不使用任何服务器控件,全面将工作放在前台实现,后台只处理数据部分。页面还是用aspx后缀,继承于统一的页面基类(为了方便权限的控制)。
2, 极大得避免代码冗余。无论是列表页面还是明细页面,你看到的代码都是极其简洁的,就算是表单,甚至不需要任何的html代码,而是定义【有用的信息】,对【布局】、【数据】有用的 【数据结构】,当然表格、搜索框 都是如此。
3,统一的数据提交/接收接口,所有的数据请求通过ajax实现,经过 handler/*.ashx处理,针对前台数据请求类型的不同,一共有6个:
ajax.ashx ---- 通用的数据请求入口(表单提交入口、表单加载入口、常用的数据加载入口等等)
grid.ashx ---- 通用的ligerGrid表格数据加载入口
treegrid.ashx ---- 通用的ligerGrid表格树格式数据加载入口
tree.ashx ---- 通用的ligerTree树格式数据加载入口
select.ashx ---- 通用的ligerComboBox数据加载入口
validate.ashx ---- 通用的验证数据验证入口(针对jQuery.validation remote验证)
4,完善的数据权限控制机制。除了基本的 (用户角色) => (模块功能) 这类的功能权限控制,还在数据请求入口做了一点小动作,根据【当前的用户信息】和【配置好的数据权限规则】筛选过滤数据。
5,自动的搜索框、自动的表单。 表单和搜索框不再需要一堆复杂冗余的html,而是定义好字段的信息(字段名、宽度、类型等)就可以自动完成页面的构造。
6,自动的表格,同样地表格也只是需要一些配置信息,就可以自动完成。并利用过滤器插件,拥有高级自定义查询功能,和历史查询功能。
系统介绍 - 首页
带权限控制的模块
加载首页时,系统会根据用户的信息加载权限许可的菜单模块:

系统介绍 - 列表页(配置的搜索框、表格、动态的按钮(权限控制))
搜索框、表格不再是一堆html拼出来,而是只定义了与【布局】和【数据】配置信息的。
操作按钮是根据当前页面的权限控制,加载有权限许可的操作按钮。
具体的做法是判断页面的MenuNo(菜单唯一编码),根据MenuNo和当前用户信息加载权限许可的按钮,MenuNo的获取规则:
优先级一:如果页面定义了ID为“MenuNo”的隐藏域,那么读取这个隐藏域的值,比如:<ipnut type="hidden" id="MenuNo" value="OrderManageOrders" />
优先级二:根据页面URL的QueryString,Name为MenuNo的值
优先级三:根据页面URL进行匹配,/OrderManage/Orders.aspx,MenuNo就是OrderManageOrders
界面效果:

相关代码:

搜索框表单元素并不是都以文本框的形式,而是支持日期、下拉框等等类型,这些编辑器是可以扩展的,理论上是通用的。比如发货城市,可以配置为下拉框选择:
display: "城市", name: "ShipCity", newline: true, labelWidth: 100, width: 220, space: 30, type: "select", cssClass: "field", options:{
url: "../handler/select.ashx?view=Orders&idfield=ShipCity&textfield=ShipCity&distinct=true"
}
系统介绍 - 明细页(自动创建表单、表单自动加载、表单提交)
表单应该包括三个部分,表单结构、表单数据、表单提交 :
表单结构:为了样式的统一,代码的简洁,表单同样也是通过“配置”出来的(利用了ligerForm插件)
表单数据:通过指定一个视图/表名、主键字段名、主键值加载到一条记录以后,利用JS访问每一个属性加载到相应的控件上面,并更新控件的样式。
表单提交:利用jquery.validate做表单验证,利用jQuery.form.js做ajax提交数据
说明两点:
1,更新控件的样式:表单的文本框、下拉框都是用ligerui内置的表单元素组件,这些组件都有updateStyle方法,就是当值改变时,界面上面没有及时反应,可调用这个方法
2,表单提交的统一入口是ajax.ashx,我们会传入type和method,利用反射的机制找到相应的方法,将请求的数据(Request.Form)传给那个方法。比如增加订单的签名:AjaxResult AddOrders(NameValueCollection form)
界面如下:

系统介绍 - 菜单/按钮
菜单的编辑保存,采用表格【行编辑】模式,并且支持提交前验证,图标在dialog中选取,使得操作更加简单。



按钮的编辑模式同菜单一样,采用表格的【行编辑模式】。对应字段信息不多的,我也比较推荐这种方式,而不是再打开一个页面。
如果需要全表格同时编辑,那么可以采用表格的【单元格编辑模式】,比如系统中【订单编辑页-订单明细表格】


系统介绍 - 权限中心
设计思想同上一个版本一样,采用 【用户】、【角色】 =》 【模块】、【功能】 的权限控制。不清楚的朋友可以参考我之前的一篇介绍:《通用权限管理设计 之 数据库结构设计》
在界面上仅仅只是用了一个页面,就完成了全部的权限控制,操作很简洁。设计规则上,角色可以授权权限许可。而用户,是在角色的基础上面,单独设置为许可、或者禁止。

可以单独给用户设置权限(许可或者禁止)

系统介绍 - 数据权限
这个版本新增的功能,可以在功能权限(上面提到的)的基础上进一步的权限控制扩展,比如销售员只能查看到自己的销售订单。
使用了ligerFilter过滤器插件,这是一个通用条件查询组件。可以自定义编辑器的类型,如下图选择角色的下拉框。

下图是编辑页面,定义了数据权限规则:【订单查看员只能查看自己的】、【订单管理员和演示角色可以看到全部的】。
管理员永远不会受到数据权限的限制
注意到有5个可选择的用户信息参数,根据业务需求这里可以扩展

5个用户信息参数在组织最终的数据库执行语句时将会返回以下的匹配关系,这里是可以很好地扩展的。

数据权限的限制总是:{字段名 条件 允许值}
下图列出了订单表的所有字段,并且加入几个用户参数方便做权限的具体分配。

利用ligerFilter编辑器可自定义的特性,这里当前用户信息可以在下拉框中选择,你甚至可以改成在弹出窗口中选择。

系统介绍 - 字段权限
如果说数据权限是对功能权限在纵向的扩展,那么字段权限就是在横向的扩展。可以禁止指定用户/角色 对某些字段的访问,这个功能同样是本版本增加的:


系统介绍 - 下拉框应用细节
下拉框在系统中的应用都很经典,比如下拉框树,下拉框表格,下拉框在弹出窗口中选取数据。这里介绍几个应用的细节
用户在部门树中选择:

实则上系统针对下拉框选取数据的各种情况都通用化了,只需要简单的配置信息就可以实现在指定数据源中选择,比如上图,只需要这样配置:

上图是下拉框树的实例,再看看普通下拉框的:

这两种情况都是加载全部数据的,如果下拉框的数据来源很大,我们当然不想在一次性加载全部数据中,而是可以在弹出的、分页的、可过滤的表格中选取数据,这样会让表单的应用变得更加人性化。基于这种需求,在这个系统对下拉框插件中扩展了openSelect方法,只需要指定grid的配置参数,search的配置参数(可选),返回的字段名,就可以快速实现这个应用。可以参考系统中【订单中选择客户】、【产品中选择供应商】。

Code:

结语
这个版本对于【增删改】常用的操作封装得更加彻底,大大强化了客户端javascript的处理能力,而服务器端只是起到数据处理的作用。
系统中大量使用了grid、tree以及各种表单插件,更大程度地展示了ligerui的很多功能的使用。
还有很多的细节和使用技巧,比如订单明细编辑表格中引入产品、Tab选项延时加载。都有待你的体验和建议。
欢迎反馈: http://bbs.ligerui.com
复选框
grid可以设置复选框模式进行多选,只需要简单的配置
checked:true
获取选中行
如果要获取选中的行,可以用getSelecteds方法:
var rows = g.getSelecteds();
alert(rows.length);
默认选中
有的时候我们想让某一些行初始化的时候就选中,可以用isChecked参数,这是一个函数,使用例子:
$("#maingrid4").ligerGrid({
checkbox: true,
columns: [
{ display: '主键', name: 'CustomerID', align: 'left', width: 120 },
{ display: '公司名', name: 'CompanyName', minWidth: 60 },
{ display: '联系名', name: 'ContactName', width: 50,align:'left' }
{ display: '城市', name: 'City' }
], pageSize:30,
data: CustomersData,
width: '100%', height: '100%', isChecked: f_isChecked
});
function f_isChecked(rowdata)
{
if (rowdata.CustomerID.indexOf('AN') == 0)
return true;
return false;
}
锁定列
如果启动了固定列功能,frozen:true。那么复选框列默认是锁定的,可以通过设置frozenCheckbox参数来解除
frozenCheckbox:false

相关事件

如果你不知道事件如何使用,可以参考
多表头
将columns配置为树的格式就可以变成多表头。比如:
columns: [
{ display: '公司信息', columns:
[
{ display: '公司名', name: 'CompanyName', minWidth: 60,width:300 }
]
},
{ display: '个人信息', columns:
[
{ display: '主键', name: 'CustomerID', align: 'left', width: 120 },
{ display: '联系名', name: 'ContactName', width: 50, align: 'left' },
{ display: '城市', name: 'City', headerText: '44444' }
]
}
]
columns可以无限级扩展,也就是说可以三级多表头,也可以是四级多表头,只要你愿意。

分组
分组只需要简单得配置一个参数groupColumnName,插件就可以自动完成。配置groupColumnDisplay可以用于显示分组时的名字:


也可以自定义分组显示的格式:


汇总
汇总有两种方式,一种是针对全部数据的汇总,一直是针对当前页进行汇总
1,全部数据的汇总: 一般你绑定的表格数据有Rows和Total属性,你可以增加其他的属性,用于统计使用,比如加上 SumAmount。
totalRender: f_totalRender
function f_totalRender(data, currentPageData)
{
return "总金额数量:"+data.SumAmount;
}

2,当前页数据/分组数据的汇总,针对某一列进行配置,只需要设置totalSummary的type:


也可以自定义汇总单元格的格式:


可以和分组一起工作,只汇总分组的数据:


明细
明细的工作原理很简单,就是在点击明细展开/收缩按钮的时候,会创建一个空白的行(下图代码中得detailPanel),并获取当前行的数据。我们会根据当前行数据进行一些工作,比如获取明细表的数据,或者是展开当前列表并未列出的一些信息,像图片之类的,也可以展开当前行的编辑行。


明细编辑行:

使用远程数据
ligerGrid允许指定一个url来加载数据,并且支持排序和分页。对于数据格式是有一定的限制的,比如
{
"Rows":[],"Total":0
}
我们需要将要显示的数据放在Rows里面(数组的形式),将记录数放在Total
Rows和Total这两个字段名不是固定的,可以通过参数进行修改:
root: 'Rows', //数据源字段名
record: 'Total', //数据源记录数字段名
使用远程数据 排序
排序在首次加载数据的时候,会判断有没有设置了sortName参数,如果有会往服务器传输排序的信息:
string sortname = context.Request["sortname"];
string sortorder = context.Request["sortorder"];
我们在表头点击的时候,也有可能触发服务器排序的操作:

通常我们会指定默认排序的字段,比如 sortName: 'OrderID':

sortname和sortorder参数名是可以改变的:

使用远程数据 分页
liger grid自带了分页,如果使用本地数据,分页可以不用关心,不过如果用到远程加载数据,那么需要你自己来完成这个分页的操作,根据分页的信息返回相应的数据。
组件会往服务器传输几个分页有用的参数:

服务器端根据这二个参数进行分页处理:
string _pagenumber = context.Request["page"];
string _pagesize = context.Request["pagesize"];
我们需要返回json格式的字符串:

如果还有什么不明白的可以参考:
jQuery LigerUI 表格LigerGrid 结合 ASP.NET MVC 显示数据
jQuery liger ui ligerGrid 打造通用的分页排序查询表格(提供下载)
或者到论坛提问:

阅读目录
准备工作。创建MVC项目,拷贝LIGERUI库到Web程序中。
一,准备工作
使用开发工具:Microsoft Visual Studio 2010
使用插件版本: jQuery 1.4.1 、 jQuery LigerUI 1.1.7
二,创建MVC项目

三,下载最新版的ligerui,并拷贝到web的根目录
下载地址:http://ligerui.googlecode.com/


增加视图和Action,引入jQuery库和ligerUI库的引用,模板页中增加视图的链接
一,增加视图


二,增加Action

三,引入jQuery库和ligerui的引用

四:模板页增加视图的链接

准备数据结构(ligerGrid的调用) 和数据源(增加一个Action,返回JSON格式)
一,编写JS代码调用ligerGrid

这里要注意一下URL的格式 : /Home/GetData
二,准备数据源(增加一个Action,返回JSON格式)

三,效果

如何分页和排序。
一,ligerGrid服务器端分页的原理
可以利用firebug来调试,可以查看到grid加载分页数据的时候,会往服务器传几个数据:

那么在后台我们需要根据这几个参数返回grid适合的数据:

二,如何使用MVC Action接收并返回数据:
1 public ActionResult GetData2()
2 {
3 //排序的字段名
4 string sortname = Request.Params["sortname"];
5 //排序的方向
6 string sortorder = Request.Params["sortorder"];
7 //当前页
8 int page = Convert.ToInt32(Request.Params["page"]);
9 //每页显示的记录数
10 int pagesize = Convert.ToInt32(Request.Params["pagesize"]);
11
12 IList<Node> list = new List<Node>();
13 var total = 1000;
14 for (var i = 0; i < total; i++)
15 {
16 list.Add(new Node()
17 {
18 id = i,
19 name = "部门" + i,
20 time = DateTime.Now
21 });
22 }
23 //这里模拟排序操作
24 if (sortorder == "desc")
25 list = list.OrderByDescending(c => c.id).ToList();
26 else
27 list = list.OrderBy(c => c.id).ToList();
28
29 IList<Node> targetList = new List<Node>();
30 //这里模拟分页操作
31 for (var i = 0; i < total; i++)
32 {
33 if (i >= (page - 1) * pagesize && i < page * pagesize)
34 {
35 targetList.Add(list[i]);
36 }
37 }
38 var griddata = new { Rows = targetList, Total = total };
39 return Json(griddata);
40 }
三,前台调用

四,效果

源码下载
下载地址:GridMvcApp.7z

前言
上个版本的发布。有些朋友提出框架图片太大的问题,在这个版本做出了解决。并对树和表格增强了拖拽能力。另外,对Dialog插件也加强了一番。具体的更新可以下载来细看:
相关链接
源码下载:http://ligerui.googlecode.com/
技术支持:http://www.cnblogs.com/leoxie2011/
V1.1.6更新记录
基础
[需求]全面优化框架图片
[需求]整理简化皮肤Silvery,需要依赖默认的Aqua
表格
[BUG]修复 隐藏列后 再次加载数据,隐藏的列会再次显示 的问题
[BUG]修复存在行序号时,汇总行错位的问题
[需求]重写列调整,需要依赖ligerResizable
[需求]支持动态设置columns
[需求]支持行移位、表头拖拽
窗口/对话框
[需求]支持最小化、最大化、可收缩
对话框
[需求]支持 右下角的提示框
树
[需求]增加节点图标
[需求]增加节点拖拽





