瀏覽代碼

合同支付,所有审批流程

MaiXinRong 7 月之前
父節點
當前提交
1f54a9600b

+ 1 - 0
app/const/audit.js

@@ -1388,6 +1388,7 @@ const pushType = {
     changePlan: 9,
     settle: 10,
     financial: 11,
+    phasePay: 12,
 };
 
 module.exports = {

+ 11 - 0
app/const/sms_type.js

@@ -15,6 +15,7 @@ const smsConst = {
     TC: 'TC',
     YFK: 'YFK',
     JS: 'JS',
+    PAY: 'PAY',
 };
 const judgeConst = {
     approval: 1,
@@ -91,6 +92,16 @@ const smsType = {
             { title: '审批结果', value: 2 },
         ],
     },
+    PAY: {
+        name: '合同支付',
+        path: '',
+        wechat: true,
+        sms: true,
+        children: [
+            { title: '需要我审批', value: 1 },
+            { title: '审批结果', value: 2 },
+        ],
+    },
 };
 
 module.exports = {

+ 2 - 0
app/const/wechat_template.js

@@ -15,6 +15,7 @@ const template = {
     material: 4,
     advance: 5,
     settle: 6,
+    phasePay: 7,
 };
 const templateId = {
     stage: '5vU3WmR90yDajbs4LWIWH4OQhunYlS1HXTiesIGxrsk',
@@ -24,6 +25,7 @@ const templateId = {
     material: 'Y9ov80rev3LHcoM2hOQE6jrK_5xZsqE-PZ0Z6HS9VGA',
     advance: 'rgZHkyiLzrqaSGnQ2nSCCrOdUz2RJJZ_JA34L_MnQik',
     settle: '5vU3WmR90yDajbs4LWIWH4OQhunYlS1HXTiesIGxrsk', // todo 暂使用计量期模板
+    phasePay: '5vU3WmR90yDajbs4LWIWH4OQhunYlS1HXTiesIGxrsk', // todo 暂使用计量期模板
 };
 const status = {
     check: '待审批',

+ 51 - 28
app/controller/pay_controller.js

@@ -32,8 +32,7 @@ module.exports = app => {
                 const relaStage = [];
                 for (const p of phasePays) {
                     // todo 加载当前审批人
-                    // if (p.audit_status !== checked) await this.ctx.service.phasePay.loadUser(p);
-                    p.curAuditors = [];
+                    if (p.audit_status !== audit.common.status.checked) await this.ctx.service.phasePay.loadUser(p);
                     relaStage.push(...p.rela_stage);
                 }
                 const stages = await this.ctx.service.stage.getAllDataByCondition({ where: { tid: ctx.tender.id }, orders: [['order', 'AEC']] });
@@ -42,6 +41,7 @@ module.exports = app => {
                 });
                 this.ctx.service.phasePay.calculatePhasePay(phasePays);
                 const renderData = {
+                    auditType: audit.auditType,
                     phasePays,
                     validStages,
                     auditConst: audit.common,
@@ -49,7 +49,8 @@ module.exports = app => {
                 };
                 await this.layout('phase_pay/index.ejs', renderData, 'phase_pay/modal.ejs');
             } catch (err) {
-                ctx.helper.log(err);
+                ctx.log(err);
+                ctx.redirect(ctx.request.header.referer);
             }
         }
 
@@ -65,7 +66,7 @@ module.exports = app => {
                 const memo = ctx.request.body.memo;
 
                 const pays = await ctx.service.phasePay.getAllPhasePay(ctx.tender.id, 'DESC');
-                const unCompleteCount = pays.filter(s => { return s.status !== audit.phasePay.status.checked; }).length;
+                const unCompleteCount = pays.filter(s => { return s.status !== audit.common.status.checked; }).length;
                 if (unCompleteCount.length > 0) throw `最新一起未审批通过,请审批通过后再新增`;
                 // 预留可以关联多期
                 const stages = await ctx.service.stage.getAllDataByCondition({ where: { tid: ctx.tender.id, order: stage } });
@@ -73,14 +74,14 @@ module.exports = app => {
                 const newPhase = await ctx.service.phasePay.add(ctx.tender.id, stages, date, memo);
                 if (!newPhase) throw '新增期失败';
                 newPhase.curTimes = 1;
-                newPhase.curOrder = 0;
+                newPhase.curSort = 0;
                 await ctx.service.phasePayDetail.calculateSave(newPhase);
 
-                ctx.redirect('/tender/' + ctx.tender.id + '/pay' + newPhase.phase_order);
+                ctx.redirect('/tender/' + ctx.tender.id + '/pay/' + newPhase.phase_order + '/detail');
             } catch (err) {
-                this.log(err);
+                ctx.log(err);
                 ctx.postError(err, '新增期失败');
-                ctx.redirect(ctx.request.header.referer);
+                ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             }
         }
 
@@ -101,7 +102,7 @@ module.exports = app => {
                 ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             } catch (err) {
                 ctx.log(err);
-                ctx.redirect(ctx.request.header.referer);
+                ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             }
         }
 
@@ -116,21 +117,40 @@ module.exports = app => {
                 if (!phasePay) throw '删除的期不存在,请刷新页面';
                 if (!ctx.session.sessionUser.is_admin && phasePay.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权修改该数据';
                 await this.ctx.service.phasePay.save(phasePay, data);
-                if (phasePay.audit_status === audit.phasePay.status.uncheck && ctx.request.body.stage) {
+                if (phasePay.audit_status === audit.common.status.uncheck && ctx.request.body.stage) {
                     const stages = await ctx.service.stage.getAllDataByCondition({ where: { tid: ctx.tender.id, order: ctx.request.body.stage } });
                     await this.ctx.service.phasePay.resetRelaStageId(phasePay, stages);
                 }
                 ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             } catch (err) {
-                console.log(err);
-                this.log(err);
+                ctx.log(err);
                 ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             }
         }
 
+        /**
+         * 期审批流程(POST)
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async loadAuditors(ctx) {
+            try {
+                const order = JSON.parse(ctx.request.body.data).order;
+                const tenderId = ctx.params.id;
+                const phasePay = await ctx.service.phasePay.getPhasePayByOrder(tenderId, order);
+                await ctx.service.phasePay.loadUser(phasePay);
+                await ctx.service.phasePay.loadAuditViewData(phasePay);
+                ctx.body = { err: 0, msg: '', data: phasePay };
+            } catch (error) {
+                ctx.log(error);
+                ctx.body = { err: 1, msg: error.toString(), data: null };
+            }
+        }
+
         async detail(ctx) {
             try {
                 // await this.ctx.service.phasePayDetail.calculateSave(ctx.phasePay);
+                await this.ctx.service.phasePay.loadAuditViewData(ctx.phasePay);
                 const pays = await this.ctx.service.phasePayDetail.getDetailData(ctx.phasePay);
                 const calcBase = this.ctx.service.phasePay.getPhasePayCalcBase(ctx.phasePay, ctx.tender.info);
                 const projectFunInfo = await this.ctx.service.project.getFunRela(ctx.session.sessionProject.id);
@@ -144,11 +164,13 @@ module.exports = app => {
                     const groupList = accountList.filter(item1 => item1.company === item.name);
                     return { groupName: item.name, groupList };
                 });
+                // 是否已验证手机短信
+                const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
                 const renderData = {
                     pays,
                     calcBase,
                     lockPayExpr: projectFunInfo.lockPayExpr,
-                    auditConst: audit.phasePay,
+                    auditConst: audit.common,
                     deadlineType: this.ctx.service.phasePayDetail.deadlineType,
                     maxStageOrder: lastStage.order,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.phasePay.detail),
@@ -156,12 +178,13 @@ module.exports = app => {
                     accountGroup,
                     shenpiConst,
                     auditType: audit.auditType,
+                    authMobile: pa.auth_mobile,
                 };
                 await this.layout('phase_pay/detail.ejs', renderData, 'phase_pay/detail_modal.ejs');
             } catch (err) {
-                ctx.helper.log(err);
+                ctx.log(err);
                 ctx.postError(err, '读取合同支付数据错误');
-                ctx.redirect(ctx.request.headers.referer);
+                ctx.redirect('/tender/' + ctx.tender.id + '/pay');
             }
         }
 
@@ -240,8 +263,7 @@ module.exports = app => {
                 }
                 ctx.body = responseData;
             } catch (err) {
-                console.log(err);
-                this.log(err);
+                ctx.log(err);
                 ctx.body = this.ajaxErrorBody(err, '数据错误');
             }
         }
@@ -302,7 +324,7 @@ module.exports = app => {
                 const result = await ctx.service.phasePayFile.delFiles(data);
                 ctx.body = { err: 0, msg: '', data: result };
             } catch(error) {
-                this.log(error);
+                ctx.log(error);
                 ctx.ajaxErrorBody(error, '删除附件失败');
             }
         }
@@ -320,7 +342,7 @@ module.exports = app => {
 
                 // 检查权限等
                 if (ctx.phasePay.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权添加审核人';
-                if (ctx.phasePay.audit_status !== audit.phasePay.status.uncheck && ctx.phasePay.audit_status !== audit.phasePay.status.checkNo) {
+                if (ctx.phasePay.audit_status !== audit.common.status.uncheck && ctx.phasePay.audit_status !== audit.common.status.checkNo) {
                     throw '当前不允许添加审核人';
                 }
 
@@ -339,7 +361,7 @@ module.exports = app => {
                 const auditors = await ctx.service.phasePayAudit.getAuditorGroup(ctx.phasePay.id, ctx.phasePay.audit_times);
                 ctx.body = { err: 0, msg: '', data: auditors };
             } catch (err) {
-                this.log(err);
+                ctx.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
@@ -360,26 +382,27 @@ module.exports = app => {
                 const auditors = await ctx.service.phasePayAudit.getAuditors(ctx.phasePay.id, ctx.phasePay.audit_times);
                 ctx.body = { err: 0, msg: '', data: auditors };
             } catch (err) {
+                ctx.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
         async auditStart(ctx) {
             try {
-                if (ctx.phasePay.user_id !== ctx.session.sessionUser.accountId) throw '您无权上报该期数据';
+                if (ctx.phasePay.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权上报该期数据';
                 if (ctx.phasePay.revising) throw '台账修订中,不可上报';
-                if (ctx.phasePay.audit_status !== audit.phasePay.status.uncheck && ctx.phasePay.audit_status !== audit.phasePay.status.checkNo) throw '该期数据当前无法上报';
+                if (ctx.phasePay.audit_status !== audit.common.status.uncheck && ctx.phasePay.audit_status !== audit.common.status.checkNo) throw '该期数据当前无法上报';
 
                 await ctx.service.phasePayAudit.start(ctx.phasePay);
                 ctx.redirect(ctx.request.header.referer);
             } catch (err) {
                 ctx.log(err);
                 ctx.postError(err, '上报失败');
-                ctx.redirect(`/tender/${ctx.phasePay.tid}/pay/${ctx.phasePay.settle_order}/select`);
+                ctx.redirect(`/tender/${ctx.phasePay.tid}/pay/${ctx.phasePay.phase_order}/detail`);
             }
         }
         async auditCheck(ctx) {
             try {
-                if (!ctx.phasePay || (ctx.phasePay.audit_status !== audit.phasePay.status.checking && ctx.phasePay.audit_status !== audit.phasePay.status.checkNoPre)) {
+                if (!ctx.phasePay || (ctx.phasePay.audit_status !== audit.common.status.checking && ctx.phasePay.audit_status !== audit.common.status.checkNoPre)) {
                     throw '当前期数据有误';
                 }
                 if (ctx.phasePay.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) < 0) {
@@ -398,8 +421,8 @@ module.exports = app => {
         }
         async auditCheckAgain(ctx) {
             try {
-                if (ctx.phasePay.phase_order !== ctx.phasePay.highOrder) throw '非最新一期,不可重新审批';
-                if (ctx.phasePay.audit_status !== audit.phasePay.status.checked) throw '未审批完成,不可重新审批';
+                if (ctx.phasePay.isLatest) throw '非最新一期,不可重新审批';
+                if (ctx.phasePay.audit_status !== audit.common.status.checked) throw '未审批完成,不可重新审批';
                 if (ctx.phasePay.revising) throw '台账修订中,不可重审';
 
                 if (ctx.session.sessionUser.loginStatus === 0) {
@@ -419,7 +442,7 @@ module.exports = app => {
 
                 await ctx.service.phasePayAudit.checkAgain(ctx.phasePay, adminCheckAgain);
             } catch (err) {
-                this.log(err);
+                ctx.log(err);
                 ctx.postError(err, '重新审批失败');
             }
             ctx.redirect(ctx.request.header.referer);
@@ -431,7 +454,7 @@ module.exports = app => {
 
                 await ctx.service.phasePayAudit.checkCancel(ctx.phasePay);
             } catch (err) {
-                this.log(err);
+                ctx.log(err);
                 ctx.postError(err, '撤回失败');
             }
             ctx.redirect(ctx.request.header.referer);

+ 0 - 136
app/public/js/phase_pay_audit.js

@@ -1,136 +0,0 @@
-'use strict';
-
-$(document).ready(() => {
-    const auditFlow = {
-        getAuditTypeText: function (type) {
-            if (type === auditType.key.common) return '';
-            return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
-        },
-        getSimpleAuditFlow: function(groups) {
-            const html = [];
-            for (const group of groups) {
-                html.push(`<li class="list-group-item" data-auditorid="${group[0].audit_id}">`);
-                html.push(`<i class="fa ${(group[0].is_final ? 'fa-stop-circle' : 'fa-chevron-circle-down')}"></i>`);
-                html.push(`${group[0].name} <small class="text-muted">${group[0].role}</small>`);
-                html.push('<span class="pull-right">${group[0].flow_name}</span>');
-                html.push('</li>');
-            }
-            return html.join('');
-        },
-        getStartAuditFlow: function(groups) {
-            const html = [];
-            for (const group of groups) {
-                if (group[0].audit_order === 0) continue;
-                html.push('<li class="list-group-item d-flex" auditorId="'+ group[0].audit_id +'">');
-                html.push(`<div class="col-auto">${group[0].audit_order}</div>`);
-                html.push('<div class="col">');
-                for (const auditor of group) {
-                    html.push(`<div class="d-inline-block mx-1"><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">');
-                if (group[0].audit_type !== auditType.key.common) {
-                    html.push(`<span class="badge badge-pill badge-${auditType.info[group[0].audit_type].class} badge-bg-small"><small>${auditType.info[group[0].audit_type].long}</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 ml-1">移除</a>');
-                }
-                html.push('</div>');
-                html.push('</li>');
-            }
-            return html.join('');
-        },
-        saveAudit: function(data, callback) {
-            postData('audit/save', data, (result) => {
-                callback(result);
-            });
-        }
-    };
-    // 搜索
-    let timer = null;
-    let oldSearchVal = null;
-    $('#gr-search').bind('input propertychange', function(e) {
-        oldSearchVal = e.target.value;
-        timer && clearTimeout(timer);
-        timer = setTimeout(() => {
-            const newVal = $('#gr-search').val();
-            let html = '';
-            if (newVal && newVal === oldSearchVal) {
-                accountList.filter(item => item && userID !== item.id && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
-                    html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
-                        <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
-                                class="ml-auto">${item.mobile || ''}</span></p>
-                        <span class="text-muted">${item.role || ''}</span>
-                    </dd>`
-                });
-                $('.book-list').empty();
-                $('.book-list').append(html);
-            } else {
-                if (!$('.acc-btn').length) {
-                    accountGroup.forEach((group, idx) => {
-                        if (!group) return;
-                        html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
-                        </a> ${group.groupName}</dt>
-                        <div class="dd-content" data-toggleid="${idx}">`;
-                        group.groupList.forEach(item => {
-                            if (item.id !== userID) {
-                                html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
-                                    <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
-                                            class="ml-auto">${item.mobile || ''}</span></p>
-                                    <span class="text-muted">${item.role || ''}</span>
-                                </dd>`
-                            }
-                        });
-                        html += '</div>';
-                    });
-                    $('.book-list').empty();
-                    $('.book-list').append(html);
-                }
-            }
-        }, 400);
-    });
-    // 展开收起角色/公司
-    $('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') {
-            $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
-                $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o');
-                $(this).find('.acc-btn').attr('data-type', 'show');
-            });
-        } else {
-            $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
-                $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square');
-                $(this).find('.acc-btn').attr('data-type', 'hide');
-            });
-        }
-        return false;
-    });
-    // 添加审批人
-    $('#book-list').on('click', 'dd', function () {
-        const id = parseInt($(this).data('id'));
-        if (!id) return;
-        auditFlow.saveAudit({ operate: 'add', audit_id: id }, (result) => {
-            $('#auditors').html(auditFlow.getStartAuditFlow(result));
-            $('#auditors-list').html(auditFlow.getSimpleAuditFlow(result));
-        });
-    });
-    // 移除审批人
-    $('body').on('click', '#auditors li a', function () {
-        const li = $(this).parents('li');
-        const data = {
-            operate: 'del',
-            audit_id: parseInt(li.attr('auditorId')),
-        };
-        auditFlow.saveAudit(data, (result) => {
-            $('#auditors').html(auditFlow.getStartAuditFlow(result));
-        });
-    });
-    $('body').on('click', '.remove-audit', function () {
-        const id = parseInt($(this).attr('data-id'));
-        postData('audit/save', { operate: 'del', audit_id: id }, (datas) => {
-            $('#admin-edit-shenpi-list').html(auditFlow.getStartAuditFlow(datas));
-            auditFlow.getStartAuditFlow(datas);
-        });
-    });
-});

+ 58 - 1
app/public/js/phase_pay_detail.js

@@ -94,7 +94,14 @@ $(document).ready(() => {
                 } else {
                     return payUtils.check.isWC(data) || payUtils.check.isSF(data) || payUtils.check.isYf(data) || !(payUtils.check.isOwner(data) || payUtils.check.isYB());
                 }
-            }
+            },
+            rangeTpReadOnly: function(data) {
+                if (payUtils.check.isOld(data)) {
+                    return !payUtils.check.isYB(data) || payUtils.check.isLock(data);
+                } else {
+                    return payUtils.check.isWC(data) || payUtils.check.isYF(data) || !(payUtils.check.isOwner(data) || payUtils.check.isYB());
+                }
+            },
         },
         menuVisible: {
             pause: function (data) {
@@ -827,6 +834,56 @@ $(document).ready(() => {
             $('a[name="base-opr"]').click(function () {
                 payEvent.baseOpr(this.getAttribute('type'));
             });
+            $('#pay-expr').bind('change onblur', function () {
+                if (this.readOnly) return;
+
+                const expr = $(this);
+                const row = expr.attr('data-row') ? _.toInteger(expr.attr('data-row')) : -1;
+                const select = payTree.nodes[row];
+                const field = expr.attr('field'), orgValue = expr.attr('org'), newValue = expr.val();
+                if (orgValue === newValue || (!orgValue && newValue == '')) { return; }
+
+                const data = { postType: 'update' };
+                if (field === 'expr') {
+                    data.postData = { id: select.id, tp: 0, expr: newValue };
+                    const [valid, msg] = payUtils.check.isSf(select)
+                        ? payCalc.checkSfExpr(newValue, data.postData, select, payTree)
+                        : payCalc.checkExpr(newValue, data.postData, select, payTree);
+                    if (!valid) {
+                        toastr.warning(msg);
+                        this.value = select.expr;
+                        return;
+                    }
+                } else if (field === 'start_expr') {
+                    data.updateData = {id: select.id};
+                    const [valid, msg] = payCalc.checkStartExpr(select, newValue, data.postData);
+                    if (!valid) {
+                        toastr.warning(msg);
+                        this.value = select.start_expr;
+                        return;
+                    }
+                } else if (field === 'range_expr') {
+                    data.updateData = {id: select.id};
+                    const [valid, msg] = payCalc.checkRangeExpr(select, newValue, data.postData);
+                    if (!valid) {
+                        toastr.warning(msg);
+                        this.value = select.range_expr;
+                        return;
+                    }
+                } else {
+                    expr.val('');
+                    return;
+                }
+                // 更新至服务器
+                postData('update', data, function (result) {
+                    if (result.reload) {
+                        payEvent.reloadPays(result.reload);
+                    } else {
+                        const refreshData = payTree.loadPostData(result);
+                        payEvent.refreshTree(refreshData);
+                    }
+                });
+            });
             $('#calc-all').click(function() {
                 payEvent.calculateAll();
             });

+ 134 - 1
app/public/js/phase_pay_list.js

@@ -1,9 +1,142 @@
 'use strict';
 
 $(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('展开历史审核记录')
+            })
+        }
+    });
 
+    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>`;
+    };
+    const getAuditorsHtml = function (auditors) {
+        const auditorsHTML = [];
+        auditors.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 === auditors.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>`);
+            }
+        });
+        return auditorsHTML;
+    }
+    const getAuditHistroyHtml = function (auditHistory) {
+        const 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) => {
+                historyHTML.push(`<li class="timeline-list-item pb-2 ${ group.audit_status === auditConst.status.uncheck && idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'is_uncheck' : ''}">`);
+                if (group.auditYear) {
+                    historyHTML.push(`<div class="timeline-item-date">${group.auditYear}<span>${group.auditDate}</span><span>${group.auditTime}</span></div>`);
+                }
+                if (group.audit_order < his.length - 1) {
+                    historyHTML.push('<div class="timeline-item-tail"></div>');
+                }
+                if (group.audit_status === auditConst.status.checked) {
+                    historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
+                } else if (group.audit_status === auditConst.status.checkNo || group.audit_status === auditConst.status.checkNoPre || 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.audit_status === auditConst.status.checking) {
+                    historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
+                } else {
+                    historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
+                }
+
+                historyHTML.push('<div class="timeline-item-content">');
+                if (group.audit_order > 0) {
+                    const statuStr = group.audit_status !== auditConst.status.uncheck ?
+                        `<span class="pull-right ${auditConst.info[group.audit_status].class}">${auditConst.info[group.audit_status].title}</span>` : '';
+                    historyHTML.push(`<div class="py-1">
+                        <span class="text-black-50">
+                        ${ !group.is_final ? group.audit_order + '' : '终' }审 ${getAuditTypeText(group.audit_type)}
+                        </span>
+                        ${statuStr}
+                    </div>`);
+                } else {
+                    historyHTML.push(` <div class="py-1">
+                        <span class="text-black-50">原报</span>
+                        <span class="pull-right text-success">${idx !== 0 ? '重新' : '' }上报审批</span>
+                    </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.audit_status === auditConst.status.checked) {
+                        historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
+                    } if (auditor.audit_status === auditConst.status.checkNo || auditor.audit_status === auditConst.status.checkNoPre || auditor.audit_status === auditConst.status.checkCancel) {
+                        historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
+                    }
+                    historyHTML.push('</div>');
+                    if (group.audit_order > 0 && 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>');
+        });
+        return historyHTML.join('');
+    }
+    // 获取审批流程
+    $('a[data-target="#sp-list" ]').on('click', function () {
+        postData('pay/auditors', { order: $(this).attr('phase-order') }, function (result) {
+            $('#auditor-list').html(getAuditorsHtml(result.hisUserGroup));
+            $('#audit-list').html(getAuditHistroyHtml(result.auditHistory));
+        });
+    });
 
-    // todo 加载审批列表
     $.subMenu({
         menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
         toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',

+ 8 - 7
app/router.js

@@ -394,20 +394,21 @@ module.exports = app => {
 
     app.get('/tender/:id/pay', sessionAuth, tenderCheck, 'payController.index');
     app.post('/tender/:id/pay/add', sessionAuth, tenderCheck, 'payController.add');
-    app.post('/tender/:id/pay/del', sessionAuth, tenderCheck, 'payController.del');
+    app.post('/tender/:id/pay/delete', sessionAuth, tenderCheck, 'payController.del');
     app.post('/tender/:id/pay/save', sessionAuth, tenderCheck, 'payController.save');
+    app.post('/tender/:id/pay/auditors', sessionAuth, tenderCheck, 'payController.loadAuditors');
     app.get('/tender/:id/pay/:order/detail', sessionAuth, tenderCheck, phasePayCheck, 'payController.detail');
     app.post('/tender/:id/pay/:order/load', sessionAuth, tenderCheck, phasePayCheck, 'payController.detailLoad');
     app.post('/tender/:id/pay/:order/update', sessionAuth, tenderCheck, phasePayCheck, 'payController.detailUpdate');
     app.post('/tender/:id/pay/:order/file/upload', sessionAuth, tenderCheck, phasePayCheck, 'payController.uploadFile');
     app.post('/tender/:id/pay/:order/file/delete', sessionAuth, tenderCheck, phasePayCheck, 'payController.deleteFile');
     // 合同支付审批
-    app.post('/tender/:id/pay/:sorder/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.addAudit');
-    app.post('/tender/:id/pay/:sorder/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.deleteAudit');
-    app.post('/tender/:id/pay/:sorder/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditStart');
-    app.post('/tender/:id/pay/:sorder/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheck');
-    app.post('/tender/:id/pay/:sorder/audit/checkAgain', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheckAgain');
-    app.post('/tender/:id/pay/:sorder/audit/checkCancel', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheckCancel');
+    app.post('/tender/:id/pay/:order/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.addAudit');
+    app.post('/tender/:id/pay/:order/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.deleteAudit');
+    app.post('/tender/:id/pay/:order/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditStart');
+    app.post('/tender/:id/pay/:order/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheck');
+    app.post('/tender/:id/pay/:order/audit/checkAgain', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheckAgain');
+    app.post('/tender/:id/pay/:order/audit/checkCancel', sessionAuth, tenderCheck, uncheckTenderCheck, phasePayCheck, 'payController.auditCheckCancel');
 
     // 变更概况
     app.get('/tender/:id/measure/stage/:order/change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.change');

+ 93 - 12
app/service/phase_pay.js

@@ -8,7 +8,7 @@
  * @version
  */
 
-const audit = require('../const/audit').phasePay;
+const audit = require('../const/audit').common;
 const projectLogConst = require('../const/project_log');
 const shenpiConst = require('../const/shenpi');
 const calcBase = [
@@ -268,8 +268,10 @@ module.exports = app => {
                 const result = await transaction.insert(this.tableName, data);
                 if (result.affectedRows !== 1) throw '新增合同支付失败';
 
-                await this.ctx.service.phasePayDetail.initPhaseData(transaction, data);
+                await this.ctx.service.phasePayDetail.initPhaseData(transaction, data, prePhase);
+                await this.ctx.service.phasePayAudit.copyPreAuditors(transaction, prePhase, data);
                 await transaction.commit();
+                this.analysisPhasePay(data);
                 return data;
             } catch(err) {
                 await transaction.rollback();
@@ -282,11 +284,15 @@ module.exports = app => {
             try {
                 await conn.delete(this.tableName, { id });
                 await conn.delete(this.ctx.service.phasePayDetail.tableName, { phase_id: id });
-                // todo 不确定是否真删除,是否需要防止用户找回附件 ?
-                // await conn.delete(this.ctx.service.phasePayAtt.tableName, { phase_id: id });
+                const files = await this.ctx.service.phasePayFile.getFiles({ where: { phase_id: id} });
+                for (const f of files) {
+                    this.ctx.app.fujianOss.delete(f.filepath);
+                }
+                await conn.delete(this.ctx.service.phasePayFile.tableName, { phase_id: id });
                 await conn.delete(this.ctx.service.phasePayAudit.tableName, { phase_id: id });
                 // 记录删除日志
                 await this.ctx.service.projectLog.addProjectLog(conn, projectLogConst.type.phasePay, projectLogConst.status.delete, `第${info.phase_order}期`);
+                await conn.commit();
             } catch (err) {
                 await conn.rollback();
                 throw err;
@@ -340,16 +346,90 @@ module.exports = app => {
 
         async loadUser(phasePay) {
             phasePay.user = await this.ctx.service.projectAccount.getAccountInfoById(phasePay.create_user_id);
-            phasePay.auditors = await this.ctx.service.phasePayAudit.getAuditors(phasePay.id, phasePay.curTimes);
+            phasePay.auditors = await this.ctx.service.phasePayAudit.getAuditors(phasePay.id, phasePay.curTimes || phasePay.audit_times);
+            phasePay.auditorIds = this._.map(phasePay.auditors, 'audit_id');
             phasePay.curAuditors = phasePay.auditors.filter(x => { return x.audit_status === audit.status.checking; });
             phasePay.curAuditorIds = phasePay.curAuditors.map(x => { return x.audit_id; });
-            phasePay.flowAuditors = phasePay.curAuditors.length === 0 ? [] : phasePay.auditors.filter(x => { return x.audit_sort === phasePay.curAuditors[0].audit_sort; });
+            phasePay.flowAuditors = phasePay.curAuditors.length === 0 ? [] : phasePay.auditors.filter(x => { return x.active_order === phasePay.curAuditors[0].active_order; });
             phasePay.flowAuditorIds = phasePay.curAuditors.map(x => { return x.audit_id; });
-            phasePay.nextAuditors = phasePay.curAuditors.length > 0 ? phasePay.auditors.filter(x => { return x.audit_sort === phasePay.curAuditors[0].audit_sort + 1; }) : [];
+            phasePay.nextAuditors = phasePay.curAuditors.length > 0 ? phasePay.auditors.filter(x => { return x.active_order === phasePay.curAuditors[0].active_order + 1; }) : [];
             phasePay.nextAuditorIds = this._.map(phasePay.nextAuditors, 'audit_id');
             phasePay.auditorGroups = this.ctx.helper.groupAuditors(phasePay.auditors, 'active_order');
             phasePay.userGroups = this.ctx.helper.groupAuditorsUniq(phasePay.auditorGroups);
             phasePay.finalAuditorIds = phasePay.userGroups.length > 1 ? phasePay.userGroups[phasePay.userGroups.length - 1].map(x => { return x.audit_id; }) : [];
+            phasePay.userIds = phasePay.audit_status === audit.status.uncheck // 当前流程下全部参与人id
+                ? [phasePay.user_id]
+                : phasePay.auditorIds;
+        }
+        async loadAuditViewData(phasePay) {
+            if (!phasePay.user) phasePay.user = await this.ctx.service.projectAccount.getAccountInfoById(phasePay.user_id);
+            const auditTimes = phasePay.audit_status === audit.status.checkNo ? phasePay.audit_times - 1 : phasePay.audit_times;
+            phasePay.auditHistory = await this.ctx.service.phasePayAudit.getAuditorHistory(phasePay.id, auditTimes);
+            // 获取审批流程中左边列表
+            if (phasePay.audit_status === audit.status.checkNo && phasePay.create_user_id !== this.ctx.session.sessionUser.accountId) {
+                const auditors = await this.ctx.service.phasePayAudit.getAuditors(phasePay.id, phasePay.audit_times - 1); // 全部参与的审批人
+                const auditorGroups = this.ctx.helper.groupAuditors(auditors);
+                phasePay.hisUserGroup = this.ctx.helper.groupAuditorsUniq(auditorGroups);
+            } else {
+                phasePay.hisUserGroup = phasePay.userGroups;
+            }
+        }
+        /**
+         * cancancel = 0 不可撤回
+         * cancancel = 1 原报撤回
+         * cancancel = 2 审批人撤回 审批通过
+         * cancancel = 3 审批人撤回 审批退回上一人
+         * cancancel = 4 审批人撤回 退回原报
+         * cancancel = 5 会签未全部审批通过时,审批人撤回 审批通过
+         *
+         * @param phasePay
+         * @returns {Promise<void>}
+         */
+        async doCheckCanCancel(phasePay) {
+            // 默认不可撤回
+            phasePay.cancancel = 0;
+            // 获取当前审批人的上一个审批人,判断是否是当前登录人,并赋予撤回功能,(当审批人存在有审批过时,上一人不允许再撤回)
+            const status = audit.status;
+            if (phasePay.audit_status === status.checked || phasePay.audit_status === status.uncheck) return;
+
+            const accountId = this.ctx.session.sessionUser.accountId;
+            if (phasePay.audit_status !== status.checkNo) {
+                // 找出当前操作人上一个审批人,包括审批完成的和退回上一个审批人的,同时当前操作人为第一人时,就是则为原报
+                if (phasePay.flowAuditors.find(x => { return x.audit_status !== status.checking}) && phasePay.flowAuditorIds.indexOf(accountId) < 0) return; // 当前流程存在审批人审批通过时,不可撤回
+                if (phasePay.curAuditorIds.indexOf(accountId) < 0 && phasePay.flowAuditorIds.indexOf(accountId) >= 0) {
+                    phasePay.cancancel = 5; // 会签未全部审批通过时,审批人撤回审批通过
+                    return;
+                }
+
+                const preAuditors = phasePay.curAuditors[0] && phasePay.curAuditors[0].active_order !== 1 ? phasePay.auditors.filter(x => { return x.active_order === phasePay.curAuditors[0].active_order - 1; }) : [];
+                const preAuditorCheckAgain = preAuditors.find(pa => { return pa.audit_status === status.checkAgain; });
+                const preAuditorCheckCancel = preAuditors.find(pa => { return pa.audit_status === status.checkCancel; });
+                const preAuditorHasOld = preAuditors.find(pa => { return pa.is_old === 1; });
+                const preAuditorIds = (preAuditorCheckAgain ? [] : preAuditors.map(x => { return x.audit_id })); // 重审不可撤回
+                if ((this._.isEqual(phasePay.flowAuditorIds, preAuditorIds) && preAuditorCheckCancel) || preAuditorHasOld) {
+                    return; // 不可以多次撤回
+                }
+
+                const preAuditChecked = preAuditors.find(pa => { return pa.audit_status === status.checked && pa.audit_id === accountId; });
+                const preAuditCheckNoPre = preAuditors.find(pa => { return pa.audit_status === status.checkNoPre && pa.audit_id === accountId; });
+                if (preAuditorIds.indexOf(accountId) >= 0) {
+                    if (preAuditChecked) {
+                        phasePay.cancancel = 2;// 审批人撤回审批通过
+                    } else if (preAuditCheckNoPre) {
+                        phasePay.cancancel = 3;// 审批人撤回审批退回上一人
+                    }
+                    phasePay.preAuditors = preAuditors;
+                } else if (preAuditors.length === 0 && accountId === phasePay.create_user_id) {
+                    phasePay.cancancel = 1;// 原报撤回
+                }
+            } else {
+                const lastAuditors = await this.ctx.service.phasePayAudit.getAuditors(phasePay.id, phasePay.audit_times - 1);
+                const onAuditor = this._.findLast(lastAuditors, { audit_status: status.checkNo });
+                if (onAuditor.audit_id === accountId) {
+                    phasePay.cancancel = 4;// 审批人撤回退回原报
+                    phasePay.preAuditors = lastAuditors.filter(x => { return x.active_order === onAuditor.active_order });
+                }
+            }
         }
         async doCheckPhase(phasePay) {
             const accountId = this.ctx.session.sessionUser.accountId;
@@ -371,19 +451,20 @@ module.exports = app => {
                     phasePay.curSort = 0;
                 } else {
                     const checkNoAudit = await this.service.phasePayAudit.getDataByCondition({
-                        phase_id: phasePay.id, audit_times: phasePay.audit_times - 1, status: audit.status.checkNo,
+                        phase_id: phasePay.id, audit_times: phasePay.audit_times - 1, audit_status: audit.status.checkNo,
                     });
-                    phasePay.curSort = checkNoAudit.audit_sort;
+                    phasePay.curSort = checkNoAudit.active_order;
                 }
             } else if (phasePay.audit_status === audit.status.checked) {
                 phasePay.readOnly = true;
                 phasePay.curSort = phasePay.audit_max_sort;
             } else {
                 // 会签,会签人部分审批通过时,只读,但是curSort需按原来的取值
-                phasePay.curSort = phasePay.flowAuditorIds.indexOf(accountId) >= 0 ? phasePay.curAuditors[0].audit_sort : phasePay.curAuditors[0].audit_sort - 1;
-                phasePay.readOnly = !_.isEqual(stage.flowAuditorIds, stage.curAuditorIds);
-                phasePay.canCheck = phasePay.readOnly && stage.curAuditorIds.indexOf(accountId) > 0;
+                phasePay.curSort = phasePay.flowAuditorIds.indexOf(accountId) >= 0 ? phasePay.curAuditors[0].active_order : phasePay.curAuditors[0].active_order - 1;
+                phasePay.readOnly = phasePay.curAuditorIds.indexOf(accountId) < 0;
+                phasePay.canCheck = phasePay.readOnly && phasePay.curAuditorIds.indexOf(accountId) > 0;
             }
+            await this.doCheckCanCancel(phasePay);
         }
         async checkShenpi(phasePay) {
             const status = audit.status;

+ 62 - 33
app/service/phase_pay_audit.js

@@ -30,7 +30,7 @@ module.exports = app => {
         // ***** 查询审批人相关
         // 获取全部参与人
         async getAuditors(phaseId, auditTimes) {
-            return await this.getAllDataByCondition({ where: { phase_id: phaseId, audit_times: auditTimes } }); // 全部参与的审批人
+            return await this.getAllDataByCondition({ where: { phase_id: phaseId, audit_times: auditTimes }, orders: [['active_order', 'asc']] }); // 全部参与的审批人
         }
         // 获取全部参与人 分组
         async getAuditorGroup(phaseId, auditTimes) {
@@ -141,8 +141,8 @@ module.exports = app => {
          */
         async _syncAuditOrder(transaction, phaseId, auditOrder, auditTimes, selfOperate = '-') {
             const sql = `Update ${this.tableName} SET audit_order = audit_order${selfOperate}1, active_order = active_order${selfOperate}1 
-                            WHERE master_id = ? and master_type = ? and audit_times = ? and active_order >= ?`;
-            return await transaction.query(sql, [phaseId, this.masterType, times, order]);
+                            WHERE phase_id = ? and audit_times = ? and active_order >= ?`;
+            return await transaction.query(sql, [phaseId, auditTimes, auditOrder]);
         }
         /**
          * 新增审核人
@@ -329,7 +329,8 @@ module.exports = app => {
             try {
                 const audit_time = new Date();
                 // 更新原报数据
-                await transaction.update(this.tableName, { audit_status: auditConst.phasePay.status.checked, audit_time }, { where: { phase_id: phasePay.id, audit_times: phasePay.audit_times, audit_order: 0 } });
+                await transaction.update(this.tableName, { audit_status: auditConst.phasePay.status.checked, audit_time },
+                    { where: { phase_id: phasePay.id, audit_times: phasePay.audit_times, audit_order: 0 } });
                 // 更新下一审批人数据
                 const updateData = audits.map(x => { return { id: x.id, audit_status: auditConst.phasePay.status.checking } });
                 await transaction.updateRows(this.tableName, updateData);
@@ -352,9 +353,9 @@ module.exports = app => {
                     tips: wxConst.tips.check,
                     code: this.ctx.session.sessionProject.code,
                 };
-                await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
+                await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
                 for (const a of audits) {
-                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
+                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.PAY, {
                         pid: this.ctx.session.sessionProject.id,
                         tid: phasePay.tid,
                         uid: a.audit_id,
@@ -402,7 +403,8 @@ module.exports = app => {
                     audit_time: time,
                 });
                 await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, selfAudit.id);
-                let auditStatus;
+                // 计算合同支付
+                const paySum = await this.ctx.service.phasePayDetail.calculateSave(phasePay, transaction);
                 if (phasePay.curAuditors.length === 1 || selfAudit.audit_type === auditType.key.or) {
                     // 或签更新他人审批状态
                     if (selfAudit.audit_type === auditType.key.or) {
@@ -420,11 +422,17 @@ module.exports = app => {
                         if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
                     }
                     // 无下一审核人表示,审核结束
-                    auditStatus = nextAudits.length > 0 ? auditConst.phasePay.status.checking : auditConst.phasePay.status.checked;
                     if (nextAudits.length > 0) {
                         // 流程至下一审批人
                         const updateData = nextAudits.map(x => { return { id: x.id, audit_status: auditConst.phasePay.status.checking }; });
                         await transaction.updateRows(this.tableName, updateData);
+                        // 计算合同支付
+                        const paySum = await this.ctx.service.phasePayDetail.calculateSave(phasePay, transaction);
+                        await transaction.update(this.ctx.service.phasePay.tableName, {
+                            id: phasePay.id, audit_max_sort: selfAudit.active_order + 1, audit_status: auditConst.phasePay.status.checking, ...paySum
+                        });
+                        // 拷贝新流程合同支付
+                        await this.ctx.service.phasePayDetail.initPhaseDataByAudit(transaction, phasePay, phasePay.audit_times, selfAudit.active_order + 1);
 
                         // todo 添加短信通知-需要审批提醒功能
                         const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.tender.id + '/phasePay/' + phasePay.phase_order);
@@ -437,9 +445,9 @@ module.exports = app => {
                             tips: wxConst.tips.check,
                             code: this.ctx.session.sessionProject.code,
                         };
-                        await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
+                        await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
                         for (const a of nextAudits) {
-                            await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
+                            await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.PAY, {
                                 pid: this.ctx.session.sessionProject.id,
                                 tid: this.ctx.tender.id,
                                 uid: a.audit_id,
@@ -451,6 +459,12 @@ module.exports = app => {
                             });
                         }
                     } else {
+                        const final_auditor_str = (selfAudit.audit_type === auditType.key.common)
+                            ? `${selfAudit.name}${(selfAudit.role ? '-' + selfAudit.role : '')}`
+                            : ctx.helper.transFormToChinese(selfAudit.audit_order) + '审';
+                        await transaction.update(this.ctx.service.phasePay.tableName, {
+                            id: phasePay.id, audit_end_time: time, audit_status: auditConst.phasePay.status.checked, final_auditor_str, ...paySum
+                        });
                         // 添加短信通知-审批通过提醒功能
                         const users = this._.uniq(phasePay.userIds);
                         // 微信模板通知
@@ -462,17 +476,16 @@ module.exports = app => {
                             tips: wxConst.tips.success,
                             code: this.ctx.session.sessionProject.code,
                         };
-                        await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.phasePay, wechatData);
+                        await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.result.toString(), wxConst.template.phasePay, wechatData);
                         // todo 审批通过 - 检查三方特殊推送
                         // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.checked);
                     }
                     // todo 上报/审批 - 检查三方特殊推送
                     // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.flow);
                 } else {
-                    auditStatus = auditConst.phasePay.status.checking;
+                    // 同步 期信息
+                    await transaction.update(this.ctx.service.phasePay.tableName, { id: phasePay.id, audit_status: auditConst.phasePay.status.checking, ...paySum });
                 }
-                // 同步 期信息
-                await transaction.update(this.ctx.service.phasePay.tableName, { id: phasePay.id, audit_status: auditStatus });
                 await transaction.commit();
             } catch (err) {
                 await transaction.rollback();
@@ -518,9 +531,12 @@ module.exports = app => {
                 await transaction.updateRows(this.tableName, updateData);
                 await this.ctx.service.noticeAgain.stopNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
                 // 更新 期信息
+                const paySum = await this.ctx.service.phasePayDetail.calculateSave(phasePay, transaction);
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_status: auditConst.phasePay.status.checkNo, audit_times: phasePay.audit_times + 1,
+                    id: phasePay.id, audit_status: auditConst.phasePay.status.checkNo, audit_times: phasePay.audit_times + 1, audit_max_sort: 0, ...paySum
                 });
+                // 拷贝新流程合同支付
+                await this.ctx.service.phasePayDetail.initPhaseDataByAudit(transaction, phasePay, phasePay.audit_times + 1, 0);
                 // 拷贝新一次审核流程列表
                 await transaction.insert(this.tableName, newAuditors);
 
@@ -535,7 +551,7 @@ module.exports = app => {
                     tips: wxConst.tips.back,
                     code: this.ctx.session.sessionProject.code,
                 };
-                await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.phasePay, wechatData);
+                await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.result.toString(), wxConst.template.phasePay, wechatData);
                 // todo 上报/审批 - 检查三方特殊推送
                 // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.flow);
                 await transaction.commit();
@@ -614,12 +630,14 @@ module.exports = app => {
                 const preAuditorIds = preAuditors.map(x => { return x.audit_id; });
 
                 // 同步 期信息
+                const paySum = await this.ctx.service.phasePayDetail.calculateSave(phasePay, transaction);
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_status: auditConst.phasePay.status.checkNoPre,
+                    id: phasePay.id, audit_max_sort: selfAudit.active_order + 1, ...paySum,
                 });
+                // 拷贝新流程合同支付
+                await this.ctx.service.phasePayDetail.initPhaseDataByAudit(transaction, phasePay, phasePay.audit_times, selfAudit.active_order + 1);
                 const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + phasePay.tid + '/phasePay/' + phasePay.phase_order);
-                const users = this._.map(phasePay.auditAssists.filter(x => {return preAuditorIds.indexOf(x.user_id) >= 0 }), 'ass_user_id');
-                users.push(...preAuditorIds);
+                const users = preAuditorIds;
                 // 微信模板通知
                 const wechatData = {
                     wap_url: shenpiUrl,
@@ -628,9 +646,9 @@ module.exports = app => {
                     tips: wxConst.tips.check,
                     code: this.ctx.session.sessionProject.code,
                 };
-                await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
+                await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
                 for (const a of newAuditors) {
-                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
+                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.PAY, {
                         pid: this.ctx.session.sessionProject.id,
                         tid: phasePay.tid,
                         uid: a.audit_id,
@@ -706,8 +724,10 @@ module.exports = app => {
 
                 // 同步 期信息
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_status: auditConst.phasePay.status.checking,
+                    id: phasePay.id, audit_status: auditConst.phasePay.status.checking, audit_end_time: null, final_auditor_str: '', audit_max_sort: finalAudit.active_order + 2,
                 });
+                // 拷贝新流程合同支付
+                await this.ctx.service.phasePayDetail.initPhaseDataByAudit(transaction, phasePay, phasePay.audit_times + 1, finalAudit.active_order + 2);
 
                 // todo 添加短信通知-需要审批提醒功能
                 const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + phasePay.tid + '/phasePay/' + phasePay.phase_order);
@@ -721,9 +741,9 @@ module.exports = app => {
                     tips: wxConst.tips.check,
                     code: this.ctx.session.sessionProject.code,
                 };
-                await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
+                await this.ctx.helper.sendWechat(users, smsTypeConst.const.PAY, smsTypeConst.judge.approval.toString(), wxConst.template.phasePay, wechatData);
                 for (const a of checkingAuditors) {
-                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.JS, {
+                    await this.ctx.service.noticeAgain.addNoticeAgain(transaction, smsTypeConst.const.PAY, {
                         pid: this.ctx.session.sessionProject.id,
                         tid: phasePay.tid,
                         uid: a.audit_id,
@@ -746,7 +766,7 @@ module.exports = app => {
          * 原报撤回,直接改动审批人状态
          * 如果存在审批人数据,将其改为原报流程数据,但保留原提交人
          *
-         * 一审 1 A checking  ->  A uncheck status改   pay/jl:删0(jl为增量数据,只删重复部分) 1->0 删1
+         * 一审 1 A checking  ->  A uncheck status改   pay:1->0 删1
          * ...
          *
          * @param phasePay
@@ -754,7 +774,6 @@ module.exports = app => {
          * @private
          */
         async _userCheckCancel(phasePay) {
-
             const transaction = await this.db.beginTransaction();
             try {
                 // 整理当前流程审核人状态更新
@@ -768,9 +787,14 @@ module.exports = app => {
                 await transaction.updateRows(this.tableName, updateData);
                 await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(updateData, 'id'));
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_times: phasePay.audit_times,
+                    id: phasePay.id, audit_times: phasePay.audit_times, audit_max_sort: 0,
                     audit_status: phasePay.audit_times === 1 ? auditConst.phasePay.status.uncheck : auditConst.phasePay.status.checkNo,
                 });
+                await transaction.delete(this.ctx.service.phasePayDetail.tableName,
+                    { phase_id: phasePay.id, audit_times: phasePay.audit_times, audit_sort: 0});
+                await transaction.update(this.ctx.service.phasePayDetail.tableName,
+                    { audit_sort: 0, master_id: phasePay.id + '-' + phasePay.audit_times + '-0' },
+                    { where: { phase_id: phasePay.id, audit_times: phasePay.audit_times, audit_sort: 1 } });
 
                 // todo 上报/审批 - 检查三方特殊推送
                 // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.flow);
@@ -811,7 +835,7 @@ module.exports = app => {
                         tid: phasePay.tid, phase_id: phasePay.id, audit_id: x.audit_id,
                         audit_times: x.audit_times, active_order: x.active_order + 1,
                         audit_type: x.audit_type, audit_order: x.audit_order,
-                        status: x.audit_id === selfAuditor.audit_id ? auditConst.phasePay.status.checkCancel : auditConst.phasePay.status.checkSkip,
+                        audit_status: x.audit_id === selfAuditor.audit_id ? auditConst.phasePay.status.checkCancel : auditConst.phasePay.status.checkSkip,
                         audit_time: time, opinion: '',
                         name: x.name, company: x.company, role: x.role, mobile: x.mobile,
                     });
@@ -821,7 +845,7 @@ module.exports = app => {
                         tid: phasePay.tid, phase_id: phasePay.id, audit_id: x.audit_id,
                         audit_times: x.audit_times, active_order: x.active_order + 2,
                         audit_type: x.audit_type, audit_order: x.audit_order,
-                        status: auditConst.phasePay.status.checking,
+                        audit_status: auditConst.phasePay.status.checking,
                         audit_time: time, opinion: '',
                         name: x.name, company: x.company, role: x.role, mobile: x.mobile,
                     });
@@ -829,8 +853,9 @@ module.exports = app => {
                 await transaction.insert(this.tableName, [...checkCancelAuditors, ...checkingAuditors]);
                 // 当前审批人变成待审批
                 await transaction.updateRows(this.tableName, phasePay.curAuditors.map(x => { return {
-                    id: x.id, audit_time: null, status: auditConst.phasePay.status.uncheck, active_order: x.active_order + 2
+                    id: x.id, audit_time: null, audit_status: auditConst.phasePay.status.uncheck, active_order: x.active_order + 2
                 }}));
+                await this.ctx.service.phasePayDetail.initPhaseDataByAuditCancel(transaction, phasePay, phasePay.audit_times, selfAuditor.active_order + 1, phasePay.audit_times, selfAuditor.active_order + 2);
                 await this.ctx.service.noticeAgain.deleteNoticeAgain(transaction, this.tableName, this._.map(phasePay.curAuditors, 'id'));
                 // 同步 期信息
                 await transaction.update(this.ctx.service.phasePay.tableName, {
@@ -887,8 +912,9 @@ module.exports = app => {
 
                 // 同步 期信息
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_times: phasePay.audit_times, status: auditConst.phasePay.status.checking,
+                    id: phasePay.id, audit_times: phasePay.audit_times, audit_status: auditConst.phasePay.status.checking,
                 });
+                await this.ctx.service.phasePayDetail.initPhaseDataByAuditCancel(transaction, phasePay, phasePay.audit_times, selfAuditor.active_order + 1, phasePay.audit_times, selfAuditor.active_order + 2);
                 // todo 上报/审批 - 检查三方特殊推送
                 // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.flow);
                 await transaction.commit();
@@ -944,8 +970,11 @@ module.exports = app => {
 
                 // 计算并合同支付最终数据
                 await transaction.update(this.ctx.service.phasePay.tableName, {
-                    id: phasePay.id, audit_times: phasePay.audit_times - 1, status: auditConst.phasePay.status.checking,
+                    id: phasePay.id, audit_times: phasePay.audit_times - 1, audit_status: auditConst.phasePay.status.checking,
                 });
+                await transaction.update(this.ctx.service.phasePayDetail.tableName,
+                    { audit_times: selfAuditor.audit_times, audit_sort: selfAuditor.active_order + 2, master_id: `${phasePay.id}-${selfAuditor.audit_times}-${selfAuditor.active_order + 2}` },
+                    { where: { phase_id: phasePay.id, audit_times: phasePay.audit_times, audit_sort: 0 } });
                 // todo 上报/审批 - 检查三方特殊推送
                 // await this.ctx.service.specMsg.addPhasePayMsg(transaction, this.ctx.session.sessionProject.id, phasePay, pushOperate.phasePay.flow);
                 await transaction.commit();
@@ -969,7 +998,7 @@ module.exports = app => {
             const transaction = await this.db.beginTransaction();
             try {
                 await transaction.update(this.tableName, {
-                    id: selfAuditor.id, status: auditConst.phasePay.status.checking, opinion: '', audit_time: null,
+                    id: selfAuditor.id, audit_status: auditConst.phasePay.status.checking, opinion: '', audit_time: null,
                 });
                 await transaction.commit();
             } catch(err) {

+ 28 - 14
app/service/phase_pay_detail.js

@@ -12,14 +12,14 @@ const payType = {
     bqsf: 'bqsf', bqyf: 'bqyf', gcjl: 'gcjl', qtfk: 'qtfk', qtkk: 'qtkk'
 };
 const defaultPays = [
-    { tree_id: 1, tree_pid: -1, tree_level: 1, tree_order: 1, tree_is_leaf: 1, tree_full_path: '1', pay_type: 'bqyf', is_minus: 0, is_fixed: 1, name: '本期应付' },
-    { tree_id: 2, tree_pid: -1, tree_level: 1, tree_order: 2, tree_is_leaf: 1, tree_full_path: '2', pay_type: 'bqsf', is_minus: 0, is_fixed: 1, name: '本期实付' },
-    { tree_id: 3, tree_pid: -1, tree_level: 1, tree_order: 3, tree_is_leaf: 0, tree_full_path: '3', pay_type: 'gcjl', is_minus: 0, is_fixed: 1, name: '工程计量款' },
-    { tree_id: 4, tree_pid: -1, tree_level: 1, tree_order: 4, tree_is_leaf: 0, tree_full_path: '4', pay_type: 'qtfk', is_minus: 0, is_fixed: 1, name: '其他付款项' },
-    { tree_id: 5, tree_pid: -1, tree_level: 1, tree_order: 5, tree_is_leaf: 0, tree_full_path: '5', pay_type: 'qtkk', is_minus: 1, is_fixed: 1, name: '其他扣款项' },
+    { tree_id: 1, tree_pid: -1, tree_level: 1, tree_order: 1, tree_is_leaf: 1, tree_full_path: '1', pay_type: 'bqyf', is_minus: 0, is_fixed: 1, name: '本期应付', expr: '' },
+    { tree_id: 2, tree_pid: -1, tree_level: 1, tree_order: 2, tree_is_leaf: 1, tree_full_path: '2', pay_type: 'bqsf', is_minus: 0, is_fixed: 1, name: '本期实付', expr: '' },
+    { tree_id: 3, tree_pid: -1, tree_level: 1, tree_order: 3, tree_is_leaf: 0, tree_full_path: '3', pay_type: 'gcjl', is_minus: 0, is_fixed: 1, name: '工程计量款', expr: '' },
+    { tree_id: 4, tree_pid: -1, tree_level: 1, tree_order: 4, tree_is_leaf: 0, tree_full_path: '4', pay_type: 'qtfk', is_minus: 0, is_fixed: 1, name: '其他付款项', expr: '' },
+    { tree_id: 5, tree_pid: -1, tree_level: 1, tree_order: 5, tree_is_leaf: 0, tree_full_path: '5', pay_type: 'qtkk', is_minus: 1, is_fixed: 1, name: '其他扣款项', expr: '' },
     { tree_id: 6, tree_pid: 3, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '3-6', pay_type: '', is_minus: 0, is_fixed: 0, name: '本期完成计量', expr: 'bqwc' },
-    { tree_id: 7, tree_pid: 4, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '4-7', pay_type: '', is_minus: 0, is_fixed: 0, name: '新增付款项' },
-    { tree_id: 8, tree_pid: 5, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '5-8', pay_type: '', is_minus: 1, is_fixed: 0, name: '新增扣款项' },
+    { tree_id: 7, tree_pid: 4, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '4-7', pay_type: '', is_minus: 0, is_fixed: 0, name: '新增付款项', expr: '' },
+    { tree_id: 8, tree_pid: 5, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '5-8', pay_type: '', is_minus: 1, is_fixed: 0, name: '新增扣款项', expr: '' },
 ];
 const TreeService = require('../base/base_tree_service');
 const Ledger = require('../lib/ledger');
@@ -232,7 +232,7 @@ class PayCalculator {
     _calculateYf(yf, pays) {
         yf.tp = 0;
         for (const p of pays) {
-            if (p.payType || !p.is_gather || !p.tree_is_leaf) continue;
+            if (p.pay_type || !p.is_gather || !p.tree_is_leaf) continue;
             yf.tp = !p.is_minus ? this.ctx.helper.add(yf.tp, p.tp) : this.ctx.helper.sub(yf.tp, p.tp);
         }
         const bqyf = this.bases.find(function (x) {return x.code === 'bqyf'});
@@ -345,7 +345,8 @@ class PhasePayDetail extends TreeService {
         const insertData = [];
         for (const dp of defaultPays) {
             insertData.push({
-                tid: phasePay.tid, phase_id: phasePay.id, create_user_id: user_id, update_user_id: user_id,
+                tid: phasePay.tid, phase_id: phasePay.id, create_phase_id: phasePay.id, master_id: phasePay.id + '-1-0',
+                create_user_id: user_id, update_user_id: user_id,
                 uuid: this.uuid.v4(), ...dp,
             });
         }
@@ -358,6 +359,8 @@ class PhasePayDetail extends TreeService {
         });
         for (const pd of preData) {
             delete pd.id;
+            pd.phase_id = phasePay.id;
+            pd.master_id = phasePay.id + '-1-0';
             pd.audit_times = 1;
             pd.audit_sort = 0;
         }
@@ -365,7 +368,7 @@ class PhasePayDetail extends TreeService {
     }
 
     async initPhaseDataByAudit(conn, phasePay, newTimes, newSort) {
-        const preData = await transaction.getAllDataByCondition({ where: { master_id: this.getMasterKey(phasePay)}});
+        const preData = await conn.select(this.tableName, { where: { master_id: this.getMasterKey(phasePay)}});
         for (const pd of preData) {
             delete pd.id;
             pd.master_id = `${phasePay.id}-${newTimes}-${newSort}`;
@@ -375,9 +378,20 @@ class PhasePayDetail extends TreeService {
         await conn.insert(this.tableName, preData);
     }
 
-    async initPhaseData(conn, phasePay){
+    async initPhaseDataByAuditCancel(conn, phasePay, oldTimes, oldSort, newTimes, newSort) {
+        const masterId = `${phasePay.id}-${oldTimes}-${oldSort}`;
+        const preData = await conn.select(this.tableName, { where: { master_id: masterId } });
+        for (const pd of preData) {
+            delete pd.id;
+            pd.master_id = `${phasePay.id}-${newTimes}-${newSort}`;
+            pd.audit_times = newTimes;
+            pd.audit_sort = newSort;
+        }
+        await conn.insert(this.tableName, preData);
+    }
+
+    async initPhaseData(conn, phasePay, prePhase){
         if (!conn) throw '内部错误';
-        const prePhase = await this.ctx.service.phasePay.getPhasePayByOrder(phasePay.tid, phasePay.phase_order - 1);
         if (prePhase) {
             await this.initPhaseDataByPre(conn, phasePay, prePhase);
         } else {
@@ -422,7 +436,7 @@ class PhasePayDetail extends TreeService {
         const updateData = calcResult.filter(x => { return x.calcUpdate; }).map(x => {
             return { id: x.id, tp: x.tp, start_tp: x.start_tp, range_tp: x.range_tp, end_tp: x.end_tp };
         });
-        if (updateData.length === 0) return false;
+        if (updateData.length === 0) return this.getPaySum(calcResult);
 
         if (transaction) {
             await transaction.updateRows(this.tableName, updateData);
@@ -447,7 +461,7 @@ class PhasePayDetail extends TreeService {
     }
 
     async addChild(phasePay, select, count = 1) {
-        if (select.payType === payType.bqsf || select.payType === payType.bqyf) throw '不可新增子项';
+        if (select.pay_type === payType.bqsf || select.pay_type === payType.bqyf) throw '不可新增子项';
         if (select.tree_level >= 2) throw '不可新增子项';
 
         const masterId = this.getMasterKey(phasePay);

+ 1 - 1
app/service/settle_audit.js

@@ -30,7 +30,7 @@ module.exports = app => {
         // ***** 查询审批人相关
         // 获取全部参与人
         async getAuditors(settleId, auditTimes) {
-            return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes } }); // 全部参与的审批人
+            return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes }, orders: [['active_order', 'asc']] }); // 全部参与的审批人
         }
         // 获取全部参与人 分组
         async getAuditorGroup(settleId, auditTimes) {

+ 6 - 6
app/view/phase_pay/audit_modal.ejs

@@ -188,7 +188,7 @@
                                             <% if (group.audit_order === 0) { %>
                                             <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                             <% } else if (group.audit_status !== auditConst.status.uncheck) { %>
-                                            <span class="pull-right <%- auditConst.statusClass[group.audit_status] %>"><%- auditConst.statusString[group.audit_status] %></span>
+                                            <span class="pull-right <%- auditConst.info[group.audit_status].class %>"><%- auditConst.info[group.audit_status].title %></span>
                                             <% } %>
                                         </div>
                                         <div class="card">
@@ -315,7 +315,7 @@
                                             <% if (group.audit_order === 0) { %>
                                             <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                             <% } else if (group.audit_status !== auditConst.status.uncheck) { %>
-                                            <span class="pull-right <%- auditConst.statusClass[group.audit_status] %>"><%- auditConst.statusString[group.audit_status] %></span>
+                                            <span class="pull-right <%- auditConst.info[group.audit_status].class %>"><%- auditConst.info[group.audit_status].title %></span>
                                             <% } %>
                                         </div>
                                         <div class="card">
@@ -446,7 +446,7 @@
                                             <% if (group.audit_order === 0) { %>
                                             <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                             <% } else if (group.audit_status !== auditConst.status.uncheck) { %>
-                                            <span class="pull-right <%- auditConst.statusClass[group.audit_status] %>"><%- auditConst.statusString[group.audit_status] %></span>
+                                            <span class="pull-right <%- auditConst.info[group.audit_status].class %>"><%- auditConst.info[group.audit_status].title %></span>
                                             <% } %>
                                         </div>
                                         <div class="card">
@@ -511,7 +511,7 @@
     </div>
 </div>
 <% } %>
-<% if (ctx.phasePay && ctx.phasePay.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0 && ctx.phasePay.audit_status === auditConst.status.checked && ctx.phasePay.phase_order === ctx.phasePay.highOrder) { %>
+<% if (ctx.phasePay && ctx.phasePay.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0 && ctx.phasePay.audit_status === auditConst.status.checked && ctx.phasePay.isLatest) { %>
 <% if (!authMobile && ctx.session.sessionUser.loginStatus === 0) { %>
 <!--终审重新审批-->
 <div class="modal fade" id="sp-down-back" data-backdrop="static">
@@ -565,7 +565,7 @@
 </div>
 <% } %>
 <% } %>
-<% if (ctx.phasePay && ctx.phasePay.create_user_id === ctx.session.sessionUser.accountId && ctx.phasePay.phase_order === ctx.phasePay.highOrder && (ctx.phasePay.audit_status === auditConst.status.checkNo || ctx.phasePay.audit_status === auditConst.status.uncheck)) { %>
+<% if (ctx.phasePay && ctx.phasePay.create_user_id === ctx.session.sessionUser.accountId && ctx.phasePay.isLatest && (ctx.phasePay.audit_status === auditConst.status.checkNo || ctx.phasePay.audit_status === auditConst.status.uncheck)) { %>
 <div class="modal fade" id="del-qi" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <form class="modal-content" action='/tender/<%= ctx.tender.id %>/pay/delete' method="post">
@@ -652,7 +652,7 @@
                                     <% } %>
                                 </td>
                                 <td></span> <%- auditor.name %> <small class="text-muted"><%- auditor.role %></small></td>
-                                <td style="text-align: center"><span class="<%- auditConst.auditStringClass[auditor.audit_status] %>"><%- auditor.audit_status !== auditConst.status.uncheck ? auditConst.auditString[auditor.audit_status] : '待审批'  %></span></td>
+                                <td style="text-align: center"><span class="<%- auditConst.info[auditor.audit_status].class %>"><%- auditor.audit_status !== auditConst.status.uncheck ? auditConst.info[auditor.audit_status].title : '待审批'  %></span></td>
                                 <td style="text-align: center">
                                     <% if (auditor.audit_status === auditConst.status.checking && j === group.length - 1) { %>
                                     <span class="dropdown mr-2">

+ 8 - 6
app/view/phase_pay/index.ejs

@@ -54,13 +54,13 @@
                         <td class="text-right"><%- pay.display_end_sf_tp %></td>
                         <td class="<%- auditConst.info[pay.audit_status].class %>">
                             <% if (pay.audit_status === auditConst.status.checked && pay.final_auditor_str) { %>
-                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- pay.phase_order %>"><%- pay.final_auditor_str %></a>
+                                <a href="#sp-list" data-toggle="modal" data-target="#sp-list" phase-order="<%- pay.phase_order %>"><%- pay.final_auditor_str %></a>
                             <% } else { %>
                                 <% if (pay.curAuditors.length > 0) { %>
                                     <% if (pay.curAuditors[0].audit_type === auditType.key.common) { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- pay.phase_order %>"><%- pay.curAuditors[0].name %><%if (pay.curAuditors[0].role !== '' && pay.curAuditors[0].role !== null) { %>-<%- pay.curAuditors[0].role %><% } %></a>
+                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" phase-order="<%- pay.phase_order %>"><%- pay.curAuditors[0].name %><%if (pay.curAuditors[0].role !== '' && pay.curAuditors[0].role !== null) { %>-<%- pay.curAuditors[0].role %><% } %></a>
                                     <% } else { %>
-                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- pay.phase_order %>"><%- ctx.helper.transFormToChinese(pay.curAuditors[0].audit_order) + '审' %></a>
+                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" phase-order="<%- pay.phase_order %>"><%- ctx.helper.transFormToChinese(pay.curAuditors[0].audit_order) + '审' %></a>
                                     <% } %>
                                 <% } %>
                             <% } %>
@@ -69,12 +69,12 @@
                         <td class="text-center">
                             <% if (pay.audit_status === auditConst.status.uncheck && pay.create_user_id === ctx.session.sessionUser.accountId) { %>
                             <a href="<%- '/tender/' + pay.tid + '/pay/' + pay.phase_order %>" target="_blank" class="btn <%- auditConst.info[pay.audit_status].btnClass %> btn-sm"><%- auditConst.info[pay.audit_status].btnTitle %></a>
-                            <% } else if (s.status === auditConst.status.checkNo && s.user_id === ctx.session.sessionUser.accountId) { %>
+                            <% } else if (pay.status === auditConst.status.checkNo && pay.user_id === ctx.session.sessionUser.accountId) { %>
                             <a href="<%- '/tender/' + pay.tid + '/pay/' + pay.phase_order %>" target="_blank" class="btn <%- auditConst.info[pay.audit_status].btnClass %> btn-sm"><%- auditConst.info[pay.audit_status].btnTitle %></a>
-                            <% } else if ((s.status === auditConst.status.checking || s.status === auditConst.status.checkNoPre) && s.curAuditors && s.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                            <% } else if ((pay.status === auditConst.status.checking || pay.status === auditConst.status.checkNoPre) && pay.curAuditors && pay.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
                             <a href="<%- '/tender/' + pay.tid + '/pay/' + pay.phase_order %>" target="_blank" class="btn <%- auditConst.info[pay.audit_status].btnClass %> btn-sm"><%- auditConst.info[pay.audit_status].btnTitle %></a>
                             <% } else { %>
-                            <span class="<%- auditConst.info[pay.audit_status].btnClass %>"><%- auditConst.info[pay.audit_status].btnTitle %></span>
+                            <span class="<%- auditConst.info[pay.audit_status].class %>"><%- auditConst.info[pay.audit_status].title %></span>
                             <% } %>
                         </td>
                         <td> <%- pay.memo %></td>
@@ -88,4 +88,6 @@
 </div>
 <script>
     const phasePays = JSON.parse('<%- JSON.stringify(phasePays) %>');
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
+    const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
 </script>

+ 25 - 0
app/view/phase_pay/modal.ejs

@@ -64,6 +64,31 @@
         </form>
     </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>
 <script>
     $('.datepicker-here').datepicker({
         autoClose: true,

+ 2 - 1
config/web.js

@@ -695,6 +695,7 @@ const JsFiles = {
                 mergeFiles: [
                     '/public/js/component/menu.js',
                     '/public/js/sub_menu.js',
+                    '/public/js/phase_pay_list.js',
                 ],
                 mergeFile: 'phase_pay_list',
             },
@@ -714,7 +715,7 @@ const JsFiles = {
                     '/public/js/path_tree.js',
                     '/public/js/shares/tools_att.js',
                     '/public/js/shares/sjs_setting.js',
-                    '/public/js/phase_pay_audit.js',
+                    '/public/js/shares/phase_pay_audit.js',
                     '/public/js/phase_pay_detail.js',
                 ],
                 mergeFile: 'phase_pay_detail',