Explorar o código

合同支付,支持删除、复制粘贴数据

MaiXinRong %!s(int64=6) %!d(string=hai) anos
pai
achega
54594363c2

+ 8 - 5
app/controller/stage_controller.js

@@ -427,6 +427,7 @@ module.exports = app => {
                 await payCalculator.calculateAll(renderData.dealPay);
                 await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs');
             } catch (err) {
+                console.log(err);
                 this.log(err);
                 ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage');
             }
@@ -438,6 +439,11 @@ module.exports = app => {
          * @returns {Promise<void>}
          */
         async savePayData(ctx) {
+            function checkCalcField(data) {
+                return data.sexpr !== undefined || data.sprice !== undefined
+                || data.rexpr !== undefined || data.rprice !== undefined
+                || data.minus !== undefined || data.is_yf !== undefined || data.dl_type !== undefined
+            }
             try {
                 // 检查登录用户,是否可操作
                 if (ctx.stage.readOnly) {
@@ -462,13 +468,10 @@ module.exports = app => {
                         break;
                     case 'info':
                         responseData.data = await ctx.service.pay.save(data.updateData);
-                        if (data.updateData.sexpr !== undefined || data.updateData.sprice !== undefined
-                            || data.updateData.rexpr !== undefined || data.updateData.rprice !== undefined
-                            || data.updateData.minus !== undefined || data.updateData.is_yf !== undefined
-                            || data.updateData.dl_type !== undefined) {
+                        const bReCalc = data.updateData instanceof Array ? checkCalcField(data.updateData[0]) : checkCalcField(data.updateData);
+                        if (bReCalc) {
                             responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage);
                             await payCalculator.calculateAll(responseData.data);
-                            //console.log(responseData.data[responseData.data.length - 1]);
                         } else {
                             responseData.data = await ctx.service.stagePay.getStagePay(ctx.stage, responseData.data.id);
                         }

+ 6 - 1
app/lib/pay_calc.js

@@ -51,7 +51,12 @@ class PayCalculate {
                 formula = formula.replace(p, v);
             }
         }
-        return math.eval(formula);
+        try {
+            const value = math.eval(formula);
+            return value;
+        } catch(err) {
+            return 0;
+        }
     }
 
     /**

+ 117 - 19
app/public/js/stage_pay.js

@@ -115,6 +115,21 @@ $(document).ready(() => {
     SpreadJsObj.loadSheetData(paySpread.getActiveSheet(), SpreadJsObj.DataType.Data, dealPay);
 
     const paySpreadObj = {
+        _checkExpr: function (text, data, priceField, exprField) {
+            if (text) {
+                const num = _.toNumber(text);
+                if (num) {
+                    data[priceField] = num;
+                    data[exprField] = null;
+                } else {
+                    data[exprField] = text.replace('=', '');
+                    data[priceField] = null;
+                }
+            } else {
+                data[priceField] = null;
+                data[exprField] = null;
+            }
+        },
         refreshActn: function () {
             const setObjEnable = function (obj, enable) {
                 if (enable) {
@@ -216,21 +231,6 @@ $(document).ready(() => {
             }
         },
         editEnded: function (e, info) {
-            const checkExpr = function (text, data, priceField, exprField) {
-                if (text) {
-                    const num = _.toNumber(text);
-                    if (num) {
-                        data[priceField] = num;
-                        data[exprField] = null;
-                    } else {
-                        data[exprField] = text;
-                        data[priceField] = null;
-                    }
-                } else {
-                    data[priceField] = null;
-                    data[exprField] = null;
-                }
-            };
             if (info.sheet.zh_setting) {
                 const select = SpreadJsObj.getSelectObject(info.sheet);
                 const col = info.sheet.zh_setting.cols[info.col];
@@ -261,14 +261,14 @@ $(document).ready(() => {
                 // 获取更新数据
                 if (col.field === 'tp') {
                     data.updateData.pid = select.pid;
-                    checkExpr(validText, data.updateData, 'tp', 'expr');
+                    paySpreadObj._checkExpr(validText, data.updateData, 'tp', 'expr');
                 } else {
                     data.updateData.id = select.pid;
                     if (validText) {
                         if (col.field === 'sprice') {
-                            checkExpr(validText, data.updateData, 'sprice', 'sexpr');
+                            paySpreadObj._checkExpr(validText, data.updateData, 'sprice', 'sexpr');
                         } else if (col.field === 'rprice') {
-                            checkExpr(validText, data.updateData, 'rprice', 'rexpr');
+                            paySpreadObj._checkExpr(validText, data.updateData, 'rprice', 'rexpr');
                         } else {
                             data.updateData[col.field] = validText;
                         }
@@ -327,7 +327,103 @@ $(document).ready(() => {
                     info.sheet.getCell(info.row, info.col).text(select.rexpr);
                 }
             }
-        }
+        },
+        deletePress: function (sheet) {
+            if (sheet.zh_setting && sheet.zh_data) {
+                const sel = sheet.getSelections()[0];
+                if (!sel) return;
+
+                const col = sheet.zh_setting.cols[sel.col];
+                if (col.readOnly === true) { return; }
+                if (sel.colCount > 1) {
+                    toast('请勿同时删除多列数据', 'warning');
+                }
+
+                const data = {type: col.field === 'tp' ? 'stage' : 'info', updateData: []};
+                for (let iRow = sel.row; iRow < sel.row + sel.rowCount; iRow++) {
+                    const node = sheet.zh_data[iRow];
+                    if (node) {
+                        const updateData = {};
+                        if (col.field === 'tp') {
+                            updateData.pid = node.pid;
+                            updateData.tp = null;
+                            updateData.expr = null;
+                        } else {
+                            updateData.id = node.pid;
+                            if (col.field === 'sprice') {
+                                updateData.sprice = null;
+                                updateData.sexpr = null;
+                            } else if (col.field === 'rprice') {
+                                updateData.rprice = null;
+                                updateData.rexpr = null;
+                            } else {
+                                updateData[col.field] = null;
+                            }
+                        }
+                        data.updateData.push(updateData);
+                    }
+                }
+                if (data.updateData.length > 0) {
+                    if (data.updateData.length === 1 && sel.rowCount === 1) {
+                        data.updateData = data.updateData[0];
+                    }
+                    postData(window.location.pathname + '/save', data, function (result) {
+                        loadUpdateDealPays(result);
+                        SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                    })
+                }
+            }
+        },
+        clipboardPasted: function (e, info) {
+            if (info.sheet.zh_setting && info.sheet.zh_data) {
+                const col = info.sheet.zh_setting.cols[info.cellRange.col];
+                if (col.readOnly === true) {
+                    SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                    return;
+                }
+                if (info.cellRange.colCount > 1) {
+                    toast('请勿同时删除多列数据', 'warning');
+                }
+
+                const sortData = info.sheet.zh_data;
+                const data = {type: col.field === 'tp' ? 'stage' : 'info', updateData: []};
+
+                for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                    const curRow = info.cellRange.row + iRow;
+                    const node = sortData[curRow];
+                    if (node) {
+                        const validText = info.sheet.getText(curRow, info.cellRange.col).replace('\n', '');
+                        const updateData = {};
+                        if (col.field === 'tp') {
+                            updateData.pid = node.pid;
+                            paySpreadObj._checkExpr(validText, updateData, 'tp', 'expr');
+                        } else {
+                            updateData.id = node.pid;
+                            if (validText) {
+                                if (col.field === 'sprice') {
+                                    paySpreadObj._checkExpr(validText, updateData, 'sprice', 'sexpr');
+                                } else if (col.field === 'rprice') {
+                                    paySpreadObj._checkExpr(validText, updateData, 'rprice', 'rexpr');
+                                } else {
+                                    updateData[col.field] = validText;
+                                }
+                            } else {
+                                updateData[col.field] = null;
+                            }
+                        }
+                        data.updateData.push(updateData);
+                    }
+                    if (data.updateData.length > 0) {
+                        postData(window.location.pathname + '/save', data, function (result) {
+                            loadUpdateDealPays(result);
+                            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                        }, function () {
+                            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                        });
+                    }
+                }
+            }
+        },
     };
     paySpreadObj.refreshActn();
     if (!readOnly) {
@@ -335,6 +431,8 @@ $(document).ready(() => {
         paySpread.bind(spreadNS.Events.SelectionChanged, paySpreadObj.selectionChanged);
         paySpread.bind(spreadNS.Events.ButtonClicked, paySpreadObj.buttonClicked);
         paySpread.bind(spreadNS.Events.EditStarting, paySpreadObj.editStarting);
+        paySpread.bind(spreadNS.Events.ClipboardPasted, paySpreadObj.clipboardPasted);
+        SpreadJsObj.addDeleteBind(paySpread, paySpreadObj.deletePress);
         $('#add').click(paySpreadObj.add);
         $('#del').click(paySpreadObj.del);
         $('#up-move').click(paySpreadObj.upMove);

+ 48 - 10
app/service/pay.js

@@ -161,25 +161,63 @@ module.exports = app => {
             }
         }
 
-        /**
-         * 保存合同支付项数据
-         * @param data
-         * @returns {Promise<boolean>}
-         */
-        async save(data) {
-            if (!this.ctx.tender || !this.ctx.stage) { return false; }
+        async _save(data, transaction) {
             const pay = await this.getDataByCondition({tid: this.ctx.tender.id, id: data.id});
             if(!pay) {
                 throw '数据错误';
             }
             const updateData = this.ctx.helper.filterValidFields(data, writableFields);
             updateData.id = data.id;
-            const result = await this.db.update(this.tableName, updateData);
-            if (result.affectedRows !== 1) {
-                throw '更新数据失败';
+            if (transaction) {
+                const result = await transaction.update(this.tableName, updateData);
+                if (result.affectedRows !== 1) {
+                    throw '更新数据失败';
+                }
+            } else {
+                const result = await this.db.update(this.tableName, updateData);
+                if (result.affectedRows !== 1) {
+                    throw '更新数据失败';
+                }
             }
             return updateData;
         }
+
+        /**
+         * 保存合同支付项数据
+         * @param data
+         * @returns {Promise<boolean>}
+         */
+        async save(data) {
+            if (!this.ctx.tender || !this.ctx.stage) { return false; }
+
+            if (data instanceof Array) {
+                const transaction = await this.db.beginTransaction();
+                const result = [];
+                try {
+                    for (const d of data) {
+                        const updateData = await this._save(d, transaction);
+                        result.push(updateData);
+                    }
+                    await transaction.commit();
+                } catch(err) {
+                    await transaction.rollback();
+                    throw err;
+                }
+                return result;
+            } else {
+                const pay = await this.getDataByCondition({tid: this.ctx.tender.id, id: data.id});
+                if(!pay) {
+                    throw '数据错误';
+                }
+                const updateData = this.ctx.helper.filterValidFields(data, writableFields);
+                updateData.id = data.id;
+                const result = await this.db.update(this.tableName, updateData);
+                if (result.affectedRows !== 1) {
+                    throw '更新数据失败';
+                }
+                return updateData;
+            }
+        }
     }
 
     return Pay;

+ 19 - 16
app/service/stage_pay.js

@@ -169,27 +169,30 @@ module.exports = app => {
          * @param data
          * @returns {Promise<void>}
          */
-        async save(data) {
+        async save(saveData) {
+            const datas = saveData instanceof Array ? saveData : [saveData];
             const transaction = await this.db.beginTransaction();
             try {
                 // 更新数据
-                const stagePay = await this.getStagePay(this.ctx.stage, data.pid);
-                const updateData = { id: stagePay.id };
-                if (data.expr !== undefined) { updateData.expr = data.expr }
-                if (data.tp !== undefined) { updateData.tp = data.tp }
-                if (data.pause !== undefined) { updateData.pause = data.pause }
-                const result = await transaction.update(this.tableName, updateData);
-                if (result.affectedRows !== 1) {
-                    throw '保存数据失败';
-                }
-                // 缓存至pay
-                if (data.expr !== undefined) {
-                    const pr = await transaction.update(this.ctx.service.pay.tableName, {
-                        id: data.pid, expr: data.expr
-                    });
-                    if (pr.affectedRows !== 1) {
+                for (const data of datas) {
+                    const stagePay = await this.getStagePay(this.ctx.stage, data.pid);
+                    const updateData = { id: stagePay.id };
+                    if (data.expr !== undefined) { updateData.expr = data.expr }
+                    if (data.tp !== undefined) { updateData.tp = data.tp }
+                    if (data.pause !== undefined) { updateData.pause = data.pause }
+                    const result = await transaction.update(this.tableName, updateData);
+                    if (result.affectedRows !== 1) {
                         throw '保存数据失败';
                     }
+                    // 缓存至pay
+                    if (data.expr !== undefined) {
+                        const pr = await transaction.update(this.ctx.service.pay.tableName, {
+                            id: data.pid, expr: data.expr
+                        });
+                        if (pr.affectedRows !== 1) {
+                            throw '保存数据失败';
+                        }
+                    }
                 }
                 await transaction.commit();
             } catch(err) {

+ 5 - 0
test/app/service/pay.test.js

@@ -56,6 +56,7 @@ describe('test/app/service/pay.test.js', () => {
         mockData.stage.curTimes = 1;
         mockData.stage.curOrder = 0;
     });
+    // 新增
     it('test add', function* () {
         const ctx = app.mockContext(mockData);
 
@@ -68,6 +69,7 @@ describe('test/app/service/pay.test.js', () => {
         const stagePays = yield ctx.service.stagePay.getStageLastestPays(ctx.stage.id);
         assert(stagePays.length === orgStagePays.length + 1);
     });
+    // 删除
     it('test del', function* () {
         const ctx = app.mockContext(mockData);
 
@@ -79,6 +81,7 @@ describe('test/app/service/pay.test.js', () => {
         const stagePays = yield ctx.service.stagePay.getStageLastestPays(ctx.stage.id);
         assert(stagePays.length === orgStagePays.length - 1);
     });
+    // 调整顺序
     it('test changeOrder', function* () {
         const ctx = app.mockContext(mockData);
 
@@ -98,6 +101,7 @@ describe('test/app/service/pay.test.js', () => {
 
         testPayId = node1.pid;
     });
+    // 名称
     it('test save', function* () {
         const ctx = app.mockContext(mockData);
         const data = {id: testPayId, name: '12345', invalidField: 'invalid'};
@@ -110,4 +114,5 @@ describe('test/app/service/pay.test.js', () => {
         const node = _.find(stagePays, {pid: testPayId});
         assert(node.name === data.name);
     });
+    // 扣款项/起扣金额/扣款限额/计提期限/停用/启用 等单元测试在stagePay.test.js中测试
 });