Explorar o código

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

Tony Kang hai 1 ano
pai
achega
060762e1be
Modificáronse 39 ficheiros con 2574 adicións e 1078 borrados
  1. 164 78
      app/controller/change_controller.js
  2. 12 0
      app/controller/file_controller.js
  3. 4 4
      app/controller/report_controller.js
  4. 32 24
      app/middleware/change_apply_audit_check.js
  5. 4 4
      app/middleware/change_apply_check.js
  6. 20 16
      app/middleware/change_audit_check.js
  7. 107 0
      app/middleware/change_plan_audit_check.js
  8. 10 12
      app/middleware/change_plan_check.js
  9. 32 24
      app/middleware/change_project_audit_check.js
  10. 3 3
      app/middleware/change_project_check.js
  11. 0 7
      app/public/js/change_apply.js
  12. 5 5
      app/public/js/change_apply_audit.js
  13. 169 0
      app/public/js/change_plan.js
  14. 84 71
      app/public/js/change_plan_audit.js
  15. 41 31
      app/public/js/change_plan_information.js
  16. 4 4
      app/public/js/change_project_audit.js
  17. 47 0
      app/public/js/file_detail.js
  18. 1 1
      app/public/js/se_bonus.js
  19. 7 2
      app/router.js
  20. 1 1
      app/service/change_apply_audit.js
  21. 72 20
      app/service/change_plan.js
  22. 656 286
      app/service/change_plan_audit.js
  23. 2 2
      app/service/change_project_audit.js
  24. 6 0
      app/service/file.js
  25. 3 1
      app/service/stage_audit.js
  26. 0 1
      app/service/stage_pay.js
  27. 8 3
      app/service/sub_project.js
  28. 34 2
      app/service/tender_cache.js
  29. 8 6
      app/view/change/apply.ejs
  30. 3 1
      app/view/change/index.ejs
  31. 24 9
      app/view/change/plan.ejs
  32. 2 2
      app/view/change/plan_information.ejs
  33. 885 451
      app/view/change/plan_information_modal.ejs
  34. 25 1
      app/view/change/plan_modal.ejs
  35. 8 6
      app/view/change/project.ejs
  36. 4 0
      app/view/file/file_modal.ejs
  37. 77 0
      config/config.remoteprod.js
  38. 1 0
      package.json
  39. 9 0
      sql/update.sql

+ 164 - 78
app/controller/change_controller.js

@@ -61,14 +61,22 @@ module.exports = app => {
             const tp = await ctx.service.change.getTp(tender.id, status);
             if (changes !== null) {
                 for (const c of changes) {
-                    c.curAuditors = await ctx.service.changeAudit.getAuditorsByStatus(c.cid, c.status, c.times);
-                    if (c.status === audit.change.status.checkNoPre) {
-                        c.curAuditors2 = await ctx.service.stageAudit.getAuditorsByStatus(c.cid, audit.change.status.checking, c.times);
-                    }
-                    if (c.status === audit.change.status.checkNo || c.status === audit.change.status.revise) {
-                        const changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, c.cid);
-                        c.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.qty); }));
-                        c.isSettle = await ctx.service.changeSettleList.isSettle(c.cid);
+                    if (c.status !== audit.change.status.checked || !c.final_auditor_str) {
+                        c.curAuditors = await ctx.service.changeAudit.getAuditorsByStatus(c.cid, c.status, c.times);
+                        if (c.status === audit.change.status.checkNoPre) {
+                            c.curAuditors2 = await ctx.service.stageAudit.getAuditorsByStatus(c.cid, audit.change.status.checking, c.times);
+                        }
+                        if (c.status === audit.change.status.checkNo || c.status === audit.change.status.revise) {
+                            const changeUsedData = await ctx.service.stageChange.getAllFinalUsedData(ctx.tender.id, c.cid);
+                            c.stageChangeNum = this.ctx.helper.sum(changeUsedData.map(x => { return Math.abs(x.qty); }));
+                            c.isSettle = await ctx.service.changeSettleList.isSettle(c.cid);
+                        }
+                        if (c.status === audit.change.status.checked && c.curAuditors.length > 0) {
+                            const final_auditor_str = c.curAuditors[0].audit_type === auditType.key.common
+                                ? c.curAuditors[0].name + (c.curAuditors[0].role ? '-' + c.curAuditors[0].role : '')
+                                : ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审';
+                            await ctx.service.change.defaultUpdate({ final_auditor_str }, { where: { cid: c.cid } });
+                        }
                     }
                     page_total = ctx.helper.add(page_total, c.total_price);
                 }
@@ -1711,7 +1719,15 @@ module.exports = app => {
             const changes = await ctx.service.changeProject.getListByStatus(tender.id, status, 1, sorts, orders);
             const total = await ctx.service.changeProject.getCountByStatus(tender.id, status);
             for (const c of changes) {
-                c.curAuditors = await ctx.service.changeProjectAudit.getAuditorsByStatus(c.id, c.status, c.times);
+                if (c.status !== audit.change.status.checked || !c.final_auditor_str) {
+                    c.curAuditors = await ctx.service.changeProjectAudit.getAuditorsByStatus(c.id, c.status, c.times);
+                    if (c.status === audit.change.status.checked && c.curAuditors.length > 0) {
+                        const final_auditor_str = c.curAuditors[0].audit_type === auditType.key.common
+                            ? c.curAuditors[0].name + (c.curAuditors[0].role ? '-' + c.curAuditors[0].role : '')
+                            : ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审';
+                        await ctx.service.changeProject.defaultUpdate({ final_auditor_str }, { where: { id: c.id } });
+                    }
+                }
             }
             const accountInfo = await this.ctx.service.projectAccount.getDataById(this.ctx.session.sessionUser.accountId);
             const userPermission = accountInfo !== undefined && accountInfo.permission !== ''
@@ -2418,10 +2434,14 @@ module.exports = app => {
                         throw '验证码不正确!';
                     }
                 }
-                // 重新审批
-                const result = await ctx.service.changeProjectAudit.checkAgain(ctx.change);
-                if (!result) {
-                    throw '重新审批失败';
+                if ((ctx.change.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.change.status === audit.changeProject.status.checked) {
+                    // 重新审批
+                    const result = await ctx.service.changeProjectAudit.checkAgain(ctx.change);
+                    if (!result) {
+                        throw '重新审批失败';
+                    }
+                } else {
+                    throw '您无权进行该操作';
                 }
                 // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
                 ctx.body = {
@@ -2536,7 +2556,15 @@ module.exports = app => {
             let page_total = 0;
             const tp = await ctx.service.changeApply.getTp(tender.id, status);
             for (const c of changes) {
-                c.curAuditors = await ctx.service.changeApplyAudit.getAuditorsByStatus(c.id, c.status, c.times);
+                if (c.status !== audit.change.status.checked || !c.final_auditor_str) {
+                    c.curAuditors = await ctx.service.changeApplyAudit.getAuditorsByStatus(c.id, c.status, c.times);
+                    if (c.status === audit.change.status.checked && c.curAuditors.length > 0) {
+                        const final_auditor_str = c.curAuditors[0].audit_type === auditType.key.common
+                            ? c.curAuditors[0].name + (c.curAuditors[0].role ? '-' + c.curAuditors[0].role : '')
+                            : ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审';
+                        await ctx.service.changeApply.defaultUpdate({ final_auditor_str }, { where: { id: c.id } });
+                    }
+                }
                 page_total = ctx.helper.add(page_total, c.total_price);
             }
             const tender_userInfo = await ctx.service.projectAccount.getDataById(ctx.tender.data.user_id);
@@ -3215,23 +3243,6 @@ module.exports = app => {
         }
 
         /**
-         * 撤回审批
-         * @param ctx
-         * @return {Promise<void>}
-         */
-        async checkApplyAuditCancel(ctx) {
-            try {
-                if (!ctx.change.cancancel) throw '您无权进行该操作';
-
-                await ctx.service.changeApplyAudit.checkCancel(ctx.change);
-                ctx.body = { err: 0, url: ctx.request.header.referer, msg: '' };
-            } catch (err) {
-                this.log(err);
-                ctx.body = { err: 1, msg: err };
-            }
-        }
-
-        /**
          * 变更申请重新审批
          * @param {Object} ctx - egg全局变量
          * @return {void}
@@ -3239,8 +3250,8 @@ module.exports = app => {
         async checkApplyAgain(ctx) {
             try {
                 // 获取终审
-                const auditInfo = await this.ctx.service.changeApplyAudit.getAuditorByStatus(ctx.change.id, audit.changeApply.status.checked);
-                if (ctx.change.status !== audit.changeApply.status.checked || ctx.session.sessionUser.accountId !== auditInfo.aid) {
+                // const auditInfo = await this.ctx.service.changeApplyAudit.getAuditorByStatus(ctx.change.id, audit.changeApply.status.checked);
+                if (ctx.change.status !== audit.changeApply.status.checked) {
                     throw '您无权进行该操作';
                 }
                 // 判断是否被变更申请调用了,是则无法发起修订
@@ -3261,10 +3272,14 @@ module.exports = app => {
                         throw '验证码不正确!';
                     }
                 }
-                // 重新审批
-                const result = await ctx.service.changeApplyAudit.checkAgain(ctx.change);
-                if (!result) {
-                    throw '重新审批失败';
+                if ((ctx.change.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.change.status === audit.changeApply.status.checked) {
+                    // 重新审批
+                    const result = await ctx.service.changeApplyAudit.checkAgain(ctx.change);
+                    if (!result) {
+                        throw '重新审批失败';
+                    }
+                } else {
+                    throw '您无权进行该操作';
                 }
                 // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
                 ctx.body = {
@@ -3379,7 +3394,18 @@ module.exports = app => {
             let page_total = 0;
             const tp = await ctx.service.changePlan.getTp(tender.id, status);
             for (const c of changes) {
-                c.curAuditor = await ctx.service.changePlanAudit.getAuditorByStatus(c.id, c.status, c.times);
+                if (c.status !== audit.change.status.checked || !c.final_auditor_str) {
+                    c.curAuditors = await ctx.service.changePlanAudit.getAuditorsByStatus(c.id, c.status, c.times);
+                    // if (c.status === audit.changePlan.status.checkNoPre) {
+                    //     c.curAuditors2 = await ctx.service.changePlanAudit.getAuditorsByStatus(c.id, audit.changePlan.status.checking, c.times);
+                    // }
+                    if (c.status === audit.change.status.checked && c.curAuditors.length > 0) {
+                        const final_auditor_str = c.curAuditors[0].audit_type === auditType.key.common
+                            ? c.curAuditors[0].name + (c.curAuditors[0].role ? '-' + c.curAuditors[0].role : '')
+                            : ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审';
+                        await ctx.service.changePlan.defaultUpdate({ final_auditor_str }, { where: { id: c.id } });
+                    }
+                }
                 page_total = ctx.helper.add(page_total, c.total_price);
             }
             const tender_userInfo = await ctx.service.projectAccount.getDataById(ctx.tender.data.user_id);
@@ -3456,6 +3482,7 @@ module.exports = app => {
                 auditConst: audit.changePlan,
                 ruleConst: codeRuleConst.measure,
                 changeConst,
+                auditType,
                 changeApplyList,
                 acLists,
                 page_total,
@@ -3498,6 +3525,25 @@ module.exports = app => {
         }
 
         /**
+         * 审批流程(Get)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async changePlanAuditors(ctx) {
+            try {
+                const id = JSON.parse(ctx.request.body.data).id;
+                const tenderId = ctx.params.id;
+                const changeInfo = await ctx.service.changePlan.getDataById(id);
+                await ctx.service.changePlan.loadChangeUser(changeInfo);
+                await ctx.service.changePlan.loadChangeAuditViewData(changeInfo);
+                ctx.body = { err: 0, msg: '', data: changeInfo };
+            } catch (error) {
+                this.log(error);
+                ctx.body = { err: 1, msg: error.toString(), data: null };
+            }
+        }
+
+        /**
          * 新增变更方案 (Post)
          *
          * @param {Object} ctx - egg全局变量
@@ -3551,22 +3597,7 @@ module.exports = app => {
          * @private
          */
         async _getChangePlanAuditViewData(ctx) {
-            const auditConst = audit.changePlan;
-            const times = ctx.change.status === auditConst.status.checkNo || ctx.change.status === auditConst.status.revise ? ctx.change.times - 1 : ctx.change.times;
-            ctx.change.user = await ctx.service.projectAccount.getAccountInfoById(ctx.change.uid);
-            ctx.change.auditHistory = [];
-            if (times >= 1) {
-                for (let i = 1; i <= times; i++) {
-                    ctx.change.auditHistory.push(await ctx.service.changePlanAudit.getAuditors(ctx.change.id, i));
-                }
-            }
-            // 获取审批流程中左边列表
-            ctx.change.auditors2 = (ctx.change.status === auditConst.status.checkNo || ctx.change.status === auditConst.status.revise) && ctx.change.uid !== ctx.session.sessionUser.accountId ?
-                await ctx.service.changePlanAudit.getAuditorsWithOwner(ctx.change.id, times) :
-                await ctx.service.changePlanAudit.getAuditorsWithOwner(ctx.change.id, ctx.change.times);
-            if (ctx.change.status === auditConst.status.uncheck || ctx.change.status === auditConst.status.checkNo || ctx.change.status === auditConst.status.revise) {
-                ctx.change.auditorList = await ctx.service.changePlanAudit.getAuditors(ctx.change.id, ctx.change.times);
-            }
+            await ctx.service.changePlan.loadChangeAuditViewData(ctx.change);
         }
 
         async planInformation(ctx) {
@@ -3579,13 +3610,19 @@ module.exports = app => {
                 // 获取清单列表
                 const changeList = await ctx.service.changePlanList.getList(ctx.change.id);
                 if (ctx.change.status === audit.changePlan.status.checking || ctx.change.status === audit.changePlan.status.checked) {
-                    const listAudits = await ctx.service.changePlanAudit.getAuditGroupByList(ctx.change.id, ctx.change.times);
-                    ctx.change.listAudits = listAudits;
+                    // const listAudits = await ctx.service.changePlanAudit.getAuditGroupByList(ctx.change.id, ctx.change.times);
+                    // ctx.change.listAudits = listAudits;
                     for (const cl of changeList) {
                         const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : '';
                         // 清单表页赋值
-                        for (const [index, au] of listAudits.entries()) {
-                            cl['audit_amount_' + au.aid] = ctx.change.shenpiPower && au.aid === ctx.session.sessionUser.accountId ? cl.spamount : (audit_amount[index] ? parseFloat(audit_amount[index]) : null);
+                        for (const au in ctx.change.userGroups) {
+                            if (ctx.change.userGroups[au][0].audit_order !== 0) {
+                                cl['audit_amount_' + ctx.change.userGroups[au][0].audit_order] =
+                                    (ctx.change.userGroups[au][0].audit_type === auditType.key.and &&
+                                        ctx.helper._.findIndex(ctx.change.userGroups[au], { aid: ctx.session.sessionUser.accountId, status: audit.changePlan.status.checked }) !== -1) ||
+                                    (ctx.change.shenpiPower && ctx.helper._.findIndex(ctx.change.userGroups[au], { aid: ctx.session.sessionUser.accountId }) !== -1) ?
+                                        cl.spamount : (audit_amount[au - 1] !== undefined ? parseFloat(audit_amount[au - 1]) : null);
+                            }
                         }
                     }
                 }
@@ -3604,6 +3641,8 @@ module.exports = app => {
                     fileList,
                     whiteList,
                     authMobile: auth_mobile,
+                    auditType,
+                    shenpiConst,
                     tpUnit: ctx.change.decimal ? ctx.change.decimal.tp : ctx.tender.info.decimal.tp,
                     upUnit: ctx.change.decimal ? ctx.change.decimal.up : ctx.tender.info.decimal.up,
                     changeUnits: changeConst.units,
@@ -3612,20 +3651,24 @@ module.exports = app => {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.change.plan_information),
                     preUrl: '/tender/' + ctx.tender.id + '/change/plan/' + ctx.change.id + '/information',
                 };
-                if ((ctx.change.status === audit.changePlan.status.uncheck || ctx.change.status === audit.changePlan.status.checkNo || ctx.change.status === audit.changePlan.status.revise) && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.tender.isTourist)) {
+                // if ((ctx.change.status === audit.changePlan.status.uncheck || ctx.change.status === audit.changePlan.status.checkNo || ctx.change.status === audit.changePlan.status.revise) && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.tender.isTourist)) {
                     // data.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', 'mobile'],
-                    });
-                    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 };
-                    });
+                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', 'mobile'],
+                });
+                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 (ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdspl) {
+                    renderData.spGroupList = await ctx.service.shenpiGroup.getGroupListByChangeType(ctx.tender.id, shenpiConst.sp_type.change, 'changePlan');
                 }
