| 
					
				 | 
			
			
				@@ -563,6 +563,32 @@ let calcTools = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (quantity) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return parseFloat(quantity).toDecimal(decimalObj.glj.quantity) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getRationsByProjectGLJ(PGLJID){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let rationIDs = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let RGs = projectObj.project.ration_glj.datas; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let rg of RGs){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (rg.projectGLJID == PGLJID){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                rationIDs.push(rg.rationID); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let rationNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let nodes = projectObj.project.mainTree.nodes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let rID of rationIDs){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            rationNodes.push(nodes['id_' + rID]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return rationNodes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getNodesByProgramID(programID){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let discreteNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let nodes = projectObj.project.mainTree.items; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let node of nodes){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (node.data.programID == programID) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                discreteNodes.push(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return discreteNodes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -751,6 +777,22 @@ let analyzer = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     isLegal: function (dispExpr, itemID, template) {  // 检测包括:无效字符、基数是否中括号、基数是否定义、行引用、循环计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        function testValue(expr){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                expr = expr.replace(/\[[\u4E00-\u9FA5]+\]/gi, '0'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                expr = expr.replace(/@\d+/gi, '0'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (expr.includes('00')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                eval(expr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch (err) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let me = analyzer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let expr = me.standard(dispExpr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let invalidChars = /[^0-9\u4e00-\u9fa5\+\-\*\/\(\)\.\[\]FL%]/g; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -803,7 +845,11 @@ let analyzer = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (me.isCycleCalc(expression, itemID, template)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             hintBox.infoBox('系统提示', '表达式中有循环计算!', 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!testValue(expression)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            hintBox.infoBox('系统提示', '表达式语法错误!', 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return true;  // 表达式合法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1480,6 +1526,7 @@ class CalcProgram { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     let calcItem = template.calcItems[idx]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     $CE.tempCalcItem = calcItem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     let feeRate = parseFloatPlus(calcItem.feeRate) ? parseFloatPlus(calcItem.feeRate).toDecimal(decimalObj.feeRate) : 100;  // 100% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // console.log(`[${calcItem.ID}]: ${calcItem.compiledExpr}`);   // for test. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(decimalObj.decimal('unitPrice', treeNode));   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 0; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1545,7 +1592,7 @@ class CalcProgram { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return changedNodes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedArr中) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     calcFormulaNodes(changedArr){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let me = this; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let formulaNodes = cbTools.getFormulaNodes(true); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1585,40 +1632,71 @@ class CalcProgram { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 计算多条零散的定额,并计算他们所属的清单、父级清单,然后打包存储。如:批量替换工料机后受影响的定额。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    calcRationsAndSave(rationNodes, callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let me = this, leafBills = [], allChangedNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (let node of rationNodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            me.innerCalc(node, allChangedNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let leafBill = node.parent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // 多条定额同属一条叶子清单时,避免叶子清单重复计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (leafBill && leafBills.indexOf(leafBill) < 0) leafBills.push(leafBill); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 这个方法实际上封装了calculate()和saveNodes()两个方法,主要目的是为了外部调用方便,少写一点累赘代码。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    calcAndSave(treeNode, callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let changedNodes = this.calculate(treeNode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.saveNodes(changedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算零散的、混杂的树节点:清单、定额混合等(如:用到某一计算程序的定额和清单)。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算多条零散的定额,并计算他们所属的清单、父清单、引用清单。如:批量替换工料机后受影响的定额。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算多条零散的清单,并计算他们的父清单、引用清单。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    calcNodesAndSave(nodes, callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let me = this, rationNodes = [], billNodes = [], leafBills = [], allChangedNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let node of nodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (node.sourceType == ModuleNames.ration) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                rationNodes.push(node) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                billNodes.push(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (let node of leafBills){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let curChangeds = me.calculate(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            mergeArr(allChangedNodes, curChangeds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 多条定额同属一条叶子清单时,避免叶子清单重复计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let ration of rationNodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            me.innerCalc(ration, allChangedNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let leafBill = ration.parent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (leafBill && leafBills.indexOf(leafBill) < 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                leafBills.push(leafBill); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let endShowTime = +new Date(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        me.saveNodes(allChangedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 计算多条零散的清单,并计算他们的父清单、引用清单,然后打包存储。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    calcBillsAndSave(billNodes,callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let me = this, allChangedNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (let node of billNodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let curChangeds = me.calculate(node, true, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            mergeArr(allChangedNodes, curChangeds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        mergeArr(billNodes, leafBills); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let bill of billNodes){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let changeBills = me.calculate(bill, true, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            mergeArr(allChangedNodes, changeBills); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         me.calcFormulaNodes(allChangedNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        me.saveNodes(allChangedNodes,callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        me.saveNodes(allChangedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 这个方法实际上封装了calculate()和saveNodes()两个方法,主要目的是为了外部调用方便,少写一点累赘代码。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    calcAndSave(treeNode, callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        let changedNodes = this.calculate(treeNode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.saveNodes(changedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    calcRationsAndSave(rationNodes, callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // let me = this, leafBills = [], allChangedNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for (let node of rationNodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     me.innerCalc(node, allChangedNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     let leafBill = node.parent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     // 多条定额同属一条叶子清单时,避免叶子清单重复计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     if (leafBill && leafBills.indexOf(leafBill) < 0) leafBills.push(leafBill); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for (let node of leafBills){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     let curChangeds = me.calculate(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     mergeArr(allChangedNodes, curChangeds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // let endShowTime = +new Date(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // me.saveNodes(allChangedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.calcNodesAndSave(rationNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    calcBillsAndSave(billNodes,callback){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // let me = this, allChangedNodes = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // for (let node of billNodes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     let curChangeds = me.calculate(node, true, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     mergeArr(allChangedNodes, curChangeds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // me.calcFormulaNodes(allChangedNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // me.saveNodes(allChangedNodes,callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.calcNodesAndSave(billNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     calcAllNodesAndSave(calcType = calcAllType.catAll, callback){ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1626,8 +1704,7 @@ class CalcProgram { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.saveNodes(changedNodes, callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 排除指定项的综合合价计算(用于带循环计算的情况)。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 这里的汇总只到清单级别即可(清单单价取费时,汇总到清单和汇总到定额两个值不一样) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 排除指定项的综合合价计算(用于带循环计算的情况。这里的汇总只到清单级别即可:清单单价取费时,汇总到清单和汇总到定额两个值不一样) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     getTotalFee(baseNodes, excludeNodes){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         let rst = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         function calcNodes(nodes) { 
			 |