浏览代码

变更审批会签或签 no.1 up

ellisran 1 年之前
父节点
当前提交
e94ea84711

+ 122 - 0
app/const/audit.js

@@ -601,6 +601,127 @@ const advance = (function() {
     return { type, status, statusString, statusClass, auditString, auditStringClass };
 })();
 
+// 变更 审批流程(新的,旧的也要保留,防止报表或其他地方调用旧的出问题)
+const change = (function() {
+    const status = {
+        uncheck: 1, // 待审批
+        checking: 2, // 审批中或者原报人待上报或者原报上报修订中
+        checked: 3, // 审批通过或者原报人上报完成
+        // checkNo: 4,     // 审批终止
+        checkNo: 5, // 退回到原报人重新上报
+        checkNoPre: 6, // 退回到上一个审批人
+        checkAgain: 7, // 重新审批
+        checkSkip: 8, // 跳过
+        revise: 9, // 修订变更
+        cancelRevise: 10, // 撤销修订
+        checkCancel: 11, // 撤回 // 该状态为上一审批人可发起,回到它到审批阶段,并同时新增一条新的审批中记录
+    };
+    const statusString = [];
+    statusString[status.uncheck] = '待上报';
+    statusString[status.checking] = '审批中';
+    statusString[status.checked] = '审批通过';
+    statusString[status.checkNo] = '审批退回';
+    statusString[status.checkNoPre] = '审批退回';
+    statusString[status.checkAgain] = '重新审批';
+    statusString[status.revise] = '修订';
+    statusString[status.cancelRevise] = '撤销修订';
+    statusString[status.checkCancel] = '撤回';
+
+    const statusClass = [];
+    statusClass[status.uncheck] = '';
+    statusClass[status.checking] = 'text-warning';
+    statusClass[status.checked] = 'text-success';
+    statusClass[status.checkNo] = 'text-warning';
+    statusClass[status.checkNoPre] = 'text-warning';
+    statusClass[status.checkAgain] = 'text-warning';
+    statusClass[status.revise] = 'text-warning';
+    statusClass[status.cancelRevise] = 'text-success';
+    statusClass[status.checkCancel] = 'text-warning';
+
+    // 标段概况页
+    // 描述文本
+    const auditString = [];
+    auditString[status.uncheck] = '';
+    auditString[status.checking] = '审批中';
+    auditString[status.checked] = '审批通过';
+    auditString[status.checkNo] = '审批退回';
+    auditString[status.checkNoPre] = '审批退回';
+    auditString[status.checkAgain] = '重新审批';
+    auditString[status.revise] = '修订';
+    auditString[status.cancelRevise] = '撤销修订';
+    auditString[status.checkCancel] = '撤回';
+    auditString[status.checkSkip] = '审批通过';
+    // 文字样式
+    const auditStringClass = [];
+    auditStringClass[status.uncheck] = '';
+    auditStringClass[status.checking] = 'text-warning';
+    auditStringClass[status.checked] = 'text-success';
+    auditStringClass[status.checkNo] = 'text-warning';
+    auditStringClass[status.checkNoPre] = 'text-warning';
+    auditStringClass[status.checkAgain] = 'text-warning';
+    auditStringClass[status.revise] = 'text-warning';
+    auditStringClass[status.cancelRevise] = 'text-success';
+    auditStringClass[status.checkCancel] = 'text-warning';
+    auditStringClass[status.checkSkip] = 'text-success';
+    // 描述文本
+    const auditProgress = [];
+    auditProgress[status.uncheck] = '草稿';
+    auditProgress[status.checking] = '审批中';
+    auditProgress[status.checked] = '审批通过';
+    auditProgress[status.checkNo] = '审批退回';
+    auditProgress[status.checkNoPre] = '审批退回';
+    auditProgress[status.checkAgain] = '重新审批';
+    auditProgress[status.revise] = '修订中';
+    auditProgress[status.cancelRevise] = '撤销修订';
+    auditProgress[status.checkCancel] = '撤回';
+    auditProgress[status.checkSkip] = '审批通过';
+    // 样式
+    const auditProgressClass = [];
+    auditProgressClass[status.uncheck] = '';
+    auditProgressClass[status.checking] = 'text-warning';
+    auditProgressClass[status.checked] = 'text-success';
+    auditProgressClass[status.checkNo] = 'text-warning';
+    auditProgressClass[status.checkNoPre] = 'text-warning';
+    auditProgressClass[status.checkAgain] = 'text-warning';
+    auditProgressClass[status.revise] = 'text-warning';
+    auditProgressClass[status.cancelRevise] = 'text-success';
+    auditProgressClass[status.checkCancel] = 'text-warning';
+    auditProgressClass[status.checkSkip] = 'text-success';
+
+    const filter = {
+        status: {
+            pending: 1,
+            uncheck: 5,
+            checking: 2,
+            checked: 3,
+            // checkNo: 4,
+        },
+        statusString: [],
+    };
+    filter.statusString[filter.status.pending] = '待处理';
+    filter.statusString[filter.status.uncheck] = '待上报';
+    filter.statusString[filter.status.checking] = '进行中';
+    filter.statusString[filter.status.checked] = '已通过';
+    // filter.statusString[filter.status.checkNo] = '终止';
+
+    // 按钮
+    const statusButton = [];
+    statusButton[status.uncheck] = '上报';
+    statusButton[status.checking] = '审批';
+    statusButton[status.checked] = '';
+    statusButton[status.checkNo] = '重新上报';
+    statusButton[status.revise] = '修订';
+
+    // 按钮样式
+    const statusButtonClass = [];
+    statusButtonClass[status.uncheck] = 'btn-primary';
+    statusButtonClass[status.checking] = 'btn-success';
+    statusButtonClass[status.checked] = '';
+    statusButtonClass[status.checkNo] = 'btn-warning';
+    statusButtonClass[status.revise] = 'btn-warning';
+    return { status, statusString, statusClass, auditString, auditStringClass, auditProgress, auditProgressClass, filter, statusButton, statusButtonClass };
+})();
+
 // 变更立项 审批流程
 const changeProject = (function() {
     const status = {
@@ -968,6 +1089,7 @@ module.exports = {
     filter,
     pushType,
     advance,
+    change,
     changeProject,
     changeApply,
     changePlan,

+ 75 - 458
app/controller/change_controller.js

@@ -19,6 +19,7 @@ const path = require('path');
 const audit = require('../const/audit');
 const codeRuleConst = require('../const/code_rule');
 const changeConst = require('../const/change');
+const auditType = require('../const/audit').auditType;
 const accountGroup = require('../const/account_group').group;
 const shenpiConst = require('../const/shenpi');
 const tenderMenu = require('../../config/menu').tenderMenu;
@@ -327,277 +328,14 @@ module.exports = app => {
         }
 
         /**
-         * 变更信息 页面 (Get)
-         *
-         * @param {Object} ctx - egg全局变量
-         * @return {void}
+         * 获取审批界面所需的 原报、审批人数据等
+         * @param ctx
+         * @return {Promise<void>}
+         * @private
          */
-        async info(ctx) {
-            try {
-                const whiteList = this.ctx.app.config.multipart.whitelist;
-                const tenderid = ctx.params.id !== undefined ? ctx.params.id : ctx.session.sessionUser.tenderId;
-                ctx.session.sessionUser.tenderId = tenderid;
-                const tender = await ctx.service.tender.getDataById(tenderid);
-                const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid });
-
-                // 后台判断当前人查看info状态
-                const auditStatus = await ctx.service.changeAudit.getStatusByChange(change);
-
-                // 获取附件列表
-                const attList = await ctx.service.changeAtt.getChangeAttachment(ctx.params.cid);
-
-                // 获取其他变更令数据
-                const othersChange = await ctx.service.change.getOthersChange(ctx.params.id, ctx.params.cid);
-
-                // 根据auditStatus获取审批人列表
-                const auditList = await ctx.service.changeAudit.getListByStatus(change, auditStatus);
-                // 获取已选清单
-                let changeList = await ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: ctx.params.cid } });
-
-                // 获取用户人验证手机号
-                const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
-                const auth_mobile = pa.auth_mobile;
-                const renderData = {
-                    uid: ctx.session.sessionUser.accountId,
-                    tender,
-                    change,
-                    othersChange,
-                    changeConst,
-                    auditStatus,
-                    auditConst: audit.flow,
-                    ledgerConsts: audit.ledger.status,
-                    attList,
-                    whiteList,
-                    auditList,
-                    changeList,
-                    tpUnit: change.tp_decimal !== null ? change.tp_decimal : ctx.tender.info.decimal.tp,
-                    upUnit: change.up_decimal !== null ? change.up_decimal : ctx.tender.info.decimal.up,
-                    authMobile: auth_mobile,
-                    shenpiConst,
-                };
-                // 根据auditStatus状态获取的不同的数据
-                if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) {
-                    renderData.changeUnits = changeConst.units;
-                    renderData.precision = ctx.tender.info.precision;
-                    // renderData.accountGroup = accountGroup;
-                    // 获取所有项目参与者
-                    const accountList = await ctx.service.projectAccount.getAllDataByCondition({
-                        where: { project_id: ctx.session.sessionProject.id, enable: 1 },
-                        columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group'],
-                    });
-                    renderData.accountList = accountList;
-                    const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
-                    renderData.accountGroup = unitList.map(item => {
-                        const groupList = accountList.filter(item1 => item1.company === item.name);
-                        return { groupName: item.name, groupList };
-                    });
-                    // 重新上报获取审批流程
-                    if (auditStatus === 2 || auditStatus === 9) {
-                        const auditList2 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
-                        // 展示页右侧审批流程列表
-                        const auditList3 = [];
-                        for (let time = 1; time <= change.times - 1; time++) {
-                            const auditTimeList = [];
-                            let max_sort = 1;
-                            for (const al of auditList2) {
-                                if (al.times === time) {
-                                    auditTimeList.push(al);
-                                    if (al.usite > max_sort) {
-                                        max_sort = al.usite;
-                                    }
-                                }
-                            }
-                            for (const i in auditTimeList) {
-                                auditTimeList[i].max_sort = max_sort;
-                            }
-                            auditList3.push(auditTimeList);
-                        }
-                        renderData.auditList3 = auditList3;
-                    }
-
-                    // 根据清单获取提交数据和计算总金额
-                    const changeListData = [];
-                    const changeWhiteListData = [];
-                    let ototalCost = 0;
-                    let ctotalCost = 0;
-                    for (const cl of changeList) {
-                        const cLArray = [
-                            cl.code,
-                            cl.name,
-                            cl.bwmx,
-                            cl.unit,
-                            cl.unit_price,
-                            cl.oamount,
-                            cl.camount,
-                            cl.detail,
-                            cl.lid,
-                            cl.xmj_code,
-                            cl.xmj_jldy,
-                            cl.gcl_id,
-                        ];
-                        ototalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.oamount, ctx.tender.info.decimal.tp);
-                        ctotalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.camount, ctx.tender.info.decimal.tp);
-                        if (cl.lid !== '0') {
-                            changeListData.push(cLArray.join('*;*'));
-                        } else {
-                            changeWhiteListData.push(cLArray.join('*;*'));
-                        }
-                    }
-                    renderData.changeListData = changeListData.join('^_^');
-                    renderData.changeWhiteListData = changeWhiteListData.join('^_^');
-                    renderData.ototalCost = ototalCost;
-                    renderData.ctotalCost = ctotalCost;
-
-                    // 获取公司列表
-                    const companyList = await ctx.service.changeCompany.getAllDataByCondition({ where: { tid: tenderid } });
-                    renderData.companyList = companyList;
-                } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) {
-                    // 展示页左侧审批流程列表和清单审批列表数据
-                    const times = change.status === audit.flow.status.back ?
-                        change.times - 1 : change.times;
-                    const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(change.cid, times);
-
-                    // 展示页右侧审批流程列表
-                    const auditList3 = [];
-                    for (let time = 1; time <= times; time++) {
-                        const auditTimeList = [];
-                        let max_sort = 1;
-                        for (const al of auditList) {
-                            if (al.times === time) {
-                                auditTimeList.push(al);
-                                if (al.usite > max_sort) {
-                                    max_sort = al.usite;
-                                }
-                            }
-                        }
-                        for (const i in auditTimeList) {
-                            auditTimeList[i].max_sort = max_sort;
-                        }
-                        auditList3.push(auditTimeList);
-                    }
-                    renderData.auditList3 = auditList3;
-
-                    changeList = JSON.parse(JSON.stringify(changeList.sort())).sort().sort();
-                    renderData.changeList = changeList;
-                    let ototalCost = 0;
-                    let ctotalCost = 0;
-                    let stotalCost = 0;
-                    const auditTotalCost = [];
-                    for (const cl of changeList) {
-                        // ototalCost += cl.unit_price === null ? 0 : parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.oamount), renderData.tpUnit));
-                        ototalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.oamount, renderData.tpUnit);
-                        // ctotalCost += cl.unit_price === null ? 0 : parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.camount), renderData.tpUnit));
-                        ctotalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.camount, renderData.tpUnit);
-                        // stotalCost += cl.samount !== '' && cl.unit_price !== null ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.samount), renderData.tpUnit)) : 0;
-                        stotalCost += cl.samount !== '' && cl.unit_price !== null ? ctx.helper.mul(cl.unit_price, cl.samount, renderData.tpUnit) : 0;
-                        const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
-                        auditTotalCost.push(audit_amount);
-                    }
-                    renderData.ototalCost = ototalCost;
-                    renderData.ctotalCost = ctotalCost;
-                    renderData.stotalCost = stotalCost;
-
-                    // 清单表页赋值
-                    for (const [index, au] of auditList2.entries()) {
-                        if (au.usite !== 0) {
-                            au.list_amount = [];
-                            au.totalCost = 0;
-                            for (const [auindex, at] of auditTotalCost.entries()) {
-                                au.list_amount.push(at[index - 1]);
-                                // au.totalCost += at[index - 1] !== undefined && changeList[auindex].unit_price !== null ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 1]), renderData.tpUnit)) : 0;
-                                au.totalCost += at[index - 1] !== undefined && changeList[auindex].unit_price !== null ? ctx.helper.mul(changeList[auindex].unit_price, at[index - 1], renderData.tpUnit) : 0;
-                            }
-                        }
-                    }
-                    renderData.auditList2 = auditList2;
-                } else if (auditStatus === 6) {
-                    // 展示页左侧审批流程列表和清单审批列表数据
-                    const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(change.cid, change.times);
-                    renderData.auditList2 = auditList2;
-                    const auditList3 = await ctx.service.changeAudit.getListOrderByTimes(change.cid, change.times);
-                    for (const i in auditList3) {
-                        auditList3[i].max_sort = auditList2.length - 1;
-                    }
-                    renderData.auditList3 = auditList3;
-
-                    // 展示页右侧审批流程列表
-                    const auditList5 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
-                    const auditList4 = [];
-                    for (let time = 1; time <= change.times; time++) {
-                        const auditTimeList = [];
-                        let max_sort = 1;
-                        for (const al of auditList5) {
-                            if (al.times === time) {
-                                auditTimeList.push(al);
-                                if (al.usite > max_sort) {
-                                    max_sort = al.usite;
-                                }
-                            }
-                        }
-                        for (const i in auditTimeList) {
-                            auditTimeList[i].max_sort = max_sort;
-                        }
-                        if (auditTimeList.length > 0) {
-                            auditList4.push(auditTimeList);
-                        }
-                    }
-                    renderData.auditList4 = auditList4;
-
-                    changeList = JSON.parse(JSON.stringify(changeList.sort())).sort().sort();
-                    renderData.changeList = changeList;
-                    let ototalCost = 0;
-                    let ctotalCost = 0;
-                    const auditTotalCost = [];
-                    const auditUnit = [];
-                    for (const cl of changeList) {
-                        // ototalCost += cl.unit_price === null ? 0 : parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.oamount), renderData.tpUnit));
-                        ototalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.oamount, renderData.tpUnit);
-                        // ctotalCost += cl.unit_price === null ? 0 : parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.camount), renderData.tpUnit));
-                        ctotalCost += cl.unit_price === null ? 0 : ctx.helper.mul(cl.unit_price, cl.camount, renderData.tpUnit);
-                        const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
-                        auditTotalCost.push(audit_amount);
-                    }
-                    renderData.ototalCost = ototalCost;
-                    renderData.ctotalCost = ctotalCost;
-
-                    // 清单表页赋值
-                    for (const [index, au] of auditList.entries()) {
-                        if (au.usite !== 0) {
-                            au.list_amount = [];
-                            au.totalCost = 0;
-                            if (au.uid === renderData.uid) {
-                                for (const [auindex, at] of auditTotalCost.entries()) {
-                                    // if (at[index - 2] !== undefined) {
-                                    //     au.list_amount.push(at[index - 2]);
-                                    //     au.totalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 2]), renderData.tpUnit));
-                                    // } else if (at[index - 2] === undefined) {
-                                    //     au.list_amount.push(changeList[auindex].camount);
-                                    //     au.totalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, changeList[auindex].camount), renderData.tpUnit));
-                                    // }
-                                    au.list_amount.push(changeList[auindex].spamount);
-                                    // au.totalCost += changeList[auindex].unit_price === null ? 0 : parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, changeList[auindex].spamount), renderData.tpUnit));
-                                    au.totalCost += changeList[auindex].unit_price === null ? 0 : ctx.helper.mul(changeList[auindex].unit_price, changeList[auindex].spamount, renderData.tpUnit);
-                                }
-                            } else {
-                                for (const [auindex, at] of auditTotalCost.entries()) {
-                                    au.list_amount.push(at[index - 1]);
-                                    // au.totalCost += at[index - 1] !== undefined && changeList[auindex].unit_price !== null ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 1]), renderData.tpUnit)) : 0;
-                                    au.totalCost += at[index - 1] !== undefined && changeList[auindex].unit_price !== null ? ctx.helper.mul(changeList[auindex].unit_price, at[index - 1], renderData.tpUnit) : 0;
-                                }
-                            }
-                        }
-                    }
-                }
-                renderData.auditList = auditList;
-
-                // 获取是否已存在调用变更令
-                const changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, change.cid);
-                renderData.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.qty); }));
-                await this.layout('change/info.ejs', renderData, 'change/info_modal.ejs');
-            } catch (err) {
-                this.log(err);
-                ctx.redirect('/tender/' + ctx.params.id + '/change');
-            }
+        async _getChangeAuditViewData(ctx) {
+            await ctx.service.change.loadChangeAuditViewData(ctx.change);
+            // await this._checkStageStart(ctx);
         }
 
         /**
@@ -609,10 +347,9 @@ module.exports = app => {
         async information(ctx) {
             try {
                 const whiteList = this.ctx.app.config.multipart.whitelist;
-                const tender = await ctx.service.tender.getDataById(ctx.tender.id);
+                await this._getChangeAuditViewData(ctx);
+                const tender = ctx.tender;
                 const change = ctx.change;
-                // 后台判断当前人查看info状态
-                const auditStatus = await ctx.service.changeAudit.getStatusByChange(change);
 
                 // 获取附件列表
                 const attList = await ctx.service.changeAtt.getChangeAttachment(change.cid, 'desc');
@@ -620,20 +357,33 @@ module.exports = app => {
                 // 获取其他变更令数据
                 const othersChange = await ctx.service.change.getOthersChange(ctx.tender.id, change.cid);
 
-                // 根据auditStatus获取审批人列表
-                const auditList = await ctx.service.changeAudit.getListByStatus(change, auditStatus);
-
                 // 获取变更方案的清单
                 let planList = [];
                 let showPlanBtn = false;
                 if (ctx.session.sessionProject.page_show.openChangePlan) {
-                    const planInfo = change.plan_code ? await ctx.service.changePlan.getDataByCondition({ tid: ctx.tender.id, code: change.plan_code }) : null;
+                    const planInfo = change.plan_code ? await ctx.service.changePlan.getDataByCondition({ tid: tender.id, code: change.plan_code }) : null;
                     showPlanBtn = change.plan_code !== null && change.plan_code !== '';
                     if (planInfo && planInfo.id) {
                         planList = await ctx.service.changePlanList.getAllDataByCondition({ where: { cpid: planInfo.id } });
                     }
                 }
 
+                // 获取清单
+                const changeList = await ctx.service.changeAuditList.getList(change.cid);
+                if (change.status === audit.change.status.checked || change.status === audit.change.status.checking || change.status === audit.change.status.checkNoPre) {
+                    for (const cl of changeList) {
+                        const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
+                        // 清单表页赋值
+                        for (const au in change.userGroups) {
+                            if (change.userGroups[au][0].audit_order !== 0) {
+                                cl['audit_amount_' + change.userGroups[au][0].audit_order] = change.shenpiPower &&
+                                ctx.helper._.findIndex(change.userGroups[au], { uid: ctx.session.sessionUser.accountId }) !== -1 ?
+                                    cl.spamount : (audit_amount[au - 1] !== undefined ? parseFloat(audit_amount[au - 1]) : null);
+                            }
+                        }
+                    }
+                }
+
                 // 工程变更类别读取
                 const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
                 const fun_set = await ctx.service.project.getFunSet(projectData.fun_set);
@@ -642,18 +392,13 @@ module.exports = app => {
                 const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
                 const auth_mobile = pa.auth_mobile;
                 const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
-
-                if (change && change.status !== audit.flow.status.checked && ctx.session.sessionUser.is_admin) {
-                    change.auditors2 = await ctx.service.changeAudit.getListGroupByWithoutYB(change.cid, change.times);
-                }
                 const settleBills = ctx.change.readySettle ? await ctx.service.settleBills.getAllDataByCondition({ where: { settle_id: ctx.change.readySettle.id } }) : [];
                 const settlePos = ctx.change.readySettle ? await ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: ctx.change.readySettle.id } }) : [];
                 // 判断并是否更新结算清单数据
                 await ctx.service.change.checkSettleUpdate(ctx.tender.id, ctx.change.readySettle);
-                // 获取清单
-                const changeList = await ctx.service.changeAuditList.getList(change.cid);
+
                 // 处理清单数据
-                const removeSettleNum = change.status !== audit.flow.status.checked ? await ctx.service.changeSettleList.updateChangeList(change.cid, settleBills, settlePos, changeList) : 0;
+                const removeSettleNum = change.status !== audit.change.status.checked ? await ctx.service.changeSettleList.updateChangeList(change.cid, settleBills, settlePos, changeList) : 0;
                 const renderData = {
                     tender,
                     change,
@@ -661,12 +406,12 @@ module.exports = app => {
                     changeConst,
                     changeClass: fun_set.change_class,
                     changeState: fun_set.change_state,
-                    auditStatus,
-                    auditConst: audit.flow,
+                    auditConst: audit.change,
                     ledgerConsts: audit.ledger.status,
+                    auditType,
+                    auditorGroups: change.userGroups,
                     attList,
                     whiteList,
-                    auditList,
                     showPlanBtn,
                     planList,
                     tpUnit: change.tp_decimal ? change.tp_decimal : ctx.tender.info.decimal.tp,
@@ -683,28 +428,25 @@ module.exports = app => {
                     removeSettleNum,
                 };
                 // 获取是否已存在调用变更令
-                let changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, change.cid);
+                let changeUsedData = await ctx.service.stageChange.getFinalUsedData(ctx.tender.id, change.cid);
                 changeUsedData = ctx.helper._.orderBy(ctx.helper._.filter(changeUsedData, function(item) {
                     return item.qty !== null;
                 }), ['sorder'], ['desc']);
                 const useChangeUsedData = [];
                 if (changeUsedData.length > 0) { // 防止未创建期时调用
-                    // const stage = await this.ctx.service.stage.getLastestStage(ctx.tender.id, true);
                     for (const cu of changeUsedData) {
-                        // if (cu.sorder !== 0 ||
-                        //     (cu.sorder === 0 && !(stage.status === audit.stage.status.uncheck || stage.status === audit.stage.status.checkNo))) {
                         const index = ctx.helper._.findIndex(useChangeUsedData, { cbid: cu.cbid });
                         if (index !== -1) {
                             useChangeUsedData[index].qty = ctx.helper.add(useChangeUsedData[index].qty, cu.qty);
                         } else {
                             useChangeUsedData.push(cu);
                         }
-                        // }
                     }
                 }
+                console.log(useChangeUsedData);
                 renderData.changeUsedData = useChangeUsedData;
                 renderData.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.qty); }));
-                if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9 || ctx.session.sessionUser.is_admin) {
+                if (!change.readOnly || ctx.session.sessionUser.is_admin) {
                     // 获取所有项目参与者
                     const accountList = await ctx.service.projectAccount.getAllDataByCondition({
                         where: { project_id: ctx.session.sessionProject.id, enable: 1 },
@@ -715,34 +457,7 @@ module.exports = app => {
                         const groupList = accountList.filter(item1 => item1.company === item.name);
                         return { groupName: item.name, groupList };
                     });
-                }
-                // 根据auditStatus状态获取的不同的数据
-                if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) {
                     renderData.changeUnits = changeConst.units;
-                    // 重新上报获取审批流程
-                    if (auditStatus === 2 || auditStatus === 9) {
-                        const auditList2 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
-                        // 展示页右侧审批流程列表
-                        const auditList3 = [];
-                        for (let time = 1; time <= change.times - 1; time++) {
-                            const auditTimeList = [];
-                            let max_sort = 1;
-                            for (const al of auditList2) {
-                                if (al.times === time) {
-                                    auditTimeList.push(al);
-                                    if (al.usite > max_sort) {
-                                        max_sort = al.usite;
-                                    }
-                                }
-                            }
-                            for (const i in auditTimeList) {
-                                auditTimeList[i].max_sort = max_sort;
-                            }
-                            auditList3.push(auditTimeList);
-                        }
-                        renderData.auditList3 = auditList3;
-                    }
-
                     // 获取公司列表
                     const companyList = await ctx.service.changeCompany.getAllDataByCondition({ where: { tid: ctx.tender.id } });
                     renderData.companyList = companyList;
@@ -780,95 +495,11 @@ module.exports = app => {
                         renderData.change.class = ctx.helper._.find(fun_set.change_class, { checked: true }).value;
                         await ctx.service.change.saveInfo({ class: ctx.helper._.find(fun_set.change_class, { checked: true }).value });
                     }
-                } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) {
-                    // 展示页左侧审批流程列表和清单审批列表数据
-                    const times = change.status === audit.flow.status.back ?
-                        change.times - 1 : change.times;
-                    const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(change.cid, times);
-
-                    // 展示页右侧审批流程列表
-                    const auditList3 = [];
-                    for (let time = 1; time <= times; time++) {
-                        const auditTimeList = [];
-                        let max_sort = 1;
-                        for (const al of auditList) {
-                            if (al.times === time) {
-                                auditTimeList.push(al);
-                                if (al.usite > max_sort) {
-                                    max_sort = al.usite;
-                                }
-                            }
-                        }
-                        for (const i in auditTimeList) {
-                            auditTimeList[i].max_sort = max_sort;
-                        }
-                        auditList3.push(auditTimeList);
-                    }
-                    renderData.auditList3 = auditList3;
-                    for (const cl of changeList) {
-                        const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
-                        // 清单表页赋值
-                        for (const [index, au] of auditList2.entries()) {
-                            if (au.usite !== 0) {
-                                cl['audit_amount_' + au.uid] = audit_amount[index - 1] !== undefined ? audit_amount[index - 1] : null;
-                            }
-                        }
-                        cl.changed_amount = ctx.helper._.indexOf([audit.flow.status.backnew, audit.flow.status.checking, audit.flow.status.checked], change.status) !== -1 ?
-                            (audit_amount !== '' ? audit_amount[audit_amount.length - 1] :
-                                (ctx.helper._.indexOf([audit.flow.status.backnew, audit.flow.status.checking], change.status) !== -1 ? cl.camount : 0)) : cl.camount;
-                        // cl.changed_amount = ctx.helper.add(cl.oamount ? parseFloat(cl.oamount) : 0, changed_amount ? parseFloat(changed_amount) : 0);
-                    }
-                    renderData.auditList2 = auditList2;
-                } else if (auditStatus === 6) {
-                    // 展示页左侧审批流程列表和清单审批列表数据
-                    const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(change.cid, change.times);
-                    renderData.auditList2 = auditList2;
-                    const auditList3 = await ctx.service.changeAudit.getListOrderByTimes(change.cid, change.times);
-                    for (const i in auditList3) {
-                        auditList3[i].max_sort = auditList2.length - 1;
-                    }
-                    renderData.auditList3 = auditList3;
-
-                    // 展示页右侧审批流程列表
-                    const auditList5 = await ctx.service.changeAudit.getListByBack(change.cid, change.times);
-                    const auditList4 = [];
-                    for (let time = 1; time <= change.times; time++) {
-                        const auditTimeList = [];
-                        let max_sort = 1;
-                        for (const al of auditList5) {
-                            if (al.times === time) {
-                                auditTimeList.push(al);
-                                if (al.usite > max_sort) {
-                                    max_sort = al.usite;
-                                }
-                            }
-                        }
-                        for (const i in auditTimeList) {
-                            auditTimeList[i].max_sort = max_sort;
-                        }
-                        if (auditTimeList.length > 0) {
-                            auditList4.push(auditTimeList);
-                        }
-                    }
-                    renderData.auditList4 = auditList4;
-                    for (const cl of changeList) {
-                        const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
-                        // 清单表页赋值
-                        for (const [index, au] of auditList2.entries()) {
-                            if (au.usite !== 0) {
-                                cl['audit_amount_' + au.uid] = au.uid === ctx.session.sessionUser.accountId ? cl.spamount : (audit_amount[index - 1] !== undefined ? audit_amount[index - 1] : null);
-                            }
-                        }
-                        cl.changed_amount = ctx.helper._.indexOf([audit.flow.status.backnew, audit.flow.status.checking, audit.flow.status.checked], change.status) !== -1 ?
-                            (audit_amount !== '' ? audit_amount[audit_amount.length - 1] :
-                                (ctx.helper._.indexOf([audit.flow.status.backnew, audit.flow.status.checking], change.status) !== -1 ? cl.camount : 0)) : cl.camount;
-                        // cl.changed_amount = ctx.helper.add(cl.oamount ? parseFloat(cl.oamount) : 0, changed_amount ? parseFloat(changed_amount) : 0);
-                    }
+                } else if (change.readOnly && change.shenpiPower) {
                     renderData.changeLedgerList = await ctx.service.changeLedger.getAllDataByCondition({ where: { tender_id: ctx.tender.id } });
                     renderData.changePosList = await ctx.service.changePos.getAllDataByCondition({ where: { tid: ctx.tender.id } });
                 }
                 renderData.changeList = changeList;
-                renderData.auditList = auditList;
                 await this.layout('change/information.ejs', renderData, 'change/information_modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -999,20 +630,20 @@ module.exports = app => {
                 if (ctx.change.uid !== ctx.session.sessionUser.accountId) {
                     throw '您无权上报该变更令数据';
                 }
-                if (!(ctx.change.status === audit.flow.status.uncheck || ctx.change.status === audit.flow.status.back || ctx.change.status === audit.flow.status.revise)) {
+                if (!(ctx.change.status === audit.change.status.uncheck || ctx.change.status === audit.change.status.checkNo || ctx.change.status === audit.change.status.revise)) {
                     throw '该变更令当前无法上报';
                 }
                 // 判断是否是修订,判断有无审批人员作弊
-                if ((ctx.change.status === audit.flow.status.revise || ctx.change.is_revise) && ctx.tender.info.shenpi.change === shenpiConst.sp_status.sqspr) {
+                if ((ctx.change.status === audit.change.status.revise || ctx.change.is_revise) && ctx.tender.info.shenpi.change === shenpiConst.sp_status.sqspr) {
                     // 获取上一次的审批人流程
-                    const lastUserList = await ctx.service.changeAudit.getListGroupByTimes(ctx.change.cid, ctx.change.times - 1);
+                    const lastUserList = await ctx.service.changeAudit.getUniqAuditor(ctx.change.cid, ctx.change.times - 1);
                     const lastUidList = ctx.helper._.map(lastUserList, 'uid');
                     // 判断上一次审批是否为非原报为审批人
                     const nowUidList = ctx.helper._.map(ctx.change.auditors, 'uid');
                     // 判断条件修订可上报条件
                     // 1.有原报,不管有无其他人   可以添加原报作为审核人,但是不能只原报上报
                     // 2.无原报,有其他人   不可以添加原报
-                    // const noYBUidList = ctx.change.status === audit.flow.status.revise ? ctx.helper._.initial(ctx.helper._.tail(lastUidList)) : ctx.helper._.tail(lastUidList);
+                    // const noYBUidList = ctx.change.status === audit.change.status.revise ? ctx.helper._.initial(ctx.helper._.tail(lastUidList)) : ctx.helper._.tail(lastUidList);
                     const noYBUidList = ctx.helper._.tail(lastUidList);
                     // if (!ctx.helper._.isEqual(lastUidList, nowUidList) && ctx.helper._.includes(noYBUidList, lastUidList[0]) && nowUidList.length === 2 && nowUidList[0] === nowUidList[1]) {
                     if (nowUidList.length === 2 && nowUidList[0] === nowUidList[1]) {
@@ -1048,7 +679,7 @@ module.exports = app => {
                 if (ctx.change.uid !== ctx.session.sessionUser.accountId) {
                     throw '您无权添加审核人';
                 }
-                if (ctx.change.status === audit.flow.status.checking || ctx.change.status === audit.flow.status.checked) {
+                if (ctx.change.status === audit.change.status.checking || ctx.change.status === audit.change.status.checked) {
                     throw '当前不允许添加审核人';
                 }
 
@@ -1065,8 +696,7 @@ module.exports = app => {
                     throw '添加审核人失败';
                 }
 
-                // const auditors = await ctx.service.changeAudit.getAuditorsWithOwner(ctx.change.id, ctx.change.times);
-                const auditors = null;
+                const auditors = await ctx.service.changeAudit.getUserGroup(ctx.change.id, ctx.change.times);
                 ctx.body = { err: 0, msg: '', data: auditors };
             } catch (err) {
                 this.log(err);
@@ -1184,8 +814,8 @@ module.exports = app => {
                 }
                 const status = parseInt(ctx.request.body.status);
                 // 判断是否到你审批,如果不是则无法审批
-                const curAuditor = await ctx.service.changeAudit.getCurAuditor(changeData.cid, changeData.times);
-                if (!curAuditor || (curAuditor && curAuditor.uid !== ctx.session.sessionUser.accountId)) {
+                const curAuditor = await ctx.service.changeAudit.getCurAuditors(changeData.cid, changeData.times);
+                if (!curAuditor || (curAuditor && ctx.helper._.findIndex(curAuditor, { uid: ctx.session.sessionUser.accountId }) === -1)) {
                     throw '该变更令当前您无权操作';
                 }
                 const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
@@ -1198,14 +828,14 @@ module.exports = app => {
                     case 3:// 审批通过
                         result = await ctx.service.change.approvalSuccess(pid, ctx.request.body, changeData);
                         break;
-                    case 4:// 审批终止
-                        result = await ctx.service.change.approvalStop(ctx.request.body);
-                        break;
+                    // case 4:// 审批终止
+                    //     result = await ctx.service.change.approvalStop(ctx.request.body);
+                    //     break;
                     case 5:// 审批退回到原报人
-                        result = await ctx.service.change.approvalBack(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNo(pid, ctx.request.body, changeData);
                         break;
                     case 6:// 审批退回到上一个审批人
-                        result = await ctx.service.change.approvalBackNew(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNoPre(pid, ctx.request.body, changeData);
                         break;
                     default:break;
                 }
@@ -1283,7 +913,7 @@ module.exports = app => {
                 const files = [];
                 let index = 0;
                 const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid });
-                const extra_upload = change.status === audit.flow.status.checked;
+                const extra_upload = change.status === audit.change.status.checked;
                 while ((stream = await parts()) !== undefined) {
                     // 判断用户是否选择上传文件
                     if (!stream.filename) {
@@ -1467,7 +1097,7 @@ module.exports = app => {
                 if (!fileInfo || !Object.keys(fileInfo).length) {
                     throw '该文件不存在';
                 }
-                if (!fileInfo.extra_upload && change.status === audit.flow.status.checked) {
+                if (!fileInfo.extra_upload && change.status === audit.change.status.checked) {
                     throw '无权限删除';
                 }
                 if (fileInfo !== undefined && fileInfo !== '') {
@@ -1549,16 +1179,7 @@ module.exports = app => {
          */
         async checkAgain(ctx) {
             try {
-                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.cid });
-                if (!changeData) {
-                    throw '变更令数据错误';
-                }
-                // 获取终审
-                const auditInfo = await ctx.service.changeAudit.getAuditorByStatus(changeData.cid, changeData.times, audit.flow.status.checked);
-                if (changeData.status !== audit.flow.status.checked || ctx.session.sessionUser.accountId !== auditInfo.uid) {
-                    throw '您无权进行该操作';
-                }
-                const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
+                const readySettle = await ctx.service.settle.getReadySettle(ctx.change.tid);
                 if (readySettle && readySettle.settle_order !== ctx.tender.data.settle_order) {
                     throw '结算数据发生变化,请刷新页面再提交';
                 }
