|
@@ -1,9 +1,5 @@
|
|
|
'use strict';
|
|
|
|
|
|
-math.config({
|
|
|
- number: 'BigNumber',
|
|
|
-});
|
|
|
-
|
|
|
$(document).ready(() => {
|
|
|
const payUtils = {
|
|
|
tips: {
|
|
@@ -47,9 +43,9 @@ $(document).ready(() => {
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
- const payCalc = (function (b) {
|
|
|
+ const payCalc = (function (b, a) {
|
|
|
class PayCalc {
|
|
|
- constructor (bases) {
|
|
|
+ constructor (bases, add) {
|
|
|
this.percentReg = /((\d+)|((\d+)(\.\d+)))%/g;
|
|
|
this.bases = bases;
|
|
|
this.bases.sort(function (a, b) {
|
|
@@ -58,6 +54,7 @@ $(document).ready(() => {
|
|
|
for (const b of this.bases) {
|
|
|
b.reg = new RegExp(b.code, 'igm');
|
|
|
}
|
|
|
+ this.addBase = add;
|
|
|
this.orderReg = /f\d+/ig;
|
|
|
this.nodeReg = /<<[a-z0-9\-]+>>/ig;
|
|
|
}
|
|
@@ -83,17 +80,241 @@ $(document).ready(() => {
|
|
|
}
|
|
|
return expr;
|
|
|
}
|
|
|
- checkSfExpr() {
|
|
|
+ checkExprValid(expr, invalidParam, selfId, payTree) {
|
|
|
+ if (!expr) return [true, ''];
|
|
|
+ const param = [];
|
|
|
+ let num = '', base = '';
|
|
|
+ let fixedIdParam;
|
|
|
+ for (let i = 0, iLen = expr.length; i < iLen; i++) {
|
|
|
+ const subExpr = expr.substring(i, expr.length);
|
|
|
+ if (/^[\d\.%]+/.test(expr[i])) {
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ num = num + expr[i];
|
|
|
+ } else if (this.nodeReg.test(subExpr)) {
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ // const node = this.nodeReg.exec(subExpr);
|
|
|
+ const node = subExpr.match(this.nodeReg);
|
|
|
+ param.push({type: 'node', value: node[0]});
|
|
|
+ i = i + node[0].length - 1;
|
|
|
+ } else if (/^[a-z]/.test(expr[i])) {
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ base = base + expr[i];
|
|
|
+ } else if (expr[i] === '(') {
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ param.push({type: 'left', value: '('});
|
|
|
+ } else if (expr[i] === ')') {
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ param.push({type: 'right', value: ')'});
|
|
|
+ } else if (/^[\+\-*\/]/.test(expr[i])) {
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ param.push({type: 'calc', value: expr[i]});
|
|
|
+ } else {
|
|
|
+ return [false, '输入的表达式含有非法字符: ' + expr[i]];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (num !== '') {
|
|
|
+ param.push({type: 'num', value: num});
|
|
|
+ num = '';
|
|
|
+ }
|
|
|
+ if (base !== '') {
|
|
|
+ param.push({type: 'base', value: base});
|
|
|
+ base = '';
|
|
|
+ }
|
|
|
+ if (param.length === 0) return [true, ''];
|
|
|
+ if (param.length > 1) {
|
|
|
+ if (param[0].value === '-' && param[1].type === 'num') {
|
|
|
+ param[1].value = '-' + param[1].value;
|
|
|
+ param.shift();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const iLen = param.length;
|
|
|
+ let iLeftCount = 0, iRightCount = 0;
|
|
|
+ for (const [i, p] of param.entries()) {
|
|
|
+ if (p.type === 'calc') {
|
|
|
+ if (i === 0 || i === iLen - 1)
|
|
|
+ return [false, '输入的表达式非法:计算符号' + p.value + '前后应有数字或计算基数'];
|
|
|
+ }
|
|
|
+ if (p.type === 'num') {
|
|
|
+ num = p.value.replace('%', '');
|
|
|
+ if (p.value.length - num.length > 1)
|
|
|
+ return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
|
|
|
+ num = _.toNumber(num);
|
|
|
+ if (num === undefined || num === null || _.isNaN(num))
|
|
|
+ return [false, '输入的表达式非法:' + p.value + '不是一个有效的数字'];
|
|
|
+ if (i > 0) {
|
|
|
+ if (param[i - 1].type !== 'calc' && param[i - 1].type !== 'left') {
|
|
|
+ return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
|
|
|
+ } else if (param[i - 1].value === '/' && num === 0) {
|
|
|
+ return [false, '输入的表达式非法:请勿除0'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (p.type === 'base') {
|
|
|
+ const baseParam = _.find(calcBase, {code: p.value});
|
|
|
+ if (!baseParam)
|
|
|
+ return [false, '输入的表达式非法:不存在计算基数' + p.value];
|
|
|
+ if (invalidParam && invalidParam.indexOf(p.value) >= 0)
|
|
|
+ return [false, '不可使用计算基数' + p.value];
|
|
|
+ if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
|
|
|
+ return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
|
|
|
+ }
|
|
|
+ if (p.type === 'node') {
|
|
|
+ if (!selfId) return [false, '输入的表达式错误:不支持行号引用'];
|
|
|
|
|
|
- }
|
|
|
- checkExpr() {
|
|
|
+ if ([`<<${selfId}>>`].indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用自己'];
|
|
|
+ if (!fixedIdParam) {
|
|
|
+ fixedIdParam = payTree.nodes.filter(x => { return x.is_fixed; }).map(x => { return `<<${x.uuid}>>`});
|
|
|
+ }
|
|
|
+ if (fixedIdParam.indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用固定项'];
|
|
|
+ }
|
|
|
+ if (p.type === 'left') {
|
|
|
+ iLeftCount += 1;
|
|
|
+ if (i !== 0 && param[i-1].type !== 'calc')
|
|
|
+ return [false, '输入的表达式非法:(前应有运算符'];
|
|
|
+ }
|
|
|
+ if (p.type === 'right') {
|
|
|
+ iRightCount += 1;
|
|
|
+ if (i !== iLen - 1 && param[i+1].type !== 'calc')
|
|
|
+ return [false, '输入的表达式非法:)后应有运算符'];
|
|
|
+ if (iRightCount > iLeftCount)
|
|
|
+ return [false, '输入的表达式非法:")"前无对应的"("'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (iLeftCount > iRightCount)
|
|
|
+ return [false, '输入的表达式非法:"("后无对应的")"'];
|
|
|
|
|
|
+ if (selfId) {
|
|
|
+ const circular = payCalc.checkCircularExpr(expr, selfId, payTree);
|
|
|
+ // 当前循环计算不检查父项
|
|
|
+ if (circular) return [false, '输入的表达式非法:循环引用'];
|
|
|
+ }
|
|
|
+ return [true, ''];
|
|
|
}
|
|
|
- checkRangeExpr() {
|
|
|
+ checkSfExpr(text, data, payNode, payTree) {
|
|
|
+ if (text) {
|
|
|
+ const num = _.toNumber(text);
|
|
|
+ if (num) {
|
|
|
+ data.expr = num;
|
|
|
+ } else {
|
|
|
+ const expr = this.trans2NodeExpr($.trim(text).replace('\t', '').replace('=', '').toLowerCase(), payTree);
|
|
|
+ const [valid, msg] = this.checkExprValid(expr, [], payNode.uuid, payTree);
|
|
|
+ if (!valid) return [valid, msg];
|
|
|
+ data.expr = expr;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ data.tp = 0;
|
|
|
+ data.expr = '';
|
|
|
+ }
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+ checkExpr(text, data, payNode, payTree) {
|
|
|
+ if (text) {
|
|
|
+ const num = _.toNumber(text);
|
|
|
+ if (num) {
|
|
|
+ data.tp = num;
|
|
|
+ data.expr = '';
|
|
|
+ } else {
|
|
|
+ const expr = this.trans2NodeExpr($.trim(text).replace('\t', '').replace('=', '').toLowerCase(), payTree);
|
|
|
+ const [valid, msg] = this.checkExprValid(expr, ['bqyf'], payNode.uuid, payTree);
|
|
|
+ if (!valid) return [valid, msg];
|
|
|
+ data.expr = expr;
|
|
|
+ data.tp = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ data.tp = 0;
|
|
|
+ data.expr = '';
|
|
|
+ }
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+ checkRangeExpr(payNode, text, data) {
|
|
|
+ if (!payNode) return [false, '数据错误'];
|
|
|
|
|
|
+ const num = text ? _.toNumber(text) : null;
|
|
|
+ let expr = text ? (num ? null : text) : null;
|
|
|
+ expr = expr ? $.trim(expr).replace('\t', '').replace('=', '').toLowerCase(): null;
|
|
|
+ const [valid, msg] = this.checkExprValid(expr, ['bqwc', 'ybbqwc', 'bqht', 'bqbg', 'bqyf']);
|
|
|
+ if (!valid) return [valid, msg];
|
|
|
+
|
|
|
+ if (payUtils.check.isStarted(payNode)) {
|
|
|
+ if (payUtils.check.isSf(payNode)) {
|
|
|
+ const value = expr ? payCalc.calculateExpr(expr) : num;
|
|
|
+ if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
|
|
|
+ data.rprice = num;
|
|
|
+ data.rexpr = expr;
|
|
|
+ return [true, ''];
|
|
|
+ } else {
|
|
|
+ // if (payNode.pre_finish) return [false, '已达扣款限额,请勿修改'];
|
|
|
+ // const value = expr ? payCalc.calculateExpr(expr) : num;
|
|
|
+ // if (payNode.pre_tp && value < payNode.pre_tp) return [false, '截止上期已计量' + payNode.pre_tp + ',扣款限额请勿少于改值'];
|
|
|
+ // data.rprice = num;
|
|
|
+ // data.rexpr = expr;
|
|
|
+ return [false, '已经开始使用,请勿修改扣款限额'];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ data.rprice = num;
|
|
|
+ data.rexpr = expr;
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
}
|
|
|
- checkStartExpr() {
|
|
|
+ checkStartExpr(payNode, text, data) {
|
|
|
+ if (!payNode) return [false, '数据错误'];
|
|
|
|
|
|
+ const num = text ? _.toNumber(text) : null;
|
|
|
+ let expr = text ? (num ? null : text) : null;
|
|
|
+ expr = expr ? $.trim(expr).replace('\t', '').replace('=', '').toLowerCase(): null;
|
|
|
+ const [valid, msg] = this.checkExprValid(expr, ['bqwc', 'ybbqwc', 'bqht', 'bqbg', 'bqyf']);
|
|
|
+ if (!valid) return [valid, msg];
|
|
|
+
|
|
|
+ if (payUtils.check.isStarted(payNode)) {
|
|
|
+ return [false, '已经开始计量,请勿修改起扣金额'];
|
|
|
+ } else {
|
|
|
+ if (this.addBase.pre_gather_tp) {
|
|
|
+ const value = expr ? payCalc.calculateExpr(expr) : num;
|
|
|
+ if (this.addBase.pre_gather_tp && value < this.addBase.pre_gather_tp)
|
|
|
+ return [false, '起扣金额请勿少于本期完成截止上期计量金额' + this.addBase.pre_gather_tp];
|
|
|
+ data.sprice = num;
|
|
|
+ data.sexpr = expr;
|
|
|
+ return [true, ''];
|
|
|
+ } else {
|
|
|
+ data.sprice = num;
|
|
|
+ data.sexpr = expr;
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
getExprInfo(field, converse = false) {
|
|
|
const exprField = [
|
|
@@ -104,34 +325,32 @@ $(document).ready(() => {
|
|
|
if (converse) return _.find(exprField, { expr: field });
|
|
|
return _.find(exprField, {qty: field});
|
|
|
}
|
|
|
-
|
|
|
- getLeafOrder(data, parentOrder) {
|
|
|
+ getLeafOrder(data, parentReg, tree) {
|
|
|
if (!data) return [];
|
|
|
- const defaultResult = data.order ? [`f${data.order}`] : [];
|
|
|
+ const defaultResult = data.uuid ? [`<<${data.uuid}>>`] : [];
|
|
|
if (!data.expr) return defaultResult;
|
|
|
- const orderParam = data.expr.match(this.orderReg);
|
|
|
- if (!orderParam || orderParam.length === 0) return defaultResult;
|
|
|
+ const nodeParam = data.expr.match(this.nodeReg);
|
|
|
+ if (!nodeParam || nodeParam.length === 0) return defaultResult;
|
|
|
|
|
|
- const result = [], payData = paySheet.zh_data || [];
|
|
|
- for (const op of orderParam) {
|
|
|
- const order = op.substring(1, op.length);
|
|
|
- if (data.order === parseInt(order) || op === parentOrder) {
|
|
|
+ const result = [];
|
|
|
+ for (const op of nodeParam) {
|
|
|
+ const id = op.substring(2, op.length - 2);
|
|
|
+ if (data.uuid === id || op === parentReg) {
|
|
|
result.push(op);
|
|
|
} else {
|
|
|
- const subOrderParam = this.getLeafOrder(payData[parseInt(order) -1], data.order ? `f${data.order}` : parentOrder);
|
|
|
+ const payNode = tree.nodes.find(x => {return x.uuid === id; });
|
|
|
+ const subOrderParam = this.getLeafOrder(payNode, data.uuid ? `<<${data.uuid}>>` : parentReg, tree);
|
|
|
result.push(...subOrderParam);
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
+ checkCircularExpr(expr, selfId, tree) {
|
|
|
+ const leafOrder = this.getLeafOrder({expr}, `<<${selfId}>>`, tree);
|
|
|
|
|
|
- checkCircularExpr(expr, selfOrder) {
|
|
|
- const leafOrder = this.getLeafOrder({expr}, `f${selfOrder}`);
|
|
|
-
|
|
|
- if (leafOrder.indexOf(`f${selfOrder}`) >= 0 || leafOrder.indexOf(`F${selfOrder}`) >= 0) return true;
|
|
|
+ if (leafOrder.indexOf(`<<${selfId}>>`) >= 0) return true;
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
calculateExpr(expr) {
|
|
|
let formula = expr;
|
|
|
for (const b of this.bases) {
|
|
@@ -145,7 +364,7 @@ $(document).ready(() => {
|
|
|
}
|
|
|
}
|
|
|
try {
|
|
|
- const value = parseFloat(math.evaluate(formula));
|
|
|
+ const value = ZhCalc.mathCalcExpr(formula);
|
|
|
return value;
|
|
|
} catch(err) {
|
|
|
return 0;
|
|
@@ -153,8 +372,8 @@ $(document).ready(() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return new PayCalc(b);
|
|
|
- })(calcBase);
|
|
|
+ return new PayCalc(b, a);
|
|
|
+ })(calcBase, addBase);
|
|
|
const payObj = (function() {
|
|
|
const spread = SpreadJsObj.createNewSpread($('#pay-spread')[0]);
|
|
|
const sheet = spread.getActiveSheet();
|
|
@@ -261,7 +480,6 @@ $(document).ready(() => {
|
|
|
const rows = [];
|
|
|
for (const u of data.update) {
|
|
|
rows.push(tree.nodes.indexOf(u));
|
|
|
- billsTag.refreshBillsTagView(u);
|
|
|
}
|
|
|
SpreadJsObj.reLoadRowsData(sheet, rows);
|
|
|
}
|
|
@@ -305,7 +523,7 @@ $(document).ready(() => {
|
|
|
const col = info.sheet.zh_setting.cols[info.col];
|
|
|
if (col.field === 'is_gather') return;
|
|
|
// 未改变值则不提交
|
|
|
- const validText = info.editingText ? info.editingText.replace('\n', '') : null;
|
|
|
+ const validText = info.editingText ? info.editingText.replace('\n', '') : '';
|
|
|
let orgValue;
|
|
|
if (col.field === 'tp') {
|
|
|
orgValue = select.expr ? payCalc.trans2OrderExpr(select.expr, payTree) : select.tp;
|
|
@@ -316,16 +534,18 @@ $(document).ready(() => {
|
|
|
} else {
|
|
|
orgValue = select[col.field];
|
|
|
}
|
|
|
- if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
|
|
|
+ orgValue = orgValue || '';
|
|
|
+ if (orgValue == validText) {
|
|
|
SpreadJsObj.reLoadRowData(info.sheet, info.row);
|
|
|
return;
|
|
|
}
|
|
|
- const data = { postType: 'update', postData: {} };
|
|
|
+
|
|
|
+ const data = { postType: 'update', postData: { id: select.id } };
|
|
|
switch(col.field) {
|
|
|
case 'tp':
|
|
|
- const [tpValid, tpMsg] = payUtils.isSF(select)
|
|
|
- ? payCalc.checkSfExpr(validText, data.updateData, select.order)
|
|
|
- : payCalc.checkExpr(validText, data.updateData, select.order);
|
|
|
+ const [tpValid, tpMsg] = payUtils.check.isSf(select)
|
|
|
+ ? payCalc.checkSfExpr(validText, data.postData, select, payTree)
|
|
|
+ : payCalc.checkExpr(validText, data.postData, select, payTree);
|
|
|
if (!tpValid) {
|
|
|
toastr.warning(tpMsg);
|
|
|
SpreadJsObj.reLoadRowData(info.sheet, info.row);
|
|
@@ -333,7 +553,7 @@ $(document).ready(() => {
|
|
|
}
|
|
|
break;
|
|
|
case 'start_tp':
|
|
|
- const [sValid, sMsg] = payCalc.checkStartExpr(select, validText, data.updateData);
|
|
|
+ const [sValid, sMsg] = payCalc.checkStartExpr(select, validText, data.postData);
|
|
|
if (!sValid) {
|
|
|
toastr.warning(sMsg);
|
|
|
SpreadJsObj.reLoadRowData(info.sheet, info.row);
|
|
@@ -341,7 +561,7 @@ $(document).ready(() => {
|
|
|
}
|
|
|
break;
|
|
|
case 'range_tp':
|
|
|
- const [rValid, rMsg] = payCalc.checkRangeExpr(select, validText, data.updateData);
|
|
|
+ const [rValid, rMsg] = payCalc.checkRangeExpr(select, validText, data.postData);
|
|
|
if (!rValid) {
|
|
|
toastr.warning(rMsg);
|
|
|
SpreadJsObj.reLoadRowData(info.sheet, info.row);
|
|
@@ -357,7 +577,12 @@ $(document).ready(() => {
|
|
|
break;
|
|
|
}
|
|
|
postData('update', data, function (result) {
|
|
|
- payEvent.reloadPays(result.reload);
|
|
|
+ if (result.reload) {
|
|
|
+ payEvent.reloadPays(result.reload);
|
|
|
+ } else {
|
|
|
+ const refreshData = payTree.loadPostData(result);
|
|
|
+ payEvent.refreshTree(refreshData);
|
|
|
+ }
|
|
|
}, function () {
|
|
|
SpreadJsObj.reLoadRowData(info.sheet, info.row);
|
|
|
});
|