使用jquery easyui和MVC实现无限级部门的treeview 升降级 重命名 新增等功能。
1、效果预览:
2、Department数据库设计:
Description暂时未用和Deep只是识别了一下深度为0的为root级部门(可以换用ParentId==null识别,Deep虽只是标示了root级别部门但在实现升降时候也做了相应的处理)。
CREATE TABLE [dbo].[Department]
(
Id int identity(1,1) NOT NULL,
Name nvarchar(50) NOT NULL,
[Description] nvarchar(400) NOT NULL,
ParentId int NULL,
Deep int NOT NULL default(0),
)
--主键
ALTER TABLE [dbo].[Department]
ADD CONSTRAINT [PK_Department]
PRIMARY KEY (Id)
--自引用外键
ALTER TABLE [dbo].[Department]
ADD CONSTRAINT [FK_Department_ParentId]
FOREIGN KEY (ParentId)
REFERENCES [dbo].[Department] (Id)
3、数据访问使用的是NHibernate 使用codesmith生成,并加以改造。
默认生成的hbm和model使用起来不是很方便hbm增加一个one-to-many的Departments来获取当前Department下的子部门。
改造后的hbm文件内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="IMubiao.Data.DomainModels" assembly="IMubiao.Data">
<class name="IMubiao.Data.DomainModels.Department, IMubiao.Data" table="[dbo].[Department]" lazy="true">
<id name="Id" column="[Id]">
<generator class="native" />
</id>
<property name="Name" column="[Name]" />
<property name="Description" column="[Description]" />
<property name="Deep" column="[Deep]" />
<many-to-one name="DepartmentMember" column="[ParentId]" class="Department" />
<bag name="Departments" lazy="true" cascade="all-delete-orphan" inverse="true" >
<key column="[ParentId]"></key>
<one-to-many class="Department"></one-to-many>
</bag>
<bag name="Hrms" lazy="true" cascade="all-delete-orphan" inverse="true" >
<key column="[DepartmentId]"></key>
<one-to-many class="Hrm"></one-to-many>
</bag>
</class>
</hibernate-mapping>
对模板生成的model也要进行相应的修改(对应修改的hbm文件进行相应处理)
private IList<Department> _dep = new List<Department>(); [JsonProperty] public virtual IList<Department> Departments { get { return _dep; } set { OnDepartmentsChanging(); _dep = value; OnDepartmentsChanged(); } } partial void OnDepartmentsChanging(); partial void OnDepartmentsChanged();
涉及到的view index.aspx(显示效果就是开头的预览图效果)两个easyui-window 做部门降级和新增的容器 代码:
<div class="easyui-panel" title="部门管理" icon="icon-option" collapsible="true" minimizable="true" maximizable="false" style="height: 500px; padding: 10px; background: #fafafa;"> <ul id="department_tree" style="height: 350px;"> </ul> <div id="department_tree_menu" class="easyui-menu" style="width: 120px;"> <div onclick="dep_up()" iconcls="icon-up"> 升级</div> <div onclick="dep_down()" iconcls="icon-down"> 降级</div> <div class="menu-sep"> </div> <div onclick="dep_rename()" iconcls="icon-rename"> 重命名</div> <div class="menu-sep"> </div> <div onclick="department_add(0)" iconcls="icon-add"> 新增子部门</div> </div> <div id="show_d_tree" class="easyui-window" closed="true" title="选择上级部门" iconcls="icon-list" style="width: 200px; height: 300px; padding: 5px; background: #fafafa;"> <div class="easyui-layout" fit="true"> <div region="center" border="false" style="padding: 10px; background: #fff; border: 1px solid #ccc;"> <div id="load_tree"> </div> </div> </div> </div> <div id="department_add" class="easyui-window" closed="true" title="新增部门" iconcls="icon-add" style="width: 300px; height: 200px; padding: 5px; background: #fafafa;"> <div class="easyui-layout" fit="true"> <div region="center" border="false" style="padding: 10px; background: #fff; border: 1px solid #ccc;"> <div> <ul> <li style="list-style-type: none; height: 30px;"> <input type="hidden" id="parent_id" value="" /> <label> 上级部门:</label><label id="parent_text" style="color: Green;">无</label></li> <li style="list-style-type: none; height: 30px;"> <label for="department_name"> 部门名称:</label><input type="text" id="department_name" /> </li> <li style="list-style-type: none; height: 30px;"><a href="javascript:department_create()" class="easyui-linkbutton" icon="icon-save">保存</a></li> </ul> </div> </div> </div> </div> <div style="margin: 10px;"> <a href="javascript:department_add()" class="easyui-linkbutton" icon="icon-add">新增部门</a> <a href="javascript:reload();" class="easyui-linkbutton" icon="icon-reload">重新加载</a> </div> </div>
部门降级用到了一个PreDown.aspx的PartialView 代码如下:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<int>" %> <ul id="pre_down"> </ul> <li style="list-style-type: none; margin-top: 5px;"> <label for="selected"> 已选择:</label><label id="selected" style="color: Green;">未选择</label></li> <li style="list-style-type: none;"> <input type="hidden" id="id_transfer" value="<%=Model %>" /> <input type="hidden" id="selected_id" /> <a href="javascript:submit_down()" icon="icon-ok" class="easyui-linkbutton">确认降级</a></li> <script type="text/javascript"> $(function () { $('#pre_down').tree({ checkbox: false, url: '<%=Url.Action("PreDownData","Department",new {id=Model}) %>?' + new Date().getTime(), onClick: function (node) { $('#selected').text(node.text); $('#selected_id').val(node.id); $(this).tree('toggle', node.target); } }); }); function submit_down() { $.post('<%=Url.Action("Down","Department") %>', { id: $('#id_transfer').val(), pid: $('#selected_id').val() }, function () { $('#show_d_tree').window('close'); $('#department_tree').tree('reload'); }); } </script>
效果预览:
部门降级只能降至当前部门上级部门的子部门一下部门,也就是这个原因没有使用easyui tree的拖拽功能去做功能调整。
用到的几个js function:
<script type="text/javascript"> //初始化部门的tree $(function () { $('#department_tree').tree({ animate: true, url: '<%=Url.Action("DataList","Department") %>', onClick: function (node) { $(this).tree('toggle', node.target); }, onDblClick: function (node) { $('#department_tree').tree('beginEdit', node.target); }, onAfterEdit: function (node) { $.post('<%=Url.Action("Edit","Department") %>', { id: node.id, name: node.text }); reload(); }, onContextMenu: function (e, node) { e.preventDefault(); $('#department_tree').tree('select', node.target); $('#department_tree_menu').menu('show', { left: e.pageX, top: e.pageY }); } }); }); //刷新部门树 function reload() { $('#department_tree').tree('reload'); } //部门升级 function dep_up() { var node = $('#department_tree').tree('getSelected'); $.post('<%=Url.Action("UP","Department") %>', { id: node.id }, function () { $('#department_tree').tree('reload'); }); } //部门降级 function dep_down() { var node = $('#department_tree').tree('getSelected'); $('#load_tree').empty().load('<%=Url.Action("PreDown","Department") %>/' + node.id, function () { $('#show_d_tree').window('open'); }); } //重命名 function dep_rename() { var node = $('#department_tree').tree('getSelected'); $('#department_tree').tree('beginEdit', node.target); } //新增部门 function department_add(val) { if (val == undefined || val == null) { $('#parent_id').val(''); $('#parent_text').text('无'); } else { var node = $('#department_tree').tree('getSelected'); $('#parent_id').val(node.id); $('#parent_text').text(node.text); } $('#department_name').val(''); $('#department_add').window('open'); } //新增窗体里保存按钮的提交操作 function department_create() { var pid = $('#parent_id').val(); var name = $('#department_name').val(); name = encodeURIComponent(name); $.post('<%=Url.Action("Create","Department") %>', { pid: pid, name: name }); reload(); $('#department_add').window('close'); } </script>
DepartmentController Actions说明:
提供无限级tree数据的DataList 内容:
public string DataList(int? id) { var preModel = db.Departments.Where(x => x.Deep == 0); return Convert(preModel).ToJson(); } private List<Models.EUITreeModel> Convert(IQueryable<Department> model) { List<Models.EUITreeModel> result = new List<Models.EUITreeModel>(); foreach (var v in model) { var temp = new Models.EUITreeModel { id = v.Id, text = v.Name, attributes = string.Empty, iconCls = string.Empty, }; if (v.Departments.Count > 0) { temp.children = Convert(v.Departments.AsQueryable()); } result.Add(temp); } return result; }
Convert方法做无限级部门的递归,绑定jquery easyui tree data。
对应 jquery easyui tree 的EUITreeModel 属性:
public class EUITreeModel { public int id { get; set; } public string text { get; set; } public string iconCls { get; set; } public bool @checked { get; set; } public List<EUITreeModel> children { get; set; } public string attributes { get; set; } }
其他一些Action辅助做一些数据的更新和新增工作!