Browse Source

短信和计量重新审批功能

laiguoran 5 years ago
parent
commit
375fdd9d19

+ 9 - 0
app/const/audit.js

@@ -69,6 +69,7 @@ const stage = (function () {
         checked: 3, // 审批通过
         checkNo: 4, // 审批退回原报
         checkNoPre: 5, // 审批退回上一人
+        checkAgain: 6, // 重新审批
     };
 
     // 流程状态提示
@@ -78,6 +79,7 @@ const stage = (function () {
     statusString[status.checked] = '审批通过';
     statusString[status.checkNo] = '审批退回';
     statusString[status.checkNoPre] = '审批退回';
+    statusString[status.checkAgain] = '重新审批';
 
     // 流程状态样式
     const statusClass = [];
@@ -86,6 +88,7 @@ const stage = (function () {
     statusClass[status.checked] = 'text-success';
     statusClass[status.checkNo] = 'text-warning';
     statusClass[status.checkNoPre] = 'text-warning';
+    statusClass[status.checkAgain] = 'text-warning';
 
     /**
      * 期列表,审批状态一列
@@ -97,6 +100,7 @@ const stage = (function () {
     statusButton[status.checked] = '';
     statusButton[status.checkNo] = '重新上报';
     statusButton[status.checkNoPre] = '重新审批';
+    statusButton[status.checkAgain] = '重新审批';
     // 按钮样式
     const statusButtonClass = [];
     statusButtonClass[status.uncheck] = 'btn-primary';
@@ -104,6 +108,7 @@ const stage = (function () {
     statusButtonClass[status.checked] = '';
     statusButtonClass[status.checkNo] = 'btn-warning';
     statusButtonClass[status.checkNoPre] = 'btn-warning';
+    statusButtonClass[status.checkAgain] = 'btn-warning';
     // 描述文本
     const auditString = [];
     auditString[status.uncheck] = '';
@@ -111,6 +116,7 @@ const stage = (function () {
     auditString[status.checked] = '完成';
     auditString[status.checkNo] = '退回';
     auditString[status.checkNoPre] = '退回';
+    auditString[status.checkAgain] = '重新审批';
     // 文字样式
     const auditStringClass = [];
     auditStringClass[status.uncheck] = '';
@@ -118,6 +124,7 @@ const stage = (function () {
     auditStringClass[status.checked] = 'text-success';
     auditStringClass[status.checkNo] = 'text-warning';
     auditStringClass[status.checkNoPre] = 'text-warning';
+    auditStringClass[status.checkAgain] = 'text-warning';
     /* ------------------------------------------------------- */
 
     /**
@@ -130,6 +137,7 @@ const stage = (function () {
     auditProgress[status.checked] = '审批通过';
     auditProgress[status.checkNo] = '审批退回';
     auditProgress[status.checkNoPre] = '审批退回';
+    auditProgress[status.checkAgain] = '重新审批';
     // 样式
     const auditProgressClass = [];
     auditProgressClass[status.uncheck] = '';
@@ -137,6 +145,7 @@ const stage = (function () {
     auditProgressClass[status.checked] = 'text-success';
     auditProgressClass[status.checkNo] = 'text-warning';
     auditProgressClass[status.checkNoPre] = 'text-warning';
+    auditProgressClass[status.checkAgain] = 'text-warning';
     /* ------------------------------------------------------- */
 
     const backType = {

+ 50 - 0
app/const/sms_type.js

@@ -0,0 +1,50 @@
+'use strict';
+
+/**
+ * 短信通知类型
+ *
+ * @author Ellisran
+ * @date 2019/8/20
+ * @version
+ */
+const smsConst = {
+    TZ: 'TZ',
+    JL: 'JL',
+    BG: 'BG',
+};
+const judgeConst = {
+    approval: 1,
+    result: 2,
+}
+const smsType = {
+    TZ: {
+        name: '台账审批',
+        path: '',
+        children: [
+            { title: '需要我审批', value: 1 },
+            { title: '审批结果', value: 2 },
+        ],
+    },
+    JL: {
+        name: '计量审批',
+        path: '',
+        children: [
+            { title: '需要我审批', value: 1 },
+            { title: '审批结果', value: 2 },
+        ],
+    },
+    BG: {
+        name: '变更管理',
+        path: '',
+        children: [
+            { title: '需要我审批', value: 1 },
+            { title: '审批结果', value: 2 },
+        ],
+    },
+};
+
+module.exports = {
+    const: smsConst,
+    judge: judgeConst,
+    type: smsType,
+};

+ 3 - 3
app/controller/change_controller.js

@@ -484,16 +484,16 @@ module.exports = app => {
                 let result = false;
                 switch (status) {
                     case 3:// 审批通过
-                        result = await ctx.service.change.approvalSuccess(ctx.request.body);
+                        result = await ctx.service.change.approvalSuccess(ctx.request.body, changeData);
                         break;
                     case 4:// 审批终止
                         result = await ctx.service.change.approvalStop(ctx.request.body);
                         break;
                     case 5:// 审批退回到原报人
-                        result = await ctx.service.change.approvalBack(ctx.request.body);
+                        result = await ctx.service.change.approvalBack(ctx.request.body, changeData);
                         break;
                     case 6:// 审批退回到上一个审批人
-                        result = await ctx.service.change.approvalBackNew(ctx.request.body);
+                        result = await ctx.service.change.approvalBackNew(ctx.request.body, changeData);
                         break;
                     default:break;
                 }

+ 25 - 1
app/controller/profile_controller.js

@@ -9,6 +9,7 @@
  */
 
 const profileMenu = require('../../config/menu').profileMenu;
+const smsTypeConst = require('../const/sms_type');
 const qr = require('qr-image');
 
 module.exports = app => {
@@ -180,8 +181,31 @@ module.exports = app => {
 
             const renderData = {
                 accountData,
+                smsType: smsTypeConst.type,
             };
-            await this.layout('profile/sms.ejs', renderData);
+            await this.layout('profile/sms.ejs', renderData, 'profile/modal.ejs');
+        }
+
+        /**
+         * 短信通知类型设置
+         *
+         * @param {object} ctx - egg全局变量
+         * @return {void}
+         */
+        async smsType(ctx) {
+            try {
+                const sessionUser = ctx.session.sessionUser;
+                const result = await ctx.service.projectAccount.smsTypeSet(sessionUser.accountId, ctx.request.body);
+
+                if (!result) {
+                    throw '修改通知类型失败!';
+                }
+                this.setMessage('通知类型绑定成功', this.messageType.SUCCESS);
+            } catch (error) {
+                console.log(error);
+                this.setMessage(error.toString(), this.messageType.ERROR);
+            }
+            ctx.redirect(ctx.request.header.referer);
         }
 
         /**

+ 1 - 1
app/controller/sign_controller.js

@@ -30,7 +30,7 @@ module.exports = app => {
                 if (userinfo && userinfo.session_token && userinfo.session_token === ctx.query.app_token) {
                     renderData.id = userinfo.id;
                     renderData.name = userinfo.name;
-                    renderData.role = userinfo.role;
+                    // renderData.role = userinfo.role;
                 } else {
                     throw '参数有误, 无法访问本页.';
                 }

+ 22 - 0
app/controller/stage_controller.js

@@ -917,6 +917,28 @@ module.exports = app => {
             }
         }
 
+        /**
+         * 重新审批
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async checkAuditAgain(ctx) {
+            try {
+                if (ctx.stage.user_id === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) {
+                    await ctx.service.stageAudit.checkAgain(ctx.stage.id, ctx.stage.times);
+                    console.log('success');
+                    ctx.redirect(ctx.request.header.referer);
+                } else {
+                    throw '您无权进行该操作';
+                }
+            } catch (err) {
+                console.log(err);
+                this.log(err);
+                ctx.session.postError = err.toString();
+                ctx.redirect(ctx.request.header.referer);
+            }
+        }
+
         // 清单汇总相关
         _getGatherSpreadSetting() {
             const _ = this.app._;

+ 3 - 0
app/extend/helper.js

@@ -232,11 +232,14 @@ module.exports = {
     async sendRequest(url, data, type = 'POST', dataType = 'json') {
         // 发起请求
         try {
+            console.log(url);
+            console.log(data);
             const response = await this.ctx.curl(url, {
                 method: type,
                 data,
                 dataType,
             });
+            console.log(response);
             if (response.status !== 200) {
                 throw '请求失败';
             }

+ 21 - 14
app/lib/sms.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const xmlReader = require('xmlreader');
+// const xmlReader = require('xmlreader');
 class SMS {
 
     /**
@@ -19,7 +19,9 @@ class SMS {
      */
     constructor(ctx) {
         this.ctx = ctx;
+        // this.url = 'https://sms.yunpian.com/v2/sms/batch_send.json';
         this.url = 'http://sms.haotingyun.com/v2/sms/single_send.json';
+        this.url2 = 'http://sms.haotingyun.com/v2/sms/tpl_single_send.json';
         // this.url = 'http://101.132.42.40:7862/sms';
     }
 
@@ -28,9 +30,10 @@ class SMS {
      *
      * @param {String|Array} mobile - 发送的电话号码
      * @param {String} content - 发送的内容
+     * @param {String} tplId - 补充的tpl_id(防止模板无法找到发送失败)
      * @return {Boolean} - 发送结果
      */
-    async send(mobile, content) {
+    async send(mobile, content, tplId = '') {
         if (mobile instanceof Array) {
             mobile = mobile.join(',');
         }
@@ -45,8 +48,12 @@ class SMS {
             text: content,
             // extno: config.extno,
         };
+        if (tplId !== '') {
+            postData.tpl_id = tplId;
+        }
+        const url = tplId !== '' ? this.url2 : this.url;
         try {
-            const response = await this.ctx.helper.sendRequest(this.url, postData, 'POST');
+            const response = await this.ctx.helper.sendRequest(url, postData, 'POST');
             // const xmlData = await this.xmlParse(response);
             // if (xmlData === undefined || xmlData.returnstatus.text() !== 'Success') {
             //     throw '短信发送失败!';
@@ -69,17 +76,17 @@ class SMS {
      * @param {String} xml - xml数据
      * @return {Object} - 解析结果
      */
-    xmlParse(xml) {
-        return new Promise(function(resolve, reject) {
-            xmlReader.read(xml, function(errors, xmlData) {
-                if (errors) {
-                    reject('');
-                } else {
-                    resolve(xmlData.returnsms);
-                }
-            });
-        });
-    }
+    // xmlParse(xml) {
+    //     return new Promise(function(resolve, reject) {
+    //         xmlReader.read(xml, function(errors, xmlData) {
+    //             if (errors) {
+    //                 reject('');
+    //             } else {
+    //                 resolve(xmlData.returnsms);
+    //             }
+    //         });
+    //     });
+    // }
 }
 
 module.exports = SMS;

+ 5 - 0
app/middleware/stage_check.js

@@ -87,6 +87,11 @@ module.exports = options => {
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }
+
+            // 获取最新的期
+            stage.highOrder = yield this.service.stage.count({
+                tid: this.tender.id,
+            });
             this.stage = stage;
             yield next;
         } catch (err) {

+ 2 - 0
app/router.js

@@ -167,6 +167,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/audit/delete', sessionAuth, tenderCheck, stageCheck, 'stageController.deleteAudit');
     app.post('/tender/:id/measure/stage/:order/audit/start', sessionAuth, tenderCheck, stageCheck, 'stageController.startAudit');
     app.post('/tender/:id/measure/stage/:order/audit/check', sessionAuth, tenderCheck, stageCheck, 'stageController.checkAudit');
+    app.get('/tender/:id/measure/stage/:order/audit/check/again', sessionAuth, tenderCheck, stageCheck, 'stageController.checkAuditAgain');
     // 清单汇总
     app.get('/tender/:id/measure/stage/:order/gather', sessionAuth, tenderCheck, stageCheck, 'stageController.gather');
     // 审核比较
@@ -203,6 +204,7 @@ module.exports = app => {
     // 个人账号相关
     app.get('/profile/info', sessionAuth, 'profileController.info');
     app.get('/profile/sms', sessionAuth, 'profileController.sms');
+    app.post('/profile/sms/type', sessionAuth, 'profileController.smsType');
     app.get('/profile/sign', sessionAuth, 'profileController.sign');
     app.post('/profile/sign/delete', sessionAuth, 'profileController.signDelete');
     app.get('/profile/safe', sessionAuth, 'profileController.safe');

+ 66 - 3
app/service/change.js

@@ -11,6 +11,8 @@
 const audit = require('../const/audit');
 const fs = require('fs');
 const path = require('path');
+const smsTypeConst = require('../const/sms_type');
+const SMS = require('../lib/sms');
 
 module.exports = app => {
     class Change extends app.BaseService {
@@ -321,6 +323,19 @@ module.exports = app => {
                         uSite++;
                         uSort++;
                         insertCA.push(caArray);
+
+                        // 添加短信通知-需要审批提醒功能
+                        if (change_status && index === 0) {
+                            const smsUser = await this.ctx.service.projectAccount.getDataById(auditInfo[0]);
+                            if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                                const smsType = JSON.parse(smsUser.sms_type);
+                                if (smsType[smsTypeConst.const.BG] !== undefined && smsType[smsTypeConst.const.BG].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                                    const sms = new SMS(this.ctx);
+                                    const content = '【纵横计量支付】' + changeInfo.code + '变更需要您审批。';
+                                    sms.send(smsUser.auth_mobile, content);
+                                }
+                            }
+                        }
                     }
                     await this.transaction.insert(this.ctx.service.changeAudit.tableName, insertCA);
                 }
@@ -398,9 +413,10 @@ module.exports = app => {
         /**
          * 审批通过
          * @param {int} postData - 表单提交的数据
+         * @param {int} changeData - 变更令的数据
          * @return {void}
          */
-        async approvalSuccess(postData) {
+        async approvalSuccess(postData, changeData) {
             // 初始化事务
             this.transaction = await this.db.beginTransaction();
             let result = false;
@@ -446,6 +462,17 @@ module.exports = app => {
                     change_update.p_code = postData.p_code;
                     change_update.sin_time = Date.parse(new Date()) / 1000;
                     change_update.total_price = total_price;
+
+                    // 添加短信通知-审批通过提醒功能
+                    const smsUser = await this.ctx.service.projectAccount.getDataById(changeData.uid);
+                    if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                        const smsType = JSON.parse(smsUser.sms_type);
+                        if (smsType[smsTypeConst.const.BG] !== undefined && smsType[smsTypeConst.const.BG].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                            const sms = new SMS(this.ctx);
+                            const content = '【纵横计量支付】' + changeData.code + '变更,审批通过。';
+                            sms.send(smsUser.auth_mobile, content);
+                        }
+                    }
                 } else {
                     // 设置下一个审批人为审批状态
                     const nextAudit_update = {
@@ -453,6 +480,18 @@ module.exports = app => {
                         status: 2,
                     };
                     await this.transaction.update(this.ctx.service.changeAudit.tableName, nextAudit_update);
+
+                    // 添加短信通知-需要审批提醒功能
+                    const nextAuditData = await this.ctx.service.changeAudit.getDataById(postData.audit_next_id);
+                    const smsUser = await this.ctx.service.projectAccount.getDataById(nextAuditData.uid);
+                    if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                        const smsType = JSON.parse(smsUser.sms_type);
+                        if (smsType[smsTypeConst.const.BG] !== undefined && smsType[smsTypeConst.const.BG].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                            const sms = new SMS(this.ctx);
+                            const content = '【纵横计量支付】' + changeData.code + '变更需要您审批。';
+                            sms.send(smsUser.auth_mobile, content);
+                        }
+                    }
                 }
                 const options = {
                     where: {
@@ -511,9 +550,10 @@ module.exports = app => {
         /**
          * 审批退回到原报人
          * @param {int} postData - 表单提交的数据
+         * @param {int} changeData - 变更令的数据
          * @return {void}
          */
-        async approvalBack(postData) {
+        async approvalBack(postData, changeData) {
             // 初始化事务
             this.transaction = await this.db.beginTransaction();
             let result = false;
@@ -566,6 +606,17 @@ module.exports = app => {
                 await this.transaction.update(this.tableName, change_update, options);
                 await this.transaction.commit();
                 result = true;
+
+                // 添加短信通知-审批退回提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(changeData.uid);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.BG] !== undefined && smsType[smsTypeConst.const.BG].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + changeData.code + '变更,审批退回。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
             } catch (error) {
                 await this.transaction.rollback();
                 result = false;
@@ -576,9 +627,10 @@ module.exports = app => {
         /**
          * 审批退回到上一个审批人
          * @param {int} postData - 表单提交的数据
+         * @param {int} changeData - 变更令的数据
          * @return {void}
          */
-        async approvalBackNew(postData) {
+        async approvalBackNew(postData, changeData) {
             // 初始化事务
             this.transaction = await this.db.beginTransaction();
             let result = false;
@@ -668,6 +720,17 @@ module.exports = app => {
                 await this.transaction.update(this.tableName, change_update, options);
                 await this.transaction.commit();
                 result = true;
+
+                // 添加短信通知-需要审批提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(lastauditInfo.uid);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.BG] !== undefined && smsType[smsTypeConst.const.BG].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + changeData.code + '变更需要您审批。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
             } catch (error) {
                 await this.transaction.rollback();
                 result = false;

+ 52 - 1
app/service/ledger_audit.js

@@ -9,6 +9,8 @@
  */
 
 const auditConst = require('../const/audit').ledger;
+const smsTypeConst = require('../const/sms_type');
+const SMS = require('../lib/sms');
 
 module.exports = app => {
     class LedgerAudit extends app.BaseService {
@@ -183,8 +185,21 @@ module.exports = app => {
             try {
                 await transaction.update(this.tableName, {id: audit.id, status: auditConst.status.checking, begin_time: new Date()});
                 await transaction.update(this.ctx.service.tender.tableName, {id: tenderId, ledger_status: auditConst.status.checking});
+
+                // 添加短信通知-需要审批提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(audit.audit_id);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.TZ] !== undefined && smsType[smsTypeConst.const.TZ].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                        const tenderInfo = await this.ctx.service.tender.getDataById(tenderId);
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + tenderInfo.name + '台帐需要您审批。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
+
                 await transaction.commit();
-            } catch(err) {
+            } catch (err) {
                 await transaction.rollback();
                 throw err;
             }
@@ -234,11 +249,35 @@ module.exports = app => {
                     // 无下一审核人表示,审核结束
                     if (nextAudit) {
                         await transaction.update(this.tableName, {id: nextAudit.id, status: auditConst.status.checking, begin_time: time});
+
+                        // 添加短信通知-需要审批提醒功能
+                        const smsUser = await this.ctx.service.projectAccount.getDataById(nextAudit.audit_id);
+                        if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                            const smsType = JSON.parse(smsUser.sms_type);
+                            if (smsType[smsTypeConst.const.TZ] !== undefined && smsType[smsTypeConst.const.TZ].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                                const tenderInfo = await this.ctx.service.tender.getDataById(tenderId);
+                                const sms = new SMS(this.ctx);
+                                const content = '【纵横计量支付】' + tenderInfo.name + '台帐需要您审批。';
+                                sms.send(smsUser.auth_mobile, content);
+                            }
+                        }
                     } else {
                         // 同步标段信息
                         await transaction.update(this.ctx.service.tender.tableName, {id: tenderId, ledger_status: checkType});
                         // 拷贝备份台账数据
                         await this._copyHisytoryLedger(tenderId, transaction, times);
+
+                        // 添加短信通知-审批通过提醒功能
+                        const tenderInfo = await this.ctx.service.tender.getDataById(tenderId);
+                        const smsUser = await this.ctx.service.projectAccount.getDataById(tenderInfo.user_id);
+                        if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                            const smsType = JSON.parse(smsUser.sms_type);
+                            if (smsType[smsTypeConst.const.TZ] !== undefined && smsType[smsTypeConst.const.TZ].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                                const sms = new SMS(this.ctx);
+                                const content = '【纵横计量支付】' + tenderInfo.name + '台账审批通过。';
+                                sms.send(smsUser.auth_mobile, content);
+                            }
+                        }
                     }
                 } else {
                     // 同步标段信息
@@ -255,6 +294,18 @@ module.exports = app => {
                     await transaction.insert(this.tableName, auditors);
                     // 拷贝备份台账数据
                     await this._copyHisytoryLedger(tenderId, transaction, times);
+
+                    // 添加短信通知-审批退回提醒功能
+                    const tenderInfo = await this.ctx.service.tender.getDataById(tenderId);
+                    const smsUser = await this.ctx.service.projectAccount.getDataById(tenderInfo.user_id);
+                    if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                        const smsType = JSON.parse(smsUser.sms_type);
+                        if (smsType[smsTypeConst.const.TZ] !== undefined && smsType[smsTypeConst.const.TZ].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                            const sms = new SMS(this.ctx);
+                            const content = '【纵横计量支付】' + tenderInfo.name + '台账审批退回。';
+                            sms.send(smsUser.auth_mobile, content);
+                        }
+                    }
                 }
 
                 await transaction.commit();

+ 23 - 0
app/service/project_account.js

@@ -513,6 +513,29 @@ module.exports = app => {
 
             return result;
         }
+
+        /**
+         * 短信通知类型设置
+         *
+         * @param {String} id - 账号id
+         * @param {Number} data - 通知类型
+         * @return {Boolean} - 返回修改结果
+         */
+        async smsTypeSet(id, data) {
+            if (data._csrf !== undefined) {
+                delete data._csrf;
+            }
+            const updateData = {
+                id,
+                sms_type: JSON.stringify(data),
+            };
+
+            const operate = await this.db.update(this.tableName, updateData);
+
+            const result = operate.affectedRows > 0;
+
+            return result;
+        }
     }
 
     return ProjectAccount;

+ 141 - 5
app/service/stage_audit.js

@@ -9,6 +9,8 @@
  */
 
 const auditConst = require('../const/audit').stage;
+const smsTypeConst = require('../const/sms_type');
+const SMS = require('../lib/sms');
 
 module.exports = app => {
     class StageAudit extends app.BaseService {
@@ -191,8 +193,22 @@ module.exports = app => {
                 await transaction.update(this.ctx.service.stage.tableName, {
                     id: stageId, status: auditConst.status.checking,
                     contract_tp: tpData.contract_tp,
-                    qc_tp: tpData.qc_tp
+                    qc_tp: tpData.qc_tp,
                 });
+
+                // 添加短信通知-需要审批提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                        const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
+                        const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,需要您审批。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
+
                 // todo 更新标段tender状态 ?
                 await transaction.commit();
             } catch(err) {
@@ -229,6 +245,19 @@ module.exports = app => {
                         contract_tp: tpData.contract_tp,
                         qc_tp: tpData.qc_tp,
                     });
+
+                    // 添加短信通知-需要审批提醒功能
+                    const smsUser = await this.ctx.service.projectAccount.getDataById(nextAudit.aid);
+                    if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                        const smsType = JSON.parse(smsUser.sms_type);
+                        if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                            const tenderInfo = await this.ctx.service.tender.getDataById(nextAudit.tid);
+                            const stageInfo = await this.ctx.service.stage.getDataById(nextAudit.sid);
+                            const sms = new SMS(this.ctx);
+                            const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,需要您审批。';
+                            sms.send(smsUser.auth_mobile, content);
+                        }
+                    }
                 } else {
                     // 本期结束
                     // 生成截止本期数据 final数据
@@ -240,6 +269,19 @@ module.exports = app => {
                         contract_tp: tpData.contract_tp,
                         qc_tp: tpData.qc_tp,
                     });
+
+                    // 添加短信通知-审批通过提醒功能
+                    const stageInfo = await this.ctx.service.stage.getDataById(stageId);
+                    const smsUser = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
+                    if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                        const smsType = JSON.parse(smsUser.sms_type);
+                        if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                            const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
+                            const sms = new SMS(this.ctx);
+                            const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,审批通过。';
+                            sms.send(smsUser.auth_mobile, content);
+                        }
+                    }
                 }
                 await transaction.commit();
             } catch (err) {
@@ -283,6 +325,20 @@ module.exports = app => {
                 await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份最新数据给原报
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times + 1, 0, transaction);
+
+                // 添加短信通知-审批退回提醒功能
+                const stageInfo = await this.ctx.service.stage.getDataById(stageId);
+                const smsUser = await this.ctx.service.projectAccount.getDataById(stageInfo.user_id);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.result.toString()) !== -1) {
+                        const tenderInfo = await this.ctx.service.tender.getDataById(stageInfo.tid);
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,审批退回。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
+
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -297,7 +353,13 @@ module.exports = app => {
             if (!audit || audit.order <= 1) {
                 throw '审核数据错误';
             }
-            const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
+            // 添加重新审批后,不能用order-1,取groupby值里的上一个才对
+            // const preAuditor = await this.getDataByCondition({sid: stageId, times: times, order: audit.order - 1});
+            const auditors2 = await this.getAuditGroupByList(stageId, times);
+            const auditorIndex = await auditors2.findIndex(function(item) {
+                return item.aid === audit.aid;
+            });
+            const preAuditor = auditors2[auditorIndex - 1];
 
             const transaction = await this.db.beginTransaction();
             try {
@@ -312,19 +374,33 @@ module.exports = app => {
                 // 上一审批人,当前审批人 再次添加至流程
                 const newAuditors = [];
                 newAuditors.push({
-                    tid: preAuditor.tid, sid: preAuditor.sid, aid: preAuditor.aid,
-                    times: preAuditor.times, order: preAuditor.order + 2, status: auditConst.status.checking,
+                    tid: audit.tid, sid: audit.sid, aid: preAuditor.aid,
+                    times: audit.times, order: audit.order + 1, status: auditConst.status.checking,
                     begin_time: time,
                 });
                 newAuditors.push({
                     tid: audit.tid, sid: audit.sid, aid: audit.aid,
-                    times: audit.times, order: audit.order + 2, status: auditConst.status.uncheck
+                    times: audit.times, order: audit.order + 2, status: auditConst.status.uncheck,
                 });
                 await transaction.insert(this.tableName, newAuditors);
                 // 计算该审批人最终数据
                 await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
                 // 复制一份最新数据给下一人
                 await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 1, transaction);
+
+                // 添加短信通知-需要审批提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(preAuditor.aid);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                        const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
+                        const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,需要您审批。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
+
                 await transaction.commit();
             } catch(err) {
                 await transaction.rollback();
@@ -480,6 +556,66 @@ module.exports = app => {
         }
 
         /**
+         * 审批
+         * @param {Number} stageId - 标段id
+         * @param {Number} times - 第几次审批
+         * @returns {Promise<void>}
+         */
+        async checkAgain(stageId, times = 1) {
+            const time = new Date();
+            // 整理当前流程审核人状态更新
+            const audit = (await this.getAllDataByCondition({ where: { sid: stageId, times }, orders: [['order', 'desc']], limit: 1, offset: 0 }))[0];
+            if (!audit || audit.order <= 1) {
+                throw '审核数据错误';
+            }
+            const transaction = await this.db.beginTransaction();
+            try {
+                // 当前审批人2次添加至流程中
+                const newAuditors = [];
+                newAuditors.push({
+                    tid: audit.tid, sid: audit.sid, aid: audit.aid,
+                    times: audit.times, order: audit.order + 1, status: auditConst.status.checkAgain,
+                    begin_time: time, end_time: time, opinion: '',
+                });
+                newAuditors.push({
+                    tid: audit.tid, sid: audit.sid, aid: audit.aid,
+                    times: audit.times, order: audit.order + 2, status: auditConst.status.checking,
+                    begin_time: time,
+                });
+                await transaction.insert(this.tableName, newAuditors);
+
+                // 复制一份最新数据给下一人
+                await this.ctx.service.stagePay.copyAuditStagePays(this.ctx.stage, this.ctx.stage.times, audit.order + 2, transaction);
+
+                // 本期结束
+                // 生成截止本期数据 final数据
+                await this.ctx.service.stageBillsFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage);
+                await this.ctx.service.stagePosFinal.delGenerateFinalData(transaction, this.ctx.tender, this.ctx.stage);
+                // 同步 期信息
+                await transaction.update(this.ctx.service.stage.tableName, {
+                    id: stageId, status: auditConst.status.checking,
+                });
+
+                // 添加短信通知-需要审批提醒功能
+                const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);
+                if (smsUser.auth_mobile !== undefined && smsUser.sms_type !== '') {
+                    const smsType = JSON.parse(smsUser.sms_type);
+                    if (smsType[smsTypeConst.const.JL] !== undefined && smsType[smsTypeConst.const.JL].indexOf(smsTypeConst.judge.approval.toString()) !== -1) {
+                        const tenderInfo = await this.ctx.service.tender.getDataById(audit.tid);
+                        const stageInfo = await this.ctx.service.stage.getDataById(audit.sid);
+                        const sms = new SMS(this.ctx);
+                        const content = '【纵横计量支付】' + tenderInfo.name + '第' + stageInfo.order + '期,需要您审批。';
+                        sms.send(smsUser.auth_mobile, content);
+                    }
+                }
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        /**
          * 获取审核人需要审核的期列表
          *
          * @param auditorId

+ 14 - 0
app/service/stage_bills_final.js

@@ -106,6 +106,20 @@ module.exports = app => {
                 await transaction.query(sql, sqlParam);
             }
         }
+
+        /**
+         * 删除生成本期最终数据
+         * @param transaction - 所属事务
+         * @param {Object} tender - 标段
+         * @param {Object} stage - 本期
+         * @returns {Promise<void>}
+         */
+        async delGenerateFinalData(transaction, tender, stage) {
+            if (!transaction || !tender || !stage) {
+                throw '数据错误';
+            }
+            await transaction.delete(this.tableName, { tid: tender.id, sid: stage.id });
+        }
     }
 
     return StageBillsFinal;

+ 15 - 1
app/service/stage_pos_final.js

@@ -91,7 +91,21 @@ module.exports = app => {
                 await transaction.query(sql, sqlParam);
             }
         }
+
+        /**
+         * 删除生成本期最终数据
+         * @param transaction - 所属事务
+         * @param {Object} tender - 标段
+         * @param {Object} stage - 本期
+         * @returns {Promise<void>}
+         */
+        async delGenerateFinalData(transaction, tender, stage) {
+            if (!transaction || !tender || !stage) {
+                throw '数据错误';
+            }
+            await transaction.delete(this.tableName, { tid: tender.id, sid: stage.id });
+        }
     }
 
     return StagePosFinal;
-}
+}

+ 7 - 8
app/view/measure/stage.ejs

@@ -25,8 +25,8 @@
                     <th class="text-center">本期完成计量</th>
                     <th class="text-center">截止上期完成计量</th>
                     <th class="text-center">截止本期完成计量</th>
-                    <th class="text-center">审批状态</th>
                     <th class="text-center">审批进度</th>
+                    <th class="text-center">操作</th>
                 </tr>
                 </thead>
                 <tbody>
@@ -44,6 +44,12 @@
                     <td class="text-right"><%- (s.tp ? s.tp : '')%></td>
                     <td class="text-right"><%- (s.pre_tp ? s.pre_tp : '')%></td>
                     <td class="text-right"><%- (s.end_tp ? s.end_tp : '')%></td>
+                    <td class="<%- auditConst.auditProgressClass[s.status] %>">
+                        <% if (s.curAuditor) { %>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- s.curAuditor.name %><%if (s.curAuditor.role !== '' && s.curAuditor.role !== null) { %>-<%- s.curAuditor.role %><% } %></a>
+                        <% } %>
+                        <%- auditConst.auditProgress[s.status] %>
+                    </td>
                     <td class="text-center">
                     <% if (s.status === auditConst.status.uncheck && s.user_id === ctx.session.sessionUser.accountId) { %>
                         <a href="<%- '/tender/' + ctx.tender.id + '/measure/stage/' + s.order %>" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
@@ -57,13 +63,6 @@
                         <span class="<%- auditConst.auditStringClass[s.status] %>"><%- auditConst.auditString[s.status] %></span>
                     <% } %>
                     </td>
-
-                    <td class="<%- auditConst.auditProgressClass[s.status] %>">
-                        <% if (s.curAuditor) { %>
-                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- s.curAuditor.name %><%if (s.curAuditor.role !== '' && s.curAuditor.role !== null) { %>-<%- s.curAuditor.role %><% } %></a>
-                        <% } %>
-                        <%- auditConst.auditProgress[s.status] %>
-                    </td>
                 </tr>
                 <% } %>
                 </tbody>

+ 16 - 0
app/view/profile/modal.ejs

@@ -0,0 +1,16 @@
+<!--短信图示-->
+<div class="modal fade" id="sms-view" >
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">短信示例</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                图片
+            </div>
+        </div>
+    </div>
+</div>

+ 16 - 90
app/view/profile/sms.ejs

@@ -45,98 +45,24 @@
                     <div class="mt-5">
                         <h4>通知类型</h4>
                         <p class="text-muted">勾选您需要接收的短信类型。</p>
-                        <div class="form-group row">
-                            <label class="col-sm-2 col-form-label">台帐审批</label>
-                            <div class="col-sm-10">
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype1" value="option1">
-                                    <label class="form-check-label" for="smstype1">需要我审批</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype2" value="option2">
-                                    <label class="form-check-label" for="smstype2">审批通过(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype3" value="option3">
-                                    <label class="form-check-label" for="smstype3">审批通过(上报人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype4" value="option4">
-                                    <label class="form-check-label" for="smstype4">审批退回(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype5" value="option5">
-                                    <label class="form-check-label" for="smstype5">审批退回(上报人)</label>
-                                </div>
-                            </div>
-                        </div>
-                        <div class="form-group row">
-                            <label class="col-sm-2 col-form-label">计量审批</label>
-                            <div class="col-sm-10">
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype6" value="option6">
-                                    <label class="form-check-label" for="smstype6">需要我审批</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype7" value="option7">
-                                    <label class="form-check-label" for="smstype7">审批通过(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype8" value="option8">
-                                    <label class="form-check-label" for="smstype8">审批通过(上报人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype9" value="option9">
-                                    <label class="form-check-label" for="smstype9">审批退回(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype10" value="option10">
-                                    <label class="form-check-label" for="smstype10">审批退回(上报人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype11" value="option11">
-                                    <label class="form-check-label" for="smstype11">审批退回(接收人)</label>
+                        <form id="sms-form" method="post" action="/profile/sms/type">
+                            <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                            <% const user_smsType = accountData.sms_type !== '' ? JSON.parse(accountData.sms_type) : null; %>
+                            <% for (const s in smsType) { %>
+                            <div class="form-group row">
+                                <label class="col-auto col-form-label"><%= smsType[s].name %><a href="#sms-view" data-toggle="modal" data-target="#sms-view" class="ml-2"><i class="fa fa-info-circle"></i></a></label>
+                                <div class="col-5">
+                                    <% for (const c of smsType[s].children) { %>
+                                    <div class="form-check ">
+                                        <input class="form-check-input" type="checkbox" name="<%= s %>[]" value="<%= c.value %>" <% if (user_smsType !== null && user_smsType[s] !== undefined && user_smsType[s].indexOf(c.value.toString()) !== -1) { %>checked<% } %>>
+                                        <label class="form-check-label" for="<%= s %>"><%= c.title %></label>
+                                    </div>
+                                    <% } %>
                                 </div>
                             </div>
-                        </div>
-                        <div class="form-group row">
-                            <label class="col-sm-2 col-form-label">变更管理</label>
-                            <div class="col-sm-10">
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype12" value="option12">
-                                    <label class="form-check-label" for="smstype12">需要我审批</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype13" value="option13">
-                                    <label class="form-check-label" for="smstype13">审批通过(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype14" value="option14">
-                                    <label class="form-check-label" for="smstype14">审批通过(上报人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype15" value="option15">
-                                    <label class="form-check-label" for="smstype15">审批退回(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype16" value="option16">
-                                    <label class="form-check-label" for="smstype16">审批退回(上报人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype17" value="option17">
-                                    <label class="form-check-label" for="smstype17">审批退回(接收人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype18" value="option18">
-                                    <label class="form-check-label" for="smstype18">审批终止(审批人)</label>
-                                </div>
-                                <div class="form-check ">
-                                    <input class="form-check-input" type="checkbox" id="smstype19" value="option19">
-                                    <label class="form-check-label" for="smstype19">审批终止(上报人)</label>
-                                </div>
-                            </div>
-                        </div>
-                        <button type="submit" class="btn btn-primary">确认修改</button>
+                            <% } %>
+                            <button type="submit" class="btn btn-primary">确认修改</button>
+                        </form>
                     </div>
                     <% } %>
                 </div>

+ 4 - 5
app/view/sign/info.ejs

@@ -44,7 +44,7 @@
         canvas {
             flex: 1;
             cursor: crosshair;
-            border:2px dashed lightgray;
+            border:2px dashed #007bff;
         }
         .image-box {
             width: 100%;
@@ -70,8 +70,8 @@
         <div id="canvasBox" :style="getHorizontalStyle" v-show="!showBox">
             <div class="greet">
                 <span>{{msg}}</span>
-                <input type="button" value="清" @touchstart="clear" @mousedown="clear"/>
-                <input type="button" value="生成png图片" @touchstart="savePNG" @mousedown="savePNG"/>
+                <input type="button" value="清" @touchstart="clear" @mousedown="clear"/>
+                <input type="button" value="下一步 生成签名图" @touchstart="savePNG" @mousedown="savePNG"/>
             </div>
             <canvas></canvas>
         </div>
@@ -92,13 +92,12 @@
 <script>
     const id = '<%- id %>';
     const name = '<%- name %>';
-    const role = '<%- role %>';
     const csrf = '<%= ctx.csrf %>';
     new Vue({
         el: '#app',
         data() {
             return {
-                msg: '你好,' + name + (role !== '' ? '-' + role : '') + '请在下方空白处签名',
+                msg: '您好,' + name + ',请在虚线框内手写您的签名。',
                 degree: 90, // 屏幕整体旋转的角度, 可取 -90,90,180等值
                 signImage: null,
                 showBox: false,

+ 7 - 4
app/view/stage/audit_btn.ejs

@@ -1,11 +1,11 @@
 <div class="contarl-box">
     <% if (ctx.stage.status === auditConst.status.uncheck) { %>
         <% if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {%>
-            <a href="javascript: void(0);" f-target="#sub-sp" class="btn btn-primary btn-sm btn-block">上报审批</a>
+            <a href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm btn-block">上报审批</a>
         <% } %>
     <% } else if (ctx.stage.status === auditConst.status.checking) { %>
         <% if (ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId) { %>
-            <a href="javascript: void(0);" f-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
+            <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
             <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm btn-block">审批退回</a>
         <% } else { %>
             <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm btn-block">审批中</a>
@@ -15,13 +15,16 @@
     <% } else if (ctx.stage.status === auditConst.status.checkNo) { %>
         <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm btn-block text-muted">审批退回</a>
         <% if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { %>
-            <a href="javascript: void(0);" f-target="#sp-list2" class="btn btn-primary btn-sm btn-block">重新上报</a>
+            <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-list2" class="btn btn-primary btn-sm btn-block">重新上报</a>
         <% } %>
     <% } else if (ctx.stage.status === auditConst.status.checkNoPre) { %>
         <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm btn-block text-muted">审批退回</a>
         <% if (ctx.session.sessionUser.accountId === ctx.stage.curAuditor.aid) { %>
-            <a href="javascript: void(0);" f-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
+            <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
             <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm btn-block">审批退回</a>
         <% } %>
     <% } %>
+    <% if (ctx.stage.user_id === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) { %>
+        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm btn-block">重新审批</a>
+    <% } %>
 </div>

+ 57 - 26
app/view/stage/audit_modal.ejs

@@ -144,6 +144,11 @@
                                     <h5 class="card-title">
                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
                                     </h5>
+                                    <% } else if (auditors[iA].status === auditConst.status.checkAgain) { %>
+                                    <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleString() %></small> 重新审批</span>
+                                    <h5 class="card-title">
+                                        <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
+                                    </h5>
                                     <% } else { %>
                                     <h5 class="card-title">
                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
@@ -225,6 +230,11 @@
                                     <h5 class="card-title">
                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
                                     </h5>
+                                    <% } else if (auditors[iA].status === auditConst.status.checkAgain) { %>
+                                    <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleString() %></small> 重新审批</span>
+                                    <h5 class="card-title">
+                                        <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
+                                    </h5>
                                     <% } else { %>
                                     <h5 class="card-title">
                                         <i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small>
@@ -243,9 +253,10 @@
                                             <label class="form-check-label" for="inlineRadio1">退回上报 <%- ctx.stage.user.name %></label>
                                         </div>
                                         <% if (auditors[iA].order > 1 && auditors[iA].aid !== auditors[0].aid) { %>
+                                        <% const auditorIndex = ctx.stage.auditors2.findIndex(function (item) { return item.aid === auditors[iA].aid }) %>
                                         <div class="form-check form-check-inline">
                                             <input class="form-check-input" type="radio" name="checkType" id="inlineRadio2" value="<%- auditConst.status.checkNoPre %>" checked>
-                                            <label class="form-check-label" for="inlineRadio2">退回上一审批人 <%- auditors[iA-1].name %></label>
+                                            <label class="form-check-label" for="inlineRadio2">退回上一审批人 <%- ctx.stage.auditors2[auditorIndex-1].name %></label>
                                         </div>
                                         <% } %>
                                     </div>
@@ -328,7 +339,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === ah.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -339,7 +350,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -350,7 +361,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -376,7 +387,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === auditors.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -387,7 +398,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -398,7 +409,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -462,7 +473,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === ah.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -473,7 +484,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -484,7 +495,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -510,7 +521,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === auditors.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -521,7 +532,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -532,7 +543,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -595,7 +606,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === ah.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -606,7 +617,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -617,7 +628,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -684,7 +695,7 @@
                                                         <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                                     <% } %>
                                                     <h5 class="card-title"><i class="fa <%if (iA === ah.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                                         <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                                         <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                                     <% } %>
@@ -695,7 +706,7 @@
                                                         <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                                     <% } %>
                                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                                         <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                                         <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                                     <% } %>
@@ -706,7 +717,7 @@
                                                         <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                                     <% } %>
                                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                                         <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                                         <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                                     <% } %>
@@ -816,7 +827,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === ah.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -827,7 +838,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -838,7 +849,7 @@
                                     <span class="<%- auditConst.statusClass[ah[iA].status] %> pull-right"><%- auditConst.statusString[ah[iA].status]%><% if (ah[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[ah[iA].status] %>"></i> <%- ah[iA].name %> <small class="text-muted"><%- ah[iA].role %></small></h5>
-                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (ah[iA].status === auditConst.status.checked || ah[iA].status === auditConst.status.checkNo || ah[iA].status === auditConst.status.checkNoPre || ah[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- ah[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- ah[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -864,7 +875,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa <%if (iA === auditors.length - 1) { %>fa-stop-circle<% } else { %>fa-chevron-circle-down<% } %> <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -875,7 +886,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-stop-circle <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -886,7 +897,7 @@
                                     <span class="<%- auditConst.statusClass[auditors[iA].status] %> pull-right"><%- auditConst.statusString[auditors[iA].status]%><% if (auditors[iA].status === auditConst.status.checkNo) { %> <%- ctx.stage.user.name %><% } %></span>
                                     <% } %>
                                     <h5 class="card-title"><i class="fa fa-chevron-circle-down <%- auditConst.statusClass[auditors[iA].status] %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
-                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                    <% if (auditors[iA].status === auditConst.status.checked || auditors[iA].status === auditConst.status.checkNo || auditors[iA].status === auditConst.status.checkNoPre || auditors[iA].status === auditConst.status.checkAgain) { %>
                                     <p class="card-text mb-1"><%- auditors[iA].opinion %></p>
                                     <p class="card-text"><small class="text-muted"><%- auditors[iA].end_time.toLocaleDateString() %></small></p>
                                     <% } %>
@@ -1057,9 +1068,10 @@
                                             <label class="form-check-label" for="inlineRadio1">退回上报 <%- ctx.stage.user.name %></label>
                                         </div>
                                         <% if (auditors[iA].order > 1 && auditors[iA].aid !== auditors[0].aid) { %>
+                                        <% const auditorIndex = ctx.stage.auditors2.findIndex(function (item) { return item.aid === auditors[iA].aid }) %>
                                         <div class="form-check form-check-inline">
                                             <input class="form-check-input" type="radio" name="checkType" id="inlineRadio2" value="<%- auditConst.status.checkNoPre %>" checked>
-                                            <label class="form-check-label" for="inlineRadio2">退回上一审批人 <%- auditors[iA-1].name %></label>
+                                            <label class="form-check-label" for="inlineRadio2">退回上一审批人 <%- ctx.stage.auditors2[auditorIndex-1].name %></label>
                                         </div>
                                         <% } %>
                                     </div>
@@ -1100,3 +1112,22 @@
     </div>
     <% } %>
 <% } %>
+<% if (ctx.stage.user_id === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) { %>
+    <!--上报审批 需要完成中间计量-->
+    <div class="modal fade" id="sp-down-back" data-backdrop="static">
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">重新审批</h5>
+                </div>
+                <div class="modal-body">
+                    <h5>确认由「终审-<%= ctx.stage.auditors[ctx.stage.auditors.length-1].name %>」重新审批「第<%= ctx.stage.order %>期」?</h5>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                    <a href="<%- preUrl %>/audit/check/again" class="btn btn-warning">确定重审</a>
+                </div>
+            </div>
+        </div>
+    </div>
+<% } %>

+ 34 - 24
package-lock.json

@@ -446,9 +446,9 @@
       "dev": true
     },
     "ali-rds": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/ali-rds/-/ali-rds-3.0.1.tgz",
-      "integrity": "sha512-UlULx/GToDq80JwkqBI0MHzYkpSNtE2tCZFdEvmETU/jzY1Va8QdeZfWtOf66/JABcQmFHyxrF8qANlELb1BQA==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/ali-rds/-/ali-rds-3.3.0.tgz",
+      "integrity": "sha512-yPe6UR6YyjKxCQ983iFQVnetSx+9CjrfL3mWaz05yfVAzFgUCtwi6mq8HZFpDTO9LvYo6Ue5kBjheYtZjgFveQ==",
       "requires": {
         "co-wrap-all": "^1.0.0",
         "debug": "^2.2.0",
@@ -9369,44 +9369,54 @@
       "dev": true
     },
     "mysql": {
-      "version": "2.15.0",
-      "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz",
-      "integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==",
+      "version": "2.17.1",
+      "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz",
+      "integrity": "sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==",
       "requires": {
-        "bignumber.js": "4.0.4",
-        "readable-stream": "2.3.3",
-        "safe-buffer": "5.1.1",
-        "sqlstring": "2.3.0"
+        "bignumber.js": "7.2.1",
+        "readable-stream": "2.3.6",
+        "safe-buffer": "5.1.2",
+        "sqlstring": "2.3.1"
       },
       "dependencies": {
         "bignumber.js": {
-          "version": "4.0.4",
-          "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz",
-          "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg=="
+          "version": "7.2.1",
+          "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz",
+          "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ=="
         },
         "isarray": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
           "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
         },
+        "process-nextick-args": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+          "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+        },
         "readable-stream": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
-          "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
           "requires": {
             "core-util-is": "~1.0.0",
             "inherits": "~2.0.3",
             "isarray": "~1.0.0",
-            "process-nextick-args": "~1.0.6",
+            "process-nextick-args": "~2.0.0",
             "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.0.3",
+            "string_decoder": "~1.1.1",
             "util-deprecate": "~1.0.1"
           }
         },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        },
         "string_decoder": {
-          "version": "1.0.3",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
-          "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
           "requires": {
             "safe-buffer": "~5.1.0"
           }
@@ -12730,9 +12740,9 @@
       "dev": true
     },
     "sqlstring": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz",
-      "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg="
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
+      "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
     },
     "ssf": {
       "version": "0.8.2",

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
   "description": "calculation paying frontend",
   "private": true,
   "dependencies": {
+    "ali-rds": "^3.3.0",
     "bignumber.js": "^8.1.1",
     "decimal.js": "^10.2.0",
     "egg": "^1.13.0",