Browse Source

合同支付bug和材料调差增删改

laiguoran 5 years ago
parent
commit
ee92fdfa67

+ 9 - 9
app/const/material.js

@@ -10,18 +10,18 @@
 
 
 // 调差类型
 // 调差类型
 const t_type = [
 const t_type = [
-    { key: 1, value: '消耗量' },
-    { key: 2, value: '费用' },
+    { text: '消耗量', value: 1 },
+    { text: '费用', value: 2 },
 ];
 ];
 // 工料分类
 // 工料分类
 const m_type = [
 const m_type = [
-    { key: 1, value: '分类' },
-    { key: 2, value: '钢材' },
-    { key: 3, value: '地材' },
-    { key: 4, value: '油料' },
-    { key: 5, value: '水泥' },
-    { key: 6, value: '半成品' },
-    { key: 7, value: '其他' },
+    { text: '分类', value: 1 },
+    { text: '钢材', value: 2 },
+    { text: '地材', value: 3 },
+    { text: '油料', value: 4 },
+    { text: '水泥', value: 5 },
+    { text: '半成品', value: 6 },
+    { text: '其他', value: 7 },
 ];
 ];
 
 
 module.exports = {
 module.exports = {

+ 17 - 18
app/const/spread.js

@@ -419,30 +419,29 @@ measure.compare.pos = {
 const material = {
 const material = {
     bill: {
     bill: {
         cols: [
         cols: [
-            {title: '调差类型', colSpan: '1', rowSpan: '2', field: 't_type', hAlign: 0, width: 80, formatter: '@'},
-            {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@'},
-            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 1, width: 180, formatter: '@', cellType: 'unit'},
-            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 2, width: 60, type: 'Number'},
-            {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 2, width: 230, type: 'Number'},
-            {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 2, width: 60, type: 'Number'},
-            {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number'},
-            {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 60, type: 'Number'},
-            {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 2, width: 60, type: 'Number'},
-            {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number'},
-            {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 2, width: 60, type: 'Number'},
-            {title: '|价差', colSpan: '1', rowSpan: '1|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number'},
-            {title: '本期材料调差|风险幅度(%)', colSpan: '3|1', rowSpan: '1|1', field: 'm_risk', hAlign: 2, width: 100, type: 'Number'},
-            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number'},
-            {title: '|调整金额', colSpan: '|1', rowSpan: '1|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number'},
-            {title: '截止上期调差金额', colSpan: '1', rowSpan: '2', field: 'pre_tp', hAlign: 2, width: 120, type: 'Number'},
-            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 2, width: 60, formatter: '@'},
+            {title: '调差类型', colSpan: '1', rowSpan: '2', field: 't_type', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.t_type', cellType: 'select'},
+            {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.code'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 1, width: 180, formatter: '@', readOnly: 'readOnly.name'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 2, width: 60, formatter: '@', readOnly: 'readOnly.unit'},
+            {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 2, width: 230, formatter: '@', readOnly: 'readOnly.spec'},
+            {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 2, width: 60, readOnly: 'readOnly.m_type', cellType: 'select'},
+            {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.basic_price'},
+            {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 2, width: 60, formatter: '@', readOnly: 'readOnly.basic_times'},
+            {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
+            {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 2, width: 60, formatter: '@', readOnly: 'readOnly.msg_times'},
+            {title: '|价差', colSpan: '1', rowSpan: '1|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '本期材料调差|风险幅度(%)', colSpan: '3|1', rowSpan: '1|1', field: 'm_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.m_risk'},
+            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '|调整金额', colSpan: '|1', rowSpan: '1|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '截止上期调差金额', colSpan: '1', rowSpan: '2', field: 'pre_tp', hAlign: 2, width: 120, type: 'Number', readOnly: true},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 2, width: 60, formatter: '@', readOnly: 'readOnly.remark'},
         ],
         ],
         emptyRows: 0,
         emptyRows: 0,
         headRows: 2,
         headRows: 2,
         headRowHeight: [32, 32],
         headRowHeight: [32, 32],
         defaultRowHeight: 21,
         defaultRowHeight: 21,
         headerFont: '10pt 微软雅黑',
         headerFont: '10pt 微软雅黑',
-        readOnly: true,
         font: '10pt 微软雅黑',
         font: '10pt 微软雅黑',
     },
     },
 }
 }

+ 51 - 17
app/controller/material_controller.js

@@ -193,20 +193,6 @@ module.exports = app => {
          * @private
          * @private
          */
          */
         _getSpreadSetting() {
         _getSpreadSetting() {
-            const _ = this.app._;
-            function removeFieldCols(setting, cols) {
-                _.remove(setting.cols, function (c) {
-                    return cols.indexOf(c.field) > -1;
-                });
-            }
-            function setColFormat(cols, field, formatter) {
-                const filterCols = cols.filter(function (c) {
-                    return c.field.search(field) !== -1;
-                });
-                for (const col of filterCols) {
-                    col.formatter = formatter;
-                }
-            }
             const billsSetting = spreadConst.material;
             const billsSetting = spreadConst.material;
             const ledger = JSON.parse(JSON.stringify(billsSetting.bill));
             const ledger = JSON.parse(JSON.stringify(billsSetting.bill));
             if (this.ctx.material.readOnly) {
             if (this.ctx.material.readOnly) {
@@ -238,7 +224,7 @@ module.exports = app => {
         }
         }
 
 
         /**
         /**
-         * 期计量页面 (Get)
+         * 调差工料页面 (Get)
          * @param {Object} ctx - egg全局变量
          * @param {Object} ctx - egg全局变量
          * @returns {Promise<void>}
          * @returns {Promise<void>}
          */
          */
@@ -246,8 +232,8 @@ module.exports = app => {
             try {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 await this._getMaterialAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
-                [renderData.billsSpread] = this._getSpreadSetting();
-                // renderData.ledgerData = await ctx.service.ledger.getData(ctx.tender.id);
+                // [renderData.billsSpread] = this._getSpreadSetting();
+                renderData.materialBillsData = await ctx.service.materialBills.getAllDataByCondition({ where: { mid: ctx.material.id } });
                 renderData.materialType = JSON.stringify(materialConst);
                 renderData.materialType = JSON.stringify(materialConst);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.info);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.material.info);
                 await this.layout('material/info.ejs', renderData, 'material/info_modal.ejs');
                 await this.layout('material/info.ejs', renderData, 'material/info_modal.ejs');
@@ -257,6 +243,54 @@ module.exports = app => {
             }
             }
         }
         }
 
 
+        /**
+         * 调差工料 - 编辑工料项 (Ajax)
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async saveBillsData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = {
+                    err: 0,
+                    msg: '',
+                    data: {},
+                };
+                switch (data.type) {
+                    case 'add':
+                        responseData.data = await ctx.service.materialBills.add();
+                        break;
+                    case 'del':
+                        await ctx.service.materialBills.del(data.id);
+                        break;
+                    case 'update':
+                        if (data.updateData.code === '' || data.updateData.code === null) {
+                            throw '请先输入编号';
+                        }
+                        // 判断编号为纯数字时,不能为小数
+                        if (!isNaN(data.updateData.code) && data.updateData.code.indexOf('.') !== -1) {
+                            throw '编号为纯数字时,不能为小数';
+                        }
+                        if (data.updateData.code.length > 15) {
+                            throw '长度不超过15个字符';
+                        }
+                        // 判断编号是否已存在
+                        const billData = await ctx.service.materialBills.getAllDataByCondition({ where: { mid: ctx.material.id, code: data.updateData.code } });
+                        if (billData.length > 1 || (billData.length > 0 && billData[0].id !== data.updateData.id)) {
+                            throw '该编号已存在,请重新输入。';
+                        }
+                        await ctx.service.materialBills.save(data.updateData);
+                        break;
+                    default: throw '参数有误';
+                }
+
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
         // 审批相关
         // 审批相关
         /**
         /**
          * 添加审批人
          * 添加审批人

+ 166 - 441
app/public/js/material.js

@@ -8,194 +8,98 @@
  * @version
  * @version
  */
  */
 
 
+function loadUpdateMaterials(newMaterial, fields) {
+    const newMaterials = newMaterial instanceof Array ? newMaterial : [newMaterial];
+    for (const nm of newMaterials) {
+        const om = _.find(materialBillsData, {id: nm.id});
+        for (const prop in nm) {
+            if (!fields || fields.indexOf(prop) >= 0) {
+                om[prop] = nm[prop];
+            }
+        }
+    }
+}
 $(document).ready(() => {
 $(document).ready(() => {
     autoFlashHeight();
     autoFlashHeight();
     const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
     const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
+    console.log(materialType);
+    const materialSpreadSetting = {
+        cols: [
+            {title: '调差类型', colSpan: '1', rowSpan: '2', field: 't_type', hAlign: 0, width: 80, formatter: '@', readOnly: 'readOnly.t_type', cellType: 'customizeCombo', comboItems: materialType.t_type, cellTypeKey: 1},
+            {title: '编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.code'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: 'readOnly.name'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.unit'},
+            {title: '规格', colSpan: '1', rowSpan: '2', field: 'spec', hAlign: 0, width: 230, formatter: '@', readOnly: 'readOnly.spec'},
+            {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 0, width: 60, readOnly: 'readOnly.m_type', cellType: 'customizeCombo', comboItems: materialType.m_type, cellTypeKey: 2},
+            {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.basic_price'},
+            {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.basic_times'},
+            {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
+            {title: '|时间', colSpan: '|1', rowSpan: '|1', field: 'msg_times', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.msg_times'},
+            {title: '|价差', colSpan: '1', rowSpan: '1|1', field: 'msg_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '本期材料调差|风险幅度(%)', colSpan: '3|1', rowSpan: '1|1', field: 'm_risk', hAlign: 2, width: 100, type: 'Number', readOnly: 'readOnly.m_risk'},
+            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '|调整金额', colSpan: '|1', rowSpan: '1|1', field: 'm_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '截止上期调差金额', colSpan: '1', rowSpan: '2', field: 'pre_tp', hAlign: 2, width: 120, type: 'Number', readOnly: true},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 60, formatter: '@', readOnly: 'readOnly.remark'},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [32, 32],
+        defaultRowHeight: 30,
+        headerFont: '10pt 微软雅黑',
+        readOnly: readOnly,
+        font: '10pt 微软雅黑',
+    };
 
 
-    SpreadJsObj.initSheet(materialSpread.getActiveSheet(), billsSpreadSetting);
-
-    const paySpreadObj = {
-        _checkExprValid(expr, invalidParam) {
-            if (!expr) return [true, null];
-            const param = [];
-            let num = '', base = '';
-            for (let i = 0, iLen = expr.length; i < iLen; i++) {
-                if (/^[\d\.%]+/.test(expr[i])) {
-                    if (base !== '') {
-                        param.push({type: 'base', value: base});
-                        base = '';
-                    }
-                    num = num + expr[i];
-                } else if (/^[a-z]/.test(expr[i])) {
-                    if (num !== '') {
-                        param.push({type: 'num', value: num});
-                        base = '';
-                    }
-                    base = base + expr[i];
-                } else if (expr[i] === '(') {
-                    if (num !== '') {
-                        param.push({type: 'num', value: num});
-                        base = '';
-                    }
-                    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});
-                        base = '';
-                    }
-                    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});
-                        base = '';
-                    }
-                    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});
-                base = '';
-            }
-            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].value = '-' + param[1];
-                }
-                param.unshift();
-            }
-            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') {
-                            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 === 'calc')
-                        return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
-                }
-                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, '输入的表达式非法:"("后无对应的")"'];
-            return [true, ''];
-        },
-        _checkSExpr: function (payNode, text, data) {
-            if (!payNode) return [false, '数据错误'];
-
-            const num = text ? _.toNumber(text) : null;
-            let expr = text ? (num ? null : text) : null;
-            expr = expr ? expr.replace('=', '').toLowerCase(): null;
-            const [valid, msg] = this._checkExprValid(expr, ['bqwc', 'ybbqwc']);
-            if (!valid) return [valid, msg];
-
-            if (payBase.isStarted(payNode)) {
-                return [false, '已经开始计量,请勿修改起扣金额'];
-            } else {
-                if (stage.order > 1) {
-                    const value = expr ? payCalc.calculateExpr(expr) : num;
-                    if (wcPay.pre_tp && value < wcPay.pre_tp)
-                        return [false, '已进行到第' + stage.order + '期,起扣金额请勿少于本期完成截止上期计量金额' + wcPay.pre_tp];
-                    data.sprice = num;
-                    data.sexpr = expr;
-                    return [true, ''];
-                } else {
-                    data.sprice = num;
-                    data.sexpr = expr;
-                    return [true, ''];
-                }
-            }
+    const materialCol = {
+        readOnly: {
+            t_type: function (data) {
+                return false;
+            },
+            code: function (data) {
+                return false;
+            },
+            name: function (data) {
+                return false;
+            },
+            unit: function (data) {
+                return false;
+            },
+            spec: function (data) {
+                return false;
+            },
+            m_type: function (data) {
+                return false;
+            },
+            quantity: function (data) {
+                return false;
+            },
+            basic_price: function (data) {
+                return false;
+            },
+            basic_times: function (data) {
+                return false;
+            },
+            msg_tp: function (data) {
+                return false;
+            },
+            msg_times: function (data) {
+                return false;
+            },
+            m_risk: function (data) {
+                return false;
+            },
+            remark: function (data) {
+                return false;
+            },
         },
         },
-        _checkRExpr: function (payNode, text, data) {
-            if (!payNode) return [false, '数据错误'];
-
-            const num = text ? _.toNumber(text) : null;
-            let expr = text ? (num ? null : text) : null;
-            expr = expr ? expr.replace('=', '').toLowerCase(): null;
-            const [valid, msg] = this._checkExprValid(expr, ['bqwc', 'ybbqwc']);
-            if (!valid) return [valid, msg];
+    };
+    SpreadJsObj.initSpreadSettingEvents(materialSpreadSetting, materialCol);
+    SpreadJsObj.initSheet(materialSpread.getActiveSheet(), materialSpreadSetting);
+    SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
 
 
-            if (payBase.isStarted(payNode)) {
-                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 [true, ''];
-            } else {
-                data.rprice = num;
-                data.rexpr = expr;
-                return [true, ''];
-            }
-        },
-        _checkExpr: function (text, data) {
-            if (text) {
-                const num = _.toNumber(text);
-                if (num) {
-                    data.tp = num;
-                    data.expr = null;
-                } else {
-                    const expr = text.replace('=', '').toLowerCase();
-                    const [valid, msg] = this._checkExprValid(expr);
-                    if (!valid) return [valid, msg];
-                    data.expr = expr;
-                    data.tp = null;
-                }
-            } else {
-                data.tp = null;
-                data.expr = null;
-            }
-            return [true, ''];
-        },
+    const materialSpreadObj = {
         refreshActn: function () {
         refreshActn: function () {
             const setObjEnable = function (obj, enable) {
             const setObjEnable = function (obj, enable) {
                 if (enable) {
                 if (enable) {
@@ -204,303 +108,124 @@ $(document).ready(() => {
                     obj.addClass('disabled');
                     obj.addClass('disabled');
                 }
                 }
             };
             };
-            const sheet = paySpread.getActiveSheet();
+            const sheet = materialSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(sheet);
             const select = SpreadJsObj.getSelectObject(sheet);
-            setObjEnable($('#add'), !readOnly);
-            const delValid = payBase.isOld(select)
-                ? !payBase.isStarted(select) && payBase.isYB()
-                : payBase.isYB() || payBase.isOwner(select);
-            setObjEnable($('#del'), !readOnly && select && delValid);
-            setObjEnable($('#up-move'), !readOnly && select && !payBase.isSpecial(select) && dealPay.indexOf(select) > 3);
-            setObjEnable($('#down-move'), !readOnly && select && !payBase.isSpecial(select) && dealPay.indexOf(select) < dealPay.length - 1);
+            setObjEnable($('#del'), !readOnly && select);
         },
         },
         add: function () {
         add: function () {
-            const sheet = billsSpread.getActiveSheet();
+            const sheet = materialSpread.getActiveSheet();
             postData(window.location.pathname + '/save', {type: 'add'}, function (result) {
             postData(window.location.pathname + '/save', {type: 'add'}, function (result) {
                 if (result) {
                 if (result) {
-                    dealPay.push(result);
-                    sheet.addRows(dealPay.length - 1, 1);
-                    SpreadJsObj.reLoadRowData(sheet, dealPay.length - 1);
-                    sheet.setSelection(dealPay.length - 1, 0, 1, 1);
-                    paySpreadObj.refreshActn();
+                    materialBillsData.push(result);
+                    sheet.addRows(materialBillsData.length - 1, 1);
+                    SpreadJsObj.reLoadRowData(sheet, materialBillsData.length - 1);
+                    sheet.setSelection(materialBillsData.length - 1, 0, 1, 1);
+                    materialSpreadObj.refreshActn();
                 }
                 }
             });
             });
         },
         },
         del: function () {
         del: function () {
-            const sheet = billsSpread.getActiveSheet();
+            const sheet = materialSpread.getActiveSheet();
             const select = SpreadJsObj.getSelectObject(sheet);
             const select = SpreadJsObj.getSelectObject(sheet);
-            if (payBase.isNonZero(select.tp)) {
-                toast('该支付(扣款)项存在数据,如需删除请先清除本期金额!');
-                return;
-            } else if (payBase.isOld(select)) {
-                if (payBase.isStarted(select)) {
-                    toast('该合同支付项往期已进行计算,不允许删除');
-                    return;
-                }
-            }
-            postData(window.location.pathname + '/save', {type: 'del', id: select.pid}, function (result) {
-                const index = dealPay.indexOf(select);
-                dealPay.splice(index, 1);
+            console.log(select);
+            postData(window.location.pathname + '/save', {type: 'del', id: select.id}, function (result) {
+                const index = materialBillsData.indexOf(select);
+                materialBillsData.splice(index, 1);
                 sheet.deleteRows(index, 1);
                 sheet.deleteRows(index, 1);
-                loadUpdateDealPays(result);
-                SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
                 const sel = sheet.getSelections();
                 const sel = sheet.getSelections();
                 sheet.setSelection(index > 0 ? index - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
                 sheet.setSelection(index > 0 ? index - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
-                paySpreadObj.refreshActn();
+                materialSpreadObj.refreshActn();
             });
             });
         },
         },
         selectionChanged: function (e, info) {
         selectionChanged: function (e, info) {
-            paySpreadObj.refreshActn();
+            materialSpreadObj.refreshActn();
             const sel = info.sheet.getSelections()[0];
             const sel = info.sheet.getSelections()[0];
             const col = info.sheet.zh_setting.cols[sel.col];
             const col = info.sheet.zh_setting.cols[sel.col];
             const data = SpreadJsObj.getSelectObject(info.sheet);
             const data = SpreadJsObj.getSelectObject(info.sheet);
-            if (col.field === 'tp') {
-                $('#expr').val(data.expr).attr('field', 'expr').attr('org', data.expr)
-                    .attr('readOnly', readOnly|| payBase.isSpecial(data));
-            } else if (col.field === 'sprice') {
-                $('#expr').val(data.sexpr).attr('field', 'sexpr').attr('org', data.sexpr)
-                    .attr('readOnly', readOnly|| payCol.readOnly.sprice(data));
-            } else if (col.field === 'rprice') {
-                $('#expr').val(data.rexpr).attr('field', 'rexpr').attr('org', data.rexpr)
-                    .attr('readOnly', readOnly|| payCol.readOnly.rprice(data));
-            } else {
-                $('#expr').val('').attr('readOnly', true);
-            }
+            materialSpreadObj.setReadOnly(true);
         },
         },
         editEnded: function (e, info) {
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {
             if (info.sheet.zh_setting) {
                 const select = SpreadJsObj.getSelectObject(info.sheet);
                 const select = SpreadJsObj.getSelectObject(info.sheet);
                 const col = info.sheet.zh_setting.cols[info.col];
                 const col = info.sheet.zh_setting.cols[info.col];
-                if (col.field === 'minus') {
-                    return;
-                }
                 // 未改变值则不提交
                 // 未改变值则不提交
-                const validText = info.editingText ? info.editingText.replace('\n', '') : null;
-                let orgValue;
-                if (col.field === 'tp') {
-                    orgValue = _.toNumber(validText) ? select.tp : select.expr;
-                } else if (col.field === 'sprice') {
-                    orgValue = _.toNumber(validText) ? select.sprice : select.sexpr;
-                } else if (col.field === 'rprice') {
-                    orgValue = _.toNumber(validText) ? select.rexpr : select.rexpr;
-                } else {
-                    orgValue = select[col.field];
-                }
+                const validText = info.editingText ? (typeof(info.editingText) === 'String' ? info.editingText.replace('\n', '') : info.editingText) : null;
+                const orgValue = select[col.field];
                 if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
                 if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     return;
                     return;
                 }
                 }
-                // 获取更新信息
-                const data = {
-                    type: (col.field === 'tp' || col.field === 'name') ? 'stage' : 'info',
-                    updateData: {}
-                };
-                // 获取更新数据
-                if (col.field === 'tp') {
-                    data.updateData.pid = select.pid;
-                    const [valid, msg] = paySpreadObj._checkExpr(validText, data.updateData);
-                    if (!valid) {
-                        toastr.warning(msg);
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                } else if (col.field === 'name') {
-                    data.updateData.pid = select.pid;
-                    data.updateData.name = validText;
-                } else {
-                    data.updateData.id = select.pid;
-                    if (validText) {
-                        if (col.field === 'sprice') {
-                            const [valid, msg] = paySpreadObj._checkSExpr(select, validText, data.updateData);
-                            if (!valid) {
-                                toastr.warning(msg);
-                                SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                                return;
-                            }
-                        } else if (col.field === 'rprice') {
-                            const [valid, msg] = paySpreadObj._checkRExpr(select, validText, data.updateData);
-                            if (!valid) {
-                                toastr.warning(msg);
-                                SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                                return;
-                            }
-                        } else {
-                            data.updateData[col.field] = validText;
-                        }
-                    } else {
-                        data.updateData[col.field] = null;
-                    }
-                }
+                select[col.field] = validText;
                 // 更新至服务器
                 // 更新至服务器
-                postData(window.location.pathname + '/save', data, function (result) {
-                    loadUpdateDealPays(result, col.field === 'name' ? ['name'] : null);
-                    SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
+                postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.row);
                 }, function () {
                 }, function () {
+                    select[col.field] = orgValue;
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                 });
                 });
             }
             }
         },
         },
-        buttonClicked: function (e, info) {
-            if (info.sheet.zh_setting) {
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                const col = info.sheet.zh_setting.cols[info.col];
-                if (payCol.readOnly.minus(select)) {
-                    return;
-                }
-                if (col.field === 'minus') {
-                    if (info.sheet.isEditing) {
-                        info.sheet.endEdit(true);
-                    }
-                    // 获取更新数据
-                    // 获取更新信息
-                    const data = {
-                        type: 'info',
-                        updateData: {id: select.pid},
-                    };
-                    data.updateData.minus = info.sheet.getValue(info.row, info.col) || false;
-                    // 更新至服务器
-                    postData(window.location.pathname + '/save', data, function (result) {
-                        loadUpdateDealPays(result);
-                        SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                    });
-                }
-            }
-        },
-        editStarting: function (e, info) {
-            const col = info.sheet.zh_setting.cols[info.col];
-            if (col.field === 'tp') {
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                if (select.expr && select.expr !== '') {
-                    info.sheet.getCell(info.row, info.col).text(select.expr);
-                }
-            } else if (col.field === 'sprice') {
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                if (select.sexpr && select.sexpr !== '') {
-                    info.sheet.getCell(info.row, info.col).text(select.sexpr);
-                }
-            } else if (col.field === 'rprice') {
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                if (select.rexpr && select.rexpr !== '') {
-                    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 && (node.ptype === 1 || node.ptype === 3)) {
-                        const updateData = {};
-                        if (col.field === 'tp') {
-                            updateData.pid = node.pid;
-                            updateData.tp = null;
-                            updateData.expr = null;
+        setReadOnly: function(readOnly) {
+            SpreadJsObj.resetFieldReadOnly(materialSpread.getActiveSheet(), 'msg_spread', 'm_spread', 'm_tp', 'pre_tp', readOnly);
+        }
+    };
+    materialSpreadObj.refreshActn();
+    materialSpread.bind(spreadNS.Events.SelectionChanged, materialSpreadObj.selectionChanged);
+    if (!readOnly) {
+        $('#add').click(materialSpreadObj.add);
+        $('#del').click(materialSpreadObj.del);
+        materialSpread.bind(spreadNS.Events.EditEnded, materialSpreadObj.editEnded);
+        // 右键菜单
+        $.contextMenu({
+            selector: '#material-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
+                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                'create': {
+                    name: '新增材料',
+                    icon: 'fa-sign-in',
+                    callback: function (key, opt) {
+                        materialSpreadObj.add(materialSpread.getActiveSheet());
+                    },
+                },
+                'delete': {
+                    name: '删除材料',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        materialSpreadObj.del(materialSpread.getActiveSheet());
+                    },
+                    disabled: function (key, opt) {
+                        const sheet = materialSpread.getActiveSheet();
+                        if (sheet.zh_data.length > 0) {
+                            const selection = sheet.getSelections();
+                            return sheet.zh_data.length < selection[0].row + selection[0].rowCount;
                         } else {
                         } else {
-                            updateData.id = node.pid;
-                            if (col.field === 'sprice') {
-                                const [valid, msg] = paySpreadObj._checkSExpr(node, null, updateData);
-                                if (!valid) {
-                                    toastr.warning(msg);
-                                    return;
-                                }
-                            } else if (col.field === 'rprice') {
-                                const [valid, msg] = paySpreadObj._checkRExpr(node, null, updateData);
-                                if (!valid) {
-                                    toastr.warning(msg);
-                                    return;
-                                }
-                            } else {
-                                updateData[col.field] = null;
-                            }
+                            return true;
                         }
                         }
-                        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, col.field === 'name' ? ['name'] : null);
-                        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 && (node.ptype === 1 || node.ptype === 3)) {
-                        const validText = info.sheet.getText(curRow, info.cellRange.col).replace('\n', '');
-                        const updateData = {};
-                        if (col.field === 'tp') {
-                            updateData.pid = node.pid;
-                            const [valid, msg] = paySpreadObj._checkExpr(validText, updateData);
-                            if (!valid) {
-                                toastr.warning(msg);
-                                SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                                return;
-                            }
-                        } else {
-                            updateData.id = node.pid;
-                            if (validText) {
-                                if (col.field === 'sprice') {
-                                    const [valid, msg] = paySpreadObj._checkSExpr(node, validText, updateData);
-                                    if (!valid) {
-                                        toastr.warning(msg);
-                                        SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                                        return;
-                                    }
-                                } else if (col.field === 'rprice') {
-                                    const [valid, msg] = paySpreadObj._checkRExpr(node, validText, updateData);
-                                    if (!valid) {
-                                        toastr.warning(msg);
-                                        SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                                        return;
-                                    }
-                                } 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, col.field === 'name' ? ['name'] : null);
-                            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                        }, function () {
-                            SpreadJsObj.reLoadSheetData(paySpread.getActiveSheet());
-                        });
-                    }
-                }
+        });
+    } else {
+        SpreadJsObj.forbiddenSpreadContextMenu('#material-spread', materialSpread);
+    }
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        //key: 'stage.compare.memu.1.0.0',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
             }
             }
-        },
-    };
+            autoFlashHeight();
+            materialSpread.refresh();
+        }
+    });
 });
 });

