Browse Source

算法结构大调整。

Chenshilong 7 years ago
parent
commit
3fe112f2c3
2 changed files with 140 additions and 195 deletions
  1. 121 77
      public/calc_util.js
  2. 19 118
      web/building_saas/main/js/models/calc_program.js

+ 121 - 77
public/calc_util.js

@@ -4,14 +4,6 @@
  * added by CSL, 2017-09-01 增加公式解析对象analyzer,用于解析用户修改公式、自定义表达式。
  */
 
-// 需求说小数位数固定为2位,这里预留缓冲接口,防止以后需求变卦。
-const Digit_Calc_Program = -2;              // 需求指定计算程序用到的小数位数。
-const Digit_Calc_Program_Default = -6;      // 需求末指定时默认用到的小数位数。
-function round(value, useDef = false) {
-    let digit = useDef ? Digit_Calc_Program_Default : Digit_Calc_Program;
-    return scMathUtil.roundTo(value, digit);
-};
-
 let executeObj = {
     treeNode: null,
     template: null,
@@ -52,12 +44,12 @@ let executeObj = {
                                if (base.gljTypes.indexOf(md.glj_type) >= 0) {
                                    price = md["base_price"];
                                    if (!price) price = 0;
-                                   mdSum = mdSum +  round(md["consumption"] * price);
-                                   mdSum = round(mdSum, true);
+                                   mdSum = mdSum + (md["consumption"] * price).toDecimal(me.digit);
+                                   mdSum = (mdSum).toDecimal(me.digitDefault);
                                }
                            };
-                           tmpSum = tmpSum + round(glj["quantity"] * mdSum, true);
-                           tmpSum = round(tmpSum, true);
+                           tmpSum = tmpSum + (glj["quantity"] * mdSum).toDecimal(me.digitDefault);
+                           tmpSum = (tmpSum).toDecimal(me.digitDefault);
                        }
                 };
             }else{
@@ -74,12 +66,13 @@ let executeObj = {
                             price = mprice - aprice;
                         };
                         if (!price) price = 0;
-                        tmpSum = round(tmpSum + round(glj["quantity"] * price, true), true);
+                        tmpSum = tmpSum + (glj["quantity"] * price).toDecimal(me.digitDefault);
+                        tmpSum = (tmpSum).toDecimal(me.digitDefault);
                     };
                 };
             };
 
-            rst = round(tmpSum);
+            rst = (tmpSum).toDecimal(me.digitDefault);
         };
 
         return rst;
