소스 검색

计量期,会签、或签、分组审批相关

MaiXinRong 3 달 전
부모
커밋
4eb6a991ce
7개의 변경된 파일158개의 추가작업 그리고 52개의 파일을 삭제
  1. 8 2
      app/middleware/stage_check.js
  2. 22 1
      app/service/stage.js
  3. 100 40
      app/service/stage_audit.js
  4. 4 0
      app/view/stage/audit_btn.ejs
  5. 20 7
      app/view/stage/audit_modal.ejs
  6. 2 1
      app/view/tender/detail.ejs
  7. 2 1
      app/view/tender/modal.ejs

+ 8 - 2
app/middleware/stage_check.js

@@ -160,13 +160,19 @@ module.exports = options => {
                         yield this.service.stage.defaultUpdate({ sp_group: stage.sp_group }, { where: { id: stage.id } });
                     }
                     const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.stage, sp_status: shenpi_status, sp_group: stage.sp_group };
-                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({
+                        where: condition,
+                        orders: [['audit_order', 'asc'], ['audit_group', 'ASC'], ['audit_group_order', 'ASC']]
+                    });
                     // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
                     let sameAudit = auditList.length === shenpiList.length;
                     if (sameAudit) {
                         for (const audit of auditList) {
                             const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
-                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type || shenpi.audit_ledger_id !== audit.audit_ledger_id) {
+                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type || shenpi.audit_ledger_id !== audit.audit_ledger_id
+                                || shenpi.audit_group !== audit.audit_group || shenpi.audit_group_order !== audit.audit_group_order || shenpi.audit_group_limit !== audit.audit_group_limit
+                                || shenpi.audit_group_need !== audit.audit_group_need || shenpi.audit_checkno_valid !== audit.audit_checkno_valid
+                            ) {
                                 sameAudit = false;
                                 break;
                             }

+ 22 - 1
app/service/stage.js

@@ -77,6 +77,19 @@ module.exports = app => {
             stage.auditors = await this.ctx.service.stageAudit.getAuditors(stage.id, stage.times); // 全部参与的审批人
             stage.auditorIds = this._.map(stage.auditors, 'aid');
             stage.curAuditors = stage.auditors.filter(x => { return x.status === status.checking; }); // 当前流程中审批中的审批人
+            // 分组审批时,根据受限筛选当前审批人
+            if (stage.curAuditors.length > 0 && stage.curAuditors[0].audit_type === auditConst.auditType.key.multi) {
+                const filter = [];
+                stage.curAuditors.forEach(x => {
+                    if (!x.audit_group_limit) {
+                        filter.push(x);
+                    } else {
+                        const exist = filter.find(f => { return f.audit_group === x.audit_group && f.audit_group_order < x.audit_group_order; });
+                        if (!exist) filter.push(x);
+                    }
+                });
+                stage.curAuditors = filter;
+            }
             stage.curAuditorIds = this._.map(stage.curAuditors, 'aid');
             stage.flowAuditors = stage.curAuditors.length > 0 ? stage.auditors.filter(x => { return x.order === stage.curAuditors[0].order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)
             stage.flowAuditorIds = this._.map(stage.flowAuditors, 'aid');
@@ -235,7 +248,15 @@ module.exports = app => {
                     const flowAssists = stage.auditAssists.filter(x => { return stage.flowAuditorIds.indexOf(x.user_id) >= 0; });
                     if (flowAssists.find(x => { return x.confirm; })) return; //当前流程存在协审人确认时,不可撤回
                     if (stage.curAuditorIds.indexOf(accountId) < 0 && stage.flowAuditorIds.indexOf(accountId) >= 0) {
-                        stage.cancancel = 5; // 会签/协同 未全部审批通过时,审批人撤回审批通过
+                        if (stage.curAuditors[0].audit_type === auditConst.auditType.key.multi) return; // 当前审批流程为分组审批时,不允许撤回
+                        const selfAudit = stage.flowAuditors.find(x => { return x.aid === accountId; });
+                        if (!selfAudit || selfAudit.status !== status.checked) return;
+                        if (selfAudit.audit_group_order) {
+                            const nextChecked = stage.flowAuditors.find(x => { return x.audit_group_order > selfAudit.audit_group_order && x.status === status.checked; });
+                            if (!nextChecked) stage.cancancel = 5;
+                        } else {
+                            stage.cancancel = 5; // 会签/协同 未全部审批通过时,审批人撤回审批通过(或签需要多人审批通过是亦然)
+                        }
                         return;
                     }
 

+ 100 - 40
app/service/stage_audit.js

@@ -80,6 +80,7 @@ module.exports = app => {
         async getLastestAuditor(stageId, times, status) {
             const sql =
                 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.audit_type, la.audit_order, la.audit_ledger_id,' +
+                '    la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need, ' +
                 '    la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                 '    FROM ' + this.tableName + ' AS la' +
                 '    Left Join ' + this.ctx.service.projectAccount.tableName + ' AS pa ON la.`aid` = pa.`id`' +
@@ -92,6 +93,7 @@ module.exports = app => {
         async getLastestAuditors(stageId, times, status) {
             const sql =
                 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.audit_type, la.audit_order, la.audit_ledger_id,' +
+                '    la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need, ' +
                 '    la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                 '    FROM ' + this.tableName + ' AS la' +
                 '    Left Join ' + this.ctx.service.projectAccount.tableName + ' AS pa ON la.`aid` = pa.`id`' +
@@ -113,6 +115,7 @@ module.exports = app => {
          */
         async getAuditors(stageId, times = 1, order_sort = 'asc') {
             const sql = 'SELECT la.id, la.aid, la.times, la.order, la.status, la.opinion, la.begin_time, la.end_time, la.audit_type, la.audit_order, la.audit_ledger_id,' +
+                '    la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need, ' +
                 '    pa.name, pa.company, pa.role, pa.mobile, pa.telephone, pa.sign_path' +
                 `  FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.aid = pa.id` +
                 '  WHERE la.sid = ? AND la.times = ?' +
@@ -160,7 +163,9 @@ module.exports = app => {
          */
         async getCurAuditor(stageId, times = 1) {
             const sql =
-                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order, la.audit_ledger_id ' +
+                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, ' +
+                '    la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order, la.audit_ledger_id, ' +
+                '    la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need ' +
                 '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
                 '  WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ?';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checking, times];
@@ -169,7 +174,9 @@ module.exports = app => {
 
         async getCurAuditors(stageId, times = 1) {
             const sql =
-                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order, la.audit_ledger_id ' +
+                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, ' +
+                '    la.`times`, la.`order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order, la.audit_ledger_id, ' +
+                '    la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need ' +
                 '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
                 '  WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ?';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checking, times];
@@ -449,10 +456,7 @@ module.exports = app => {
                 };
                 const records = [];
                 auditors.forEach(audit => {
-                    records.push({
-                        uid: audit.aid,
-                        ...defaultNoticeRecord,
-                    });
+                    records.push({ uid: audit.aid, ...defaultNoticeRecord });
                 });
                 this.ctx.stage.userAssists.forEach(u => {
                     records.push({ uid: u.ass_user_id, ...defaultNoticeRecord});
@@ -462,14 +466,32 @@ module.exports = app => {
                 });
                 await transaction.insert('zh_notice', records);
 
-                // 更新本人审批状态
-                await transaction.update(this.tableName, {
+                const auditUpdateData = [{
                     id: selfAudit.id,
                     status: checkData.checkType,
                     opinion: checkData.opinion,
                     end_time: time,
-                });
-                await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
+                }];
+                if (selfAudit.audit_type === auditType.key.multi || (selfAudit.audit_type === auditType.key.and && selfAudit.audit_group_order)) {
+                    const skipAudit = flowAudits.filter(x => {
+                        if (!selfAudit.audit_group_order || x.id === selfAudit.id) return false;
+                        return x.status === auditConst.status.checking && x.audit_group === selfAudit.audit_group && x.audit_group_order <= selfAudit.audit_group_order;
+                    });
+                    if (skipAudit.length > 0) skipAudit.forEach(x => { auditUpdateData.push({ id: x.id, status: auditConst.status.checkSkip, opinion: '', end_time: time }); });
+                } else if (selfAudit.audit_type === auditType.key.or) {
+                    if (flowAudits.length - audits.length + 1 >= selfAudit.audit_group_need) {
+                        for (const audit of audits) {
+                            if (audit.aid === selfAudit.aid) continue;
+                            auditUpdateData.push({ id: audit.id, status: auditConst.status.checkSkip, opinion: '', end_time: time });
+                            await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
+                        }
+                    }
+                }
+                // 更新本人审批状态
+                await transaction.updateRows(this.tableName, auditUpdateData);
+                for (const au of auditUpdateData) {
+                    await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, au.id);
+                }
                 const stageTp = {
                     contract_tp: tpData.contract_tp,
                     qc_tp: tpData.qc_tp,
@@ -479,22 +501,7 @@ module.exports = app => {
                     sf_tp: sfPay.tp,
                 };
                 this.ctx.stage.tp_history.push({ times, order: selfAudit.order, ...stageTp });
-                if (audits.length === 1 || selfAudit.audit_type === auditType.key.or) {
-                    // 或签更新他人审批状态
-                    if (selfAudit.audit_type === auditType.key.or) {
-                        const updateOther = [];
-                        for (const audit of audits) {
-                            if (audit.aid === selfAudit.aid) continue;
-                            updateOther.push({
-                                id: audit.id,
-                                status: auditConst.status.checkSkip,
-                                opinion: '',
-                                end_time: time,
-                            });
-                            await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
-                        }
-                        if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
-                    }
+                if (audits.length === auditUpdateData.length) {
                     // 无下一审核人表示,审核结束
                     if (nextAudits.length > 0) {
                         // 复制一份下一审核人数据
@@ -654,7 +661,11 @@ module.exports = app => {
                return {
                    aid: x.aid, tid: selfAudit.tid, sid: selfAudit.sid,
                    times: times + 1, order: x.audit_order, status: auditConst.status.uncheck,
-                   audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                   audit_type: x.audit_type, audit_order: x.audit_order,
+                   audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                   audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                   audit_group_need: x.audit_group_need,
+                   audit_ledger_id: x.audit_ledger_id,
                }
             });
 
@@ -865,6 +876,9 @@ module.exports = app => {
                         times: x.times, order: selfAudit.order + 1,
                         status: auditConst.status.checking, begin_time: time,
                         audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
                         audit_ledger_id: x.audit_ledger_id,
                     });
                 });
@@ -881,6 +895,9 @@ module.exports = app => {
                         times: x.times, order: selfAudit.order + 2,
                         status: auditConst.status.uncheck,
                         audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
                         audit_ledger_id: x.audit_ledger_id,
                     });
                 });
@@ -1023,7 +1040,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 1,
                         status: !selfAudit || x.aid === selfAudit.aid ? auditConst.status.checkAgain : auditConst.status.checkSkip,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 audits.forEach(x => {
@@ -1032,7 +1053,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 2,
                         status: auditConst.status.checking,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 await transaction.insert(this.tableName, checkAgainAuditors);
@@ -1244,7 +1269,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 1,
                         status: x.aid === selfAuditor.aid ? auditConst.status.checkCancel : auditConst.status.checkSkip,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 stage.preAuditors.forEach(x => {
@@ -1253,7 +1282,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 2,
                         status: auditConst.status.checking,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
@@ -1346,7 +1379,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 1,
                         status: x.aid === selfAuditor.aid ? auditConst.status.checkCancel : auditConst.status.checkSkip,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 await transaction.insert(this.tableName, newAuditors);
@@ -1437,7 +1474,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 1,
                         status: x.aid === selfAuditor.aid ? auditConst.status.checkCancel : auditConst.status.checkSkip,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 stage.preAuditors.forEach(x => {
@@ -1446,7 +1487,11 @@ module.exports = app => {
                         times: x.times, order: x.order + 2,
                         status: auditConst.status.checking,
                         begin_time: time, end_time: time, opinion: '',
-                        audit_type: x.audit_type, audit_order: x.audit_order, audit_ledger_id: x.audit_ledger_id,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                        audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                        audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                        audit_group_need: x.audit_group_need,
+                        audit_ledger_id: x.audit_ledger_id,
                     });
                 });
                 await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
@@ -1717,7 +1762,8 @@ module.exports = app => {
             //     '  WHERE la.`sid` = ? and la.`times` = ? and la.`is_old` = 0 GROUP BY la.`aid` ORDER BY la.`order`';
             // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times];
             const sql =
-                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_type, la.audit_order, la.audit_ledger_id' +
+                'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_type, la.audit_order, ' +
+                '  la.audit_group, la.audit_group_order, la.audit_group_limit, la.audit_group_need, la.audit_checkno_valid, la.audit_ledger_id ' +
                 ' FROM (SELECT `aid`, max(`order`) `order` FROM ?? WHERE `sid` = ? and `times` = ? and `is_old` = ? GROUP BY aid) sa' +
                 ' LEFT JOIN ?? la ON sa.`aid` = la.`aid` AND sa.`order` = la.`order`' +
                 ' Left JOIN ?? AS pa On la.`aid` = pa.`id` WHERE la.`sid` = ? and la.`times` = ? and la.`is_old` = ? order BY la.`order`';
@@ -1766,7 +1812,12 @@ module.exports = app => {
                     status: auditConst.status.uncheck,
                     audit_type: a.audit_type,
                     audit_order: a.audit_order,
-                    audit_ledger_id: a.audit_ledger_id,
+                    audit_group: a.audit_group,
+                    audit_group_order: a.audit_group_order,
+                    audit_group_limit: a.audit_group_limit,
+                    audit_group_need: a.audit_group_need,
+                    audit_checkno_valid: a.audit_checkno_valid,
+                    audit_ledger_id: a.audit_ledger_id || '',
                 };
                 newAuditors.push(na);
             }
@@ -1794,14 +1845,16 @@ module.exports = app => {
                 case auditConst.status.checking:
                 case auditConst.status.checked:
                 case auditConst.status.checkNoPre:
-                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order` ' +
+                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.audit_order, la.audit_type, la.audit_group, la.audit_group_order,' +
+                          '    la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need, la.audit_ledger_id ' +
                           '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                           '  WHERE la.`sid` = ? and la.`status` = ? order by la.`times` desc, la.`order` desc';
                     sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, status];
                     auditor = await this.db.queryOne(sql, sqlParam);
                     break;
                 case auditConst.status.checkNo:
-                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order` ' +
+                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.audit_order, la.audit_type, la.audit_group, la.audit_group_order, ' +
+                        '    la.audit_group_limit, la.audit_checkno_valid, la.audit_group_need, la.audit_ledger_id ' +
                           '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                           '  WHERE la.`sid` = ? and la.`status` = ? and la.`times` = ? order by la.`times` desc, la.`order` desc';
                     sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, auditConst.status.checkNo, parseInt(times) - 1];
@@ -1826,7 +1879,8 @@ module.exports = app => {
                     cur = await this.db.queryOne(`SELECT * From ${this.tableName} where sid = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`order` DESC', [stageId, times, status]);
                     if (!cur) return [];
 
-                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_order, la.audit_type, la.audit_ledger_id ' +
+                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_order, la.audit_type, la.audit_group, la.audit_group_order, ' +
+                        '    la.audit_group_limit, la.audit_group_need, la.audit_checkno_valid, la.audit_ledger_id ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                         '  WHERE la.`sid` = ? and la.`order` = ? and times = ?';
                     sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, cur.order, times];
@@ -1836,7 +1890,8 @@ module.exports = app => {
                     cur = await this.db.queryOne(`SELECT * From ${this.tableName} where sid = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`order` DESC', [stageId, parseInt(times) - 1, status]);
                     if (!cur) return [];
 
-                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_order, la.audit_type, la.audit_ledger_id ' +
+                    sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`order`, la.`status`, la.audit_order, la.audit_type, la.audit_group, la.audit_group_order, ' +
+                        '    la.audit_group_limit, la.audit_group_need, la.audit_checkno_valid, la.audit_ledger_id ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                         '  WHERE la.`sid` = ? and la.`order` = ? and la.`times` = ?';
                     sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, cur.order, parseInt(times) - 1];
@@ -2022,6 +2077,11 @@ module.exports = app => {
                         times: stage.times, order: auditor.audit_order, status: auditConst.status.uncheck,
                         audit_type: auditor.audit_type, audit_order: auditor.audit_order,
                         audit_ledger_id: auditor.audit_type === auditType.key.union ? auditor.audit_ledger_id : '',
+                        audit_group: auditor.audit_type === auditType.key.multi ? auditor.audit_group : '',
+                        audit_group_order: auditor.audit_type === auditType.key.multi || auditor.audit_type === auditType.key.and ? auditor.audit_group_order : 0,
+                        audit_group_limit : auditor.audit_type === auditType.key.multi ? auditor.audit_group_limit : 0,
+                        audit_group_need: auditor.audit_type === auditType.key.or ? auditor.audit_group_need : 1,
+                        audit_checkno_valid: auditor.audit_type === auditType.key.multi || auditor.audit_type === auditType.key.and ? auditor.audit_checkno_valid : 1,
                     });
                 }
                 if(newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);

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

@@ -18,7 +18,9 @@
     <% } else if (ctx.stage.status === auditConst.status.checking) { %>
         <% if (ctx.stage.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
             <a id="sp-done-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
+            <% if (ctx.stage.relaAuditor.audit_checkno_valid) { %>
             <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>
         <% } %>
@@ -38,7 +40,9 @@
         <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.stage.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
             <a id="sp-done-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm btn-block">审批通过</a>
+            <% if (ctx.stage.relaAuditor.audit_checkno_valid) { %>
             <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm btn-block">审批退回</a>
+            <% } %>
         <% } %>
     <% } %>
     <% if (ctx.stage.auditors !== undefined && ctx.stage.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0 && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) { %>

+ 20 - 7
app/view/stage/audit_modal.ejs

@@ -58,7 +58,11 @@
                                 <li class="list-group-item d-flex" auditorId="<%- ctx.stage.auditorGroups[i][0].aid %>">
                                     <div class="col-auto"><%- i+1 %></div>
                                     <div class="col">
-                                        <% for (const auditor of ctx.stage.auditorGroups[i]) { %>
+                                        <% for (const [ia, auditor] of ctx.stage.auditorGroups[i].entries()) { %>
+                                            <% if (ia === 0 || (ia > 0 && auditor.audit_group !== ctx.stage.auditorGroups[i][ia-1].audit_group)) { %>
+                                                <% if (ia !== 0) { %><br/><% } %>
+                                                <% if (auditor.audit_type === auditType.key.multi && auditor.audit_group) { %><div class="d-inline-block mr-2"><%- auditor.audit_group %></div> <% } %>
+                                            <% } %>
                                         <div class="d-inline-block mx-1" auditorId="<%- auditor.aid %>">
                                             <i class="fa fa-user text-muted"></i> <%- auditor.name %> <small class="text-muted"><%- auditor.role %></small>
                                         </div>
@@ -126,7 +130,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa fa-stop-circle"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -141,7 +146,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa-chevron-circle-down"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -239,6 +245,7 @@
                                                         <% for (const [i, auditor] of group.auditors.entries()) { %>
                                                         <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
                                                             <div class="col-10">
+                                                                <% if (auditor.audit_type === auditType.key.multi) { %><span class="mr-2"><%- auditor.audit_group %></span><% } %>
                                                                 <span class="h6"><%- auditor.name %></span>
                                                                 <span class="text-muted ml-1"><%- auditor.company %>
                                                                 <% if (auditor.role) { %>
@@ -314,7 +321,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa fa-stop-circle"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -329,7 +337,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa-chevron-circle-down"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -427,6 +436,7 @@
                                                     <% for (const [i, auditor] of group.auditors.entries()) { %>
                                                     <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
                                                         <div class="col-10">
+                                                            <% if (auditor.audit_type === auditType.key.multi) { %><span class="mr-2"><%- auditor.audit_group %></span><% } %>
                                                             <span class="h6"><%- auditor.name %></span>
                                                             <span class="text-muted ml-1"><%- auditor.company %>
                                                             <% if (auditor.role) { %>
@@ -505,7 +515,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa fa-stop-circle"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -520,7 +531,8 @@
                                     <li class="list-group-item d-flex justify-content-between align-items-center">
                                         <span class="mr-1"><i class="fa fa-chevron-circle-down"></i></span>
                                         <span class="text-muted">
-                                            <% for (const u of item) { %>
+                                            <% for (const [iu, u] of item.entries()) { %>
+                                            <% if ((iu > 0 && u.audit_group !== item[iu-1].audit_group)) { %><br/><% } %>
                                             <small class="d-inline-block text-dark mx-1" title="<%- u.company %>" data-auditorId="<%- u.aid %>"><%- u.name %></small>
                                             <% } %>
                                         </span>
@@ -617,6 +629,7 @@
                                                     <% for (const [i, auditor] of group.auditors.entries()) { %>
                                                     <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
                                                         <div class="col-10">
+                                                            <% if (auditor.audit_type === auditType.key.multi) { %><span class="mr-2"><%- auditor.audit_group %></span><% } %>
                                                             <span class="h6"><%- auditor.name %></span>
                                                             <span class="text-muted ml-1"><%- auditor.company %>
                                                             <% if (auditor.role) { %>

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

@@ -1267,7 +1267,8 @@
                     historyHTML.push(`<div class="card ${darkHTML}"><div class="card-body px-3 py-0">`);
                     for (const [i, auditor] of group.auditors.entries()) {
                         historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
-                        historyHTML.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
+                        const auditGroupName = (auditor.audit_type === auditType.key.multi) ? `<span class="mr-2">${auditor.audit_group}</span>` : '';
+                        historyHTML.push(`<div class="col">${auditGroupName}<span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
                         historyHTML.push('<div class="col">');
                         if (auditor.status === auditConst.status.checked) {
                             historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');

+ 2 - 1
app/view/tender/modal.ejs

@@ -198,7 +198,8 @@
                     historyHTML.push('<div class="card"><div class="card-body px-3 py-0">');
                     for (const [i, auditor] of group.auditors.entries()) {
                         historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
-                        historyHTML.push(`<div class="col-10"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.company}${auditor.role ? ' - ' + auditor.role : ''}</span></div>`);
+                        const auditGroupName = (auditor.audit_type === auditType.key.multi) ? `<span class="mr-2">${auditor.audit_group}</span>` : '';
+                        historyHTML.push(`<div class="col-10">${auditGroupName}<span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.company}${auditor.role ? ' - ' + auditor.role : ''}</span></div>`);
                         historyHTML.push('<div class="col">');
                         if (auditor.status === auditConst2.status.checked) {
                             historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');