+ 2 - 0
app/router.js

@@ -220,6 +220,8 @@ module.exports = app => {
     app.post('/tender/:id/measure/material/:order/audit/delete', sessionAuth, tenderCheck, materialCheck, 'materialController.deleteAudit');
     app.post('/tender/:id/measure/material/:order/audit/delete', sessionAuth, tenderCheck, materialCheck, 'materialController.deleteAudit');
     app.post('/tender/:id/measure/material/:order/audit/start', sessionAuth, tenderCheck, materialCheck, 'materialController.startAudit');
     app.post('/tender/:id/measure/material/:order/audit/start', sessionAuth, tenderCheck, materialCheck, 'materialController.startAudit');
     app.post('/tender/:id/measure/material/:order/audit/check', sessionAuth, tenderCheck, materialCheck, 'materialController.checkAudit');
     app.post('/tender/:id/measure/material/:order/audit/check', sessionAuth, tenderCheck, materialCheck, 'materialController.checkAudit');
+    // 调差工料
+    app.post('/tender/:id/measure/material/:order/save', sessionAuth, tenderCheck, materialCheck, 'materialController.saveBillsData');
 
 
     // 个人账号相关
     // 个人账号相关
     app.get('/profile/info', sessionAuth, 'profileController.info');
     app.get('/profile/info', sessionAuth, 'profileController.info');

+ 0 - 3
app/service/material.js

@@ -9,9 +9,6 @@
  */
  */
 
 
 const auditConst = require('../const/audit').material;
 const auditConst = require('../const/audit').material;
-const payConst = require('../const/deal_pay.js');
-const fs = require('fs');
-const path = require('path');
 
 
 module.exports = app => {
 module.exports = app => {
     class Material extends app.BaseService {
     class Material extends app.BaseService {

+ 77 - 0
app/service/material_bills.js

@@ -0,0 +1,77 @@
+'use strict';
+
+/**
+ * 期计量 数据模型
+ *
+ * @author Mai
+ * @date 2018/8/13
+ * @version
+ */
+
+const auditConst = require('../const/audit').material;
+
+module.exports = app => {
+    class MaterialBills extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_bills';
+        }
+
+        /**
+         * 添加工料
+         * @return {void}
+         */
+        async add() {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            const newBills = {
+                tid: this.ctx.tender.id,
+                mid: this.ctx.material.id,
+                in_time: new Date(),
+            };
+
+            // 新增工料
+            const result = await this.db.insert(this.tableName, newBills);
+            if (result.affectedRows !== 1) {
+                throw '新增工料数据失败';
+            }
+            return await this.getDataById(result.insertId);
+        }
+
+        /**
+         * 删除工料
+         * @param {int} id 工料id
+         * @return {void}
+         */
+        async del(id) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            // 判断是否可删
+            return await this.deleteById(id);
+        }
+
+        /**
+         * 修改工料信息
+         * @param {Object} data 工料内容
+         * @return {void}
+         */
+        async save(data) {
+            if (!this.ctx.tender || !this.ctx.material) {
+                throw '数据错误';
+            }
+            delete data.in_time;
+            // 判断是否可修改
+            return await this.db.update(this.tableName, data);
+        }
+    }
+
+    return MaterialBills;
+};

+ 1 - 0
app/service/stage.js

@@ -335,6 +335,7 @@ module.exports = app => {
                     }
                     }
                 }
                 }
                 await transaction.delete(this.ctx.service.stagePay.tableName, { sid: id });
                 await transaction.delete(this.ctx.service.stagePay.tableName, { sid: id });