@@ -242,6 +235,8 @@ class Calculation {
         me.compiledFeeTypeNames = [];
         me.compiledCalcBases = {};
         me.saveForReports = [];
+        me.digit = 2;
+        me.digitDefault = 6;
 
         let private_compile_feeRateFile = function() {
             if (feeRates) {
@@ -392,81 +387,130 @@ class Calculation {
         };
     };
 
-    calculate(treeNode){
-        let me = this;
-        let templateID = treeNode.data.programID;
-        if (!templateID) templateID = 1;
-        let template = me.compiledTemplates[templateID];
-        treeNode.data.calcTemplate = template;
+    initFees(treeNode){
+        if (!treeNode.data.fees) {
+            treeNode.data.fees = [];
+            treeNode.data.feesIndex = {};
+            treeNode.changed = true;
+        };
+    };
 
-        let project = projectObj.project;
+    checkFee(treeNode, feeObj){
+        if (feeObj.fieldName == '') return;
 
-        // 缺省计算程序需要提供总金额作为计算基数,然后每条按比例(费率)计算,不需要工料机明细。
-        if (treeNode.data.baseTotalPrice != undefined){
-            delete treeNode.data.gljList;
+        if (!treeNode.data.feesIndex[feeObj.fieldName]){
+            let fee = {
+                'fieldName': feeObj.fieldName,
+                'unitFee': feeObj.unitFee,
+                'totalFee': feeObj.totalFee,
+                'tenderUnitFee': 0,
+                'tenderTotalFee': 0
+            };
+            treeNode.data.fees.push(fee);
+            treeNode.data.feesIndex[feeObj.fieldName] = fee;
+            treeNode.changed = true;
         }
-        else {
-            if (treeNode.sourceType === project.Ration.getSourceType()) {
-                treeNode.data.gljList = project.ration_glj.getGljArrByRation(treeNode.data.ID);
-            }
-            else if (treeNode.sourceType === project.Bills.getSourceType()) {
-                let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
-                treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
+        else{
+            if (treeNode.data.feesIndex[feeObj.fieldName].unitFee != feeObj.unitFee){
+                treeNode.data.feesIndex[feeObj.fieldName].unitFee = feeObj.unitFee;
+                treeNode.changed = true;
             };
-        };
-
-        if (treeNode && template.hasCompiled) {
-            let $CE = executeObj;
-            $CE.treeNode = treeNode;
-            $CE.template = template;
-            $CE.calcBase = me.compiledCalcBases;
 
-            if (!treeNode.data.fees) {
-                treeNode.data.fees = [];
-                treeNode.data.feesIndex = {};
+            if (treeNode.data.feesIndex[feeObj.fieldName].totalFee != feeObj.totalFee){
+                treeNode.data.feesIndex[feeObj.fieldName].totalFee = feeObj.totalFee;
                 treeNode.changed = true;
             };
+        };
+    };
 
-            for (let idx of template.compiledSeq) {
-                let calcItem = template.calcItems[idx];
-
-                let feeRate = calcItem.feeRate;
-                if (!feeRate) feeRate = 100;    // 100%
-                calcItem.unitFee = round(eval(calcItem.compiledExpr) * feeRate * 0.01);   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
-
-                let quantity = treeNode.data.quantity;
-                if (!quantity) quantity = 0;
-                calcItem.totalFee = round(calcItem.unitFee * quantity);
-
-                // 费用同步到定额
-                // 引入小麦的字段检测后,快速切换定额出现计算卡顿现象,过多的循环造成。这里把她的代码拆出来,减少微循环。
-                if (calcItem.fieldName != '') {
-                    if (!treeNode.data.feesIndex[calcItem.fieldName]){
-                        let fee = {
-                            'fieldName': calcItem.fieldName,
-                            'unitFee': calcItem.unitFee,
-                            'totalFee': calcItem.totalFee,
-                            'tenderUnitFee': 0,
-                            'tenderTotalFee': 0
-                        };
-                        treeNode.data.fees.push(fee);
-                        treeNode.data.feesIndex[calcItem.fieldName] = fee;
-                        treeNode.changed = true;
-                    }
-                    else{
-                        if (treeNode.data.feesIndex[calcItem.fieldName].unitFee != calcItem.unitFee){
-                            treeNode.data.feesIndex[calcItem.fieldName].unitFee = calcItem.unitFee;
-                            treeNode.changed = true;
-                        };
+    calculate(treeNode){
+        let me = this;
+        let project = projectObj.project;
 
-                        if (treeNode.data.feesIndex[calcItem.fieldName].totalFee != calcItem.totalFee){
-                            treeNode.data.feesIndex[calcItem.fieldName].totalFee = calcItem.totalFee;
-                            treeNode.changed = true;
-                        };
-                    }
+        // 汇总定额或子清单的费用类别
+        if (treeNode.data.gatherType != undefined){
+            if (treeNode.sourceType != project.Bills.getSourceType()) return;
+
+            me.initFees(treeNode);
+
+            let objsArr = (treeNode.data.gatherType === CP_GatherType.rations) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
+            let rst = [];
+            for (let ft of feeType) {
+                let ftObj = {};
+                ftObj.fieldName = ft.type;
+                ftObj.name = ft.name;
+                let uf = 0, tf = 0, tuf = 0, ttf = 0;
+                for (let item of objsArr) {
+                    let data = (treeNode.data.gatherType === CP_GatherType.rations) ? item : item.data;
+                    if (data.feesIndex && data.feesIndex[ft.type]) {
+                        uf = (uf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(me.digitDefault);
+                        tf = (tf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(me.digitDefault);
+                        tuf = (tuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(me.digitDefault);
+                        ttf = (ttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(me.digitDefault);
+                    };
                 };
+                ftObj.unitFee = uf.toDecimal(me.digit);
+                ftObj.totalFee = tf.toDecimal(me.digit);
+                ftObj.tenderUnitFee = tuf.toDecimal(me.digit);
+                ftObj.tenderTotalFee = ttf.toDecimal(me.digit);
+
+                me.checkFee(treeNode, ftObj);
+
+                rst.push(ftObj);
             };
+            treeNode.data.calcTemplate = {"calcItems": rst};
         }
+        else{
+            // 叶子清单的缺省计算程序需要提供总金额作为计算基数(不需要工料机),然后每条按比例(费率)计算,不需要工料机明细。
+            if (treeNode.data.baseTotalPrice != undefined){
+                if (treeNode.sourceType != project.Bills.getSourceType()) return;
+
+                delete treeNode.data.gljList;
+
+                if (treeNode.data.programID == undefined){
+                    treeNode.data.programID = defaultBillTemplate.ID;
+                };
+            }
+            else {
+                if (treeNode.sourceType === project.Ration.getSourceType()) {
+                    treeNode.data.gljList = project.ration_glj.getGljArrByRation(treeNode.data.ID);
+                }
+                else if (treeNode.sourceType === project.Bills.getSourceType()) {
+                    let rations = project.Ration.getBillsSortRation(treeNode.source.getID());
+                    treeNode.data.gljList = project.ration_glj.getGatherGljArrByRations(rations);
+                };
+
+                if (treeNode.data.programID == undefined){
+                    treeNode.data.programID = 1;
+                };
+            };
+
+            let template = me.compiledTemplates[treeNode.data.programID];
+            treeNode.data.calcTemplate = template;
+
+            if (treeNode && template.hasCompiled) {
+                let $CE = executeObj;
+                $CE.treeNode = treeNode;
+                $CE.template = template;
+                $CE.calcBase = me.compiledCalcBases;
+
+                me.initFees(treeNode);
+
+                for (let idx of template.compiledSeq) {
+                    let calcItem = template.calcItems[idx];
+
+                    let feeRate = calcItem.feeRate;
+                    if (!feeRate) feeRate = 100;    // 100%
+                    calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(me.digit);   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
+
+                    let quantity = treeNode.data.quantity;
+                    if (!quantity) quantity = 0;
+                    calcItem.totalFee = (calcItem.unitFee * quantity).toDecimal(me.digit);
+
+                    me.checkFee(treeNode, calcItem);
+                };
+            }
+        };
     }
 };
 

+ 19 - 118
web/building_saas/main/js/models/calc_program.js

@@ -103,8 +103,6 @@ class CalcProgram {
     constructor(project){
         this.project = project;
         this.datas = [];
-        this.digit = 2;
-        this.digitDefault = 6;
         this.calc = new Calculation();
         project.registerModule(ModuleNames.calc_program, this);
     };
@@ -148,7 +146,13 @@ class CalcProgram {
 
     calculate(treeNode){
         let me = this;
+
         me.calc.calculate(treeNode);
+
+        // 还原,防止出现混乱影响下次计算
+        delete treeNode.data.baseTotalPrice;
+        delete treeNode.data.gatherType;
+
         // 存储、刷新本结点、所有父结点
         if (treeNode.changed) {
             me.saveAndCalcParents(treeNode);
@@ -169,110 +173,6 @@ class CalcProgram {
         projectObj.mainController.refreshTreeNode([treeNode]);
     };
 
-    initFees(treeNode){
-        if (!treeNode.data.fees) {
-            treeNode.data.fees = [];
-            treeNode.data.feesIndex = {};
-            treeNode.changed = true;
-        };
-    };
-
-    checkFee(treeNode, ftObj){
-        if (!treeNode.data.feesIndex[ftObj.fieldName]){
-            let fee = {
-                'fieldName': ftObj.fieldName,
-                'unitFee': ftObj.unitFee,
-                'totalFee': ftObj.totalFee,
-                'tenderUnitFee': 0,
-                'tenderTotalFee': 0
-            };
-            treeNode.data.fees.push(fee);
-            treeNode.data.feesIndex[ftObj.fieldName] = fee;
-            treeNode.changed = true;
-        }
-        else{
-            if (treeNode.data.feesIndex[ftObj.fieldName].unitFee != ftObj.unitFee){
-                treeNode.data.feesIndex[ftObj.fieldName].unitFee = ftObj.unitFee;
-                treeNode.changed = true;
-            };
-
-            if (treeNode.data.feesIndex[ftObj.fieldName].totalFee != ftObj.totalFee){
-                treeNode.data.feesIndex[ftObj.fieldName].totalFee = ftObj.totalFee;
-                treeNode.changed = true;
-            };
-        };
-    };
-
-    gatherFeeTypes(treeNode, gatherType){
-        let me = this;
-        let rst = [];
-
-        if (treeNode.sourceType === this.project.Bills.getSourceType()) {
-            me.initFees(treeNode);
-
-            let objsArr = [];
-            if (gatherType == CP_GatherType.rations){
-                objsArr = this.project.Ration.getRationsByNode(treeNode);
-            }else if (gatherType == CP_GatherType.bills){
-                objsArr = treeNode.children;
-            };
-
-            for (let ft of feeType) {
-                let ftObj = {};
-                ftObj.fieldName = ft.type;
-                ftObj.name = ft.name;
-                let uf = 0, tf = 0, tuf = 0, ttf = 0;
-                for (let item of objsArr) {
-                    let data = {};
-                    if (gatherType == CP_GatherType.rations){
-                        data = item;
-                    }else if (gatherType == CP_GatherType.bills){
-                        data = item.data;
-                    };
-                    if (data.feesIndex && data.feesIndex[ft.type]) {
-                        uf = (uf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(me.digitDefault);
-                        tf = (tf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(me.digitDefault);
-                        tuf = (tuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(me.digitDefault);
-                        ttf = (ttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(me.digitDefault);
-                    };
-                };
-                ftObj.unitFee = uf.toDecimal(me.digit);
-                ftObj.totalFee = tf.toDecimal(me.digit);
-                ftObj.tenderUnitFee = tuf.toDecimal(me.digit);
-                ftObj.tenderTotalFee = ttf.toDecimal(me.digit);
-
-                me.checkFee(treeNode, ftObj);
-
-                rst.push(ftObj);
-            };
-
-            if (treeNode.changed) {
-                me.saveAndCalcParents(treeNode);
-                delete treeNode.changed;
-            };
-        };
-
-        return rst;
-    };
-
-    calcDefaultBillTemp(treeNode, totalPrice){
-        let me = this;
-        let rst = [];
-        if (treeNode.sourceType != me.project.Bills.getSourceType()){return rst};
-
-        treeNode.data.baseTotalPrice = totalPrice;
-        treeNode.data.programID = defaultBillTemplate.ID;
-        me.calc.calculate(treeNode);
-
-        if (treeNode.changed) {
-            me.saveAndCalcParents(treeNode);
-            delete treeNode.changed;
-        };
-
-        rst = treeNode.data.calcTemplate.calcItems;
-        return rst;
-    };
-
     getCalcDatas(treeNode){
         let me = this;
         let rst = [];
@@ -281,9 +181,8 @@ class CalcProgram {
         let isLeafBill = isBill && treeNode.source.children && treeNode.source.children.length === 0;
         let isBillPriceCalc = me.project.projSetting.billsCalcMode === billsPrice;
 
-        if (isRation) {                 // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。
-            me.calculate(treeNode);
-            rst = treeNode.data.calcTemplate.calcItems;
+        if (isRation) {
+            //
         }
         else if (isLeafBill) {
             let ct = '';
@@ -300,26 +199,28 @@ class CalcProgram {
             };
 
             if (ct == childrenType.ration){
-                if (isBillPriceCalc){   // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算
-                    me.calculate(treeNode);
-                    rst = treeNode.data.calcTemplate.calcItems;
-                }else{                  // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
-                    rst = me.gatherFeeTypes(treeNode, CP_GatherType.rations);
+                if (isBillPriceCalc){                   // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算
+
+                }
+                else{                                   // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
+                    treeNode.data.gatherType = CP_GatherType.rations;
                 };
             }
             else if (ct == childrenType.volumePrice){
                 let totalPrice = 10000;
-                rst = me.calcDefaultBillTemp(treeNode, totalPrice);
+                treeNode.data.baseTotalPrice = totalPrice;
             }
             else if (ct == childrenType.formula){
                 let totalPrice = 20000;
-                rst = me.calcDefaultBillTemp(treeNode, totalPrice);
+                treeNode.data.baseTotalPrice = totalPrice;
             };
         }
-        else if (isBill){    // 父清单:汇总子清单的费用类别
-            rst = me.gatherFeeTypes(treeNode, CP_GatherType.bills);
+        else if (isBill){                                   // 父清单:汇总子清单的费用类别
+            treeNode.data.gatherType = CP_GatherType.bills;
         };
 
+        me.calculate(treeNode);
+        rst = treeNode.data.calcTemplate.calcItems;
         return rst;
     }
 }