+                // }
                 await this.layout('change/plan_information.ejs', renderData, 'change/plan_information_modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -3633,6 +3676,20 @@ module.exports = app => {
             }
         }
 
+        async changePlanSpGroup(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.changePlanAudit.changeSpGroup(ctx.change, data.sp_group);
+                if (!result) {
+                    throw '切换审批组失败';
+                }
+                const auditors = await ctx.service.changePlanAudit.getUserGroup(ctx.change.id, ctx.change.times);
+                ctx.body = { err: 0, msg: '', data: auditors };
+            } catch (err) {
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
         // 审批相关
         /**
          * 添加审批人
@@ -3668,7 +3725,7 @@ module.exports = app => {
                     throw '添加审核人失败';
                 }
 
-                const auditors = await ctx.service.changePlanAudit.getAuditorsWithOwner(ctx.change.id, ctx.change.times);
+                const auditors = await ctx.service.changePlanAudit.getUserGroup(ctx.change.id, ctx.change.times);
                 ctx.body = { err: 0, msg: '', data: auditors };
             } catch (err) {
                 this.log(err);
@@ -3701,6 +3758,31 @@ module.exports = app => {
             }
         }
 
+        async savePlanAudit(ctx) {
+            try {
+                // if (ctx.change.revising) {
+                //     throw '台账修订中,请勿修改提交期数据';
+                // }
+                const data = JSON.parse(ctx.request.body.data);
+                if (ctx.session.sessionUser.is_admin && ctx.change.status !== audit.change.status.checked) {
+                    await ctx.service.changePlanAudit.saveAudit(ctx.change.id, ctx.change.times, ctx.change.sp_group, data);
+                    const auditors = await ctx.service.changePlanAudit.getUniqUserGroup(ctx.change.id, ctx.change.times);
+                    ctx.body = { err: 0, msg: '', data: auditors };
+                } else {
+                    throw '您无权进行该操作';
+                }
+            } catch (err) {
+                this.log(err);
+                // ctx.session.postError = err.toString();
+                // ctx.redirect(ctx.request.header.referer);
+                ctx.body = {
+                    err: 1,
+                    // url: ctx.request.header.referer,
+                    msg: err,
+                };
+            }
+        }
+
         /**
          * 上传附件
          * @param {*} ctx 上下文
@@ -3886,9 +3968,9 @@ module.exports = app => {
             try {
                 const auditConst = audit.changePlan;
                 if (!ctx.change || ctx.change.status !== auditConst.status.checking) {
-                    throw '当前材料调差期数据有误';
+                    throw '当前变更方案数据有误';
                 }
-                if (!ctx.change.curAuditor || ctx.change.curAuditor.aid !== ctx.session.sessionUser.accountId) {
+                if (ctx.change.curAuditorIds.length === 0 || ctx.change.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) === -1) {
                     throw '您无权进行该操作';
                 }
                 const data = {
@@ -4019,8 +4101,8 @@ module.exports = app => {
         async checkPlanAgain(ctx) {
             try {
                 // 获取终审
-                const auditInfo = await this.ctx.service.changePlanAudit.getAuditorByStatus(ctx.change.id, audit.changePlan.status.checked);
-                if (ctx.change.status !== audit.changePlan.status.checked || ctx.session.sessionUser.accountId !== auditInfo.aid) {
+                // const auditInfo = await this.ctx.service.changePlanAudit.getAuditorByStatus(ctx.change.id, audit.changePlan.status.checked);
+                if (ctx.change.status !== audit.changePlan.status.checked) {
                     throw '您无权进行该操作';
                 }
                 // 判断是否被变更申请调用了,是则无法发起修订
@@ -4041,10 +4123,14 @@ module.exports = app => {
                         throw '验证码不正确!';
                     }
                 }
-                // 重新审批
-                const result = await ctx.service.changePlanAudit.checkAgain(ctx.change);
-                if (!result) {
-                    throw '重新审批失败';
+                if ((ctx.change.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.change.status === audit.changePlan.status.checked) {
+                    // 重新审批
+                    const result = await ctx.service.changePlanAudit.checkAgain(ctx.change);
+                    if (!result) {
+                        throw '重新审批失败';
+                    }
+                } else {
+                    throw '您无权进行该操作';
                 }
                 // ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info');
                 ctx.body = {

+ 12 - 0
app/controller/file_controller.js

@@ -158,6 +158,18 @@ module.exports = app => {
             if (child) throw '该分类下存在子分类,请在子分类下上传、导入文件';
         }
 
+        async checkFiles(ctx) {
+            try{
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.filing_id || !data.files) throw '缺少参数';
+                const result = await ctx.service.file.checkFiles(data.filing_id, data.files);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch(error) {
+                this.log(error);
+                ctx.ajaxErrorBody(error, '检查附件错误');
+            }
+        }
+
         async uploadFile(ctx){
             let stream;
             try {

+ 4 - 4
app/controller/report_controller.js

@@ -892,7 +892,7 @@ module.exports = app => {
         async _commonGetAudit(ctx, params, stgAudit) {
             switch (params.stage_id) {
                 case -300: // 变更令
-                    const changeAudit = await ctx.service.changeAudit.getAuditors(params.change_id, params.change_times, true);
+                    const changeAudit = await ctx.service.changeAudit.getAuditors(params.change_id, params.change_times, 'asc', true);
                     const change = await ctx.service.change.getChangeByCid(params.change_id);
                     let orgChangeStatus = 3;
                     if ([1, 9].includes(change.status)) orgChangeStatus = 1; // 原报只要已上报(非1、9),status都是3
@@ -902,7 +902,7 @@ module.exports = app => {
                     });
                     break;
                 case -301: // 变更方案
-                    const changePlanAudit = await ctx.service.changePlanAudit.getAuditors(params.business_id, params.change_plan_times, true);
+                    const changePlanAudit = await ctx.service.changePlanAudit.getAuditors(params.business_id, params.change_plan_times, 'asc', true);
                     const change_plan = await ctx.service.changePlan.getDataById(params.business_id);
                     let orgChangePlanStatus = 3;
                     if ([1, 9].includes(change_plan.status)) orgChangePlanStatus = 1; // 原报只要已上报(非1、9),status都是3
@@ -912,7 +912,7 @@ module.exports = app => {
                     });
                     break;
                 case -302: // 变更立项
-                    const changeProjectAudit = await ctx.service.changeProjectAudit.getAuditors(params.business_id, params.change_project_times, true);
+                    const changeProjectAudit = await ctx.service.changeProjectAudit.getAuditors(params.business_id, params.change_project_times, 'asc', true);
                     const change_project = await ctx.service.changeProject.getDataById(params.business_id);
                     let orgChangePrjStatus = 3;
                     if ([1, 9].includes(change_project.status)) orgChangePrjStatus = 1; // 原报只要已上报(非1、9),status都是3
@@ -922,7 +922,7 @@ module.exports = app => {
                     });
                     break;
                 case -303: // 变更申请
-                    const changeApplyAudit = await ctx.service.changeApplyAudit.getAuditors(params.business_id, params.change_apply_times, true);
+                    const changeApplyAudit = await ctx.service.changeApplyAudit.getAuditors(params.business_id, params.change_apply_times, 'asc', true);
                     const change_apply = await ctx.service.changeApply.getDataById(params.business_id);
                     let orgChangeApplyStatus = 3;
                     if ([1, 9].includes(change_apply.status)) orgChangeApplyStatus = 1; // 原报只要已上报(非1、9),status都是3

+ 32 - 24
app/middleware/change_apply_audit_check.js

@@ -47,36 +47,44 @@ module.exports = options => {
                         change.sp_group = group ? group.id : 0;
                         yield this.service.changeApply.defaultUpdate({ id: change.id, sp_group: change.sp_group });
                     }
-                    const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
-                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
-                    yield this.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
-                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    let sameAudit = auditList.length === shenpiList.length;
-                    if (sameAudit) {
-                        for (const audit of auditList) {
-                            const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
-                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
-                                sameAudit = false;
-                                break;
+                    if (change.sp_group === 0) {
+                        this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
+                        const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                        yield this.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
+                                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                    sameAudit = false;
+                                    break;
+                                }
                             }
                         }
-                    }
-                    if (!sameAudit) {
-                        yield this.service.changeApplyAudit.updateNewAuditList(change, shenpiList);
-                        yield this.service.changeApply.loadChangeUser(change);
-                        yield this.service.changeApply.doCheckChangeCanCancel(change);
+                        if (!sameAudit) {
+                            yield this.service.changeApplyAudit.updateNewAuditList(change, shenpiList);
+                            yield this.service.changeApply.loadChangeUser(change);
+                            yield this.service.changeApply.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和添加终审
-                    const lastAuditors = auditList.filter(x => { return x.order === auditList.length - 1; });
-                    if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
-                        yield this.service.changeApplyAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
-                        yield this.service.changeApply.loadChangeUser(change);
-                        yield this.service.changeApply.doCheckChangeCanCancel(change);
-                    } else if (!shenpiInfo) {
-                        // 不存在终审人的状态下这里恢复为授权审批人
+                    if (!shenpiInfo || (shenpiInfo && shenpiInfo.audit_id === change.uid)) {
+                        // 不存在终审人 或 存在终审但与原报相同时, 这里恢复为授权审批人
                         this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+                        const lastAuditors = auditList.filter(x => {
+                            return x.order === auditList.length - 1;
+                        });
+                        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
+                            yield this.service.changeApplyAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
+                            yield this.service.changeApply.loadChangeUser(change);
+                            yield this.service.changeApply.doCheckChangeCanCancel(change);
+                        }
                     }
                 }
             }

+ 4 - 4
app/middleware/change_apply_check.js

@@ -28,7 +28,7 @@ module.exports = options => {
             }
             const caid = this.params.caid || this.request.body.caid;
             if (!caid) {
-                throw '您访问的变更立项不存在';
+                throw '您访问的变更申请不存在';
             }
             const change = yield this.service.changeApply.getDataById(caid);
             if (!change) throw '变更申请数据有误';
@@ -58,15 +58,15 @@ module.exports = options => {
                     throw '您无权查看该数据';
                 }
                 change.filePermission = true;
+            } else if (this.tender.isTourist) {
+                change.curTimes = change.times;
+                change.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
             } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
                 change.curTimes = change.status === status.checkNo || change.status === status.revise ? change.times - 1 : change.times;
                 change.filePermission = false;
-            } else if (this.tender.isTourist) {
-                change.curTimes = change.times;
-                change.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }

+ 20 - 16
app/middleware/change_audit_check.js

@@ -49,24 +49,28 @@ module.exports = options => {
                         change.sp_group = group ? group.id : 0;
                         yield this.service.change.defaultUpdate({ sp_group: change.sp_group }, { where: { cid: change.cid } });
                     }
-                    const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
-                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition });
-                    // const shenpiIdList = _.map(shenpiList, 'audit_id');
-                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    let sameAudit = auditList.length === shenpiList.length;
-                    if (sameAudit) {
-                        for (const audit of auditList) {
-                            const shenpi = shenpiList.find(x => { return x.audit_id === audit.uid; });
-                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
-                                sameAudit = false;
-                                break;
+                    if (change.sp_group === 0) {
+                        this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
+                        const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition });
+                        // const shenpiIdList = _.map(shenpiList, 'audit_id');
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => { return x.audit_id === audit.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);
+                        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 });

+ 107 - 0
app/middleware/change_plan_audit_check.js

@@ -0,0 +1,107 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Ellisran
+ * @date 2020/10/15
+ * @version
+ */
+
+const status = require('../const/audit').changePlan.status;
+const shenpiConst = require('../const/shenpi');
+const _ = require('lodash');
+
+module.exports = options => {
+    /**
+     * 标段校验 中间件
+     * 1. 读取标段数据(包括属性)
+     * 2. 检验用户是否可见标段(不校验具体权限)
+     *
+     * @param {function} next - 中间件继续执行的方法
+     * @return {void}
+     */
+    return function* changePlanAuditCheck(next) {
+        try {
+            // 获取revise
+            const id = this.params.cpid || this.request.body.cpid;
+            if (!id) {
+                throw '您访问的变更立项不存在';
+            }
+            // const change = yield this.service.change.getDataByCondition({ cid });
+            if (!this.change) {
+                const change = yield this.service.changePlan.getDataById(id);
+                if (!change) throw '变更立项数据有误';
+                yield this.service.changePlan.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.changePlanAudit.getAllDataByCondition({ where: { cpid: change.id, times: change.times }, orders: [['order', 'asc']] });
+                if (shenpi_status === shenpiConst.sp_status.gdspl) {
+                    // 判断并获取审批组
+                    const group = yield this.service.shenpiGroup.getSelectGroupByChangeType(this.tender.id, shenpiConst.sp_type.change, 'changePlan', change.sp_group);
+                    if ((group && change.sp_group !== group.id) || (!group && change.sp_group !== 0)) {
+                        change.sp_group = group ? group.id : 0;
+                        yield this.service.changePlan.defaultUpdate({ id: change.id, sp_group: change.sp_group });
+                    }
+                    if (change.sp_group === 0) {
+                        this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
+                        const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                        yield this.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
+                                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                    sameAudit = false;
+                                    break;
+                                }
+                            }
+                        }
+                        if (!sameAudit) {
+                            yield this.service.changePlanAudit.updateNewAuditList(change, shenpiList);
+                            yield this.service.changePlan.loadChangeUser(change);
+                            yield this.service.changePlan.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 });
+                    if (!shenpiInfo || (shenpiInfo && shenpiInfo.audit_id === change.uid)) {
+                        // 不存在终审人 或 存在终审但与原报相同时, 这里恢复为授权审批人
+                        this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+                        const lastAuditors = auditList.filter(x => { return x.order === auditList.length - 1; });
+                        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
+                            yield this.service.changePlanAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
+                            yield this.service.changePlan.loadChangeUser(change);
+                            yield this.service.changePlan.doCheckChangeCanCancel(change);
+                        }
+                    }
+                }
+            }
+            yield next;
+        } catch (err) {
+            console.log(err);
+            // 输出错误到日志
+            if (err.stack) {
+                this.logger.error(err);
+            } else {
+                this.getLogger('fail').info(JSON.stringify({
+                    error: err,
+                    project: this.session.sessionProject,
+                    user: this.session.sessionUser,
+                    body: this.session.body,
+                }));
+            }
+            // 重定向值标段管理
+            this.redirect(this.request.headers.referer);
+        }
+    };
+};