@@ -1576,16 +1197,20 @@ module.exports = app => {
                     }
                 }
                 // 重新审批
-                const result = await ctx.service.change.checkAgain(changeData.cid);
-                if (!result) {
-                    throw '重新审批失败';
+                if ((ctx.change.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.change.status === audit.change.status.checked) {
+                    const result = await ctx.service.change.checkAgain(ctx.change);
+                    if (!result) {
+                        throw '重新审批失败';
+                    }
+                    // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
+                    ctx.body = {
+                        err: 0,
+                        url: ctx.request.header.referer,
+                        msg: '',
+                    };
+                } else {
+                    throw '您无权进行该操作';
                 }
-                // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
-                ctx.body = {
-                    err: 0,
-                    url: ctx.request.header.referer,
-                    msg: '',
-                };
             } catch (err) {
                 console.log(err);
                 // ctx.redirect(ctx.request.header.referer);
@@ -1604,14 +1229,10 @@ module.exports = app => {
          */
         async checkRevise(ctx) {
             try {
-                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.cid });
-                if (!changeData) {
-                    throw '变更令数据错误';
-                }
-                if (changeData.status !== audit.flow.status.checked || ctx.session.sessionUser.accountId !== changeData.uid) {
+                if (ctx.change.status !== audit.change.status.checked || ctx.session.sessionUser.accountId !== ctx.change.uid) {
                     throw '您无权进行该操作';
                 }
-                const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
+                const readySettle = await ctx.service.settle.getReadySettle(ctx.change.tid);
                 if (readySettle && readySettle.settle_order !== ctx.tender.data.settle_order) {
                     throw '结算数据发生变化,请刷新页面再提交';
                 }
@@ -1636,7 +1257,7 @@ module.exports = app => {
                 //     throw '该变更令已被调用,无法重新审批';
                 // }
                 // 重新审批
-                const result = await ctx.service.change.checkRevise(changeData.cid);
+                const result = await ctx.service.change.checkRevise(ctx.change);
                 if (!result) {
                     throw '修订发起失败';
                 }
@@ -1664,19 +1285,15 @@ module.exports = app => {
          */
         async cancelRevise(ctx) {
             try {
-                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.cid });
-                if (!changeData) {
-                    throw '变更令数据错误';
-                }
-                if (!(changeData.status === audit.flow.status.revise && (ctx.session.sessionUser.accountId === changeData.uid || ctx.session.sessionUser.accountId === ctx.session.sessionUser.is_admin))) {
+                if (!(ctx.change.status === audit.change.status.revise && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.session.sessionUser.accountId === ctx.session.sessionUser.is_admin))) {
                     throw '您无权进行该操作';
                 }
-                const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
+                const readySettle = await ctx.service.settle.getReadySettle(ctx.change.tid);
                 if (readySettle && readySettle.settle_order !== ctx.tender.data.settle_order) {
                     throw '结算数据发生变化,请刷新页面再提交';
                 }
                 // 重新审批
-                const result = await ctx.service.change.cancelRevise(changeData.cid, changeData.times);
+                const result = await ctx.service.change.cancelRevise(ctx.change.cid, ctx.change.times);
                 if (!result) {
                     throw '撤销修订失败';
                 }
@@ -1700,9 +1317,9 @@ module.exports = app => {
                 //     throw '台账修订中,请勿修改提交期数据';
                 // }
                 const data = JSON.parse(ctx.request.body.data);
-                if (ctx.session.sessionUser.is_admin && ctx.change.status !== audit.flow.status.checked) {
+                if (ctx.session.sessionUser.is_admin && ctx.change.status !== audit.change.status.checked) {
                     await ctx.service.changeAudit.saveAudit(ctx.change.cid, ctx.change.times, data);
-                    const auditors = await ctx.service.changeAudit.getListGroupByTimes(ctx.change.cid, ctx.change.times);
+                    const auditors = await ctx.service.changeAudit.getUniqUserGroup(ctx.change.id, ctx.change.times);
                     ctx.body = { err: 0, msg: '', data: auditors };
                 } else {
                     throw '您无权进行该操作';
@@ -1807,7 +1424,7 @@ module.exports = app => {
                 const change = ctx.change;
                 let edit = true;
                 let changing = false;
-                if (change.status !== audit.flow.status.uncheck && change.status !== audit.flow.status.back && change.status !== audit.flow.status.revise) {
+                if (change.status !== audit.change.status.uncheck && change.status !== audit.change.status.checkNo && change.status !== audit.change.status.revise) {
                     // throw '本条变更审批中或已完成,无法操作台账数据';
                     edit = false;
                     changing = true;
@@ -1861,7 +1478,7 @@ module.exports = app => {
                 if (!data.postType || !data.postData) throw '数据错误';
                 const responseData = { err: 0, msg: '', data: {} };
                 const change = ctx.change;
-                if (change.status !== audit.flow.status.uncheck && change.status !== audit.flow.status.back && change.status !== audit.flow.status.revise) {
+                if (change.status !== audit.change.status.uncheck && change.status !== audit.change.status.checkNo && change.status !== audit.change.status.revise) {
                     throw '该变更令正在审批中或已完成,无法操作新增部位数据';
                 }
                 // 判断是否在修订中,是则无法操作本页

+ 15 - 20
app/controller/wap_controller.js

@@ -369,7 +369,7 @@ module.exports = app => {
             try {
                 const tender = ctx.tender.data;
                 const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid });
-                const times = change.status !== auditConst.flow.status.back ? change.times : change.times - 1;
+                const times = change.status !== auditConst.change.status.checkNo ? change.times : change.times - 1;
                 const auditList = await ctx.service.changeAudit.getListOrderByTimes(change.cid, times);
                 const auditGroupList = await ctx.service.changeAudit.getListGroupByTimes(change.cid, times);
                 const renderData = {
@@ -377,7 +377,7 @@ module.exports = app => {
                     change,
                     auditList,
                     auditGroupList,
-                    auditConst: auditConst.flow,
+                    auditConst: auditConst.change,
                     changeConst,
                     tpUnit: ctx.tender.info.decimal.tp,
                 };
@@ -516,40 +516,35 @@ module.exports = app => {
          */
         async changeApproval(ctx) {
             try {
-                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.change_id });
+                const cid = ctx.request.body.change_id;
+                const changeData = await ctx.service.change.getDataByCondition({ cid });
                 if (!changeData) {
                     throw '变更令数据错误';
                 }
                 // 判断是否到你审批,如果不是则无法审批
-                const curAuditor = await ctx.service.changeAudit.getCurAuditor(changeData.cid, changeData.times);
-                if (!curAuditor || (curAuditor && curAuditor.uid !== ctx.session.sessionUser.accountId)) {
+                const curAuditor = await ctx.service.changeAudit.getCurAuditors(changeData.cid, changeData.times);
+                if (!curAuditor || (curAuditor && ctx.helper._.findIndex(curAuditor, { uid: ctx.session.sessionUser.accountId }) === -1)) {
                     throw '该变更令当前您无权操作';
                 }
+                const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
+                if (readySettle && readySettle.settle_order !== ctx.tender.data.settle_order) {
+                    throw '结算数据发生变化,请刷新页面再提交';
+                }
                 const status = parseInt(ctx.request.body.status);
                 const pid = this.ctx.session.sessionProject.id;
                 let result = false;
                 switch (status) {
                     case 3:// 审批通过
-                        // 获取前一个人的list,生成bills_list
-                        // 获取已选清单
-                        const changeList = await ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: ctx.request.body.change_id } });
-                        const bills_array = [];
-                        for (const cl of changeList) {
-                            const bill = cl.id + '_' + cl.spamount;
-                            bills_array.push(bill);
-                        }
-                        const postData = ctx.request.body;
-                        postData.bills_list = bills_array.join(',');
                         result = await ctx.service.change.approvalSuccess(pid, ctx.request.body, changeData);
                         break;
-                    case 4:// 审批终止
-                        result = await ctx.service.change.approvalStop(ctx.request.body);
-                        break;
+                    // case 4:// 审批终止
+                    //     result = await ctx.service.change.approvalStop(ctx.request.body);
+                    //     break;
                     case 5:// 审批退回到原报人
-                        result = await ctx.service.change.approvalBack(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNo(pid, ctx.request.body, changeData);
                         break;
                     case 6:// 审批退回到上一个审批人
-                        result = await ctx.service.change.approvalBackNew(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNoPre(pid, ctx.request.body, changeData);
                         break;
                     default:break;
                 }

+ 30 - 9
app/middleware/change_audit_check.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const status = require('../const/audit').flow.status;
+const status = require('../const/audit').change.status;
 const shenpiConst = require('../const/shenpi');
 const _ = require('lodash');
 
@@ -28,26 +28,47 @@ module.exports = options => {
             if (!cid) {
                 throw '您访问的变更令不存在';
             }
-            const change = yield this.service.change.getDataByCondition({ cid });
-            if (!change) throw '变更令数据有误';
-            if ((change.status === status.uncheck || change.status === status.back || change.status === status.revise) && this.tender.info.shenpi.change !== shenpiConst.sp_status.sqspr) {
+            // const change = yield this.service.change.getDataByCondition({ cid });
+            if (!this.change) {
+                const change = yield this.service.change.getDataByCondition({ cid });
+                if (!change) throw '变更令数据有误';
+                yield this.service.change.loadChangeUser(change);
+                this.change = change;
+            }
+            const change = this.change;
+            if ((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && this.tender.info.shenpi.change !== shenpiConst.sp_status.sqspr) {
                 const shenpi_status = this.tender.info.shenpi.change;
                 // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
-                const auditList = yield this.service.changeAudit.getAllDataByCondition({ where: { cid: change.cid, times: change.times }, orders: [['usort', 'asc']] });
+                const auditList = yield this.service.changeAudit.getAllDataByCondition({ where: { cid: change.cid, times: change.times }, orders: [['usite', 'asc']] });
                 auditList.shift();
                 const auditIdList = _.map(auditList, 'uid');
                 if (shenpi_status === shenpiConst.sp_status.gdspl) {
                     const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status } });
-                    const shenpiIdList = _.map(shenpiList, 'audit_id');
+                    // const shenpiIdList = _.map(shenpiList, 'audit_id');
                     // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    if (!_.isEqual(auditIdList, shenpiIdList)) {
-                        yield this.service.changeAudit.updateNewAuditList(change, shenpiIdList);
+                    let sameAudit = auditList.length === shenpiList.length;
+                    if (sameAudit) {
+                        for (const audit of auditList) {
+                            const shenpi = shenpiList.find(x => { return x.audit_id === audit.uid; });
+                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                sameAudit = false;
+                                break;
+                            }
+                        }
+                    }
+                    if (!sameAudit) {
+                        yield this.service.changeAudit.updateNewAuditList(change, shenpiList);
+                        yield this.service.change.loadChangeUser(change);
+                        yield this.service.change.doCheckChangeCanCancel(change);
                     }
                 } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
                     const shenpiInfo = yield this.service.shenpiAudit.getDataByCondition({ tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status });
                     // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
-                    if (shenpiInfo && shenpiInfo.audit_id !== _.last(auditIdList)) {
+                    const lastAuditors = auditList.filter(x => { return x.usite === auditList.length - 1; });
+                    if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].uid))) {
                         yield this.service.changeAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
+                        yield this.service.change.loadChangeUser(change);
+                        yield this.service.change.doCheckChangeCanCancel(change);
                     } else if (!shenpiInfo) {
                         // 不存在终审人的状态下这里恢复为授权审批人
                         this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;

+ 29 - 15
app/middleware/change_check.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const status = require('../const/audit').flow.status;
+const status = require('../const/audit').change.status;
 const shenpiConst = require('../const/shenpi');
 const _ = require('lodash');
 
@@ -30,47 +30,61 @@ module.exports = options => {
             }
             const change = yield this.service.change.getDataByCondition({ cid });
             // 读取原报、审核人数据
-            change.auditors = yield this.service.changeAudit.getListGroupByTimes(change.cid, change.times);
-            change.curAuditor = yield this.service.changeAudit.getCurAuditor(change.cid, change.times);
+            // 读取原报、审核人数据
+            yield this.service.change.loadChangeUser(change);
+            // change.auditors = yield this.service.changeAudit.getListGroupByTimes(change.cid, change.times);
+            // change.curAuditor = yield this.service.changeAudit.getCurAuditor(change.cid, change.times);
 
             if (!change) throw '变更令数据有误';
             // 权限相关
             // todo 校验权限 (变更参与人)
             const accountId = this.session.sessionUser.accountId,
-                auditorIds = _.map(change.auditors, 'uid'),
                 shareIds = [];
             const permission = this.session.sessionUser.permission;
+            // if (change.status === status.uncheck || change.status === status.checkNo) {
+            //     change.readOnly = accountId !== change.uid;
+            // } else if (change.status === status.checked) {
+            //     change.readOnly = true;
+            // } else {
+            //     change.readOnly = change.flowAuditors.indexOf(accountId) < 0;
+            //     if (!change.readOnly) {
+            //         change.readOnly = !_.isEqual(change.flowAuditorIds, change.curAuditorIds);
+            //         change.canCheck = true;
+            //     }
+            // }
             if (accountId === change.uid) { // 原报
-                if (change.curAuditor) {
-                    change.readOnly = change.curAuditor.uid !== accountId;
-                } else {
-                    change.readOnly = change.status !== status.uncheck && change.status !== status.back && change.status !== status.revise;
-                }
+                change.curTimes = change.times;
+                change.filePermission = true;
             } else if (this.tender.isTourist) {
-                change.readOnly = true;
-            } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
+                change.curTimes = change.times;
+                change.filePermission = this.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
+            } else if (change.auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
-                change.readOnly = true;
+                change.curTimes = change.status === status.checkNo || change.status === status.revise ? change.times - 1 : change.times;
+                change.filePermission = true;
             } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
                 change.readOnly = true;
-            } else if (change.status === status.back && change.uid !== accountId) {
+            } else if ((change.status === status.checkNo || change.status === status.revise) && change.uid !== accountId) {
                 const preAuditors = yield this.service.changeAudit.getListGroupByTimes(change.cid, change.times - 1);
                 const preAuditorIds = _.map(preAuditors, 'uid');
                 if (preAuditorIds.indexOf(accountId) === -1) {
                     throw '您无权查看该数据';
                 }
-                change.readOnly = true;
+                change.filePermission = true;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }
             change.readySettle = yield this.service.settle.getReadySettle(change.tid);
+            // 调差的readOnly 指表格和页面只能看不能改,和审批无关
+            change.readOnly = !((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && accountId === change.uid);
+            change.shenpiPower = (change.status === status.checking || change.status === status.checkNoPre) && change.curAuditorIds.indexOf(accountId) !== -1;
             this.change = change;
-            if ((change.status === status.uncheck || change.status === status.back || change.status === status.revise) && change.tp_decimal !== this.tender.info.decimal.tp) {
+            if ((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && change.tp_decimal !== this.tender.info.decimal.tp) {
                 this.change.tp_decimal = this.tender.info.decimal.tp;
                 yield this.service.change.updateDecimalAndTp();
             }

+ 56 - 62
app/public/js/change_audit.js

@@ -84,66 +84,60 @@ $(document).ready(function () {
     // 添加到审批流程中
     $('dl').on('click', 'dd', function () {
         const id = parseInt($(this).data('id'));
-        if (id) {
-            const auditListIdData = [];
-            $('#auditList li').each(function () {
-                const aid = $(this).data('auditid');
-                auditListIdData.push(aid);
-            });
-            if (!in_array(auditListIdData, id)) {
-                postData(getUrlPre() + '/audit/add', { auditorId: id }, (datas) => {
-                    if (shenpi_status === shenpiConst.sp_status.gdzs) {
-                        auditListIdData.splice(-1,0,id);
-                    } else {
-                        auditListIdData.push(id);
-                    }
-                    const html = [];
-                    const auditorshtml = [];
-                    auditListIdData.unshift(changesUid);
-                    for (const [index,ids] of auditListIdData.entries()) {
-                        const accountInfo = _.find(accountList, { 'id': ids });
-                        if (index !== 0) {
-                            const user = accountInfo.id + '/%/' + accountInfo.name + '/%/' + accountInfo.role + '/%/' + accountInfo.company;
-                            html.push('<li class="list-group-item" data-auditmsg="' + user + '" data-auditid="'+ ids +'">');
-                            if (shenpi_status === shenpiConst.sp_status.sqspr || (shenpi_status === shenpiConst.sp_status.gdzs && index+1 !== auditListIdData.length)) {
-                                html.push('<a href="javascript:void(0);" class="text-danger pull-right remove_audit_btn">移除</a>');
-                            }
-                            html.push('<span>');
-                            html.push(index + ' ');
-                            html.push('</span> ');
-                            html.push(accountInfo.name + ' ');
-                            html.push('<small class="text-muted">');
-                            html.push(accountInfo.role);
-                            html.push('</small>');
-                            html.push('<p class="m-0 ml-2"><small class="text-muted">' + accountInfo.company + '</small></p>');
-                            html.push('</li>');
+        if (id !== 0) {
+            postData(getUrlPre() + '/audit/add', { auditorId: id }, (datas) => {
+                const html = [];
+                // 如果是重新上报,添加到重新上报列表中
+                const auditorshtml = [];
+                for (const [index,data] of datas.entries()) {
+                    if (index !== 0) {
+                        html.push('<li class="list-group-item d-flex" data-auditid="'+ data[0].uid +'">');
+                        html.push(`<div class="col-auto">${index}</div>`);
+                        html.push('<div class="col">');
+                        for (const auditor of data) {
+                            html.push(`<div class="d-inline-block mx-1" auditorId="${auditor.uid}"><i class="fa fa-user text-muted"></i> ${auditor.name} <small class="text-muted">${auditor.role}</small></div>`);
                         }
-                        // 添加新审批人流程修改
-                        auditorshtml.push('<li class="list-group-item" ' + (index !== 0 ? 'data-auditid="' + accountInfo.id + '"' : '') + '>');
-                        auditorshtml.push('<i class="fa ' + (index+1 === auditListIdData.length ? 'fa-stop-circle' : 'fa-chevron-circle-down') + '"></i> ');
-                        auditorshtml.push(accountInfo.name + ' <small class="text-muted">' + accountInfo.role + '</small>');
-                        if (index === 0) {
-                            auditorshtml.push('<span class="pull-right">原报</span>');
-                        } else if (index+1 === auditListIdData.length) {
-                            auditorshtml.push('<span class="pull-right">终审</span>');
-                        } else {
-                            auditorshtml.push('<span class="pull-right">'+ transFormToChinese(index) +'审</span>');
+                        html.push('</div>');
+                        html.push('<div class="col-auto">');
+                        // todo 添加会签或签时
+                        // html.push('<span class="badge badge-pill badge-primary badge-bg-small"><small></small></span>');
+                        if (shenpi_status === shenpiConst.sp_status.sqspr || (shenpi_status === shenpiConst.sp_status.gdzs && index+1 !== datas.length)) {
+                            html.push('<a href="javascript: void(0)" class="text-danger pull-right">移除</a>');
                         }
-                        auditorshtml.push('</li>');
+                        html.push('</div>');
+                        html.push('</li>');
                     }
-                    $('#auditList').html(html.join(''));
-                    $('#shenpi-audit-list').html(auditorshtml.join(''));
-                });
-            } else {
-                toastr.error('审批流程中已存在该用户!');
-            }
+                    auditorshtml.push(`<li class="list-group-item d-flex justify-content-between align-items-center" data-auditid="${index !== 0 ? data[0].uid : ''}">`);
+                    auditorshtml.push('<span class="mr-1"><i class="fa ' + (index === 0 ? 'fa-play-circle fa-rotate-90' : index+1 === datas.length ? 'fa-stop-circle' : 'fa-chevron-circle-down') + '"></i></span>');
+                    auditorshtml.push('<span class="text-muted">');
+                    for (const auditor of data) {
+                        auditorshtml.push(`<small class="d-inline-block text-dark mx-1" title="${auditor.role}" data-auditorId="${auditor.uid}">${auditor.name}</small>`);
+                    }
+                    auditorshtml.push('</span>');
+                    auditorshtml.push('<div class="d-flex ml-auto">');
+                    if (data[0].audit_type !== auditType.key.common) {
+                        auditorshtml.push(`<span class="badge badge-pill badge-${auditType.info[data[0].audit_type].class} p-1"><small>${auditType.info[data[0].audit_type].short}</small></span>`);
+                    }
+                    if (index === 0) {
+                        auditorshtml.push('<span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>');
+                    } else if (index+1 === datas.length) {
+                        auditorshtml.push('<span class="badge badge-light badge-pill"><small>终审</small></span>');
+                    } else {
+                        auditorshtml.push('<span class="badge badge-light badge-pill"><small>'+ transFormToChinese(index) +'审</small></span>');
+                    }
+                    auditorshtml.push('</div>');
+                    auditorshtml.push('</li>');
+                }
+                $('#auditList').html(html.join(''));
+                $('#auditors-list').html(auditorshtml.join(''));
+            });
         }
     });
 
     // 移除审批流程的审批人
-    $('body').on('click', '.remove_audit_btn', function () {
+    $('body').on('click', '#auditList li a', function () {
         const uid = $(this).parents('li').attr('data-auditid');
-        const li = $(this).parent();
+        const li = $(this).parents('li');
         const data = {
             auditorId: uid,
         };
@@ -151,24 +145,24 @@ $(document).ready(function () {
             li.remove();
             let index = 1;
             $('#auditList li').each(function () {
-                $(this).children('span').text(index);
+                $(this).children('.col-auto').eq(0).text(index);
                 index++;
             });
-            if (index === 1) {
-                $('#account_list').val(0);
-            }
+            // if (index === 1) {
+            //     $('#account_list').val(0);
+            // }
 
             // 重新上报时。移除审批流程
             // 令最后一个图标转换
-            $('#shenpi-audit-list li[data-auditid="' + uid + '"]').remove();
-            if ($('#shenpi-audit-list li').length !== 0 && !$('#shenpi-audit-list li i').hasClass('fa-stop-circle')) {
-                $('#shenpi-audit-list li').eq($('#shenpi-audit-list li').length-1).children('i')
+            $('#auditors-list li[data-auditid="' + uid + '"]').remove();
+            if ($('#auditors-list li').length !== 0 && !$('#auditors-list li').find('i').hasClass('fa-stop-circle')) {
+                $('#auditors-list li').eq($('#auditors-list li').length-1).find('i')
                     .removeClass('fa-chevron-circle-down').addClass('fa-stop-circle');
             }
-            for (let i = 0; i < $('#shenpi-audit-list li').length; i++) {
-                $('#shenpi-audit-list li').eq(i).find('.pull-right').text(i === 0 ? '原报' : (i+1 === $('#shenpi-audit-list li').length ? '终' : transFormToChinese(i)) + '审');
+            for (let i = 0; i < $('#auditors-list li').length; i++) {
+                $('#auditors-list li').eq(i).find('.badge-pill').children('small').text(i === 0 ? '原报' : (i+1 === $('#auditors-list li').length ? '终' : transFormToChinese(i)) + '审');
             }
-            $('#shenpi-audit-list li i').eq(0).removeClass('fa-chevron-circle-down').addClass('fa-play-circle');
+            // $('#auditors-list li').eq(0).find('i').removeClass('fa-chevron-circle-down').addClass('fa-play-circle fa-rotate-90');
         });
     });
 

+ 10 - 10
app/public/js/change_information.js

@@ -431,12 +431,12 @@ $(document).ready(() => {
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.unit_price'},
             {title: '申报变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'camount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.camount'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'ca_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.ca_tp'},
-            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'amount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.amount', visible: auditStatus === 7},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'a_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.a_tp', visible: auditStatus === 7},
-            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'spamount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.spamount', visible: [3,4,5,6,8].indexOf(auditStatus) !== -1},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'spa_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.spa_tp', visible: [3,4,5,6,8].indexOf(auditStatus) !== -1},
-            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', hAlign: 2, width: 60, type: 'Number', getValue: '', visible: [1,2,9].indexOf(auditStatus) !== -1},
-            {title: '|金额', colSpan: '|1', rowSpan: '|1', hAlign: 2, width: 80, type: 'Number', getValue: '', visible: [1,2,9].indexOf(auditStatus) !== -1},
+            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'amount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.amount', visible: !readOnly && shenpiPower},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'a_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.a_tp', visible: !readOnly && shenpiPower},
+            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'spamount', hAlign: 2, width: 60, type: 'Number', getValue: 'getValue.spamount', visible: !readOnly && !shenpiPower},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'spa_tp', hAlign: 2, width: 80, type: 'Number', getValue: 'getValue.spa_tp', visible: !readOnly && !shenpiPower},
+            {title: '审批变更|数量', colSpan: '2|1', rowSpan: '1|1', hAlign: 2, width: 60, type: 'Number', getValue: '', visible: readOnly},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', hAlign: 2, width: 80, type: 'Number', getValue: '', visible: readOnly},
         ],
         emptyRows: 0,
         headRows: 2,
@@ -479,11 +479,11 @@ $(document).ready(() => {
         makeBackColor: function () {
             const rowCount = hzSpread.getActiveSheet().getRowCount();
             for (let i = 0; i < rowCount; i++) {
-                if ([3,4,5,6,8].indexOf(auditStatus) !== -1 && hzSpread.getActiveSheet().zh_data[i].camount != hzSpread.getActiveSheet().zh_data[i].spamount) {
+                if (!readOnly && !shenpiPower && hzSpread.getActiveSheet().zh_data[i].camount != hzSpread.getActiveSheet().zh_data[i].spamount) {
                     hzSpread.getActiveSheet().getRange(i, -1, 1, -1).backColor('#ffeeba');
-                } else if (auditStatus === 7 && hzSpread.getActiveSheet().zh_data[i].camount != hzSpread.getActiveSheet().zh_data[i].amount) {
+                } else if (!readOnly && shenpiPower && hzSpread.getActiveSheet().zh_data[i].camount != hzSpread.getActiveSheet().zh_data[i].amount) {
                     hzSpread.getActiveSheet().getRange(i, -1, 1, -1).backColor('#ffeeba');
-                } else if ([1,2,9].indexOf(auditStatus) !== -1 && !(hzSpread.getActiveSheet().zh_data[i].camount === '' || hzSpread.getActiveSheet().zh_data[i].camount === 0 || hzSpread.getActiveSheet().zh_data[i].camount === null)) {
+                } else if (readOnly && !(hzSpread.getActiveSheet().zh_data[i].camount === '' || hzSpread.getActiveSheet().zh_data[i].camount === 0 || hzSpread.getActiveSheet().zh_data[i].camount === null)) {
                     hzSpread.getActiveSheet().getRange(i, -1, 1, -1).backColor('#ffeeba');
                 }
             }
@@ -706,7 +706,7 @@ function getAllList(currPageNum = 1) {
         <td>${moment(att.in_time * 1000).format('YYYY-MM-DD')}<br>${bytesToSize(att.filesize)}</td>
         <td>
             <a href="/change/download/file/${att.id}" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>`
-        html += (att.uid === accountId && (auditStatus === 4 ? Boolean(att.extra_upload) : true)) ?
+        html += (att.uid === accountId && (changeStatus === auditConst.status.checked ? Boolean(att.extra_upload) : true)) ?
             `<a href="javascript:void(0)" class="mr-2 delete-file" data-attid="${att.id}" title="删除附件"><span class="fa fa-trash text-danger"></span></a>` : '';
         html += `</td>`;
     }

+ 4 - 15
app/public/js/change_information_approval.js

@@ -62,12 +62,12 @@ $(document).ready(() => {
         }
     };
     for (const aid of aidList) {
-        const userinfo = _.find(auditList2, { 'uid': aid });
+        // const userinfo = _.find(auditList2, { 'uid': aid });
         const newColcount = {
-            title: userinfo.name + ' 审批|数量',
+            title: (auditors2[aid - 1] && auditors2[aid - 1].length > 1 ? (aid + '审') : auditors2[aid - 1][0].name) + ' 审批|数量',
             colSpan: '2|1', rowSpan: '1|1',
             field: 'audit_amount_' + aid,
-            hAlign: 2, width: 60, type: 'Number', readOnly: aid !== parseInt(accountId) ? true : 'readOnly.isSettle' ,
+            hAlign: 2, width: 60, type: 'Number', readOnly: _.findIndex(auditors2[aid - 1], { uid: parseInt(accountId) }) === -1 ? true : 'readOnly.isSettle' ,
         };
         const newColTp = {
             title: '|金额',
@@ -414,17 +414,6 @@ $(document).ready(() => {
                     returnflag = false;
                 });
             }
-            // 判断并提交变更清单表格数据到表单中
-            const clist = [];
-            for(const [i,cl] of changeList.entries()) {
-                // if (cl['audit_amount_' + accountId] === null || cl['audit_amount_' + accountId] === '') {
-                //     toastr.error('清单第' + (i+1) + '行审批变更数量不能为空');
-                //     returnflag = false;
-                // } else {
-                clist.push(cl.id + '_' + cl['audit_amount_' + accountId]);
-                // }
-            }
-            $('#change-list-approval').val(clist.join(','));
 
             if(returnflag) {
                 $('input[name="w_code"]').val($.trim($('#w_code').val()));
@@ -443,7 +432,7 @@ $(document).ready(() => {
             if (type === undefined) {
                 // toastr.error('请选择退回类型!');
                 if (!$('#warning-text').length) {
-                    $('#change-back-content').prepend('<p id="warning-text" style="color: red; margin: 0;">请选择退回流程</p>');
+                    $('#change-back-content').append('<p id="warning-text" style="color: red; margin: 0;">请选择退回流程</p>');
                 }
                 returnflag = false;
             }

+ 7 - 4
app/public/js/change_information_show.js

@@ -52,9 +52,9 @@ $(document).ready(() => {
         }
     };
     for (const aid of aidList) {
-        const userinfo = _.find(auditList2, { 'uid': aid });
+        // const userinfo = _.find(auditList2, { 'uid': aid });
         const newColcount = {
-            title: userinfo.name + ' 审批|数量',
+            title: (auditors2[aid - 1] && auditors2[aid - 1].length > 1 ? (aid + '审') : auditors2[aid - 1][0].name) + ' 审批|数量',
             colSpan: '2|1', rowSpan: '1|1',
             field: 'audit_amount_' + aid,
             hAlign: 2, width: 60, type: 'Number',
@@ -98,11 +98,14 @@ $(document).ready(() => {
                 return ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.samount, findDecimal(data.unit))), totalPriceUnit);
             },
             changed_amount: function (data) {
-                return ZhCalc.add(ZhCalc.round(data.oamount, findDecimal(data.unit)), ZhCalc.round(data.changed_amount, findDecimal(data.unit)));
+                return ZhCalc.round(ZhCalc.add(data.oamount, data.spamount), findDecimal(data.unit));
+                // return ZhCalc.add(ZhCalc.round(data.oamount, findDecimal(data.unit)), ZhCalc.round(data.checked_amount, findDecimal(data.unit)));
             },
             changed_tp: function (data) {
                 return ZhCalc.add(ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.oamount, findDecimal(data.unit))), totalPriceUnit),
-                    ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.changed_amount, findDecimal(data.unit))), totalPriceUnit));
+                    ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.spamount, findDecimal(data.unit))), totalPriceUnit));
+                // return ZhCalc.add(ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.oamount, findDecimal(data.unit))), totalPriceUnit),
+                //     ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), ZhCalc.round(data.checked_amount, findDecimal(data.unit))), totalPriceUnit));
             },
         },
     };

+ 2 - 2
app/public/js/shenpi.js

@@ -249,7 +249,7 @@ $(document).ready(function () {
         },
         getAuditTypeHtml: function(code, type) {
             const html = [];
-            const hide = code !== 'stage' ? 'style="display: none;"' : '';
+            const hide = ['stage', 'change'].indexOf(code) === -1 ? 'style="display: none;"' : '';
             html.push(`<span class="d-inline-block"><select class="form-control form-control-sm" ${hide} data-type="${type}">`);
             for (const t of auditType.types) {
                 html.push(`<option value="${t.value}" ${t.value === type ? 'selected' : ''}>${t.name}</option>`);
@@ -641,7 +641,7 @@ $(document).ready(function () {
     $('body').on('click', '.set-otherShenpi', function () {
         let canSetOther = true;
         const this_code = $(this).data('code');
-        if (this_code === 'stage') {
+        if (['stage', 'change'].indexOf(this_code) !== -1) {
             const select = $(this).siblings('.lc-show').find('select');
             select.each((i, s) => {
                 if (s.value !== '1') canSetOther = false;

+ 2 - 2
app/public/js/stage_audit.js

@@ -318,7 +318,7 @@ $(document).ready(function () {
                             makeSelectAudit(auditor.aid+'_add', auditor.aid, 'add'),'</div>', '</span>');
                         if (auditor.audit_type !== auditType.key.common) {
                             html.push('<span class="dropdown mr-2">',
-                                '<a href="javascript: void(0)" class="add-audit" id="<%- auditor.aid %>_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">平级</a>',
+                                `<a href="javascript: void(0)" class="add-audit" id="${auditor.aid}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">平级</a>`,
                                 makeSelectAudit(auditor.aid+'_add-sibling', auditor.aid, 'add-sibling'),'</div>', '</span>');
                         }
                     }
@@ -401,7 +401,7 @@ $(document).ready(function () {
             }
             auditorshtml.push('<span class="text-muted">');
             for (const u of data) {
-                auditorshtml.push(`<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="<%- u.aid %>">${u.name}</small>`);
+                auditorshtml.push(`<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`);
             }
             auditorshtml.push('</span>');
             auditorshtml.push('<div class="d-flex ml-auto">');

+ 3 - 4
app/router.js

@@ -531,9 +531,9 @@ module.exports = app => {
     app.post('/tender/:id/change/save', sessionAuth, tenderCheck, uncheckTenderCheck, changeAuditCheck, 'changeController.save');
 
     app.post('/tender/:id/change/approval', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.approval');
-    app.post('/tender/:id/change/check/again', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.checkAgain');
-    app.post('/tender/:id/change/check/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.checkRevise');
-    app.post('/tender/:id/change/cancel/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.cancelRevise');
+    app.post('/tender/:id/change/check/again', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changeCheck, changeAuditCheck, 'changeController.checkAgain');
+    app.post('/tender/:id/change/check/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changeCheck, changeAuditCheck, 'changeController.checkRevise');
+    app.post('/tender/:id/change/cancel/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changeCheck, changeAuditCheck, 'changeController.cancelRevise');
 
     app.post('/tender/:id/change/:cid/check/codeRepeat', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.checkCodeRepeat');
     app.post('/tender/:id/change/:cid/info/copy', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.copyChange');
@@ -541,7 +541,6 @@ module.exports = app => {
     app.post('/change/update/company', sessionAuth, 'changeController.updateCompany');
 
     // 变更令 - 新版本
-    app.get('/tender/:id/change/:cid/info', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, changeAuditCheck, 'changeController.information');// 针对旧数据wap端跳转web问题
     app.get('/tender/:id/change/:cid/information', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, changeAuditCheck, 'changeController.information');
     app.post('/tender/:id/change/:cid/information/save', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, 'changeController.saveListsData');
     app.post('/tender/:id/change/:cid/information/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, changeCheck, changeAuditCheck, 'changeController.startAudit');

文件差异内容过多而无法显示
+ 414 - 396
app/service/change.js


+ 1 - 0
app/service/change_apply_audit.js

@@ -97,6 +97,7 @@ module.exports = app => {
                 case auditConst.status.checking :
                 case auditConst.status.checked :
                 case auditConst.status.revise :
+                case auditConst.status.cancelRevise :
                     sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`caid`, la.`aid`, la.`order` ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                         '  WHERE la.`caid` = ? and la.`status` = ? ' +

+ 427 - 254
app/service/change_audit.js

@@ -8,7 +8,8 @@
  * @version
  */
 
-const auditConst = require('../const/audit').flow;
+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');
@@ -84,7 +85,7 @@ module.exports = app => {
                 operate: '=',
             });
             this.sqlBuilder.setAndWhere('status', {
-                value: 6,
+                value: auditConst.status.checkNoPre,
                 operate: '=',
             });
             const u_sort = [['usort', 'DESC']];
@@ -96,53 +97,6 @@ module.exports = app => {
         }
 
         /**
-         * 获取当前审批人查看info时的状态
-         * @param {Object} change - 变更令数据
-         * @return {void}
-         */
-        async getStatusByChange(change) {
-            const statusConst = auditConst.status;
-            const auditStatusConst = auditConst.auditStatus;
-            const uid = this.ctx.session.sessionUser.accountId;
-            const changeAuditInfo = await this.getAllDataByCondition({ where: { cid: change.cid, times: change.times, uid }, orders: [['usort', 'desc']], limit: 1, offset: 0 });
-            if (!change.status === statusConst.checked && (changeAuditInfo === null || changeAuditInfo[0] === undefined) && !ctx.tender.isTourist) {
-                // 无权限查看此变更令
-                return 0;
-            }
-
-            if (change.status === statusConst.uncheck && uid === change.uid) {
-                // 待上报
-                return 1;
-            } else if (change.status === statusConst.back && uid === change.uid) {
-                // 待重新上报
-                return 2;
-            } else if (change.status === statusConst.revise && uid === change.uid) {
-                // 修订上报
-                return 9;
-            } else if ((change.status === statusConst.back || change.status === statusConst.revise) && uid !== change.uid) {
-                // 被退回或修订中但你不是原报人
-                return 3;
-            } else if (change.status === statusConst.checked) {
-                // 已完成
-                return 4;
-            } else if (change.status === statusConst.checkNo) {
-                // 已终止
-                return 5;
-            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo.length > 0 && changeAuditInfo[0].status === auditStatusConst.checking) {
-                // 待你审批
-                return 6;
-            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo.length > 0 && changeAuditInfo[0].status !== auditStatusConst.checking) {
-                // 审批中但你未到你审批或你已审批
-                return 7;
-            } else if (this.ctx.tender.isTourist) {
-                // 游客模式,只预览不能操作
-                return 8;
-            }
-            // 无权限查看此变更令
-            return 0;
-        }
-
-        /**
          * 根据用户查看此变更状态获取审批人列表
          * @param {Object} change - 变更令
          * @param {int} status - 状态
@@ -259,43 +213,6 @@ module.exports = app => {
         }
 
         /**
-         * 获取比sort大的审批人列表
-         * @param {Object} cid - 变更令id
-         * @param {int} usort - 排序
-         * @return {object} 返回结果
-         */
-        async getNextAuditList(cid, usort) {
-            const sql = 'SELECT * FROM ?? WHERE ' +
-                'cid = ? AND usort > ?';
-            const sqlParam = [this.tableName, cid, usort];
-            const list = await this.db.query(sql, sqlParam);
-            return list;
-        }
-
-        /**
-         * 获取除当前次数的审批人列表
-         * @param {Object} cid - 变更令id
-         * @param {int} times - 次数
-         * @return {object} 返回结果
-         */
-        async getListByBack(cid, times) {
-            this.initSqlBuilder();
-            this.sqlBuilder.setAndWhere('cid', {
-                value: this.db.escape(cid),
-                operate: '=',
-            });
-            this.sqlBuilder.setAndWhere('times', {
-                value: times,
-                operate: '!=',
-            });
-            this.sqlBuilder.orderBy = [['usort', 'ASC']];
-            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
-            const result = await this.db.query(sql, sqlParam);
-
-            return result;
-        }
-
-        /**
          * 获取 审核人 待审批的() 变更令列表
          * @param uid
          * @return {Promise<void>}
@@ -310,7 +227,7 @@ module.exports = app => {
             const sqlParam = [this.tableName, this.ctx.service.change.tableName, this.ctx.service.tender.tableName, uid, 2, auditConst.status.uncheck];
             const changes = await this.db.query(sql, sqlParam);
             for (const c of changes) {
-                if (c.cstatus === auditConst.status.back) {
+                if (c.cstatus === auditConst.status.checkNo) {
                     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];
@@ -332,7 +249,7 @@ module.exports = app => {
          * @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.back, auditConst.status.backnew]) +')';
+            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;
@@ -347,7 +264,7 @@ module.exports = app => {
          */
         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.back, auditConst.status.backnew]) + ') ORDER BY `sin_time` DESC';
+                '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;
@@ -409,7 +326,7 @@ module.exports = app => {
                 '  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.auditStatus.checking, auditConst.status.checking, auditConst.status.backnew];
+            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 ' +
@@ -420,7 +337,7 @@ module.exports = app => {
             return await this.db.query(sql, sqlParam);
         }
 
-        async updateNewAuditList(change, newIdList) {
+        async updateNewAuditList(change, newList) {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先删除旧的审批流(除了原报),再添加新的
@@ -429,19 +346,24 @@ module.exports = app => {
                 await transaction.query(sql, sqlParam);
 
                 const newAuditors = [];
-                let order = 1;
-                let uSort = await transaction.count(this.tableName, { cid: change.cid });
-                for (const aid of newIdList) {
-                    const accountInfo = await this.ctx.service.projectAccount.getDataById(aid);
+                // 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: aid,
+                        tid: change.tid, cid: change.cid, uid: auditor.audit_id,
                         name: accountInfo.name, jobs: accountInfo.role, company: accountInfo.company,
-                        times: change.times, usite: order, usort: uSort, status: auditConst.auditStatus.uncheck,
+                        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,
                     });
-                    order++;
-                    uSort++;
+                    // 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 } });
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -453,26 +375,42 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
-                const idList = this._.map(auditList, 'uid');
-                let order = idList.length + 1;
-                if (idList.indexOf(lastId) !== -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 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 });
+                // 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: order, usort: uSort, status: auditConst.auditStatus.uncheck,
+                    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();
@@ -513,6 +451,10 @@ module.exports = app => {
                 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);
 
@@ -533,6 +475,19 @@ module.exports = app => {
         }
 
         /**
+         * 获取 当前审核组
+         *
+         * @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
@@ -548,6 +503,154 @@ module.exports = app => {
         }
 
         /**
+         * 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 === x.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
@@ -558,17 +661,19 @@ module.exports = app => {
         async addAuditor(cid, auditorId, times = 1, is_gdzs = 0) {
             const transaction = await this.db.beginTransaction();
             try {
-                let newOrder = await transaction.count(this.tableName, { cid, times });
-                let uSort = await transaction.count(this.tableName, { cid });
+                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
-                newOrder = is_gdzs === 1 ? newOrder - 1 : newOrder;
                 uSort = is_gdzs === 1 ? uSort - 1 : uSort;
-                if (is_gdzs) await this._syncOrderByDelete(transaction, cid, newOrder, uSort, times, '+');
+                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: newOrder, usort: uSort, status: auditConst.auditStatus.uncheck,
+                    times: times, usite: newAuditOrder, usort: uSort, status: auditConst.status.uncheck,
+                    audit_order: newAuditOrder,
                 };
                 const result = await transaction.insert(this.tableName, newAuditor);
                 await transaction.commit();
@@ -581,6 +686,20 @@ module.exports = app => {
         }
 
         /**
+         * 获取 最新审核顺序
+         *
+         * @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
@@ -597,8 +716,9 @@ module.exports = app => {
                 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.delete(this.tableName, { id: auditor.id });
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -614,9 +734,9 @@ module.exports = app => {
          * @return {Promise<boolean>}
          */
         async start(cid, times = 1) {
-            const audit = await this.getDataByCondition({ cid, times, usite: 1 });
+            const audits = await this.getAllDataByCondition({ where: { cid, times, usite: 1 } });
             const yBAudit = await this.getDataByCondition({ cid, times, usite: 0 });
-            if (!audit) {
+            if (audits.length === 0) {
                 if(this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdspl) {
                     throw '请联系管理员添加审批人';
                 } else {
@@ -626,12 +746,15 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             try {
-                await transaction.update(this.tableName, { id: audit.id, status: auditConst.auditStatus.checking, sin_time: new Date() });
+                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.auditStatus.checked,
-                    sin_time: new Date(),
+                    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;
@@ -668,7 +791,7 @@ module.exports = app => {
                 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(audit.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, {
+                await this.ctx.helper.sendAliSms(this._.map(audits, 'uid'), smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), SmsAliConst.template.change_check, {
                     biangeng: code,
                     code: shenpiUrl,
                 });
@@ -680,18 +803,20 @@ module.exports = app => {
                     code: this.ctx.session.sessionProject.code,
                     c_name: this.ctx.change.name,
                 };
-                await this.ctx.helper.sendWechat(audit.uid, smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData);
+                await this.ctx.helper.sendWechat(this._.map(audits, 'uid'), smsTypeConst.const.BG, smsTypeConst.judge.approval.toString(), wxConst.template.change, wechatData);
                 // 重新发送配置
-                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,
-                });
+                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) {
@@ -704,7 +829,7 @@ module.exports = app => {
         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.auditStatus.checked, startMonth, endMonth];
+            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;
         }
@@ -722,12 +847,17 @@ module.exports = app => {
             // 2.审批人撤回审批通过,增加流程,并回到它审批中
             // 3.审批人撤回审批退回上一人,并删除退回人,增加流程,并回到它审批中,并更新计量期状态为审批中
             // 4.审批人撤回退回原报操作,删除新增的审批流,增加流程,回滚到它审批中
-            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 '不可撤回,请刷新页面重试';
+            // 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);
@@ -768,20 +898,24 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 // 整理当前流程审核人状态更新
-                const curAudit = await this.getDataByCondition({ cid: change.cid, times: change.times, status: auditConst.auditStatus.checking });
-                // // 审批人变成待审批状态
-                await transaction.update(this.tableName, {
-                    id: curAudit.id,
-                    status: auditConst.auditStatus.uncheck,
-                    sin_time: null,
-                    sdesc: null,
+                // 审批人变成待审批状态
+                const updateData = change.curAuditors.map(x => {
+                    return {
+                        id: x.id,
+                        status: auditConst.status.uncheck,
+                        begin_time: null,
+                        sin_time: null,
+                        sdesc: '',
+                    }
                 });
-                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, curAudit.id);
+                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.auditStatus.checked });
+                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.auditStatus.checking,
+                    status: auditConst.status.checking,
+                    end_time: null,
                     sin_time: new Date(),
                 });
                 // 变更令变成待上报状态
@@ -791,7 +925,7 @@ module.exports = app => {
                     },
                 };
                 await transaction.update(this.ctx.service.change.tableName, {
-                    status: change.times === 1 ? auditConst.status.uncheck : auditConst.status.back,
+                    status: change.times === 1 ? auditConst.status.uncheck : auditConst.status.checkNo,
                 }, options);
                 await transaction.commit();
             } catch(err) {
@@ -815,57 +949,50 @@ module.exports = app => {
          * @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 curAudit = await this.getDataByCondition({ cid: change.cid, times: change.times, status: auditConst.status.checking });
-                const preAudit = change.preAudit;
-                if (!curAudit || curAudit.usite <= 1 || !preAudit) {
-                    throw '撤回用户数据错误';
-                }
+                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, curAudit.usort]);
+                await transaction.query(sql, [change.cid, change.times, change.curAuditors[0].usort]);
                 // 当前审批人2次添加至流程中
-                const newAuditors = [];
-                // 先入撤回记录
-                newAuditors.push({
-                    tid: change.tid,
-                    cid: change.cid,
-                    uid: preAudit.uid,
-                    name: preAudit.name,
-                    jobs: preAudit.jobs,
-                    company: preAudit.company,
-                    times: change.times,
-                    usite: preAudit.usite,
-                    usort: curAudit.usort,
-                    status: auditConst.auditStatus.checkCancel,
-                    sin_time: time,
-                    sdesc: '',
+                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,
+                    });
                 });
-                newAuditors.push({
-                    tid: change.tid,
-                    cid: change.cid,
-                    uid: preAudit.uid,
-                    name: preAudit.name,
-                    jobs: preAudit.jobs,
-                    company: preAudit.company,
-                    times: change.times,
-                    usite: preAudit.usite,
-                    usort: curAudit.usort + 1,
-                    status: auditConst.auditStatus.checking,
-                    sin_time: time,
+                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, newAuditors);
+                await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
+                const newAuditors = [];
                 // 当前审批人变成待审批
-                await transaction.update(this.tableName, { id: curAudit.id, usort: curAudit.usort + 2, sin_time: null, status: auditConst.auditStatus.uncheck });
-                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, curAudit.id);
+                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.getAllDataByCondition({
-                    where: { cid: change.cid },
-                });
+                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 = [];
@@ -915,50 +1042,44 @@ module.exports = app => {
          * @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 curAudit = await this.getDataByCondition({ cid: change.cid, times: change.times, status: auditConst.status.checking });
-                const preAudit = change.preAudit;
-                if (!curAudit || curAudit.order <= 1 || !preAudit) {
-                    throw '撤回用户数据错误';
-                }
+                const selfAuditor = change.preAuditors.find(x => { return x.uid === accountId; });
+                if (!selfAuditor) throw '撤回用户数据错误';
                 // 整理当前流程审核人状态更新
                 // 删除当前审批人
-                await transaction.delete(this.tableName, { id: curAudit.id });
-                await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, curAudit.id);
+                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 = [];
-                newAuditors.push({
-                    tid: change.tid,
-                    cid: change.cid,
-                    uid: preAudit.uid,
-                    name: preAudit.name,
-                    jobs: preAudit.jobs,
-                    company: preAudit.company,
-                    times: change.times,
-                    usite: preAudit.usite,
-                    usort: curAudit.usort,
-                    status: auditConst.auditStatus.checkCancel,
-                    sin_time: time,
-                    sdesc: '',
+                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,  { sin_time: time, status: auditConst.status.checking }, {
-                    where: { cid: change.cid, times: change.times, usort: curAudit.usort + 1 }
+                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.getAllDataByCondition({
-                    where: { cid: change.cid },
-                });
+                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(',') : [];
-                    // const last_amount = audit_amount[audit_amount.length - 1] ? audit_amount[audit_amount.length - 1] : 0;
                     audit_amount.push(cl.spamount);
                     const list_update = {
                         id: cl.id,
@@ -1005,47 +1126,43 @@ module.exports = app => {
          * @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 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, change.times - 1, curAudit.usort]);
+                await transaction.query(sql, [change.cid, selfAuditor.times, selfAuditor.usort]);
                 // 当前审批人2次添加至流程中
-                const newAuditors = [];
-                newAuditors.push({
-                    tid: change.tid,
-                    cid: change.cid,
-                    uid: curAudit.uid,
-                    name: curAudit.name,
-                    jobs: curAudit.jobs,
-                    company: curAudit.company,
-                    times: curAudit.times,
-                    usite: curAudit.usite,
-                    usort: curAudit.usort + 1,
-                    status: auditConst.auditStatus.checkCancel,
-                    sin_time: time,
-                    sdesc: '',
+                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,
+                    });
                 });
-                newAuditors.push({
-                    tid: change.tid,
-                    cid: change.cid,
-                    uid: curAudit.uid,
-                    name: curAudit.name,
-                    jobs: curAudit.jobs,
-                    company: curAudit.company,
-                    times: curAudit.times,
-                    usite: curAudit.usite,
-                    usort: curAudit.usort + 2,
-                    status: auditConst.auditStatus.checking,
-                    sin_time: time,
+                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, newAuditors);
+                await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
                 // 删除当前次审批流
                 await transaction.delete(this.tableName, { cid: change.cid, times: change.times });
                 // 回退数据
@@ -1057,6 +1174,29 @@ module.exports = app => {
                 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';
@@ -1069,6 +1209,10 @@ module.exports = app => {
             try {
                 const auditors = await this.getListGroupByWithoutYB(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 '当前人下无法操作新增';
@@ -1081,21 +1225,44 @@ module.exports = app => {
                         name: nowAuditInfo.name,
                         company: nowAuditInfo.company,
                         jobs: nowAuditInfo.role,
-                        usort: now_audit.usort+1,
-                        usite: now_audit.usite+1,
+                        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.auditStatus.uncheck,
+                        status: auditConst.status.uncheck,
                     };
                     // order+1
-                    await this._syncOrderByDelete(transaction, cid, now_audit.usite+1, now_audit.usort+1, times, '+');
+                    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.order === now_audit.order; });
                     await transaction.delete(this.tableName, { cid, times, uid: now_audit.uid, usite: now_audit.usite });
-                    await this._syncOrderByDelete(transaction, cid, now_audit.usite, now_audit.usort, times);
+                    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: {
@@ -1124,7 +1291,13 @@ module.exports = app => {
                     //     }
                     // });
                 }
-                if (this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdspl || this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdzs) {
+                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);
+                } 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'));
                 }

+ 1 - 0
app/service/change_plan_audit.js

@@ -97,6 +97,7 @@ module.exports = app => {
                 case auditConst.status.checking :
                 case auditConst.status.checked :
                 case auditConst.status.revise :
+                case auditConst.status.cancelRevise :
                     sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`cpid`, la.`aid`, la.`order`, la.`status` ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id` ' +
                         '  WHERE la.`cpid` = ? and la.`status` = ? ' +

+ 2 - 2
app/service/shenpi_audit.js

@@ -358,9 +358,9 @@ module.exports = app => {
                     tid: tenderId,
                     sp_type,
                     sp_status,
-                    audit_id: a.aid,
+                    audit_id: a.aid || a.uid,
                     audit_order: a.audit_order,
-                    audit_type: a.audit_type
+                    audit_type: a.audit_type,
                 });
             }
             await transaction.insert(this.tableName, insertDatas);

+ 64 - 53
app/view/change/information.ejs

@@ -14,44 +14,48 @@
                 </div>
                 <div class="pull-right mr-3" id="sp-btn">
                     <% if (ctx.change.cancancel) { %>
-                        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-cancel" class="btn btn-danger btn-sm">撤回</a>
+                        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-cancel" class="btn btn-danger btn-sm mr-2">撤回</a>
                     <% } %>
-                    <!--info状态区分-->
-                    <% if (auditStatus === 1) { %>
-                        <a href="#sub-ap" data-category="up_change" data-toggle="modal" data-target="#sub-ap" class="btn btn-primary btn-sm">上报审批</a>
-                    <% } else if (auditStatus === 2 || auditStatus === 9) { %>
-                        <a href="#sub-sp2" data-category="up_change" data-toggle="modal" data-target="#sub-sp2" class="btn btn-primary btn-sm">重新上报</a>
-                        <% if (auditStatus === 9) { %>
-                            <a href="#sub-revoke" data-toggle="modal" data-target="#sub-revoke" class="btn btn-warning btn-sm">撤销修订</a>
+                    <% if (ctx.change.status === auditConst.status.uncheck) { %>
+                        <% if (ctx.session.sessionUser.accountId === ctx.change.uid) { %>
+                            <a id="sub-sp-btn" href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm">上报审批</a>
+                        <% } else { %>
+                            <a id="sub-sp-btn" href="#sub-sp" data-toggle="modal" data-target="#sub-sp" class="btn btn-outline-secondary btn-sm">上报中</a>
                         <% } %>
-                    <% } else if (auditStatus === 3) { %>
+                    <% } else if (ctx.change.status === auditConst.status.checking) { %>
+                        <% if (ctx.change.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
+                            <a id="sp-done-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm">审批通过</a>
+                            <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm">审批退回</a>
+                        <% } else { %>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                        <% } %>
+                    <% } else if (ctx.change.status === auditConst.status.checkNoPre) { %>
                         <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted">审批退回</a>
-                    <% } else if (auditStatus === 4) { %>
+                        <% if (ctx.change.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
+                            <a id="sp-done-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm">审批通过</a>
+                            <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm">审批退回</a>
+                        <% } %>
+                    <% } else if (ctx.change.status === auditConst.status.checked) { %>
                         <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-success btn-sm">审批完成</a>
-                    <% } else if (auditStatus === 5) { %>
-                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-danger btn-sm">审批终止</a>
-                    <% } else if (auditStatus === 6) { %>
-                        <a href="#sp-done" data-toggle="modal" data-target="#sp-done" class="btn btn-success btn-sm">审批通过</a>
-                        <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm">审批退回</a>
-                    <% } else if (auditStatus === 7) { %>
-                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
-                    <% } else if (auditStatus === 8) { %>
-                        <% if (change.status === auditConst.status.uncheck) { %>
-                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">上报中</a>
-                        <% } else if (change.status === auditConst.status.checking) { %>
-                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                        <% if (ctx.change.auditors !== undefined && ctx.change.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
+                            <!--重新审批-->
+                            <a href="#sp-down-back" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm ml-2">重新审批</a>
+                        <% } %>
+                        <% if (ctx.session.sessionUser.accountId === ctx.change.uid) { %>
+                            <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-revise" class="btn btn-warning btn-sm ml-2">修订变更</a>
+                        <% } %>
+                    <% } else if (ctx.change.status === auditConst.status.checkNo || ctx.change.status === auditConst.status.revise) { %>
+                        <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted sp-list-btn">审批<% if (ctx.change.status === auditConst.status.checkNo) { %>退回<% } else { %>修订<% } %></a>
+                        <% if (ctx.session.sessionUser.accountId === ctx.change.uid) { %>
+                            <a href="#sp-list" data-type="show" data-toggle="modal" data-target="#sp-list" class="btn btn-primary btn-sm sp-list-btn">重新上报</a>
+                        <% } %>
+                        <% if (ctx.change.status === auditConst.status.revise && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.session.sessionUser.is_admin)) { %>
+                            <a href="#sub-revoke" data-toggle="modal" data-target="#sub-revoke" class="btn btn-warning btn-sm ml-2">撤销修订</a>
                         <% } %>
-                    <% } %>
-                    <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === auditList2[auditList2.length-1].uid) { %>
-                        <!--重新审批-->
-                        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm">重新审批</a>
-                    <% } %>
-                    <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === change.uid) { %>
-                        <a href="javascript: void(0);" data-toggle="modal" data-target="#sp-down-revise" class="btn btn-warning btn-sm">修订变更</a>
                     <% } %>
                 </div>
                 <!--info状态区分-->
-                <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
+                <% if (!change.readOnly) { %>
                     <div class="pull-right px-3" id="show-save-btn" style="display: none">
 <!--                        <span>您修改了变更信息,记得保存修改。</span>-->
                         <button class="btn btn-sm btn-primary save_change_btn" id="save_change"><i class="fa fa-save"></i> 保存修改</button>
@@ -66,8 +70,8 @@
         <div class="w-100 sub-content row">
             <div class="c-body" id="left-view" style="width: 33.33%">
                 <div class="sjs-bar-1">
-                    <input type="hidden" id="tenderId" value="<%- ctx.tender.id %>">
-                    <input type="hidden" id="changeId" value="<%- ctx.change.cid %>">
+                    <input type="hidden" id="tenderId" value="<%- tender.id %>">
+                    <input type="hidden" id="changeId" value="<%- change.cid %>">
                     <ul class="nav nav-tabs">
                         <li class="nav-item">
                             <a class="nav-link active" data-toggle="tab" data-tab="bgxinxi" href="#bgxinxi" role="tab">变更信息</a>
@@ -76,7 +80,7 @@
                             <a class="nav-link" data-toggle="tab" data-tab="bgfujian" href="#bgfujian" role="tab">附件</a>
                         </li>
                         <li class="nav-item ml-auto pt-1 mr-3" id="copy_btn">
-                            <% if(auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
+                            <% if(!change.readOnly) { %>
                                 <a class="btn btn-sm btn-primary" href="#add-bj" data-toggle="modal" data-target="#add-bj">拷贝其他变更令数据</a>
                             <% } %>
                         </li>
@@ -85,7 +89,7 @@
                             <button  data-toggle="modal" class="btn btn-sm btn-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</button>
                             <!-- <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a> -->
                             <a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a>
-                            <% if (auditStatus !== 8 || (auditStatus === 8 && ctx.tender.touristPermission.file)) { %>
+                            <% if (change.filePermission) { %>
                             <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="上传附件"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
                             <% } %>
                             <a href="javascript: void(0);" id="zipDown" download style="display: none;"></a>
@@ -95,7 +99,7 @@
                 <div class="tab-content">
                     <div class="tab-pane active" id="bgxinxi">
                         <div class="sjs-sh-1" style="overflow-y: auto;">
-                            <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
+                            <% if (!change.readOnly) { %>
                             <form class="p-2" action="/tender/<%- change.tid %>/change/<%- change.cid %>/information/save?_csrf_j=<%= ctx.csrf %>" method="post" id="change_form">
                                 <% if (ctx.session.sessionProject.page_show.openChangeState) { %>
                                 <div class="form-group">
@@ -233,7 +237,7 @@
                                     <label>申请编号</label>
                                     <input class="form-control form-control-sm" value="<%- change.code %>" type="text" readonly>
                                 </div>
-                                <% if (auditStatus === 4) { %>
+                                <% if (change.status === auditConst.status.checked) { %>
                                     <div class="form-group">
                                         <label>变更令号(批复编号)</label>
                                         <input class="form-control form-control-sm" value="<%- change.p_code %>" type="text" readonly>
@@ -335,7 +339,7 @@
                                 </div>
                                 <div class="form-group">
                                     <label>批复文号</label>
-                                    <input class="form-control form-control-sm" id="w_code" placeholder="" type="text" value="<%- change.w_code %>" <% if (auditStatus !== 6) { %>readonly<% } %>>
+                                    <input class="form-control form-control-sm" id="w_code" placeholder="" type="text" value="<%- change.w_code %>" <% if (!change.shenpiPower) { %>readonly<% } %>>
                                 </div>
                             </form>
                             <% } %>
@@ -364,7 +368,7 @@
                                                 <td><%- moment(att.in_time * 1000).format('YYYY-MM-DD') %><br><%- ctx.helper.bytesToSize(att.filesize) %></td>
                                                 <td>
                                                     <a href="/change/download/file/<%- att.id %>" class="mr-2" title="下载"><span class="fa fa-download text-primary"></span></a>
-                                                    <% if (att.uid === ctx.session.sessionUser.accountId && (auditStatus === 4 ? Boolean(att.extra_upload) : true )) { %>
+                                                    <% if (att.uid === ctx.session.sessionUser.accountId && (change.status === auditConst.status.checked ? Boolean(att.extra_upload) : true )) { %>
                                                         <a href="javascript:void(0)" class="mr-2 delete-file" data-attid="<%- att.id %>" title="删除附件"><span class="fa fa-trash text-danger"></span></a>
                                                     <% } %>
                                                 </td>
@@ -385,7 +389,7 @@
                 <div class="sjs-height-1 row w-100 sub-content">
                     <div class="c-body" style="width: 100%">
                         <div class="m-1" id="list-tab">
-                            <% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
+                            <% if (!change.readOnly) { %>
                                 <div class="d-inline-block ml-1">
                                     <a href="#addlist" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="open-list-modal" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-plus" aria-hidden="true"></i> <span class="order_text"><% if (change.order_by === 0) { %>添加<% } else { %>插入<% } %></span>台账清单</a>
                                 </div>
@@ -424,7 +428,7 @@
                                     <label class="custom-control-label" for="customCheck1">变更详情</label>
                                 </div>
                             </div>
-                            <% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
+                            <% if (change.readOnly && !change.shenpiPower) { %>
                                 <div class="d-inline-block mr-2">
                                     <div class="custom-control custom-checkbox">
                                         <input type="checkbox" class="custom-control-input" id="show-table-detail">
@@ -469,21 +473,19 @@
     </div>
 </div>
 <script>
-    const tenderName = JSON.parse(unescape('<%- escape(JSON.stringify(tender.name)) %>'));
+    const tenderName = JSON.parse(unescape('<%- escape(JSON.stringify(tender.data.name)) %>'));
     const tenderId = '<%- tender.id %>';
     const totalPriceUnit = '<%- tpUnit %>';
     const unitPriceUnit = '<%- upUnit %>';
     const accountId = parseInt('<%- ctx.session.sessionUser.accountId %>');
     const ledgeStatus = '<%- tender.ledger_status %>';
     const ledgerConsts = JSON.parse('<%- JSON.stringify(ledgerConsts) %>');
-    const auditStatus = parseInt('<%- auditStatus %>');
     const changeName = JSON.parse(unescape('<%- escape(JSON.stringify(change.name)) %>'));
     let changeTp = parseFloat('<%- change.total_price ? change.total_price : 0 %>');
     let changePp = parseFloat('<%- change.positive_tp ? change.positive_tp : 0 %>');
     let changeNp = parseFloat('<%- change.negative_tp ? change.negative_tp : 0 %>');
     const changeStatus = parseFloat('<%- change.status %>');
     const touristPermission = parseInt('<%- ctx.tender.touristPermission.file %>');
-    const auditList = JSON.parse(unescape('<%- escape(JSON.stringify(auditList)) %>'));
     const precision = JSON.parse('<%- JSON.stringify(precision) %>');
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
@@ -492,14 +494,16 @@
     const change_uid = parseInt('<%- change.uid %>');;
     const settleBills = JSON.parse(unescape('<%- escape(JSON.stringify(settleBills)) %>'));
     const settlePos = JSON.parse(unescape('<%- escape(JSON.stringify(settlePos)) %>'));
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
     autoFlashHeight();
-    $('a[href="#sub-ap"').click(function() {
+    $('a[href="#sub-sp"').click(function() {
         if (parseInt(ledgeStatus) === ledgerConsts.uncheck) {
             $('#warning-ledger').modal('show');
             return false;
         }
     });
     const readOnly = <%- change.readOnly %>;
+    const shenpiPower = <%- change.shenpiPower %>;
     const changeSpread = SpreadJsObj.createNewSpread($('#change-spread')[0]);
     const changeSpreadSheet = changeSpread.getActiveSheet();
     const xmjSpread = SpreadJsObj.createNewSpread($('#xmj-spread')[0]);
@@ -527,7 +531,7 @@
         toastr.warning('结算发生变化,已移除 ' + removeSettleNum + ' 条已结算清单。');
     }
 </script>
-<% if (auditStatus === 1 || auditStatus === 2 || auditStatus === 9) { %>
+<% if (!change.readOnly) { %>
 <script>
     let changeUnits = JSON.parse('<%- JSON.stringify(changeUnits) %>');
     changeUnits = _.map(changeUnits, 'unit');
@@ -569,18 +573,25 @@
 </script>
 <script src="/public/js/change_information_set.js"></script>
 <script src="/public/js/change_audit.js"></script>
-<% } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
+<% } else if (change.readOnly && !change.shenpiPower) { %>
 <script>
-    const auditList2 = JSON.parse(unescape('<%- escape(JSON.stringify(auditList2)) %>'));
-    const aidList = _.map(auditList2, 'uid');
-    aidList.splice(0, 1);
+    const auditors2 = JSON.parse(unescape('<%- escape(JSON.stringify(change.auditors2)) %>'));
+    auditors2.shift();
+    const aidList = [];
+    for (let i = 0; i < auditors2.length; i++) {
+        aidList.push(auditors2[i][0].audit_order);
+    }
 </script>
 <script src="/public/js/change_information_show.js?202206211"></script>
-<% } else if (auditStatus === 6) { %>
+<% } else if (change.shenpiPower) { %>
 <script>
-    const auditList2 = JSON.parse(unescape('<%- escape(JSON.stringify(auditList2)) %>'));
-    const aidList = _.map(auditList2, 'uid');
-    aidList.splice(0, 1);
+    const auditors2 = JSON.parse(unescape('<%- escape(JSON.stringify(change.auditors2)) %>'));
+    auditors2.shift();
+    console.log(auditors2);
+    const aidList = [];
+    for (let i = 0; i < auditors2.length; i++) {
+        aidList.push(auditors2[i][0].audit_order);
+    }
     let changeUsedData = JSON.parse(unescape('<%- escape(JSON.stringify(changeUsedData)) %>'));
     // console.log(changeUsedData);
     const changeLedgerList = JSON.parse(unescape('<%- escape(JSON.stringify(changeLedgerList)) %>'));

文件差异内容过多而无法显示
+ 730 - 880
app/view/change/information_modal.ejs


+ 1 - 1
app/view/stage/audit_modal.ejs

@@ -611,7 +611,7 @@
                                                                     <input class="form-check-input" type="radio" name="checkType" id="inlineRadio2" value="<%- auditConst.status.checkNoPre %>">
                                                                     <label class="form-check-label" for="inlineRadio2">退回上一审批人
                                                                         <% const pre = his.find(x => { return x.audit_order === auditor.audit_order - 1}); %>
-                                                                        <% (pre.audit_type === auditType.key.common ? pre.auditors[0].name : `${pre.audit_order}审`)%>
+                                                                        <%- (pre.audit_type === auditType.key.common ? pre.auditors[0].name : `${pre.audit_order}审`)%>
                                                                     </label>
                                                                 </div>
                                                                 <% } %>

+ 2 - 2
app/view/tender/shenpi.ejs

@@ -41,7 +41,7 @@
                                             <span class="col-auto"><%- ctx.helper.transFormToChinese(i+1) %>审</span>
                                             <span class="col-7 spr-span">
                                                 <span class="d-inline-block">
-                                                    <select class="form-control form-control-sm" data-type="<%- auditGroup[0].audit_type %>" <% if (sp.code !== 'stage') { %> style="display: none;" <% } %>>
+                                                    <select class="form-control form-control-sm" data-type="<%- auditGroup[0].audit_type %>" <% if (['stage', 'change'].indexOf(sp.code) === -1 ) { %> style="display: none;" <% } %>>
                                                         <% for (const at of auditType.types) { %>
                                                         <option value="<%- at.value %>" <% if (auditGroup[0].audit_type === at.value) { %>selected<%} %>><%- at.name %></option>
                                                         <% } %>
@@ -98,7 +98,7 @@
                                             <span class="col-auto">一审</span>
                                             <span class="col-7 spr-span">
                                                 <span class="d-inline-block">
-                                                    <select class="form-control form-control-sm" data-type="<%- auditType.key.common %>" <% if (sp.code !== 'stage') { %> style="display: none;" <% } %>>
+                                                    <select class="form-control form-control-sm" data-type="<%- auditType.key.common %>" <% if (['stage', 'change'].indexOf(sp.code) === -1) { %> style="display: none;" <% } %>>
                                                         <% for (const at of auditType.types) { %>
                                                         <option value="<%- at.value %>" <% if (auditType.key.common === at.value) { %>selected<%} %>><%- at.name %></option>
                                                         <% } %>

+ 18 - 0
sql/update.sql

@@ -75,3 +75,21 @@ CREATE TABLE `zh_tender_cert`  (
   `create_time` datetime NULL COMMENT '入库时间',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT = '标段从业人员表';
+
+ALTER TABLE `zh_change_audit`
+ADD COLUMN `audit_type`  tinyint(4) UNSIGNED NOT NULL DEFAULT 1 COMMENT '审批类型(1个人,2会签,3或签)' AFTER `sin_time`,
+ADD COLUMN `audit_order`  tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '审批顺序' AFTER `audit_type`;
+
+update `zh_change_audit` set `audit_order` = `usite`;
+
+ALTER TABLE `zh_change_audit`
+ADD COLUMN `begin_time` datetime NULL DEFAULT NULL COMMENT '审批开始时间' AFTER `sdesc`,
+ADD COLUMN `end_time` datetime NULL DEFAULT NULL COMMENT '审批结束时间' AFTER `begin_time`,
+MODIFY COLUMN `name` varchar(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '审批人名称' AFTER `uid`,
+MODIFY COLUMN `jobs` varchar(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '审批人职称' AFTER `name`,
+MODIFY COLUMN `company` varchar(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '审批人单位' AFTER `jobs`;
+MODIFY COLUMN `sin_time` datetime NULL DEFAULT NULL COMMENT '审批结束时间' AFTER `end_time`;
+
+update `zh_change_audit` set `begin_time` = `sin_time`;
+update `zh_change_audit` set `end_time` = `sin_time`;
+