Browse Source

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

zhangweicheng 7 years ago
parent
commit
17b47736b8

+ 152 - 79
web/building_saas/main/js/models/calc_program.js

@@ -6,7 +6,8 @@
  *  用到费率的规则必须有feeRateID属性,当有该属性时,会自动显示费率值。
  */
 
-/*let defaultBillTemplate = {
+/*  新版GLD 取消了默认清单模板,所以这里废弃。先留着,预防不时之需。
+let defaultBillTemplate = {
     ID: 15,
     name: "清单公式",
     calcItems: [
@@ -430,26 +431,74 @@ let treeNodeTools = {
         return nodes;
     },
 
-    isRation: function(treeNode){
-        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.ration;
+    isBill: function(treeNode){
+        return treeNode.sourceType === ModuleNames.bills;
     },
-
     isLeafBill: function(treeNode){
-        return treeNode.sourceType === projectObj.project.Bills.getSourceType() &&
+        return treeNode.sourceType === ModuleNames.bills &&
             treeNode.source.children &&
             treeNode.source.children.length === 0;
     },
-
     isNullBill: function (treeNode) {
         return this.isLeafBill(treeNode) && (treeNode.children.length === 0) && (!treeNode.data.calcBase);
     },
 
+    isRationCategory: function(treeNode){
+        return treeNode.sourceType === ModuleNames.ration;
+    },
+    isRation: function(treeNode){
+        return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.ration;
+    },
     isVolumePrice: function (treeNode) {
         return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.volumePrice;
     },
-
     isGljRation: function (treeNode) {
         return treeNode.sourceType === ModuleNames.ration && treeNode.data.type === rationType.gljRation;
+    },
+
+    initFeeField(treeNode, fieldName){
+        if (!treeNode.data.fees) {
+            treeNode.data.fees = [];
+            treeNode.data.feesIndex = {};
+        };
+        if (!treeNode.data.feesIndex[fieldName]) {
+            let fee = {
+                'fieldName': fieldName,
+                'unitFee': 0,
+                'totalFee': 0,
+                'tenderUnitFee': 0,
+                'tenderTotalFee': 0
+            };
+            treeNode.data.fees.push(fee);
+            treeNode.data.feesIndex[fieldName] = fee;
+        };
+    },
+
+    getCalcType(treeNode) {
+        if (this.isRationCategory(treeNode)){
+            return treeNodeCalcType.ctRationCalcProgram;
+        }
+        else if (this.isNullBill(treeNode)){
+            return treeNodeCalcType.ctCommonUnitFee;
+        }
+        else if (this.isLeafBill(treeNode)) {
+            if (treeNode.children && treeNode.children.length > 0){
+                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
+                if (projectObj.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
+                    return treeNodeCalcType.ctBillCalcProgram;
+                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
+                    return treeNodeCalcType.ctGatherRationsFees;
+            }
+            else{                                          // 公式计算
+                return treeNodeCalcType.ctCalcBaseValue;
+            };
+        }
+        else if (this.isBill(treeNode)) {                              // 父清单:汇总子清单的费用类别
+            return treeNodeCalcType.ctGatherBillsFees;
+        }
+        else {
+            return treeNodeCalcType.ctRationCalcProgram;
+        };
     }
 };
 
@@ -463,18 +512,18 @@ class CalcProgram {
 
     getSourceType () {
         return ModuleNames.calc_program;
-    };
+    };    // 兼容Project框架方法
 
     loadData (datas) {
         this.datas = datas;
         this.compileAllTemps();
-    };
+    };   // 兼容Project框架方法
 
     doAfterUpdate (err, data) {
         if(!err){
             $.bootstrapLoading.end();
         }
-    };
+    };  // 兼容Project框架方法
 
     // 经测试,全部编译一次耗时0.003~0.004秒。耗时基本忽略不计。
     compileAllTemps(){
@@ -648,28 +697,14 @@ class CalcProgram {
         };
     };
 
-    initFeeField(treeNode, fieldName){
-        if (!treeNode.data.fees) {
-            treeNode.data.fees = [];
-            treeNode.data.feesIndex = {};
-        };
-        if (!treeNode.data.feesIndex[fieldName]) {
-            let fee = {
-                'fieldName': fieldName,
-                'unitFee': 0,
-                'totalFee': 0,
-                'tenderUnitFee': 0,
-                'tenderTotalFee': 0
-            };
-            treeNode.data.fees.push(fee);
-            treeNode.data.feesIndex[fieldName] = fee;
-        };
-    };
-
   // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
-    InnerCalc(treeNode){
+    innerCalc(treeNode){
         let me = this;
-        let project = me.project;
+        // 仅用作树节点显示的工料机不能参与计算。
+        if (treeNode.sourceType === me.project.ration_glj.getSourceType()) return;
+
+        treeNode.calcType = treeNodeTools.getCalcType(treeNode);
+        // if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue) return;
 
         function initFees(treeNode){
             if (!treeNode.data.fees) {
@@ -711,12 +746,13 @@ class CalcProgram {
             return ['labour', 'material', 'machine', 'mainMaterial', 'equipment'].indexOf(type) > -1;
         };
 
-        // 汇总定额或子清单的费用类别
-        if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees || treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
+        // 父清单汇总子项(定额或子清单)的费用类别
+        if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees ||
+            treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
             treeNode.data.programID = null;
             initFees(treeNode);
 
-            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
+            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? me.project.Ration.getRationsByNode(treeNode) : treeNode.children;
             let rst = [];
             for (let ft of cpFeeTypes) {
                 let ftObj = {};
@@ -798,7 +834,7 @@ class CalcProgram {
 
             delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
             delete treeNode.data.feesIndex;
-            me.initFeeField(treeNode, 'common');
+            treeNodeTools.initFeeField(treeNode, 'common');
             treeNode.data.feesIndex.common.unitFee = uf.toDecimal(decimalObj.bills.unitPrice);
             treeNode.data.feesIndex.common.totalFee = tf.toDecimal(decimalObj.bills.totalPrice);
             treeNode.data.feesIndex.common.tenderUnitFee = tuf.toDecimal(decimalObj.bills.unitPrice);
@@ -806,13 +842,12 @@ class CalcProgram {
             treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
-        // 叶子清单的计算基数计算
+        // 叶子清单公式计算
         else if (treeNode.calcType == treeNodeCalcType.ctCalcBaseValue){
             delete treeNode.data.gljList;
             if (treeNode.data.programID) treeNode.data.programID = null;
 
             let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
-            // let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
             if (!treeNode.data.quantity) treeNode.data.quantity = 1;
             let q = treeNode.data.quantity;
             let b = treeNode.data.calcBaseValue ? treeNode.data.calcBaseValue : 0;
@@ -823,7 +858,7 @@ class CalcProgram {
 
             delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
             delete treeNode.data.feesIndex;
-            me.initFeeField(treeNode, 'common');
+            treeNodeTools.initFeeField(treeNode, 'common');
             treeNode.data.feesIndex.common.unitFee = uf;
             treeNode.data.feesIndex.common.totalFee = tf;
             treeNode.data.feesIndex.common.tenderUnitFee = tuf;
@@ -831,7 +866,7 @@ class CalcProgram {
             treeNode.changed = true;
             treeNode.data.calcTemplate = {"calcItems": []};
         }
-        // 定额或清单自己的计算程序计算
+        // 定额或叶子清单自己的计算程序计算
         else{
             if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
                 if (treeNode.data.type == rationType.volumePrice){
@@ -852,10 +887,9 @@ class CalcProgram {
                 };
             }
             else if (treeNode.calcType == treeNodeCalcType.ctBillCalcProgram) {
-                let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
-                treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
+                let rations = me.project.Ration.getBillsSortRation(treeNode.source.getID());
+                treeNode.data.gljList = me.project.ration_glj.getGatherGljArrByRations(rations);
 
-                // if (treeNode.data.programID == undefined || treeNode.data.programID == defaultBillTemplate.ID){
                 if (treeNode.data.programID == undefined){
                     treeNode.data.programID = projectInfoObj.projectInfo.property.engineering;
                 }
@@ -891,40 +925,60 @@ class CalcProgram {
         };
     };
 
+    /*// 计算公式结点(叶子清单的计算基数计算)。仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
+    innerCalcFormula(treeNode){
+        treeNode.calcType = treeNodeTools.getCalcType(treeNode);
+        if (treeNode.calcType != treeNodeCalcType.ctCalcBaseValue) return;
+
+        let me = this;
+        delete treeNode.data.gljList;
+        if (treeNode.data.programID) treeNode.data.programID = null;
+
+        let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
+        if (!treeNode.data.quantity) treeNode.data.quantity = 1;
+        let q = treeNode.data.quantity;
+        let b = treeNode.data.calcBaseValue ? treeNode.data.calcBaseValue : 0;
+        let uf = (b * f * q / 100).toDecimal(decimalObj.bills.unitPrice);
+        let tuf = uf;
+        let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
+        let ttf = tf;
+
+        delete treeNode.data.fees;    // 直接删掉再新增,不用一个个费判断更新,效率更高。
+        delete treeNode.data.feesIndex;
+        treeNodeTools.initFeeField(treeNode, 'common');
+        treeNode.data.feesIndex.common.unitFee = uf;
+        treeNode.data.feesIndex.common.totalFee = tf;
+        treeNode.data.feesIndex.common.tenderUnitFee = tuf;
+        treeNode.data.feesIndex.common.tenderTotalFee = ttf;
+        treeNode.changed = true;
+        treeNode.data.calcTemplate = {"calcItems": []};
+    };*/
+
     // 计算本节点(默认同时递归计算所有父节点,可选)
     calculate(treeNode, calcParents = true){
         let me = this;
-        if (treeNode.sourceType === me.project.ration_glj.getSourceType()) return;     // 仅用作树节点显示的工料机不能参与计算。
-        let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
-        let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
+        let changedNodes = [];
 
-        if (isRation){
-            treeNode.calcType = treeNodeCalcType.ctRationCalcProgram;
-        }
-        else  if (treeNodeTools.isNullBill(treeNode)){
-            treeNode.calcType = treeNodeCalcType.ctCommonUnitFee;
-        }
-        else if (treeNodeTools.isLeafBill(treeNode)) {
-            if (treeNode.children && treeNode.children.length > 0){
-                // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
-                if (me.project.property.billsCalcMode === leafBillGetFeeType.billsPrice)
-                    treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
-                else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
-                    treeNode.calcType = treeNodeCalcType.ctGatherRationsFees;
-            }
-            else{                                          // 公式计算
-                treeNode.calcType = treeNodeCalcType.ctCalcBaseValue;
-            };
-        }
-        else if (isBill)                                 // 父清单:汇总子清单的费用类别
-            treeNode.calcType = treeNodeCalcType.ctGatherBillsFees;
+        me.innerCalc(treeNode);
 
-        me.InnerCalc(treeNode);
+        if (treeNode.changed) {
+            if (!changedNodes.includes(treeNode)) changedNodes.push(treeNode);
+
+            // 计算父结点
+            if (calcParents){
+                let curNode = treeNode.parent;
+                while (curNode){
+                    me.innerCalc(curNode);
+                    if (curNode.changed && !changedNodes.includes(curNode)) changedNodes.push(curNode);
+                    curNode = curNode.parent;
+                };
+            };
 
-        // 计算所有父结点
-        if (treeNode.changed && calcParents && treeNode.parent) {
-            me.calculate(treeNode.parent);
+            // 父结点算完,再算所有的公式结点(必须先算完父结点,再算公式结点)
+            me.calcFormulaNodes(changedNodes);
         };
+
+        return changedNodes;
     };
 
     // 存储、刷新本节点(默认存储刷新所有父节点,可选)
@@ -1016,20 +1070,32 @@ class CalcProgram {
         return changedNodes;
     };
 
-    // 计算全部公式项
-    calcFormulaNodes(){
-        let nodes = treeNodeTools.getFormulaNodes();
-        if (nodes.length == 0) return;
-        for (let node of nodes){
-              this.calcFormulaNode(node);
+    // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
+    calcFormulaNodes(changedNodesArr){
+        let me = this;
+        let formulaNodes = treeNodeTools.getFormulaNodes();
+        if (formulaNodes.length == 0) return;
+        for (let formulaNode of formulaNodes){
+            formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。
+            projectObj.project.calcBase.calculate(formulaNode, true);
+            if (projectObj.project.calcBase.success){
+                // 计算公式结点
+                me.innerCalc(formulaNode);
+                if (formulaNode.changed && !changedNodesArr.includes(formulaNode)) changedNodesArr.push(formulaNode);
+
+                // 计算父结点
+                if (formulaNode.changed){
+                    let curNode = formulaNode.parent;
+                    while (curNode){
+                        me.innerCalc(curNode);
+                        if (curNode.changed && !changedNodesArr.includes(curNode)) changedNodesArr.push(curNode);
+                        curNode = curNode.parent;
+                    };
+                };
+            };
         };
     };
 
-    // 计算公式项。(它一定是叶子结点,它的父结点一定没有公式)
-    calcFormulaNode(treeNode){
-        // do
-    };
-
     // 计算叶子清单下的所有子结点(如定额、量价、工料机定额等), 并计算自身和所有父结点。最后打包存储。
     calcLeafAndSave(treeNode){
         let me = this;
@@ -1074,4 +1140,11 @@ class CalcProgram {
         me.saveNodes(changedNodes);
     };
 
+    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。
+    // 这个方法实际上封装了calculate()和saveNodes()两个方法,方便外部调用,少写一点代码。
+    calcAndSave(treeNode){
+        let changedNodes = this.calculate(treeNode);
+        this.saveNodes(changedNodes);
+    };
+
 }

+ 1 - 2
web/building_saas/main/js/models/fee_rate.js

@@ -348,8 +348,7 @@ var FeeRate = {
                     var rate =me.getFeeRateByID(bill.feeRateID);
                     var data=me.getfbUpdateData(rate,bill,fee_value,value);
                     if(data==null){//只更改清单的值的情况下,由计算程序更新
-                        project.calcProgram.calculate(node);
-                        project.calcProgram.saveNode(node);
+                        project.calcProgram.calcAndSave(node);
                     }
                     this.setFeeRateToBill(data,function (result) {
                         if(data.hasOwnProperty('feeRate')){

+ 2 - 4
web/building_saas/main/js/models/quantity_detail.js

@@ -587,8 +587,7 @@ var quantity_detail = {
                 project.calcProgram.calcRationsAndSave(needUpdateChildren);
             }else {
                 node.changed = true;
-                project.calcProgram.calculate(node);
-                project.calcProgram.saveNode(node);
+                project.calcProgram.calcAndSave(node);
             }
             if(gljNodes.length>0){
                 projectObj.mainController.refreshTreeNode(gljNodes);
@@ -607,8 +606,7 @@ var quantity_detail = {
             value = scMathUtil.roundForObj(value,decimalObj.decimal("quantity",node))
             node.data.quantity=value;
             node.changed = true;
-            project.calcProgram.calculate(node);
-            project.calcProgram.saveNode(node);
+            project.calcProgram.calcAndSave(node);
             projectObj.mainController.refreshTreeNode(node.children);//刷新子工料机总消耗量
             gljOprObj.showRationGLJSheetData();
         };

+ 1 - 1
web/building_saas/main/js/views/calc_base_view.js

@@ -136,7 +136,7 @@ let calcBaseView = {
         }
         me.buildSheet();
         let baseObj = projectObj.project.calcBase.getBaseByClass(node);
-        console.log(baseObj);
+        // console.log(baseObj);
         me.showData(me.toViewData(baseObj));
 
     },

+ 1 - 2
web/building_saas/main/js/views/calc_program_view.js

@@ -43,8 +43,7 @@ let calcProgramObj = {
         var me = this;
         me.treeNode = treeNode;
         if (needCalc){
-            projectObj.project.calcProgram.calculate(treeNode);
-            projectObj.project.calcProgram.saveNode(treeNode);
+            projectObj.project.calcProgram.calcAndSave(treeNode);
         };
         me.datas = treeNode.data.calcTemplate ? treeNode.data.calcTemplate.calcItems : [];
         sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);

+ 1 - 2
web/building_saas/main/js/views/fee_rate_view.js

@@ -652,8 +652,7 @@ var feeRateObject={
             selected.data.feeRateID=rate.ID.toString();
             selected.data.feeRate=scMathUtil.roundToString(rate.rate,getDecimal("feeRate"));
             selected.changed = true;
-            projectObj.project.calcProgram.calculate(selected);
-            projectObj.project.calcProgram.saveNode(selected);
+            projectObj.project.calcProgram.calcAndSave(selected);
             //projectObj.mainController.refreshTreeNode([selected]);
             $("#fee_rate_tree").modal('hide');
         });

+ 3 - 5
web/building_saas/main/js/views/project_view.js

@@ -304,12 +304,11 @@ var projectObj = {
                 };
                 node.changed = true;
                 if (fieldName == 'feesIndex.common.unitFee'){
-                    project.calcProgram.initFeeField(node, 'common');
+                    treeNodeTools.initFeeField(node, 'common');
                     node.data.feesIndex.common.unitFee = value;
                 }
                 else node.data[fieldName] = value;
-                project.calcProgram.calculate(node);
-                project.calcProgram.saveNode(node);
+                project.calcProgram.calcAndSave(node);
                 gljOprObj.showRationGLJSheetData();
             }
             else {
@@ -663,8 +662,7 @@ var projectObj = {
             this.project.Bills.updateNodes(nodes, true);
             calc = null;
         }*/
-        projectObj.project.calcProgram.calculate(node);
-        projectObj.project.calcProgram.saveNode(node);
+        projectObj.project.calcProgram.calcAndSave(node);
     },
     // 计算全部清单
 /*    calculateAll: function () {