Przeglądaj źródła

台账修订,会签或签上报相关

MaiXinRong 9 miesięcy temu
rodzic
commit
824d5cf4ed

+ 8 - 21
app/controller/revise_controller.js

@@ -289,30 +289,19 @@ module.exports = app => {
                 revise.status === audit.revise.status.checking || revise.status === audit.revise.status.checked);
             const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
                 ctx.tender.data.valuation, ctx.tender.data.measure_type);
-            const curAuditor = await ctx.service.reviseAudit.getCurAuditor(revise.id, revise.times);
-            const user = await ctx.service.projectAccount.getAccountInfoById(revise.uid);
-            const times = revise.status === audit.revise.status.checkNo ? revise.times - 1 : revise.times;
-            const auditors = revise.status === audit.revise.status.checkNo && revise.uid === ctx.session.sessionUser.accountId ?
-                await ctx.service.reviseAudit.getAuditorsWithOwner(revise.id, revise.times) :
-                await ctx.service.reviseAudit.getAuditorsWithOwner(revise.id, times);
-            const auditHistory = [];
-            if (times >= 1) {
-                for (let i = 1; i <= times; i++) {
-                    auditHistory.push(await ctx.service.reviseAudit.getAuditors(revise.id, i));
-                }
-            }
+
+            await ctx.service.reviseAudit.loadReviseUser(revise);
+            await ctx.service.reviseAudit.loadReviseAuditViewData(revise);
+
             return {
                 revise, tender: ctx.tender.data,
                 ledgerSpread, posSpread, tenderMenu, measureType,
                 audit: audit.revise,
+                auditType: audit.auditType,
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.info),
                 stdBills,
                 auditConst: audit.revise,
                 stdChapters,
-                curAuditor,
-                auditors,
-                user,
-                auditHistory,
                 shenpiConst,
                 nodeType: stdConst.nodeType,
                 settleStatus: ctx.service.settle.settleStatus,
@@ -352,7 +341,6 @@ module.exports = app => {
             renderData.posSpread.readOnly = true;
             renderData.history = false;
             renderData.historyRevise = [];
-            renderData.curAuditor = await ctx.service.reviseAudit.getCurAuditor(revise.id, revise.times);
             renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
             renderData.preUrl = ctx.url.replace('/info', '');
             await this.layout('revise/info.ejs', renderData, 'revise/info_modal.ejs');
@@ -376,8 +364,6 @@ module.exports = app => {
                 const groupList = renderData.accountList.filter(item1 => item1.company === item.name);
                 return { groupName: item.name, groupList };
             });
-            renderData.auditorList = await ctx.service.reviseAudit.getAuditors(revise.id, revise.times);
-            renderData.curAuditor = await ctx.service.reviseAudit.getCurAuditor(revise.id, revise.times);
             renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.session.sessionProject.id);
             renderData.preUrl = ctx.url.replace('/info', '');
             await this.layout('revise/info.ejs', renderData, 'revise/info_modal.ejs');
@@ -841,8 +827,9 @@ module.exports = app => {
                 const revise = ctx.revise;
                 if (!revise || revise.status !== audit.revise.status.checking) throw '台账修订数据有误';
 
-                const curAudit = await ctx.service.reviseAudit.getCurAuditor(revise.id, revise.times);
-                if (curAudit.audit_id !== ctx.session.sessionUser.accountId) throw '审批失败';
+                const curAudits = await ctx.service.reviseAudit.getCurAuditors(revise.id, revise.times);
+                const curAuditorIds = curAudits.map(x => { return x.audit_id; });
+                if (curAuditorIds.indexOf(ctx.session.sessionUser.accountId) < 0) throw '审批失败';
 
                 const checkType = parseInt(ctx.request.body.checkType);
                 if (!checkType || isNaN(checkType)) throw '提交数据错误';

+ 1 - 1
app/middleware/ledger_audit_check.js

@@ -38,7 +38,7 @@ const checkAuditFlow = async function(ctx) {
     } 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; });
