BOM树的构造

 

 

物料清单是是描述企业产品组成的技术文件。在加工资本式行业,它表明了产品的总装件、分装件、组件、部件、零件、直到原材料之间的结构关系,以及所需的数量。在化工、制药和食品行业产品组成则对主要原料、中间体、辅助材料及其配方和所需数量的说明。BOM是将用图表示的产品组成改用数据表格的形式表示出来,它是MRPII系统中计算MRP过程中的重要控制文件。

    ERP系统需求。本次版本的所有功能需求都是建立在老版本ERP之上的,所以本文档的功能需求以及业务逻辑完全COPY原来版本,而修改的是实现方式。

树的设计

首先,新建一个物料清单(以下简称BOM)的时候,我们设计的页面是左边的树结构没有数据,而在一张BOM单据保存建立之后,相应的页面左边的树结构将会把本BOM所对应的BOM母件和子件以及子件的BOM信息数据加载过来,并且在页面的左下部其BOM单据的母件图片也会显示出来(如图示12)。

 

图示1BOM新建时的页面显示状态)

 

图示2BOM保存后生成单据后页面树结构显示状态)

 

   另外,我们要在这里分析以下这个数的数据结构。首先从图示2中可以看到BOM树的根节点的文本是母件的品名和BOM版本号拼接起来的一个文本字符串,而子节点的文本是当前BOM下的所有子件品名信息,但是其中的子件文本信息还是有条件的显示的。如果这个子件单纯的是个子件的话,那就把子件品名信息文本显示出来就行了,且没有下级结点;而当该子件本身是一个BOM的是时候我们要分两种情况来判断他在当前BOM的显示状态,即:如果该子件的BOM有多个版本(两个或两个以上版本)的话,子件的显示状态是显示子件品名文本且该子节点有下级结点,那么这个子件的下级结点应该是该子件所有不同版本BOM的信息(该子件BOM信息也是由子件名称和相应的版本号拼接起来的);而如果该子件BOM只有一个版本的话呢,我们只需要把该子件BOM信息(由子件名称和相应的版本号拼接起来的文本)替代该子件的品名来显示(图示2就是这种情况)。

树的代码实现

首先,在ASPX页面上要用到EXT中的TreePanel控件,这个控件的属性以及相关事件的代码截图如:

图示2

从上面的截图看到,这棵树的根节点是一个异步树节点,而且在这个树控件上次根节点默认为不显示的;另外,在这棵树中好定义了一个BeforeLoad监听事件,这个事件的作用是加载当前树节点中其子节点的数据,而且吧这些数据装载到这棵树中。具体代码如下:

function nodeLoad(node) {//参数node是当前展开的节点对象

    var billid = document.getElementById('txtIdentityID').value;//BOM单据的BillID

    if (billid > 0) {

        var splitIndex = node.id.indexOf("_");//请注意树节点的数据结构:

        if (splitIndex == -1) {

//发送一次请求到服务器端进行数据处理

            Ext.net.DirectMethods.NodeLoad(billid, node.id, {

                success: function(result) {

                    var data = eval("(" + result + ")");

                    node.loadNodes(data);

                },

                failure: function(errorMsg) {

                    Ext.Msg.alert('Failure', errorMsg);

                }

            });

        }

        else {

            var splitstr = node.id.split("_");

            if (splitstr[0] == "1") {

//发送一次请求到服务器端进行数据处理

                Ext.net.DirectMethods.AddSubModules(splitstr[1], {

                    success: function(result) {

                        var data = eval("(" + result + ")");

                        node.loadNodes(data);

                    },

                    failure: function(errorMsg) {

                        Ext.Msg.alert('Failure', errorMsg);

                    }

                });

            }

            if (splitstr[0] == '11') {

//发送一次请求到服务器端进行数据处理

                Ext.net.DirectMethods.NodeLoad(splitstr[1], splitstr[1], {

                    success: function(result) {

                        var data = eval("(" + result + ")");

                        node.loadNodes(data);

                    },

                    failure: function(errorMsg) {

                        Ext.Msg.alert('Failure', errorMsg);

                    }

                });

            }

        }

    }

}