+ 10 - 12
app/middleware/change_plan_check.js

@@ -31,30 +31,26 @@ module.exports = options => {
                 throw '您访问的变更方案不存在';
             }
             const change = yield this.service.changePlan.getDataById(cpid);
+            if (!change) throw '变更方案数据有误';
             // 读取原报、审核人数据
-            change.auditors = yield this.service.changePlanAudit.getAuditors(change.id, change.times);
-            change.curAuditor = yield this.service.changePlanAudit.getCurAuditor(change.id, change.times);
+            yield this.service.changePlan.loadChangeUser(change);
             // decimal小数位设置
             change.decimal = change.decimal ? JSON.parse(change.decimal) : { tp: this.tender.info.decimal.tp, up: this.tender.info.decimal.up, precision: this.tender.info.precision };
 
-            if (!change) throw '变更令数据有误';
             // 权限相关
             // todo 校验权限 (标段参与人、分享)
             const accountId = this.session.sessionUser.accountId,
-                auditorIds = _.map(change.auditors, 'aid'),
                 shareIds = [];
+            const permission = this.session.sessionUser.permission;
             if (accountId === change.uid) { // 原报
                 change.curTimes = change.times;
                 change.filePermission = true;
-            } else if (this.tender.isTourist) {
-                change.curTimes = change.times;
-                change.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
-            } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
+            } else if (change.auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
                 // change.readOnly = change.status !== status.checking || accountId !== change.curAuditor.aid;
-                change.curTimes = change.status === status.checkNo ? change.times - 1 : change.times;
+                change.curTimes = change.status === status.checkNo || change.status === status.revise ? change.times - 1 : change.times;
                 change.filePermission = true;
             } else if ((change.status === status.checkNo || change.status === status.revise) && change.uid !== accountId) {
                 const preAuditors = yield this.service.changePlanAudit.getAuditors(change.id, change.times - 1);
@@ -63,7 +59,10 @@ module.exports = options => {
                     throw '您无权查看该数据';
                 }
                 change.filePermission = true;
-            } else if (shareIds.indexOf(accountId) !== -1) { // 分享人
+            } else if (this.tender.isTourist) {
+                change.curTimes = change.times;
+                change.filePermission = this.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
+            } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
@@ -75,10 +74,9 @@ module.exports = options => {
             }
             // 调差的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.curAuditor.aid === accountId;
+            change.shenpiPower = change.status === status.checking && change.curAuditorIds.indexOf(accountId) !== -1;
             this.change = change;
             yield this.service.changePlan.doCheckChangeCanCancel(this.change);
-            console.log(this.change.cancancel);
             yield next;
         } catch (err) {
             console.log(err);

+ 32 - 24
app/middleware/change_project_audit_check.js

@@ -47,36 +47,44 @@ module.exports = options => {
                         change.sp_group = group ? group.id : 0;
                         yield this.service.changeProject.defaultUpdate({ id: change.id, sp_group: change.sp_group });
                     }
-                    const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
-                    const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
-                    yield this.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
-                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
-                    let sameAudit = auditList.length === shenpiList.length;
-                    if (sameAudit) {
-                        for (const audit of auditList) {
-                            const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
-                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
-                                sameAudit = false;
-                                break;
+                    if (change.sp_group === 0) {
+                        this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        const condition = { tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
+                        const shenpiList = yield this.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                        yield this.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => {
+                                    return x.audit_id === audit.aid;
+                                });
+                                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                    sameAudit = false;
+                                    break;
+                                }
                             }
                         }
-                    }
-                    if (!sameAudit) {
-                        yield this.service.changeProjectAudit.updateNewAuditList(change, shenpiList);
-                        yield this.service.changeProject.loadChangeUser(change);
-                        yield this.service.changeProject.doCheckChangeCanCancel(change);
+                        if (!sameAudit) {
+                            yield this.service.changeProjectAudit.updateNewAuditList(change, shenpiList);
+                            yield this.service.changeProject.loadChangeUser(change);
+                            yield this.service.changeProject.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和添加终审
-                    const lastAuditors = auditList.filter(x => { return x.order === auditList.length - 1; });
-                    if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
-                        yield this.service.changeProjectAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
-                        yield this.service.changeProject.loadChangeUser(change);
-                        yield this.service.changeProject.doCheckChangeCanCancel(change);
-                    } else if (!shenpiInfo) {
-                        // 不存在终审人的状态下这里恢复为授权审批人
+                    if (!shenpiInfo || (shenpiInfo && shenpiInfo.audit_id === change.uid)) {
+                        // 不存在终审人 或 存在终审但与原报相同时, 这里恢复为授权审批人
                         this.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+                        const lastAuditors = auditList.filter(x => { return x.order === auditList.length - 1; });
+                        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
+                            yield this.service.changeProjectAudit.updateLastAudit(change, auditList, shenpiInfo.audit_id);
+                            yield this.service.changeProject.loadChangeUser(change);
+                            yield this.service.changeProject.doCheckChangeCanCancel(change);
+                        }
                     }
                 }
             }

+ 3 - 3
app/middleware/change_project_check.js

