Преглед изворни кода

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

TonyKang пре 4 година
родитељ
комит
7f8fcaf6e8

+ 12 - 2
app/const/advance.js

@@ -12,9 +12,19 @@
 const typeCol = [
     { key: 'start', type: 0, name: '开工预付款' },
     { key: 'material', type: 1, name: '材料预付款' },
-    // { key: 'safe', type: 2, name: '安全生产预付款' },
-]
+    { key: 'safe', type: 2, name: '安全生产预付款' },
+    { key: 'dust', type: 3, name: '扬尘污染预付款' },
+];
+
+const typeColMap = {
+    0: { text: '开工预付款', value: 'start' },
+    1: { text: '材料预付款', value: 'material' },
+    2: { text: '安全生产预付款', value: 'safe' },
+    3: { text: '扬尘污染预付款', value: 'dust' },
+};
+
 
 module.exports = {
     typeCol,
+    typeColMap,
 };

+ 1 - 0
app/const/tender_info.js

@@ -101,6 +101,7 @@ const defaultInfo = {
         startAdvance: 0,
         materialAdvance: 0,
         safeAdvance: 0,
+        dustAdvance: 0,
     },
     // 显示设置
     display: {

+ 30 - 26
app/controller/advance_controller.js

@@ -2,6 +2,7 @@
 const accountGroup = require('../const/account_group').group;
 const auditConst = require('../const/audit').advance;
 const shenpiConst = require('../const/shenpi');
+const typeConsts = require('../const/advance');
 const sendToWormhole = require('stream-wormhole');
 const path = require('path');
 const fs = require('fs');
@@ -18,8 +19,9 @@ module.exports = app => {
          * @param {Object} ctx 全局上下文
          */
         async index(ctx) {
-            const type = auditConst.type.start;
-            const advancePayTotal = ctx.tender.info.deal_param.startAdvance;
+            const advanceType = typeConsts.typeCol.find(item => item.key === ctx.params.type);
+            const type = advanceType.type;
+            const advancePayTotal = ctx.tender.info.deal_param[`${advanceType.key}Advance`];
             const advanceList = await ctx.service.advance.getAdvanceList(ctx.tender.id, type, this.decimal, advancePayTotal);
             const latestOrder = await ctx.service.advance.getLastestAdvance(ctx.tender.id, type, true);
             const progress = await ctx.service.advance.calcProgress(latestOrder, advancePayTotal);
@@ -31,6 +33,7 @@ module.exports = app => {
                 advanceList,
                 latestOrder,
                 auditConst,
+                typeColMap: typeConsts.typeColMap,
                 preUrl: `/tender/${ctx.tender.id}/advance/${type}/create`,
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.advance.main),
                 advancePayTotal,
@@ -43,27 +46,27 @@ module.exports = app => {
          * 材料预付款页面(AJAX) GET
          * @param {Object} ctx 全局上下文
          */
-        async materialList(ctx) {
-            const type = auditConst.type.material;
-            const advancePayTotal = ctx.tender.info.deal_param.materialAdvance;
-            const advanceList = await ctx.service.advance.getAdvanceList(ctx.tender.id, type, this.decimal, advancePayTotal);
-            const latestOrder = await ctx.service.advance.getLastestAdvance(ctx.tender.id, type, true);
-            const progress = await ctx.service.advance.calcProgress(latestOrder, advancePayTotal);
-            const showAddBtn = ctx.tender.data.user_id === ctx.session.sessionUser.accountId ? !latestOrder || (latestOrder.status === auditConst.status.checked && latestOrder.prev_total_amount < advancePayTotal) : false;
-            const renderData = {
-                type,
-                decimal: this.decimal,
-                showAddBtn,
-                advanceList,
-                latestOrder,
-                auditConst,
-                preUrl: `/tender/${ctx.tender.id}/advance/${type}/create`,
-                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.advance.main),
-                advancePayTotal,
-                progress,
-            };
-            await this.layout('advance/index.ejs', renderData, 'advance/modal.ejs');
-        }
+        // async materialList(ctx) {
+        //     const type = auditConst.type.material;
+        //     const advancePayTotal = ctx.tender.info.deal_param.materialAdvance;
+        //     const advanceList = await ctx.service.advance.getAdvanceList(ctx.tender.id, type, this.decimal, advancePayTotal);
+        //     const latestOrder = await ctx.service.advance.getLastestAdvance(ctx.tender.id, type, true);
+        //     const progress = await ctx.service.advance.calcProgress(latestOrder, advancePayTotal);
+        //     const showAddBtn = ctx.tender.data.user_id === ctx.session.sessionUser.accountId ? !latestOrder || (latestOrder.status === auditConst.status.checked && latestOrder.prev_total_amount < advancePayTotal) : false;
+        //     const renderData = {
+        //         type,
+        //         decimal: this.decimal,
+        //         showAddBtn,
+        //         advanceList,
+        //         latestOrder,
+        //         auditConst,
+        //         preUrl: `/tender/${ctx.tender.id}/advance/${type}/create`,
+        //         jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.advance.main),
+        //         advancePayTotal,
+        //         progress,
+        //     };
+        //     await this.layout('advance/index.ejs', renderData, 'advance/modal.ejs');
+        // }
 
         /**
          * 获取通用的renderData(用于layout, Menu, subMenu部分)
@@ -142,7 +145,7 @@ module.exports = app => {
          * @param {Object} ctx 全局上下文
          */
         async detail(ctx) {
-            const advancePayTotal = ctx.advance.type === 0 ? ctx.tender.info.deal_param.startAdvance : ctx.tender.info.deal_param.materialAdvance;
+            const advancePayTotal = ctx.tender.info.deal_param[`${typeConsts.typeColMap[ctx.advance.type].value}startAdvance`];
             try {
                 await this._checkCanEntry(ctx);
                 const { uncheck, checkNo } = auditConst.status;
@@ -178,12 +181,13 @@ module.exports = app => {
                 renderData.prev_total_amount = prev_total_amount;
                 renderData.max_pr = max_pr;
                 renderData.decimal = 2;
+                renderData.typeColMap = typeConsts.typeColMap;
                 renderData.advancePayTotal = advancePayTotal;
                 renderData.prevAdvance = prevAdvance;
                 await this.layout('advance/detail.ejs', renderData, 'advance/modal_audit.ejs');
             } catch (error) {
                 this.log(error);
-                ctx.redirect('/tender/' + ctx.tender.id + '/advance');
+                ctx.redirect('/tender/' + ctx.tender.id + '/advance/' + typeConsts.typeColMap[ctx.advance.type].value);
             }
         }
 
@@ -222,7 +226,7 @@ module.exports = app => {
                 ctx.redirect(`/tender/${ctx.tender.id}/advance/${record.id}/detail`);
             } catch (error) {
                 this.log(error);
-                ctx.redirect(`/tender/${ctx.tender.id}/advance`);
+                ctx.redirect(`/tender/${ctx.tender.id}/advance/${typeConsts.typeColMap[ctx.advance.type].value}`);
             }
         }
 

+ 1 - 1
app/controller/schedule_controller.js

@@ -574,7 +574,7 @@ module.exports = app => {
                 }
                 // 判断修改权限
                 if (ctx.session.sessionUser.is_admin === 0) {
-                    throw '你没有权限修改形象进度';
+                    throw '你没有权限修改投资进度';
                 }
                 let info = '';
                 switch (data.type) {

+ 15 - 15
app/controller/stage_controller.js

@@ -1296,21 +1296,21 @@ module.exports = app => {
          */
         _checkStageCanModifyRe(ctx) {
             // 检查登录用户,是否可操作
-            if (ctx.stage.readOnly) {
-                if (ctx.stage.status === auditConst.status.checked) {
-                    // 当前期状态为完成,且提交人是审核列表中的则可再次上传
-                    if (ctx.stage.user_id === ctx.session.sessionUser.accountId || ctx.stage.auditors.findIndex(auditor => auditor.aid === ctx.session.sessionUser.accountId) !== -1) {
-                        // 再次上传的图片要给个标识,方便给前端进行编辑操作
-                        // ctx.reUploadPermission = true;
-                        return;
-                    }
-
-                    throw '该计量期当前您无权操作';
-
-                } else {
-                    throw '该计量期当前您无权操作';
-                }
-            }
+            // if (ctx.stage.readOnly) {
+            //     if (ctx.stage.status === auditConst.status.checked) {
+            //         // 当前期状态为完成,且提交人是审核列表中的则可再次上传
+            //         if (ctx.stage.user_id === ctx.session.sessionUser.accountId || ctx.stage.auditors.findIndex(auditor => auditor.aid === ctx.session.sessionUser.accountId) !== -1) {
+            //             // 再次上传的图片要给个标识,方便给前端进行编辑操作
+            //             // ctx.reUploadPermission = true;
+            //             return;
+            //         }
+
+            //         throw '该计量期当前您无权操作';
+
+            //     } else {
+            //         throw '该计量期当前您无权操作';
+            //     }
+            // }
             if (ctx.stage.revising) {
                 throw '台账修订中,请勿修改提交期数据';
             }

+ 1 - 1
app/controller/tender_controller.js

@@ -468,7 +468,7 @@ module.exports = app => {
                     renderData.accountGroup = accountGroupList;
                 }
                 if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) {
-                    // 形象进度内容
+                    // 投资进度内容
                     renderData.scheduleAuditList = await ctx.service.scheduleAudit.getAllDataByCondition({ where: { tid: tender.id } });
                     renderData.scPermission = scheduleConst.permission;
                 }

+ 11 - 2
app/lib/pay_calc.js

@@ -228,9 +228,18 @@ class PayCalculate {
             bqyf.value = this.yf.tp;
         }
         if (this.sf.expr === null || this.sf.expr === '') {
-            this.sf.tp = this.yf.tp;
+            if (this.sf.rprice) {
+                this.sf.tp = Math.min(this.ctx.helper.sub(this.sf.rprice, this.sf.pre_tp), this.yf.tp);
+            } else {
+                this.sf.tp = this.yf.tp;
+            }
         } else {
-            this.sf.tp = this.ctx.helper.round(this._calculateTpExpr(this.sf), this.decimal);
+            const value = this.ctx.helper.round(this._calculateTpExpr(this.sf), this.decimal);
+            if (this.sf.rprice) {
+                this.sf.tp = Math.min(this.ctx.helper.sub(this.sf.rprice, this.sf.pre_tp), value);
+            } else {
+                this.sf.tp = this.ctx.helper.round(value, this.decimal);
+            }
         }
         this.sf.end_tp = this.ctx.helper.add(this.sf.tp, this.sf.pre_tp);
     }

+ 1 - 1
app/middleware/schedule_check.js

@@ -10,7 +10,7 @@
 const scPermission = require('../const/schedule').permission;
 module.exports = options => {
     /**
-     * 形象进度校验 中间件
+     * 投资进度校验 中间件
      *
      * @param {function} next - 中间件继续执行的方法
      * @return {void}

+ 1 - 1
app/middleware/tender_check.js

@@ -78,7 +78,7 @@ module.exports = options => {
             tender.ledgerUsers = tender.ledger_status === auditConst.status.uncheck ? [tender.data.user_id] : [tender.data.user_id, ...auditorsId];
             this.tender = tender;
             this.session.sessionProject.page_show = yield this.service.project.getPageshow(this.session.sessionProject.id);
-            // 形象进度权限获取
+            // 投资进度权限获取
             let schedule_permission = scPermission.no;
             if (this.session.sessionUser.accountId === tender.data.user_id) {
                 schedule_permission = scPermission.edit;

+ 197 - 36
app/public/js/material_list.js

@@ -51,7 +51,7 @@ function calcOneBQJC(xmj) {
 function getPasteHint (str, row = '') {
     let returnObj = str;
     if (row) {
-        returnObj.msg = '清单第' + (row+1) + '行' + str.msg;
+        returnObj.msg = '清单第' + (row+1) + '行' + (str.msg ? str.msg : str);
     }
     return returnObj;
 }
@@ -226,10 +226,11 @@ $(document).ready(() => {
     const materialSpread = SpreadJsObj.createNewSpread($('#material-spread')[0]);
     const materialSpreadSetting = {
         cols: [
-            {title: '清单工料含量|编号', colSpan: '4|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '清单工料含量|编号', colSpan: '5|1', rowSpan: '1|1', field: 'code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
             {title: '|名称', colSpan: '|1', rowSpan: '|1', field: 'name', hAlign: 0, width: 100, formatter: '@', readOnly: true},
             {title: '|单位', colSpan: '|1', rowSpan: '|1', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true},
-            {title: '|数量 �', colSpan: '1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 120, type: 'Number', readOnly: 'readOnly.isEdit'},
+            {title: '|计算式', colSpan: '|1', rowSpan: '|1', field: 'expr', hAlign: 2, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
+            {title: '|数量 �', colSpan: '1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 80, type: 'Number', readOnly: 'readOnly.isEdit'},
         ],
         emptyRows: 0,
         headRows: 2,
@@ -282,7 +283,7 @@ $(document).ready(() => {
     loadMaterialData(0, 0);
     const sheet = materialSpread.getActiveSheet();
     sheet.suspendPaint();
-    sheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+    sheet.setCellType(1, 4, new TipCellType(), spreadNS.SheetArea.colHeader);
     sheet.resumePaint();
     // 不参与调差数据值变灰
     function checkNotJoinMaterialData() {
@@ -520,30 +521,56 @@ $(document).ready(() => {
             deletePress: function (sheet) {
                 return;
             },
+            editStarting: function (e, info) {
+                const col = info.sheet.zh_setting.cols[info.col];
+                const select = SpreadJsObj.getSelectObject(info.sheet);
+                if (col.field === 'quantity') {
+                    if (select.expr && select.expr !== '') {
+                        info.sheet.getCell(info.row, info.col).text(select.expr);
+                    }
+                }
+            },
             editEnded: function (e, info) {
                 if (info.sheet.zh_setting) {
                     const select = SpreadJsObj.getSelectObject(info.sheet);
                     const col = info.sheet.zh_setting.cols[info.col];
                     // 未改变值则不提交
                     // const validText = info.editingText ? (typeof(info.editingText) === 'String' ? info.editingText.replace('\n', '') : info.editingText) : null;
-                    const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
-                    const orgValue = select[col.field];
+                    // const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
+                    // let orgValue = select[col.field];
+                    const validText = info.editingText ? info.editingText.replace('\n', '') : null;
+                    let orgValue;
+                    if (col.field === 'quantity') {
+                        orgValue = validText && validText !== ''
+                            ? _.toNumber(validText) ? select.quantity : select.expr
+                            : (select.expr && select.expr !== '') ? select.expr : select.quantity;
+                    } else {
+                        orgValue = select[col.field];
+                    }
                     if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === '' || validText === null))) {
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                         return;
                     }
-                    if (col.field === 'quantity') {
-                        if (isNaN(validText)) {
-                            toastr.error('不能输入其它非数字类型字符');
-                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                            return;
-                        }
-                        const num = parseFloat(validText);
-                        if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
-                            toastr.error('请输入大于0并且小于6位小数的浮点数');
-                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                            return;
-                        }
+                    const exprQuantity = {
+                        expr: '',
+                        quantity: 0,
+                    };
+                    const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
+                    if (!valid) {
+                        toastr.error(msg);
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    if (isNaN(exprQuantity.quantity)) {
+                        toastr.error('不能输入其它非数字类型字符');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
+                    }
+                    const num = parseFloat(exprQuantity.quantity);
+                    if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
+                        toastr.error('数量值必须大于0并且小于6位小数的浮点数');
+                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        return;
                     }
                     // 更新至服务器
                     const ledgerSheet = ledgerSpread.getActiveSheet();
@@ -559,8 +586,8 @@ $(document).ready(() => {
                         };
                         datas.push(data);
                     }
-                    console.log(validText, datas, select.mb_id);
-                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, quantity: validText, mb_id: select.mb_id } }, function (result) {
+                    console.log(exprQuantity, datas, select.mb_id);
+                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id } }, function (result) {
                         materialListData = result;
                         calculateJiaCha(gclGatherData);
                         // const index = gclGatherData.indexOf(ledgerSelect);
@@ -604,7 +631,7 @@ $(document).ready(() => {
                     SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
                     return;
                 }
-                if (sortData.length > 0 && range.col + range.colCount > 4) {
+                if (sortData.length > 0 && range.col + range.colCount > 5) {
                     toastMessageUniq(hint.cellError);
                     SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
                     SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
@@ -622,8 +649,9 @@ $(document).ready(() => {
                         const colSetting = info.sheet.zh_setting.cols[curCol];
                         if (!colSetting) continue;
 
-                        let validText = info.sheet.getText(curRow, curCol);
-                        validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
+                        // let validText = info.sheet.getText(curRow, curCol);
+                        // validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
+                        const validText = info.sheet.getText(curRow, curCol).replace('\n', '');
                         const orgValue = sortData[curRow][colSetting.field];
                         if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
                             sameCol++;
@@ -632,20 +660,30 @@ $(document).ready(() => {
                             }
                             continue;
                         }
-                        if (colSetting.field === 'quantity') {
-                            if (isNaN(validText)) {
-                                toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
-                                bPaste = false;
-                                continue;
-                            }
-                            const num = parseFloat(validText);
-                            if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
-                                toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
-                                bPaste = false;
-                                continue;
-                            }
+                        const exprQuantity = {
+                            expr: '',
+                            quantity: 0,
+                        };
+                        const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
+                        if (!valid) {
+                            toastMessageUniq(getPasteHint(msg, hintRow));
+                            bPaste = false;
+                            continue;
                         }
-                        materialData[colSetting.field] = validText;
+                        if (isNaN(exprQuantity.quantity)) {
+                            toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
+                            bPaste = false;
+                            continue;
+                        }
+                        const num = parseFloat(exprQuantity.quantity);
+                        if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
+                            toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
+                            bPaste = false;
+                            continue;
+                        }
+                        // materialData[colSetting.field] = validText;
+                        materialData.expr = exprQuantity.expr;
+                        materialData.quantity = exprQuantity.quantity;
                     }
                     if (bPaste) {
                         data.push(materialData);
@@ -697,7 +735,130 @@ $(document).ready(() => {
                 //     SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 // });
             },
+            _checkExprValid(expr) {
+                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 (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].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' && param[i - 1].type !== 'left') {
+                                return [false, '输入的表达式非法:' + p.value + '前应有运算符'];
+                            } else if (param[i - 1].value === '/' && num === 0) {
+                                return [false, '输入的表达式非法:请勿除0'];
+                            }
+                        }
+                    }
+                    if (p.type === 'base') {
+                        if (i > 0 && (param[i - 1].type === 'num' || param[i - 1].type === 'right'))
+                            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, ''];
+            },
+            _checkExpr: function (text, data) {
+                if (text) {
+                    const num = _.toNumber(text);
+                    if (num) {
+                        data.quantity = num;
+                        data.expr = '';
+                    } else {
+                        const expr = $.trim(text).replace('\t', '').replace('=', '').toLowerCase();
+                        const [valid, msg] = this._checkExprValid(expr);
+                        if (!valid) return [valid, msg];
+                        data.expr = expr;
+                        data.quantity = eval(expr);
+                    }
+                } else {
+                    data.quantity = 0;
+                    data.expr = '';
+                }
+                return [true, ''];
+            },
         };
+        materialSpread.bind(spreadNS.Events.EditStarting, materialSpreadObj.editStarting);
         materialSpread.bind(spreadNS.Events.EditEnded, materialSpreadObj.editEnded);
         materialSpread.bind(spreadNS.Events.ClipboardPasted, materialSpreadObj.clipboardPasted);
         SpreadJsObj.addDeleteBind(materialSpread, materialSpreadObj.deletePress);

+ 4 - 0
app/public/js/measure_material.js

@@ -237,9 +237,13 @@ $(function () {
 
     // 提交表单判断
     $('#addMaterial').click(function () {
+        $(this).attr('disabled', true);
         if ($('#s_order').val() == '') {
             toastr.error('请选择计量期');
+            $(this).removeAttr('disabled');
             return false;
         }
+        $(this).text('添加中,请稍后...');
+        $(this).parents('form').submit();
     })
 });

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

@@ -251,7 +251,7 @@ $(document).ready(() => {
                 if (payBase.isOld(data)) {
                     return !payBase.isYB(data);
                 } else {
-                    return payBase.isWC(data) || payBase.isSF(data) || payBase.isYF(data) || !(payBase.isOwner(data) || payBase.isYB());
+                    return payBase.isWC(data) || payBase.isYF(data) || !(payBase.isOwner(data) || payBase.isYB());
                 }
             },
         },
@@ -435,12 +435,20 @@ $(document).ready(() => {
             if (!valid) return [valid, msg];
 
             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 [false, '已经开始使用,请勿修改扣款限额'];
+                if (payBase.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;

+ 4 - 4
app/router.js

@@ -25,7 +25,7 @@ module.exports = app => {
     const advanceCheck = app.middlewares.advanceCheck();
     // 变更令中间件
     const changeCheck = app.middlewares.changeCheck();
-    // 形象进度中间件
+    // 投资进度中间件
     const scheduleCheck = app.middlewares.scheduleCheck();
     // 登入登出相关
     app.get('/login', 'loginController.index');
@@ -135,8 +135,8 @@ module.exports = app => {
     app.post('/tender/:id/tourist/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.saveTourist');
 
     // 预付款
-    app.get('/tender/:id/advance', sessionAuth, tenderCheck, 'advanceController.index');
-    app.get('/tender/:id/advance/material', sessionAuth, tenderCheck, 'advanceController.materialList');
+    app.get('/tender/:id/advance/:type', sessionAuth, tenderCheck, 'advanceController.index');
+    // app.get('/tender/:id/advance/material', sessionAuth, tenderCheck, 'advanceController.materialList');
     app.post('/tender/:id/advance/create', sessionAuth, tenderCheck, 'advanceController.create');
     app.post('/tender/:id/advance/delete', sessionAuth, tenderCheck, 'advanceController.delete');
     app.get('/tender/:id/advance/:order/detail', sessionAuth, tenderCheck, advanceCheck, 'advanceController.detail');
@@ -469,7 +469,7 @@ module.exports = app => {
     app.get('/wx/test', 'wechatController.testwx');
     app.get('/MP_verify_t3MkWAMqplVxPjmr.txt', 'wechatController.oauthTxt');
 
-    // 形象进度
+    // 投资进度
     app.get('/tender/:id/schedule', sessionAuth, tenderCheck, uncheckTenderCheck, scheduleCheck, 'scheduleController.index');
     app.get('/tender/:id/schedule/ledger', sessionAuth, tenderCheck, uncheckTenderCheck, scheduleCheck, 'scheduleController.ledger');
     app.post('/tender/:id/schedule/ledger/load', sessionAuth, tenderCheck, uncheckTenderCheck, 'scheduleController.loadLedgerData');

+ 4 - 2
app/service/deal_bills.js

@@ -46,8 +46,9 @@ module.exports = app => {
                     const row = sheet.data[iRow];
                     if (!bCheckCol) {
                         for (let iCol = 0; iCol < row.length; iCol++) {
-                            const value = row[iCol];
+                            let value = row[iCol];
                             if (typeof value !== "string") { continue }
+                            value = this.ctx.helper._.trim(value);
                             if (['清单编号', '子目号', '子目编号', '编号', '清单号'].indexOf(value) >= 0) iCode = iCol;
                             if (['清单名称', '名称', '子目名称'].indexOf(value) >= 0) iName = iCol;
                             if (value.indexOf('单位') >= 0) iUnit = iCol;
@@ -138,8 +139,9 @@ module.exports = app => {
                 const row = sheet.rows[iRow];
                 if (!bCheckCol) {
                     for (let iCol = 0; iCol < row.length; iCol++) {
-                        const value = row[iCol];
+                        let value = row[iCol];
                         if (typeof value !== "string") { continue }
+                        value = this.ctx.helper._.trim(value);
                         if (value === '子目号' || value === '清单编号') iCode = iCol;
                         if (value.indexOf('名称') >= 0) iName = iCol;
                         if (value.indexOf('单位') >= 0) iUnit = iCol;

+ 1 - 1
app/service/ledger_revise.js

@@ -216,7 +216,7 @@ module.exports = app => {
                     id: revise.id, valid: false, end_time: new Date(),
                     bills_file: billsHis, pos_file: posHis,
                 });
-                // 形象进度改变状态
+                // 投资进度改变状态
                 await transaction.update(this.ctx.service.schedule.tableName, { revising: 0 }, { where: { tid: this.ctx.tender.id } });
                 await transaction.commit();
                 return result.affectedRows === 1;

+ 3 - 1
app/service/material_list.js

@@ -241,7 +241,7 @@ module.exports = app => {
          * @return {void}
          */
         async getMaterialData(tid, mid) {
-            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`' +
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`' +
                 ' FROM ' + this.tableName + ' as ml' +
                 ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb' +
                 ' ON ml.`mb_id` = mb.`id`' +
@@ -398,6 +398,7 @@ module.exports = app => {
                 for (const xmj of datas.xmjs) {
                     const udata = {
                         row: {
+                            expr: datas.expr,
                             quantity: datas.quantity,
                         },
                         where: {
@@ -440,6 +441,7 @@ module.exports = app => {
                     for (const xmj of datas.xmjs) {
                         const udata = {
                             row: {
+                                expr: data.expr,
                                 quantity: data.quantity,
                             },
                             where: {

+ 5 - 5
app/service/report_memory.js

@@ -1080,7 +1080,7 @@ module.exports = app => {
             await this.ctx.service.tender.checkTender(tid);
             await this.ctx.service.stage.checkStage(sid);
             this.changeInfo = await this.ctx.service.change.getChangeAndUsedInfo(tid);
-            const usedChangesId = await ctx.service.stageChange.getStageUsedChangeId(sid);
+            const usedChangesId = await this.ctx.service.stageChange.getStageUsedChangeId(sid);
             for (const c of this.changeInfo) {
                 c.cur_used = usedChangesId.indexOf(c.cid) >= 0;
             }
@@ -1092,17 +1092,17 @@ module.exports = app => {
             this.changeInfoBills = [];
             for (const c of this.changeInfo) {
                 const cb = await this.ctx.service.stageChange.getUsedData(tid, c.cid);
-                const curUsedBills = await this.ctx.service.stageChange.getStageUsedData(sid, cid);
+                const curUsedBills = await this.ctx.service.stageChange.getStageUsedData(sid, c.cid);
                 for (const b of cb) {
                     b.qty = this.ctx.helper._.toNumber(b.samount);
-                    b.valid_qty = ZhCalc.sub(b.qty, b.used_qty);
+                    b.valid_qty = this.ctx.helper.sub(b.qty, b.used_qty);
                     b.tp = this.ctx.helper.round(this.ctx.helper.mul(b.qty, b.unit_price), this.ctx.tender.info.decimal.tp);
                     const pos = this.ctx.helper._.filter(curUsedBills, { cbid: b.id });
                     b.cur_qty = 0;
                     for (const p of pos) {
-                        b.cur_qty = ZhCalc.add(b.cur_qty, p.qty);
+                        b.cur_qty = this.ctx.helper.add(b.cur_qty, p.qty);
                     }
-                    b.cur_used = !!data.cur_qty;
+                    b.cur_used = !!b.cur_qty;
                     this.changeInfoBills.push(b);
                 }
             }

+ 1 - 1
app/service/revise_audit.js

@@ -258,7 +258,7 @@ module.exports = app => {
                 }
                 await transaction.update(this.ctx.service.ledgerRevise.tableName, reviseData);
 
-                // 形象进度改变状态
+                // 投资进度改变状态
                 await transaction.update(this.ctx.service.schedule.tableName, { revising: 1 }, { where: { tid: this.ctx.tender.id } });
 
                 // 添加短信通知-需要审批提醒功能

+ 1 - 1
app/service/schedule_ledger.js

@@ -53,7 +53,7 @@ module.exports = app => {
                     total_tp = this.ctx.helper.add(total_tp, u.tp);
                 }
                 if (updateOptions.length > 0) await transaction.updateRows(this.tableName, updateOptions);
-                // 判断是否已创建了形象进度表
+                // 判断是否已创建了投资进度表
                 const scheduleInfo = await this.ctx.service.schedule.getDataByCondition({ tid: this.ctx.tender.id });
                 if (!scheduleInfo) {
                     const newSchedule = {

+ 2 - 3
app/view/advance/detail.ejs

@@ -17,13 +17,12 @@
             <div class="sjs-height-0">
                 <div class="col-xl-8 mx-auto">
                     <h4 class="mt-3 text-center mb-3">第<%- advance.order %>期
-                        <%- advance.type === auditConst.type.start ? '开工' : '材料' %>预付款</h4>
+                        <%- typeColMap[advance.type].text %></h4>
                     <table class="table table-bordered">
                         <thead>
                             <tr>
                                 <th colspan="4" class="text-center">
-                                    <!-- 签约<%- advance.type === auditConst.type.start ? '开工' : '材料' %>预付款:<%- ctx.helper.formatMoney(advancePayTotal, ',', 2) %> -->
-                                    签约<%- advance.type === auditConst.type.start ? '开工' : '材料' %>预付款:<%- ctx.helper.formatMoney(advancePayTotal, ',', parseFloat(advancePayTotal).toString().split('.')[1] && parseFloat(advancePayTotal).toString().split('.')[1].length || 0) %>
+                                    签约<%- typeColMap[advance.type].text %>:<%- ctx.helper.formatMoney(advancePayTotal, ',', parseFloat(advancePayTotal).toString().split('.')[1] && parseFloat(advancePayTotal).toString().split('.')[1].length || 0) %>
                                 </th>
                             </tr>

+ 8 - 2
app/view/advance/index.ejs

@@ -5,16 +5,22 @@
             <div>
                 <div class="d-inline-block">
                     <div class="btn-group group-tab">
-                        <a class="btn btn-sm btn-light <%- type === 0 ? 'active' : '' %>" href="/tender/<%- ctx.tender.id %>/advance">
+                        <a class="btn btn-sm btn-light <%- type === 0 ? 'active' : '' %>" href="/tender/<%- ctx.tender.id %>/advance/start">
                             开工预付款<%- type === 0 && latestOrder ? `(第${latestOrder.order}期)` : '' %>
                         </a>
                         <a class="btn btn-sm btn-light <%- type === 1 ? 'active' : '' %>" href="/tender/<%- ctx.tender.id %>/advance/material">
                             材料预付款<%- type === 1 && latestOrder ? `(第${latestOrder.order}期)` : '' %>
                         </a>
+                        <a class="btn btn-sm btn-light <%- type === 2 ? 'active' : '' %>" href="/tender/<%- ctx.tender.id %>/advance/safe">
+                          安全生产预付款<%- type === 2 && latestOrder ? `(第${latestOrder.order}期)` : '' %>
+                        </a>
+                        <a class="btn btn-sm btn-light <%- type === 3 ? 'active' : '' %>" href="/tender/<%- ctx.tender.id %>/advance/dust">
+                          扬尘污染预付款<%- type === 3 && latestOrder ? `(第${latestOrder.order}期)` : '' %>
+                        </a>
                     </div>
                 </div>
                 <div class="d-inline-block ml-2">
-                    签约<%- type === 0 ? '开工' : '材料' %>预付款
+                    签约<%- typeColMap[type].text%>
                     <b><%- ctx.helper.formatMoney(advancePayTotal, ',', parseFloat(advancePayTotal).toString().split('.')[1] && parseFloat(advancePayTotal).toString().split('.')[1].length || 0) %></b> 元
                 </div>
                 <div class="d-inline-block ml-4" style="width:300px">

+ 2 - 2
app/view/schedule/modal.ejs

@@ -15,7 +15,7 @@
             </div>
             <% } else { %>
             <div class="modal-body">
-                <h5>首次使用形象进度需要进行进度台帐初始化设置</h5>
+                <h5>首次使用投资进度需要进行进度台帐初始化设置</h5>
             </div>
             <div class="modal-footer">
                 <a href="/tender/<%- ctx.tender.id %>/schedule/ledger" class="btn btn-sm btn-primary">开始设置</a>
@@ -34,7 +34,7 @@
                     <h5 class="modal-title">提示</h5>
                 </div>
                 <div class="modal-body">
-                    <h5>台账正在进行修订,形象进度无法进行任何操作。</h5>
+                    <h5>台账正在进行修订,投资进度无法进行任何操作。</h5>
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">好的</button>

+ 4 - 1
app/view/stage/index.ejs

@@ -273,7 +273,10 @@
                                     <a href="javascript:void(0);" id="bach-download" class="btn btn-sm btn-primary" type="curr">批量下载</a>
                                     <!--所有附件 翻页-->
                                     <span id="showPage" style="display: none"><a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a></span>
-                                    <% if (!ctx.tender.isTourist && stage.filePermission) { %>
+                                    <!-- <% if (!ctx.tender.isTourist && stage.filePermission) { %>
+                                    <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
+                                    <% } %> -->
+                                    <% if (!ctx.tender.isTourist) { %>
                                     <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
                                     <% } %>
                                 </li>

+ 1 - 1
app/view/tender/detail.ejs

@@ -102,7 +102,7 @@
                                 <a href="#bd-set-7" data-toggle="modal" data-target="#bd-set-7" class="btn btn-sm btn-outline-primary">付款账号</a>
                                 <i class="mx-2">|</i>
                                 <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) { %>
-                                <a href="#xxjd-set" data-toggle="modal" data-target="#xxjd-set" class="btn btn-sm btn-outline-primary">形象进度</a>
+                                <a href="#xxjd-set" data-toggle="modal" data-target="#xxjd-set" class="btn btn-sm btn-outline-primary">投资进度</a>
                                 <% } %>
                                 <a href="javascript: void(0);" class="btn btn-sm btn-outline-primary" id="copyBtn">拷贝设置</a>
                                 <% if (ctx.session.sessionUser.is_admin) { %>

+ 142 - 19
app/view/tender/detail_modal.ejs

@@ -601,9 +601,31 @@
                 <h5 class="modal-title">合同参数</h5>
             </div>
             <div class="modal-body">
-                <div class="form-group">
-                    <!--默认显示-->
-                    <div class="form-group" id="param-spread" style="height: 230px; width: 465px;">
+                <ul class="nav nav-tabs nav-justified mb-2">
+                    <li class="nav-item">
+                        <a class="nav-link active" data-toggle="tab" href="#htcs" role="tab" aria-selected="true">合同参数</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" data-toggle="tab" href="#bzqd" role="tab" aria-selected="false">100章清单</a>
+                    </li>
+                </ul>
+                <div class="tab-content">
+                    <div class="tab-pane active" id="htcs">
+                        <div class="modal-height-300" style="overflow-y: auto">
+                            <div class="form-group">
+                                <!--默认显示-->
+                                <div class="form-group" id="param-spread" style="height: 230px; width: 465px;">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="tab-pane" id="bzqd">
+                        <div class="modal-height-300" style="overflow-y: auto">
+                            <div class="form-group">
+                                <div class="form-group" id="cap100-spread" style="height: 230px; width: 465px;">
+                                </div>
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -623,9 +645,31 @@
                 <h5 class="modal-title">合同参数</h5>
             </div>
             <div class="modal-body">
-                <div class="form-group">
-                    <!--默认显示-->
-                    <div class="form-group" id="param-spread" style="height: 230px; width: 465px;">
+                <ul class="nav nav-tabs nav-justified mb-2">
+                    <li class="nav-item">
+                        <a class="nav-link active" data-toggle="tab" href="#htcs" role="tab" aria-selected="true">合同参数</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" data-toggle="tab" href="#bzqd" role="tab" aria-selected="false">100章清单</a>
+                    </li>
+                </ul>
+                <div class="tab-content">
+                    <div class="tab-pane active" id="htcs">
+                        <div class="modal-height-300" style="overflow-y: auto">
+                            <div class="form-group">
+                                <!--默认显示-->
+                                <div class="form-group" id="param-spread" style="height: 230px; width: 465px;">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="tab-pane" id="bzqd">
+                        <div class="modal-height-300" style="overflow-y: auto">
+                            <div class="form-group">
+                                <div class="form-group" id="cap100-spread" style="height: 230px; width: 465px;">
+                                </div>
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -1220,11 +1264,11 @@
         SpreadJsObj.massOperationSheet(sheet, function () {
             sheet.defaults.rowHeight = 21;
             sheet.setColumnCount(2);
-            sheet.setRowCount(6);
+            sheet.setRowCount(5);
             sheet.setColumnWidth(0, 200);
             sheet.setColumnWidth(1, 200);
-            sheet.getRange(0, 0, 6, 1).vAlign(1).backColor('#e4e7ea').locked(true);
-            sheet.getRange(0, 1, 6, 1).vAlign(1).hAlign(2).locked(false);
+            sheet.getRange(0, 0, 5, 1).vAlign(1).backColor('#e4e7ea').locked(true);
+            sheet.getRange(0, 1, 5, 1).vAlign(1).hAlign(2).locked(false);
             sheet.setText(0, 0, '签约合同价');
             sheet.setText(1, 0, '暂列金额');
             sheet.setText(2, 0, '签约合同价(不含暂列金)');
@@ -1233,11 +1277,39 @@
             sheet.setText(5, 0, '安全生产费');
             sheet.getCell(2, 1).locked(true);
             const lineBorder = new spreadNS.LineBorder('#dee2e6', spreadNS.LineStyle.thin);
-            sheet.getRange(0, 0, 6, 2).setBorder(lineBorder, {all: true});
-            sheet.getRange(0, 0, 6, 2).formatter('@');
+            sheet.getRange(0, 0, 5, 2).setBorder(lineBorder, {all: true});
+            sheet.getRange(0, 0, 5, 2).formatter('@');
             sheet.setSelection(0, 1, 1, 1);
         });
 
+        const cap100spread = SpreadJsObj.createNewSpread($('#cap100-spread')[0]);
+        cap100spread.options.showVerticalScrollbar = false;
+        cap100spread.options.showHorizontalScrollbar = false;
+        const cap100sheet = cap100spread.getActiveSheet();
+        SpreadJsObj.protectedSheet(cap100sheet);
+        cap100sheet.setText(0, 0, '参数名', spreadNS.SheetArea.colHeader);
+        cap100sheet.setText(0, 1, '参数值', spreadNS.SheetArea.colHeader);
+        cap100sheet.setRowHeight(0, 32, spreadNS.SheetArea.colHeader);
+        cap100sheet.setDefaultStyle(vStyle, spreadNS.SheetArea.viewport);
+        cap100sheet.setDefaultStyle(xStyle, spreadNS.SheetArea.colHeader);
+        cap100sheet.setDefaultStyle(yStyle, spreadNS.SheetArea.rowHeader);
+
+        SpreadJsObj.massOperationSheet(cap100sheet, function () {
+            cap100sheet.defaults.rowHeight = 21;
+            cap100sheet.setColumnCount(2);
+            cap100sheet.setRowCount(2);
+            cap100sheet.setColumnWidth(0, 200);
+            cap100sheet.setColumnWidth(1, 200);
+            cap100sheet.getRange(0, 0, 2, 1).vAlign(1).backColor('#e4e7ea').locked(true);
+            cap100sheet.getRange(0, 1, 2, 1).vAlign(1).hAlign(2).locked(false);
+            cap100sheet.setText(0, 0, '安全生产费');
+            cap100sheet.setText(1, 0, '扬尘污染费');
+            const cap100lineBorder = new spreadNS.LineBorder('#dee2e6', spreadNS.LineStyle.thin);
+            cap100sheet.getRange(0, 0, 2, 2).setBorder(cap100lineBorder, {all: true});
+            cap100sheet.getRange(0, 0, 2, 2).formatter('@');
+            cap100sheet.setSelection(0, 1, 1, 1);
+        });
+
         function calcHtjMinusZlj() {
             const htj = _.toNumber(sheet.getText(0, 1));
             const zlj = _.toNumber(sheet.getText(1, 1));
@@ -1290,6 +1362,51 @@
             }
             calcHtjMinusZlj();
         });
+        cap100spread.bind(spreadNS.Events.EditEnded, function (e, info) {
+            const value = _.toNumber(info.editingText);
+            if (_.isNaN(value)) {
+                toastr.warning('请输入不超过万亿的数字');
+                info.sheet.setText(info.row, info.col, '0');
+            } else if (value > Math.pow(10, 13)) {
+                toastr.warning('请输入不超过万亿的数字');
+                info.sheet.setText(info.row, info.col, '0');
+            }
+            // if (info.row === 0 || info.row === 1) {
+            //     calcHtjMinusZlj();
+            // }
+        });
+        SpreadJsObj.addDeleteBind(cap100spread, function (sheet) {
+            const sel = sheet.getSelections()[0];
+            // let calc = false;
+            if (sel) {
+                for (let iRow = sel.row, iRowLength = sel.row + sel.rowCount; iRow < iRowLength; iRow++) {
+                    if (iRow === 2) continue;
+                    for (let iCol = sel.col, iColLength = sel.col + sel.colCount; iCol < iColLength; iCol++) {
+                        if (iCol !== 1) continue;
+                        sheet.setText(iRow, iCol, '0');
+                        // if (iRow === 0 || iRow === 1) calc = true;
+                    }
+                }
+            }
+            // if (calc) calcHtjMinusZlj();
+        });
+        cap100spread.bind(spreadNS.Events.ClipboardPasted, function (e, info) {
+            let bHint = false;
+            for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                const curRow = info.cellRange.row + iRow;
+                for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                    const curCol = info.cellRange.col + iCol;
+                    const value = _.toNumber(info.sheet.getText(curRow, curCol));
+                    if (_.isNaN(value) || value > Math.pow(10, 13)) {
+                        bHint = true;
+                        info.sheet.setText(curRow, curCol, '0');
+                    }
+                }
+            }
+            if (bHint) {
+                toastr.warning('请输入不超过万亿的数字');
+            }
+        });
 
         function loadDealProperty() {
             sheet.setValue(0, 1, property.deal_param.contractPrice);
@@ -1297,7 +1414,9 @@
             sheet.setValue(2, 1, ZhCalc.sub(property.deal_param.contractPrice, property.deal_param.zanLiePrice));
             sheet.setValue(3, 1, property.deal_param.startAdvance);
             sheet.setValue(4, 1, property.deal_param.materialAdvance);
-            sheet.setValue(5, 1, property.deal_param.safeAdvance);
+            // sheet.setValue(5, 1, property.deal_param.safeAdvance);
+            cap100sheet.setValue(0, 1, property.deal_param.safeAdvance);
+            cap100sheet.setValue(1, 1, property.deal_param.dustAdvance);
 
         }
         function setReadOnly (readOnly) {
@@ -1305,7 +1424,9 @@
             sheet.getCell(1, 1).locked(readOnly);
             sheet.getCell(3, 1).locked(readOnly);
             sheet.getCell(4, 1).locked(readOnly);
-            sheet.getCell(5, 1).locked(readOnly);
+            // sheet.getCell(5, 1).locked(readOnly);
+            cap100sheet.getCell(0, 1).locked(readOnly);
+            cap100sheet.getCell(1, 1).locked(readOnly);
         }
         function getNewDealData () {
             const result = {};
@@ -1313,7 +1434,9 @@
             result.zanLiePrice = _.toNumber(sheet.getText(1, 1));
             result.startAdvance = _.toNumber(sheet.getText(3, 1));
             result.materialAdvance = _.toNumber(sheet.getText(4, 1));
-            result.safeAdvance = _.toNumber(sheet.getText(5, 1));
+            // result.safeAdvance = _.toNumber(sheet.getText(5, 1));
+            result.safeAdvance = _.toNumber(cap100sheet.getText(0, 1));
+            result.dustAdvance = _.toNumber(cap100sheet.getText(1, 1));
             return result;
         }
 
@@ -1648,7 +1771,7 @@
         });
     }
     $(function () {
-        // 形象进度
+        // 投资进度
         let timer2 = null;
         let oldSearchVal2 = null;
         $('body').on('input propertychange', '#tourist_dropdownMenu .gr-search', function (e) {
@@ -1772,15 +1895,15 @@
 </script>
 <% } %>
 <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) { %>
-<!--标段设置-形象进度-->
+<!--标段设置-投资进度-->
 <div class="modal fade" id="xxjd-set" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">
             <div class="modal-header">
-                <h5 class="modal-title">形象进度</h5>
+                <h5 class="modal-title">投资进度</h5>
             </div>
             <div class="modal-body">
-                <div class="alert alert-warning">设置可使用「形象进度」用户</div>
+                <div class="alert alert-warning">设置可使用「投资进度」用户</div>
                 <div class="dropdown">
                     <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" id="xxjd_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                         添加用户
@@ -1841,7 +1964,7 @@
 <script>
     $(function () {
         const scPermission = JSON.parse(unescape('<%- escape(JSON.stringify(scPermission)) %>'));
-        // 形象进度
+        // 投资进度
         let timer = null;
         let oldSearchVal = null;
         $('body').on('input propertychange', '#xxjd_dropdownMenu .gr-search', function(e) {

+ 2 - 2
app/view/tender/tender_sub_menu.ejs

@@ -11,7 +11,7 @@
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <% const curUrl = `/tender/${ctx.tender.id}/advance` %>
-                <li <% if (ctx.url.indexOf(curUrl) !== -1) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/advance"><i class="fa fa-handshake-o"></i> <span>预付款</span></a></li>
+                <li <% if (ctx.url.indexOf(curUrl) !== -1) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/advance/start"><i class="fa fa-handshake-o"></i> <span>预付款</span></a></li>
             </ul>
         </div>
         <div class="nav-box">
@@ -45,7 +45,7 @@
         </div>
         <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && (ctx.tender.schedule_permission !== 0 || ctx.tender.isTourist)) { %>
         <div class="nav-box">
-            <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
+            <h3><i class="fa fa-bar-chart "></i> 投资进度</h3>
             <ul class="nav-list list-unstyled sub-list">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>

+ 1 - 1
app/view/tender/tender_sub_mini_menu.ejs

@@ -49,7 +49,7 @@
         </div>
         <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && (ctx.tender.schedule_permission !== 0|| ctx.tender.isTourist)) { %>
         <div class="nav-box">
-            <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
+            <h3><i class="fa fa-bar-chart "></i> 投资进度</h3>
             <ul class="nav-list list-unstyled sub-list">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule' || ctx.url === '/tender/' + ctx.tender.id + '/schedule/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule"><span>进度概况</span></a></li>
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/schedule/plan') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/schedule/plan"><span>计划进度</span></a></li>

+ 3 - 0
sql/update.sql

@@ -6,3 +6,6 @@ CREATE TABLE `calculation`.`zh_rpt_archive_encryption` (
   PRIMARY KEY (`id`),
   INDEX `PRJ_STG` (`prj_id` ASC, `stage_id` ASC))
 COMMENT = '归档文档的需要加密签名的坐标及其他key信息(如签名角色id,签名角色名称等)';
+
+ALTER TABLE `zh_material_list` ADD `expr` VARCHAR(500) NULL DEFAULT '' COMMENT '公式' AFTER `quantity`;
+