基于MVC的前台ExtJs树型表格的批量数据操作实现

来源:互联网 发布:汉武大帝知乎 编辑:程序博客网 时间:2024/06/16 08:47

项目背景:在项目管理信息系统中,基于软件项目的生命周期中有个很重要的模块是计划管理,通常计划管理会分成四层计划:项目范围+季度计划+月度计划
+周任务单,在范围计划界面输入就涉及到树表的应用

项目中树表实现的要求:添加同级节点行+添加子级节点行+修改+删除,其中未保存前添加节点和修改要能够批量操作,点击提交按钮,前台数据整体提交。PS:范围计划实际编辑中层级和修改会比较多,不能使用弹窗和右键菜单。效果如下:


项目基本框架:Extjs+MVC+SQLServer

Extjs的前台树形表格实现思路:前台使用Extjs的TreePanel控件,前台处理完之后数据整体提交到Controller中,Controller调用BLL层方法处理数据,数据库的操作全部使用存储过程,

Extjs前台树形表的修改+增就同级节点+增子节点的批量操作实现思路:

Step1:使用TreePanel 组件构造出想要的树表(首先得构造一个Store 和Model):

Ext.define('Plan.RangePlan.RangePlanContentMg', {
    extend: 'Ext.tree.Panel',
    alias: 'widget.RangePlanContentMg',
    rootVisible: false,
    border: false,   
    useArrows: true,
    initComponent: function () {
        var me = this;
        var store = Ext.create("Plan.RangePlanStore");
        store.load({
            params: {
                pId: 0
            }
        });
        Ext.apply(me, {
            columnLines: true,
            store: store,
            selModel: {
                selType: 'checkboxmodel',
                singleSelect: true
            },
            plugins: [Ext.create('Ext.grid.plugin.CellEditing', {
                clicksToEdit: 2
            })],
            columns: [{
                xtype: 'rownumberer',
                align: 'center',
                width: 35,
                text: "序号"
                },{
                    xtype: 'treecolumn',
                    header: "模块名称",
                    flex: 1,
                    dataIndex: 'TaskName',
                    sortable: false,
                    width: 100,
                    editor: { xtype: 'textarea', allowBlank: false }
                }, {
                    header: "模块描述",
                    dataIndex: 'TaskDesc',
                    flex: 1,
                    width: 120,
                    editor: { xtype: 'textarea', allowBlank: false }
                }, {
                    header: "交付物",
                    dataIndex: 'DestName',
                    flex: 1,
                    width: 100,
                    editor: { xtype: 'textarea', allowBlank: false }
                }, {
                    header: "验收标注",
                    dataIndex: 'Measurement',
                    flex: 1,
                    width: 100,
                    editor: { xtype: 'textarea', allowBlank: false }
                }, {
                    id:'startime',
                    header: "开始日期",
                    dataIndex: 'StartDate',
                    flex: 1,
                    xtype: 'datecolumn',
                    align: 'center',
                    width: 100,
                    //将日期转化成yyyy/mm/dd格式
                    renderer: Ext.util.Format.dateRenderer(Ext.custom.dateFormat()),
                    editor: {
                        xtype: 'datefield',
                        format: 'y/m/d',
                        width: 100,
                        id: 'StartDate',
                        minValue: new Date(),
                        disabledDays: [0, 6],
                        disabledDaysText: 'Plants are not available on the weekends'
                    }
                }, {
                    header: "结束日期",
                    dataIndex: 'EndDate',
                    flex: 1,
                    xtype: 'datecolumn',
                    align: 'center',
                    width: 100,
                    //将日期转化成yyyy/mm/dd格式
                    renderer: Ext.util.Format.dateRenderer(Ext.custom.dateFormat()),
                    editor: {
                        xtype: 'datefield',
                        format: 'y/m/d',
                        width: 100,
                        id: 'EndDate',
                        minValue: new Date(),
                        disabledDays: [0, 6],
                        disabledDaysText: 'Plants are not available on the weekends'
                    }
                   
                },
            {
                header: "状态",
                flex: 1,
                dataIndex: 'Status',
                width: 70,
                editor: { xtype:  'combo', allowBlank: false }
            },
            {
                header: "计划类型",
                flex: 1,
                dataIndex: 'ApprovalStatus',
                width: 70,
                editor: { xtype: 'combo', allowBlank: false }
            },
            {
                header: "批注",
                flex: 1,
                dataIndex: 'Remark',
                width: 100,
                editor: { xtype: 'textarea', allowBlank: false }
            }],
            dockedItems: [{
                xtype: 'toolbar',
                dock: 'top',
                items: [{
                    xtype: 'button',
                    text: '添加同级节点',
                    iconCls: 'add',
                    tag: 'add',
                    handler: me.onAddRange
                }, '-', {
                    xtype: 'button',
                    text: '添加子级节点',
                    iconCls: 'add',
                    tag: 'addsub',
                    handler: me.onAddSubRange
                }, '-', {
                    xtype: 'button',
                    text: '修改',
                    disabled: true,
                    iconCls: 'edit',
                    tag: 'edit',
                    handler: me.onEditRange
                }, '-', {
                    xtype: 'button',
                    text: '删除',
                    iconCls: 'delete',
                    tag: 'delete',
                    handler: me.onDeleteRange
                }, '-', {
                    xtype: 'button',
                    text: "保存",
                    iconCls: 'save',
                    tag: 'save',
                    handler: me.onSaveRange
                }, '-', {
                    xtype: 'button',
                    text: '提交',
                    disabled:true,
                    iconCls: 'export',
                    tag: 'submit',
                    handler: me.onSubmitRange
                }]
            }]
        });
        me.callParent(arguments);
    },

Step2:前台Js文件中写上各个按钮的Handler与上面的相呼应:

 //添加同级节点
    onAddRange: function (btn) {
        var grid = btn.up('RangePlanContentMg');
        var treeStore = grid.getStore();
        var node = grid.getSelectionModel().getSelection()[0];
        var pn = node.parentNode;
        var id = node.parentNode.get("SeqId");
        var data = {
            "SeqId":null,
            "ParentSeqId": node.parentNode.get("SeqId"),
            "TaskName": null,
            "TaskDesc": null,
            "DestName": null,
            "Measurement": null,
            "StartDate": null,
            "EndDate": null,
            "Status": null,
            "ApprovalStatus": null,
            "Remark": null,
            "leaf": true
        };
        var rec = Ext.create('Plan.RangePlanModel', data);
        node.set('leaf', true);
        pn.appendChild(rec);        
    },


    //添加子级节点
    onAddSubRange: function (btn) {
        var grid = btn.up('RangePlanContentMg');
        var node = grid.getSelectionModel().getSelection()[0];
        var treeStore = grid.getStore();
        var id = node.get('SeqId');
        var data = {
            "SeqId": null,
            "ParentSeqId": node.get('SeqId'),
            "TaskName": null,
            "TaskDesc": null,
            "DestName": null,
            "Measurement": null,
            "StartDate": null,
            "EndDate": null,
            "Status": null,
            "ApprovalStatus": null,
            "Remark": null,
            "leaf": true
        };
        var rec = Ext.create('Plan.RangePlanModel', data);
        node.set("leaf", false);
        node.appendChild(rec);
        node.expand();
    },


    //根据选中行进行编辑修改
    onEditRange:function (btn) {
        var grid = btn.up('RangePlanContentMg');
        var records = grid.getSelectionModel().getSelection();
        //var data = grid.getStore().getById(records[records.length - 1].internalId);
        var data = grid.getStore().getById(records[records.length - 1].get("SeqId"));
        if (records.length == 0) {
            Ext.Msg.Show(iGeneral.iSeleteNoneItem, iGeneral.iNote);
            return false;
        }
        else (records.length != 0)
        {
            Ext.create('SMS.PostInfoWindow', {
                edRecord: data,
                edit: true,
                title: iSMS_Post.iEditTitle,
                grid: grid
            }).show();
        }
        grid.getStore().reload();
    },


    //根据选中节点获取Id进行删除
    onDeleteRange: function (btn) {
        var grid = btn.up('RangePlanContentMg');
        var rows = grid.getSelectionModel().getSelection()[0];
        var pn = rows.parentNode;
        Ext.MessageBox.confirm(iGeneral.iNote, '您确认要删除吗?', function (btn) {
            if (btn == "yes") {
                Ext.Ajax.request({
                    url: '../RangePlan/DeleteRangePlan',
                    params: { seqid: rows.get('SeqId') },
                    success: function (response) {
                        pn.removeChild(rows);
                        if (!pn.hasChildNodes()) {
                            pn.set('leaf', true);
                        }
                        grid.store.reload();
                        grid.getSelectionModel().selectNext();  //删除后,默认选择下一行.
                        Ext.custom.msg('提示:', '删除成功!', 2000);
                    },
                    failure: function (response) {
                        var errorMsg = Ext.decode(response.responseText).Error;
                        Ext.Msg.alert("Error", errorMsg);
                    }


                });
            }
        });
    },


    ///将前台页面的数据保存到后台
    onSaveRange: function (btn) {
        var grid = btn.up('RangePlanContentMg');
        var store = grid.store.tree.root;
        var dataList = new Array();
        var j = 0;
        dataList = getChildNotes(store);        
        function getChildNotes(node) {
            for (var i = 0; i < node.childNodes.length; i++) {
                var records = node.childNodes[i];
                    var data = {
                        "SeqId": records.data.SeqId,
                        "ProjectId": records.data.ProjectId,
                        "ParentSeqId": records.data.ParentSeqId,
                        "ItemId": records.data.ItemId,
                        "TaskName": records.data.TaskName,
                        "TaskDesc": records.data.TaskDesc,
                        "DestName": records.data.DestName,
                        "Measurement": records.data.Measurement,
                        "StartDate": records.data.StartDate,
                        "EndDate": records.data.EndDate,
                        "Status": records.data.Status,
                        "IsNew": records.data.IsNew,
                        "ApprovalStatus": records.data.ApprovalStatus,
                        "Remark": records.data.Remark,
                        "CreatedTime": records.data.CreatedTime,
                        "CreatedUserId": records.data.CreatedUserId,
                        "ApprovalRemak": records.data.ChangeApprovalRemark,
                        "ChangeApprovalRemark": records.data.ChangeApprovalRemark,
                        "Remark": records.data.Remark,
                        "leaf": true
                    };
                    dataList[j] = data;
                    j++;
                    getChildNotes(node.childNodes[i]);
            }
            return (dataList);
        }


        Ext.Ajax.request({
            url: '../RangePlan/SaveRange',
            params: {
                rangeStr: Ext.encode(dataList)
            },
            method: 'POST',
            success: function (response) {
                var params = Ext.decode(response.responseText);
                grid.store.reload();
                Ext.custom.msg('提示:', '保存成功!', 2000);
            },
            failure: function (response) {
                var errorMsg = Ext.decode(response.responseText).Error;
                Ext.Msg.alert("Error", errorMsg);
            }
        });
       
    },

Step3:前台数据的删除是直接删除数据库中数据,添加和修改操作可以批量进行,点击保存之后前台的数据一起在onSaveRange中传到Ctrollers中 :

   /// <summary>
        /// 通过前台选中SeqId删除选中数据项
        /// </summary>
        /// <returns></returns>
        public JsonResult DeleteRangePlan(int seqid)
        {
            string errMsg;
            var obj = new Modeltb_Plan_Range
            {
                //SPReturnType = AppEnum.SPReturnTypes.DataSet,
                SeqId = seqid
            };
            Blltb_Plan_Range.Delete(obj, out errMsg);
            return Json(new { success = true }, JsonRequestBehavior.AllowGet);
        }


        /// <summary>
        /// 保存前台修改和增加节点操作之后的数据
        /// </summary>
        /// <param name="rangeStr"></param>
        /// <returns></returns>
        public JsonResult SaveRange(string rangeStr)
        {   
            string errMsg;
            IList<Modeltb_Plan_Range> lstPosts = JSONUtil.JsonToObject(rangeStr, typeof(IList<Modeltb_Plan_Range>)) as IList<Modeltb_Plan_Range>;
            foreach (Modeltb_Plan_Range item in lstPosts)
           {
                var obj = new Modeltb_Plan_Range
                {
                    SeqId = item.SeqId,
                    ProjectId = item.ProjectId,
                    ItemId = item.ItemId,
                    ParentSeqId = item.ParentSeqId,
                    TaskName = item.TaskName,
                    TaskDesc = item.TaskDesc,
                    DestName = item.DestName,
                    Measurement = item.Measurement,
                    StartDate = item.StartDate,
                    EndDate = item.EndDate,
                    Status = item.Status,
                    IsNew =item.IsNew,
                    ApprovalStatus = item.ApprovalStatus,
                    Remark = item.Remark,
                    CreatedTime = item.CreatedTime,
                    CreatedUserId = item.CreatedUserId,
                    ApprovalRemak = item.ApprovalRemak,
                    ChangeRemark = item.ChangeRemark
                };
                if (item.SeqId != 0)
                {
                    Blltb_Plan_Range.UpdateUnique(obj, out errMsg);
                }
                else {
                    Blltb_Plan_Range.InsertUnique(obj, out errMsg);
                }
            }
            return Json(new { success = true }, JsonRequestBehavior.AllowGet);
        }

Step4:Controller中根据前台传过来的SeqId判断某条数据是修改还是添加的节点,然后调用不同的BLL层处理数据。

 /// Insert Unique Data 
        /// </summary> 
        /// <param name="obj">Tabletb_Plan_Range Model</param> 
        /// <param name="errMsg">错误信息</param> 
        /// <returns>long</returns> 
        public static long InsertUnique(Modeltb_Plan_Range obj, out string errMsg) 
        {
            object returnObj = MainDal.DoDal(obj, "Tabletb_Plan_Range", new List<object> { SPActionstb_Plan_Range.Unique, SPActionstb_Plan_Range.Insert }, out errMsg); 
            if (!string.IsNullOrEmpty(errMsg)) 
            {
                return -1;
            }
            return Convert.ToInt64(returnObj);
        }


        /// <summary> 
        /// Update Unique Data 
        /// </summary> 
        /// <param name="obj">Tabletb_Plan_Range Model</param> 
        /// <param name="errMsg">错误信息</param> 
        public static void UpdateUnique(Modeltb_Plan_Range obj, out string errMsg) 
        {
            MainDal.DoDal(obj, "Tabletb_Plan_Range", new List<object> { SPActionstb_Plan_Range.Unique, SPActionstb_Plan_Range.Update }, out errMsg); 
        }


        /// <summary> 
        /// Delete Data 
        /// </summary> 
        /// <param name="obj">Tabletb_Plan_Range Model</param> 
        /// <param name="errMsg">错误信息</param> 
        public static void Delete(Modeltb_Plan_Range obj, out string errMsg) 
        {
            MainDal.DoDal(obj, "Tabletb_Plan_Range", new List<object> { SPActionstb_Plan_Range.Delete }, out errMsg); 
        }

提供了部分代码,这样一个前台树形表的批量操作就可以实现了。



0 0
原创粉丝点击