|  | @@ -1230,13 +1230,11 @@ class CalcProgram {
 | 
	
		
			
				|  |  |      getSourceType () {
 | 
	
		
			
				|  |  |          return ModuleNames.calc_program;
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 兼容Project框架方法
 | 
	
		
			
				|  |  |      loadData (datas) {
 | 
	
		
			
				|  |  |          this.datas = datas;
 | 
	
		
			
				|  |  |          this.compileAllTemps();
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      // 兼容Project框架方法
 | 
	
		
			
				|  |  |      doAfterUpdate (err, data) {
 | 
	
		
			
				|  |  |          if(!err){
 | 
	
	
		
			
				|  | @@ -1420,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;
 | 
	
	
		
			
				|  | @@ -1723,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;
 | 
	
	
		
			
				|  | @@ -1745,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;
 | 
	
	
		
			
				|  | @@ -1768,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);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 计算零散的、混杂的树节点:清单、定额混合等(如:用到某一计算程序的定额和清单)。
 | 
	
		
			
				|  |  | +    // 计算多条零散的定额,并计算他们所属的清单、父清单、引用清单。如:批量替换工料机后受影响的定额。
 | 
	
		
			
				|  |  | +    // 计算多条零散的清单,并计算他们的父清单、引用清单。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。
 | 
	
		
			
				|  |  | +    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:将通过本方法后发生改变的节点存入changedArr中)
 | 
	
		
			
				|  |  |      calcFormulaNodes(changedArr, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
		
			
				|  |  |          let formulaNodes = cbTools.getFormulaNodes(true);
 | 
	
	
		
			
				|  | @@ -1798,7 +1842,7 @@ class CalcProgram {
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      // 计算叶子清单下的所有子结点、自身、所有父结点、公式引用结点(即跟该叶子清单相关的所有结点)。最后打包存储。
 | 
	
		
			
				|  |  | -    calcLeafAndSave(treeNode){
 | 
	
		
			
				|  |  | +    calcLeafAndSave(treeNode, tender){
 | 
	
		
			
				|  |  |          let me = this;
 | 
	
		
			
				|  |  |          if(!calcTools.isLeafBill(treeNode)) return;
 | 
	
		
			
				|  |  |          if (treeNode.children && treeNode.children.length > 0) {
 | 
	
	
		
			
				|  | @@ -1807,85 +1851,12 @@ class CalcProgram {
 | 
	
		
			
				|  |  |                  me.innerCalc(child, changedNodes);
 | 
	
		
			
				|  |  |              };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            let curChangeds = me.calculate(treeNode);
 | 
	
		
			
				|  |  | +            let curChangeds = me.calculate(treeNode, true, true, tender);
 | 
	
		
			
				|  |  |              mergeArr(changedNodes, curChangeds);
 | 
	
		
			
				|  |  |              me.saveNodes(changedNodes);
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // 计算并保存指定的一个树节点。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。
 | 
	
		
			
				|  |  | -    // 这个方法实际上封装了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 ration of rationNodes) {
 | 
	
		
			
				|  |  | -            me.innerCalc(ration, allChangedNodes);
 | 
	
		
			
				|  |  | -            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);
 | 
	
		
			
				|  |  | -            mergeArr(allChangedNodes, changeBills);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        me.calcFormulaNodes(allChangedNodes);
 | 
	
		
			
				|  |  | -        me.saveNodes(allChangedNodes, 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);
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 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;
 |