|  | @@ -1418,56 +1418,6 @@ class CalcProgram {
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // 存储、刷新零散的多个结点。
 | 
	
		
			
				|  |  | -    saveNodes(treeNodes, callback){
 | 
	
		
			
				|  |  | -        if (treeNodes.length < 1) {
 | 
	
		
			
				|  |  | -            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | -            return;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let me = this;
 | 
	
		
			
				|  |  | -/*        me.project.beginUpdate('');
 | 
	
		
			
				|  |  | -        for (let node of treeNodes){
 | 
	
		
			
				|  |  | -            if (node.changed){
 | 
	
		
			
				|  |  | -                let data = calcTools.cutNodeForSave(node);
 | 
	
		
			
				|  |  | -                let newData = {'updateType': 'ut_update', 'updateData': data};
 | 
	
		
			
				|  |  | -                me.project.push(node.sourceType, [newData]);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        me.project.endUpdate();*/
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let dataArr = [];
 | 
	
		
			
				|  |  | -        for (let node of treeNodes){
 | 
	
		
			
				|  |  | -            if (node.changed){
 | 
	
		
			
				|  |  | -                let data = calcTools.cutNodeForSave(node);
 | 
	
		
			
				|  |  | -                let newData = {'type': node.sourceType, 'data': data};
 | 
	
		
			
				|  |  | -                dataArr.push(newData);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        if (dataArr.length < 1) {
 | 
	
		
			
				|  |  | -            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | -            return;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        $.bootstrapLoading.start();
 | 
	
		
			
				|  |  | -        let startTime = +new Date();
 | 
	
		
			
				|  |  | -        me.project.updateNodes(dataArr, function (data) {
 | 
	
		
			
				|  |  | -            let endShowTime = +new Date();
 | 
	
		
			
				|  |  | -            console.log(`保存所需时间——${endShowTime - startTime}`);
 | 
	
		
			
				|  |  | -            if(callback){
 | 
	
		
			
				|  |  | -                callback(data);
 | 
	
		
			
				|  |  | -            };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            for (let node of treeNodes){delete node.changed};
 | 
	
		
			
				|  |  | -            projectObj.mainController.refreshTreeNode(treeNodes);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 批量树结点计算后,计算程序早已物是人非,所以这里要重新计算一下。
 | 
	
		
			
				|  |  | -            if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
 | 
	
		
			
				|  |  | -                calcProgramObj.refreshCurNodeCalcItems(me.project.mainTree.selected);
 | 
	
		
			
				|  |  | -            };
 | 
	
		
			
				|  |  | -            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 只计算treeNode自身。changedArr: 外部传来的一个数组,专门存储发生变动的节点。
 | 
	
		
			
				|  |  |      innerCalc(treeNode, changedArr, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
	
		
			
				|  | @@ -1721,6 +1671,56 @@ class CalcProgram {
 | 
	
		
			
				|  |  |          if (treeNode.changed && !changedArr.includes(treeNode)) changedArr.push(treeNode);
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    // 存储、刷新零散的多个结点。
 | 
	
		
			
				|  |  | +    saveNodes(treeNodes, callback){
 | 
	
		
			
				|  |  | +        if (treeNodes.length < 1) {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let me = this;
 | 
	
		
			
				|  |  | +        /*        me.project.beginUpdate('');
 | 
	
		
			
				|  |  | +                for (let node of treeNodes){
 | 
	
		
			
				|  |  | +                    if (node.changed){
 | 
	
		
			
				|  |  | +                        let data = calcTools.cutNodeForSave(node);
 | 
	
		
			
				|  |  | +                        let newData = {'updateType': 'ut_update', 'updateData': data};
 | 
	
		
			
				|  |  | +                        me.project.push(node.sourceType, [newData]);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                };
 | 
	
		
			
				|  |  | +                me.project.endUpdate();*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let dataArr = [];
 | 
	
		
			
				|  |  | +        for (let node of treeNodes){
 | 
	
		
			
				|  |  | +            if (node.changed){
 | 
	
		
			
				|  |  | +                let data = calcTools.cutNodeForSave(node);
 | 
	
		
			
				|  |  | +                let newData = {'type': node.sourceType, 'data': data};
 | 
	
		
			
				|  |  | +                dataArr.push(newData);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        if (dataArr.length < 1) {
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +            return;
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        $.bootstrapLoading.start();
 | 
	
		
			
				|  |  | +        let startTime = +new Date();
 | 
	
		
			
				|  |  | +        me.project.updateNodes(dataArr, function (data) {
 | 
	
		
			
				|  |  | +            let endShowTime = +new Date();
 | 
	
		
			
				|  |  | +            console.log(`保存所需时间——${endShowTime - startTime}`);
 | 
	
		
			
				|  |  | +            if(callback){
 | 
	
		
			
				|  |  | +                callback(data);
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for (let node of treeNodes){delete node.changed};
 | 
	
		
			
				|  |  | +            projectObj.mainController.refreshTreeNode(treeNodes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 批量树结点计算后,计算程序早已物是人非,所以这里要重新计算一下。
 | 
	
		
			
				|  |  | +            if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
 | 
	
		
			
				|  |  | +                calcProgramObj.refreshCurNodeCalcItems(me.project.mainTree.selected);
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +            $.bootstrapLoading.end();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // 计算本节点、所有父节点(默认,可选)、公式引用节点(默认,可选)。
 | 
	
		
			
				|  |  |      calculate(treeNode, calcParents = true, calcFormulas = true, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
	
		
			
				|  | @@ -1743,12 +1743,17 @@ class CalcProgram {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return changedNodes;
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | +    // 计算并保存一个树节点。(修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点)
 | 
	
		
			
				|  |  | +    calcAndSave(treeNode, callback, tender){
 | 
	
		
			
				|  |  | +        let changedNodes = this.calculate(treeNode, true, true, tender);
 | 
	
		
			
				|  |  | +        this.saveNodes(changedNodes, callback);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* 计算所有树结点(分3种情况),并返回发生变动的零散的多个树结点。参数取值如下:
 | 
	
		
			
				|  |  | -        calcAllType.catAll       计算所有树结点 (不指定参数时的默认值)
 | 
	
		
			
				|  |  | +        calcAllType.catAll       计算所有树结点 (默认值)
 | 
	
		
			
				|  |  |          calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
 | 
	
		
			
				|  |  | -        calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到)  不要用
 | 
	
		
			
				|  |  | -        缺陷:calcAllType.catRations 参数情况不会计算父结点。(calcAllType.catBills 可以,因为清单的父结点也是清单会计算)
 | 
	
		
			
				|  |  | +        calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到)
 | 
	
		
			
				|  |  | +                                 (calcAllType.catRations时程序中做了特殊处理,实际上是计算所有树结点!)
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |      calcAllNodes(calcType = calcAllType.catAll, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
	
		
			
				|  | @@ -1766,12 +1771,53 @@ class CalcProgram {
 | 
	
		
			
				|  |  |                  };
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // calcAllType.catRations 参数情况不会计算父结点(因为父结点是清单),所以这里进行特殊处理。
 | 
	
		
			
				|  |  | +        if (calcType == calcAllType.catRations)
 | 
	
		
			
				|  |  | +            calcType == calcAllType.catAll;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          calcNodes(me.project.mainTree.roots);
 | 
	
		
			
				|  |  |          me.calcFormulaNodes(changedNodes, tender);
 | 
	
		
			
				|  |  |          return changedNodes;
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | +    // tender: null:不调价(普通计算)。 1: 正向调价   2:反向调价-调子目    3: 反向调价-调工料机
 | 
	
		
			
				|  |  | +    calcAllNodesAndSave(calcType = calcAllType.catAll, callback, tender){
 | 
	
		
			
				|  |  | +        let changedNodes = this.calcAllNodes(calcType, tender);
 | 
	
		
			
				|  |  | +        this.saveNodes(changedNodes, callback);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedArr中)
 | 
	
		
			
				|  |  | +    // 计算零散的、混杂的树节点:清单、定额混合等(如:用到某一计算程序的定额和清单)。
 | 
	
		
			
				|  |  | +    // 计算多条零散的定额,并计算他们所属的清单、父清单、引用清单。如:批量替换工料机后受影响的定额。
 | 
	
		
			
				|  |  | +    // 计算多条零散的清单,并计算他们的父清单、引用清单。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。
 | 
	
		
			
				|  |  | +    calcNodesAndSave(nodes, callback, tender){
 | 
	
		
			
				|  |  | +        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 ration of rationNodes) {
 | 
	
		
			
				|  |  | +            me.innerCalc(ration, allChangedNodes, tender);
 | 
	
		
			
				|  |  | +            let leafBill = ration.parent;
 | 
	
		
			
				|  |  | +            if (leafBill && leafBills.indexOf(leafBill) < 0)
 | 
	
		
			
				|  |  | +                leafBills.push(leafBill);
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        mergeArr(billNodes, leafBills);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for (let bill of billNodes){
 | 
	
		
			
				|  |  | +            let changeBills = me.calculate(bill, true, false, tender);
 | 
	
		
			
				|  |  | +            mergeArr(allChangedNodes, changeBills);
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        me.calcFormulaNodes(allChangedNodes, tender);
 | 
	
		
			
				|  |  | +        me.saveNodes(allChangedNodes, callback);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 计算全部公式项。 (changedArr:将通过本方法后发生改变的节点存入changedArr中)
 | 
	
		
			
				|  |  |      calcFormulaNodes(changedArr, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
		
			
				|  |  |          let formulaNodes = cbTools.getFormulaNodes(true);
 | 
	
	
		
			
				|  | @@ -1811,50 +1857,6 @@ class CalcProgram {
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。
 | 
	
		
			
				|  |  | -    // 这个方法实际上封装了calculate()和saveNodes()两个方法,主要目的是为了外部调用方便,少写一点累赘代码。
 | 
	
		
			
				|  |  | -    calcAndSave(treeNode, callback, tender){
 | 
	
		
			
				|  |  | -        let changedNodes = this.calculate(treeNode, true, true, tender);
 | 
	
		
			
				|  |  | -        this.saveNodes(changedNodes, callback);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 计算零散的、混杂的树节点:清单、定额混合等(如:用到某一计算程序的定额和清单)。
 | 
	
		
			
				|  |  | -    // 计算多条零散的定额,并计算他们所属的清单、父清单、引用清单。如:批量替换工料机后受影响的定额。
 | 
	
		
			
				|  |  | -    // 计算多条零散的清单,并计算他们的父清单、引用清单。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。
 | 
	
		
			
				|  |  | -    calcNodesAndSave(nodes, callback, tender){
 | 
	
		
			
				|  |  | -        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 ration of rationNodes) {
 | 
	
		
			
				|  |  | -            me.innerCalc(ration, allChangedNodes, tender);
 | 
	
		
			
				|  |  | -            let leafBill = ration.parent;
 | 
	
		
			
				|  |  | -            if (leafBill && leafBills.indexOf(leafBill) < 0)
 | 
	
		
			
				|  |  | -                leafBills.push(leafBill);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        mergeArr(billNodes, leafBills);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        for (let bill of billNodes){
 | 
	
		
			
				|  |  | -            let changeBills = me.calculate(bill, true, false, tender);
 | 
	
		
			
				|  |  | -            mergeArr(allChangedNodes, changeBills);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        me.calcFormulaNodes(allChangedNodes);
 | 
	
		
			
				|  |  | -        me.saveNodes(allChangedNodes, callback);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // tender: null:不调价(普通计算)。 1: 正向调价   2:反向调价-调子目    3: 反向调价-调工料机
 | 
	
		
			
				|  |  | -    calcAllNodesAndSave(calcType = calcAllType.catAll, callback, tender){
 | 
	
		
			
				|  |  | -        let changedNodes = this.calcAllNodes(calcType, tender);
 | 
	
		
			
				|  |  | -        this.saveNodes(changedNodes, callback);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 排除指定项的综合合价计算(用于带循环计算的情况。这里的汇总只到清单级别即可:清单单价取费时,汇总到清单和汇总到定额两个值不一样)
 | 
	
		
			
				|  |  |      getTotalFee(baseNodes, excludeNodes){
 | 
	
		
			
				|  |  |          let rst = 0;
 |