Browse Source

合同支付,计算相关

MaiXinRong 2 years ago
parent
commit
c1e1ddf6ea
2 changed files with 93 additions and 10 deletions
  1. 39 3
      app/lib/pay_calc.js
  2. 54 7
      app/public/js/stage_pay.js

+ 39 - 3
app/lib/pay_calc.js

@@ -23,6 +23,7 @@ class PayCalculate {
         this.percentReg = /((\d+)|((\d+)(\.\d+)))%/g;
         this.tenderInfo = tenderInfo;
         this.decimal = tenderInfo.decimal.pay ? tenderInfo.decimal.payTp : tenderInfo.decimal.tp;
+        this.orderReg = /f\d+/ig;
         /* 以下变量在调用calculate方法后获得
         this.add;
         this.pre;
@@ -51,8 +52,16 @@ class PayCalculate {
         }
     }
 
-    _calculateTpExpr(pay) {
+    _calculateTpExpr(pay, pays) {
         let formula = pay.expr;
+        const orderParam = pay.expr.match(this.orderReg);
+        if (orderParam) {
+            for (const op of orderParam) {
+                const order = parseInt(op.substring(1, op.length));
+                const orderPay = pays.find(x => { return x.order === order });
+                formula = formula.replace(op, orderPay.tp || 0);
+            }
+        }
         for (const b of this.bases) {
             if ((b.code === 'bqwc' || b.code === 'bqht') && (!pay.pre_used && pay.sprice)) {
                 switch (b.code) {
@@ -177,6 +186,31 @@ class PayCalculate {
         }
     }
 
+    getLeafOrder(data, pays) {
+        if (!data) return [];
+        if (!data.expr) return [`f${data.order}`];
+        const orderParam = data.expr.match(this.orderReg);
+        if (!orderParam || orderParam.length === 0) return [`f${data.order}`];
+
+        const result = [...orderParam];
+        for (const op of orderParam) {
+            const order = op.substring(1, op.length);
+            result.push(...this.getLeafOrder(pays[parseInt(order) -1], pays));
+        }
+        return this.ctx.helper._.uniq(result);
+    }
+
+    sortPaysByCalc(pays) {
+        for (const pay of pays) {
+            pay.calcLeaf = this.getLeafOrder(pay, pays);
+        }
+        pays.sort((x, y) => {return x.calcLeaf.length - y.calcLeaf.length; });
+    }
+
+    sortPaysByOrder(pays) {
+        pays.sort((x, y) => { return x.order - y.order; });
+    }
+
     /**
      * 计算本期、截止本期金额
      * @param {Array} pays - (标段&期)合同支付数据
@@ -195,7 +229,7 @@ class PayCalculate {
             if (p.ptype === payType.normal || p.ptype === payType.wc) {
                 if (!p.pause && (!p.sprice || this.add.gather_tp >= p.sprice)) {
                     if (p.expr && p.expr !== '') {
-                        const value = this.ctx.helper.round(this._calculateTpExpr(p), this.decimal);
+                        const value = this.ctx.helper.round(this._calculateTpExpr(p, pays), this.decimal);
                         if (p.rprice) {
                             if (this._checkDeadline(p)) {
                                 p.tp = this.ctx.helper.sub(p.rprice, p.pre_tp);
@@ -248,7 +282,7 @@ class PayCalculate {
                 this.sf.tp = this.yf.tp;
             }
         } else {
-            const value = this.ctx.helper.round(this._calculateTpExpr(this.sf), this.decimal);
+            const value = this.ctx.helper.round(this._calculateTpExpr(this.sf, pays), this.decimal);
             if (this.sf.rprice) {
                 this.sf.tp = Math.min(this.ctx.helper.sub(this.sf.rprice, this.sf.pre_tp), value);
             } else {
@@ -262,7 +296,9 @@ class PayCalculate {
         await this.getCalcBase();
         await this._getAddCalcRela();
         await this.calculateStartRangePrice(pays);
+        this.sortPaysByCalc(pays);
         await this.calculate(pays);
+        this.sortPaysByOrder(pays);
     }
 }
 

+ 54 - 7
app/public/js/stage_pay.js

@@ -59,6 +59,28 @@ $(document).ready(() => {
                 for (const b of this.bases) {
                     b.reg = new RegExp(b.code, 'igm');
                 }
+                this.orderReg = /f\d+/ig;
+            }
+
+            getLeafOrder(data) {
+                if (!data) return [];
+                if (!data.expr) return [`f${data.order}`];
+                const orderParam = data.expr.match(this.orderReg);
+                if (!orderParam || orderParam.length === 0) return [`f${data.order}`];
+
+                const result = [], payData = paySheet.zh_data || [];
+                for (const op of orderParam) {
+                    const order = op.substring(1, op.length);
+                    result.push(...this.getLeafOrder(payData[parseInt(order) -1]));
+                }
+                return result;
+            }
+
+            checkCircularExpr(expr, selfOrder) {
+                const leafOrder = this.getLeafOrder({expr});
+
+                if (leafOrder.indexOf(`f${selfOrder}`) >= 0 || leafOrder.indexOf(`F${selfOrder}`) >= 0) return true;
+                return false;
             }
 
             calculateExpr(expr) {
@@ -85,6 +107,7 @@ $(document).ready(() => {
         return new PayCalc(b);
     })(calcBase);
     const paySpread = SpreadJsObj.createNewSpread($('#pay-spread')[0]);
+    const paySheet = paySpread.getActiveSheet();
     const wcPay = dealPay.find(function (x) {return x.ptype === 4});
 
     $.subMenu({
@@ -230,7 +253,6 @@ $(document).ready(() => {
         },
         isLock: function (data) {
             const result = !!lockPayExpr && payBase.isStarted(data) && payBase.hasBase(data);
-            console.log(data.name, result);
             return result;
         }
     };
@@ -309,17 +331,31 @@ $(document).ready(() => {
     SpreadJsObj.loadSheetData(paySpread.getActiveSheet(), SpreadJsObj.DataType.Data, dealPay);
 
     const paySpreadObj = {
-        _checkExprValid(expr, invalidParam) {
+        _checkExprValid(expr, invalidParam, selfOrder) {
             if (!expr) return [true, null];
             const param = [];
+            const orderReg = /^f\d+/i;
             let num = '', base = '';
             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 (orderReg.test(subExpr)) {
+                    if (num !== '') {
+                        param.push({type: 'num', value: num});
+                        num = '';
+                    }
+                    if (base !== '') {
+                        param.push({type: 'base', value: base});
+                        base = '';
+                    }
+                    const order = orderReg.exec(subExpr);
+                    param.push({type: 'order', value: order[0]});
+                    i = i + order[0].length - 1;
                 } else if (/^[a-z]/.test(expr[i])) {
                     if (num !== '') {
                         param.push({type: 'num', value: num});
@@ -406,6 +442,12 @@ $(document).ready(() => {
                     if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
                         return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
                 }
+                if (p.type === 'order') {
+                    if (selfOrder === undefined) return [false, '输入的表达式错误:不支持行号引用'];
+
+                    if ([`f${selfOrder}`, `F${selfOrder}`].indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用自己'];
+                    if (['f1', 'f2', 'f3', 'F1', 'F2', 'F3'].indexOf(p.value) >= 0) return [false, '输入的表达式非法:请勿引用前三行'];
+                }
                 if (p.type === 'left') {
                     iLeftCount += 1;
                     if (i !== 0 && param[i-1].type !== 'calc')
@@ -421,6 +463,11 @@ $(document).ready(() => {
             }
             if (iLeftCount > iRightCount)
                 return [false, '输入的表达式非法:"("后无对应的")"'];
+
+            if (selfOrder !== undefined) {
+                const circular = payCalc.checkCircularExpr(expr);
+                if (circular) return [false, '输入的表达式非法:循环引用'];
+            }
             return [true, ''];
         },
         _checkSExpr: function (payNode, text, data) {
@@ -479,7 +526,7 @@ $(document).ready(() => {
                 return [true, ''];
             }
         },
-        _checkExpr: function (text, data) {
+        _checkExpr: function (text, data, order) {
             if (text) {
                 const num = _.toNumber(text);
                 if (num) {
@@ -487,7 +534,7 @@ $(document).ready(() => {
                     data.expr = null;
                 } else {
                     const expr = $.trim(text).replace('\t', '').replace('=', '').toLowerCase();
-                    const [valid, msg] = this._checkExprValid(expr, ['bqyf']);
+                    const [valid, msg] = this._checkExprValid(expr, ['bqyf'], order);
                     if (!valid) return [valid, msg];
                     data.expr = expr;
                     data.tp = null;
@@ -675,7 +722,7 @@ $(document).ready(() => {
                     case 'tp':
                         const [tpValid, tpMsg] = payBase.isSF(select)
                             ? paySpreadObj._checkSfExpr(validText, data.updateData)
-                            : paySpreadObj._checkExpr(validText, data.updateData);
+                            : paySpreadObj._checkExpr(validText, data.updateData, select.order);
                         if (!tpValid) {
                             toastr.warning(tpMsg);
                             SpreadJsObj.reLoadRowData(info.sheet, info.row);
@@ -848,7 +895,7 @@ $(document).ready(() => {
                             case 'tp':
                                 const [tpValid, tpMsg] = payBase.isSF(node)
                                     ? paySpreadObj._checkSfExpr(validText, updateData)
-                                    : paySpreadObj._checkExpr(validText, updateData);
+                                    : paySpreadObj._checkExpr(validText, updateData, select.order);
                                 if (!tpValid) {
                                     toastr.warning(tpMsg);
                                     SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
@@ -923,7 +970,7 @@ $(document).ready(() => {
                 data.updateData = { pid: select.pid, tp: null, expr: newValue };
                 const [valid, msg] = payBase.isSF(select)
                     ? paySpreadObj._checkSfExpr(newValue, data.updateData)
-                    : paySpreadObj._checkExpr(newValue, data.updateData);
+                    : paySpreadObj._checkExpr(newValue, data.updateData, select.order);
                 if (!valid) {
                     toastr.warning(msg);
                     this.value = select.expr;