+        const lastAuditors = auditList.filter(x => { x.order === auditList[auditList.length - 1].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) {

+ 41 - 39
app/middleware/revise_audit_check.js

@@ -12,6 +12,44 @@ const status = require('../const/audit').revise.status;
 const shenpiConst = require('../const/shenpi');
 const _ = require('lodash');
 
+const checkAuditFlow = async function(ctx) {
+    const info = ctx.tender.info;
+    const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+    if (!revise) throw '台账修订数据有误';
+
+    if (info.shenpi.revise === shenpiConst.sp_status.sqspr) return;
+    if (revise.status !== status.uncheck && revise.status !== status.checkNo) return;
+
+    const shenpi_status = info.shenpi.ledger;
+    // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
+    const auditList = await ctx.service.reviseAudit.getAuditors(revise.id, revise.times);
+    if (shenpi_status === shenpiConst.sp_status.gdspl) {
+        const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: revise.tid, sp_type: shenpiConst.sp_type.revise, 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.reviseAudit.updateNewAuditList(revise, shenpiList);
+    } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
+        const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: revise.tid, sp_type: shenpiConst.sp_type.revise, sp_status: shenpi_status });
+        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+        const lastAuditors = auditList.filter(x => { x.order === auditList[auditList.length - 1].order; });
+        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {
+            await ctx.service.reviseAudit.updateLastAudit(revise, auditList, shenpiInfo.audit_id);
+        } else if (!shenpiInfo) {
+            // 不存在终审人的状态下这里恢复为授权审批人
+            info.shenpi.revise = shenpiConst.sp_status.sqspr;
+        }
+    }
+};
+
 module.exports = options => {
     /**
      * 标段校验 中间件
@@ -23,46 +61,10 @@ module.exports = options => {
      */
     return function* reviseAuditCheck(next) {
         try {
-            // 获取revise
-            const revise = yield this.service.ledgerRevise.getLastestRevise(this.tender.id);
-            if (!revise) throw '台账修订数据有误';
-            if ((revise.status === status.uncheck || revise.status === status.checkNo) && this.tender.info.shenpi.revise !== shenpiConst.sp_status.sqspr) {
-                const shenpi_status = this.tender.info.shenpi.revise;
-                // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.reviseAudit.getAllDataByCondition({ where: { rid: revise.id, times: revise.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.revise, sp_status: shenpi_status } });
-                    const shenpiIdList = _.map(shenpiList, 'audit_id');
-                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    if (!_.isEqual(auditIdList, shenpiIdList)) {
-                        yield this.service.reviseAudit.updateNewAuditList(revise, 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.revise, sp_status: shenpi_status });
-                    // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
-                    if (shenpiInfo && shenpiInfo.audit_id !== _.last(auditIdList)) {
-                        yield this.service.reviseAudit.updateLastAudit(revise, auditList, shenpiInfo.audit_id);
-                    } else if (!shenpiInfo) {
-                        // 不存在终审人的状态下这里恢复为授权审批人
-                        this.tender.info.shenpi.revise = shenpiConst.sp_status.sqspr;
-                    }
-                }
-            }
-            yield next;
+            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);
         }

+ 1 - 1
app/middleware/stage_check.js

@@ -167,7 +167,7 @@ module.exports = options => {
                 } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
                     const shenpiInfo = yield this.service.shenpiAudit.getDataByCondition({ tid: stage.tid, sp_type: shenpiConst.sp_type.stage, sp_status: shenpi_status });
                     // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
-                    const lastAuditors = auditList.filter(x => { x.order === auditList.order; });
+                    const lastAuditors = auditList.filter(x => { x.order === auditList[auditList.length - 1].order; });
                     if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
                         yield this.service.stageAudit.updateLastAudit(stage, auditList, shenpiInfo.audit_id);
                         yield this.service.stage.loadStageUser(stage);

+ 17 - 10
app/service/ledger_audit.js

@@ -271,7 +271,7 @@ module.exports = app => {
             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.userIds = tender.ledger_status === status.uncheck // 当前流程下全部参与人id
                 ? [tender.user_id]
                 : [tender.user_id, ...tender.userAssistIds, ...tender.auditorIds, ...tender.auditAssistIds];
         }
@@ -365,7 +365,6 @@ 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();
@@ -856,14 +855,22 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
-                const idList = this._.map(auditList, 'audit_id');
-                let order = idList.length + 1;
-                if (idList.indexOf(lastId) !== -1) {
-                    await transaction.delete(this.tableName, { tender_id: tender.id, times: tender.ledger_times, audit_id: lastId });
-                    const audit = this._.find(auditList, { 'audit_id': lastId });
-                    // 顺移之后审核人流程顺序
-                    await this._syncOrderByDelete(transaction, tender.id, audit.audit_order, tender.ledger_times);
-                    order = order - 1;
+                const existAudit = auditList.find(x => { return x.aid === lastId });
+                let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.audit_order)}, 0) + 1 : 1; // 最大值 + 1
+                if (existAudit) {
+                    await transaction.delete(this.tableName, { sid: stage.id, times: stage.times, audit_id: lastId });
+                    const sameOrder = auditList.filter(x => { return x.audit_order === existAudit.audit_order });
+                    if (sameOrder.length === 1) {
+                        const updateData = [];
+                        auditList.forEach(x => {
+                            if (x.audit_order <= existAudit.audit_order) return;
+                            updateData.push({id: x.id, audit_order: x.audit_order - 1});
+                        });
+                        if (updateData.length > 0) {
+                            await transaction.updateRows(updateData);
+                        }
+                        order = order - 1;
+                    }
                 }
 
                 // 添加终审

