|
@@ -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,39 +777,62 @@ 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;
|
|
|
if (invalidChars.test(expr)){
|
|
|
- hintBox.infoBox('系数提示','表达式中含有无效的字符!',1);
|
|
|
+ hintBox.infoBox('错误提示',`表达式中含有${hintBox.font('无效字符')}!`,1);
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
+ let i = expr.search(/\df/ig); // 4F3
|
|
|
+ let j = expr.search(/\d\[/ig); // 4[定额基价人工费]
|
|
|
+ if (i > -1 || j > -1){
|
|
|
+ hintBox.infoBox('错误提示', `表达式中${hintBox.font('缺少运算符')}!`, 1);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
let pattCn = new RegExp(/[\u4E00-\u9FA5]+/gi);
|
|
|
let arrCn = expr.match(pattCn);
|
|
|
let pattBase = new RegExp(/\[[\u4E00-\u9FA5]+\]/gi);
|
|
|
let arrBase = expr.match(pattBase);
|
|
|
if (arrCn && !arrBase){
|
|
|
- hintBox.infoBox('系统提示', '定额基数必须用中括号[]括起来!', 1);
|
|
|
+ hintBox.infoBox('错误提示', `定额基数必须用中括号${hintBox.font('[]')}括起来!`, 1);
|
|
|
return false;
|
|
|
};
|
|
|
if (arrCn && arrBase && (arrCn.length != arrBase.length)){
|
|
|
for (let cn of arrCn){
|
|
|
let tempBase = `[${cn}]`;
|
|
|
if (!arrBase.includes(tempBase)){
|
|
|
- hintBox.infoBox('系统提示', `定额基数“${cn}”必须用中括号[]括起来!`, 1);
|
|
|
+ hintBox.infoBox('错误提示', `定额基数“${hintBox.font(cn)}”必须用中括号${hintBox.font('[]')}括起来!`, 1);
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
// 这里要加一个保险。因为上面的 for 循环在“主材费 + [主材费]” 情况下有Bug
|
|
|
- hintBox.infoBox('系统提示', '定额基数必须用中括号[]括起来!', 1);
|
|
|
+ hintBox.infoBox('错误提示', `定额基数必须用中括号${hintBox.font('[]')}括起来!`, 1);
|
|
|
return false;
|
|
|
};
|
|
|
if (arrBase){
|
|
|
for (let base of arrBase){
|
|
|
let baseName = base.slice(1, -1);
|
|
|
if (!rationCalcBases[baseName]){
|
|
|
- hintBox.infoBox('系统提示', '定额基数 [' + baseName + '] 末定义!', 1);
|
|
|
+ hintBox.infoBox('错误提示', `定额基数${hintBox.font('[' +baseName + ']')}末定义!`, 1);
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
@@ -794,16 +843,20 @@ let analyzer = {
|
|
|
let num = F.slice(1);
|
|
|
if (num > template.calcItems.length){
|
|
|
let s = hintBox.font('F'+num);
|
|
|
- hintBox.infoBox('系统提示', `表达式中 “${s}” 行号引用错误!`, 1);
|
|
|
+ hintBox.infoBox('错误提示', `表达式中 “${hintBox.font(s)}” 行号引用错误!`, 1);
|
|
|
return false;
|
|
|
};
|
|
|
};
|
|
|
|
|
|
let expression = me.getExpression(expr, template);
|
|
|
if (me.isCycleCalc(expression, itemID, template)){
|
|
|
- hintBox.infoBox('系统提示', '表达式中有循环计算!', 1);
|
|
|
+ hintBox.infoBox('错误提示', `表达式中有${hintBox.font('循环计算')}!`, 1);
|
|
|
return false;
|
|
|
- }
|
|
|
+ };
|
|
|
+ if (!testValue(expression)){
|
|
|
+ hintBox.infoBox('错误提示', `表达式中有${hintBox.font('语法错误')}!`, 1);
|
|
|
+ return false;
|
|
|
+ };
|
|
|
|
|
|
return true; // 表达式合法
|
|
|
},
|
|
@@ -1480,6 +1533,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 +1599,7 @@ class CalcProgram {
|
|
|
return changedNodes;
|
|
|
};
|
|
|
|
|
|
- // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedNodesArr中)
|
|
|
+ // 计算全部公式项。 (参数意义:将通过本方法后发生改变的节点存入changedArr中)
|
|
|
calcFormulaNodes(changedArr){
|
|
|
let me = this;
|
|
|
let formulaNodes = cbTools.getFormulaNodes(true);
|
|
@@ -1585,40 +1639,66 @@ 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);
|
|
|
};
|
|
|
+
|
|
|
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 +1706,7 @@ class CalcProgram {
|
|
|
this.saveNodes(changedNodes, callback);
|
|
|
};
|
|
|
|
|
|
- // 排除指定项的综合合价计算(用于带循环计算的情况)。
|
|
|
- // 这里的汇总只到清单级别即可(清单单价取费时,汇总到清单和汇总到定额两个值不一样)
|
|
|
+ // 排除指定项的综合合价计算(用于带循环计算的情况。这里的汇总只到清单级别即可:清单单价取费时,汇总到清单和汇总到定额两个值不一样)
|
|
|
getTotalFee(baseNodes, excludeNodes){
|
|
|
let rst = 0;
|
|
|
function calcNodes(nodes) {
|