| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375 | 'use strict';/** * * * @author Mai * @date 2018/8/14 * @version */const auditConst = require('../const/audit').change;const auditType = require('../const/audit').auditType;const pushType = require('../const/audit').pushType;const shenpiConst = require('../const/shenpi');const smsTypeConst = require('../const/sms_type');const SMS = require('../lib/sms');const SmsAliConst = require('../const/sms_alitemplate');const wxConst = require('../const/wechat_template');module.exports = app => {    class ChangeAudit extends app.BaseService {        /**         * 构造函数         *         * @param {Object} ctx - egg全局变量         * @return {void}         */        constructor(ctx) {            super(ctx);            this.tableName = 'change_audit';        }        /**         * 获取最后一位审批人         * @param {int} cid - 变更令id         * @param {int} times - 次数         * @param {int} site - 位置         * @param {int} status - 状态         * @return {void}         */        async getLastUser(cid, times, site = 1, status = 1) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('cid', {                value: this.db.escape(cid),                operate: '=',            });            this.sqlBuilder.setAndWhere('times', {                value: times,                operate: '=',            });            if (status === 1) {                this.sqlBuilder.setAndWhere('status', {                    value: 1,                    operate: '!=',                });            }            if (site === 0) {                this.sqlBuilder.setAndWhere('usite', {                    value: site,                    operate: '=',                });            }            const u_sort = [['usort', 'DESC']];            this.sqlBuilder.orderBy = u_sort;            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.queryOne(sql, sqlParam);            return data;        }        /**         * 获取最后一位退回的审批人         * @param {int} cid - 变更令id         * @param {int} times - 次数         * @return {void}         */        async getLastBackUser(cid, times) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('cid', {                value: this.db.escape(cid),                operate: '=',            });            this.sqlBuilder.setAndWhere('times', {                value: times,                operate: '=',            });            this.sqlBuilder.setAndWhere('status', {                value: auditConst.status.checkNoPre,                operate: '=',            });            const u_sort = [['usort', 'DESC']];            this.sqlBuilder.orderBy = u_sort;            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);            const data = await this.db.queryOne(sql, sqlParam);            return data;        }        /**         * 根据用户查看此变更状态获取审批人列表         * @param {Object} change - 变更令         * @param {int} status - 状态         * @return {object} list - 列表         */        async getListByStatus(change, status) {            let sql = '';            let sqlParam = '';            switch (status) {                case 1:// 待上报                case 2:// 待重新上报                case 9:// 待修订                    sql = 'SELECT * FROM ?? WHERE ' +                        'cid = ? AND times = ? GROUP BY usite ORDER BY usort asc';                    sqlParam = [this.tableName, change.cid,                        change.times];                    break;                case 3: // 被退回但你不是原报人                case 4:// 已完成                case 5:// 已终止                case 7:// 审批中但你未到你审批或你已审批                case 8:// 游客                    // 获取完整的审批顺序                    sql = 'SELECT * FROM ?? WHERE ' +                        'cid = ? ORDER BY usort';                    sqlParam = [this.tableName, change.cid];                    break;                case 6: // 审批中                    sql = 'SELECT * FROM (SELECT MAX(usort) as ust FROM ?? ' +                        'WHERE cid = ? and times = ? GROUP BY usite ) as b ' +                        'JOIN ?? as a ON a.usort = b.ust WHERE cid = ? and times = ? ORDER BY usite asc';                    sqlParam = [this.tableName, change.cid, change.times, this.tableName, change.cid, change.times];                    // sql = 'SELECT * FROM ?? WHERE ' +                    //     'cid = ? AND times = ? ORDER BY usort';                    // sqlParam = [this.tableName, change.cid, change.times];                    break;                default:// 无权限查看此变更令                    break;            }            const list = await this.db.query(sql, sqlParam);            return list;        }        /**         * 删除变更令审批人列表         * @param {Object} transaction - 事务         * @param {Object} cid - 变更令id         * @param {int} times - 次数         * @return {object} 返回结果         */        async deleteAuditData(transaction, cid, times) {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('cid', {                value: this.db.escape(cid),                operate: '=',            });            this.sqlBuilder.setAndWhere('times', {                value: times,                operate: '=',            });            this.sqlBuilder.setAndWhere('usite', {                value: 0,                operate: '!=',            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'delete');            const result = await transaction.query(sql, sqlParam);            return result;        }        /**         * 获取不重复列表         * @param {Object} cid - 变更令id         * @param {int} times - 次数         * @return {object} 返回结果         */        async getListGroupByTimes(cid, times) {            const sql = 'SELECT * FROM ?? where id in (SELECT MAX(id) FROM ?? WHERE ' +                'cid = ? AND times = ? GROUP BY usite) ORDER BY usite asc';            const sqlParam = [this.tableName, this.tableName, cid, times];            const list = await this.db.query(sql, sqlParam);            return list;        }        /**         * 获取不重复列表         * @param {Object} cid - 变更令id         * @param {int} times - 次数         * @return {object} 返回结果         */        async getListGroupByWithoutYB(cid, times, transaction = null) {            const sql = 'SELECT * FROM ?? where cid = ? AND times = ? AND usite != 0 AND usort in (SELECT MAX(usort) FROM ?? WHERE ' +                'cid = ? AND times = ? AND usite != 0 GROUP BY usite) ORDER BY usite asc';            const sqlParam = [this.tableName, cid, times, this.tableName, cid, times];            const list = transaction ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);            return list;        }        async getListOrderByTimes(cid, times) {            const sql = 'SELECT * FROM ?? WHERE ' +                'cid = ? AND times = ? ORDER BY usort';            const sqlParam = [this.tableName, cid, times];            const list = await this.db.query(sql, sqlParam);            return list;        }        async getListGroupByTimesWithDetail(cid, times) {            const sql = 'SELECT *, pa.name, pa.company, pa.role, pa.mobile, pa.telephone FROM ' + this.tableName + ' ca ' +                '  Left Join ' + this.ctx.service.projectAccount.tableName + ' pa On ca.uid = pa.id' +                '  where id in (SELECT MAX(id) FROM ' + this.tableName +' WHERE cid = ? AND times = ? GROUP BY usite)' +                '  ORDER BY usite asc';            const sqlParam = [cid, times];            const list = await this.db.query(sql, sqlParam);            return list;        }        /**         * 获取 审核人 待审批的() 变更令列表         * @param uid         * @return {Promise<void>}         */        async getAuditChange(uid) {            // const sql = 'SELECT ca.`uid`, ca.`times`, ca.`usite`, ca.`usort`, ca.`tid`, ca.`cid`, ca.`begin_time`, ca.`end_time`, ca.`sin_time`, ca.`name` As `caname`, ' +            //     '    c.`code` As `ccode`, c.`name` As `cname`, c.`status` As `cstatus`, c.`cin_time`, ' +            //     '    t.`name`, t.`type`, t.`user_id` ' +            //     '  FROM ?? AS ca, ?? AS c, ?? As t ' +            //     '  WHERE ca.`uid` = ? and ca.`status` = ? and c.`status` != ?' +            //     '    and ca.`cid` = c.`cid` and ca.`tid` = t.`id` ORDER BY ca.`sin_time` DESC';            const sql = 'SELECT ca.`uid`, ca.`times`, ca.`usite`, ca.`usort`, ca.`tid`, ca.`cid`, ca.`begin_time`, ca.`end_time`, ca.`sin_time`, ca.`name` As `caname`, ' +                '    c.`code` As `ccode`, c.`name` As `cname`, c.`status` As `cstatus`, c.`cin_time`, ' +                '    t.`name`, t.`type`, t.`user_id` ' +                '  FROM ?? AS ca LEFT JOIN ?? AS c ON ca.`cid` = c.`cid` ' +                '    LEFT JOIN ?? As t ON ca.`tid` = t.`id` ' +                '  WHERE ca.`uid` = ? and ca.`status` = ? and c.`status` != ?' +                '  ORDER BY ca.`sin_time` DESC';            const sqlParam = [this.tableName, this.ctx.service.change.tableName, this.ctx.service.tender.tableName, uid, auditConst.status.checking, auditConst.status.uncheck];            const changes = await this.db.query(sql, sqlParam);            for (const c of changes) {                if (c.cstatus === auditConst.status.checkNo || c.cstatus === auditConst.status.revise) {                    const preSql = 'SELECT pa.`id`, pa.`account`, pa.`account_group`, pa.`name`, pa.`company`, pa.`role`, pa.`telephone` FROM ?? As ca, ?? As pa ' +                        '  WHERE ca.cid = ? and ca.times = ? and ca.status = ? and ca.uid = pa.id';                    const preSqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, c.cid, c.times - 1, c.cstatus];                    c.pre = await this.db.queryOne(preSql, preSqlParam);                } else {                    const preSql = 'SELECT pa.`id`, pa.`account`, pa.`account_group`, pa.`name`, pa.`company`, pa.`role`, pa.`telephone` FROM ?? As ca, ?? As pa ' +                        '  WHERE ca.cid = ? and ca.times = ? and ca.usort = ? and ca.uid = pa.id';                    const preSqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, c.cid, c.times, c.usort - 1];                    c.pre = await this.db.queryOne(preSql, preSqlParam);                }            }            return changes;        }        /**         * 获取审核人审核的次数         *         * @param auditorId         * @return {Promise<*>}         */        async getCountByChecked(auditorId) {            const sql = 'Select count(*) as count FROM ?? WHERE uid = ? AND usite != 0 AND status in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre]) +')';            const sqlParam = [this.tableName, auditorId];            const result = await this.db.queryOne(sql, sqlParam);            return result.count ? result.count : 0;            // return await this.db.count(this.tableName, { aid: auditorId, status: [auditConst.status.checked, auditConst.status.checkNo] });        }        /**         * 获取最近一次审批结束时间         *         * @param auditorId         * @return {Promise<*>}         */        async getLastEndTimeByChecked(auditorId) {            const sql = 'SELECT `sin_time` FROM ?? WHERE `uid` = ? AND usite != 0 ' +                'AND `status` in (' + this.ctx.helper.getInArrStrSqlFilter([auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre]) + ') ORDER BY `sin_time` DESC';            const sqlParam = [this.tableName, auditorId];            const result = await this.db.queryOne(sql, sqlParam);            return result ? result.sin_time : null;        }        /**         * 获取 某时间后 审批进度更新的 变更令         * @param {Number} pid - 查询标段         * @param {Number} uid - 查询人         * @param {Date} time - 查询时间         * @return {Promise<*>}         */        async getNoticeChange(pid, uid, time) {            // const sql = 'SELECT * FROM (SELECT t.`id`, t.`name`, t.`type`, t.`user_id`, ' +            //             '    ca.`cid`, c.`code` As `c_code`, c.name As `c_name`, ' +            //             '    ca.`uid`, ca.`sin_time` As `cu_time`, ca.`status` As `cu_status`, ca.`name` As `cu_name`, ca.`jobs` As `cu_jobs`, ca.company As `cu_company`' +            //             '  FROM (SELECT * FROM ?? WHERE `user_id` = ? OR `id` in (SELECT `tid` FROM ?? WHERE `uid` = ? GROUP BY `tid`)) As t' +            //             '  LEFT JOIN ?? As c ON c.`tid` = t.`id`' +            //             '  LEFT JOIN ?? As ca ON ca.`cid` = c.`cid`' +            //             '  WHERE t.`project_id` = ? and `ca`.`sin_time` > ? and `ca`.`usite` != 0 and `ca`.`status` != ?' +            //             '  ORDER By ca.`sin_time` DESC LIMIT 1000) as new_t GROUP BY new_t.`id`' +            //             '  ORDER BY new_t.`cu_time`';            // const sqlParam = [this.ctx.service.tender.tableName, uid, this.tableName, uid, this.ctx.service.change.tableName, this.tableName, pid, time, auditConst.status.checking];            // return await this.db.query(sql, sqlParam);            let notice = await this.db.select('zh_notice', {                where: { pid, type: pushType.change, uid },                orders: [['create_time', 'desc']],                limit: 10, offset: 0,            });            notice = notice.map(v => {                const extra = JSON.parse(v.content);                delete v.content;                return { ...v, ...extra };            });            return notice;        }        async getAllAuditors(tenderId) {            const sql = 'SELECT ca.uid, ca.tid FROM ' + this.tableName + ' ca' +                '  LEFT JOIN ' + this.ctx.service.tender.tableName + ' t On ca.tid = t.id' +                '  WHERE t.id = ?' +                '  GROUP BY ca.uid';            const sqlParam = [tenderId];            return this.db.query(sql, sqlParam);        }        /**         * 取待审批变更列表(wap用)         *         * @param auditorId         * @return {Promise<*>}         */        async getAuditChangeByWap(uid) {            const sql = 'SELECT ca.`uid`, ca.`times`, ca.`usite`, ca.`usort`, ca.`tid`, ca.`cid`, ca.`sin_time`, ca.`name` As `caname`, ' +                '    c.`code` As `ccode`, c.`name` As `cname`, c.`status` As `cstatus`, c.`quality`, c.`total_price`,' +                '    t.`name`, t.`type`, t.`user_id`, ' +                '    ti.`deal_info`, ti.`decimal` ' +                '  FROM ?? AS ca, ?? AS c, ?? As t, ?? AS ti ' +                '  WHERE ca.`uid` = ? and ca.`status` = ? and (c.`status` = ? or c.`status` = ?)' +                '    and ca.`cid` = c.`cid` and ca.`tid` = t.`id` and ti.`tid` = t.`id`';            const sqlParam = [this.tableName, this.ctx.service.change.tableName, this.ctx.service.tender.tableName, this.ctx.service.tenderInfo.tableName, uid, auditConst.status.checking, auditConst.status.checking, auditConst.status.checkNoPre];            const changes = await this.db.query(sql, sqlParam);            for (const c of changes) {                const preSql = 'SELECT pa.`id`, pa.`account`, pa.`account_group`, pa.`name`, pa.`company`, pa.`role`, pa.`telephone` FROM ?? As ca, ?? As pa ' +                    '  WHERE ca.cid = ? and ca.times = ? and ca.usort = ? and ca.uid = pa.id';                const preSqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, c.cid, c.times, c.usort - 1];                c.pre = await this.db.queryOne(preSql, preSqlParam);            }            return await this.db.query(sql, sqlParam);        }        async updateNewAuditList(change, newList) {            const transaction = await this.db.beginTransaction();            try {                await this.updateNewAuditors(change, newList, transaction);                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }        }        async updateNewAuditors(change, newList, transaction) {            // 先删除旧的审批流(除了原报),再添加新的            const sql = 'DELETE FROM ?? WHERE `cid`= ? AND `times` = ? AND `usite` != 0';            const sqlParam = [this.tableName, change.cid, change.times];            await transaction.query(sql, sqlParam);            const newAuditors = [];            // let uSort = await transaction.count(this.tableName, { cid: change.cid });            // let last_order = 0;            for (const auditor of newList) {                const accountInfo = await this.ctx.service.projectAccount.getDataById(auditor.audit_id);                newAuditors.push({                    tid: change.tid, cid: change.cid, uid: auditor.audit_id,                    name: accountInfo.name, jobs: accountInfo.role, company: accountInfo.company,                    times: change.times, usite: auditor.audit_order, usort: auditor.audit_order, status: auditConst.status.uncheck,                    audit_type: auditor.audit_type, audit_order: auditor.audit_order,                });                // if (auditor.audit_order !== last_order) {                //     last_order = auditor.audit_order;                //     uSort++;                // }            }            if (newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);            // 同步设置原报为usort为0            await transaction.update(this.tableName, { usort: 0 }, { where: { cid: change.cid, times: change.times, usite: 0 } });        }        async updateLastAudit(change, auditList, lastId) {            const transaction = await this.db.beginTransaction();            try {                // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order                const existAudit = auditList.find(x => { return x.uid === lastId && x.usite !== 0 });                let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.usort)}, 0) + 1 : 1; // 最大值 + 1                let audit_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, { cid: change.cid, times: change.times, uid: lastId });                    const sameOrder = auditList.filter(x => { return x.usort === existAudit.usort });                    if (sameOrder.length === 1) {                        const updateData = [];                        auditList.forEach(x => {                            if (x.usort <= existAudit.usort) return;                            updateData.push({id: x.id, usite: x.usite - 1, usort: x.usort - 1, audit_order: x.audit_order - 1});                        });                        if (updateData.length > 0) {                            await transaction.updateRows(updateData);                        }                        order = order - 1;                        audit_order = audit_order - 1;                    }                    // const sql = 'DELETE FROM ?? WHERE `cid`= ? AND `times` = ? AND `uid` = ? AND `usite` != 0';                    // const sqlParam = [this.tableName, change.cid, change.times, lastId];                    // await transaction.query(sql, sqlParam);                    // // await transaction.delete(this.tableName, { cid: change.cid, times: change.times, uid: lastId, usite: 0 });                    // const user = this._.find(auditList, { 'uid': lastId });                    // // 顺移之后审核人流程顺序                    // await this._syncOrderByDelete(transaction, change.cid, user.usite, user.usort, change.times);                    // order = order - 1;                }                // 添加终审                const userInfo = await this.ctx.service.projectAccount.getDataById(lastId);                // let uSort = await transaction.count(this.tableName, { cid: change.cid });                const newAuditor = {                    tid: change.tid, cid: change.cid, uid: lastId,                    name: userInfo.name, jobs: userInfo.role, company: userInfo.company,                    times: change.times, usite: audit_order, usort: order, status: auditConst.status.uncheck,                    audit_type: auditType.key.common, audit_order,                };                await transaction.insert(this.tableName, newAuditor);                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }        }        /**         * 移除审核人时,同步其后审核人order         * @param transaction - 事务         * @param {Number} changeId - 变更令id         * @param {Number} usite - 审核人id         * @param {Number} usort - 审核人id         * @param {Number} times - 第几次审批         * @return {Promise<*>}         * @private         */        async _syncOrderByDelete(transaction, changeId, usite, usort, times, selfOperate = '-') {            this.initSqlBuilder();            this.sqlBuilder.setAndWhere('cid', {                value: this.db.escape(changeId),                operate: '=',            });            this.sqlBuilder.setAndWhere('usite', {                value: usite,                operate: '>=',            });            this.sqlBuilder.setAndWhere('times', {                value: times,                operate: '=',            });            this.sqlBuilder.setUpdateData('usite', {                value: 1,                selfOperate: selfOperate,            });            this.sqlBuilder.setUpdateData('usort', {                value: 1,                selfOperate: selfOperate,            });            this.sqlBuilder.setUpdateData('audit_order', {                value: 1,                selfOperate: selfOperate,            });            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');            const data = await transaction.query(sql, sqlParam);            return data;        }        /**         * 获取 当前审核人         *         * @param {Number} cid - 期id         * @param {Number} times - 第几次审批         * @return {Promise<*>}         */        async getCurAuditor(cid, times = 1) {            const sql = 'SELECT * FROM ?? WHERE `cid` = ? and `status` = ? and `times` = ? and usite != 0';            const sqlParam = [this.tableName, cid, auditConst.status.checking, times];            return await this.db.queryOne(sql, sqlParam);        }        /**         * 获取 当前审核组         *         * @param {Number} cid - 期id         * @param {Number} times - 第几次审批         * @return {Promise<*>}         */        async getCurAuditors(cid, times = 1) {            const sql = 'SELECT * FROM ?? WHERE `cid` = ? and `status` = ? and `times` = ? and usite != 0';            const sqlParam = [this.tableName, cid, auditConst.status.checking, times];            return await this.db.query(sql, sqlParam);        }        /**         * 获取 审核人列表(除去原报)         *         * @param {Number} cid - 变更id         * @param {Number} times - 第几次审批         * @param {Boolean} includeOR - 是否包含原报         * @return {Promise<*>}         */        async getAuditors(cid, times = 1, includeOR = false) {            const sql = `SELECT * FROM ?? WHERE cid = ? and times = ?${includeOR ? '' : ' and usite != 0'}`;            // const sql = 'SELECT * FROM ?? WHERE `cid` = ? and `times` = ? and usite != 0';            const sqlParam = [this.tableName, cid, times];            return await this.db.query(sql, sqlParam);        }        /**         * new* 获取 审核列表信息(除去原报)         *         * @param {Number} stageId - 期id         * @param {Number} times - 第几次审批         * @param {Number} order_sort - 列表排序方式         * @return {Promise<*>}         */        async getAuditorsNew(cid, times = 1, order_sort = 'asc') {            const sql = 'SELECT la.id, la.uid, la.times, la.usite, la.usort, la.status, la.sdesc, la.begin_time, la.end_time, la.sin_time, la.audit_type, la.audit_order,' +                '    pa.name, pa.company, pa.role, pa.mobile, pa.telephone' +                `  FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.uid = pa.id` +                '  WHERE la.cid = ? AND la.times = ?' +                '  ORDER BY la.usort ' + order_sort;            const sqlParam = [cid, 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;        }        async getAuditorGroup(cid, times) {            const auditors = await this.getAuditorsNew(cid, times); // 全部参与的审批人            return this.ctx.helper.groupAuditors(auditors, 'usort');        }        async getUserGroup(cid, times) {            const group = await this.getAuditorGroup(cid, times);            // const sql =            //     'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As sid, 0 As `order`, 1 As audit_type, 0 As audit_order' +            //     '  FROM ' + this.ctx.service.change.tableName + ' As s' +            //     '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +            //     '  ON s.user_id = pa.id' +            //     '  WHERE s.id = ?';            // const sqlParam = [times, stageId, stageId];            // const user = await this.db.queryOne(sql, sqlParam);            // group.unshift([ user ]);            return group;        }        async getUniqUserGroup(cid, times) {            const group = await this.getAuditorGroup(cid, times);            // const sql =            //     'SELECT pa.`id` As aid, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As sid, 0 As `order`, 1 As audit_type, 0 As audit_order' +            //     '  FROM ' + this.ctx.service.stage.tableName + ' As s' +            //     '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +            //     '  ON s.user_id = pa.id' +            //     '  WHERE s.id = ?';            // const sqlParam = [times, stageId, stageId];            // const user = await this.db.queryOne(sql, sqlParam);            // user.audit_order = 0;            // group.unshift([ user ]);            return this.ctx.helper.groupAuditorsUniq(group);        }        async getUniqAuditor(cid, times) {            const auditors = await this.getAuditorsNew(cid, times); // 全部参与的审批人            const result = [];            auditors.forEach(x => {                if (result.findIndex(r => { return x.uid === r.uid && x.audit_order === r.audit_order; }) < 0) {                    result.push(x);                }            });            return result;        }        async getAuditorHistory(cid, times, reverse = false) {            const history = [];            if (times >= 1) {                for (let i = 1; i <= times; i++) {                    const auditors = await this.getAuditorsNew(cid, i);                    const group = this.ctx.helper.groupAuditors(auditors, 'usort');                    const historyGroup = [];                    // 找出group里audit_order最大值                    const max_info = group.length > 0 ? this._.maxBy(group, function (item) {                        return item && item[0] && item[0].audit_order;                    }) : null;                    const max_order = max_info ? max_info[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;        }        /**         * 获取审核人流程列表(除去原报)         *         * @param auditorId         * @return {Promise<*>}         */        async getAuditGroupByList(cid, times, transaction = false) {            // const sql =            //     'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`sid`, la.`aid`, la.`order`, la.`status`' +            //     '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +            //     '  WHERE la.`sid` = ? and la.`times` = ? and la.`is_old` = 0 GROUP BY la.`aid` ORDER BY la.`order`';            // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, stageId, times];            const sql =                'SELECT la.`uid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`usite`, la.`usort`, la.`status`, la.audit_type, la.audit_order' +                ' FROM (SELECT `uid`, max(`usort`) `usort` FROM ?? WHERE `cid` = ? and `times` = ? and `usite` != 0 GROUP BY uid) sa' +                ' LEFT JOIN ?? la ON sa.`uid` = la.`uid` AND sa.`usort` = la.`usort`' +                ' Left JOIN ?? AS pa On la.`uid` = pa.`id` WHERE la.`cid` = ? and la.`times` = ? and la.`usite` != 0 order BY la.`usort`';            const sqlParam = [this.tableName, cid, times, this.tableName, this.ctx.service.projectAccount.tableName, cid, times];            return transaction !== false ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);        }        /**         * 新增审核人         *         * @param {Number} cid - 变更令id         * @param {Number} auditorId - 审核人id         * @param {Number} times - 第几次审批         * @return {Promise<number>}         */        async addAuditor(cid, auditorId, times = 1, is_gdzs = 0) {            const transaction = await this.db.beginTransaction();            try {                let [uSort, newAuditOrder] = await this.getNewOrder(cid, times);                // let newOrder = await transaction.count(this.tableName, { cid, times });                // let uSort = await transaction.count(this.tableName, { cid });                // 判断是否存在固定终审,存在则newOrder - 1并使终审order+1                uSort = is_gdzs === 1 ? uSort - 1 : uSort;                newAuditOrder = is_gdzs === 1 ? newAuditOrder - 1 : newAuditOrder;                if (is_gdzs) await this._syncOrderByDelete(transaction, cid, newAuditOrder, uSort, times, '+');                const userInfo = await this.ctx.service.projectAccount.getDataById(auditorId);                const newAuditor = {                    tid: this.ctx.tender.id, cid: cid, uid: auditorId,                    name: userInfo.name, jobs: userInfo.role, company: userInfo.company,                    times: times, usite: newAuditOrder, usort: uSort, status: auditConst.status.uncheck,                    audit_order: newAuditOrder,                };                const result = await transaction.insert(this.tableName, newAuditor);                await transaction.commit();                return result.effectRows = 1;            } catch (err) {                await transaction.rollback();                throw err;            }            return false;        }        /**         * 获取 最新审核顺序         *         * @param {Number} cid - 变更id         * @param {Number} times - 第几次审批         * @return {Promise<number>}         */        async getNewOrder(cid, times = 1) {            const sql = 'SELECT Max(`usort`) As max_order, Max(audit_order) As max_audit_order FROM ' + this.tableName + ' Where `cid` = ? and `times` = ?';            const sqlParam = [cid, times];            const result = await this.db.queryOne(sql, sqlParam);            return result && result.max_order ? [result.max_order + 1, result.max_audit_order + 1] : [1, 1];        }        /**         * 移除审核人         *         * @param {Number} cid - 变更令id         * @param {Number} auditorId - 审核人id         * @param {Number} times - 第几次审批         * @return {Promise<boolean>}         */        async deleteAuditor(cid, auditorId, times = 1) {            const transaction = await this.db.beginTransaction();            try {                const sql = 'SELECT * FROM ?? WHERE `cid` = ? and `times` = ? and `uid` = ? and `usite` != 0 ORDER BY `usort` DESC';                const sqlParam = [this.tableName, cid, times, auditorId];                const auditor = await transaction.queryOne(sql, sqlParam);                if (!auditor) {                    throw '该审核人不存在';                }                // 移除整个流程的人                await transaction.delete(this.tableName, { cid, times, usite: auditor.usite });                await this._syncOrderByDelete(transaction, cid, auditor.usite, auditor.usort, times);                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }            return true;        }        async changeSpGroup(change, sp_group) {            const transaction = await this.db.beginTransaction();            try {                const group = await this.ctx.service.shenpiGroup.getDataById(sp_group);                if (!group) {                    throw '该固定审批组不存在,请刷新页面重新获取';                }                const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.ctx.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpiConst.sp_status.gdspl, sp_group: group.id } });                await this.updateNewAuditors(change, shenpiList, transaction);                await transaction.update(this.ctx.service.change.tableName, { sp_group: group.id }, { where: { cid: change.cid } });                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }            return true;        }        /**         * 开始审批         * @param {Number} cid - 变更令id         * @param {Number} times - 第几次审批         * @return {Promise<boolean>}         */        async start(cid, times = 1) {            const audits = await this.getAllDataByCondition({ where: { cid, times, usite: 1 } });            const yBAudit = await this.getDataByCondition({ cid, times, usite: 0 });            if (audits.length === 0) {                if(this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdspl) {                    throw '请联系管理员添加审批人';                } else {                    throw '请先选择审批人,再上报数据';                }            }            const transaction = await this.db.beginTransaction();            try {                const begin_time = new Date();                const updateUserData = audits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time, sin_time: begin_time } });                await transaction.updateRows(this.tableName, updateUserData);                // 更新原报人审批状态                await transaction.update(this.tableName, {                    id: yBAudit.id,                    status: auditConst.status.checked,                    sin_time: begin_time,                    end_time: begin_time,                });                const changeList = await this.ctx.service.changeAuditList.getList(cid);                let total_price = 0;                // 更新清单spamount的值                const updateListData = [];                for (const cl of changeList) {                    total_price = this.ctx.helper.accAdd(total_price, this.ctx.helper.mul(cl.unit_price, cl.camount, this.ctx.tender.info.decimal.tp));                    if(cl.camount !== cl.spamount) {                        const uld = {                            id: cl.id,                            spamount: cl.camount,                        };                        updateListData.push(uld);                    }                }                if(updateListData.length > 0) await transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateListData);                const options = {                    where: {                        cid: cid,                    },                };                const updateData = {                    total_price,                    tp_decimal: this.ctx.tender.info.decimal.tp,                    up_decimal: this.ctx.tender.info.decimal.up,                    status: auditConst.status.checking,                };                await transaction.update(this.ctx.service.change.tableName, updateData, options);                // 清空audit_amount                if(times > 1) await transaction.update(this.ctx.service.changeAuditList.tableName, { audit_amount: null }, { where: { cid: cid } });                // 添加短信通知-需要审批提醒功能                const sms = new SMS(this.ctx);                const code = await sms.contentChange(this.ctx.change.code);                const shenpiUrl = await this.ctx.helper.urlToShort(                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.change.tid + '/change/' + cid + '/information#shenpi'                );                await this.ctx.helper.sendAliSms(this._.map(audits, 'uid'), smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, {                    biangeng: code,                    code: shenpiUrl,                });                // 微信模板通知                const wechatData = {                    wap_url: shenpiUrl,                    status: wxConst.status.check,                    tips: wxConst.tips.check,                    code: this.ctx.session.sessionProject.code,                    c_name: this.ctx.change.name,                };                await this.ctx.helper.sendWechat(this._.map(audits, 'uid'), smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData);                // 重新发送配置                for (const audit of audits) {                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.BG, {                        pid: this.ctx.session.sessionProject.id,                        tid: this.ctx.change.tid,                        uid: audit.uid,                        sp_type: 'change',                        sp_id: audit.id,                        table_name: this.tableName,                        template: wxConst.template.change,                        wx_data: wechatData,                    });                }                await transaction.delete(this.ctx.service.changeHistory.tableName, { cid });                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }            return true;        }        async getNumByMonth(tid, startMonth, endMonth) {            const sql = 'SELECT COUNT(*) as num FROM ?? t1 JOIN (SELECT MAX(id) as max_id FROM ?? WHERE tid = ? AND usite != 0 GROUP BY id ORDER BY usort DESC) t2 ON t1.id = t2.max_id WHERE t1.status = ? AND t1.sin_time between ? and ?';            // const sql = 'SELECT COUNT(*) as num FROM ?? WHERE id in (SELECT b.id FROM (SELECT * FROM ?? WHERE tid = ? AND usite != 0 GROUP BY id ORDER BY usort DESC) as b GROUP BY b.cid) AND status = ? AND sin_time between ? and ?';            const sqlParam = [this.tableName, this.tableName, tid, auditConst.status.checked, startMonth, endMonth];            const result = await this.db.queryOne(sql, sqlParam);            return result ? result.num : 0;        }        /**         * 审批撤回         * @param {Number} stageId - 标段id         * @param {Number} times - 第几次审批         * @return {Promise<void>}         */        async checkCancel(change) {            // 分4种情况,根据ctx.cancancel值判断:            // 1.原报发起撤回,当前流程删除,并回到待上报            // 2.审批人撤回审批通过,增加流程,并回到它审批中            // 3.审批人撤回审批退回上一人,并删除退回人,增加流程,并回到它审批中,并更新计量期状态为审批中            // 4.审批人撤回退回原报操作,删除新增的审批流,增加流程,回滚到它审批中            // 5.会签审批人撤回审批通过(还有其他审批人未审批通过),仅修改本人流程状态            if (change.cancancel === 5) {                await this._auditCheckCancelAnd(change);            } else {                switch (change.cancancel) {                    case 1: await this._userCheckCancel(change); break;                    case 2: await this._auditCheckCancel(change); break;                    case 3: await this._auditCheckCancelNoPre(change); break;                    case 4: await this._auditCheckCancelNo(change); break;                    default: throw '不可撤回,请刷新页面重试';                }            }            // if (stage.cancancel === 5) {            //     await this._auditCheckCancelAnd(stage);            // } else {            //     switch (this.ctx.stage.cancancel) {            //         case 1: await this._userCheckCancel(stage); break;            //         case 2: await this._auditCheckCancel(stage); break;            //         case 3: await this._auditCheckCancelNoPre(stage); break;            //         case 4: await this._auditCheckCancelNo(stage); break;            //         default: throw '不可撤回,请刷新页面重试';            //     }            //     // 通知发送 - 第三方更新            //     if (this.ctx.session.sessionProject.custom && syncApiConst.notice_type.indexOf(this.ctx.session.sessionProject.customType) !== -1) {            //         const base_data = {            //             tid: stage.tid,            //             sid: stage.id,            //             op: 'update',            //         };            //         this.ctx.helper.syncNoticeSend(this.ctx.session.sessionProject.customType, JSON.stringify(base_data));            //         base_data.op = 'update';            //         base_data.sid = -1;            //         this.ctx.helper.syncNoticeSend(this.ctx.session.sessionProject.customType, JSON.stringify(base_data));            //     }            // }        }        /**         * 原报撤回,直接改动审批人状态         * 如果存在审批人数据,将其改为原报流程数据,但保留原提交人         *         * 一审 1 A checking  ->  A uncheck status改   pay/jl:删0(jl为增量数据,只删重复部分) 1->0 删1         * ...         *         * @param stage         * @returns {Promise<void>}         * @private         */        async _userCheckCancel(change) {            const transaction = await this.db.beginTransaction();            try {                // 整理当前流程审核人状态更新                // 审批人变成待审批状态                const updateData = change.curAuditors.map(x => {                    return {                        id: x.id,                        status: auditConst.status.uncheck,                        begin_time: null,                        sin_time: null,                        sdesc: '',                    }                });                await transaction.updateRows(this.tableName, updateData);                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));                // 原报变成checking状态                const ybAudit = await this.getDataByCondition({ cid: change.cid, times: change.times, usite: 0, status: auditConst.status.checked });                await transaction.update(this.tableName, {                    id: ybAudit.id,                    status: auditConst.status.checking,                    end_time: null,                    sin_time: new Date(),                });                // 变更令变成待上报状态                const options = {                    where: {                        cid: change.cid,                    },                };                await transaction.update(this.ctx.service.change.tableName, {                    status: change.times === 1 ? auditConst.status.uncheck : auditConst.status.checkNo,                }, options);                await transaction.commit();            } catch(err) {                await transaction.rollback();                throw err;            }        }        /**         * 审批人撤回审批通过,插入两条数据         *         * 一审 1 A checked             一审 1 A checked         * 二审 2 B checked   pre ->    二审 2 B checked         * 三审 3 C checking  cur       二审 3 B checkCancel  增                增extra_his     增tp_his         * 四审 4 D uncheck             二审 4 B checking     增                增pay_cur         *                             三审 5 C uncheck      order、status改         *                             四审 6 D uncheck      order改         *         * @param stage         * @returns {Promise<void>}         * @private         */        async _auditCheckCancel(change) {            if (change.curAuditors.length === 0 || change.curAuditors[0].usort <= 1) {                throw '撤回用户数据错误';            }            const accountId = this.ctx.session.sessionUser.accountId;            const time = new Date();            const transaction = await this.db.beginTransaction();            try {                const selfAuditor = change.preAuditors.find(x => { return x.uid === accountId; });                if (!selfAuditor) throw '撤回用户数据错误';                // 顺移其后审核人流程顺序                const sql = 'UPDATE ' + this.tableName + ' SET `usort` = `usort` + 2 WHERE cid = ? AND times = ? AND `usort` > ?';                await transaction.query(sql, [change.cid, change.times, change.curAuditors[0].usort]);                // 当前审批人2次添加至流程中                const checkCancelAuditors = [], checkingAuditors = [];                change.preAuditors.forEach(x => {                    checkCancelAuditors.push({                        tid: change.tid, cid: change.cid, uid: x.uid,                        times: x.times, usite: x.usite, usort: x.usort + 1,                        status: x.uid === selfAuditor.uid ? auditConst.status.checkCancel : auditConst.status.checkSkip,                        begin_time: time, end_time: time, sin_time: time, sdesc: '',                        name: x.name, jobs: x.role || x.jobs, company: x.company,                        audit_type: x.audit_type, audit_order: x.audit_order,                    });                });                change.preAuditors.forEach(x => {                    checkingAuditors.push({                        tid: change.tid, cid: change.cid, uid: x.uid,                        times: x.times, usite: x.usite, usort: x.usort + 2,                        status: auditConst.status.checking,                        begin_time: time, sin_time: time, sdesc: '',                        name: x.name, jobs: x.role || x.jobs, company: x.company,                        audit_type: x.audit_type, audit_order: x.audit_order,                    });                });                await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);                const newAuditors = [];                // 当前审批人变成待审批                await transaction.updateRows(this.tableName, change.curAuditors.map(x => { return {                    id: x.id, begin_time: null, sin_time: null, status: auditConst.status.uncheck, usort: x.usort + 2                }}));                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(change.curAuditors, 'id'));                // 审批列表数据也要回退                const changeList = await this.ctx.service.changeAuditList.getList(change.cid);                let total_price = 0;                const tp_decimal = change.tp_decimal ? change.tp_decimal : this.ctx.tender.info.decimal.tp;                const updateList = [];                for (const cl of changeList) {                    const audit_amount = cl.audit_amount.split(',');                    const last_amount = audit_amount[audit_amount.length - 1] ? audit_amount[audit_amount.length - 1] : 0;                    audit_amount.splice(-1, 1);                    const list_update = {                        id: cl.id,                        audit_amount: audit_amount.join(','),                        spamount: parseFloat(last_amount),                    };                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(last_amount), tp_decimal));                    updateList.push(list_update)                }                if (updateList.length > 0) await transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateList);                // 变更令变成待上报状态                const options = {                    where: {                        cid: change.cid,                    },                };                await transaction.update(this.ctx.service.change.tableName, {                    status: auditConst.status.checking,                    total_price,                    cin_time: Date.parse(time) / 1000,                }, options);                await transaction.commit();            } catch(err) {                await transaction.rollback();                throw err;            }        }        /**         * 审批人撤回审批退回上一人,插入两条数据         *         * 一审 1 A checked                   一审 1 A checked         * 二审 2 B checked                   二审 2 B checked         * 三审 3 C checkNoPre  pre   ->      三审 3 C checkNoPre         * 二审 4 B checking    cur           三审 4 C checkCancel   删4B 增4C    增extra_his    增tp_his         * 三审 5 C uncheck                   三审 5 C checking      status改     增pay_cur         * 四审 6 D uncheck                   四审 6 D uncheck         *         * @param stage         * @returns {Promise<void>}         * @private         */        async _auditCheckCancelNoPre(change) {            if (change.curAuditors.length === 0 || change.curAuditors[0].usort <= 1) {                throw '撤回用户数据错误';            }            const accountId = this.ctx.session.sessionUser.accountId;            const time = new Date();            const transaction = await this.db.beginTransaction();            try {                const selfAuditor = change.preAuditors.find(x => { return x.uid === accountId; });                if (!selfAuditor) throw '撤回用户数据错误';                // 整理当前流程审核人状态更新                // 删除当前审批人                await transaction.delete(this.tableName, { id: change.curAuditors.map(x => { return x.id; }) });                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(change.curAuditors, 'id'));                // 添加撤回人到审批流程中                const newAuditors = [];                change.preAuditors.forEach(x => {                    newAuditors.push({                        tid: change.tid, cid: change.cid, uid: x.uid,                        times: x.times, usite: x.usite, usort: x.usort + 1,                        status: x.uid === selfAuditor.uid ? auditConst.status.checkCancel : auditConst.status.checkSkip,                        begin_time: time, end_time: time, sin_time: time, sdesc: '',                        name: x.name, jobs: x.role || x.jobs, company: x.company,                        audit_type: x.audit_type, audit_order: x.audit_order,                    });                });                await transaction.insert(this.tableName, newAuditors);                // 更新上一个人,最新审批状态为审批中                await transaction.update(this.tableName,  { begin_time: time, sin_time: time, status: auditConst.status.checking }, {                    where: { cid: change.cid, times: change.times, usort: selfAuditor.usort + 2 }                });                // 回退spamount值数据                const changeList = await this.ctx.service.changeAuditList.getList(change.cid);                let total_price = 0;                const tp_decimal = change.tp_decimal ? change.tp_decimal : this.ctx.tender.info.decimal.tp;                const updateList = [];                for (const cl of changeList) {                    const audit_amount = cl.audit_amount !== '' ? cl.audit_amount.split(',') : [];                    audit_amount.push(cl.spamount);                    const list_update = {                        id: cl.id,                        audit_amount: audit_amount.join(','),                    };                    total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(cl.unit_price, parseFloat(cl.spamount), tp_decimal));                    updateList.push(list_update);                }                if (updateList.length > 0) await transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateList);                // 变更令变成待上报状态                const options = {                    where: {                        cid: change.cid,                    },                };                await transaction.update(this.ctx.service.change.tableName, {                    status: auditConst.status.checking,                    total_price,                    cin_time: Date.parse(time) / 1000,                }, options);                await transaction.commit();            } catch(err) {                await transaction.rollback();                throw err;            }        }        /**         * 审批人撤回审批退回原报         *         * 1# 一审 1 A checked              1# 一审 1 A checked         *    二审 2 B checkNo   pre   ->      二审 2 B checkNo         *    三审 3 C uncheck                 二审 3 B checkCancel    增       pay: 2#0 -> 1#3   jl: 2#0 -> 1#3   增tp_his   增extra_his         *                                    二审 4 B checking       增       pay: 2#0 -> 1#4         *                                    三审 5 C uncheck        order改         *         * 2# 一审 1 A uncheck              2#                        删       pay: 2#0删   jl: 2#0删         *    二审 2 B uncheck         *    三审 3 C uncheck         *         * @param stage         * @returns {Promise<void>}         * @private         */        async _auditCheckCancelNo(change) {            const accountId = this.ctx.session.sessionUser.accountId;            const selfAuditor = change.preAuditors.find(x => { return x.uid === accountId && x.status === auditConst.status.checkNo; });            if (!selfAuditor) throw '该标段由他人审批退回,您不可撤回';            const time = new Date();            const transaction = await this.db.beginTransaction();            try {                // const curAudit = await this.getDataByCondition({ cid: change.cid, times: change.times - 1, status: auditConst.auditStatus.back });                // const curAudit = await this.getAuditorByStatus(change.cid, change.times - 1, auditConst.auditStatus.back);                // 整理上一个流程审核人状态更新                // 顺移其后审核人流程顺序                const sql = 'UPDATE ' + this.tableName + ' SET `usort` = `usort` + 2 WHERE cid = ? AND times = ? AND `usort` > ?';                await transaction.query(sql, [change.cid, selfAuditor.times, selfAuditor.usort]);                // 当前审批人2次添加至流程中                const checkCancelAuditors = [], checkingAuditors = [];                change.preAuditors.forEach(x => {                    checkCancelAuditors.push({                        tid: change.tid, cid: change.cid, uid: x.uid,                        times: x.times, usite: x.usite, usort: x.usort + 1,                        status: x.uid === selfAuditor.uid ? auditConst.status.checkCancel : auditConst.status.checkSkip,                        begin_time: time, end_time: time, sin_time: time, sdesc: '',                        name: x.name, jobs: x.role || x.jobs, company: x.company,                        audit_type: x.audit_type, audit_order: x.audit_order,                    });                });                change.preAuditors.forEach(x => {                    checkingAuditors.push({                        tid: change.tid, cid: change.cid, uid: x.uid,                        times: x.times, usite: x.usite, usort: x.usort + 2,                        status: auditConst.status.checking,                        begin_time: time, sin_time: time, sdesc: '',                        name: x.name, jobs: x.role || x.jobs, company: x.company,                        audit_type: x.audit_type, audit_order: x.audit_order,                    });                });                await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);                // 删除当前次审批流                await transaction.delete(this.tableName, { cid: change.cid, times: change.times });                // 回退数据                await this.ctx.service.changeHistory.returnHistory(transaction, change.cid);                await transaction.delete(this.ctx.service.changeHistory.tableName, { cid: change.cid });                await transaction.commit();            } catch(err) {                await transaction.rollback();                throw err;            }        }        /**         * 会签未全部审批通过时,撤回仅修改本人状态         *         * @param stage         * @returns {Promise<void>}         * @private         */        async _auditCheckCancelAnd(change) {            const accountId = this.ctx.session.sessionUser.accountId;            const selfAuditor = change.flowAuditors.find(x => { return x.uid === accountId; });            if (!selfAuditor || selfAuditor.status !== auditConst.status.checked) throw '不可撤回';            const transaction = await this.db.beginTransaction();            try {                await transaction.update(this.tableName, {                    id: selfAuditor.id, status: auditConst.status.checking, sdesc: '', end_time: null,                });                await transaction.commit();            } catch(err) {                await transaction.rollback();                throw err;            }        }        async getAuditorByStatus(cid, times, status, transaction= null) {            const sql = 'SELECT * FROM ?? WHERE `cid` = ? AND `times` = ? AND `status` = ? ORDER BY `usort` DESC';            const sqlParam = [this.tableName, cid, times, status];            return transaction ? await transaction.queryOne(sql, sqlParam) : await this.db.queryOne(sql, sqlParam);        }        async getAuditorsByStatus(cid, status, times = 1) {            let auditor = [];            let sql = '';            let sqlParam = '';            let cur;            switch (status) {                case auditConst.status.checking:                case auditConst.status.checked:                case auditConst.status.checkNoPre:                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where cid = ? AND times = ? AND status = ? AND audit_order != 0 ORDER By times DESC, ` + '`usort` DESC', [cid, times, status]);                    if (!cur) return [];                    sql = 'SELECT la.`uid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`status`, la.`usort`, la.`usite`, la.audit_order, la.audit_type ' +                        '  FROM ?? AS la Left Join ?? AS pa On la.`uid` = pa.`id` ' +                        '  WHERE la.`cid` = ? and la.`usort` = ? and la.`times` = ?';                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, cur.usort, times];                    auditor = await this.db.query(sql, sqlParam);                    break;                case auditConst.status.checkNo:                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where cid = ? AND times = ? AND status = ? AND audit_order != 0 ORDER By times DESC, ` + '`usort` DESC', [cid, parseInt(times) - 1, status]);                    if (!cur) return [];                    sql = 'SELECT la.`uid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`status`, la.`usort`, la.`usite`, la.audit_order, la.audit_type ' +                        '  FROM ?? AS la Left Join ?? AS pa On la.`uid` = pa.`id` ' +                        '  WHERE la.`cid` = ? and la.`usort` = ? and la.`times` = ?';                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, cur.usort, parseInt(times) - 1];                    auditor = await this.db.query(sql, sqlParam);                    break;                case auditConst.status.revise:                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where cid = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`usort` DESC', [cid, parseInt(times) - 1, status]);                    if (!cur) return [];                    sql = 'SELECT la.`uid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cid`, la.`status`, la.`usort`, la.`usite`, la.audit_order, la.audit_type ' +                        '  FROM ?? AS la Left Join ?? AS pa On la.`uid` = pa.`id` ' +                        '  WHERE la.`cid` = ? and la.`usort` = ? and la.`times` = ?';                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cid, cur.usort, parseInt(times) - 1];                    auditor = await this.db.query(sql, sqlParam);                    break;                case auditConst.status.uncheck:                default:                    break;            }            return auditor;        }        async saveAudit(cid, times, sp_group, data) {            const transaction = await this.db.beginTransaction();            try {                const auditors = await this.getAuditGroupByList(cid, times);                const now_audit = this._.find(auditors, { uid: data.old_aid });                if (data.operate !== 'del') {                    const exist = await this.getDataByCondition({ cid, times, uid: data.new_aid });                    if (exist) throw '该审核人已存在,请勿重复添加';                }                if (data.operate === 'add') {                    if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {                        throw '当前人下无法操作新增';                    }                    const nowAuditInfo = await this.ctx.service.projectAccount.getDataById(data.new_aid);                    const newAudit = {                        tid: this.ctx.tender.id, cid, uid: data.new_aid,                        name: nowAuditInfo.name, company: nowAuditInfo.company, jobs: nowAuditInfo.role,                        usort: now_audit.usort + 1, usite: now_audit.usite + 1,                        audit_order: now_audit.audit_order + 1, audit_type: auditType.key.common,                        times: times, status: auditConst.status.uncheck,                    };                    // order+1                    await this._syncOrderByDelete(transaction, cid, now_audit.usite + 1, now_audit.usort + 1, times, '+');                    await transaction.insert(this.tableName, newAudit);                    // 更新审批流程页数据,如果存在                } else if (data.operate === 'add-sibling') {                    if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {                        throw '当前人下无法操作新增';                    }                    const nowAuditInfo = await this.ctx.service.projectAccount.getDataById(data.new_aid);                    const newAudit = {                        tid: this.ctx.tender.id, cid, uid: data.new_aid,                        name: nowAuditInfo.name, company: nowAuditInfo.company, jobs: nowAuditInfo.role,                        usort: now_audit.usort, usite: now_audit.usite,                        audit_order: now_audit.audit_order, audit_type: now_audit.audit_type,                        times: times,                        status: auditConst.status.uncheck,                    };                    await transaction.insert(this.tableName, newAudit);                } else if (data.operate === 'del') {                    if (now_audit.status !== auditConst.status.uncheck) {                        throw '当前人无法操作删除';                    }                    const flowAuditors = auditors.filter(x => { return x.audit_order === now_audit.audit_order; });                    await transaction.delete(this.tableName, { cid, times, uid: now_audit.uid, usite: now_audit.usite });                    if (flowAuditors.length === 1) await this._syncOrderByDelete(transaction, cid, now_audit.usite, now_audit.usort, 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({ cid, times, uid: now_audit.uid, usite: now_audit.usite });                    if (now_audit.status !== auditConst.status.uncheck || !nowAudit) {                        throw '当前人无法操作替换';                    }                    const nowAuditInfo = await this.ctx.service.projectAccount.getDataById(data.new_aid);                    nowAudit.uid = data.new_aid;                    nowAudit.name = nowAuditInfo.name;                    nowAudit.company = nowAuditInfo.company;                    nowAudit.jobs = nowAuditInfo.role;                    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.change === shenpiConst.sp_status.gdspl) {                    const newAuditors = await transaction.select(this.tableName, { where: { cid, times }, orders: [['usite', 'asc']] });                    newAuditors.shift();                    const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'usort');                    const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);                    await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, uniqNewAuditorGroup, sp_group);                } else if (this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdzs) {                    const newAuditors = await this.getListGroupByWithoutYB(cid, times, transaction);                    await this.ctx.service.shenpiAudit.updateAuditList(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, this._.map(newAuditors, 'uid'));                }                // 更新到审批流程方法                await transaction.commit();            } catch (err) {                console.log(err);                await transaction.rollback();                throw err;            }        }    }    return ChangeAudit;};
 |