|
@@ -553,7 +553,6 @@ const rationCalcBases = {
|
|
|
|
|
|
let analyzer = {
|
|
|
calcTemplate: null,
|
|
|
- success: true,
|
|
|
|
|
|
standard: function(expr){
|
|
|
let str = expr;
|
|
@@ -587,47 +586,59 @@ let analyzer = {
|
|
|
isCycleCalc: function (expr) { // @5+@6 这里已经是ID引用
|
|
|
let me = this;
|
|
|
|
|
|
- function checkCycle() {
|
|
|
-
|
|
|
- }
|
|
|
- let atIDArr = me.getAtIDArr(expr);
|
|
|
- for (let atID of atIDArr){
|
|
|
- let ID = atID.slice(1);
|
|
|
- let item = me.calcTemplate.compiledCalcItems[ID];
|
|
|
- let expression = item.expression;
|
|
|
- if (expression.includes(atID)) return false;
|
|
|
-
|
|
|
+ function isCycle(nodeExpr) {
|
|
|
+ let atIDArr = me.getAtIDArr(nodeExpr);
|
|
|
+ for (let atID of atIDArr){
|
|
|
+ let ID = atID.slice(1);
|
|
|
+ let item = me.calcTemplate.compiledCalcItems[ID];
|
|
|
+ if (item.expression.includes(atID)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ isCycle(item.expression);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return false;
|
|
|
};
|
|
|
+
|
|
|
+ return isCycle(expr);
|
|
|
},
|
|
|
- isLegal: function (expr) {
|
|
|
+ isLegal: function (expr) { // 调用前必须先标准化
|
|
|
let me = this;
|
|
|
- let stdExpr = me.standard(expr);
|
|
|
|
|
|
let invalidChars = /[^0-9\u4e00-\u9fa5\+\-\*\/\(\)\.\[\]F%]/g;
|
|
|
- if (invalidChars.test(stdExpr)){
|
|
|
+ if (invalidChars.test(expr)){
|
|
|
alert('表达式中含有无效的字符!');
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
let pattCn = new RegExp(/[\u4E00-\u9FA5]+/gi);
|
|
|
- let arrCn = stdExpr.match(pattCn);
|
|
|
+ let arrCn = expr.match(pattCn);
|
|
|
let pattBase = new RegExp(/\[[\u4E00-\u9FA5]+\]/gi);
|
|
|
- let arrBase = stdExpr.match(pattBase);
|
|
|
+ let arrBase = expr.match(pattBase);
|
|
|
if (arrCn.length != arrBase.length){
|
|
|
- alert('定额基数必须用“[]”括起来!');
|
|
|
+ for (let cn of arrCn){
|
|
|
+ let tempBase = `[${cn}]`;
|
|
|
+ if (!arrBase.includes(tempBase)){
|
|
|
+ alert(`定额基数“${cn}”必须用中括号[]括起来!`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 这里要加一个保险。因为上面的 for 循环在“主材费 + [主材费]” 情况下有Bug
|
|
|
+ alert('定额基数必须用中括号[]括起来!');
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
for (let base of arrBase){
|
|
|
let baseName = base.slice(1, -1);
|
|
|
if (!rationCalcBases[baseName]){
|
|
|
- alert('定额基数“' + baseName + '”末定义!');
|
|
|
+ alert('定额基数 [' + baseName + '] 末定义!');
|
|
|
return false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 行引用检测、行引用转ID引用
|
|
|
- let arrF = me.getFArr(stdExpr);
|
|
|
+ let arrF = me.getFArr(expr);
|
|
|
for (let F of arrF){
|
|
|
let num = F.slice(1);
|
|
|
if (num > me.calcTemplate.calcItems.length){
|
|
@@ -636,140 +647,28 @@ let analyzer = {
|
|
|
};
|
|
|
let id = me.getFID(F);
|
|
|
let fn = new RegExp(F, "g");
|
|
|
- stdExpr = stdExpr.replace(fn, '@' + id);
|
|
|
+ expr = expr.replace(fn, `@('${id}')`);
|
|
|
};
|
|
|
|
|
|
// 循环计算
|
|
|
- if (me.isCycleCalc(stdExpr)){
|
|
|
+ if (me.isCycleCalc(expr)){
|
|
|
alert('表达式中有循环计算!');
|
|
|
return false;
|
|
|
}
|
|
|
- },
|
|
|
- analyzeCalcBase: function(expr){
|
|
|
- // 前提:必须无空格、无特殊符号
|
|
|
- function getCalcBase(expr){
|
|
|
- let base = '',
|
|
|
- iPos1 = -1, iPos2 = -1;
|
|
|
- for (let i = 0; i < expr.length; i++) {
|
|
|
- if (expr[i] === '['){
|
|
|
- iPos1 = i;
|
|
|
- }
|
|
|
- else if (iPos1 != -1 && expr[i]===']'){
|
|
|
- iPos2 = i;
|
|
|
- };
|
|
|
-
|
|
|
- if (iPos1 != -1 && iPos2 != -1){
|
|
|
- base = expr.slice(iPos1, iPos2 + 1);
|
|
|
- break;
|
|
|
- }
|
|
|
- };
|
|
|
- return base;
|
|
|
- };
|
|
|
- function calcBaseToIDExpr(base){
|
|
|
- /*// for test. 公路模式,基数到ID
|
|
|
- let id = -1;
|
|
|
- if (base == '[人工费]'){
|
|
|
- id = 111;
|
|
|
- }
|
|
|
- else if (base == '[材料费]'){
|
|
|
- id = 222;
|
|
|
- }
|
|
|
- else if (base == '[机械费]'){
|
|
|
- id = 333;
|
|
|
- }
|
|
|
- else id = "错误";
|
|
|
-
|
|
|
- return "@('" + id + "')";*/
|
|
|
- let baseValue = base.slice(1, -1);
|
|
|
- return "base('" + baseValue + "')";
|
|
|
- };
|
|
|
-
|
|
|
- while (expr.indexOf('[') > 0) {
|
|
|
- let base = getCalcBase(expr);
|
|
|
- let id = calcBaseToIDExpr(base);
|
|
|
- let baseValue = base.slice(1, -1); // []会给下面的正则带来干扰,这里去掉
|
|
|
- var pattBase =new RegExp(baseValue, "g");
|
|
|
- expr = expr.replace(pattBase, id);
|
|
|
- expr = expr.replace(/\[base\('/g, "base('"); // [@(' [base('
|
|
|
- expr = expr.replace(/'\)\]/g, "')"); // ')]
|
|
|
- };
|
|
|
-
|
|
|
- return expr;
|
|
|
- },
|
|
|
-
|
|
|
- analyzeLineRef: function(expr){
|
|
|
- let me = this;
|
|
|
- function isOperator(char){
|
|
|
- var operator = "+-*/()";
|
|
|
- return operator.indexOf(char) > -1;
|
|
|
- };
|
|
|
- function lineNumToID(lineNum){
|
|
|
- if (lineNum > me.calcTemplate.calcItems.length){
|
|
|
- me.success = false;
|
|
|
- return '越界';
|
|
|
- }
|
|
|
- else{
|
|
|
- let id = me.calcTemplate.calcItems[lineNum - 1].ID;
|
|
|
- return id;
|
|
|
- }
|
|
|
- };
|
|
|
- // 前提:必须无空格、无特殊符号、标准大写F
|
|
|
- function getSection(expr){
|
|
|
- let section = '',
|
|
|
- iPos1 = -1, iPos2 = -1;
|
|
|
- for (let i = 0; i < expr.length; i++) {
|
|
|
- if (expr[i] === 'F'){
|
|
|
- iPos1 = i;
|
|
|
- }
|
|
|
- else if (iPos1 != -1 && isOperator(expr[i])){
|
|
|
- iPos2 = i;
|
|
|
- }
|
|
|
- else if (iPos1 != -1 && i == expr.length - 1){
|
|
|
- iPos2 = i + 1;
|
|
|
-
|
|
|
- };
|
|
|
- if (iPos1 != -1 && iPos2 != -1){
|
|
|
- section = expr.slice(iPos1, iPos2);
|
|
|
- break;
|
|
|
- }
|
|
|
- };
|
|
|
- return section;
|
|
|
- };
|
|
|
- function sectionToIDExpr(section){
|
|
|
- if (section){
|
|
|
- let lineNum = section.slice(1);
|
|
|
- if (isNaN(lineNum)){
|
|
|
- me.success = false;
|
|
|
- return '错误'; // 这里的返回提示不能加上section,因为会无限循环
|
|
|
- }
|
|
|
- else
|
|
|
- return "@('" + lineNumToID(lineNum) + "')";
|
|
|
- }
|
|
|
- else return '';
|
|
|
- };
|
|
|
|
|
|
- while (expr.indexOf('F') > 0) {
|
|
|
- let sec = getSection(expr);
|
|
|
- let id = sectionToIDExpr(sec);
|
|
|
- var pattSec =new RegExp(sec, "g");
|
|
|
- expr = expr.replace(pattSec, id);
|
|
|
- };
|
|
|
- return expr;
|
|
|
+ return true;
|
|
|
},
|
|
|
-
|
|
|
analyzeUserExpr: function(calcTemplate, calcItem){
|
|
|
let me = this;
|
|
|
me.calcTemplate = calcTemplate;
|
|
|
let expr = calcItem.dispExpr;
|
|
|
- // 标准化:处理特殊字符、中文符号、大小写
|
|
|
expr = me.standard(expr);
|
|
|
calcItem.dispExpr = expr;
|
|
|
- // 先换掉计算基数
|
|
|
- expr = me.analyzeCalcBase(expr);
|
|
|
- // 再换掉行引用
|
|
|
- expr = me.analyzeLineRef(expr);
|
|
|
- calcItem.expression = expr;
|
|
|
- return me.success;
|
|
|
+ if (me.isLegal(expr)){
|
|
|
+ calcItem.expression = expr;
|
|
|
+ return true;
|
|
|
+ }else
|
|
|
+ return false;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -1079,10 +978,12 @@ class CalcProgram {
|
|
|
let nodes = (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees) ? treeNode.children : me.project.Ration.getRationNodes(treeNode);
|
|
|
let rst = [];
|
|
|
for (let ft of cpFeeTypes) {
|
|
|
+ let isEstimate = ft.name == '暂估费';
|
|
|
let ftObj = {};
|
|
|
ftObj.fieldName = ft.type;
|
|
|
ftObj.name = ft.name;
|
|
|
let buf = 0, btf = 0, btuf = 0, bttf = 0;
|
|
|
+ let bq = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
|
|
|
|
|
|
if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
|
|
|
for (let node of nodes) {
|
|
@@ -1097,7 +998,6 @@ class CalcProgram {
|
|
|
}
|
|
|
else if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){ // 这里的算法要配合冷姐姐的神图才能看懂^_^
|
|
|
let sum_rtf = 0, sum_rttf = 0;
|
|
|
- let bq = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
|
|
|
for (let node of nodes) {
|
|
|
let rq = calcTools.uiNodeQty(node) ? calcTools.uiNodeQty(node) : 0;
|
|
|
let ruf = 0, rtuf = 0, rtf = 0, rttf = 0;
|
|
@@ -1108,33 +1008,46 @@ class CalcProgram {
|
|
|
rttf = parseFloat(node.data.feesIndex[ft.type].tenderTotalFee);
|
|
|
};
|
|
|
if (me.project.property.billsCalcMode === leafBillGetFeeType.rationContent) {
|
|
|
- buf = (buf + (ruf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
|
|
|
- btuf = (btuf + (rtuf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
|
|
|
+ buf = (buf + (ruf * rq / bq).toDecimal(decimalObj.bills.unitFee)).toDecimal(decimalObj.bills.unitFee);
|
|
|
+ btuf = (btuf + (rtuf * rq / bq).toDecimal(decimalObj.bills.unitFee)).toDecimal(decimalObj.bills.unitFee);
|
|
|
};
|
|
|
sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
|
|
|
sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
|
|
|
};
|
|
|
-
|
|
|
- if (me.project.property.billsCalcMode == leafBillGetFeeType.rationPriceConverse ||
|
|
|
- me.project.property.billsCalcMode == leafBillGetFeeType.rationPrice) {
|
|
|
- buf = (sum_rtf / bq).toDecimal(decimalObj.process);
|
|
|
- btuf = (sum_rttf / bq).toDecimal(decimalObj.process);
|
|
|
- };
|
|
|
- if (isBaseFeeType(ft.type) ||
|
|
|
- (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice && ft.type == "common")){
|
|
|
+ if (isEstimate){
|
|
|
btf = sum_rtf;
|
|
|
bttf = sum_rttf;
|
|
|
- }
|
|
|
- else{
|
|
|
- btf = (buf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
|
|
|
- bttf = (btuf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
|
|
|
+ }else{
|
|
|
+ if (me.project.property.billsCalcMode == leafBillGetFeeType.rationPriceConverse ||
|
|
|
+ me.project.property.billsCalcMode == leafBillGetFeeType.rationPrice) {
|
|
|
+ buf = (sum_rtf / bq).toDecimal(decimalObj.process);
|
|
|
+ btuf = (sum_rttf / bq).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
+ if (isBaseFeeType(ft.type) ||
|
|
|
+ (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice && ft.type == "common")){
|
|
|
+ btf = sum_rtf;
|
|
|
+ bttf = sum_rttf;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ btf = (buf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
|
|
|
+ bttf = (btuf.toDecimal(decimalObj.bills.unitPrice) * bq).toDecimal(decimalObj.process);
|
|
|
+ };
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- ftObj.unitFee = buf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
ftObj.totalFee = btf.toDecimal(decimalObj.bills.totalPrice);
|
|
|
- ftObj.tenderUnitFee = btuf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
ftObj.tenderTotalFee = bttf.toDecimal(decimalObj.bills.totalPrice);
|
|
|
+ if (isEstimate){
|
|
|
+ if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){
|
|
|
+ ftObj.unitFee = (ftObj.totalFee / bq).toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ ftObj.tenderUnitFee = (ftObj.tenderTotalFee / bq).toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ ftObj.unitFee = buf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ ftObj.tenderUnitFee = btuf.toDecimal(decimalObj.bills.unitPrice);
|
|
|
+ }
|
|
|
+
|
|
|
calcTools.checkFeeField(treeNode, ftObj);
|
|
|
|
|
|
rst.push(ftObj);
|
|
@@ -1413,7 +1326,7 @@ class CalcProgram {
|
|
|
}
|
|
|
else{
|
|
|
if (node.sourceType != ModuleNames.ration_glj) {
|
|
|
- rst = (rst + calcTools.getFee(node, 'common.totalFee')).toDecimal(decimalObj.bills.totalPrice);
|
|
|
+ rst = (rst + calcTools.getFee(node, 'common.totalFee')).toDecimal(decimalObj.decimal("totalPrice", node));
|
|
|
};
|
|
|
}
|
|
|
}
|