فهرست منبع

台账审批,支持会签或签

MaiXinRong 9 ماه پیش
والد
کامیت
6c4f15d802

+ 11 - 19
app/controller/ledger_controller.js

@@ -98,19 +98,10 @@ module.exports = app => {
                 const tender = ctx.tender;
                 const [ledgerSpread, posSpread] = await spreadSetting.getLedgerSpreadSetting(ctx, tender.id,
                     this._ledgerReadOnly(tender.data));
-                const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
 
-                const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(tender.id, tender.data.ledger_times);
-                const auditors = tender.data.ledger_status === auditConst.status.checkNo && tender.data.user_id !== ctx.session.sessionUser.accountId && !ctx.tender.isTourist ?
-                    await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, times) :
-                    await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, tender.data.ledger_times);
-                const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id);
-                const auditHistory = [];
-                if (times >= 1) {
-                    for (let i = 1; i <= times; i++) {
-                        auditHistory.push(await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, i));
-                    }
-                }
+                await ctx.service.ledgerAudit.loadLedgerUser(tender.data);
+                await ctx.service.ledgerAudit.loadLedgerAuditViewData(tender.data);
+
                 const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
                     ctx.tender.data.valuation, ctx.tender.data.measure_type);
 
@@ -135,12 +126,13 @@ module.exports = app => {
                     tender: tender.data,
                     tenderInfo: tender.info,
                     auditConst,
-                    auditors,
-                    curAuditor,
-                    user,
+                    auditType: audit.auditType,
+                    auditors: tender.data.auditors,
+                    curAuditors: tender.data.curAuditors,
+                    auditHistory: tender.data.auditHistory,
+                    user: tender.data.user,
                     attData,
                     whiteList,
-                    auditHistory,
                     ledgerSpreadSetting: JSON.stringify(ledgerSpread),
                     posSpreadSetting: JSON.stringify(posSpread),
                     tenderMenu,
@@ -149,7 +141,7 @@ module.exports = app => {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.explode),
                     stdBills,
                     stdChapters,
-                    dealBillsPermission: this._canUpdateDealBills(tender.data, auditors.filter(x => {return x.audit_order > 0})),
+                    dealBillsPermission: this._canUpdateDealBills(tender.data, tender.data.auditors),
                     shenpiConst,
                     categoryData,
                     syncLedgerUrl: syncLedger ? `${ctx.app.config.url3f}/${syncLedger.pull_class}/sync-tz/${tender.id}` : '',
@@ -157,8 +149,8 @@ module.exports = app => {
                     authMobile: pa.auth_mobile,
                     deleteFilePermission: PermissionCheck.delFile(this.ctx.session.sessionUser.permission),
                 };
-                if ((tender.data.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) || ((tender.data.ledger_status === auditConst.status.uncheck || tender.data.ledger_status === auditConst.status.checkNo) && tender.data.user_id === ctx.session.sessionUser.accountId)) {
-                    // renderData.accountGroup = accountGroup;
+                if ((tender.data.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) ||
+                    ((tender.data.ledger_status === auditConst.status.uncheck || tender.data.ledger_status === auditConst.status.checkNo) && tender.data.user_id === ctx.session.sessionUser.accountId)) {
                     // 获取所有项目参与者
                     const accountList = await ctx.service.projectAccount.getAllDataByCondition({
                         where: { project_id: ctx.session.sessionProject.id, enable: 1 },

+ 38 - 35
app/middleware/ledger_audit_check.js

@@ -12,6 +12,42 @@ const status = require('../const/audit').ledger.status;
 const shenpiConst = require('../const/shenpi');
 const _ = require('lodash');
 
+const checkAuditFlow = async function(ctx) {
+    const tender = ctx.tender.data;
+    const info = ctx.tender.info;
+    if (info.shenpi.ledger === shenpiConst.sp_status.sqspr) return;
+    if (tender.ledger_status !== status.uncheck && tender.ledger_status !== status.checkNo) return;
+
+    const shenpi_status = info.shenpi.ledger;
+    // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
+    const auditList = await ctx.service.ledgerAudit.getAuditors(tender.id, tender.times);
+    if (shenpi_status === shenpiConst.sp_status.gdspl) {
+        const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });
+        // 判断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.audit_id; });
+                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type || shenpi.audit_ledger_id !== audit.audit_ledger_id) {
+                    sameAudit = false;
+                    break;
+                }
+            }
+        }
+        if (!sameAudit) await ctx.service.ledgerAudit.updateNewAuditList(tender, shenpiList);
+    } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
+        const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status });
+        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+        const lastAuditors = auditList.filter(x => { x.order === auditList.order; });
+        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {
+            await ctx.service.ledgerAudit.updateLastAudit(tender, auditList, shenpiInfo.audit_id);
+        } else if (!shenpiInfo) {
+            // 不存在终审人的状态下这里恢复为授权审批人
+            info.shenpi.ledger = shenpiConst.sp_status.sqspr;
+        }
+    }
+};
+
 module.exports = options => {
     /**
      * 标段校验 中间件
@@ -23,43 +59,10 @@ module.exports = options => {
      */
     return function* ledgerAuditCheck(next) {
         try {
-            if ((this.tender.data.ledger_status === status.uncheck || this.tender.data.ledger_status === status.checkNo) && this.tender.info.shenpi.ledger !== shenpiConst.sp_status.sqspr) {
-                const shenpi_status = this.tender.info.shenpi.ledger;
-                // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.ledgerAudit.getAllDataByCondition({ where: { tender_id: this.tender.id, times: this.tender.data.ledger_times }, orders: [['audit_order', 'asc']] });
-                const auditIdList = _.map(auditList, 'audit_id');
-                if (shenpi_status === shenpiConst.sp_status.gdspl) {
-                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status } });
-                    const shenpiIdList = _.map(shenpiList, 'audit_id');
-                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    if (!_.isEqual(auditIdList, shenpiIdList)) {
-                        yield this.service.ledgerAudit.updateNewAuditList(this.tender.data, shenpiIdList);
-                    }
-                } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
-                    const shenpiInfo = yield this.service.shenpiAudit.getDataByCondition({ tid: this.tender.id, sp_type: shenpiConst.sp_type.ledger, sp_status: shenpi_status });
-                    // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
-                    if (shenpiInfo && shenpiInfo.audit_id !== _.last(auditIdList)) {
-                        yield this.service.ledgerAudit.updateLastAudit(this.tender.data, auditList, shenpiInfo.audit_id);
-                    } else if (!shenpiInfo) {
-                        // 不存在终审人的状态下这里恢复为授权审批人
-                        this.tender.info.shenpi.ledger = shenpiConst.sp_status.sqspr;
-                    }
-                }
-            }
+            yield checkAuditFlow(this);
             yield next;
         } catch (err) {
-            console.log(err);
-            // 输出错误到日志
-            if (err.stack) {
-                this.logger.error(err);
-            } else {
-                this.getLogger('fail').info(JSON.stringify({
-                    error: err,
-                    project: this.session.sessionProject,
-                    user: this.session.sessionUser,
-                    body: this.session.body,
-                }));
-            }
+            this.log(err);
             // 重定向值标段管理
             this.redirect(this.request.headers.referer);
         }

+ 355 - 188
app/service/ledger_audit.js

@@ -9,6 +9,7 @@
  */
 
 const auditConst = require('../const/audit').ledger;
+const auditType = require('../const/audit').auditType;
 const smsTypeConst = require('../const/sms_type');
 const SMS = require('../lib/sms');
 const SmsAliConst = require('../const/sms_alitemplate');
@@ -30,6 +31,7 @@ module.exports = app => {
             this.tableName = 'ledger_audit';
         }
 
+
         /**
          * 获取标段审核人信息
          *
@@ -39,7 +41,7 @@ module.exports = app => {
          * @return {Promise<*>}
          */
         async getAuditor(tenderId, auditorId, times = 1) {
-            const sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+            const sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`audit_type`, la.`audit_ledger_id`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                 '  FROM ?? AS la Left Join ?? AS pa ON la.`audit_id` = pa.`id`' +
                 '  WHERE la.`tender_id` = ? and la.`audit_id` = ? and la.`times` = ?';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditorId, times];
@@ -47,17 +49,29 @@ module.exports = app => {
         }
 
         async getAuditorByOrder(tenderId, order, times = 1) {
-            const sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+            const sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`audit_type`, la.`audit_ledger_id`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
                 '  FROM ?? AS la Left Join ?? AS pa ON la.`audit_id` = pa.`id`' +
                 '  WHERE la.`tender_id` = ? and la.`audit_order` = ? and la.`times` = ?';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, order, times];
             return await this.db.queryOne(sql, sqlParam);
         }
 
