Browse Source

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

zhangweicheng 7 years ago
parent
commit
ad926a192b

+ 196 - 46
web/building_saas/main/js/models/calc_base.js

@@ -40,6 +40,25 @@ let cbTools = {
         }
         return null;
     },
+    //通过ID获取节点行
+    getRowByID: function (items, ID) {
+        for(let i = 0, len = items.length; i < len; i++){
+            if(items[i]['data']['ID'] == ID){
+                return i + 1;
+            }
+        }
+        return null;
+    },
+    //通过ID获取节点
+    getNodeByID: function (items, ID) {
+        ID = parseInt(ID);
+        for(let i = 0, len = items.length; i < len; i++){
+            if(items[i]['data']['ID'] === ID){
+                return items[i];
+            }
+        }
+        return null;
+    },
     //获取该节点所有父节点
     getParents: function (node) {
         let rst = [];
@@ -69,7 +88,7 @@ let cbTools = {
             return rst;
         }
         //获取表达式中的基数和行引用
-        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
+        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getXNum(cbParser.getFArr(exp)));
         for(let i = 0, len = figureF.length; i < len; i++){
             let figure = figureF[i];
             if(figure.type === 'base' && cbTools.isDef(calcBase.baseFigures[figure.value])){
@@ -156,28 +175,22 @@ let cbTools = {
         let parent = node.parent;
         if(this.isFlag(node.data) && (node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.SUB_ENGINERRING
             || node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_TECH)){
-            //node.data.baseFigureClass = null;
             return null;
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CONSTRUCTION_ORGANIZATION){
-            //node.data.baseFigureClass = 'CONSTRUCTION_ORGANIZATION';
             return calcBase.baseFigureClass.CONSTRUCTION_ORGANIZATION;
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.OTHER){
-            //node.data.baseFigureClass = 'OTHER';
             return calcBase.baseFigureClass.OTHER;
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.CHARGE){
-            //node.data.baseFigureClass = 'CHARGE';
             return calcBase.baseFigureClass.CHARGE;
         }
         else if(this.isFlag(node.data) && node.data.flagsIndex.fixed.flag === calcBase.fixedFlag.TAX){
-            //node.data.baseFigureClass = 'TAX';
             return calcBase.baseFigureClass.TAX;
         }
         else {
             if(!parent){
-                //node.data.baseFigureClass = 'OTHERS';
                 return calcBase.baseFigureClass.OTHERS;
             }
             else {
@@ -229,8 +242,8 @@ let cbTools = {
                 if(bases[i]['type'] === 'base' && cbTools.isDef(calcBase.baseFigures[bases[i]['value']])){
                     block.push(calcBase.baseFigures[bases[i]['value']]['fixedBill']['bill']['ID']);
                 }
-                else if(bases[i]['type'] === 'row'){
-                    let node = cbTools.getBillByRow(calcBase.project.mainTree.items, bases[i]['value'] - 1);
+                else if(bases[i]['type'] === 'id'){
+                    let node = cbTools.getNodeByID(calcBase.project.mainTree.items, bases[i]['value']);
                     if(cbTools.isDef(node)){
                         block.push(node.data.ID);
                     }
@@ -241,7 +254,7 @@ let cbTools = {
         function getBase(node){
             if(node && node.children.length === 0){
                 if(cbTools.isDef(node.data.calcBase) && node.data.calcBase !== ''){
-                    let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getRArr(cbParser.getFArr(node.data.calcBase)));
+                    let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getXNum(cbParser.getFIDArr(node.data.calcBase)));
                     tempBases = tempBases.concat(figureF);
                 }
             }
@@ -259,6 +272,48 @@ let cbTools = {
             }
             return null;
         }
+    },
+
+    // 获取全部有公式的树节点清单。 CSL, 2018-01-05
+    getFormulaNodes: function (needOrder = false) {
+        // 给公式结点清单换照引用计算顺序排序。
+        function orderFormulaNodes (nodesArr) {
+            let orderArr = [];
+            function recursionNode(nodes) {
+                for (let node of nodes){
+                    if (orderArr.includes(node)) continue;    // 已排过序的节点则跳过
+                    if (node.data.calcBase){
+                        let subNodes = cbTools.getNodesByExp(node.data.calcBase);
+                        recursionNode(subNodes);
+                    };
+                    if (nodesArr.includes(node) && !orderArr.includes(node)) orderArr.push(node);
+                };
+            }
+            recursionNode(nodesArr);
+            return orderArr;
+        };
+
+        let nodes = [];
+        for (let node of projectObj.project.mainTree.items){
+            if (node.sourceType == ModuleNames.bills && node.data.calcBase && node.data.calcBase != '')
+                nodes.push(node);
+        };
+        if (needOrder && nodes.length >= 2) return orderFormulaNodes(nodes)
+        else return nodes;
+    },
+    // 刷新全部行引用的公式清单。 CSL, 2018-01-05
+    refreshFormulaNodes: function () {
+        let nodes = this.getFormulaNodes();
+        if (nodes.length > 0) projectObj.mainController.refreshTreeNode(nodes);
+    },
+    // 判断结点是否被其它结点的表达式引用。
+    isUsedByFormula: function(node){
+        let nodes = this.getFormulaNodes();
+        if (nodes.length == 0) return false;
+        let sID = '@' + node.data.ID;
+        for (let node of nodes){
+             if (node.data.calcBase.hasSubStr(sID)) return true;
+        };
     }
 };
 
@@ -477,7 +532,7 @@ let cbAnalyzer = {
     },
     //输入合法性
     inputLegal: function (exp) {
-        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F]/g;
+        let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F,%]/g;
         return !ilegalRex.test(exp);
     },
     //基数合法性、存在性
@@ -503,15 +558,22 @@ let cbAnalyzer = {
     },
     //行引用合法性、存在性
     fLegal: function (items, exp) {
+        //提取F标记
+        let fmArr = cbParser.getFMArr(exp);
         //提取行引用
         let fArr = cbParser.getFArr(exp);
+        if(fmArr.length !== fArr.length){
+            return false;
+        }
         //提取行数
-        let rArr = cbParser.getRArr(fArr);
+        let rArr = cbParser.getXNum(fArr);
+        if(fArr.length !== rArr.length){
+            return false;
+        }
         //判断合法性和存在性
         for(let i = 0, len = rArr.length; i < len; i++){
             let idx = rArr[i] - 1;
             if(cbTools.isUnDef(cbTools.getBillByRow(items, idx))){
-                calcBase.errMsg = '行引用不合法';
                 return false;
             }
         }
@@ -525,16 +587,16 @@ let cbAnalyzer = {
         }
         //用于判断的起始清单ID
         let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
-        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
+        let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getXNum(cbParser.getFIDArr(exp)));
         for(let i = 0, len = figureF.length; i < len; i++){
             let figure = figureF[i];
             let bill = null;
             if(figure.type === 'base' && cbTools.isDef(baseFigures[figure.value])){
                 bill = baseFigures[figure.value]['fixedBill']['bill'];
             }
-            else if(figure.type === 'row'){
-                let tempBill = cbTools.getBillByRow(calcBase.project.mainTree.items, figure.value - 1);
-                bill = cbTools.isDef(tempBill) ? tempBill.data : null;
+            else if(figure.type === 'id'){
+                let node = cbTools.getNodeByID(calcBase.project.mainTree.items, figure.value);
+                bill = cbTools.isDef(node) ? node.data : null;
             }
             if(cbTools.isDef(bill) && checkStack(getRefStack([bill.ID]), sIDs)){
                 console.log('循环计算');
@@ -569,20 +631,27 @@ let cbAnalyzer = {
         let ilegalRex = /[\+,\-,\*,\/]{2}/g;
         let rex2 = /[{]{2}/g;
         let rex3 = /[}]{2}/g;
-        let rex4 = /[F]{2}/g
-        return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.test(exp);
+        let rex4 = /[F]{2}/g;
+        let rex5 = /[.]{2}/g;
+        let rex6 = /[%]{2}/g;
+        return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.test(exp) && !rex5.test(exp) && !rex6.test(exp);
     },
     //
     legalExp: function (node) {
         let exp = this.standar(node.data.userCalcBase);
         if(this.inputLegal(exp)){
-            if(this.baseLegal(cbTools.getFigure(node), exp)){
-                if(this.fLegal(calcBase.project.mainTree.items, exp)){
-                    if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
-                        if(this.arithmeticLegal(exp)){
+            if(this.arithmeticLegal(exp)){
+                if(this.baseLegal(cbTools.getFigure(node), exp)){
+                    if(this.fLegal(calcBase.project.mainTree.items, exp)){
+                        //转换成ID引用
+                        exp = cbParser.toIDExpr(exp);
+                        if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
                             return exp;
                         }
                     }
+                    else {
+                        calcBase.errMsg = '行引用不合法';
+                    }
                 }
             }
         }
@@ -592,22 +661,34 @@ let cbAnalyzer = {
 
 //输入式转换器
 let cbParser = {
+    //获取标记F
+    getFMArr: function (exp) {
+        let fmRex = /F/g;
+        let fmArr = exp.match(fmRex);
+        return cbTools.isDef(fmArr) ? fmArr : [];
+    },
     //获取行引用 eg: F10
     getFArr: function (exp) {
         let fRex = /F\d+/g;
         let fArr = exp.match(fRex);
         return cbTools.isDef(fArr) ? fArr : [];
     },
-    //获取行 eg: F10  10
-    getRArr: function (fArr) {
+    //获取X+num eg: F10  10 @105 105
+    getXNum: function (arr) {
         let rRex = /\d+/g;
         let tempArr = [];
-        for(let i = 0, len = fArr.length; i < len; i++){
-            tempArr = tempArr.concat(fArr[i].match(rRex));
+        for(let i = 0, len = arr.length; i < len; i++){
+            tempArr = tempArr.concat(arr[i].match(rRex));
         }
         let rArr = Array.from(new Set(tempArr));
         return rArr;
     },
+    //获取ID引用
+    getFIDArr: function (exp) {
+        let fidRex = /@\d+/g;
+        let fidArr = exp.match(fidRex);
+        return cbTools.isDef(fidArr) ? fidArr : [];
+    },
     //获取表达式中的中文式,没有{}需求时
     getCN: function(expr){
         let rst = [];
@@ -632,8 +713,8 @@ let cbParser = {
         }
         return rst;
     },
-    //获取表达式中的基数和
-    getFigureF: function (figures, rArr) {
+    //获取表达式中的基数和ID引用
+    getFigureF: function (figures, fidArr) {
         let rst = [];
         for(let i = 0, len = figures.length; i < len; i++){
             let obj = Object.create(null);
@@ -641,15 +722,75 @@ let cbParser = {
             obj.value = figures[i];
             rst.push(obj);
         }
-        for(let i = 0, len = rArr.length; i < len; i++){
+        for(let i = 0, len = fidArr.length; i < len; i++){
             let obj = Object.create(null);
-            obj.type = 'row';
-            obj.value = rArr[i];
+            obj.type = 'id';
+            obj.value = fidArr[i];
             rst.push(obj);
         }
         return rst;
     },
-
+    //表达式中的百分数转换成小数
+    percentToNum: function (exp) {
+        let rex = /\d+(\.\d+)?%/g;
+        let percents = exp.match(rex);
+        let numRex = /\d+(\.\d+)?/g;
+        if(cbTools.isDef(percents)){
+            for(let i = 0, len = percents.length; i < len; i++){
+                let percentNum = percents[i].match(numRex);
+                if(cbTools.isDef(percentNum) && percentNum.length === 1){
+                    exp = exp.replace(new RegExp(percents[i], 'g'), percentNum[0]/100);
+                }
+            }
+        }
+        return exp;
+    },
+    //将行引用转换成ID引用
+    toIDExpr: function (exp) {
+        let exps = [];
+        //获得行引用
+        let fArr = this.getFArr(exp);
+        for(let i = 0, len = fArr.length; i < len; i++){
+            let r = this.getXNum([fArr[i]]);
+            if(r.length === 1){
+                let node = cbTools.getBillByRow(calcBase.project.mainTree.items, r[0] - 1);
+                if(cbTools.isUnDef(node)){
+                    //continue;
+                    calcBase.errMsg = '行引用错误';
+                    throw '行引用错误';
+                }
+                exps.push({orgExp: fArr[i], newExp: '@' + node.data.ID});
+            }
+            else {
+                calcBase.errMsg = '行引用错误';
+                throw '行引用错误';
+            }
+        }
+        for(let i = 0, len = exps.length; i < len; i++){
+            exp = exp.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].newExp);
+        }
+        return exp;
+    },
+    //将ID引用转换成行引用
+    toFExpr: function (exp) {
+        let exps = [];
+        //获得ID引用
+        let fidArr = this.getFIDArr(exp);
+        for(let i = 0, len = fidArr.length; i < len; i++){
+            let id = this.getXNum([fidArr[i]]);
+            if(id.length === 1){
+                let row = cbTools.getRowByID(calcBase.project.mainTree.items, id[0]);
+                if(cbTools.isUnDef(row)){
+                    continue;
+                }
+                exps.push({orgExp: fidArr[i], newExp: 'F' + row});
+            }
+        }
+        for(let i = 0, len = exps.length; i < len; i++){
+            exp = exp.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].newExp);
+        }
+        return exp;
+    },
     //将表达式转换为可编译的表达式
     toCompileExpr: function(v){
         if(v === ''){
@@ -670,15 +811,15 @@ let cbParser = {
             v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
         }
         //行引用
-        let fArr = this.getFArr(v);
+        let fidArr = this.getFIDArr(v);
         let fExps = [];
-        for(let i = 0, len = fArr.length; i < len; i++){
+        for(let i = 0, len = fidArr.length; i < len; i++){
             let fExp = Object.create(null);
-            fExp.orgExp = fArr[i];
+            fExp.orgExp = fidArr[i];
             fExps.push(fExp);
         }
         for(let i = 0, len = fExps.length; i < len; i++){
-            fExps[i].compileExp = '$CBC.f(\'' + fExps[i].orgExp + '\')';
+            fExps[i].compileExp = '$CBC.ref(\'' + fExps[i].orgExp + '\')';
             v = v.replace(new RegExp(fExps[i].orgExp, 'g'), fExps[i].compileExp);
         }
         return v;
@@ -693,13 +834,18 @@ let cbCalctor = {
         }
         return baseFigureTemplate[calcBase.baseFigures[figure]['base']]();
     },
-    //行引用
-    f: function (fExp) {
-        let r = cbParser.getRArr([fExp]);
-        return cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']) &&
-            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common'])&&
-            cbTools.isDef(calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee']) ?
-            calcBase.project.mainTree.items[r[0] - 1]['data']['feesIndex']['common']['totalFee'] : 0;
+    //ID引用
+    ref: function (fExp) {
+        let ID = cbParser.getXNum([fExp]);
+        if(ID.length === 1){
+            let node = cbTools.getNodeByID(calcBase.project.mainTree.items, parseInt(ID[0]));
+            return cbTools.isDef(node) &&
+                    cbTools.isDef(node.data.feesIndex) &&
+                    cbTools.isDef(node.data.feesIndex.common) &&
+                    cbTools.isDef(node.data.feesIndex.common.totalFee) ?
+                    node.data.feesIndex.common.totalFee : 0;
+        }
+        return 0;
     },
     //计算
     exec: function () {
@@ -738,7 +884,7 @@ let calcBase = {
         return cbTools.getBaseBill(node);
     },
     calculate: function (node, reCalc = null) {
-        let me = calcBase,
+            let me = calcBase,
             $CBA = cbAnalyzer,
             $CBP = cbParser,
             $CBC = cbCalctor;
@@ -754,10 +900,14 @@ let calcBase = {
             if(!cbTools.isDef(exp)){
                 throw '表达式不正确';
             }
+
             //输入式转换表达式
             let compileExp = $CBP.toCompileExpr(exp);
             //计算
-            let calcBaseValue = eval(compileExp);
+            console.log(compileExp);
+            let calcExp = $CBP.percentToNum(compileExp);
+            console.log(calcExp);
+            let calcBaseValue = eval(calcExp);
             if(!cbTools.isNum(calcBaseValue)){
                 throw '表达式不正确';
             }

+ 17 - 42
web/building_saas/main/js/models/calc_program.js

@@ -422,39 +422,6 @@ let executeObj = {
 };
 
 let treeNodeTools = {
-    // 获取全部有公式的树节点清单
-    getFormulaNodes: function () {
-        let nodes = [];
-        for (let node of projectObj.project.mainTree.items){
-              if (node.sourceType == ModuleNames.bills && node.data.calcBase && node.data.calcBase != '')
-                  nodes.push(node);
-        };
-
-        if (nodes.length >= 2) return this.orderFormulaNodes(nodes)
-        else return nodes;
-    },
-
-    // 给公式结点清单换照引用计算顺序排序。
-    orderFormulaNodes: function (nodesArr) {
-        let orderArr = [];
-
-        function recursionNode(nodes) {
-            for (let node of nodes){
-                if (orderArr.includes(node)) continue;    // 已排过序的节点则跳过
-
-                if (node.data.calcBase){
-                    let subNodes = cbTools.getNodesByExp(node.data.calcBase);
-                    recursionNode(subNodes);
-                };
-
-                if (nodesArr.includes(node) && !orderArr.includes(node)) orderArr.push(node);
-            };
-        }
-
-        recursionNode(nodesArr);
-        return orderArr;
-    },
-
     isBill: function(treeNode){
         return treeNode.sourceType === ModuleNames.bills;
     },
@@ -496,6 +463,7 @@ let treeNodeTools = {
             treeNode.data.fees.push(fee);
             treeNode.data.feesIndex[fieldName] = fee;
         };
+        treeNode.changed = true;
     },
 
     getCalcType(treeNode) {
@@ -932,14 +900,21 @@ class CalcProgram {
             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;
+            if (treeNode.data.feesIndex && treeNode.data.feesIndex.common){
+                if (treeNode.data.feesIndex.common.unitFee != uf ||
+                    treeNode.data.feesIndex.common.totalFee != tf ||
+                    treeNode.data.feesIndex.common.tenderUnitFee != tuf ||
+                    treeNode.data.feesIndex.common.tenderTotalFee != ttf ){
+                    delete treeNode.data.fees;    // 直接删掉再新增。从其它计算方式切换到公式计算方式,会多出其它的费(不光是common)所以这里直接删掉,不用一个个费判断更新,效率更高。
+                    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": []};
         }
         // 定额或叶子清单自己的计算程序计算
@@ -1059,7 +1034,7 @@ class CalcProgram {
     // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
     calcFormulaNodes(changedArr){
         let me = this;
-        let formulaNodes = treeNodeTools.getFormulaNodes();
+        let formulaNodes = cbTools.getFormulaNodes(true);
         if (formulaNodes.length == 0) return;
         for (let formulaNode of formulaNodes){
             formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。

+ 5 - 2
web/building_saas/main/js/views/calc_base_view.js

@@ -132,7 +132,8 @@ let calcBaseView = {
         let me = calcBaseView;
         //输入框显示原本的
         if(me.isDef(node.data.calcBase)){
-            me.inputExpr.val(node.data.calcBase);
+            console.log('enter');
+            me.inputExpr.val(cbParser.toFExpr(node.data.calcBase));
         }
         me.buildSheet();
         let baseObj = projectObj.project.calcBase.getBaseByClass(node);
@@ -151,7 +152,9 @@ let calcBaseView = {
         let rex2 = /[{]{2}/g;
         let rex3 = /[}]{2}/g;
         let rex4 = /[F]{2}/g;
-        return !rex.test(v) && !rex2.test(v) && !rex3.test(v) && !rex4.test(v);
+        let rex5 = /[.]{2}/g;
+        let rex6 = /[%]{2}/g;
+        return !rex.test(v) && !rex2.test(v) && !rex3.test(v) && !rex4.test(v) && !rex5.test(v) && !rex6.test(v);
     },
 
     //运算符点击显示到运算窗口

+ 5 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -33,6 +33,11 @@ let MainTreeCol = {
             let programID = node.data.programID;
             if (!programID) return
             else return projectObj.project.calcProgram.compiledTemplateMaps[programID];
+        },
+        calcBase: function (node) {
+            if (node.data.calcBase && node.data.calcBase != ""){
+                return cbParser.toFExpr(node.data.calcBase);
+            }
         }
     },
     readOnly: {

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

@@ -306,7 +306,9 @@ var projectObj = {
                     treeNodeTools.initFeeField(node, 'common');
                     node.data.feesIndex.common.unitFee = value;
                 }
-                else node.data[fieldName] = value;
+                else if(fieldName !== 'calcBase'){
+                    node.data[fieldName] = value;
+                }
                 project.calcProgram.calcAndSave(node);
                 gljOprObj.showRationGLJSheetData();
             } else if (node.sourceType === project.Bills.getSourceType()&&fieldName === 'unit'){//修改清单单位的时候清单工程量要重新4舍5入
@@ -494,6 +496,7 @@ var projectObj = {
                     },
                     callback: function (key, opt) {
                         ProjectController.addRootBill(project, controller);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         return project.mainTree.selected&&project.mainTree.selected.parent==null;
@@ -520,6 +523,7 @@ var projectObj = {
                     },
                     callback: function (key, opt) {
                         ProjectController.addFB(project, controller);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
@@ -553,6 +557,7 @@ var projectObj = {
                     },
                     callback: function (key, opt) {
                         ProjectController.addFX(project, controller);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         return project.Bills.isFBFX(project.mainTree.selected );//不属于分部分项的话隐藏
@@ -572,6 +577,7 @@ var projectObj = {
                             }
                         }
                         ProjectController.addBills(project, controller);
+                        cbTools.refreshFormulaNodes();
                     },
                      visible: function(key, opt){
                          return  project.Bills.isFBFX(project.mainTree.selected)==true?false:true;//不属于分部分项的话隐藏
@@ -586,6 +592,7 @@ var projectObj = {
                     },
                     callback: function (key, opt) {
                         ProjectController.addRation(project, controller, rationType.ration);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
@@ -605,6 +612,7 @@ var projectObj = {
                     },
                     callback: function (key, opt) {
                         ProjectController.addRation(project, controller, rationType.volumePrice);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
@@ -633,6 +641,7 @@ var projectObj = {
                             }
                         }
                         getGLJData('insert');// ProjectController.addRation(project, controller, rationType.volumePrice);
+                        cbTools.refreshFormulaNodes();
                     },
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
@@ -655,6 +664,10 @@ var projectObj = {
                         var selected = controller.tree.selected, parent = selected.parent;
                         if (selected) {
                             if (selected.sourceType === project.Bills.getSourceType()) {
+                                if (cbTools.isUsedByFormula(selected)){
+                                    alert('该清单行被其它公式结点引用,不允许删除!');
+                                    return;
+                                };
                                 project.Bills.deleteBills(selected.source);
                                 controller.delete();
                             } else if (selected.sourceType === project.Ration.getSourceType()) {
@@ -662,6 +675,7 @@ var projectObj = {
                                 controller.delete();
                             };
                             projectObj.converseCalculateBills(parent);
+                            cbTools.refreshFormulaNodes();
                         }
                     }
                 },
@@ -669,8 +683,10 @@ var projectObj = {
                 "calculateAll_RationContent": {
                     name: '造价计算',
                     callback: function () {
+                        $.bootstrapLoading.start();
                         let changedNodes = project.calcProgram.calcAllNodes();
                         project.calcProgram.saveNodes(changedNodes);
+                        $.bootstrapLoading.end();
                     }
                 }
             }
@@ -813,7 +829,9 @@ $('#insert').click(function () {
         ProjectController.addBills(project, controller);
     } else if (selected.sourceType === project.Ration.getSourceType()) {
         ProjectController.addRation(project, controller, selected.data.type);
-    }
+    };
+
+    cbTools.refreshFormulaNodes();
 });
 $('#delete').click(function () {
     var controller = projectObj.mainController, project = projectObj.project;
@@ -821,6 +839,10 @@ $('#delete').click(function () {
 
     if (selected) {
         if (selected.sourceType === project.Bills.getSourceType()) {
+            if (cbTools.isUsedByFormula(selected)){
+                alert('该清单行被其它公式结点引用,不允许删除!');
+                return;
+            };
             project.Bills.deleteBills(selected.source);
             controller.delete();
         } else if (selected.sourceType === project.Ration.getSourceType()) {
@@ -830,7 +852,9 @@ $('#delete').click(function () {
             project.ration_glj.updataOrdelete(selected.source);
         };
         projectObj.converseCalculateBills(parent);
-    }
+    };
+
+    cbTools.refreshFormulaNodes();
 });
 $('#upLevel').click(function () {
     var controller = projectObj.mainController, project = projectObj.project;