@@ -59,15 +59,15 @@ module.exports = options => {
                     throw '您无权查看该数据';
                 }
                 change.filePermission = true;
+            } else if (this.tender.isTourist) {
+                change.curTimes = change.times;
+                change.filePermission = this.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
             } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }
                 change.curTimes = change.status === status.back || change.status === status.revise ? change.times - 1 : change.times;
                 change.filePermission = false;
-            } else if (this.tender.isTourist) {
-                change.curTimes = change.times;
-                change.filePermission = this.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }

+ 0 - 7
app/public/js/change_apply.js

@@ -134,13 +134,6 @@ class codeRuleSet {
         });
     }
 }
-/**
- * 期计量 - 期列表页面 js
- *
- * @author Mai
- * @date 2018/12/7
- * @version
- */
 const getGroupAuditHtml = function (group) {
     return group.map(u => { return `<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`; }).join('');
 };

+ 5 - 5
app/public/js/change_apply_audit.js

@@ -83,7 +83,7 @@ $(document).ready(function () {
     });
     // 删除审批人
     $('body').on('click', '#auditors li a', function () {
-        const li = $(this).parent();
+        const li = $(this).parents('li');
         const data = {
             auditorId: parseInt(li.attr('auditorId')),
         };
@@ -191,11 +191,11 @@ function makeSpHtml(datas) {
 // 检查上报情况
 function checkAuditorFrom () {
     if ($('#auditors li').length === 0) {
-        // if(shenpi_status === shenpiConst.sp_status.gdspl) {
-        //     toastr.error('请联系管理员添加审批人');
-        // } else {
+        if(shenpi_status === shenpiConst.sp_status.gdspl) {
+            toastr.error('请联系管理员添加审批人');
+        } else {
             toastr.error('请先选择审批人,再上报数据');
-        // }
+        }
         return false;
     }
     let flag = false;

+ 169 - 0
app/public/js/change_plan.js

@@ -134,8 +134,177 @@ class codeRuleSet {
         });
     }
 }
+const getGroupAuditHtml = function (group) {
+    return group.map(u => { return `<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`; }).join('');
+};
 
+const getAuditTypeHtml = function (type) {
+    if (type === auditType.key.common) return '';
+    return `<div class="li-subscript"><span class="badge badge-pill badge-${auditType.info[type].class} p-1 badge-bg-small"><small>${auditType.info[type].short}</small></span></div>`;
+};
+
+const getAuditTypeText = function (type) {
+    if (type === auditType.key.common) return '';
+    return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
+};
 $(document).ready(() => {
+
+    $('#audit-list').on('click', 'a', function() {
+        const type = $(this).data('target')
+        const auditCard = $(this).parent().parent()
+        if (type === 'show') {
+            $(this).data('target', 'hide')
+            auditCard.find('.fold-card').slideDown('swing', () => {
+                auditCard.find('#end-target').text($(this).data('idx') + '#')
+                auditCard.find('#fold-btn').text('收起历史审核记录')
+            })
+        } else {
+            $(this).data('target', 'show')
+            auditCard.find('.fold-card').slideUp('swing', () => {
+                auditCard.find('#end-target').text('1#')
+                auditCard.find('#fold-btn').text('展开历史审核记录')
+            })
+        }
+    });
+
+    // 获取审批流程
+    $('a[data-target="#sp-list" ]').on('click', function () {
+        const data = {
+            id: $(this).attr('c-id'),
+        };
+        postData('/tender/' + tenderId + '/change/plan/auditors', data, function (result) {
+            const { auditHistory, auditors2, user } = result;
+            let auditorsHTML = [];
+            auditors2.forEach((group, idx) => {
+                if (idx === 0) {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
+                    </li>`);
+                } else if(idx === auditors2.length -1 && idx !== 0) {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-stop-circle fa-rotate-90"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <div class="d-flex ml-auto">
+                    ${getAuditTypeHtml(group[0].audit_type)}
+                    <span class="badge badge-light badge-pill ml-auto"><small>终审</small></span>
+                    </div>
+                    </li>`);
+                } else {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-chevron-circle-down"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <div class="d-flex ml-auto">
+                    ${getAuditTypeHtml(group[0].audit_type)}
+                    <span class="badge badge-light badge-pill"><small>${transFormToChinese(idx)}审</small></span>
+                    </div>
+                    </li>`);
+                }
+            });
+            $('#auditor-list').empty();
+            $('#auditor-list').append(auditorsHTML.join(''));
+
+            let historyHTML = [];
+            auditHistory.forEach((his, idx) => {
+                if (idx === auditHistory.length - 1 && auditHistory.length !== 1) {
+                    historyHTML.push(`<div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a></div>`);
+                }
+                historyHTML.push(`<div class="${idx < auditHistory.length - 1 ? 'fold-card' : ''}">`);
+                historyHTML.push(`<div class="text-center text-muted">${idx+1}#</div>`);
+                historyHTML.push(`<ul class="timeline-list list-unstyled mt-2 ${ idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'last-auditor-list' : '' }">`);
+                his.forEach((group, index) => {
+                    if (index === 0) {
+                        historyHTML.push(`<li class="timeline-list-item pb-2">
+                                            <div class="timeline-item-date">
+                                                ${group.beginYear}
+                                                <span>${group.beginDate}</span>
+                                                <span>${group.beginTime}</span>
+                                            </div>
+                                            <div class="timeline-item-tail"></div>
+                                            <div class="timeline-item-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
+                                            <div class="timeline-item-content">
+                                                <div class="py-1">
+                                                    <span class="text-black-50">原报</span>
+                                                    <span class="pull-right text-success">${idx !== 0 ? '重新' : '' }上报审批</span>
+                                                </div>
+                                                <div class="card">
+                                                    <div class="card-body px-3 py-0">
+                                                        <div class="card-text p-2 py-3 row">
+                                                            <div class="col">
+                                                                <span class="h6">${user.name}</span>
+                                                                <span class="text-muted ml-1">${user.role}</span>
+                                                            </div>
+                                                            <div class="col">
+                                                                <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                        </li>`);
+                    }
+                    historyHTML.push(`<li class="timeline-list-item pb-2 ${ group.status === auditConst.status.uncheck && idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'is_uncheck' : ''}">`);
+                    if (group.endYear) {
+                        historyHTML.push(`<div class="timeline-item-date">${group.endYear}<span>${group.endDate}</span><span>${group.endTime}</span></div>`);
+                    }
+                    if (index < his.length - 1) {
+                        historyHTML.push('<div class="timeline-item-tail"></div>');
+                    }
+                    if (group.status === auditConst.status.checked || group.status === auditConst.status.cancelRevise) {
+                        historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
+                    } else if (group.status === auditConst.status.checkNo || group.status === auditConst.status.revise || group.status === auditConst.status.checkCancel) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>');
+                    } else if (group.status === auditConst.status.checking) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
+                    } else if(group.status === auditConst.status.checkAgain) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>');
+                    } else {
+                        historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
+                    }
+
+                    historyHTML.push('<div class="timeline-item-content">');
+                    historyHTML.push('<div class="py-1">');
+                    const statuStr = group.status !== auditConst.status.uncheck ?
+                        `<span class="pull-right ${auditConst.statusClass[group.status]}">${auditConst.statusString[group.status]}</span>` : '';
+                    historyHTML.push(`
+                    <span class="text-black-50">
+                    ${ group.audit_order === 0 ? '原报' : !group.is_final ? group.audit_order + '审' : '终审' } ${getAuditTypeText(group.audit_type)}
+                    </span>
+                    ${statuStr}`);
+                    historyHTML.push('</div>');
+                    historyHTML.push('<div class="card"><div class="card-body px-3 py-0">');
+                    for (const [i, auditor] of group.auditors.entries()) {
+                        historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
+                        historyHTML.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
+                        historyHTML.push('<div class="col">');
+                        if (auditor.status === auditConst.status.checked || group.status === auditConst.status.cancelRevise) {
+                            historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
+                        } else if (auditor.status === auditConst.status.checkNo || group.status === auditConst.status.revise || auditor.status === auditConst.status.checkCancel) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
+                        } else if (auditor.status === auditConst.status.checking) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>');
+                        } else if (auditor.status === auditConst.status.checkAgain) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-check"></i></span>');
+                        }
+                        historyHTML.push('</div>');
+                        if (auditor.opinion) {
+                            historyHTML.push(`<div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i>${auditor.opinion}</div>`);
+                        }
+                        historyHTML.push('</div>');
+                    }
+                    historyHTML.push('</div></div>');
+                    historyHTML.push('</div>');
+                    historyHTML.push('</li>');
+                });
+                historyHTML.push('</div>');
+                historyHTML.push('</ul>');
+            });
+            $('#audit-list').empty();
+            $('#audit-list').append(historyHTML.join(''));
+        });
+    });
+
     // 首次进入设置
     let showNoNeed = false;
     if (cRuleFirst) {

+ 84 - 71
app/public/js/change_plan_audit.js

@@ -54,7 +54,7 @@ $(document).ready(function () {
     })
 
     // 添加审批流程按钮逻辑
-    $('.book-list').on('click', 'dt', function () {
+    $('body').on('click', '.book-list dt', function () {
         const idx = $(this).find('.acc-btn').attr('data-groupid')
         const type = $(this).find('.acc-btn').attr('data-type')
         if (type === 'hide') {
@@ -73,94 +73,57 @@ $(document).ready(function () {
     })
 
     // 添加到审批流程中
-    $('dl').on('click', 'dd', function () {
+    $('.search-user-list').on('click', 'dd', function () {
         const id = parseInt($(this).data('id'));
         if (id) {
             postData(preUrl + '/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" auditorId="'+ data.aid +'">');
-                        html.push('<a href="javascript: void(0)" class="text-danger pull-right">移除</a>');
-                        html.push('<span>');
-                        html.push(data.order + ' ');
-                        html.push(data.name + ' ');
-                        html.push('</span>');
-                        html.push('<small class="text-muted">');
-                        html.push(data.role);
-                        html.push('</small></li>');
-                    }
-                    // 添加新审批人流程修改
-                    auditorshtml.push('<li class="list-group-item" data-auditorid="' + data.aid + '">');
-                    auditorshtml.push('<i class="fa ' + (index+1 === datas.length ? 'fa-stop-circle' : 'fa-chevron-circle-down') + '"></i> ');
-                    auditorshtml.push(data.name + ' <small class="text-muted">' + data.role + '</small>');
-                    if (index === 0) {
-                        auditorshtml.push('<span class="pull-right">原报</span>');
-                    } else if (index+1 === datas.length) {
-                        auditorshtml.push('<span class="pull-right">终审</span>');
-                    } else {
-                        auditorshtml.push('<span class="pull-right">'+ transFormToChinese(index) +'审</span>');
-                    }
-                    auditorshtml.push('</li>');
-                }
-                $('#auditors').html(html.join(''));
-
-
-                // 重新上报时。令其它的审批人流程图标转换
-                // $('#auditors-list li i').removeClass('fa-stop-circle').addClass('fa-chevron-circle-down');
-                // for (let i = 0; i < $('#auditors-list li').length; i++) {
-                //     $('#auditors-list li').eq(i).find('.pull-right').text(transFormToChinese(i+1) + '审');
-                //     $('#auditors-list2 li').eq(i).find('.pull-right').text(transFormToChinese(i+1) + '审');
-                // }
-
-                $('#auditors-list').html(auditorshtml.join(''));
-
-                // const auditorshtml2 = [];
-                // // 重新上报时。令其它的审批人流程图标转换
-                // $('#auditors-list2 li i').removeClass('fa-stop-circle').addClass('fa-chevron-circle-down');
-                // // 添加新审批人
-                // auditorshtml2.push('<li class="list-group-item" data-auditid="' + data.aid + '">');
-                // auditorshtml2.push('<h5 class="card-title"><i class="fa fa-stop-circle"></i> ');
-                // auditorshtml2.push(data.name + ' <small class="text-muted">' + data.role + '</small>');
-                // auditorshtml2.push('<span class="pull-right">终审</span>');
-                // auditorshtml2.push('</h5></li>');
-                // $('#auditors-list2').append(auditorshtml2.join(''));
+                makeSpHtml(datas);
             });
         }
     });
     // 删除审批人
-    $('body').on('click', '#auditors li>a', function () {
-        const li = $(this).parent();
+    $('body').on('click', '#auditors li a', function () {
+        const li = $(this).parents('li');
         const data = {
             auditorId: parseInt(li.attr('auditorId')),
         };
         postData(preUrl +  '/audit/delete', data, (result) => {
             li.remove();
-            for (const rst of result) {
-                const aLi = $('li[auditorId=' + rst.aid + ']');
-                $('span', aLi).text(rst.order + ' ' + rst.name + ' ');
-            }
+            let index = 1;
+            $('#auditors li').each(function () {
+                $(this).children('.col-auto').eq(0).text(index);
+                index++;
+            });
 
             // 如果是重新上报
             // 令最后一个图标转换
-            $('#auditors-list li[data-auditorid="' + data.auditorId + '"]').remove();
+            $('#auditors-list li[data-auditorId="' + data.auditorId + '"]').remove();
             if ($('#auditors-list li').length !== 0 && !$('#auditors-list li i').hasClass('fa-stop-circle')) {
-                $('#auditors-list li').eq($('#auditors-list li').length-1).children('i')
+                console.log($('#auditors-list li').length-1, $('#auditors-list li').eq($('#auditors-list li').length-1).find('i'));
+                $('#auditors-list li').eq($('#auditors-list li').length-1).find('i')
                     .removeClass('fa-chevron-circle-down').addClass('fa-stop-circle');
             }
-            // $('#auditors-list2 li[data-auditid="' + data.auditorId + '"]').remove();
-            // if ($('#auditors-list2 li').length !== 0 && !$('#auditors-list2 li i').hasClass('fa-stop-circle')) {
-            //     $('#auditors-list2 li').eq($('#auditors-list2 li').length-1).children('i')
-            //         .removeClass('fa-chevron-circle-down').addClass('fa-stop-circle');
-            // }
             for (let i = 0; i < $('#auditors-list li').length; i++) {
-                $('#auditors-list li').eq(i).find('.pull-right').text(i === 0 ? '原报' : (i+1 === $('#auditors-list li').length ? '终' : transFormToChinese(i)) + '审');
-                // $('#auditors-list2').eq(i).find('.pull-right').text((i+1 === $('#auditors-list2').length ? '终' : transFormToChinese(i+1)) + '审');
+                $('#auditors-list li').eq(i).find('.badge-pill').children('small').text(i === 0 ? '原报' : (i+1 === $('#auditors-list li').length ? '终' : transFormToChinese(i)) + '审');
             }
         });
     });
+
+    // 切换审批组
+    $('#change-sp-group').change(function () {
+        const data = {
+            type: 'change_sp_group',
+            sp_group: parseInt($(this).val()),
+        }
+        if (!data.sp_group) {
+            toastr.error('请选择固定审批组');
+            return false;
+        }
+        console.log(data);
+        postData(preUrl + '/audit/spgroup', data, (datas) => {
+            makeSpHtml(datas);
+        });
+    });
     // 退回选择修改审批人流程
     $('#hideSp').click(function () {
         $('#sp-list').modal('hide');
@@ -174,14 +137,64 @@ $(document).ready(function () {
         $(document.body).addClass('modal-open');
     });
 });
+function makeSpHtml(datas) {
+    const html = [];
+    // 如果是重新上报,添加到重新上报列表中
+    const auditorshtml = [];
+    for (const [index,data] of datas.entries()) {
+        if (index !== 0) {
+            html.push('<li class="list-group-item d-flex" auditorId="'+ data[0].aid +'">');
+            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>`);
+            }
+            html.push('</div>');
+            html.push('<div class="col-auto">');
+            // todo 添加会签或签时
+            if (data[0].audit_type !== auditType.key.common) {
+                html.push(`<span class="badge badge-pill badge-${auditType.info[data[0].audit_type].class} badge-bg-small"><small>${auditType.info[data[0].audit_type].long}</small></span>`);
+            }
+            // 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>');
+            }
+            html.push('</div>');
+            html.push('</li>');
+        }
+        // 添加新审批人流程修改
+        auditorshtml.push('<li class="list-group-item d-flex justify-content-between align-items-center" data-auditorid="' + data[0].aid + '">');
+        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>');
+    }
+    $('#auditors').html(html.join(''));
+    $('#auditors-list').html(auditorshtml.join(''));
+}
 // 检查上报情况
 function checkAuditorFrom () {
     if ($('#auditors li').length === 0) {
-        // if(shenpi_status === shenpiConst.sp_status.gdspl) {
-        //     toastr.error('请联系管理员添加审批人');
-        // } else {
+        if(shenpi_status === shenpiConst.sp_status.gdspl) {
+            toastr.error('请联系管理员添加审批人');
+        } else {
             toastr.error('请先选择审批人,再上报数据');
-        // }
+        }
         return false;
     }
     let flag = false;

+ 41 - 31
app/public/js/change_plan_information.js

@@ -204,27 +204,29 @@ $(document).ready(() => {
             colWidth: true,
         }
     };
-    console.log(changeList, change.listAudits);
+    console.log(changeList, change.userGroups);
 
     if (change.status === auditConst.status.checking || change.status === auditConst.status.checked) {
-        for (const audit of change.listAudits) {
-            // const userinfo = _.find(auditList2, { 'aid': aid });
-            const newColcount = {
-                title: audit.name + ' 审批|数量',
-                colSpan: '2|1', rowSpan: '1|1',
-                field: 'audit_amount_' + audit.aid,
-                hAlign: 2, width: 60, type: 'Number',
-                readOnly: !(change.shenpiPower && audit.aid === parseInt(cur_uid))
-            };
-            const newColTp = {
-                title: '|金额',
-                colSpan: '|1', rowSpan: '|1',
-                field: 'sa_tp_' + audit.aid,
-                hAlign: 2, width: 80, type: 'Number',
-                readOnly: true
-            };
-            changeSpreadSetting.cols.push(newColcount);
-            changeSpreadSetting.cols.push(newColTp);
+        for (const audit of change.userGroups) {
+            if (audit[0] && audit[0].audit_order !== 0) {
+                // const userinfo = _.find(auditList2, { 'aid': aid });
+                const newColcount = {
+                    title: (audit && audit.length > 1 ? (audit[0].audit_order + '审') : audit[0].name) + ' 审批|数量',
+                    colSpan: '2|1', rowSpan: '1|1',
+                    field: 'audit_amount_' + audit[0].audit_order,
+                    hAlign: 2, width: 60, type: 'Number',
+                    readOnly: !(change.shenpiPower && _.findIndex(audit, { aid: parseInt(cur_uid) }) !== -1),
+                };
+                const newColTp = {
+                    title: '|金额',
+                    colSpan: '|1', rowSpan: '|1',
+                    field: 'sa_tp_' + audit[0].audit_order,
+                    hAlign: 2, width: 80, type: 'Number',
+                    readOnly: true
+                };
+                changeSpreadSetting.cols.push(newColcount);
+                changeSpreadSetting.cols.push(newColTp);
+            }
         }
     }
     changeSpreadSetting.cols.push({title: '备注1', colSpan: '1', rowSpan: '2', field: 'ex_memo1', hAlign: 0, width: 110, formatter: '@', readOnly: 'readOnly.isEdit2', cellType: 'ellipsisAutoTip', scrollHeightClass: '.sjs-height-0'});
@@ -275,16 +277,20 @@ $(document).ready(() => {
         },
         setAuditValue: function () {
             for (const c of changeList) {
-                for (const audit of change.listAudits) {
-                    c['audit_amount_' + audit.aid] = ZhCalc.round(c['audit_amount_' + audit.aid], findDecimal(c.unit));
-                    c['sa_tp_' + audit.aid] = ZhCalc.round(ZhCalc.mul(c['audit_amount_' + audit.aid], ZhCalc.round(c.unit_price, unitPriceUnit)), totalPriceUnit);
+                for (const audit of change.userGroups) {
+                    if (audit[0].audit_order !== 0) {
+                        c['audit_amount_' + audit[0].audit_order] = ZhCalc.round(c['audit_amount_' + audit[0].audit_order], findDecimal(c.unit));
+                        c['sa_tp_' + audit[0].audit_order] = ZhCalc.round(ZhCalc.mul(c['audit_amount_' + audit[0].audit_order], ZhCalc.round(c.unit_price, unitPriceUnit)), totalPriceUnit);
+                    }
                 }
             }
         },
         setRowValueAndSum: function (data, row, col) {
-            for (const j in change.listAudits) {
-                const sum = ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), parseFloat(changeSpreadSheet.getValue(row, 11 + parseInt(j)*2))), totalPriceUnit);
-                changeSpreadSheet.setValue(row, 12 + j*2, sum !== 0 ? sum : null);
+            for (const j in change.userGroups) {
+                if (change.userGroups[j][0].audit_order !== 0) {
+                    const sum = ZhCalc.round(ZhCalc.mul(ZhCalc.round(data.unit_price, unitPriceUnit), parseFloat(changeSpreadSheet.getValue(row, 11 + parseInt(j - 1) * 2))), totalPriceUnit);
+                    changeSpreadSheet.setValue(row, 12 + (j - 1) * 2, sum !== 0 ? sum : null);
+                }
             }
             // const sum = ZhCalc.round(ZhCalc.mul(data.unit_price, data.spamount), totalPriceUnit);
             // changeSpreadSheet.setValue(row, col+1, sum !== 0 ? sum : null);
@@ -313,13 +319,17 @@ $(document).ready(() => {
             changeSpreadSheet.setValue(changeSpreadSheet.getRowCount() - 1, 6, oSum !== 0 ? oSum : null);
             changeSpreadSheet.setValue(changeSpreadSheet.getRowCount() - 1, 8, cSum !== 0 ? cSum : null);
             changeSpreadSheet.setValue(changeSpreadSheet.getRowCount() - 1, 10, sSum !== 0 ? sSum : null);
-            // 用户的数据合计
-            for (const j in change.listAudits) {
-                let audit_sum = 0;
-                for(let i = 0; i < rowCount - 1; i++){
-                    audit_sum = ZhCalc.add(audit_sum, changeSpreadSheet.getValue(i, 12 + j*2));
+            if (readOnly) {
+                // 用户的数据合计
+                for (const j in change.userGroups) {
+                    if (change.userGroups[j][0].audit_order !== 0) {
+                        let audit_sum = 0;
+                        for (let i = 0; i < rowCount - 1; i++) {
+                            audit_sum = ZhCalc.add(audit_sum, changeSpreadSheet.getValue(i, 12 + (j - 1) * 2));
+                        }
+                        changeSpreadSheet.setValue(changeSpreadSheet.getRowCount() - 1, 12 + (j - 1) * 2, audit_sum !== 0 ? audit_sum : null);
+                    }
                 }
-                changeSpreadSheet.setValue(changeSpreadSheet.getRowCount() - 1, 12 + j*2, audit_sum !== 0 ? audit_sum : null);
             }
         },
         deletePress: function (sheet) {

+ 4 - 4
app/public/js/change_project_audit.js

@@ -293,11 +293,11 @@ function makeSpHtml(datas) {
 // 检查上报情况
 function checkAuditorFrom () {
     if ($('#auditors li').length === 0) {
-        // if(shenpi_status === shenpiConst.sp_status.gdspl) {
-        //     toastr.error('请联系管理员添加审批人');
-        // } else {
+        if(shenpi_status === shenpiConst.sp_status.gdspl) {
+            toastr.error('请联系管理员添加审批人');
+        } else {
             toastr.error('请先选择审批人,再上报数据');
-        // }
+        }
         return false;
     }
     let flag = false;

+ 47 - 0
app/public/js/file_detail.js

@@ -220,6 +220,16 @@ $(document).ready(function() {
                 parent = parent.getParentNode();
             }
         }
+        checkFilesExist(files, callback) {
+            const data = [];
+            for (const file of files) {
+                if (file === undefined) return [];
+                data.push(file.name);
+            }
+            postData('file/check', { filing_id: filingObj.curFiling.id, files: data }, function(result) {
+                callback(result);
+            });
+        }
         uploadFiles(files, callback) {
             const formData = new FormData();
             formData.append('filing_id', filingObj.curFiling.id);
@@ -563,6 +573,25 @@ $(document).ready(function() {
             $('#del-filing').modal('hide');
         });
     });
+    $('#add-file').on('show.bs.modal', function() {
+        $('#upload-file-hint').hide();
+        $('#upload-file')[0].value = '';
+        if ($('#add-file-ok').hasClass('btn-warning')) $('#add-file-ok').removeClass('btn-warning').addClass('btn-primary');
+    });
+    $('#upload-file').change(() => {
+        $('#add-file-ok').attr('disabled', true);
+        const input = $('#upload-file');
+        filingObj.checkFilesExist(input[0].files, function(result) {
+            if (result.length === 0) {
+                $('#upload-file-hint').hide();
+                $('#add-file-ok').removeClass('btn-warning').addClass('btn-primary').attr('disabled', false);
+            } else {
+                const msg = result[0] + (result.length > 1 ? `(等${result.length}个文件)`: '') + '</br>存在同名文件,请确认是否上传重复';
+                $('#upload-file-hint').html(msg).show();
+                $('#add-file-ok').removeClass('btn-primary').addClass('btn-warning').attr('disabled', false);
+            }
+        });
+    });
     $('#add-file-ok').click(() => {
         const input = $('#upload-file');
         filingObj.uploadFiles(input[0].files, function() {
@@ -570,6 +599,24 @@ $(document).ready(function() {
             $('#add-file').modal('hide');
         });
     });
+    $('#add-big-file').on('show.bs.modal', function() {
+        $('#upload-big-file-hint').hide();
+        $('#upload-big-file')[0].value = '';
+        if ($('#add-big-file-ok').hasClass('btn-warning')) $('#add-big-file-ok').removeClass('btn-warning').addClass('btn-primary');
+    });
+    $('#upload-big-file').change(() => {
+        $('#add-big-file-ok').attr('disabled', true);
+        const input = $('#upload-big-file');
+        filingObj.checkFilesExist(input[0].files, function(result) {
+            if (result.length === 0) {
+                $('#upload-big-file-hint').hide();
+                $('#add-big-file-ok').removeClass('btn-warning').addClass('btn-primary').attr('disabled', false);
+            } else {
+                $('#upload-big-file-hint').html('存在同名文件,请确认是否上传重复').show();
+                $('#add-big-file-ok').removeClass('btn-primary').addClass('btn-warning').attr('disabled', false);
+            }
+        });
+    });
     $('#add-big-file-ok').click(() => {
         const input = $('#upload-big-file');
         filingObj.uploadBigFile(input[0].files[0], function () {

+ 1 - 1
app/public/js/se_bonus.js

@@ -30,7 +30,7 @@ $(document).ready(() => {
             {title: '编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: isPre, },
             {title: '发文单位', colSpan: '1', rowSpan: '1', field: 'doc_co', hAlign: 0, width: 150, formatter: '@', readOnly: isPre},
             {
-                title: '依据材料证明', colSpan: '1', rowSpan: '1', field: 'proof_file', hAlign: 1, width: 80, formatter: '@',
+                title: '依据材料证明', colSpan: '1', rowSpan: '1', field: 'proof_file', hAlign: 0, width: 80, formatter: '@',
                 readOnly: true, cellType: 'imageBtn', normalImg: '#rela-file-icon', hoverImg: '#rela-file-hover',
                 getValue: function (data) {
                     return data.proof_file ? data.proof_file.length : 0;

+ 7 - 2
app/router.js

@@ -15,6 +15,7 @@ module.exports = app => {
     const changeAuditCheck = app.middlewares.changeAuditCheck();
     const changeProjectAuditCheck = app.middlewares.changeProjectAuditCheck();
     const changeApplyAuditCheck = app.middlewares.changeApplyAuditCheck();
+    const changePlanAuditCheck = app.middlewares.changePlanAuditCheck();
     const uncheckTenderCheck = app.middlewares.uncheckTenderCheck();
     // 期读取中间件
     const stageCheck = app.middlewares.stageCheck();
@@ -613,20 +614,23 @@ module.exports = app => {
     app.post('/tender/:id/change/plan/add', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.planAdd');
     app.post('/tender/:id/change/plan/delete', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'changeController.planDelete');
     app.get('/tender/:id/change/plan/:cpid/info', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.planInformation');// 针对旧数据wap端跳转web问题
-    app.get('/tender/:id/change/plan/:cpid/information', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.planInformation');
+    app.get('/tender/:id/change/plan/:cpid/information', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, changePlanAuditCheck, 'changeController.planInformation');
     app.post('/tender/:id/change/plan/:cpid/information/save', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.planInformationSave');
     app.post('/tender/:id/change/plan/:cpid/information/file/upload', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.uploadPlanFile');
     app.post('/tender/:id/change/plan/:cpid/information/file/delete', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.deletePlanFile');
     app.get('/tender/:id/change/plan/:cpid/information/file/:fid/download', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.downloadPlanFile');
     app.post('/tender/:id/change/plan/:cpid/information/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.addPlanAudit');
     app.post('/tender/:id/change/plan/:cpid/information/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.deletePlanAudit');
-    app.post('/tender/:id/change/plan/:cpid/information/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, tenderBuildCheck, 'changeController.startPlanAudit');
+    app.post('/tender/:id/change/plan/:cpid/information/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, changePlanAuditCheck, tenderBuildCheck, 'changeController.startPlanAudit');
     app.post('/tender/:id/change/plan/:cpid/information/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, tenderBuildCheck, 'changeController.checkPlanAudit');
     app.post('/tender/:id/change/plan/:cpid/information/list/save', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.savePlanListsData');
     app.post('/tender/:id/change/plan/cancel/audit', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changePlanCheck, 'changeController.checkPlanAuditCancel');
     app.post('/tender/:id/change/plan/check/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changePlanCheck, 'changeController.checkPlanRevise');
     app.post('/tender/:id/change/plan/cancel/revise', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changePlanCheck, 'changeController.cancelPlanRevise');
     app.post('/tender/:id/change/plan/check/again', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, changePlanCheck, 'changeController.checkPlanAgain');
+    app.post('/tender/:id/change/plan/:cpid/information/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.savePlanAudit');
+    app.post('/tender/:id/change/plan/:cpid/information/audit/spgroup', sessionAuth, tenderCheck, uncheckTenderCheck, changePlanCheck, 'changeController.changePlanSpGroup');
+    app.post('/tender/:id/change/plan/auditors', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.changePlanAuditors');
     // 材料调差
     app.get('/tender/:id/measure/material', sessionAuth, tenderCheck, uncheckTenderCheck, 'materialController.index');
     app.post('/tender/:id/measure/material/add', sessionAuth, tenderCheck, uncheckTenderCheck, tenderBuildCheck, 'materialController.add');
@@ -835,6 +839,7 @@ module.exports = app => {
     app.post('/sp/:id/filing/del', sessionAuth, subProjectCheck, 'fileController.delFiling');
     app.post('/sp/:id/filing/move', sessionAuth, subProjectCheck, 'fileController.moveFiling');
     app.post('/sp/:id/file/load', sessionAuth, subProjectCheck, 'fileController.loadFile');
+    app.post('/sp/:id/file/check', sessionAuth, subProjectCheck, 'fileController.checkFiles');
     app.post('/sp/:id/file/upload', sessionAuth, subProjectCheck, 'fileController.uploadFile');
     app.post('/sp/:id/file/upload/big', sessionAuth, subProjectCheck, 'fileController.uploadBigFile');
     app.post('/sp/:id/file/del', sessionAuth, subProjectCheck, 'fileController.delFile');

+ 1 - 1
app/service/change_apply_audit.js

@@ -1263,7 +1263,7 @@ module.exports = app => {
                     const newAuditors = await transaction.select(this.tableName, { where: { caid: caId, times }, orders: [['order', 'asc']] });
                     const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'order', true);
                     const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);
-                    await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, uniqNewAuditorGroup, sp_group);
+                    // await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, uniqNewAuditorGroup, sp_group);
                 } else if (this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdzs) {
                     const newAuditors = await this.getAuditGroupByList(caId, 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, 'aid'));

+ 72 - 20
app/service/change_plan.js

@@ -9,6 +9,7 @@
  */
 
 const audit = require('../const/audit').changePlan;
+const auditType = require('../const/audit').auditType;
 // const smsTypeConst = require('../const/sms_type');
 // const SMS = require('../lib/sms');
 // const SmsAliConst = require('../const/sms_alitemplate');
@@ -31,6 +32,50 @@ module.exports = app => {
             this.tableName = 'change_plan';
         }
 
+        async loadChangeAuditViewData(change) {
+            const times = change.status === audit.status.checkNo || change.status === audit.status.revise ? change.times - 1 : change.times;
+
+            if (!change.user) change.user = await this.ctx.service.projectAccount.getAccountInfoById(change.uid);
+            change.auditHistory = await this.ctx.service.changePlanAudit.getAuditorHistory(change.id, times);
+            // 获取审批流程中左边列表
+            if ((change.status === audit.status.checkNo || change.status === audit.status.revise) && change.uid !== this.ctx.session.sessionUser.accountId && !this.ctx.session.sessionUser.is_admin) {
+                const auditors = await this.ctx.service.changePlanAudit.getAuditors(change.id, times); // 全部参与的审批人
+                const auditorGroups = this.ctx.helper.groupAuditors(auditors, 'order', true);
+                change.auditors2 = this.ctx.helper.groupAuditorsUniq(auditorGroups);
+                change.auditors2.unshift([{
+                    aid: change.user.id, order: 0, times: change.times - 1, audit_order: 0, audit_type: auditType.key.common,
+                    name: change.user.name, role: change.user.role, company: change.user.company,
+                }]);
+            } else {
+                change.auditors2 = change.userGroups;
+            }
+            if (change.status === audit.status.uncheck || change.status === audit.status.checkNo || change.status === audit.status.revise) {
+                change.auditorList = await this.ctx.service.changePlanAudit.getAuditors(change.id, change.times);
+            }
+        }
+
+        async loadChangeUser(change) {
+            const status = audit.status;
+            const accountId = this.ctx.session.sessionUser.accountId;
+
+            change.user = await this.ctx.service.projectAccount.getAccountInfoById(change.uid);
+            change.auditors = await this.ctx.service.changePlanAudit.getAuditors(change.id, change.times); // 全部参与的审批人
+            change.auditorIds = this._.map(change.auditors, 'aid');
+            change.curAuditors = change.auditors.filter(x => { return x.status === status.checking; }); // 当前流程中审批中的审批人
+            change.curAuditorIds = this._.map(change.curAuditors, 'aid');
+            change.flowAuditors = change.curAuditors.length > 0 ? change.auditors.filter(x => { return x.order === change.curAuditors[0].order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)
+            change.flowAuditorIds = this._.map(change.flowAuditors, 'aid');
+            change.nextAuditors = change.curAuditors.length > 0 ? change.auditors.filter(x => { return x.order === change.curAuditors[0].order + 1; }) : [];
+            change.nextAuditorIds = this._.map(change.nextAuditors, 'aid');
+            change.auditorGroups = this.ctx.helper.groupAuditors(change.auditors, 'order', true);
+            change.userGroups = this.ctx.helper.groupAuditorsUniq(change.auditorGroups);
+            change.userGroups.unshift([{
+                aid: change.user.id, order: 0, times: change.times, audit_order: 0, audit_type: auditType.key.common,
+                name: change.user.name, role: change.user.role, company: change.user.company,
+            }]);
+            change.finalAuditorIds = change.userGroups[change.userGroups.length - 1].map(x => { return x.aid; });
+        }
+
         async add(tenderId, userId, code, apply_code, name) {
             const sql = 'SELECT COUNT(*) as count FROM ?? WHERE `tid` = ? AND `code` = ?';
             const sqlParam = [this.tableName, tenderId, code];
@@ -441,32 +486,39 @@ module.exports = app => {
             const auditors = change.auditors;
             change.cancancel = 0;
             if (change.status !== status.checked && change.status !== status.uncheck && change.status !== status.revise) {
-                if (change.status !== status.checkNo) {
-                    // 找出当前操作人上一个审批人,包括审批完成的和退回上一个审批人的,同时当前操作人为第一人时,就是则为原报
-                    const onAuditor = this._.find(auditors, function(item) {
-                        return item.aid === change.curAuditor.aid && item.status === status.checking;
-                    });
-                    const preAudit = onAuditor.order !== 1 ? this._.find(auditors, { order: onAuditor.order - 1 }) : false;
-                    const preAid = preAudit ? (preAudit.status !== status.checkAgain ? preAudit.aid : false) : change.uid;// 已发起重审无法撤回
-                    if (onAuditor && onAuditor.aid === preAid && preAudit.status === status.checkCancel) {
-                        return;// 不可以多次撤回
-                    } else if (preAid === accountId && preAid !== change.uid) {
-                        if (preAudit.status === status.checked) {
+                if (change.status === status.checkNo) {
+                    const lastAuditors = await this.service.changePlanAudit.getAuditors(change.id, change.times - 1);
+                    const onAuditor = this._.findLast(lastAuditors, { status: status.checkNo });
+                    if (onAuditor && onAuditor.aid === accountId) {
+                        change.cancancel = 4;// 审批人撤回退回原报
+                        change.preAuditors = lastAuditors.filter(x => { return x.order === onAuditor.order; });
+                    }
+                } else {
+                    if (change.flowAuditors.find(x => { return x.status !== status.checking; }) && change.flowAuditorIds.indexOf(accountId) < 0) return; // 当前流程存在审批人审批通过时,不可撤回
+                    if (change.curAuditorIds.indexOf(accountId) < 0 && change.flowAuditorIds.indexOf(accountId) >= 0) {
+                        change.cancancel = 5; // 会签未全部审批通过时,审批人撤回审批通过
+                        return;
+                    }
+                    const preAuditors = change.curAuditors[0].order !== 1 ? change.auditors.filter(x => { return x.order === change.curAuditors[0].order - 1; }) : [];
+                    const preAuditorCheckAgain = preAuditors.find(pa => { return pa.status === status.checkAgain; });
+                    const preAuditorCheckCancel = preAuditors.find(pa => { return pa.status === status.checkCancel; });
+                    const preAuditorIds = preAuditorCheckAgain ? [] : preAuditors.map(x => { return x.aid; }); // 重审不可撤回
+                    if ((this._.isEqual(change.flowAuditorIds, preAuditorIds) && preAuditorCheckCancel)) {
+                        return; // 不可以多次撤回
+                    }
+                    const preAuditChecked = preAuditors.find(pa => { return pa.status === status.checked && pa.aid === accountId; });
+                    // const preAuditCheckNoPre = preAuditors.find(pa => { return pa.status === status.checkNoPre && pa.uid === accountId; });
+                    if (preAuditorIds.indexOf(accountId) >= 0) {
+                        if (preAuditChecked && change.status === status.checking) {
                             change.cancancel = 2;// 审批人撤回审批通过
                         }
-                        // else if (preAudit.status === status.checkNoPre) {
+                        // else if (preAuditCheckNoPre && change.status === status.checkNoPre) {
                         //     change.cancancel = 3;// 审批人撤回审批退回上一人
                         // }
-                        change.preAudit = preAudit;
-                    } else if (preAid === accountId && preAid === change.uid) {
+                        change.preAuditors = preAuditors;
+                    } else if (preAuditors.length === 0 && accountId === change.uid) {
                         change.cancancel = 1;// 原报撤回
                     }
-                } else {
-                    const lastAuditors = await this.service.changePlanAudit.getAuditors(change.id, change.times - 1);
-                    const onAuditor = this._.findLast(lastAuditors, { status: status.checkNo });
-                    if (onAuditor && onAuditor.aid === accountId) {
-                        change.cancancel = 4;// 审批人撤回退回原报
-                    }
                 }
             }
         }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 656 - 286
app/service/change_plan_audit.js


+ 2 - 2
app/service/change_project_audit.js

@@ -785,7 +785,7 @@ module.exports = app => {
          */
         async checkCancel(change) {
 
-            // 分4种情况,根据ctx.cancancel值判断:
+            // 分5种情况,根据ctx.cancancel值判断:
             // 1.原报发起撤回,当前流程删除,并回到待上报
             // 2.审批人撤回审批通过,增加流程,并回到它审批中
             // 3.审批人撤回审批终止,增加流程,并回到它审批中,并更新立项状态为审批中
@@ -1399,7 +1399,7 @@ module.exports = app => {
                     const newAuditors = await transaction.select(this.tableName, { where: { cpid: cpId, times }, orders: [['order', 'asc']] });
                     const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'order', true);
                     const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);
-                    await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, uniqNewAuditorGroup, sp_group);
+                    // await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.change, shenpiConst.sp_type.change, uniqNewAuditorGroup, sp_group);
                 } else if (this.ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdzs) {
                     const newAuditors = await this.getAuditGroupByList(cpId, 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, 'aid'));

+ 6 - 0
app/service/file.js

@@ -44,6 +44,12 @@ module.exports = app => {
             return result;
         }
 
+        async checkFiles(filing_id, files) {
+            const existFiles = await this.getAllDataByCondition({ columns: ['filename', 'fileext'], where: { filing_id } });
+            const existFilesName = existFiles.map(x => { return x.filename + x.fileext });
+            return files.filter(x => { return existFilesName.indexOf(x) >= 0; });
+        }
+
         async addFiles(filing, fileInfo, user) {
             const conn = await this.db.beginTransaction();
             const result = {};

+ 3 - 1
app/service/stage_audit.js

@@ -567,7 +567,6 @@ module.exports = app => {
                             his_id,
                         });
 
-                        await this.ctx.service.tenderCache.updateStageCache4Flow(transaction, this.ctx.stage, checkData.checkType, nextAudits, flowAudits, ledgerTp, stageTp);
                         await this.ctx.service.stagePay.cacheOrder(this.ctx.stage, transaction);
                         // 当前期不是最新一起时
                         if (this.ctx.stage.highOrder !== this.ctx.stage.order) {
@@ -588,6 +587,9 @@ module.exports = app => {
                                 pre_sf_tp: this.ctx.helper.add(this.ctx.stage.pre_sf_tp, stageTp.sf_tp),
                             };
                             await transaction.updateRows(this.ctx.service.stage.tableName, nextStages.map(x => { return { id: x.id, ...preStageTp }; }));
+                            await this.ctx.service.tenderCache.updateStageCache4MultiChecked(transaction, this.ctx.stage, flowAudits, ledgerTp, stageTp, nextStages[0], preStageTp);
+                        } else {
+                            await this.ctx.service.tenderCache.updateStageCache4Flow(transaction, this.ctx.stage, checkData.checkType, nextAudits, flowAudits, ledgerTp, stageTp);
                         }
 
                         // 添加短信通知-审批通过提醒功能

+ 0 - 1
app/service/stage_pay.js

@@ -144,7 +144,6 @@ module.exports = app => {
             const stagePays = [];
             const prePays = await this.getStageLastestPays(preStage);
             for (const pp of prePays) {
-                console.log(pp);
                 const p = this._.find(pays, {id: pp.pid});
                 if (!p.valid) continue;
                 stagePays.push({

+ 8 - 3
app/service/sub_project.js

@@ -369,7 +369,14 @@ module.exports = app => {
             const users = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: subProject.project_id, company: data.management }});
             const orgMember = await this.ctx.service.subProjPermission.getAllDataByCondition({ where: { spid: subProject.id } });
             const dm = [], um = [], im = [];
-            const filing_type = this.ctx.service.filing.allFilingType.join(','), file_permission = '1,2';
+
+            const template = await this.ctx.service.filingTemplateList.getDataById(data.filingTemplate);
+            if (!template) throw '选择的文件类别不存在';
+
+            const templateFiling = await this.ctx.service.filingTemplate.getAllDataByCondition({
+                where: { temp_id: template.id, tree_level: 1 },
+            });
+            const filing_type = templateFiling.map(x => { return x.filing_type; }).join(','), file_permission = '1,2';
             for (const u of users) {
                 const nm = orgMember.find(x => { return u.id === x.uid; });
                 if (nm) {
@@ -378,8 +385,6 @@ module.exports = app => {
                     im.push({ id: this.uuid.v4(), spid: subProject.id, pid: subProject.project_id, uid: u.id, file_permission, filing_type });
                 }
             }
-            const template = await this.ctx.service.filingTemplateList.getDataById(data.filingTemplate);
-            if (!template) throw '选择的文件类别不存在';
 
             const conn = await this.db.beginTransaction();
             try {

+ 34 - 2
app/service/tender_cache.js

@@ -63,7 +63,6 @@ module.exports = app => {
                         status_class: auditConst.stage.tiStatusStringClass[cache.stage_status],
                     };
                 } catch (err) {
-                    console.log(tender.id);
                     tender.progress = {
                         title: `第${tender.stage_count}期`,
                         status: auditConst.stage.tiStatusString[cache.stage_status],
@@ -85,7 +84,6 @@ module.exports = app => {
                         status_class: auditConst.stage.tiStatusStringClass[auditConst.stage.status.checked],
                     };
                 } catch(err) {
-                    console.log(tender.id);
                     tender.progress = {
                         title: `第${tender.stage_count}期`,
                         status: auditConst.stage.tiStatusString[auditConst.stage.status.checked],
@@ -299,6 +297,40 @@ module.exports = app => {
             await transaction.update(this.tableName, data);
         }
 
+        async updateStageCache4MultiChecked(transaction, stage, auditors, ledgerTp, stageTp, nextStage, nextStageTp) {
+            if (!stage.isCheckFirst) return;
+
+            const orgCache = await this.getDataById(stage.tid);
+
+            const data = { id: stage.tid, stage_status: auditConst.stage.status.uncheck, stage_complete_count: stage.order, stage_count: stage.order + 1 };
+            if (ledgerTp) data.ledger_tp = JSON.stringify(ledgerTp);
+            const tp = orgCache.stage_flow_cur_tp ? JSON.parse(orgCache.stage_flow_cur_tp) : (orgCache.stage_flow_pre_tp ? JSON.parse(orgCache.stage_flow_pre_tp) : {});
+            if (stageTp) this._.assign(tp, stageTp);
+
+            if (auditors && auditors.length > 0) {
+                const auditorIds = auditors.map(x => { return x.aid; });
+                data.stage_flow_pre_uid = auditorIds.join(',');
+                const info = await this.ctx.service.projectAccount.getAccountCacheDatas(auditorIds, { order: stage.order,
+                    audit_type: auditors[0].audit_type, status: auditConst.stage.status.checked, audit_order: auditors[0].audit_order });
+                data.stage_flow_pre_info = info.length > 0 ? JSON.stringify(info) : '';
+            }
+            data.stage_flow_pre_tp = JSON.stringify(tp);
+
+            data.stage_flow_cur_uid = nextStage.user_id;
+            const cur_flow_info = await this.ctx.service.projectAccount.getAccountCacheData(nextStage.user_id);
+            cur_flow_info.order = nextStage.order;
+            cur_flow_info.status = auditConst.stage.status.uncheck;
+            data.stage_flow_cur_info = JSON.stringify(cur_flow_info);
+            const cur_flow_tp = {
+                contract_tp: 0, qc_tp: 0,
+                positive_qc_tp: 0, negative_qc_tp: 0,
+                yf_tp: 0, sf_tp: 0,
+                ...nextStageTp,
+            };
+            data.stage_flow_cur_tp = JSON.stringify(cur_flow_tp);
+            await transaction.update(this.tableName, data);
+        }
+
         async updateStageCache4Revise(transaction, tid, ledgerTp, pcTp) {
             const orgCache = await this.getDataById(tid);
             const data = { id: tid };

+ 8 - 6
app/view/change/apply.ejs

@@ -98,12 +98,14 @@
                                 <% } %>
                             </td>
                             <td class="<%- auditConst.auditProgressClass[c.status] %>">
-                                <% if (c.curAuditors && c.curAuditors.length > 0) { %>
-                                    <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
-                                    <% } else { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审' %></a>
-                                    <% } %>
+                                <% if (c.status === auditConst.status.checked && c.final_auditor_str) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.final_auditor_str %></a>
+                                <% } else if (c.curAuditors.length > 0) { %>
+                                <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
+                                <% } else { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审' %></a>
+                                <% } %>
                                 <% } %>
                                 <%- auditConst.auditProgress[c.status] %>
                             </td>

+ 3 - 1
app/view/change/index.ejs

@@ -135,7 +135,9 @@
                             <% } %>
                         </td>
                         <td class="<%- auditConst.auditProgressClass[c.status] %>">
-                            <% if (c.curAuditors.length > 0) { %>
+                            <% if (c.status === auditConst.status.checked && c.final_auditor_str) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.cid %>"><%- c.final_auditor_str %></a>
+                            <% } else if (c.curAuditors.length > 0) { %>
                                 <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
                                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.cid %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
                                 <% } else { %>

+ 24 - 9
app/view/change/plan.ejs

@@ -67,7 +67,7 @@
         <div class="c-body">
             <div class="sjs-height-0">
                 <table class="table table-bordered">
-                    <thead>
+                    <thead class="text-center">
                     <tr>
                         <th width="15%" id="sort_change">变更方案编号</th><th width="20%">变更工程名称</th>
                         <th width="10%">变更性质</th><th width="15%">变更金额</th><th width="15%">变更申请编号</th>
@@ -80,20 +80,33 @@
                             <td><%- c.quality %></td>
                             <td style="text-align: right"><%- c.total_price %></td>
                             <td><%- c.apply_code %></td>
-                            <td>
-                                <% if ((c.status === auditConst.status.uncheck || c.status === auditConst.status.checkNo || c.status === auditConst.status.revise) && c.uid === ctx.session.sessionUser.accountId) { %>
+                            <td class="text-center">
+                                <% if (c.status === auditConst.status.uncheck && c.uid === ctx.session.sessionUser.accountId) { %>
                                     <a href="/tender/<%- tender.id %>/change/plan/<%- c.id %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm"><%- auditConst.statusButton[c.status] %></a>
-                                <% } else if (c.status === auditConst.status.checking && c.curAuditor && c.curAuditor.aid === ctx.session.sessionUser.accountId) { %>
+                                <% } else if ((c.status === auditConst.status.checkNo || c.status === auditConst.status.revise) && c.curAuditors && c.aid === ctx.session.sessionUser.accountId) { %>
                                     <a href="/tender/<%- tender.id %>/change/plan/<%- c.id %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm"><%- auditConst.statusButton[c.status] %></a>
+                                <% } else if (c.status === auditConst.status.checking && c.curAuditors && c.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                                    <% const curAudit = c.curAuditors.find(x => { return x.aid === ctx.session.sessionUser.accountId; }); %>
+                                    <% if (curAudit.status === auditConst.status.checking) { %>
+                                        <a href="/tender/<%- tender.id %>/change/plan/<%- c.id %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm"><%- auditConst.statusButton[c.status] %></a>
+                                    <% } else { %>
+                                        <span class="<%- auditConst.auditStringClass[curAudit.status] %>"><%- auditConst.auditString[curAudit.status] %></span>
+                                    <% } %>
                                 <% } else { %>
-                                    <span class="<%- auditConst.auditProgressClass[c.status] %>"><%- auditConst.auditProgress[c.status] %></span>
+                                    <span class="<%- auditConst.auditStringClass[c.status] %>"><%- auditConst.auditString[c.status] %></span>
                                 <% } %>
                             </td>
-                            <td>
-                                <% if (c.status !== auditConst.status.uncheck) { %>
-                                    <%- c.curAuditor.name %>-<%- c.curAuditor.role %>
+                            <td class="<%- auditConst.auditProgressClass[c.status] %>">
+                                <% if (c.status === auditConst.status.checked && c.final_auditor_str) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.final_auditor_str %></a>
+                                <% } else if (c.curAuditors.length > 0) { %>
+                                <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
+                                <% } else { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审' %></a>
+                                <% } %>
                                 <% } %>
-                                <span class="<%- auditConst.statusClass[c.status] %>"><%- auditConst.statusString[c.status] %></span>
+                                <%- auditConst.auditProgress[c.status] %>
                             </td>
                             <td>
                                 <% if (c.uid === uid && (c.status === auditConst.status.uncheck || c.status === auditConst.status.checkNo)) { %><a href="#del-bg" cpid="<%= c.id %>" data-toggle="modal" data-target="#del-bg" class="btn btn-outline-danger btn-sm delete-cpid-modal">删除</a><% } %>
@@ -120,5 +133,7 @@
     const ruleType = parseInt('<%- ruleType %>');
     const openChangeApply = parseInt('<%- ctx.session.sessionProject.page_show.openChangeApply %>');
     const rulesType = '<%- rule_type %>';
+    const auditType = JSON.parse(unescape('<%- escape(JSON.stringify(auditType)) %>'));
+    const auditConst = JSON.parse(unescape('<%- escape(JSON.stringify(auditConst)) %>'));
     const changeApplyList = JSON.parse(unescape('<%- escape(JSON.stringify(changeApplyList)) %>'));
 </script>

+ 2 - 2
app/view/change/plan_information.ejs

@@ -33,7 +33,7 @@
                         <a id="sub-sp-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-outline-secondary btn-sm">上报中</a>
                     <% } %>
                 <% } else if (ctx.change.status === auditConst.status.checking) { %>
-                    <% if (ctx.change.curAuditor && ctx.change.curAuditor.aid === ctx.session.sessionUser.accountId) { %>
+                    <% 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 { %>
@@ -41,7 +41,7 @@
                     <% } %>
                 <% } 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>
-                    <% if (ctx.session.sessionUser.accountId === ctx.change.auditors2[ctx.change.auditors2.length-1].aid) { %>
+                    <% 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>
                     <% } %>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 885 - 451
app/view/change/plan_information_modal.ejs


+ 25 - 1
app/view/change/plan_modal.ejs

@@ -17,7 +17,31 @@
         </div>
     </div>
 </div>
-
+<!--审批流程/结果-->
+<div class="modal fade" id="sp-list" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批流程</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-4 modal-height-500" style="overflow: auto">
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush" id="auditor-list">
+                            </ul>
+                        </div>
+                    </div>
+                    <div class="col-8 modal-height-500" style="overflow: auto" id="audit-list">
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% if (tender.user_id === uid) { %>
 <!--弹出添加变更令-->
 <div class="modal fade" id="add-bj-modal" data-backdrop="static">

+ 8 - 6
app/view/change/project.ejs

@@ -95,12 +95,14 @@
                                 <% } %>
                             </td>
                             <td class="<%- auditConst.auditProgressClass[c.status] %>">
-                                <% if (c.curAuditors && c.curAuditors.length > 0) { %>
-                                    <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
-                                    <% } else { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审' %></a>
-                                    <% } %>
+                                <% if (c.status === auditConst.status.checked && c.final_auditor_str) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.final_auditor_str %></a>
+                                <% } else if (c.curAuditors.length > 0) { %>
+                                <% if (c.curAuditors[0].audit_type === auditType.key.common) { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- c.curAuditors[0].name %><%if (c.curAuditors[0].role !== '' && c.curAuditors[0].role !== null) { %>-<%- c.curAuditors[0].role %><% } %></a>
+                                <% } else { %>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- c.id %>"><%- ctx.helper.transFormToChinese(c.curAuditors[0].audit_order) + '审' %></a>
+                                <% } %>
                                 <% } %>
                                 <%- auditConst.auditProgress[c.status] %>
                             </td>

+ 4 - 0
app/view/file/file_modal.ejs

@@ -70,6 +70,8 @@
                 <h5 class="modal-title">上传附件</h5>
             </div>
             <div class="modal-body">
+                <div class="form-group text-danger" style="display: none" id="upload-file-hint">
+                </div>
                 <div class="form-group">
                     <label for="formGroupExampleInput">单个文件大小限制:50MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-file" multiple>
@@ -89,6 +91,8 @@
                 <h5 class="modal-title">上传附件</h5>
             </div>
             <div class="modal-body">
+                <div class="form-group text-danger" style="display: none" id="upload-big-file-hint">
+                </div>
                 <div class="form-group">
                     <label for="formGroupExampleInput">文件大小限制:500MB,支持<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="doc,docx,xls,xlsx,ppt,pptx,pdf">office等文档格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="jpg,png,bmp">图片格式</span>、<span data-toggle="tooltip" data-placement="bottom" title="" data-original-title="rar,zip">压缩包格式</span></label>
                     <input type="file" class="" id="upload-big-file">

+ 77 - 0
config/config.remoteprod.js

@@ -0,0 +1,77 @@
+'use strict';
+/**
+ * 开发环境相关配置
+ *
+ * @author CaiAoLin
+ * @date 2017/8/29
+ * @version
+ */
+
+module.exports = appInfo => {
+    const config = {};
+    // 数据库配置
+    config.mysql = {
+        client: {
+            // host
+            host: 'rm-wz9ae9t6qopwrday6po.mysql.rds.aliyuncs.com',
+            // 端口号
+            port: '3306',
+            // 用户名
+            user: 'zh_calc',
+            // 密码
+            password: 'Zh@)!(3850Calc',
+            // 数据库名
+            database: 'calculation',
+            multipleStatements: true,
+        },
+        // 是否加载到 app 上,默认开启
+        app: true,
+        // 是否加载到 agent 上,默认关闭
+        agent: false,
+    };
+    // 表名前缀
+    config.tablePrefix = 'zh_';
+
+    // redis设置
+    config.redis = {
+        client: {
+            host: '192.168.1.76',
+            port: '6379',
+            password: 'zongheng2019',
+            db: '0',
+        },
+        agent: true,
+    };
+
+    // session配置
+    config.session = {
+        key: 'ZHC_SESS',
+        maxAge: 7 * 24 * 3600 * 1000, // 7天
+        httpOnly: true,
+        encrypt: true,
+        //renew: true, // session临近过期更新过期时间
+        rolling: true, // 每次都更新session有效期
+    };
+
+    config.oss = {
+        clients: {
+            signPdf: {
+                bucket: 'measure-sign-pdf',
+            },
+            fujian: {
+                bucket: 'jiliang-qa',
+            },
+        },
+        default: {
+            accessKeyId: 'LTAIALMjBHOs9PLA',
+            accessKeySecret: 'HSnULQs87wAJhcziAdyRv3GZ4EYctc',
+            endpoint: 'oss-cn-shenzhen.aliyuncs.com',
+            timeout: '60s',
+        },
+    };
+
+    config.fujianOssPath = 'https://jiliang-qa-oss.smartcost.com.cn/uat/';
+    config.fujianOssFolder = 'uat/';
+
+    return config;
+};

+ 1 - 0
package.json

@@ -76,6 +76,7 @@
         "dev-local": "set EGG_SERVER_ENV=local&&egg-bin dev --port 7002",
         "dev-remoteqa": "set EGG_SERVER_ENV=remoteqa&&egg-bin dev --port 7002",
         "dev-remoteuat": "set EGG_SERVER_ENV=remoteuat&&egg-bin dev --port 7002",
+        "dev-remoteprod": "set EGG_SERVER_ENV=remoteprod&&egg-bin dev --port 7002",
         "dev-localpro": "set EGG_SERVER_ENV=localpro&&egg-bin dev --port 7002",
         "dev-temp": "set EGG_SERVER_ENV=temp&&egg-bin dev --port 7002",
         "dev-qa": "set EGG_SERVER_ENV=qa&&egg-bin dev --port 7002",

+ 9 - 0
sql/update.sql

@@ -41,3 +41,12 @@ ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审
 
 ALTER TABLE `zh_global_log`
 ADD COLUMN `memo` varchar(255) NOT NULL DEFAULT '' AFTER `run_time`;
+
+ALTER TABLE `zh_change`
+ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审人相关(cache)' AFTER `sp_group`;
+ALTER TABLE `zh_change_apply`
+ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审人相关(cache)' AFTER `sp_group`;
+ALTER TABLE `zh_change_plan`
+ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审人相关(cache)' AFTER `sp_group`;
+ALTER TABLE `zh_change_project`
+ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审人相关(cache)' AFTER `sp_group`;