+        async getAuditorsByOrder(tenderId, order, times) {
+            const sql =
+                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`,' +
+                '    la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_ledger_id ' +
+                '    FROM ' + this.tableName + ' AS la' +
+                '    Left Join ' + this.ctx.service.projectAccount.tableName + ' AS pa ON la.`audit_id` = pa.`id`' +
+                '  WHERE la.`tender_id` = ? and la.`audit_order` = ? and la.`times` = ?' +
+                '  ORDER BY `audit_order` DESC';
+            const sqlParam = [tenderId, order, times ? times: 1];
+            return await this.db.query(sql, sqlParam);
+        }
+
         async getLastestAuditor(tenderId, times, status) {
             const sql =
                 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`,' +
-                '    la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+                '    la.`times`, la.`audit_order`, la.`audit_type`, la.`audit_ledger_id`, 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.`audit_id` = pa.`id`' +
                 '  WHERE la.`tender_id` = ? and la.`status` = ? and la.`times` = ?' +
@@ -66,44 +80,239 @@ module.exports = app => {
             return await this.db.queryOne(sql, sqlParam);
         }
 
+        async getLastestAuditors(tenderId, times, status) {
+            const sql =
+                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.audit_type, la.audit_order, la.audit_ledger_id,' +
+                '    la.`times`, la.`audit_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.`audit_id` = pa.`id`' +
+                '  WHERE la.`tender_id` = ? and la.`status` = ? and la.`times` = ?' +
+                '  ORDER BY `audit_order` DESC';
+            const sqlParam = [tenderId, status, times ? times: 1];
+            const result = await this.db.query(sql, sqlParam);
+            if (result.length === 0) return [];
+            return result.filter(x => { return x.audit_order === result[0].audit_order });
+        }
+
         /**
-         * 获取标段审核人最后一位的名称
+         * 获取标段审核列表信息
          *
          * @param {Number} tenderId - 标段id
-         * @param {Number} auditorId - 审核人id
          * @param {Number} times - 第几次审批
          * @return {Promise<*>}
          */
-        async getStatusName(tenderId, times) {
-            const sql = 'SELECT pa.`name` FROM ?? AS la Left Join ?? AS pa ON la.`audit_id` = pa.`id`' +
-                '  WHERE la.`tender_id` = ? and la.`status` != ? ORDER BY la.`times` DESC, la.`audit_order` DESC';
-            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditConst.status.uncheck];
-            return await this.db.queryOne(sql, sqlParam);
+        async getAuditors(tenderId, times = 1, order_sort = 'asc') {
+            const sql = 'SELECT la.id, la.audit_id, la.times, la.audit_order, la.audit_type, la.audit_ledger_id, la.status, la.opinion, la.begin_time, la.end_time, ' +
+                '    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.audit_id = pa.id` +
+                '  WHERE la.tender_id = ? AND la.times = ?' +
+                '  ORDER BY la.audit_order ' + order_sort;
+            const sqlParam = [tenderId, times];
+            const result = await this.db.query(sql, sqlParam);
+            const max_sort = this._.max(result.map(x => { return x.audit_order; }));
+            for (const i in result) {
+                result[i].max_sort = max_sort;
+            }
+            return result;
         }
 
         /**
-         * 获取标段审核列表信息
+         * 获取标段当前审核人
          *
          * @param {Number} tenderId - 标段id
          * @param {Number} times - 第几次审批
          * @return {Promise<*>}
          */
-        async getAuditors(tenderId, times = 1) {
+        async getCurAuditor(tenderId, times = 1) {
             const sql =
-                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, g.`sort` ' +
-                'FROM ?? AS la, ?? AS pa, (SELECT t1.`audit_id`,(@i:=@i+1) as `sort` FROM (SELECT t.`audit_id`, t.`audit_order` FROM (select `audit_id`, `audit_order` from ?? WHERE `tender_id` = ? AND `times` = ? ORDER BY `audit_order` LIMIT 200) t GROUP BY t.`audit_id` ORDER BY t.`audit_order`) t1, (select @i:=0) as it) as g ' +
-                'WHERE la.`tender_id` = ? and la.`times` = ? and la.`audit_id` = pa.`id` and g.`audit_id` = la.`audit_id` order by la.`audit_order`';
-            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, tenderId, times, tenderId, times];
-            const result = await this.db.query(sql, sqlParam);
-            const sql2 = 'SELECT COUNT(a.`audit_id`) as num FROM (SELECT `audit_id` FROM ?? WHERE `tender_id` = ? AND `times` = ? GROUP BY `audit_id`) as a';
-            const sqlParam2 = [this.tableName, tenderId, times];
-            const count = await this.db.queryOne(sql2, sqlParam2);
-            for (const i in result) {
-                result[i].max_sort = count.num;
+                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`audit_type`, la.`audit_ledger_id`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
+                '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id`' +
+                '  WHERE la.`tender_id` = ? and la.`status` = ? and la.`times` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditConst.status.checking, times];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        async getCurAuditors(tenderId, times = 1) {
+            const sql =
+                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`, la.audit_type, la.audit_order, la.audit_ledger_id ' +
+                '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id`' +
+                '  WHERE la.`tender_id` = ? and la.`status` = ? and la.`times` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditConst.status.checking, times];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        async getAuditorGroup(tenderId, times) {
+            const auditors = await this.getAuditors(tenderId, times); // 全部参与的审批人
+            return this.ctx.helper.groupAuditors(auditors, 'audit_order');
+        }
+
+        async getUserGroup(tenderId, times) {
+            const group = await this.getAuditorGroup(tenderId, times);
+            const sql =
+                'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As tender_id, 0 As audit_order, 1 As audit_type' +
+                '  FROM ' + this.ctx.service.tender.tableName + ' As t' +
+                '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
+                '  ON t.user_id = pa.id' +
+                '  WHERE t.id = ?';
+            const sqlParam = [times, tenderId, tenderId];
+            const user = await this.db.queryOne(sql, sqlParam);
+            group.unshift([ user ]);
+            return group;
+        }
+
+        async getUniqUserGroup(tenderId, times) {
+            const group = await this.getAuditorGroup(tenderId, times);
+            const sql =
+                'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As tender_id, 0 As audit_order, 1 As audit_type' +
+                '  FROM ' + this.ctx.service.tender.tableName + ' As t' +
+                '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
+                '  ON t.user_id = pa.id' +
+                '  WHERE t.id = ?';
+            const sqlParam = [times, tenderId, tenderId];
+            const user = await this.db.queryOne(sql, sqlParam);
+            group.unshift([ user ]);
+            return this.ctx.helper.groupAuditorsUniq(group, 'audit_order');
+        }
+
+        async getAuditorHistory(tenderId, times, reverse = false) {
+            const history = [];
+            if (times >= 1) {
+                for (let i = 1; i <= times; i++) {
+                    const auditors = await this.getAuditors(tenderId, i);
+                    const group = this.ctx.helper.groupAuditors(auditors, 'audit_order');
+                    const historyGroup = [];
+                    const max_order = group.length > 0 && group[group.length - 1].length > 0 ? group[group.length - 1][0].audit_order : -1;
+                    for (const g of group) {
+                        const his = {
+                            beginYear: '', beginDate: '', beginTime: '', endYear: '', endDate: '', endTime: '', begin_time: null, end_time: null,
+                            audit_type: g[0].audit_type, audit_order: g[0].audit_order,
+                            auditors: g
+                        };
+                        if (his.audit_type === auditType.key.common) {
+                            his.name = g[0].name;
+                        } else {
+                            his.name = this.ctx.helper.transFormToChinese(his.audit_order) + '审';
+                        }
+                        his.is_final = his.audit_order === max_order;
+                        if (g[0].begin_time) {
+                            his.begin_time = g[0].begin_time;
+                            const beginTime = this.ctx.moment(g[0].begin_time);
+                            his.beginYear = beginTime.format('YYYY');
+                            his.beginDate = beginTime.format('MM-DD');
+                            his.beginTime = beginTime.format('HH:mm:ss');
+                        }
+                        let end_time;
+                        g.forEach(x => {
+                            if (x.status === auditConst.status.checkSkip) return;
+                            if (!his.status || x.status === auditConst.status.checking) his.status = x.status;
+                            if (x.end_time && (!end_time || x.end_time > end_time)) {
+                                end_time = x.end_time;
+                                if (his.status !== auditConst.status.checking) his.status = x.status;
+                            }
+                        });
+                        if (end_time) {
+                            his.end_time = end_time;
+                            const endTime = this.ctx.moment(end_time);
+                            his.endYear = endTime.format('YYYY');
+                            his.endDate = endTime.format('MM-DD');
+                            his.endTime = endTime.format('HH:mm:ss');
+                        }
+                        historyGroup.push(his);
+                    }
+                    if (reverse) {
+                        history.push(historyGroup.reverse());
+                    } else {
+                        history.push(historyGroup);
+                    }
+                }
             }
+            return history;
+        }
+
+        async getUniqAuditor(tenderId, times) {
+            const auditors = await this.getAuditors(tenderId, times); // 全部参与的审批人
+            const result = [];
+            auditors.forEach(x => {
+                if (result.findIndex(r => { return x.audit_id === r.audit_id && x.audit_order === r.audit_order; }) < 0) {
+                    result.push(x);
+                }
+            });
             return result;
         }
 
+        async loadLedgerUser(tender) {
+            const status = auditConst.status;
+            const accountId = this.ctx.session.sessionUser.accountId;
+
+            tender.user = await this.ctx.service.projectAccount.getAccountInfoById(tender.user_id);
+            tender.auditors = await this.getAuditors(tender.id, tender.ledger_times); // 全部参与的审批人
+            tender.auditorIds = this._.map(tender.auditors, 'audit_id');
+            tender.curAuditors = tender.auditors.filter(x => { return x.status === status.checking; }); // 当前流程中审批中的审批人
+            tender.curAuditorIds = this._.map(tender.curAuditors, 'audit_id');
+            tender.flowAuditors = tender.curAuditors.length > 0 ? tender.auditors.filter(x => { return x.audit_order === tender.curAuditors[0].audit_order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)
+            tender.flowAuditorIds = this._.map(tender.flowAuditors, 'audit_id');
+            tender.nextAuditors = tender.curAuditors.length > 0 ? tender.auditors.filter(x => { return x.audit_order === tender.curAuditors[0].audit_order + 1; }) : [];
+            tender.nextAuditorIds = this._.map(tender.nextAuditors, 'audit_id');
+            tender.auditorGroups = this.ctx.helper.groupAuditors(tender.auditors, 'audit_order');
+            tender.userGroups = this.ctx.helper.groupAuditorsUniq(tender.auditorGroups);
+            tender.userGroups.unshift([{
+                aid: tender.user.id, order: 0, times: tender.ledger_times, audit_order: 0, audit_type: auditType.key.common,
+                name: tender.user.name, role: tender.user.role, company: tender.user.company
+            }]);
+            tender.finalAuditorIds = tender.userGroups[tender.userGroups.length - 1].map(x => { return x.aid; });
+            tender.relaAuditor = tender.auditors.find(x => { return x.aid === accountId });
+
+            tender.assists = [];// await this.service.ledgerAuditAss.getData(tender); // 全部协同人
+            tender.assists = tender.assists.filter(x => {
+                return x.user_id === tender.user_id || tender.auditorIds.indexOf(x.user_id) >= 0;
+            }); // 过滤无效协同人
+            tender.userAssists = tender.assists.filter(x => { return x.user_id === tender.user_id; }); // 原报协同人
+            tender.userAssistIds = this._.map(tender.userAssists, 'ass_user_id');
+            tender.auditAssists = tender.assists.filter(x => { return x.user_id !== tender.user_id; }); // 审批协同人
+            tender.auditAssistIds = this._.map(tender.auditAssists, 'ass_user_id');
+            tender.relaAssists = tender.assists.filter(x => { return x.user_id === accountId }); // 登录人的协同人
+            tender.userIds = tender.status === status.uncheck // 当前流程下全部参与人id
+                ? [tender.user_id]
+                : [tender.user_id, ...tender.userAssistIds, ...tender.auditorIds, ...tender.auditAssistIds];
+        }
+
+        async loadLedgerAuditViewData(tender) {
+            const times = tender.ledger_status === auditConst.status.checkNo ? tender.ledger_times - 1 : tender.ledger_times;
+
+            if (!tender.user) tender.user = await this.ctx.service.projectAccount.getAccountInfoById(tender.user_id);
+            tender.auditHistory = await this.getAuditorHistory(tender.id, times);
+            // 获取审批流程中左边列表
+            if (tender.status === auditConst.status.checkNo && tender.user_id !== this.ctx.session.sessionUser.accountId) {
+                const auditors = await this.getAuditors(tender.id, times); // 全部参与的审批人
+                const auditorGroups = this.ctx.helper.groupAuditors(auditors, 'audit_order');
+                tender.auditors2 = this.ctx.helper.groupAuditorsUniq(auditorGroups, 'audit_order');
+                tender.auditors2.unshift([{
+                    aid: tender.user.id, order: 0, times: tender.ledger_times - 1, audit_order: 0, audit_type: auditConst.auditType.key.common,
+                    name: tender.user.name, role: tender.user.role, company: tender.user.company
+                }]);
+            } else {
+                tender.auditors2 = tender.userGroups;
+            }
+            if (tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) {
+                tender.auditorList = await this.getAuditors(tender.id, tender.ledger_times);
+            }
+        }
+
+        /**
+         * 获取标段审核人最后一位的名称
+         *
+         * @param {Number} tenderId - 标段id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @return {Promise<*>}
+         */
+        async getStatusName(tenderId, times) {
+            const sql = 'SELECT pa.`name` FROM ?? AS la Left Join ?? AS pa ON la.`audit_id` = pa.`id`' +
+                '  WHERE la.`tender_id` = ? and la.`status` != ? ORDER BY la.`times` DESC, la.`audit_order` DESC';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditConst.status.uncheck];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
         async getFinalAuditGroup(tenderId, times = 1) {
             const sql =
                 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, pa.`sign_path`, la.`times`, la.`tender_id`, Max(la.`audit_order`) as max_order ' +
@@ -122,22 +331,6 @@ module.exports = app => {
         }
 
         /**
-         * 获取标段当前审核人
-         *
-         * @param {Number} tenderId - 标段id
-         * @param {Number} times - 第几次审批
-         * @return {Promise<*>}
-         */
-        async getCurAuditor(tenderId, times = 1) {
-            const sql =
-                'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time` ' +
-                '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id`' +
-                '  WHERE la.`tender_id` = ? and la.`status` = ? and la.`times` = ?';
-            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, auditConst.status.checking, times];
-            return await this.db.queryOne(sql, sqlParam);
-        }
-
-        /**
          * 获取最新审核顺序
          *
          * @param {Number} tenderId - 标段id
@@ -172,6 +365,7 @@ module.exports = app => {
                     times,
                     audit_order: newOrder,
                     status: auditConst.status.uncheck,
+                    audit_type: 0,
                 };
                 const result = await transaction.insert(this.tableName, data);
                 await transaction.commit();
@@ -250,8 +444,8 @@ module.exports = app => {
          * @return {Promise<boolean>}
          */
         async start(tenderId, times = 1) {
-            const audit = await this.getDataByCondition({ tender_id: tenderId, times, audit_order: 1 });
-            if (!audit) {
+            const audits = await this.getAllDataByCondition({ where: { tender_id: tenderId, times, audit_order: 1 } });
+            if (audits.length === 0) {
                 if(this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdspl) {
                     throw '请联系管理员添加审批人';
                 } else {
@@ -264,11 +458,9 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
-                await transaction.update(this.tableName, {
-                    id: audit.id,
-                    status: auditConst.status.checking,
-                    begin_time: new Date(),
-                });
+                const begin_time = new Date();
+                const updateAuditData = audits.map(a => { return { id: a.id, status: auditConst.status.checking, begin_time }; });
+                await transaction.updateRows(this.tableName, updateAuditData);
                 await transaction.update(this.ctx.service.tender.tableName, {
                     id: tenderId,
                     ledger_status: auditConst.status.checking,
@@ -276,27 +468,30 @@ module.exports = app => {
                     deal_tp: sum.deal_tp,
                     his_id: his_id,
                 });
-                await this.ctx.service.tenderCache.updateLedgerCache4Start(transaction, tenderId, auditConst.status.checking, audit, sum);
+                await this.ctx.service.tenderCache.updateLedgerCache4Start(transaction, tenderId, auditConst.status.checking, audits, sum);
 
                 // 添加短信通知-需要审批提醒功能
-                await this.ctx.helper.sendAliSms(audit.audit_id, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), SmsAliConst.template.ledger_check);
+                const auditorIds = audits.map(x => { return x.audit_id; });
+                await this.ctx.helper.sendAliSms(auditorIds, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), SmsAliConst.template.ledger_check);
                 // 微信模板通知
                 const wechatData = {
                     status: wxConst.status.check,
                     tips: wxConst.tips.check,
                     begin_time: Date.parse(new Date()),
                 };
-                await this.ctx.helper.sendWechat(audit.audit_id, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), wxConst.template.ledger, wechatData);
-                await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.TZ, {
-                    pid: this.ctx.session.sessionProject.id,
-                    tid: tenderId,
-                    uid: audit.audit_id,
-                    sp_type: 'ledger',
-                    sp_id: audit.id,
-                    table_name: this.tableName,
-                    template: wxConst.template.ledger,
-                    wx_data: wechatData,
-                });
+                await this.ctx.helper.sendWechat(auditorIds, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), wxConst.template.ledger, wechatData);
+                for (const audit of audits) {
+                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.TZ, {
+                        pid: this.ctx.session.sessionProject.id,
+                        tid: tenderId,
+                        uid: audit.audit_id,
+                        sp_type: 'ledger',
+                        sp_id: audit.id,
+                        table_name: this.tableName,
+                        template: wxConst.template.ledger,
+                        wx_data: wechatData,
+                    });
+                }
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -314,133 +509,122 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async check(tenderId, checkType, opinion, times = 1) {
+            const accountId = this.ctx.session.sessionUser.accountId;
             if (checkType !== auditConst.status.checked && checkType !== auditConst.status.checkNo) {
                 throw '提交数据错误';
             }
             const pid = this.ctx.session.sessionProject.id;
+            const auditors = await this.getAllDataByCondition({ where: { tender_id: tenderId, times, status: auditConst.status.checking } });
+            if (auditors.length === 0) throw '审核数据错误';
+            const selfAuditor = auditors.find(x => { return x.audit_id === accountId; });
+            if (!selfAuditor) throw '当前标段您无权审批';
+
+            const flowAuditors = await this.getAllDataByCondition({ where: { tender_id: tenderId, times, audit_order: selfAuditor.audit_order } });
+            const nextAuditors = await this.getAllDataByCondition({ where: { tender_id: tenderId, times, audit_order: selfAuditor.audit_order + 1 } });
+            const beginAuditors = await this.getAllDataByCondition({ where: { tender_id: tenderId, audit_order: 1, times } });
+            const time = new Date();
+
+            const noticeContent = await this.getNoticeContent(selfAuditor.tender_id, pid, accountId, opinion);
+            const defaultNoticeRecord = { pid, type: pushType.ledger, status: checkType, content: noticeContent };
+
             const transaction = await this.db.beginTransaction();
             try {
-                // 整理当前流程审核人状态更新
-                const time = new Date();
-                const audit = await this.getDataByCondition({
-                    tender_id: tenderId,
-                    times,
-                    status: auditConst.status.checking,
-                });
-                if (!audit) {
-                    throw '审核数据错误';
-                }
-
-                // 获取审核人列表
+                // 获取审核人列表,添加提醒
+                const records = [{ uid: this.ctx.tender.data.user_id, ...defaultNoticeRecord } ];
                 const auditList = await this.getAuditors(tenderId, times);
-                // 添加推送
-                const noticeContent = await this.getNoticeContent(audit.tender_id, pid, audit.audit_id, opinion);
-                const records = [
-                    {
-                        pid,
-                        type: pushType.ledger,
-                        uid: this.ctx.tender.data.user_id,
-                        status: checkType,
-                        content: noticeContent,
-                    },
-                ];
                 auditList.forEach(audit => {
-                    records.push({
-                        pid,
-                        type: pushType.ledger,
-                        uid: audit.audit_id,
-                        status: checkType,
-                        content: noticeContent,
-                    });
+                    records.push({ uid: audit.audit_id, ...defaultNoticeRecord});
                 });
                 await transaction.insert('zh_notice', records);
+                const users = this._.uniq(this._.concat(this._.map(auditList, 'audit_id'), this.ctx.tender.data.user_id));
+
                 // 更新当前审核流程
-                await transaction.update(this.tableName, { id: audit.id, status: checkType, opinion, end_time: time });
-                await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, audit.id);
-                const begin_audit = await this.getDataByCondition({
-                    tender_id: tenderId,
-                    audit_order: 1,
-                });
-                const tenderMsg = await this.ctx.service.tender.getDataById(tenderId);
-                const users = this._.uniq(this._.concat(this._.map(auditList, 'audit_id'), tenderMsg.user_id));
+                await transaction.update(this.tableName, { id: selfAuditor.id, status: checkType, opinion, end_time: time });
+                // 审批提醒
+                await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAuditor.id);
+
                 if (checkType === auditConst.status.checked) {
-                    const nextAudit = await this.getDataByCondition({
-                        tender_id: tenderId,
-                        times,
-                        audit_order: audit.audit_order + 1,
-                    });
-                    // 无下一审核人表示,审核结束
-                    if (nextAudit) {
-                        await transaction.update(this.tableName, {
-                            id: nextAudit.id,
-                            status: auditConst.status.checking,
-                            begin_time: time,
-                        });
-                        await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, auditConst.status.checking, checkType, nextAudit);
-                        await this.ctx.helper.sendAliSms(nextAudit.audit_id, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), SmsAliConst.template.ledger_check);
-                        // 微信模板通知
-                        const wechatData = {
-                            status: wxConst.status.check,
-                            tips: wxConst.tips.check,
-                            begin_time: Date.parse(begin_audit.begin_time),
-                        };
-                        await this.ctx.helper.sendWechat(nextAudit.audit_id, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), wxConst.template.ledger, wechatData);
-                        await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.TZ, {
-                            pid: this.ctx.session.sessionProject.id,
-                            tid: tenderId,
-                            uid: nextAudit.audit_id,
-                            sp_type: 'ledger',
-                            sp_id: nextAudit.id,
-                            table_name: this.tableName,
-                            template: wxConst.template.ledger,
-                            wx_data: wechatData,
-                        });
-                    } else {
-                        // 同步标段信息
-                        await transaction.update(this.ctx.service.tender.tableName, {
-                            id: tenderId,
-                            ledger_status: checkType,
-                        });
-                        await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, checkType, checkType);
-                        await this.ctx.service.tenderTag.saveTenderTag(tenderId, {ledger_time: new Date()}, transaction);
-                        // const users = this._.pull(this._.map(auditList, 'audit_id'), audit.id);
-                        await this.ctx.helper.sendAliSms(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), SmsAliConst.template.ledger_result, {
-                            status: SmsAliConst.status.success,
-                        });
-                        // 微信模板通知
-                        const wechatData = {
-                            status: wxConst.status.success,
-                            tips: wxConst.tips.success,
-                            begin_time: Date.parse(begin_audit.begin_time),
-                        };
-                        await this.ctx.helper.sendWechat(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), wxConst.template.ledger, wechatData);
-                        // 审批通过 - 检查三方特殊推送
-                        await this.ctx.service.specMsg.addLedgerMsg(transaction, pid, this.ctx.tender, pushOperate.ledger.checked);
+                    if (auditors.length === 1 || selfAuditor.audit_type === auditType.key.or) {
+                        // 或签更新他人审批状态
+                        if (selfAuditor.audit_type === auditType.key.or) {
+                            const updateOther = [];
+                            for (const audit of auditors) {
+                                if (audit.audit_id === selfAuditor.audit_id) 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 (nextAuditors.length > 0) {
+                            const nextAuditUpdateData = nextAuditors.map(x => { return {id: x.id, status: auditConst.status.checking, begin_time: time }; });
+                            await transaction.updateRows(this.tableName, nextAuditUpdateData);
+
+                            await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, auditConst.status.checking, checkType, nextAuditors);
+                            const nextAuditorIds = nextAuditors.map(x => { return x.audit_id; });
+                            await this.ctx.helper.sendAliSms(nextAuditorIds, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), SmsAliConst.template.ledger_check);
+                            // 微信模板通知
+                            const wechatData = {
+                                status: wxConst.status.check,
+                                tips: wxConst.tips.check,
+                                begin_time: Date.parse(beginAuditors[0].begin_time),
+                            };
+                            await this.ctx.helper.sendWechat(nextAuditorIds, smsTypeConst.const.TZ, smsTypeConst.judge.approval.toString(), wxConst.template.ledger, wechatData);
+                            for (const audit of nextAuditors) {
+                                await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.TZ, {
+                                    pid: this.ctx.session.sessionProject.id,
+                                    tid: tenderId,
+                                    uid: audit.audit_id,
+                                    sp_type: 'ledger',
+                                    sp_id: audit.id,
+                                    table_name: this.tableName,
+                                    template: wxConst.template.ledger,
+                                    wx_data: wechatData,
+                                });
+                            }
+                        } else {
+                            // 同步标段信息
+                            await transaction.update(this.ctx.service.tender.tableName, {
+                                id: tenderId, ledger_status: checkType,
+                            });
+                            await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, checkType, checkType);
+                            // 审批通过,添加标记
+                            await this.ctx.service.tenderTag.saveTenderTag(tenderId, { ledger_time: time }, transaction);
+                            await this.ctx.helper.sendAliSms(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), SmsAliConst.template.ledger_result, {
+                                status: SmsAliConst.status.success,
+                            });
+                            // 微信模板通知
+                            const wechatData = {
+                                status: wxConst.status.success,
+                                tips: wxConst.tips.success,
+                                begin_time: Date.parse(beginAuditors[0].begin_time),
+                            };
+                            await this.ctx.helper.sendWechat(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), wxConst.template.ledger, wechatData);
+                            // 审批通过 - 检查三方特殊推送
+                            await this.ctx.service.specMsg.addLedgerMsg(transaction, pid, this.ctx.tender, pushOperate.ledger.checked);
+                        }
                     }
                 } else {
                     // 同步标段信息
                     await transaction.update(this.ctx.service.tender.tableName, {
-                        id: tenderId,
-                        ledger_times: times + 1,
-                        ledger_status: checkType,
+                        id: tenderId, ledger_times: times + 1, ledger_status: checkType,
                     });
-                    await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, checkType, checkType, { audit_id: this.ctx.tender.data.user_id });
+                    await this.ctx.service.tenderCache.updateLedgerCache(transaction, tenderId, checkType, checkType, [{ audit_id: this.ctx.tender.data.user_id }]);
                     // 拷贝新一次审核流程列表
                     const auditors = await this.getAllDataByCondition({
                         where: { tender_id: tenderId, times },
-                        columns: ['tender_id', 'audit_order', 'audit_id'],
+                        columns: ['tender_id', 'audit_order', 'audit_id', 'audit_type', 'audit_ledger_id'],
+                    });
+                    const insertAuditors = auditors.map(x => {
+                        return { ...x, times: times + 1, status: auditConst.status.uncheck };
                     });