+                await transaction.delete(this.ctx.service.pay.tableName, { csid: id });
                 // 删除计量附件文件
                 // 删除计量附件文件
                 const attList = await this.ctx.service.stageAtt.getAllDataByCondition({ where: { sid: id } });
                 const attList = await this.ctx.service.stageAtt.getAllDataByCondition({ where: { sid: id } });
                 if (attList.length !== 0) {
                 if (attList.length !== 0) {

+ 5 - 19
app/view/material/info.ejs

@@ -4,10 +4,12 @@
         <div class="title-main d-flex justify-content-between">
         <div class="title-main d-flex justify-content-between">
             <% include ./material_sub_mini_menu.ejs %>
             <% include ./material_sub_mini_menu.ejs %>
             <div>
             <div>
+                <% if ((ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                 <div class="d-inline-block">
                 <div class="d-inline-block">
                     <a href="javascript: void(0);" id="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增材料"><i class="fa fa-plus" aria-hidden="true"></i></a>
                     <a href="javascript: void(0);" id="add" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="新增材料"><i class="fa fa-plus" aria-hidden="true"></i></a>
-                    <a href="javascript: void(0);" id="del" class="btn btn-sm btn-light text-primary disabled" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除材料"><i class="fa fa-remove" aria-hidden="true"></i></a>
+                    <a href="javascript: void(0);" id="del" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="删除材料"><i class="fa fa-remove" aria-hidden="true"></i></a>
                 </div>
                 </div>
+                <% } %>
                 <div class="d-inline-block">
                 <div class="d-inline-block">
                     本期调差计量期:第<span class="mx-2"><%= ctx.material.s_order.split(',').join(',') %></span>期
                     本期调差计量期:第<span class="mx-2"><%= ctx.material.s_order.split(',').join(',') %></span>期
                 </div>
                 </div>
@@ -52,23 +54,7 @@
 <script>
 <script>
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
     const materialType = JSON.parse('<%- materialType %>');
     const materialType = JSON.parse('<%- materialType %>');
-    const billsSpreadSetting = JSON.parse('<%- JSON.stringify(billsSpread) %>');
+    const materialBillsData = JSON.parse('<%- JSON.stringify(materialBillsData) %>');
+    const readOnly = <%- material.readOnly %>;
 </script>
 </script>
 <% } %>
 <% } %>
-<script>
-    $.subMenu({
-        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
-        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
-        //key: 'stage.compare.memu.1.0.0',
-        callback: function (info) {
-            if (info.mini) {
-                $('.panel-title').addClass('fluid');
-                $('#sub-menu').removeClass('panel-sidebar');
-            } else {
-                $('.panel-title').removeClass('fluid');
-                $('#sub-menu').addClass('panel-sidebar');
-            }
-            autoFlashHeight();
-        }
-    });
-</script>