可以看到在这个方法中,有几次条件判断以及在不同条件下执行了不同的请求;这些条件是通过树节点的nodeId来建立的,nodeId的数据结构是这样子的:DOM根节点(DOM母件节点)的nodeID是此BOM单据的ID,而其子节点的nodeID是有多个字符串拼接起来的,具体可以看一下下面的服务器端代码(注意红色标记部分):

    #region 绑定Bom清单

    [DirectMethod]

    public string NodeLoad(int BomID, int nodeID)

    {

        string companyCD = ((UserInfoUtil)SessionUtil.Session["UserInfo"]).CompanyCD;

        BomModel model = new BomModel();

        model.CompanyCD = companyCD;

        model.ID = BomID;

        DataTable dt = BomBus.GetBomsInfoByID(model);

        Ext.Net.TreeNodeCollection nodes = new Ext.Net.TreeNodeCollection();

        if (dt.Rows.Count > 0)

        {

            string Bom_Nodeid = dt.Rows[0]["ID"].ToString();

            string strDateTime = DateTime.Now.ToString("yyyyMMddhhmmss");

            if (nodeID == 0)

            {

                Ext.Net.AsyncTreeNode asyncNode = new AsyncTreeNode();

                if (!string.IsNullOrEmpty(dt.Rows[0]["Verson"].ToString()))

                {

                    asyncNode.Text = dt.Rows[0]["ProductName"].ToString() + "(" + dt.Rows[0]["Verson"].ToString() + ")";

                }

                else

                {

                    asyncNode.Text = dt.Rows[0]["ProductName"].ToString();

                }

                asyncNode.NodeID = dt.Rows[0]["ID"].ToString();//BOM根节点的NODEID

                asyncNode.Listeners.Click.Handler = "LoadBomInfo(" + asyncNode.NodeID.ToString() + ",'checktree')";

                nodes.Add(asyncNode);

            }

            else

            {

                foreach (DataRow row in dt.Select("ID='0'"))

                {

                    Ext.Net.AsyncTreeNode asyncSubNode = new AsyncTreeNode();

                    if (row["IsBasicBom"].ToString() == "0")

                    {

                        asyncSubNode.Text = row["ProductName"].ToString();

                        asyncSubNode.NodeID = "0_" + row["ProductID"].ToString() + "_" + Bom_Nodeid + "_" + strDateTime;//一个子节点的NODEID

                        asyncSubNode.Leaf = true;

                        asyncSubNode.Listeners.Click.Handler = "LoadBomInfo(" + Bom_Nodeid.ToString() + ",'checktree')";

                    }

                    else

                    {

                        BomModel model1 = new BomModel();

                        model1.CompanyCD = companyCD;

                        model1.ProductID = row["ProductID"].ToString();

 

                        DataTable dt1 = BomBus.GetBomsByProductID(model1);

                        if (dt1.Rows.Count == 1)

                        {

                            if (!string.IsNullOrEmpty(dt1.Rows[0]["Verson"].ToString()))

                            {

                                asyncSubNode.Text = dt1.Rows[0]["ProductName"].ToString() + "(" + dt1.Rows[0]["Verson"].ToString() + ")";

                            }

                            else

                            {

                                asyncSubNode.Text = dt1.Rows[0]["ProductName"].ToString();

                            }

                            asyncSubNode.NodeID = "11_" + dt1.Rows[0]["ID"].ToString() + "_" + strDateTime;//子节点的NODEID

                            asyncSubNode.Listeners.Click.Handler = "LoadBomInfo(" + dt1.Rows[0]["ID"].ToString() + ",'checktree')";

                        }

                        else

                        {

                            asyncSubNode.Text = row["ProductName"].ToString();

                            asyncSubNode.NodeID = "1_" + row["ProductID"].ToString() + "_" + Bom_Nodeid + "_" + strDateTime;子节点的NODEID

 

                            asyncSubNode.Listeners.Click.Handler = "LoadBomInfo(" + Bom_Nodeid.ToString() + ",'checktree')";

                        }

                    }

                    nodes.Add(asyncSubNode);

                }

            }

        }

        return nodes.ToJson();

    }

    //递归

    [DirectMethod]

    public string AddSubModules(string productid)

    {

        string companyCD = ((UserInfoUtil)SessionUtil.Session["UserInfo"]).CompanyCD;

        Ext.Net.TreeNodeCollection nodes = new Ext.Net.TreeNodeCollection();

        string strDateTime = DateTime.Now.ToString("yyyyMMddhhmmss");

 

        BomModel model = new BomModel();

        model.CompanyCD = companyCD;

        model.ProductID = productid;

 

        DataTable dt = BomBus.GetBomsByProductID(model);

        //DataRow[] rows = userModules.Select("SuperDeptID = '" + moduleId + "'");

        foreach (DataRow row in dt.Rows)

        {

            Ext.Net.AsyncTreeNode asyncNode = new Ext.Net.AsyncTreeNode();

            if (!string.IsNullOrEmpty(row["Verson"].ToString()))

            {

                asyncNode.Text = row["ProductName"].ToString() + "(" + row["Verson"].ToString() + ")";

            }

            else

            {

                asyncNode.Text = row["ProductName"].ToString();

            }

            asyncNode.NodeID = "11_" + row["ID"].ToString() + "_" + strDateTime;

            asyncNode.Listeners.Click.Handler = "LoadBomInfo(" + row["ID"].ToString() + ",'checktree')";

            nodes.Add(asyncNode);

        }

        return nodes.ToJson();

    }

    #endregion

这些红色字体标记部分就是通过“标记_子件物品ID或子件BOMID_当前时间”的格式拼接起来的,这样的拼接可以保证个节点的NODEID是不一样的,并且“标记”元素的设计可以在JS的方法nodeLoad()中作为很好的判断条件,这个标记是这样设计的:当子件不是BOM时,标记=0;当子件只有一个版本BOM时,标记=11 而当子件有多个版本的BOM时,标记=1

    我们接着看上面这段代码。这段代码是获取DOM树中数据的一个方法,是和JS中的方法nodeLoad()相关联的,且看上面两段代码(jscs两部分代码)中标记为绿色字体部分,这部分代码是关联在一起的,首先在一定条件下JS端(浏览器端)可以分别通过一个请求直接调用了CS代码中的NodeLoad(int BomID, int nodeID)方法或者string AddSubModules(string productid)方法,这两个CS中的代码使用递归的方式来获取所需数据,之后返回到JS端(浏览器端)使其接收到数据后,使用node.loadNodes(data);来给树添加数据。

 

至此,整个BOM树的数据处理过程基本已经结束。其中的关键是对这棵树结构的理解。

 

原文地址:https://www.cnblogs.com/xinzeda/p/2161903.html