|
@@ -30,6 +30,38 @@ let cbTools = {
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ //通过行获取根节点清单
|
|
|
+ getBillByRow: function (items, row) {
|
|
|
+ if(cbTools.isDef(items[row]) &&
|
|
|
+ cbTools.isUnDef(items[row]['parent'])&&
|
|
|
+ cbTools.isDef(items[row]['sourceType']) &&
|
|
|
+ items[row]['sourceType'] === calcBase.project.Bills.getSourceType()){
|
|
|
+ return items[row];
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ //获取该节点所有父节点
|
|
|
+ getParents: function (node) {
|
|
|
+ let rst = [];
|
|
|
+ rParent(node);
|
|
|
+ return rst;
|
|
|
+ function rParent(node){
|
|
|
+ if(cbTools.isDef(node.parent)){
|
|
|
+ rst.push(node.parent);
|
|
|
+ rParent(node.parent);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //获取所有节点的ID
|
|
|
+ getNodeIDs: function (nodes) {
|
|
|
+ let rst = [];
|
|
|
+ for(let i = 0, len = nodes.length; i < len; i++){
|
|
|
+ if(this.isDef(nodes[i]['data']['ID'])){
|
|
|
+ rst.push(nodes[i]['data']['ID']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rst;
|
|
|
+ },
|
|
|
//需要用到计算基数的时候,先找出所有的固定清单,避免每个基数都要去遍历寻找清单
|
|
|
setFixedBills: function (project, billsObj, fixedFlag) {
|
|
|
let bills = project.Bills.datas;
|
|
@@ -150,11 +182,19 @@ let cbTools = {
|
|
|
return tempBases;
|
|
|
}
|
|
|
else {
|
|
|
+ //获取基数和行引用
|
|
|
getBase(node);
|
|
|
let bases = Array.from(new Set(tempBases));
|
|
|
+ //根据基数和行引用获取清单ID
|
|
|
for(let i = 0, len = bases.length; i < len; i++){
|
|
|
- if(cbTools.isDef(calcBase.baseFigures[bases[i]])){
|
|
|
- block.push(calcBase.baseFigures[bases[i]]['fixedBill']['bill']['ID']);
|
|
|
+ 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);
|
|
|
+ if(cbTools.isDef(node)){
|
|
|
+ block.push(node.data.ID);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return Array.from(new Set(block));
|
|
@@ -162,8 +202,8 @@ let cbTools = {
|
|
|
function getBase(node){
|
|
|
if(node && node.children.length === 0){
|
|
|
if(cbTools.isDef(node.data.calcBase) && node.data.calcBase !== ''){
|
|
|
- let figures = cbParser.getFigure(node.data.calcBase);
|
|
|
- tempBases = tempBases.concat(figures);
|
|
|
+ let figureF = cbParser.getFigureF(cbParser.getFigure(node.data.calcBase), cbParser.getRArr(cbParser.getFArr(node.data.calcBase)));
|
|
|
+ tempBases = tempBases.concat(figureF);
|
|
|
}
|
|
|
}
|
|
|
else if(node && node.children.length > 0) {
|
|
@@ -398,7 +438,7 @@ let cbAnalyzer = {
|
|
|
},
|
|
|
//输入合法性
|
|
|
inputLegal: function (exp) {
|
|
|
- let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,}]/g;
|
|
|
+ let ilegalRex = /[^0-9,\u4e00-\u9fa5,\+,\-,\/,\*,\(,\),.,{,},F]/g;
|
|
|
return !ilegalRex.test(exp);
|
|
|
},
|
|
|
//基数合法性、存在性
|
|
@@ -422,29 +462,61 @@ let cbAnalyzer = {
|
|
|
}
|
|
|
return true;
|
|
|
},
|
|
|
+ //行引用合法性、存在性
|
|
|
+ fLegal: function (items, exp) {
|
|
|
+ console.log(items);
|
|
|
+ console.log(exp);
|
|
|
+ //提取行引用
|
|
|
+ let fArr = cbParser.getFArr(exp);
|
|
|
+ //提取行数
|
|
|
+ let rArr = cbParser.getRArr(fArr);
|
|
|
+ //判断合法性和存在性
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
//循环计算
|
|
|
cycleCalc: function (node, baseFigures, exp) {
|
|
|
let stack = [];
|
|
|
if(node.sourceType !== calcBase.project.Bills.getSourceType()){
|
|
|
return false;
|
|
|
}
|
|
|
- let sbillID = cbTools.getBaseBill(node).data.ID;
|
|
|
- let expFigures = cbParser.getFigure(exp);
|
|
|
- for(let i = 0, len = expFigures.length; i < len; i++){
|
|
|
- let figure = expFigures[i];
|
|
|
- if(cbTools.isDef(baseFigures[figure])){
|
|
|
- let bill = baseFigures[figure]['fixedBill']['bill'];
|
|
|
- if(checkStack(getRefStack([bill.ID]), sbillID)){
|
|
|
- console.log('循环计算');
|
|
|
- calcBase.errMsg = '表达式出现循环计算';
|
|
|
- return true;
|
|
|
- }
|
|
|
+ //用于判断的起始清单ID
|
|
|
+ let sIDs = cbTools.getNodeIDs(Array.from(new Set([cbTools.getBaseBill(node)].concat(cbTools.getParents(node)))));
|
|
|
+ console.log(cbParser.getFArr(exp));
|
|
|
+ console.log(cbParser.getRArr(cbParser.getFArr(exp)));
|
|
|
+ let figureF = cbParser.getFigureF(cbParser.getFigure(exp), cbParser.getRArr(cbParser.getFArr(exp)));
|
|
|
+ console.log(figureF);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ if(cbTools.isDef(bill) && checkStack(getRefStack([bill.ID]), sIDs)){
|
|
|
+ console.log('循环计算');
|
|
|
+ calcBase.errMsg = '表达式出现循环计算';
|
|
|
+ return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
- function checkStack(stack, startBillID){
|
|
|
+ function checkStack(stack, sIDs){
|
|
|
//引用栈发现了初始引用
|
|
|
- return stack.indexOf(startBillID) !== -1;
|
|
|
+ for(let i = 0, len = sIDs.length; i < len; i++){
|
|
|
+ if(stack.indexOf(sIDs[i]) !== -1){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
function getRefStack(billIDs){
|
|
|
stack = Array.from(new Set(stack.concat(billIDs)));
|
|
@@ -458,25 +530,27 @@ let cbAnalyzer = {
|
|
|
return stack;
|
|
|
}
|
|
|
},
|
|
|
- //四则运算合法性,前端控制不允许重复出现运算符,这里主要判断()的使用问题,这里再判断一次
|
|
|
+ //四则运算合法性,前端控制不允许重复出现运算符,这里主要判断()的使用问题,这里再判断一次,控制行引用只能F
|
|
|
arithmeticLegal: function (exp) {
|
|
|
let ilegalRex = /[\+,\-,\*,\/]{2}/g;
|
|
|
let rex2 = /[{]{2}/g;
|
|
|
let rex3 = /[}]{2}/g;
|
|
|
- return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp);
|
|
|
+ let rex4 = /[F]{2}/g
|
|
|
+ return !ilegalRex.test(exp) && !rex2.test(exp) && !rex3.test(exp) && !rex4.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.cycleCalc(node, cbTools.getFigure(node), exp)){
|
|
|
- if(this.arithmeticLegal(exp)){
|
|
|
- return exp;
|
|
|
+ if(this.fLegal(calcBase.project.mainTree.items, exp)){
|
|
|
+ if(!this.cycleCalc(node, cbTools.getFigure(node), exp)){
|
|
|
+ if(this.arithmeticLegal(exp)){
|
|
|
+ return exp;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return null;
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
@@ -484,6 +558,22 @@ let cbAnalyzer = {
|
|
|
|
|
|
//输入式转换器
|
|
|
let cbParser = {
|
|
|
+ //获取行引用 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) {
|
|
|
+ let rRex = /\d+/g;
|
|
|
+ let tempArr = [];
|
|
|
+ for(let i = 0, len = fArr.length; i < len; i++){
|
|
|
+ tempArr = tempArr.concat(fArr[i].match(rRex));
|
|
|
+ }
|
|
|
+ let rArr = Array.from(new Set(tempArr));
|
|
|
+ return rArr;
|
|
|
+ },
|
|
|
//获取表达式中的中文式,没有{}需求时
|
|
|
getCN: function(expr){
|
|
|
let rst = [];
|
|
@@ -508,12 +598,30 @@ let cbParser = {
|
|
|
}
|
|
|
return rst;
|
|
|
},
|
|
|
+ //获取表达式中的基数和行
|
|
|
+ getFigureF: function (figures, rArr) {
|
|
|
+ let rst = [];
|
|
|
+ for(let i = 0, len = figures.length; i < len; i++){
|
|
|
+ let obj = Object.create(null);
|
|
|
+ obj.type = 'base';
|
|
|
+ obj.value = figures[i];
|
|
|
+ rst.push(obj);
|
|
|
+ }
|
|
|
+ for(let i = 0, len = rArr.length; i < len; i++){
|
|
|
+ let obj = Object.create(null);
|
|
|
+ obj.type = 'row';
|
|
|
+ obj.value = rArr[i];
|
|
|
+ rst.push(obj);
|
|
|
+ }
|
|
|
+ return rst;
|
|
|
+ },
|
|
|
|
|
|
//将表达式转换为可编译的表达式
|
|
|
toCompileExpr: function(v){
|
|
|
if(v === ''){
|
|
|
return '$CBC.base(\'NONE\')';
|
|
|
}
|
|
|
+ //基数
|
|
|
let strs = this.getFigure(v);
|
|
|
let exps = [];
|
|
|
for(let i = 0, len = strs.length; i < len; i++){
|
|
@@ -524,9 +632,20 @@ let cbParser = {
|
|
|
//去{}
|
|
|
v = v.replace(/[{, }]/g, '');
|
|
|
for(let i = 0, len = exps.length;i < len; i++){
|
|
|
- exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp;
|
|
|
- exps[i].compileExp = exps[i].compileExp + '\')';
|
|
|
- v = v.replace(new RegExp(exps[i].orgExp,"g"), exps[i].compileExp);
|
|
|
+ exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp + '\')';
|
|
|
+ v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
|
|
|
+ }
|
|
|
+ //行引用
|
|
|
+ let fArr = this.getFArr(v);
|
|
|
+ let fExps = [];
|
|
|
+ for(let i = 0, len = fArr.length; i < len; i++){
|
|
|
+ let fExp = Object.create(null);
|
|
|
+ fExp.orgExp = fArr[i];
|
|
|
+ fExps.push(fExp);
|
|
|
+ }
|
|
|
+ for(let i = 0, len = fExps.length; i < len; i++){
|
|
|
+ fExps[i].compileExp = '$CBC.f(\'' + fExps[i].orgExp + '\')';
|
|
|
+ v = v.replace(new RegExp(fExps[i].orgExp, 'g'), fExps[i].compileExp);
|
|
|
}
|
|
|
return v;
|
|
|
}
|
|
@@ -540,6 +659,14 @@ 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;
|
|
|
+ },
|
|
|
//计算
|
|
|
exec: function () {
|
|
|
|
|
@@ -576,7 +703,7 @@ let calcBase = {
|
|
|
getBaseBill: function (node) {
|
|
|
return cbTools.getBaseBill(node);
|
|
|
},
|
|
|
- calculate: function (node, reCalc) {
|
|
|
+ calculate: function (node, reCalc = null) {
|
|
|
let me = calcBase,
|
|
|
$CBA = cbAnalyzer,
|
|
|
$CBP = cbParser,
|
|
@@ -595,7 +722,6 @@ let calcBase = {
|
|
|
}
|
|
|
//输入式转换表达式
|
|
|
let compileExp = $CBP.toCompileExpr(exp);
|
|
|
-
|
|
|
//计算
|
|
|
let calcBaseValue = eval(compileExp);
|
|
|
if(!cbTools.isNum(calcBaseValue)){
|