-                    const insertAuditors = [];
-                    for (const a of auditors) {
-                        if (insertAuditors.find(x => { return x.audit_id === a.audit_id; })) continue;
-                        a.audit_order = insertAuditors.length + 1;
-                        a.times = times + 1;
-                        a.status = auditConst.status.uncheck;
-                        insertAuditors.push(a)
-                    }
                     await transaction.insert(this.tableName, insertAuditors);
 
-                    // const users = this._.pull(this._.map(auditList, 'audit_id'), audit.id);
                     await this.ctx.helper.sendAliSms(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), SmsAliConst.template.ledger_result, {
                         status: SmsAliConst.status.back,
                     });
@@ -448,7 +632,7 @@ module.exports = app => {
                     const wechatData = {
                         status: wxConst.status.back,
                         tips: wxConst.tips.back,
-                        begin_time: Date.parse(begin_audit.begin_time),
+                        begin_time: Date.parse(beginAuditors[0].begin_time),
                     };
                     await this.ctx.helper.sendWechat(users, smsTypeConst.const.TZ, smsTypeConst.judge.result.toString(), wxConst.template.ledger, wechatData);
                 }
@@ -463,7 +647,7 @@ module.exports = app => {
 
         /**
          * 重新审批
-         * @param {Number} stageId - 标段id
+         * @param {Number} tenderId - 标段id
          * @param {Number} times - 第几次审批
          * @return {Promise<void>}
          */
@@ -647,19 +831,18 @@ module.exports = app => {
             return result;
         }
 
-        async updateNewAuditList(tender, newIdList) {
+        async updateNewAuditList(tender, newList) {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先删除旧的审批流,再添加新的
                 await transaction.delete(this.tableName, { tender_id: tender.id, times: tender.ledger_times });
                 const newAuditors = [];
-                let order = 1;
-                for (const aid of newIdList) {
+                for (const auditor of newList) {
                     newAuditors.push({
-                        tender_id: tender.id, audit_id: aid,
-                        times: tender.ledger_times, audit_order: order, status: auditConst.status.uncheck,
-                    });
-                    order++;
+                        tender_id: tender.id, audit_id: auditor.audit_id,
+                        times: tender.ledger_times, audit_order: auditor.audit_order, status: auditConst.status.uncheck,
+                        audit_type: auditor.audit_type, audit_ledger_id: auditor.audit_type === auditType.key.union ? auditor.audit_ledger_id : '',
+                    })
                 }
                 if(newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);
                 await transaction.commit();
@@ -698,7 +881,7 @@ module.exports = app => {
 
         /**
          * 删除本次审批流程
-         * @param {Number} stageId - 标段id
+         * @param {Number} tenderId - 标段id
          * @param {Number} times - 第几次审批
          * @param {Object} data - 更改参数
          * @return {Promise<void>}
@@ -729,14 +912,6 @@ module.exports = app => {
                     }
                     await transaction.delete(this.tableName, { tender_id: tenderId, times, audit_id: now_audit.audit_id, audit_order: now_audit.audit_order });
                     await this._syncOrderByDelete(transaction, tenderId, now_audit.audit_order, times);
-                    // // 旧的更新为is_old为1
-                    // await transaction.update(this.tableName, { is_old: 1 }, {
-                    //     where: {
-                    //         sid: stageId,
-                    //         times,
-                    //         aid: data.old_aid,
-                    //     }
-                    // });
                 } else if (data.operate === 'change') {
                     const nowAudit = await this.getDataByCondition({ tender_id: tenderId, times, audit_id: now_audit.audit_id, audit_order: now_audit.audit_order });
                     if (now_audit.status !== auditConst.status.uncheck || !nowAudit) {
@@ -744,14 +919,6 @@ module.exports = app => {
                     }
                     nowAudit.audit_id = data.new_aid;
                     await transaction.update(this.tableName, nowAudit);
-                    // 旧的更新为is_old为1
-                    // await transaction.update(this.tableName, { is_old: 1 }, {
-                    //     where: {
-                    //         sid: stageId,
-                    //         times,
-                    //         aid: data.old_aid,
-                    //     }
-                    // });
                 }
                 if (this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdspl || this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdzs) {
                     const newAuditors = await this.getAuditGroupByList(tenderId, times, transaction);

+ 78 - 2
app/service/stage_audit.js

@@ -1726,7 +1726,7 @@ 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_ledger_id: x.audit_ledger_id,
                 };
                 newAuditors.push(na);
             }
@@ -2251,6 +2251,82 @@ module.exports = app => {
             return result;
         }
 
+        async lockConfirm4CheckNoPre(stage, uid, pre_uid, transaction) {
+            if (!transaction) throw '缺少参数';
+
+            const locked = await this.getAllDataByCondition({ where: { sid: stage.id, locked: 1, times: stage.curTimes } });
+            locked.forEach(x => {
+                x.locked_ledger_id = x.ass_ledger_id.split(',');
+            });
+            // 审批人数据锁定
+            const locking = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: uid, confirm: 1 } });
+            locking.forEach(x => {
+                x.locked_ledger_id = x.ass_ledger_id.split(',');
+            });
+            if (locking.length > 0) {
+                const updateLock = locking.map(x => { return { id: x.id, locked: 1 }; });
+                await transaction.updateRows(this.tableName, updateLock);
+            }
+            const preConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: pre_uid, confirm: 1 } });
+            // 前审批人数据,与被锁定数据相关数据确认状态保留
+            locked.push(...locking);
+            if (preConfirm.length > 0) {
+                const delConfirm = [];
+                for (const pc of preConfirm) {
+                    const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: pc.ledger_id });
+                    const billsOwner = bills ? bills.full_path.split('-') : [];
+                    const exist = locked.find(x => {
+                        for (const id of x.locked_ledger_id) {
+                            if (billsOwner.indexOf(id) >= 0) return true;
+                        }
+                        return false;
+                    });
+                    if (!exist) delConfirm.push(pc.id);
+                }
+                if (delConfirm.length > 0) await transaction.delete(this.tableName, { id: delConfirm });
+            }
+        }
+
+        async lockConfirm4CheckNo(stage, uid, auditors, transaction) {
+            if (!transaction) throw '缺少参数';
+            // 审批人数据锁定
+            const lockConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, o: uid, confirm: 1 } });
+            if (lockConfirm.length === 0) return;
+
+            const insertData = [];
+            lockConfirm.forEach(x => {
+                delete x.id;
+                x.locked = 1;
+                x.times = x.times + 1;
+                insertData.push(x);
+            });
+            // 审批人前所有角色,与锁定数据相关确认状态保留
+            const keepUid = [ stage.user_id ];
+            for (const a of auditors) {
+                if (a.aid === uid) break;
+                keepUid.push(a.aid);
+            }
+            const keepConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: keepUid, confirm: 1 } });
+            for (const kc of keepConfirm) {
+                const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: kc.ledger_id });
+                const billsOwner = bills ? bills.full_path.split('-') : [];
+                const exist = lockConfirm.find(x => {
+                    const lid = x.ass_ledger_id.split(',');
+                    for (const id of lid) {
+                        if (billsOwner.indexOf(id) >= 0) return true;
+                    }
+                    return false;
+                });
+                if (exist) {
+                    delete kc.id;
+                    kc.locked = 0;
+                    kc.times = kc.times + 1;
+                    insertData.push(kc);
+                }
+            }
+            if (insertData.length > 0) await transaction.insert(this.tableName, insertData);
+        }
+
         async cancelLock(stage, uid, transaction) {
             if (transaction) {
                 await transaction.update(this.tableName, { locked: 0 }, { where: { sid: stage.id, times: stage.times, aid: uid } });
@@ -2260,7 +2336,7 @@ module.exports = app => {
         }
 
         async getLockedId(stage) {
-            return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, audit_locked: 1 } });
+            return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, locked: 1 } });
         }
     }
 

+ 1 - 1
app/service/stage_audit_ass.js

@@ -52,7 +52,7 @@ module.exports = app => {
             const accountStageAssDatas = [];
             for (const as of accountStageAssData) {
                 const s = this._.find(lastStageList, { tid: as.tid });
-                if (s.id === as.sid) {
+                if (s && s.id === as.sid) {
                     const asaIndex = accountStageAssDatas.findIndex(x => { return x.sid === as.sid; });
                     if (asaIndex === -1 || (asaIndex >= 0 && as.times > accountStageAssDatas[asaIndex].times)) {
                         if (asaIndex >= 0 && as.times > accountStageAssDatas[asaIndex].times) accountStageAssDatas.splice(asaIndex, 1);

+ 13 - 11
app/service/tender_cache.js

@@ -115,7 +115,7 @@ module.exports = app => {
             await transaction.insert(this.tableName, data);
         }
 
-        async updateLedgerCache4Start(transaction, tid, status, audit, tp) {
+        async updateLedgerCache4Start(transaction, tid, status, auditors, tp) {
             const orgCache = await this.getDataById(tid);
             const preInfo = JSON.parse(orgCache.ledger_flow_cur_info);
             preInfo.time = new Date();
@@ -123,12 +123,12 @@ module.exports = app => {
                 id: tid, ledger_status: status,
                 ledger_flow_pre_uid: orgCache.ledger_flow_cur_uid, ledger_flow_pre_info: JSON.stringify(preInfo),
             };
-            if (audit) {
-                const info = await this.ctx.service.projectAccount.getAccountCacheData(audit.audit_id);
-                info.order = audit.audit_order;
-                info.status = status;
-                data.ledger_flow_cur_uid = audit.audit_id;
-                data.ledger_flow_cur_info = JSON.stringify(info);
+            if (auditors.length > 0) {
+                const auditIds = auditors.map(x => { return x.audit_id; });
+                const curInfo = await this.ctx.service.projectAccount.getAccountCacheDatas(auditIds,
+                    {audit_type: auditors[0].audit_type, audit_order: 1, status});
+                data.ledger_flow_cur_uid = auditIds.join(',');
+                data.ledger_flow_cur_info = JSON.stringify(curInfo);
             }
             if (tp) data.ledger_tp = JSON.stringify(tp);
             await transaction.update(this.tableName, data);
@@ -143,10 +143,12 @@ module.exports = app => {
                 id: tid, ledger_status: status,
                 ledger_flow_pre_uid: orgCache.ledger_flow_cur_uid || orgCache.ledger_flow_pre_uid, ledger_flow_pre_info: JSON.stringify(preInfo),
             };
-            if (next) {
-                const info = await this.ctx.service.projectAccount.getAccountCacheData(next.audit_id);
-                info.status = checkType === auditConst.ledger.status.checkNo ? status : auditConst.ledger.status.uncheck;
-                data.ledger_flow_cur_uid = next.audit_id;
+            if (next && next.length > 0) {
+                const auditIds = next.map(x => { return x.audit_id; });
+                const infoStatus = checkType === auditConst.ledger.status.checkNo ? status : auditConst.ledger.status.uncheck;
+                const info = await this.ctx.service.projectAccount.getAccountCacheDatas(auditIds,
+                    {audit_type: next[0].audit_type, audit_order: next[0].audit_order, status: infoStatus});
+                data.ledger_flow_cur_uid = auditIds.join(',');
                 data.ledger_flow_cur_info = JSON.stringify(info);
             } else {
                 data.ledger_flow_cur_uid = 0;

+ 2 - 2
app/view/file/file.ejs

@@ -73,8 +73,8 @@
                             <div class="input-group input-group-sm pb-1">
                                 <div class="input-group-prepend">
                                     <select class="input-group-text" id="search-filter">
-                                        <option value="cur">当前类</option>
-                                        <option value="all">全部类</option>
+                                        <option value="cur">当前类</option>
+                                        <option value="all">全部类</option>
                                     </select>
                                 </div>
                                 <input id="search-keyword" type="text" class="form-control" autocomplete="off" placeholder="输入文件名称查找" aria-label="Recipient\'s username" aria-describedby="button-addon2">

+ 221 - 248
app/view/ledger/audit_modal.ejs

@@ -1,4 +1,4 @@
-<% if (tender.ledger_status === auditConst.status.checking && curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
+<% if (tender.ledger_status === auditConst.status.checking && tender.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
 <!--审批通过-->
 <div class="modal fade sp-location-list" id="sp-done" data-backdrop="static">
     <div class="modal-dialog modal-lg" role="document">
@@ -12,173 +12,160 @@
                         <% if(tender.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) { %>
                             <a class="sp-list-item" href="#sub-sp2" data-toggle="modal" data-target="#sub-sp2" id="hideSp">修改审批流程</a>
                         <% } %>
-                        <div class="card mt-3">
-                            <ul class="list-group list-group-flush auditors-list">
-                                <% auditors.forEach((item, idx) => { %>
+                        <div class="card modal-height-500 mt-3 scroll-y">
+                            <ul class="list-group list-group-flush auditors-list" id="auditors-list">
+                                <% tender.userGroups.forEach((group, idx) => { %>
                                 <% if (idx === 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">原报</span>
+                                <li class="list-group-item d-flex justify-content-between align-items-center">
+                                    <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                                    <small class="text-muted">
+                                        <% for (const u of group) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
                                 </li>
-                                <% } else if(idx === auditors.length -1 && idx !== 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-stop-circle"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">终审</span>
+                                <% } else if(idx === tender.userGroups.length -1 && idx !== 0) { %>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of group) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (group[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%-  auditType.info[group[0].audit_type].class %> p-1"><small><%- auditType.info[group[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small>终审</small></span>
+                                    </div>
                                 </li>
                                 <% } else {%>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right"><%= ctx.helper.transFormToChinese(idx) %>审</span>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of group) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (group[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%- auditType.info[group[0].audit_type].class %> p-1"><small><%- auditType.info[group[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small><%= ctx.helper.transFormToChinese(idx) %>审</small></span>
+                                    </div>
                                 </li>
                                 <% } %>
                                 <% }) %>
                             </ul>
                         </div>
                     </div>
-                    <div class="col-8 modal-height-500" style="overflow: auto">
-                        <% auditHistory.forEach((auditors, idx) => { %>
+                    <div class="col-8 modal-height-500 scroll-y">
+                        <% tender.auditHistory.forEach((his, idx) => { %>
                             <!-- 展开/收起历史流程 -->
-                        <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
+                        <% if(idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>
                             <div class="text-right">
                                 <a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a>
                             </div>
                             <% } %>
-                        <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
+                        <div class="<%- idx < tender.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === auditHistory.length - 1) { %>last-auditor-list<% } %>">
-                                <% auditors.forEach((auditor, index) => { %>
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1 && tender.auditHistory.length > 1) { %>last-auditor-list<% } %>">
+                                <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.begin_time) %>
+                                        <%- group.beginYear %>
+                                        <span><%- group.beginDate %></span>
+                                        <span><%- group.beginTime %></span>
                                     </div>
                                     <div class="timeline-item-tail"></div>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-caret-down"></i>
-                                    </div>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
                                     <div class="timeline-item-content">
-                                        <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span
-                                                            class="h5"><%- user.name %></span><span
-                                                            class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- user.role %></p>
-                                                </div>
-                                            </div>
+                                        <div class="py-1">
+                                            <span class="text-black-50">原报</span>
+                                            <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                         </div>
-                                    </div>
-                                </li>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
-                                    <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
-                                    </div>
-                                    <% if(index < auditors.length - 1) { %>
-                                    <div class="timeline-item-tail"></div>
-                                    <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
-                                    <% } else {%>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
-                                    <% } %>
-                                    <div class="timeline-item-content">
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span><span
-                                                            class="pull-right <%- auditConst.statusClass[auditor.status] %>"><%- auditConst.statusString[auditor.status] %></span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <div class="card-text p-2 py-3 row">
+                                                    <div class="col">
+                                                        <span class="h6"><%- tender.user.name %></span>
+                                                        <span class="text-muted ml-1"><%- tender.user.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                    </div>
                                                 </div>
                                             </div>
-                                            <!--审批意见-->
-                                            <% if(auditor.status !== auditConst.status.uncheck) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <% if (tender.ledger_times === idx + 1 && auditor.status === auditConst.status.checking) { %>
-                                                <label>审批意见<b class="text-danger">*</b></label>
-                                                <textarea class="form-control form-control-sm"
-                                                    name="opinion">同意</textarea>
-                                                <% } else { %>
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                                <% } %>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } else {%>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
+                                <% } %>
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length > 1) { %>is_uncheck<% } %>">
+                                    <% if (group.endYear) { %>
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
+                                        <%- group.endYear %>
+                                        <span><%- group.endDate %></span>
+                                        <span><%- group.endTime %></span>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% } %>
+                                    <% if (index < his.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
+                                    <% if (group.status === auditConst.status.checked) { %>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>
+                                    <% } else if (group.status === auditConst.status.checkNo || group.status === auditConst.status.checkNoPre || group.status === auditConst.status.checkCancel) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>
+                                    <% } else if (group.status === auditConst.status.checking) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>
                                     <% } else { %>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
+                                    <div class="timeline-item-icon bg-secondary text-light"></div>
                                     <% } %>
                                     <div class="timeline-item-content">
+                                        <div class="py-1">
+                                                <span class="text-black-50">
+                                                    <%- (!group.is_final ? group.audit_order : '终') %>审
+                                                    <% if (group.audit_type !== auditType.key.common) { %><span class="text-<%- auditType.info[group.audit_type].class %> "><%- auditType.info[group.audit_type].long %></span><% } %>
+                                                </span>
+                                            <% if (group.status !== auditConst.status.uncheck) { %>
+                                            <span class="pull-right <%- auditConst.statusClass[group.status] %>"><%- auditConst.statusString[group.status] %></span>
+                                            <% } %>
+                                        </div>
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span>
-                                                        <span class="pull-right <%- auditConst.statusClass[auditor.status] %>">
-                                                            <%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
-                                                            <%- auditor.status === auditConst.status.checkNo ? user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
-                                                        </span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <% for (const [i, auditor] of group.auditors.entries()) { %>
+                                                <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
+                                                    <div class="col">
+                                                        <span class="h6"><%- auditor.name %></span>
+                                                        <span class="text-muted ml-1"><%- auditor.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <% if (auditor.status === auditConst.status.checked) { %>
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                        <% } if (auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre || auditor.status === auditConst.status.checkCancel) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                        <% } else if (auditor.status === auditConst.status.checking) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>
+                                                        <% } %>
+                                                    </div>
+                                                    <% if (auditor.status !== auditConst.status.uncheck && auditor.opinion) { %>
+                                                    <div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i><%- auditor.opinion%></div>
+                                                    <% } %>
+                                                    <% if (auditor.status === auditConst.status.checking && auditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                                                    <div class="col-12 py-1 bg-light">
+                                                        <textarea class="form-control form-control-sm" name="opinion">同意</textarea>
+                                                    </div>
+                                                    <% } %>
                                                 </div>
-                                            </div>
-                                            <!--审批意见-->
-                                            <% if(auditor.status !== auditConst.status.uncheck) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <% if (tender.ledger_times === idx + 1 && auditor.status === auditConst.status.checking) { %>
-                                                <label>审批意见<b class="text-danger">*</b></label>
-                                                <textarea class="form-control form-control-sm"
-                                                    name="opinion">同意</textarea>
-                                                <% } else { %>
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
                                                 <% } %>
                                             </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } %>
                                 <% }) %>
                             </ul>
                         </div>
-
                         <% }) %>
                     </div>
                 </div>
@@ -206,171 +193,157 @@
                         <% if(tender.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) { %>
                             <a class="sp-list-item" href="#sub-sp2" data-toggle="modal" data-target="#sub-sp2" id="hideSp">修改审批流程</a>
                         <% } %>
-                        <div class="card mt-3">
-                            <ul class="list-group list-group-flush auditors-list">
-                                <% auditors.forEach((item, idx) => { %>
+                        <div class="card modal-height-500 mt-3 scroll-y" style="overflow: auto">
+                            <ul class="list-group list-group-flush auditors-list" id="auditors-list">
+                                <% tender.userGroups.forEach((item, idx) => { %>
                                 <% if (idx === 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">原报</span>
+                                <li class="list-group-item d-flex justify-content-between align-items-center">
+                                    <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
                                 </li>
-                                <% } else if(idx === auditors.length -1 && idx !== 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-stop-circle"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">终审</span>
+                                <% } else if(idx === tender.userGroups.length -1 && idx !== 0) { %>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%-  auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small>终审</small></span>
+                                    </div>
                                 </li>
                                 <% } else {%>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right"><%= ctx.helper.transFormToChinese(idx) %>审</span>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%- auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small><%= ctx.helper.transFormToChinese(idx) %>审</small></span>
+                                    </div>
                                 </li>
                                 <% } %>
                                 <% }) %>
                             </ul>
                         </div>
                     </div>
+
                     <div class="col-8 modal-height-500" style="overflow: auto">
-                        <% auditHistory.forEach((auditors, idx) => { %>
-                            <!-- 展开/收起历史流程 -->
-                        <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
-                            <div class="text-right">
-                                <a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a>
-                            </div>
-                            <% } %>
-                        <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
+                        <% tender.auditHistory.forEach((his, idx) => { %>
+                        <!-- 展开/收起历史流程 -->
+                        <% if(idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>
+                        <div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show"
+                                                   data-idx="<%- idx + 1 %>">展开历史审批流程</a></div>
+                        <% } %>
+                        <div class="<%- idx < tender.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === auditHistory.length - 1) { %>last-auditor-list<% } %>">
-                                <% auditors.forEach((auditor, index) => { %>
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                                <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.begin_time) %>
+                                        <%- group.beginYear %>
+                                        <span><%- group.beginDate %></span>
+                                        <span><%- group.beginTime %></span>
                                     </div>
                                     <div class="timeline-item-tail"></div>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-caret-down"></i>
-                                    </div>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
                                     <div class="timeline-item-content">
-                                        <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span
-                                                            class="h5"><%- user.name %></span><span
-                                                            class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- user.role %></p>
-                                                </div>
-                                            </div>
+                                        <div class="py-1">
+                                            <span class="text-black-50">原报</span>
+                                            <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                         </div>
-                                    </div>
-                                </li>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
-                                    <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
-                                    </div>
-                                    <% if(index < auditors.length - 1) { %>
-                                    <div class="timeline-item-tail"></div>
-                                    <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
-                                    <% } else {%>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
-                                    <% } %>
-                                    <div class="timeline-item-content">
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span><span
-                                                            class="pull-right <%- auditConst.statusClass[auditor.status] %>"><%- auditConst.statusString[auditor.status] %></span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <div class="card-text p-2 py-3 row">
+                                                    <div class="col">
+                                                        <span class="h6"><%- tender.user.name %></span>
+                                                        <span class="text-muted ml-1"><%- tender.user.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                    </div>
                                                 </div>
                                             </div>
-
-                                            <!--审批意见-->
-                                            <% if(auditor.times === tender.ledger_times && auditor.status !== auditConst.status.uncheck) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <% if (tender.ledger_times === idx + 1 && auditor.status === auditConst.status.checking) { %>
-                                                <label>审批意见<b class="text-danger">*</b></label>
-                                                <textarea class="form-control form-control-sm"
-                                                    name="opinion">不同意</textarea>
-                                                <% } else if(auditor.status === auditConst.status.checked){ %>
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                                <% } %>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } else {%>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
+                                <% } %>
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                    <% if (his.endYear) { %>
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
+                                        <%- group.endYear %>
+                                        <span><%- group.endDate %></span>
+                                        <span><%- group.endTime %></span>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% } %>
+                                    <% if (index < his.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
+                                    <% if (group.status === auditConst.status.checked) { %>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>
+                                    <% } else if (group.status === auditConst.status.checkNo || group.status === auditConst.status.checkNoPre || group.status === auditConst.status.checkCancel) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>
+                                    <% } else if (group.status === auditConst.status.checking) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>
                                     <% } else { %>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
+                                    <div class="timeline-item-icon bg-secondary text-light"></div>
                                     <% } %>
                                     <div class="timeline-item-content">
+                                        <div class="py-1">
+                                                <span class="text-black-50">
+                                                    <%- (!group.is_final ? group.audit_order : '终') %>审
+                                                    <% if (group.audit_type !== auditType.key.common) { %><span class="text-<%- auditType.info[group.audit_type].class %> "><%- auditType.info[group.audit_type].long %></span><% } %>
+                                                </span>
+                                            <% if (group.status !== auditConst.status.uncheck) { %>
+                                            <span class="pull-right <%- auditConst.statusClass[group.status] %>"><%- auditConst.statusString[group.status] %></span>
+                                            <% } %>
+                                        </div>
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span>
-                                                        <span
-                                                            class="pull-right
-                                                                            <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
-                                                            <%- auditor.status === auditConst.status.checkNo ? user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
-                                                        </span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <% for (const [i, auditor] of group.auditors.entries()) { %>
+                                                <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
+                                                    <div class="col">
+                                                        <span class="h6"><%- auditor.name %></span>
+                                                        <span class="text-muted ml-1"><%- auditor.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <% if (auditor.status === auditConst.status.checked) { %>
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                        <% } if (auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre || auditor.status === auditConst.status.checkCancel) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                        <% } else if (auditor.status === auditConst.status.checking) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>
+                                                        <% } %>
+                                                    </div>
+                                                    <% if (auditor.status !== auditConst.status.uncheck && auditor.opinion) { %>
+                                                    <div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i><%- auditor.opinion%></div>
+                                                    <% } %>
+                                                    <% if (auditor.status === auditConst.status.checking && auditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                                                    <div class="col-12 py-1 bg-light">
+                                                        <textarea class="form-control form-control-sm" name="opinion">不同意</textarea>
+                                                    </div>
+                                                    <% } %>
                                                 </div>
-                                            </div>
-                                            <!--审批意见-->
-                                            <% if(auditor.times === tender.ledger_times && auditor.status !== auditConst.status.uncheck) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <% if (tender.ledger_times === idx + 1 && auditor.status === auditConst.status.checking) { %>
-                                                <label>审批意见<b class="text-danger">*</b></label>
-                                                <textarea class="form-control form-control-sm"
-                                                    name="opinion">不同意</textarea>
-                                                <% } else { %>
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
                                                 <% } %>
                                             </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } %>
                                 <% }) %>
                             </ul>
                         </div>

+ 3 - 3
app/view/ledger/explode.ejs

@@ -52,7 +52,7 @@
                 <a class="btn btn-sm btn-primary mr-1" id="ledger-check2" href="javascript: void(0);">数据检查</a>
                 <% if (tender.ledger_status === auditConst.status.checkNo) { %>
                     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-dark sp-list-btn">审批退回</a>
-                <% } else if (tender.ledger_status === auditConst.status.checking && curAuditor.audit_id !== ctx.session.sessionUser.accountId) { %>
+                <% } else if (tender.ledger_status === auditConst.status.checking && tender.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) < 0) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-dark">审批中</a>
                 <% } else if (tender.ledger_status === auditConst.status.checked) { %>
                     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm sp-list-btn">审批完成</a>
@@ -65,11 +65,11 @@
                     <% } %>
                 <% } %>
 
-                <% if (tender.ledger_status === auditConst.status.checking && curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                <% if (tender.ledger_status === auditConst.status.checking && tender.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
                 <a href="#sp-done" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm mr-1">审批通过</a>
                 <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm mr-1">审批退回</a>
                 <% }%>
-                <% if (tender.ledger_status === auditConst.status.checked && auditors[auditors.length - 1].audit_id === ctx.session.sessionUser.accountId && !tender.hasStage && !tender.hasRevise) { %>
+                <% if (tender.ledger_status === auditConst.status.checked && tender.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0 && !tender.hasStage && !tender.hasRevise) { %>
                 <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm mr-1">重新审批</a>
                 <% }%>
             </div>

+ 122 - 121
app/view/ledger/explode_modal.ejs

@@ -159,14 +159,26 @@
                     </div>
                     <div class="modal-height-500" style="overflow: auto">
                     <ul class="list-group list-group-flush" id="auditors">
-                        <% for (let i = 0, iLen = auditorList.length; i < iLen; i++) { %>
-                        <li class="list-group-item" auditorId="<%- auditorList[i].audit_id %>">
-                            <% if (ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.sqspr ||
-                                    (ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdzs && i+1 !== iLen)) { %>
-                            <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
-                            <% } %>
-                            <span><%- auditorList[i].audit_order %> <%- auditorList[i].name %></span>
-                            <small class="text-muted"><%- auditorList[i].role %></small>
+                        <% for (let i = 0, iLen = tender.auditorGroups.length; i < iLen; i++) { %>
+                        <li class="list-group-item d-flex" auditorId="<%- tender.auditorGroups[i][0].audit_id %>">
+                            <div class="col-auto"><%- i+1 %></div>
+                            <div class="col">
+                                <% for (const auditor of tender.auditorGroups[i]) { %>
+                                <div class="d-inline-block mx-1" auditorId="<%- auditor.audit_id %>">
+                                    <i class="fa fa-user text-muted"></i> <%- auditor.name %> <small class="text-muted"><%- auditor.role %></small>
+                                </div>
+                                <% } %>
+                            </div>
+                            <div class="col-auto">
+                                <% if (tender.auditorGroups[i][0].audit_type !== auditType.key.common) { %>
+                                <span class="badge badge-pill badge-<%- auditType.info[tender.auditorGroups[i][0].audit_type].class %> badge-bg-small"><small><%- auditType.info[tender.auditorGroups[i][0].audit_type].long%></small></span>
+                                <% } %>
+                                <% if (ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.sqspr ||
+                                        (ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdzs && i+1 !== iLen)) { %>
+                                <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
+                                <% } %>
+                            </div>
+
                         </li>
                         <% } %>
                     </ul>
@@ -193,32 +205,53 @@
             <div class="modal-body">
                 <div class="row">
                     <div class="col-4">
-                        <% if(tender.ledger_status === auditConst.status.checkNo) { %>
+                        <% if(tender.ledger_status === auditConst.status.checkNo && tender.user_id === ctx.session.sessionUser.accountId) { %>
                             <a class="sp-list-item" href="#sub-sp" data-toggle="modal" data-target="#sub-sp" id="hideSp">修改审批流程</a>
                         <% } else if(tender.ledger_status !== auditConst.status.checked && ctx.session.sessionUser.is_admin) { %>
-                            <a class="sp-list-item" href="#sub-sp2" data-toggle="modal" data-target="#sub-sp2"
-                               id="hideSp">修改审批流程</a>
+                            <a class="sp-list-item" href="#sub-sp2" data-toggle="modal" data-target="#sub-sp2" id="hideSp">修改审批流程</a>
                         <% } %>
-                        <div class="card mt-3">
+                        <div class="card modal-height-500 mt-3" style="overflow: auto">
                             <ul class="list-group list-group-flush auditors-list" id="auditors-list">
-                                <% auditors.forEach((item, idx) => { %>
+                                <% tender.userGroups.forEach((item, idx) => { %>
                                 <% if (idx === 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">原报</span>
+                                <li class="list-group-item d-flex justify-content-between align-items-center">
+                                    <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
                                 </li>
-                                <% } else if(idx === auditors.length -1 && idx !== 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-stop-circle"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">终审</span>
+                                <% } else if(idx === tender.userGroups.length -1 && idx !== 0) { %>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%-  auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small>终审</small></span>
+                                    </div>
                                 </li>
                                 <% } else {%>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right"><%= ctx.helper.transFormToChinese(idx) %>审</span>
+                                <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>
+                                    <small class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </small>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%- auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small><%= ctx.helper.transFormToChinese(idx) %>审</small></span>
+                                    </div>
                                 </li>
                                 <% } %>
                                 <% }) %>
@@ -226,132 +259,101 @@
                         </div>
                     </div>
                     <div class="col-8 modal-height-500" style="overflow: auto">
-                        <% auditHistory.forEach((auditors, idx) => { %>
+                        <% tender.auditHistory.forEach((his, idx) => { %>
                             <!-- 展开/收起历史流程 -->
-                        <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
+                        <% if(idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>
                             <div class="text-right">
                                 <a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a>
                             </div>
                         <% } %>
-                        <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
+                        <div class="<%- idx < tender.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === auditHistory.length - 1) { %>last-auditor-list<% } %>">
-                                <% auditors.forEach((auditor, index) => { %>
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1) { %>last-auditor-list<% } %>">
+                                <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.begin_time) %>
+                                        <%- group.beginYear %>
+                                        <span><%- group.beginDate %></span>
+                                        <span><%- group.beginTime %></span>
                                     </div>
                                     <div class="timeline-item-tail"></div>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-caret-down"></i>
-                                    </div>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
                                     <div class="timeline-item-content">
-                                        <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span
-                                                            class="h5"><%- user.name %></span><span
-                                                            class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- user.role %></p>
-                                                </div>
-                                            </div>
+                                        <div class="py-1">
+                                            <span class="text-black-50">原报</span>
+                                            <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                         </div>
-                                    </div>
-                                </li>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
-                                    <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
-                                    </div>
-                                    <% if(index < auditors.length - 1) { %>
-                                    <div class="timeline-item-tail"></div>
-                                    <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
-                                    <% } else {%>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
-                                    <% } %>
-                                    <div class="timeline-item-content">
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span><span
-                                                            class="pull-right <%- auditConst.statusClass[auditor.status] %>"><%- auditConst.statusString[auditor.status] %></span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <div class="card-text p-2 py-3 row">
+                                                    <div class="col">
+                                                        <span class="h6"><%- tender.user.name %></span>
+                                                        <span class="text-muted ml-1"><%- tender.user.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                    </div>
                                                 </div>
                                             </div>
-
-                                            <!--审批意见-->
-                                            <% if (auditor.opinion) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } else {%>
-                                <li class="timeline-list-item pb-2 <% if (auditor.status === auditConst.status.uncheck && idx === auditHistory.length - 1) { %>is_uncheck<% } %>">
+                                <% } %>
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                    <% if (group.endYear) { %>
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
+                                        <%- group.endYear %>
+                                        <span><%- group.endDate %></span>
+                                        <span><%- group.endTime %></span>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% } %>
+                                    <% if (index < his.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
+                                    <% if (group.status === auditConst.status.checked) { %>
+                                    <div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>
+                                    <% } else if (group.status === auditConst.status.checkNo || group.status === auditConst.status.checkNoPre || group.status === auditConst.status.checkCancel) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>
+                                    <% } else if (group.status === auditConst.status.checking) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>
                                     <% } else { %>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
+                                    <div class="timeline-item-icon bg-secondary text-light"></div>
                                     <% } %>
                                     <div class="timeline-item-content">
-                                        <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span>
-                                                        <span
-                                                            class="pull-right
-                                                                            <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
-                                                            <%- auditor.status === auditConst.status.checkNo ? user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                        <div class="py-1">
+                                                        <span class="text-black-50">
+                                                            <%- (!group.is_final ? group.audit_order : '终') %>审
+                                                            <% if (group.audit_type !== auditType.key.common) { %><span class="text-<%- auditType.info[group.audit_type].class %> "><%- auditType.info[group.audit_type].long %></span><% } %>
                                                         </span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <% if (group.status !== auditConst.status.uncheck) { %>
+                                            <span class="pull-right <%- auditConst.statusClass[group.status] %>"><%- auditConst.statusString[group.status] %></span>
+                                            <% } %>
+                                        </div>
+                                        <div class="card">
+                                            <div class="card-body px-3 py-0">
+                                                <% for (const [i, auditor] of group.auditors.entries()) { %>
+                                                <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
+                                                    <div class="col">
+                                                        <span class="h6"><%- auditor.name %></span>
+                                                        <span class="text-muted ml-1"><%- auditor.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <% if (auditor.status === auditConst.status.checked) { %>
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                        <% } else if (auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre || auditor.status === auditConst.status.checkCancel) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                        <% } %>
+                                                    </div>
+                                                    <% if (auditor.opinion) { %>
+                                                    <div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i><%- auditor.opinion%></div>
+                                                    <% } %>
                                                 </div>
+                                                <% } %>
                                             </div>
-                                            <!--审批意见-->
-                                            <% if (auditor.opinion) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } %>
                                 <% }) %>
                             </ul>
                         </div>
@@ -472,7 +474,6 @@
 </div>
 <% } %>
 
-<% console.log(ctx.session.sessionUser.accountId, ctx.tender.data.user_id, ctx.session.sessionUser.is_admin) %>
 <% if ((ctx.session.sessionUser.accountId === ctx.tender.data.user_id || ctx.session.sessionUser.is_admin) && (ctx.tender.data.ledger_status === auditConst.status.uncheck || ctx.tender.data.ledger_status === auditConst.status.checkNo)) { %>
     <script>
         const shenpi_status = <%- ctx.tender.info.shenpi.ledger %>;

+ 4 - 0
sql/update.sql

@@ -460,6 +460,10 @@ ALTER TABLE `calculation`.`zh_revise_audit`
 ADD COLUMN `audit_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '审批类型' AFTER `audit_order`,
 ADD COLUMN `audit_ledger_id` varchar(5000) NOT NULL DEFAULT '' COMMENT '审批台账id' AFTER `audit_type`;
 
+ALTER TABLE `calculation`.`zh_tender_cache`
+MODIFY COLUMN `ledger_flow_cur_uid` varchar(1000) NOT NULL DEFAULT '0' COMMENT '台账-当前流程人id' AFTER `ledger_status`,
+MODIFY COLUMN `ledger_flow_pre_uid` varchar(1000) NOT NULL DEFAULT '0' COMMENT '台账-上一流程人id' AFTER `ledger_flow_cur_info`;
+
 -- update请放在最后
 
 Update zh_filing_template SET is_fixed = 1 WHERE tree_level = 1;