+ 2 - 0
app/service/ledger_revise.js

@@ -159,6 +159,8 @@ module.exports = app => {
                     in_time: inTime,
                     audit_order: newAuditors.length + 1,
                     audit_id: a.audit_id,
+                    audit_type: a.audit_type,
+                    audit_ledger_id: a.audit_ledger_id,
                     times: 1,
                     status: audit.status.uncheck,
                 });

+ 273 - 50
app/service/revise_audit.js

@@ -9,6 +9,7 @@
  */
 
 const auditConst = require('../const/audit').revise;
+const auditType = require('../const/audit').auditType;
 const smsTypeConst = require('../const/sms_type');
 const SmsAliConst = require('../const/sms_alitemplate');
 const wxConst = require('../const/wechat_template');
@@ -47,6 +48,52 @@ module.exports = app => {
             return await this.db.queryOne(sql, sqlParam);
         }
 
+        async getAuditorByOrder(reviseId, 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.`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.`rid` = ? and la.`audit_order` = ? and la.`times` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, reviseId, order, times];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        async getAuditorsByOrder(reviseId, 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.`rid` = ? and la.`audit_order` = ? and la.`times` = ?' +
+                '  ORDER BY `audit_order` DESC';
+            const sqlParam = [reviseId, order, times ? times: 1];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        async getLatestAuditor(reviseId, times, status) {
+            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 ' + this.tableName + ' AS la' +
+                '    Left Join ' + this.ctx.service.projectAccount.tableName + ' AS pa ON la.`audit_id` = pa.`id`' +
+                '  WHERE la.`rid` = ? and la.`status` = ? and la.`times` = ?' +
+                '  ORDER BY `audit_order` DESC';
+            const sqlParam = [reviseId, status, times ? times : 1];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        async getLatestAuditors(reviseId, 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.`rid` = ? and la.`status` = ? and la.`times` = ?' +
+                '  ORDER BY `audit_order` DESC';
+            const sqlParam = [reviseId, 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 });
+        }
+
         /**
          * 获取标段审核列表信息
          *
@@ -54,16 +101,19 @@ module.exports = app => {
          * @param {Number} times - 第几次审批
          * @return {Promise<*>}
          */
-        async getAuditors(reviseId, times = 1) {
-            const sql =
-                'SELECT la.`audit_id`, la.`times`, la.`audit_order`, la.`status`, la.`opinion`, la.`begin_time`, la.`end_time`,' +
-                '    pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`' +
-                '  FROM ' + this.tableName + ' AS la ' +
-                '  INNER JOIN ' + this.ctx.service.projectAccount.tableName +
-                ' AS pa ON la.`rid` = ? and la.`times` = ? and la.`audit_id` = pa.`id`' +
-                '  ORDER BY la.`audit_order`';
+        async getAuditors(reviseId, 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.rid = ? AND la.times = ?' +
+                '  ORDER BY la.audit_order ' + order_sort;
             const sqlParam = [reviseId, times];
-            return await this.db.query(sql, sqlParam);
+            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;
         }
 
         /**
@@ -105,6 +155,173 @@ module.exports = app => {
             return await this.db.queryOne(sql, sqlParam);
         }
 
+        async getCurAuditors(reviseId, 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.`rid` = ? and la.`status` = ? and la.`times` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, reviseId, auditConst.status.checking, times];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        async getAuditorGroup(reviseId, times) {
+            const auditors = await this.getAuditors(reviseId, times); // 全部参与的审批人
+            return this.ctx.helper.groupAuditors(auditors, 'audit_order');
+        }
+
+        async getUserGroup(reviseId, times) {
+            const group = await this.getAuditorGroup(reviseId, times);
+            const sql =
+                'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As rid, 0 As audit_order, 1 As audit_type' +
+                '  FROM ' + this.ctx.service.ledgerRevise.tableName + ' As r' +
+                '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
+                '  ON r.uid = pa.id' +
+                '  WHERE r.id = ?';
+            const sqlParam = [times, reviseId, reviseId];
+            const user = await this.db.queryOne(sql, sqlParam);
+            group.unshift([ user ]);
+            return group;
+        }
+
+        async getUniqUserGroup(reviseId, times) {
+            const group = await this.getAuditorGroup(reviseId, times);
+            const sql =
+                'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As rid, 0 As audit_order, 1 As audit_type' +
+                '  FROM ' + this.ctx.service.ledgerRevise.tableName + ' As r' +
+                '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
+                '  ON r.uid = pa.id' +
+                '  WHERE r.id = ?';
+            const sqlParam = [times, reviseId, reviseId];
+            const user = await this.db.queryOne(sql, sqlParam);
+            group.unshift([ user ]);
+            return this.ctx.helper.groupAuditorsUniq(group, 'audit_order');
+        }
+
+        async getAuditorHistory(reviseId, times, reverse = false) {
+            const history = [];
+            if (times >= 1) {
+                for (let i = 1; i <= times; i++) {
+                    const auditors = await this.getAuditors(reviseId, 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(reviseId, times) {
+            const auditors = await this.getAuditors(reviseId, 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 loadReviseUser(revise) {
+            const status = auditConst.status;
+            const accountId = this.ctx.session.sessionUser.accountId;
+
+            revise.user = await this.ctx.service.projectAccount.getAccountInfoById(revise.uid);
+            revise.auditors = await this.getAuditors(revise.id, revise.times); // 全部参与的审批人
+            revise.auditorIds = this._.map(revise.auditors, 'audit_id');
+            revise.curAuditors = revise.auditors.filter(x => { return x.status === status.checking; }); // 当前流程中审批中的审批人
+            revise.curAuditorIds = this._.map(revise.curAuditors, 'audit_id');
+            revise.flowAuditors = revise.curAuditors.length > 0 ? revise.auditors.filter(x => { return x.audit_order === revise.curAuditors[0].audit_order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)
+            revise.flowAuditorIds = this._.map(revise.flowAuditors, 'audit_id');
+            revise.nextAuditors = revise.curAuditors.length > 0 ? revise.auditors.filter(x => { return x.audit_order === revise.curAuditors[0].audit_order + 1; }) : [];
+            revise.nextAuditorIds = this._.map(revise.nextAuditors, 'audit_id');
+            revise.auditorGroups = this.ctx.helper.groupAuditors(revise.auditors, 'audit_order');
+            console.log(revise.auditorGroups);
+            revise.userGroups = this.ctx.helper.groupAuditorsUniq(revise.auditorGroups);
+            revise.userGroups.unshift([{
+                aid: revise.user.id, order: 0, times: revise.times, audit_order: 0, audit_type: auditType.key.common,
+                name: revise.user.name, role: revise.user.role, company: revise.user.company
+            }]);
+            revise.finalAuditorIds = revise.userGroups[revise.userGroups.length - 1].map(x => { return x.aid; });
+            revise.relaAuditor = revise.auditors.find(x => { return x.aid === accountId });
+
+            revise.assists = [];// await this.service.ledgerAuditAss.getData(tender); // 全部协同人
+            revise.assists = revise.assists.filter(x => {
+                return x.user_id === revise.uid || revise.auditorIds.indexOf(x.uid) >= 0;
+            }); // 过滤无效协同人
+            revise.userAssists = revise.assists.filter(x => { return x.user_id === revise.uid; }); // 原报协同人
+            revise.userAssistIds = this._.map(revise.userAssists, 'ass_user_id');
+            revise.auditAssists = revise.assists.filter(x => { return x.user_id !== revise.uid; }); // 审批协同人
+            revise.auditAssistIds = this._.map(revise.auditAssists, 'ass_user_id');
+            revise.relaAssists = revise.assists.filter(x => { return x.user_id === accountId }); // 登录人的协同人
+            revise.userIds = revise.status === status.uncheck // 当前流程下全部参与人id
+                ? [revise.user_id, ...revise.userAssistIds]
+                : [revise.user_id, ...revise.userAssistIds, ...revise.auditorIds, ...revise.auditAssistIds];
+        }
+
+        async loadReviseAuditViewData(revise) {
+            const times = revise.status === auditConst.status.checkNo ? revise.times - 1 : revise.times;
+
+            if (!revise.user) revise.user = await this.ctx.service.projectAccount.getAccountInfoById(revise.uid);
+            revise.auditHistory = await this.getAuditorHistory(revise.id, times);
+            // 获取审批流程中左边列表
+            if (revise.status === auditConst.status.checkNo && revise.user_id !== this.ctx.session.sessionUser.accountId) {
+                const auditors = await this.getAuditors(revise.id, times); // 全部参与的审批人
+                const auditorGroups = this.ctx.helper.groupAuditors(auditors, 'audit_order');
+                revise.auditors2 = this.ctx.helper.groupAuditorsUniq(auditorGroups, 'audit_order');
+                revise.auditors2.unshift([{
+                    aid: revise.user.id, order: 0, times: revise.times - 1, audit_order: 0, audit_type: auditConst.auditType.key.common,
+                    name: revise.user.name, role: revise.user.role, company: revise.user.company
+                }]);
+            } else {
+                revise.auditors2 = revise.userGroups;
+            }
+            if (revise.status === auditConst.status.uncheck || revise.status === auditConst.status.checkNo) {
+                revise.auditorList = await this.getAuditors(revise.id, revise.times);
+            }
+        }
+
         /**
          * 获取最新审核顺序
          *
@@ -222,8 +439,8 @@ module.exports = app => {
          * @return {Promise<boolean>}
          */
         async start(revise, times = 1) {
-            const audit = await this.getDataByCondition({ rid: revise.id, times, audit_order: 1 });
-            if (!audit) {
+            const audits = await this.getAllDataByCondition({ where: { rid: revise.id, times, audit_order: 1 } });
+            if (!audits.length === 0) {
                 if(this.ctx.tender.info.shenpi.revise === shenpiConst.sp_status.gdspl) {
                     throw '请联系管理员添加审批人';
                 } else {
@@ -237,21 +454,17 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
-                await transaction.update(this.tableName, {
-                    id: audit.id,
-                    status: auditConst.status.checking,
-                    begin_time: time,
-                    bills_file: revise.bills_file,
-                    pos_file: revise.pos_file,
-                });
+                const updateAuditData = audits.map(a => { return {
+                    id: a.id, status: auditConst.status.checking, begin_time: time,
+                    bills_file: revise.bills_file, pos_file: revise.pos_file
+                }; });
+                await transaction.updateRows(this.tableName, updateAuditData);
                 const reviseData = {
                     id: revise.id,
                     status: auditConst.status.checking,
                     his_id, sum: JSON.stringify(sum),
                 };
-                if (revise.times === 1) {
-                    reviseData.begin_time = time;
-                }
+                if (revise.times === 1) reviseData.begin_time = time;
                 await transaction.update(this.ctx.service.ledgerRevise.tableName, reviseData);
 
                 // 投资进度改变状态
@@ -261,7 +474,8 @@ module.exports = app => {
                 // 下一人
                 // await this.ctx.helper.sendUserSms(audit.audit_id, smsTypeConst.const.XD,
                 //     smsTypeConst.judge.approval.toString(), '台账修订需要您审批,请登录系统处理。');
-                await this.ctx.helper.sendAliSms(audit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
+                const auditorIds = audits.map(x => { return x.audit_id; });
+                await this.ctx.helper.sendAliSms(auditorIds, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
                 // 微信模板通知
                 const shenpiUrl = await this.ctx.helper.urlToShort(
                     this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + revise.tid + '/revise/' + revise.id + '/info'
@@ -273,20 +487,22 @@ module.exports = app => {
                     code: this.ctx.session.sessionProject.code,
                     begin_time: Date.parse(time),
                 };
-                await this.ctx.helper.sendWechat(audit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), wxConst.template.revise, wechatData);
-                await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.XD, {
-                    pid: this.ctx.session.sessionProject.id,
-                    tid: this.ctx.tender.id,
-                    uid: audit.audit_id,
-                    sp_type: 'revise',
-                    sp_id: audit.id,
-                    table_name: this.tableName,
-                    template: wxConst.template.revise,
-                    wx_data: wechatData,
-                });
+                await this.ctx.helper.sendWechat(auditorIds, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), wxConst.template.revise, wechatData);
+                for (const audit of audits) {
+                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.XD, {
+                        pid: this.ctx.session.sessionProject.id,
+                        tid: this.ctx.tender.id,
+                        uid: audit.audit_id,
+                        sp_type: 'revise',
+                        sp_id: audit.id,
+                        table_name: this.tableName,
+                        template: wxConst.template.revise,
+                        wx_data: wechatData,
+                    });
+                }
                 // 其他参与人
                 const auditList = await this.getAuditors(revise.id, times);
-                const users = this._.pull(this._.map(auditList, 'user_id'), audit.audit_id);
+                const users = this._.map(auditList.filter(x => { return auditorIds.indexOf(x.audit_id) < 0; }, 'audit_id'));
                 // await this.ctx.helper.sendUserSms(users, smsTypeConst.const.XD,
                 //     smsTypeConst.judge.result.toString(), '台账修订已上报。');
                 await this.ctx.helper.sendAliSms(users, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), SmsAliConst.template.revise_report);
@@ -808,20 +1024,19 @@ module.exports = app => {
             return this.db.query(sql, sqlParam);
         }
 
-        async updateNewAuditList(revise, newIdList) {
+        async updateNewAuditList(revise, newList) {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先删除旧的审批流,再添加新的
                 await transaction.delete(this.tableName, { rid: revise.id, times: revise.times });
                 const newAuditors = [];
-                let order = 1;
-                for (const aid of newIdList) {
+                const in_time = new Date();
+                for (const auditor of newList) {
                     newAuditors.push({
-                        tender_id: revise.tid, audit_id: aid,
-                        times: revise.times, audit_order: order, status: auditConst.status.uncheck,
-                        rid: revise.id,in_time: new Date(),
-                    });
-                    order++;
+                        tender_id: revise.tid, audit_id: auditor.audit_id, rid: revise.id, in_time,
+                        times: revise.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();
@@ -835,14 +1050,22 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
-                const idList = this._.map(auditList, 'audit_id');
-                let order = idList.length + 1;
-                if (idList.indexOf(lastId) !== -1) {
-                    await transaction.delete(this.tableName, { rid: revise.id, times: revise.times, audit_id: lastId });
-                    const audit = this._.find(auditList, { 'audit_id': lastId });
-                    // 顺移之后审核人流程顺序
-                    await this._syncOrderByDelete(transaction, revise.id, audit.audit_order, revise.times);
-                    order = order - 1;
+                const existAudit = auditList.find(x => { return x.aid === lastId });
+                let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.audit_order)}, 0) + 1 : 1; // 最大值 + 1
+                if (existAudit) {
+                    await transaction.delete(this.tableName, { sid: stage.id, times: stage.times, audit_id: lastId });
+                    const sameOrder = auditList.filter(x => { return x.audit_order === existAudit.audit_order });
+                    if (sameOrder.length === 1) {
+                        const updateData = [];
+                        auditList.forEach(x => {
+                            if (x.audit_order <= existAudit.audit_order) return;
+                            updateData.push({id: x.id, audit_order: x.audit_order - 1});
+                        });
+                        if (updateData.length > 0) {
+                            await transaction.updateRows(updateData);
+                        }
+                        order = order - 1;
+                    }
                 }
 
                 // 添加终审

+ 1 - 1
app/view/revise/info.ejs

@@ -58,7 +58,7 @@
                 <% } %>
                 <% if (revise.status === audit.status.checking) { %>
                 <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-dark mr-1">审批中</a>
-                    <% if (curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                    <% if (revise.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>
                     <% } %>

Plik diff jest za duży
+ 400 - 470
app/view/revise/info_modal.ejs


+ 4 - 4
sql/update.sql

@@ -453,14 +453,14 @@ ADD COLUMN `audit_ledger_id` varchar(5000) NOT NULL DEFAULT '' COMMENT '审批
 ADD COLUMN `audit_locked` tinyint(1) NOT NULL DEFAULT 0  COMMENT '审批锁定(仅协审用)' AFTER `audit_ledger_id`;
 
 ALTER TABLE `zh_ledger_audit`
-ADD COLUMN `audit_type` tinyint(4) NOT NULL DEFAULT 0  COMMENT '审批类型' AFTER `audit_order`,
+ADD COLUMN `audit_type` tinyint(4) NOT NULL DEFAULT 1  COMMENT '审批类型' AFTER `audit_order`,
 ADD COLUMN `audit_ledger_id` varchar(5000) NOT NULL DEFAULT '' COMMENT '审批台账id' AFTER `audit_id`;
 
-ALTER TABLE `calculation`.`zh_revise_audit`
-ADD COLUMN `audit_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '审批类型' AFTER `audit_order`,
+ALTER TABLE `zh_revise_audit`
+ADD COLUMN `audit_type` tinyint(4) NOT NULL DEFAULT 1 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`
+ALTER TABLE `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`;