Переглянути джерело

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

Tony Kang 11 місяців тому
батько
коміт
ea7975b49f

+ 4 - 3
app/controller/ledger_audit_controller.js

@@ -193,9 +193,10 @@ module.exports = app => {
             try {
                 const data = JSON.parse(ctx.request.body.data);
                 if (ctx.session.sessionUser.is_admin && ctx.tender.ledger_status !== auditConst.status.checked) {
-                    await ctx.service.ledgerAudit.saveAudit(ctx.tender.id, ctx.tender.data.ledger_times, data);
-                    const auditors = await ctx.service.ledgerAudit.getAuditorsWithOwner(ctx.tender.id, ctx.tender.data.ledger_times);
-                    ctx.body = { err: 0, msg: '', data: auditors };
+                    await ctx.service.ledgerAudit.saveAudit(ctx.tender.id, ctx.tender.data.ledger_times, 0, data);
+                    const auditorUniqs = await ctx.service.ledgerAudit.getUniqUserGroup(ctx.tender.id, ctx.tender.data.ledger_times);
+                    const auditors = await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, ctx.tender.data.ledger_times);
+                    ctx.body = { err: 0, msg: '', data: { auditorUniqs, auditors } };
                 } else {
                     throw '您无权进行该操作';
                 }

+ 3 - 2
app/controller/measure_controller.js

@@ -101,7 +101,7 @@ module.exports = app => {
          */
         async add(ctx) {
             try {
-                if (ctx.session.sessionUser.accountId !== ctx.tender.data.user_id) {
+                if (ctx.session.sessionUser.accountId !== ctx.tender.data.user_id && ctx.tender.userAssistsId.indexOf(ctx.session.sessionUser.accountId) < 0) {
                     throw '您无权创建计量期';
                 }
                 const date = ctx.request.body.date;
@@ -119,13 +119,14 @@ module.exports = app => {
                         throw `最新一起未审批通过,请审批通过后再新增计量`
                     }
                 }
-                const newStage = await ctx.service.stage.addStage(ctx.tender.id, date, period);
+                const newStage = await ctx.service.stage.addStage(ctx.tender.data, date, period);
                 if (!newStage) {
                     throw '新增计量期失败,请重试';
                 }
                 ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + newStage.order);
             } catch (err) {
                 this.log(err);
+                ctx.postError(err, '新增计量期失败');
                 ctx.redirect(ctx.request.header.referer);
             }
         }

+ 7 - 31
app/controller/revise_controller.js

@@ -143,6 +143,7 @@ module.exports = app => {
                     addValid,
                     changeValid,
                     auditConst: audit.revise,
+                    auditType: audit.auditType,
                     auditConst2: JSON.stringify(audit.revise),
                     stdBills,
                     stdChapters,
@@ -171,27 +172,11 @@ module.exports = app => {
          */
         async reviseAuditors(ctx) {
             try {
-                const responseData = {
-                    err: 0, msg: '', data: {},
-                };
                 const rid = JSON.parse(ctx.request.body.data).id;
                 const reviseInfo = await ctx.service.ledgerRevise.getDataById(rid);
-                // 获取审批流程中右边列表
-                const auditHistory = [];
-                const times = reviseInfo.status === audit.revise.status.checkNo ? reviseInfo.times - 1 : reviseInfo.times;
-                if (times >= 1) {
-                    for (let i = 1; i <= times; i++) {
-                        auditHistory.push(await ctx.service.reviseAudit.getAuditors2ReviseList(reviseInfo.id, i));
-                    }
-                }
-                responseData.data.user = await ctx.service.projectAccount.getAccountInfoById(reviseInfo.uid);
-                responseData.data.auditHistory = auditHistory;
-                // 获取审批流程中左边列表
-                responseData.data.auditors = await ctx.service.reviseAudit.getAuditorsWithOwner(reviseInfo.id, times);
-                // 获取原报信息
-                // const reviseAuditor = await ctx.service.projectAccount.getAccountInfoById(reviseInfo.uid);
-                // responseData.data.reviseAuditor = reviseAuditor;
-                ctx.body = responseData;
+                await ctx.service.reviseAudit.loadReviseUser(reviseInfo);
+                await ctx.service.reviseAudit.loadReviseAuditViewData(reviseInfo);
+                ctx.body = { err: 0, msg: '', data: reviseInfo};
             } catch (error) {
                 this.log(error);
                 ctx.body = { err: 1, msg: error.toString(), data: null };
@@ -484,32 +469,23 @@ module.exports = app => {
         async history(ctx) {
             try {
                 const revise = ctx.revise;
+                await ctx.service.reviseAudit.loadReviseUser(revise);
+                await ctx.service.reviseAudit.loadReviseAuditViewData(revise);
 
                 const [ledgerSpread, posSpread] = await spreadSetting.getLedgerSpreadSetting(ctx, revise.tid,
                     revise.status === audit.revise.status.checking || revise.status === audit.revise.status.checked);
                 ledgerSpread.readOnly = true;
                 posSpread.readOnly = true;
                 const historyRevise = await ctx.service.ledgerRevise.getAllReviseList(ctx.tender.id);
-                // 获取审批流程中右边列表
-                const auditHistory = [];
-                const times = revise.status === audit.revise.status.checkNo ? revise.times - 1 : revise.times;
-                if (times >= 1) {
-                    for (let i = 1; i <= times; i++) {
-                        auditHistory.push(await ctx.service.reviseAudit.getAuditors2ReviseList(revise.id, i));
-                    }
-                }
                 const user = await ctx.service.projectAccount.getAccountInfoById(revise.uid);
-                // 获取审批流程中左边列表
-                const auditors = await ctx.service.reviseAudit.getAuditorsWithOwner(revise.id, times);
                 const renderData = {
                     preUrl: ctx.url.replace('/info', ''),
                     measureType, audit, revise,
                     ledgerSpread, posSpread,
                     readOnly: true,
                     historyRevise,
-                    auditHistory,
-                    auditors,
                     auditConst: audit.revise,
+                    auditType: audit.auditType,
                     user,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.history),
                     nodeType: stdConst.nodeType,

+ 1 - 0
app/controller/stage_controller.js

@@ -1032,6 +1032,7 @@ module.exports = app => {
 
                 const projectFunInfo = await this.ctx.service.project.getFunRela(ctx.session.sessionProject.id);
                 renderData.lockPayExpr = projectFunInfo.lockPayExpr;
+                renderData.showMinusCol = projectFunInfo.showMinusCol;
                 renderData.deleteFilePermission = PermissionCheck.delFile(this.ctx.session.sessionUser.permission);
 
                 if (!ctx.stage.readOnly || ctx.tender.isTourist) {

+ 1 - 1
app/middleware/revise_audit_check.js

@@ -20,7 +20,7 @@ const checkAuditFlow = async function(ctx) {
     if (info.shenpi.revise === shenpiConst.sp_status.sqspr) return;
     if (revise.status !== status.uncheck && revise.status !== status.checkNo) return;
 
-    const shenpi_status = info.shenpi.ledger;
+    const shenpi_status = info.shenpi.revise;
     // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
     const auditList = await ctx.service.reviseAudit.getAuditors(revise.id, revise.times);
     if (shenpi_status === shenpiConst.sp_status.gdspl) {

+ 2 - 0
app/middleware/tender_check.js

@@ -64,6 +64,8 @@ module.exports = options => {
                 return x.user_id === tender.data.user_id || stageAuditorsId.indexOf(x.user_id) >= 0;
             });
             const auditAssistsId = this.helper._.map(auditAssists, 'ass_user_id');
+            tender.userAssistsId = auditAssists.filter(x => {return x.user_id === tender.data.user_id;})
+                .map(x => { return x.ass_user_id; });
             const settleAuditors = yield this.service.settleAudit.getAllAuditors(tender.id);
             const settleAuditorsId = this.helper._.map(settleAuditors, 'audit_id');
             const changeAuditors = yield this.service.changeAudit.getAllAuditors(tender.id);

+ 112 - 96
app/public/js/ledger.js

@@ -4168,10 +4168,11 @@ $(document).ready(function() {
                     }
                     html.push('</div>');
                     html.push('<div class="col-auto">');
-                    // todo 添加会签或签时
-                    // html.push('<span class="badge badge-pill badge-primary badge-bg-small"><small></small></span>');
+                    if (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>`);
+                    }
                     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('<a href="javascript: void(0)" class="text-danger pull-right ml-1">移除</a>');
                     }
                     html.push('</div>');
                     html.push('</li>');
@@ -4279,6 +4280,59 @@ $(document).ready(function() {
         }, 400);
     });
 
+    const getAdminEditShenpiListHtml = function(auditGroup) {
+        const html = [];
+        for (const [i, group] of auditGroup.entries()) {
+            if (i === 0) continue;
+            for (const [j, auditor] of group.entries()) {
+                html.push('<tr>');
+                if (j === 0) {
+                    const auditTypeHtml = auditor.type === auditType.key.common ? '' : `<span class="ml-2 badge badge-pill badge-${auditType.info[auditor.audit_type].class} p-1"><small>${auditType.info[auditor.audit_type].short}</small></span>`;
+                    html.push(`<td class="text-left d-flex">${i + '审'}${auditTypeHtml}</td>`);
+                } else {
+                    html.push(`<td class="text-left d-flex"></td>`);
+                }
+                html.push(`<td></span> ${auditor.name} <small class="text-muted">${auditor.role}</small></td>`);
+                html.push(`<td style="text-align: center"><span class="${auditConst.auditStringClass[auditor.status]}">${ auditor.status !== auditConst.status.uncheck ? auditConst.auditString[auditor.status] : '待审批' }</span></td>`);
+                html.push('<td style="text-align: center">');
+                if (auditor.status === auditConst.status.checking && j === group.length - 1) {
+                    html.push('<span class="dropdown mr-2">',
+                        `<a href="javascript: void(0)" class="add-audit" id="${auditor.audit_id}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>`,
+                        makeSelectAudit(auditor.audit_id+'_add', auditor.audit_id, 'add'),'</div>', '</span>');
+                }
+                if (auditor.status === auditConst.status.uncheck) {
+                    if (j === group.length - 1) {
+                        html.push('<span class="dropdown mr-2">',
+                            `<a href="javascript: void(0)" class="add-audit" id="${auditor.audit_id}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>`,
+                            makeSelectAudit(auditor.audit_id+'_add', auditor.audit_id, 'add'),'</div>', '</span>');
+                        if (auditor.audit_type !== auditType.key.common) {
+                            html.push('<span class="dropdown mr-2">',
+                                `<a href="javascript: void(0)" class="add-audit" id="${auditor.audit_id}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">平级</a>`,
+                                makeSelectAudit(auditor.audit_id+'_add-sibling', auditor.audit_id, 'add-sibling'),'</div>', '</span>');
+                        }
+                    }
+                    html.push('<span class="dropdown mr-2">',
+                        `<a href="javascript: void(0)" class="add-audit" id="${auditor.audit_id}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更换</a>`,
+                        makeSelectAudit(auditor.audit_id+'_change', auditor.audit_id, 'change'),'</div>', '</span>');
+                    html.push(`<span class="dropdown">
+                                    <a href="javascript: void(0)" class="text-danger" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">移除</a>
+                                    <div class="dropdown-menu">
+                                        <span class="dropdown-item" href="javascript:void(0);">确认移除审批人?</span>
+                                        <div class="dropdown-divider"></div>
+                                        <div class="px-2 py-1 text-center">
+                                            <button class="remove-audit btn btn-sm btn-danger" data-id="${auditor.audit_id}">移除</button>
+                                            <button class="btn btn-sm btn-secondary">取消</button>
+                                        </div>
+                                    </div>
+                                    </span>`);
+                }
+                html.push('</td>');
+                html.push('</tr>');
+            }
+        }
+        return html.join('');
+    };
+
     $('body').on('click', '#admin-edit-shenpi dl dd', function () {
         const id = parseInt($(this).attr('data-id'));
         if (!id) return;
@@ -4293,64 +4347,15 @@ $(document).ready(function() {
             toastr.warning('该审核人已存在,请勿重复添加');
             return;
         }
-        const order = parseInt($(this).parents('tr').find('.shenpi-order').text());
-        const curAuditorIndex = _.findIndex(auditorList, { audit_id: this_aid });
         const prop = {
             operate: this_operate,
             old_aid: this_aid,
             new_aid: user.id,
         };
         postData('/tender/' + getTenderId() + '/ledger/audit/save', prop, (datas) => {
-            if (this_operate === 'add') {
-                const addhtml = '<tr>\n' +
-                    `                                <td><span class="shenpi-order">${order+1}</span> ${user.name} <small class="text-muted">${user.role}</small></td>\n` +
-                    `                                <td style="text-align: center"><span class="">待审批</span></td>\n` +
-                    '                                <td style="text-align: center">\n' +
-                    '                                    <span class="dropdown mr-2">\n' +
-                    `                                    <a href="javascript: void(0)" class="add-audit" id="${user.id}_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>\n` +
-                    makeSelectAudit(user.id+'_add', user.id, 'add') +
-                    '                                        </div>\n' +
-                    '                                    </span>\n' +
-                    '                                    <span class="dropdown mr-2">\n' +
-                    `                                        <a href="javascript: void(0)" class="change-audit" id="${user.id}_change_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更换</a>\n` +
-                    makeSelectAudit(user.id+'_change', user.id, 'change') +
-                    '                                    </span>\n' +
-                    '                                    <span class="dropdown">\n' +
-                    '                                    <a href="javascript: void(0)" class="text-danger" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">移除</a>\n' +
-                    '                                    <div class="dropdown-menu">\n' +
-                    '                                        <span class="dropdown-item">确认移除审批人?</span>\n' +
-                    '                                        <div class="dropdown-divider"></div>\n' +
-                    '                                        <div class="px-2 py-1 text-center">\n' +
-                    `                                            <button class="remove-audit btn btn-sm btn-danger" data-id="${user.id}">移除</button>\n` +
-                    '                                            <button class="btn btn-sm btn-secondary">取消</button>\n' +
-                    '                                        </div>\n' +
-                    '                                    </div>\n' +
-                    '                                    </span>\n' +
-                    '                                </td>\n' +
-                    '                            </tr>';
-                $(this).parents('tr').after(addhtml);
-                auditorList.splice(curAuditorIndex+1, 0, { audit_id: user.id, company: user.company, name: user.name, role: user.role });
-                updateOrder(user.id);
-            } else if (this_operate === 'change') {
-                const this_user = _.find(auditorList, { audit_id: this_aid });
-                this_user.audit_id = user.id;
-                this_user.company = user.company;
-                this_user.role = user.role;
-                this_user.name = user.name;
-                auditorList.splice(curAuditorIndex, 1, this_user);
-                $(this).parents('tr').children('td').eq(0).html(`<span class="shenpi-order">${order}</span> ${user.name} <small class="text-muted">${user.role}</small>`);
-                // 替换所有aid
-                $(this).parents('.book-list').attr('data-aid', user.id);
-                $(this).parents('.dropdown-menu').attr('id', user.id +'_change_dropdownMenu').attr('aria-labelledby', user.id +'_change_dropdownMenuButton');
-                $(this).parents('.dropdown-menu').children('mb-2').children('input').attr('data-code', user.id +'_change');
-                $(this).parents('.dropdown-menu').siblings('.change-audit').attr('id', user.id +'_change_dropdownMenuButton');
-                $(this).parents('td').children('span').eq(0).find('.add-audit').attr('id', user.id +'_add_dropdownMenuButton');
-                $(this).parents('td').children('span').eq(0).find('.dropdown-menu').attr('id', user.id +'_add_dropdownMenu').attr('aria-labelledby', user.id +'_add_dropdownMenuButton');
-                $(this).parents('td').children('span').eq(0).find('.dropdown-menu').children('mb-2').children('input').attr('data-code', user.id +'_add');
-                $(this).parents('td').children('span').eq(0).find('.dropdown-menu').children('.book-list').attr('data-aid', user.id);
-                $(this).parents('td').children('span').eq(2).find('.remove-audit').attr('data-id', user.id);
-            }
-            changeLiucheng(datas);
+            auditorList = datas.auditors;
+            $('#admin-edit-shenpi-list').html(getAdminEditShenpiListHtml(datas.auditorUniqs));
+            changeLiucheng(datas.auditorUniqs);
         });
     });
 
@@ -4362,62 +4367,73 @@ $(document).ready(function() {
             old_aid: id,
         };
         postData('/tender/' + getTenderId() + '/ledger/audit/save', prop, (datas) => {
-            updateOrder(id, 0);
-            const curAuditorIndex = _.findIndex(auditorList, { audit_id: id });
-            auditorList.splice(curAuditorIndex, 1);
-            $(this).parents('tr').remove();
-            changeLiucheng(datas);
+            auditorList = datas.auditors;
+            $('#admin-edit-shenpi-list').html(getAdminEditShenpiListHtml(datas.auditorUniqs));
+            changeLiucheng(datas.auditorUniqs);
         });
     });
 
-    // 比uid大的序号进行调整
-    function updateOrder(aid, num = 1) {
-        const index = _.findIndex(auditorList, { audit_id: aid });
-        for (let i = index;i < auditorList.length; i++) {
-            $('#admin-edit-shenpi tbody').children('tr').eq(i).find('.shenpi-order').text(i+num);
-        }
-    }
+    const getAuditTypeText = function (type) {
+        if (type === auditType.key.common) return '';
+        return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
+    };
 
     function changeLiucheng(datas) {
         const auditorshtml = [];
-        let lastAuditorHtml = '';
+        let lastAuditorHtml = [];
         for (const [index,data] of datas.entries()) {
-            auditorshtml.push('<li class="list-group-item" data-auditorid="' + data.audit_id + '">');
-            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>');
+            auditorshtml.push('<li class="list-group-item d-flex justify-content-between align-items-center">');
             if (index === 0) {
-                auditorshtml.push('<span class="pull-right">原报</span>');
+                auditorshtml.push('<span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>');
             } else if (index+1 === datas.length) {
-                auditorshtml.push('<span class="pull-right">终审</span>');
+                auditorshtml.push('<span class="mr-1"><i class="fa fa fa-stop-circle"></i></span>');
             } else {
-                auditorshtml.push('<span class="pull-right">'+ transFormToChinese(index) +'审</span>');
+                auditorshtml.push('<span class="mr-1"><i class="fa fa-chevron-circle-down"></i></span>');
+            }
+            auditorshtml.push('<span class="text-muted">');
+            for (const u of data) {
+                auditorshtml.push(`<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.audit_id}">${u.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>');
-            if (data.status === auditConst.status.uncheck) {
-                lastAuditorHtml += '<li class="timeline-list-item pb-2 is_uncheck">\n' +
-                    '                                            <div class="timeline-item-date">\n' +
-                    '                                                \n' +
-                    '                                            </div>\n' +
-                    '                                            <div class="timeline-item-icon bg-secondary text-light">\n' +
-                    '                                            </div>\n' +
-                    '                                            <div class="timeline-item-content">\n' +
-                    '                                                <div class="card">\n' +
-                    '                                                    <div class="card-body p-3">\n' +
-                    '                                                        <div class="card-text">\n' +
-                    `                                                            <p class="mb-1"><span class="h5">${data.name}</span>\n` +
-                    '                                                                <span class="pull-right ">\n' +
-                    '                                                                </span>\n' +
-                    '                                                            </p>\n' +
-                    `                                                            <p class="text-muted mb-0">${data.role}</p>\n` +
-                    '                                                        </div>\n' +
-                    '                                                    </div>\n' +
-                    '                                                </div>\n' +
-                    '                                            </div>\n' +
-                    '                                        </li>';
+            if (data[0].status === auditConst.status.uncheck) {
+                lastAuditorHtml.push('<li class="timeline-list-item pb-2 is_uncheck">');
+                if (index < datas.length - 1) {
+                    lastAuditorHtml.push('<div class="timeline-item-tail"></div>');
+                }
+                lastAuditorHtml.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
+
+                lastAuditorHtml.push('<div class="timeline-item-content">');
+                lastAuditorHtml.push(`<div class="py-1">
+                        <span class="text-black-50">
+                        ${ index !== datas.length - 1 ? data[0].audit_order + '' : '终' }审 ${getAuditTypeText(data[0].audit_type)}
+                        </span>
+                    </div>`);
+                lastAuditorHtml.push('<div class="card"><div class="card-body px-3 py-0">');
+                for (const [i, auditor] of data.entries()) {
+                    lastAuditorHtml.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
+                    lastAuditorHtml.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
+                    lastAuditorHtml.push('<div class="col">');
+                    lastAuditorHtml.push('</div>');
+                    lastAuditorHtml.push('</div>');
+                }
+                lastAuditorHtml.push('</div></div>');
+                lastAuditorHtml.push('</div>');
+                lastAuditorHtml.push('</li>');
             }
         }
         $('.last-auditor-list .is_uncheck').remove();
-        $('.last-auditor-list').append(lastAuditorHtml);
+        $('.last-auditor-list').append(lastAuditorHtml.join(''));
         $('.auditors-list').html(auditorshtml.join(''));
 
     }

+ 3 - 1
app/public/js/stage.js

@@ -5372,7 +5372,9 @@ function makeOneShouFang(sf) {
     sf.name = lData.b_code;
     if (sf.pid) {
         const pData = _.find(posData, { id: sf.pid });
-        sf.name = lData.b_code + ' / ' + pData.name;
+        if (pData && pData.name) {
+            sf.name = lData.b_code + ' / ' + pData.name;
+        }
     }
     return sf;
 }

+ 4 - 3
app/public/js/stage_audit.js

@@ -143,10 +143,11 @@ $(document).ready(function () {
                         }
                         html.push('</div>');
                         html.push('<div class="col-auto">');
-                        // todo 添加会签或签时
-                        // html.push('<span class="badge badge-pill badge-primary badge-bg-small"><small></small></span>');
+                        if (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>`);
+                        }
                         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('<a href="javascript: void(0)" class="text-danger pull-right ml-1">移除</a>');
                         }
                         html.push('</div>');
                         html.push('</li>');

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

@@ -147,7 +147,7 @@ $(document).ready(() => {
                     return tips.join('<br/>');
                 }
             },
-            {title: '扣款', colSpan: '1', rowSpan: '1', field: 'minus', hAlign: 1, width: 50, cellType: 'checkbox', readOnly: 'readOnly.minus'},
+            {title: '扣款', colSpan: '1', rowSpan: '1', field: 'minus', hAlign: 1, width: 50, cellType: 'checkbox', readOnly: 'readOnly.minus', visible: showMinusCol},
             {title: '本期金额(F)', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 120, readOnly: 'readOnly.tp', type: 'Number', /*cellType: 'tip', getTip: function (data) {return data ? data.expr : '';}*/},
             {title: '截止上期金额',  colSpan: '1', rowSpan: '1', field: 'pre_tp', hAlign: 2, width: 100, readOnly: true, type: 'Number',},
             {title: '截止本期金额',  colSpan: '1', rowSpan: '1', field: 'end_tp', hAlign: 2, width: 100, readOnly: true, type: 'Number',},

+ 42 - 14
app/service/ledger_audit.js

@@ -102,23 +102,23 @@ module.exports = app => {
             switch (status) {
                 case auditConst.status.checking:
                 case auditConst.status.checked:
-                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where tender_id = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`order` DESC', [tenderId, times, status]);
+                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where tender_id = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`audit_order` DESC', [tenderId, times, status]);
                     if (!cur) return [];
 
                     sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`tender_id`, la.audit_order, la.audit_type, la.audit_ledger_id ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id` ' +
                         '  WHERE la.`tender_id` = ? and la.`audit_order` = ? and la.`times` = ?';
-                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, cur.order, times];
+                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, cur.audit_order, times];
                     auditor = await this.db.query(sql, sqlParam);
                     break;
                 case auditConst.status.checkNo:
-                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where tender_id = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`order` DESC', [tenderId, parseInt(times) - 1, status]);
+                    cur = await this.db.queryOne(`SELECT * From ${this.tableName} where tender_id = ? AND times = ? AND status = ? ORDER By times DESC, ` + '`audit_order` DESC', [tenderId, parseInt(times) - 1, status]);
                     if (!cur) return [];
 
                     sql = 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`tender_id`, la.audit_order, la.audit_type, la.audit_ledger_id ' +
                         '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id` ' +
-                        '  WHERE la.`sid` = ? and la.`audit_order` = ? and la.`times` = ?';
-                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, cur.order, parseInt(times) - 1];
+                        '  WHERE la.`tender_id` = ? and la.`audit_order` = ? and la.`times` = ?';
+                    sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tenderId, cur.audit_order, parseInt(times) - 1];
                     auditor = await this.db.query(sql, sqlParam);
                     break;
                 case auditConst.status.uncheck:
@@ -213,6 +213,8 @@ module.exports = app => {
 
         async getUniqUserGroup(tenderId, times) {
             const group = await this.getAuditorGroup(tenderId, times);
+            // 台账因为可选原报人为审批人,这里有点不同,这里要先过滤再取原报插入
+            const newGroup = this.groupAuditorsUniq(group);
             const sql =
                 'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As tender_id, 0 As audit_order, 1 As audit_type' +
                 '  FROM ' + this.ctx.service.tender.tableName + ' As t' +
@@ -221,8 +223,8 @@ module.exports = app => {
                 '  WHERE t.id = ?';
             const sqlParam = [times, tenderId, tenderId];
             const user = await this.db.queryOne(sql, sqlParam);
-            group.unshift([ user ]);
-            return this.groupAuditorsUniq(group);
+            newGroup.unshift([ user ]);
+            return newGroup;
         }
 
         async getAuditorHistory(tenderId, times, reverse = false) {
@@ -611,8 +613,10 @@ module.exports = app => {
                     where: { tender_id: tenderId, times },
                     columns: ['tender_id', 'audit_order', 'audit_id', 'audit_type', 'audit_ledger_id'],
                 });
-                const insertAuditors = orgAuditors.map(x => {
-                    return { ...x, times: times + 1, status: auditConst.status.uncheck };
+                const insertAuditors = [];
+                orgAuditors.forEach(x => {
+                    if (insertAuditors.find(y => { return y.audit_id === x.audit_id && y.audit_type === x.audit_type})) return;
+                    insertAuditors.push({ ...x, times: times + 1, status: auditConst.status.uncheck });
                 });
                 await transaction.insert(this.tableName, insertAuditors);
 
@@ -913,7 +917,7 @@ module.exports = app => {
             // const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tender_id, times];
             // return transaction ? await transaction.query(sql, sqlParam) : await this.db.query(sql, sqlParam);
             const sql =
-                'SELECT la.`audit_id`, la.`status`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`tender_id`, la.`audit_order` ' +
+                'SELECT la.`audit_id`, la.`status`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`tender_id`, la.`audit_order`, la.`audit_type` ' +
                 '  FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id`' +
                 '  WHERE la.`tender_id` = ? and la.`times` = ? ORDER BY la.`audit_order` DESC';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tender_id, times];
@@ -975,7 +979,7 @@ module.exports = app => {
                 const existAudit = auditList.find(x => { return x.audit_id === lastId });
                 let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.audit_order)}, 0) + 1 : 1; // 最大值 + 1
                 if (existAudit) {
-                    await transaction.delete(this.tableName, { sid: stage.id, times: stage.times, audit_id: lastId });
+                    await transaction.delete(this.tableName, { tender_id: tender.id, times: tender.ledger_times, audit_id: lastId });
                     const sameOrder = auditList.filter(x => { return x.audit_order === existAudit.audit_order });
                     if (sameOrder.length === 1) {
                         const updateData = [];
@@ -1010,11 +1014,15 @@ module.exports = app => {
          * @param {Object} data - 更改参数
          * @return {Promise<void>}
          */
-        async saveAudit(tenderId, times, data) {
+        async saveAudit(tenderId, times, sp_group, data) {
             const transaction = await this.db.beginTransaction();
             try {
                 const auditors = await this.getAuditGroupByList(tenderId, times);
                 const now_audit = this._.find(auditors, { audit_id: data.old_aid });
+                if (data.operate !== 'del') {
+                    const exist = await this.getDataByCondition({ tender_id: tenderId, times, audit_id: data.new_aid });
+                    if (exist) throw '该审核人已存在,请勿重复添加';
+                }
                 if (data.operate === 'add') {
                     if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {
                         throw '当前人下无法操作新增';
@@ -1023,6 +1031,7 @@ module.exports = app => {
                         tender_id: tenderId,
                         audit_id: data.new_aid,
                         audit_order: now_audit.audit_order + 1,
+                        audit_type: auditType.key.common,
                         times,
                         status: auditConst.status.uncheck,
                     };
@@ -1030,12 +1039,26 @@ module.exports = app => {
                     await this._syncOrderByDelete(transaction, tenderId, now_audit.audit_order + 1, times, '+');
                     await transaction.insert(this.tableName, newAudit);
                     // 更新审批流程页数据,如果存在
+                } else if (data.operate === 'add-sibling') {
+                    if (now_audit.status !== auditConst.status.uncheck && now_audit.status !== auditConst.status.checking) {
+                        throw '当前人下无法操作新增';
+                    }
+                    const newAudit = {
+                        tender_id: tenderId,
+                        audit_id: data.new_aid,
+                        audit_order: now_audit.audit_order,
+                        audit_type: now_audit.audit_type,
+                        times: times,
+                        status: auditConst.status.uncheck,
+                    };
+                    await transaction.insert(this.tableName, newAudit);
                 } else if (data.operate === 'del') {
                     if (now_audit.status !== auditConst.status.uncheck) {
                         throw '当前人无法操作删除';
                     }
+                    const flowAuditors = auditors.filter(x => { return x.audit_order === now_audit.audit_order; });
                     await transaction.delete(this.tableName, { tender_id: tenderId, times, audit_id: now_audit.audit_id, audit_order: now_audit.audit_order });
-                    await this._syncOrderByDelete(transaction, tenderId, now_audit.audit_order, times);
+                    if (flowAuditors.length === 1) await this._syncOrderByDelete(transaction, tenderId, now_audit.audit_order, times);
                 } else if (data.operate === 'change') {
                     const nowAudit = await this.getDataByCondition({ tender_id: tenderId, times, audit_id: now_audit.audit_id, audit_order: now_audit.audit_order });
                     if (now_audit.status !== auditConst.status.uncheck || !nowAudit) {
@@ -1044,7 +1067,12 @@ module.exports = app => {
                     nowAudit.audit_id = data.new_aid;
                     await transaction.update(this.tableName, nowAudit);
                 }
-                if (this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdspl || this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdzs) {
+                if (this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdspl) {
+                    const newAuditors = await transaction.select(this.tableName, { where: { tender_id: tenderId, times } });
+                    const newAuditorGroup = this.ctx.helper.groupAuditors(newAuditors, 'audit_order');
+                    const uniqNewAuditorGroup = this.ctx.helper.groupAuditorsUniq(newAuditorGroup);
+                    await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.ledger, shenpiConst.sp_type.ledger, uniqNewAuditorGroup, sp_group);
+                } else if (this.ctx.tender.info.shenpi.ledger === shenpiConst.sp_status.gdzs) {
                     const newAuditors = await this.getAuditGroupByList(tenderId, times, transaction);
                     await this.ctx.service.shenpiAudit.updateAuditList(transaction, this.ctx.tender.id, this.ctx.tender.info.shenpi.ledger, shenpiConst.sp_type.ledger, this._.map(newAuditors, 'audit_id'));
                 }

+ 4 - 1
app/service/project.js

@@ -14,6 +14,7 @@ const defaultFunRela = {
     banMinusChangeBills: true,
     minusNoValue: true,
     lockPayExpr: false,
+    showMinusCol: true,
     imType: imType.zl.value,
     needGcl: false,
 };
@@ -68,6 +69,7 @@ module.exports = app => {
                         banMinusChangeBills: {type: 'bool', required: true,},
                         minusNoValue: {type: 'bool', required: true,},
                         lockPayExpr: {type: 'bool', required: true,},
+                        showMinusCol: {type: 'bool', required: true,},
                     };
                     break;
                 default:
@@ -174,7 +176,8 @@ module.exports = app => {
             const result = await this.db.update(this.tableName, {
                 id: id, fun_rela: JSON.stringify({
                     banOver: data.banOver, hintOver: data.hintOver, banMinusChangeBills: data.banMinusChangeBills,
-                    imType: data.imType, needGcl: data.needGcl, minusNoValue: data.minusNoValue, lockPayExpr: data.lockPayExpr,
+                    imType: data.imType, needGcl: data.needGcl, minusNoValue: data.minusNoValue,
+                    lockPayExpr: data.lockPayExpr, showMinusCol: data.showMinusCol,
                 }),
             });
             return result.affectedRows === 1;

+ 2 - 2
app/service/revise_audit.js

@@ -673,7 +673,7 @@ module.exports = app => {
                     // 更新台账缓存
                     await this.ctx.service.tenderCache.updateStageCache4Revise(transaction, revise.tid, sum, pcTp);
                     // 清除变更新增部位maxLid缓存,防止树结构混乱
-                    await this.ctx.service.changeLedger._removeCacheMaxLid(audit.tender_id);
+                    await this.ctx.service.changeLedger._removeCacheMaxLid(revise.tid);
 
                     // 短信通知-审批通过提醒功能
                     await this.ctx.helper.sendAliSms(revise.uid, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), SmsAliConst.template.revise_result, {
@@ -1056,7 +1056,7 @@ module.exports = app => {
                 const existAudit = auditList.find(x => { return x.audit_id === lastId });
                 let order = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.audit_order)}, 0) + 1 : 1; // 最大值 + 1
                 if (existAudit) {
-                    await transaction.delete(this.tableName, { sid: stage.id, times: stage.times, audit_id: lastId });
+                    await transaction.delete(this.tableName, { rid: revise.id, times: revise.times, audit_id: lastId });
                     const sameOrder = auditList.filter(x => { return x.audit_order === existAudit.audit_order });
                     if (sameOrder.length === 1) {
                         const updateData = [];

+ 1 - 1
app/service/shenpi_audit.js

@@ -431,7 +431,7 @@ module.exports = app => {
                     tid: tenderId,
                     sp_type,
                     sp_status,
-                    audit_id: a.aid || a.uid,
+                    audit_id: a.aid || a.uid || a.audit_id,
                     audit_order: a.audit_order,
                     audit_type: a.audit_type,
                     sp_group,

+ 6 - 6
app/service/stage.js

@@ -500,9 +500,9 @@ module.exports = app => {
          * @param period - 开始-截止日期
          * @return {Promise<void>}
          */
-        async addStage(tenderId, date, period) {
+        async addStage(tender, date, period) {
             const stages = await this.getAllDataByCondition({
-                where: { tid: tenderId },
+                where: { tid: tender.id },
                 orders: [['order', 'DESC']],
             });
             const preStage = stages[0];
@@ -510,14 +510,14 @@ module.exports = app => {
             const order = stages.length + 1;
             const newStage = {
                 sid: this.uuid.v4(),
-                tid: tenderId,
+                tid: tender.id,
                 order,
                 in_time: new Date(),
                 s_time: date,
                 period,
                 times: 1,
                 status: auditConst.stage.status.uncheck,
-                user_id: this.ctx.session.sessionUser.accountId,
+                user_id: tender.user_id, // this.ctx.session.sessionUser.accountId,
                 check_calc: false,
             };
             newStage.cache_time_l = newStage.in_time;
@@ -591,14 +591,14 @@ module.exports = app => {
                 // 新增期拷贝报表相关配置/签名角色 等
                 if (preStage) {
                     const rptResult = await this.ctx.service.rptCustomDefine.addInitialStageData(newStage, preStage, transaction);
-                    await this.ctx.service.roleRptRel.addInitialStageData(tenderId, newStage, preStage);
+                    await this.ctx.service.roleRptRel.addInitialStageData(tender.id, newStage, preStage);
                 }
 
                 await transaction.commit();
                 // 通知发送 - 第三方更新
                 if (this.ctx.session.sessionProject.custom && syncApiConst.notice_type.indexOf(this.ctx.session.sessionProject.customType) !== -1) {
                     const base_data = {
-                        tid: tenderId,
+                        tid: tender.id,
                         sid: result.insertId,
                         op: 'insert',
                     };

+ 3 - 2
app/service/tender.js

@@ -91,14 +91,15 @@ module.exports = app => {
             let sql = '';
             let sqlParam = [];
             if (listStatus === 'manage') {
+                const userFilter = getAll ? '' : this.db.format('And t.user_id = ?', [session.sessionUser.accountId]);
                 // 管理页面只取属于自己创建的标段
                 sql = 'SELECT t.`id`, t.`project_id`, t.`name`, t.`status`, t.`category`, t.`ledger_times`, t.`ledger_status`, t.`measure_type`, t.`user_id`, t.`create_time`, t.`total_price`, t.`deal_tp`, t.`spid`,' +
                     '    pa.`name` As `user_name`, pa.`role` As `user_role`, pa.`company` As `user_company` ' +
                     '  FROM ?? As t ' +
                     '  Left Join ?? As pa ' +
                     '  ON t.`user_id` = pa.`id` ' +
-                    '  WHERE t.`project_id` = ? ' + buildStatusFilter + ' AND t.`user_id` = ? ORDER BY CONVERT(t.`name` USING GBK) ASC';
-                sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, session.sessionProject.id, session.sessionUser.accountId];
+                    '  WHERE t.`project_id` = ? ' + buildStatusFilter + userFilter + ' ORDER BY CONVERT(t.`name` USING GBK) ASC';
+                sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, session.sessionProject.id];
             } else if (getAll === 1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) {
                 // 具有查看所有标段权限的用户查阅标段
                 sql = 'SELECT t.`id`, t.`project_id`, t.`name`, t.`status`, t.`category`, t.`ledger_times`, t.`ledger_status`, t.`measure_type`, t.`user_id`, t.`create_time`, t.`total_price`, t.`deal_tp`, t.`spid`,' +

+ 89 - 55
app/view/ledger/audit_modal.ejs

@@ -70,7 +70,7 @@
                             <% } %>
                         <div class="<%- idx < tender.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1 && tender.auditHistory.length > 1) { %>last-auditor-list<% } %>">
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                 <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
@@ -102,7 +102,7 @@
                                     </div>
                                 </li>
                                 <% } %>
-                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length > 1) { %>is_uncheck<% } %>">
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                     <% if (group.endYear) { %>
                                     <div class="timeline-item-date">
                                         <%- group.endYear %>
@@ -251,7 +251,7 @@
                         <% } %>
                         <div class="<%- idx < tender.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>last-auditor-list<% } %>">
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === tender.auditHistory.length - 1) { %>last-auditor-list<% } %>">
                                 <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
@@ -283,7 +283,7 @@
                                     </div>
                                 </li>
                                 <% } %>
-                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                     <% if (his.endYear) { %>
                                     <div class="timeline-item-date">
                                         <%- group.endYear %>
@@ -387,107 +387,141 @@
                             </style>
                             <table class="table table-hover" id="admin-edit-shenpi">
                                 <thead>
-                                <tr class="card-header">
-                                    <th>审批流程</th>
+                                <tr class="card-header text-center">
+                                    <th width="100px">审批流程</th>
+                                    <th>审批人员</th>
                                     <th width="80" style="text-align: center">审批状态</th>
                                     <th width="200" style="text-align: center">操作</th>
                                 </tr>
                                 </thead>
-                                <% for (let i = 1, iLen = auditors.length; i < iLen; i++) { %>
-                                    <tr>
-                                        <td><span class="shenpi-order"><%- i %></span> <%- auditors[i].name %> <small class="text-muted"><%- auditors[i].role %></small></td>
-                                        <td style="text-align: center"><span class="<%- auditConst.auditStringClass[auditors[i].status] %>"><%- auditors[i].status !== auditConst.status.uncheck ? auditConst.auditString[auditors[i].status] : '待审批'  %></span></td>
-                                        <td style="text-align: center">
-                                            <% if (auditors[i].status === auditConst.status.checking) { %>
-                                                <span class="dropdown mr-2">
-                                    <a href="javascript: void(0)" class="add-audit" id="<%- auditors[i].audit_id %>_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>
-                                    <div class="dropdown-menu dropdown-menu-right" id="<%- auditors[i].audit_id %>_add_dropdownMenu" aria-labelledby="<%- auditors[i].audit_id %>_add_dropdownMenuButton" style="width:220px">
+                                <tbody id="admin-edit-shenpi-list">
+                                <% for (const [i, group] of tender.auditors2.entries()) { %>
+                                    <% if (i === 0) continue; %>
+                                    <% for (const [j, auditor] of group.entries()) { %>
+                                        <tr>
+                                            <td class="text-left d-flex">
+                                                <% if (j === 0) { %>
+                                                    <%- i + '审' %>
+                                                    <% if (auditor.audit_type !== auditType.key.common) { %>
+                                                        <span class="ml-2 badge badge-pill badge-<%-  auditType.info[auditor.audit_type].class %> p-1"><small><%- auditType.info[auditor.audit_type].short %></small></span>
+                                                    <% } %>
+                                                <% } %>
+                                            </td>
+                                            <td></span> <%- auditor.name %> <small class="text-muted"><%- auditor.role %></small></td>
+                                            <td style="text-align: center"><span class="<%- auditConst.auditStringClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.auditString[auditor.status] : '待审批'  %></span></td>
+                                            <td style="text-align: center">
+                                                <% if (auditor.status === auditConst.status.checking && j === group.length - 1) { %>
+                                                    <span class="dropdown mr-2">
+                                    <a href="javascript: void(0)" class="add-audit" id="<%- auditor.audit_id %>_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>
+                                    <div class="dropdown-menu dropdown-menu-right" id="<%- auditor.audit_id %>_add_dropdownMenu" aria-labelledby="<%- auditor.audit_id %>_add_dropdownMenuButton" style="width:220px">
                                         <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"
-                                                                     placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditors[i].audit_id %>_add"></div>
-                                        <dl class="list-unstyled book-list" data-aid="<%- auditors[i].audit_id %>" data-operate="add">
+                                                                     placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditor.audit_id %>_add"></div>
+                                        <dl class="list-unstyled book-list" data-aid="<%- auditor.audit_id %>" data-operate="add">
                                             <% accountGroup.forEach((group, idx) => { %>
                                                 <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 !== ctx.tender.user_id) { %>
-                                                            <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>
-                                                        <% } %>
+                                                        <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>
                                                     <% });%>
                                                 </div>
                                             <% }) %>
                                         </dl>
                                     </div>
                                     </span>
-                                            <% } %>
-                                            <% if (auditors[i].status === auditConst.status.uncheck) { %>
-                                                <span class="dropdown mr-2">
-                                    <a href="javascript: void(0)" class="add-audit" id="<%- auditors[i].audit_id %>_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>
-                                        <div class="dropdown-menu dropdown-menu-right" id="<%- auditors[i].audit_id %>_add_dropdownMenu" aria-labelledby="<%- auditors[i].audit_id %>_add_dropdownMenuButton" style="width:220px">
+                                                <% } %>
+                                                <% if (auditor.status === auditConst.status.uncheck) { %>
+                                                    <% if (j === group.length - 1) { %>
+                                                        <span class="dropdown mr-2">
+                                    <a href="javascript: void(0)" class="add-audit" id="<%- auditor.audit_id %>_add_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">增加</a>
+                                        <div class="dropdown-menu dropdown-menu-right" id="<%- auditor.audit_id %>_add_dropdownMenu" aria-labelledby="<%- auditor.audit_id %>_add_dropdownMenuButton" style="width:220px">
+                                            <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"
+                                                                         placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditor.aid %>_add"></div>
+                                            <dl class="list-unstyled book-list" data-aid="<%- auditor.audit_id %>" data-operate="add">
+                                                <% accountGroup.forEach((group, idx) => { %>
+                                                    <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 => { %>
+                                                            <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>
+                                                        <% });%>
+                                                    </div>
+                                                <% }) %>
+                                            </dl>
+                                        </div>
+                                    </span>
+                                                        <% if (auditor.audit_type !== auditType.key.common) { %>
+                                                            <span class="dropdown mr-2">
+                                    <a href="javascript: void(0)" class="add-audit" id="<%- auditor.audit_id %>_add-sibling_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">平级</a>
+                                        <div class="dropdown-menu dropdown-menu-right" id="<%- auditor.audit_id %>_add-sibling_dropdownMenu" aria-labelledby="<%- auditor.audit_id %>_add-sibling_dropdownMenuButton" style="width:220px">
                                             <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"
-                                                                         placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditors[i].audit_id %>_add"></div>
-                                            <dl class="list-unstyled book-list" data-aid="<%- auditors[i].audit_id %>" data-operate="add">
+                                                                         placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditor.audit_id %>_add-sibling"></div>
+                                            <dl class="list-unstyled book-list" data-aid="<%- auditor.audit_id %>" data-operate="add-sibling">
                                                 <% accountGroup.forEach((group, idx) => { %>
                                                     <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 !== ctx.tender.user_id) { %>
-                                                                <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>
-                                                            <% } %>
+                                                            <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>
                                                         <% });%>
                                                     </div>
                                                 <% }) %>
                                             </dl>
                                         </div>
                                     </span>
-                                                <span class="dropdown mr-2">
-                                        <a href="javascript: void(0)" class="change-audit" id="<%- auditors[i].audit_id %>_change_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更换</a>
-                                        <div class="dropdown-menu dropdown-menu-right" id="<%- auditors[i].audit_id %>_change_dropdownMenu" aria-labelledby="<%- auditors[i].audit_id %>_change_dropdownMenuButton" style="width:220px">
+                                                        <% } %>
+                                                    <% } %>
+                                                    <span class="dropdown mr-2">
+                                        <a href="javascript: void(0)" class="change-audit" id="<%- auditor.audit_id %>_change_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更换</a>
+                                        <div class="dropdown-menu dropdown-menu-right" id="<%- auditor.audit_id %>_change_dropdownMenu" aria-labelledby="<%- auditor.audit_id %>_change_dropdownMenuButton" style="width:220px">
                                             <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"
-                                                                         placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditors[i].audit_id %>_change"></div>
-                                            <dl class="list-unstyled book-list" data-aid="<%- auditors[i].audit_id %>" data-operate="change">
+                                                                         placeholder="姓名/手机 检索" autocomplete="off" data-code="<%- auditor.audit_id %>_change"></div>
+                                            <dl class="list-unstyled book-list" data-aid="<%- auditor.audit_id %>" data-operate="change">
                                                 <% accountGroup.forEach((group, idx) => { %>
                                                     <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 !== ctx.tender.user_id) { %>
-                                                                <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>
-                                                            <% } %>
+                                                            <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>
                                                         <% });%>
                                                     </div>
                                                 <% }) %>
                                             </dl>
                                         </div>
                                     </span>
-                                                <span class="dropdown">
+                                                    <span class="dropdown">
                                     <a href="javascript: void(0)" class="text-danger" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">移除</a>
                                     <div class="dropdown-menu">
                                         <span class="dropdown-item" href="javascript:void(0);">确认移除审批人?</span>
                                         <div class="dropdown-divider"></div>
                                         <div class="px-2 py-1 text-center">
-                                            <button class="remove-audit btn btn-sm btn-danger" data-id="<%- auditors[i].audit_id %>">移除</button>
+                                            <button class="remove-audit btn btn-sm btn-danger" data-id="<%- auditor.audit_id %>">移除</button>
                                             <button class="btn btn-sm btn-secondary">取消</button>
                                         </div>
                                     </div>
                                     </span>
-                                            <% } %>
-                                        </td>
-                                    </tr>
+                                                <% } %>
+                                            </td>
+                                        </tr>
+                                    <% } %>
                                 <% } %>
+                                </tbody>
                             </table>
                         </div>
                     </div>

+ 2 - 1
app/view/ledger/explode.ejs

@@ -361,6 +361,7 @@
     const tenderInfo = JSON.parse(unescape('<%- escape(JSON.stringify(tenderInfo)) %>'));
     const thousandth = <%- ctx.tender.info.display.thousandth %>;
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
     let attData = JSON.parse(unescape('<%- escape(JSON.stringify(attData)) %>'));
     const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
     const measureType = JSON.parse('<%- JSON.stringify(measureType) %>');
@@ -397,6 +398,6 @@
 <script>
     const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
     const accountGroup = JSON.parse('<%- JSON.stringify(accountGroup) %>');
-    const auditorList = JSON.parse(unescape('<%- escape(JSON.stringify(auditors)) %>'));
+    let auditorList = JSON.parse(unescape('<%- escape(JSON.stringify(auditors)) %>'));
 </script>
 <% } %>

+ 2 - 2
app/view/ledger/explode_modal.ejs

@@ -158,7 +158,7 @@
                         审批流程
                     </div>
                     <div class="modal-height-500" style="overflow: auto">
-                    <ul class="list-group list-group-flush" id="auditors">
+                    <ul class="list-group list-group-flush auditors-list" id="auditors">
                         <% for (let i = 0, iLen = tender.auditorGroups.length; i < iLen; i++) { %>
                         <li class="list-group-item d-flex" auditorId="<%- tender.auditorGroups[i][0].audit_id %>">
                             <div class="col-auto"><%- i+1 %></div>
@@ -299,7 +299,7 @@
                                     </div>
                                 </li>
                                 <% } %>
-                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1 && tender.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === tender.auditHistory.length - 1) { %>is_uncheck<% } %>">
                                     <% if (group.endYear) { %>
                                     <div class="timeline-item-date">
                                         <%- group.endYear %>

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

@@ -10,7 +10,7 @@
                 <% if (ctx.session.sessionProject.page_show.openSettle) { %>
                 <a href="/tender/<%= ctx.tender.id %>/settle" class="btn btn-primary btn-sm">计量结算</a>
                 <% } %>
-                <% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && ctx.tender.data.ledger_status === auditConst.status.checked) { %>
+                <% if ((ctx.session.sessionUser.accountId === ctx.tender.data.user_id || ctx.tender.userAssistsId.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.tender.data.ledger_status === auditConst.status.checked) { %>
                     <% if (!ctx.session.sessionProject.page_show.close1stStageCheckDealParam && ctx.helper.checkZero(ctx.tender.info.deal_param.contractPrice) && stages.length === 0) { %>
                         <a href="#add-qi" data-toggle="modal" data-target="#tips" class="btn btn-primary btn-sm">开始新一期</a>
                     <% } else { %>

+ 3 - 3
app/view/measure/stage_modal.ejs

@@ -1,4 +1,4 @@
-<% if (ctx.session.sessionUser.accountId === ctx.tender.data.user_id && ctx.tender.data.ledger_status === auditConst.status.checked) { %>
+<% if ((ctx.session.sessionUser.accountId === ctx.tender.data.user_id || ctx.tender.userAssistsId.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.tender.data.ledger_status === auditConst.status.checked) { %>
 <!--弹出填写合同参数-->
 <div class="modal fade" id="tips" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -61,7 +61,7 @@
                             </ul>
                         </div>
                     </div>
-                    <div class="col-8 modal-height-500" style="overflow: auto" id="audit-list">
+                    <div class="col-8 modal-height-500 scroll-y"id="audit-list">
                     </div>
                 </div>
             </div>
@@ -106,7 +106,7 @@
 <script src="/public/js/datepicker/datepicker.min.js"></script>
 <script src="/public/js/datepicker/datepicker.zh.js"></script>
 <script>
-    <% if (stages.length > 0 && stages[0].user_id === ctx.session.sessionUser.accountId) { %>
+    <% if (stages.length > 0 && stages[0].user_id === ctx.session.sessionUser.accountId ) { %>
     $(function () {
        $('.edit-stage').on('click', function () {
            const index = parseInt($(this).data('index'));

+ 105 - 115
app/view/revise/history_modal.ejs

@@ -9,162 +9,152 @@
                 <div class="row">
                     <div class="col-4">
                         <div class="card mt-3">
-                            <ul class="list-group list-group-flush">
-                                <% auditors.forEach((item, idx) => { %>
+                            <ul class="list-group list-group-flush"  id="auditors-list">
+                                <% revise.userGroups.forEach((item, idx) => { %>
                                 <% if (idx === 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-play-circle fa-rotate-90"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">原报</span>
+                                <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">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </span>
+                                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
                                 </li>
-                                <% } else if(idx === auditors.length -1 && idx !== 0) { %>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa fa-stop-circle"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right">终审</span>
+                                <% } else if(idx === revise.userGroups.length -1 && idx !== 0) { %>
+                                <li class="list-group-item d-flex justify-content-between align-items-center">
+                                    <span class="mr-1"><i class="fa fa fa-stop-circle"></i></span>
+                                    <span class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </span>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%-  auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small>终审</small></span>
+                                    </div>
                                 </li>
                                 <% } else {%>
-                                <li class="list-group-item" data-auditorId="<%- item.audit_id %>">
-                                    <i class="fa fa-chevron-circle-down"></i> <%- item.name %>
-                                    <small class="text-muted"><%- item.role %></small>
-                                    <span class="pull-right"><%= ctx.helper.transFormToChinese(idx) %>审</span>
+                                <li class="list-group-item d-flex justify-content-between align-items-center">
+                                    <span class="mr-1"><i class="fa fa-chevron-circle-down"></i></span>
+                                    <span class="text-muted">
+                                        <% for (const u of item) { %>
+                                        <small class="d-inline-block text-dark mx-1" title="<%- u.role %>" data-auditorId="<%- u.audit_id %>"><%- u.name %></small>
+                                        <% } %>
+                                    </span>
+                                    <div class="d-flex ml-auto">
+                                        <% if (item[0].audit_type !== auditType.key.common) { %>
+                                        <span class="badge badge-pill badge-<%- auditType.info[item[0].audit_type].class %> p-1"><small><%- auditType.info[item[0].audit_type].short %></small></span>
+                                        <% } %>
+                                        <span class="badge badge-light badge-pill"><small><%= ctx.helper.transFormToChinese(idx) %>审</small></span>
+                                    </div>
                                 </li>
                                 <% } %>
                                 <% }) %>
                             </ul>
                         </div>
                     </div>
-                    <div class="col-8 modal-height-500" style="overflow: auto">
-                        <% auditHistory.forEach((auditors, idx) => { %>
-                            <!-- 展开/收起历史流程 -->
-                        <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
-                            <div class="text-right">
-                                <a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a>
-                            </div>
+                    <div class="col-8 modal-height-500 scroll-y">
+                        <% revise.auditHistory.forEach((his, idx) => { %>
+                        <!-- 展开/收起历史流程 -->
+                        <% if(idx === revise.auditHistory.length - 1 && revise.auditHistory.length !== 1) { %>
+                        <div class="text-right">
+                            <a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a>
+                        </div>
                         <% } %>
-                        <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
+                        <div class="<%- idx < revise.auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
-                            <ul class="timeline-list list-unstyled mt-2">
-                                <% auditors.forEach((auditor, index) => { %>
+                            <ul class="timeline-list list-unstyled mt-2 <% if (idx === revise.auditHistory.length - 1) { %>last-auditor-list<% } %>">
+                                <% his.forEach((group, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.begin_time) %>
+                                        <%- 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-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
                                     <div class="timeline-item-content">
-                                        <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span
-                                                            class="h5"><%- user.name %></span><span
-                                                            class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- user.role %></p>
-                                                </div>
-                                            </div>
+                                        <div class="py-1">
+                                            <span class="text-black-50">原报</span>
+                                            <span class="pull-right text-success"><%- idx !== 0 ? '重新' : '' %>上报审批</span>
                                         </div>
-                                    </div>
-                                </li>
-                                <li class="timeline-list-item pb-2">
-                                    <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
-                                    </div>
-                                    <% if(index < auditors.length - 1) { %>
-                                    <div class="timeline-item-tail"></div>
-                                    <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
-                                    <% } else {%>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
-                                    <% } %>
-                                    <div class="timeline-item-content">
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span><span
-                                                            class="pull-right <%- auditConst.statusClass[auditor.status] %>"><%- auditConst.statusString[auditor.status] %></span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <div class="card-text p-2 py-3 row">
+                                                    <div class="col">
+                                                        <span class="h6"><%- revise.user.name %></span>
+                                                        <span class="text-muted ml-1"><%- revise.user.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                    </div>
                                                 </div>
                                             </div>
-
-                                            <!--审批意见-->
-                                            <% if (auditor.opinion) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } else {%>
-                                <li class="timeline-list-item pb-2">
+                                <% } %>
+                                <li class="timeline-list-item pb-2 <% if (group.status === auditConst.status.uncheck && idx === revise.auditHistory.length - 1 && revise.auditHistory.length !== 1) { %>is_uncheck<% } %>">
+                                    <% if (group.endYear) { %>
                                     <div class="timeline-item-date">
-                                        <%- ctx.helper.formatDate(auditor.end_time) %>
+                                        <%- group.endYear %>
+                                        <span><%- group.endDate %></span>
+                                        <span><%- group.endTime %></span>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% } %>
+                                    <% if (index < his.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
-                                    <% if(auditor.status === auditConst.status.checked) { %>
-                                    <div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {%>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>
-                                    <% } else if(auditor.status === auditConst.status.checking) { %>
-                                    <div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>
+                                    <% if (group.status === auditConst.status.checked) { %>
+                                    <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.checkNoPre || group.status === auditConst.status.checkCancel) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>
+                                    <% } else if (group.status === auditConst.status.checking) { %>
+                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>
                                     <% } else { %>
-                                    <div class="timeline-item-icon bg-secondary text-light">
-                                    </div>
+                                    <div class="timeline-item-icon bg-secondary text-light"></div>
                                     <% } %>
                                     <div class="timeline-item-content">
+                                        <div class="py-1">
+                                            <span class="text-black-50">
+                                                <%- (!group.is_final ? group.audit_order : '终') %>审
+                                                <% if (group.audit_type !== auditType.key.common) { %><span class="text-<%- auditType.info[group.audit_type].class %> "><%- auditType.info[group.audit_type].long %></span><% } %>
+                                            </span>
+                                            <% if (group.status !== auditConst.status.uncheck) { %>
+                                            <span class="pull-right <%- auditConst.statusClass[group.status] %>"><%- auditConst.statusString[group.status] %></span>
+                                            <% } %>
+                                        </div>
                                         <div class="card">
-                                            <div class="card-body p-3">
-                                                <div class="card-text">
-                                                    <p class="mb-1"><span class="h5"><%- auditor.name %></span>
-                                                        <span
-                                                            class="pull-right
-                                                                            <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
-                                                            <%- auditor.status === auditConst.status.checkNo ? user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
-                                                        </span>
-                                                    </p>
-                                                    <p class="text-muted mb-0"><%- auditor.role %></p>
+                                            <div class="card-body px-3 py-0">
+                                                <% for (const [i, auditor] of group.auditors.entries()) { %>
+                                                <div class="card-text p-2 py-3 row <%- ( i > 0 ? 'border-top' : '') %>">
+                                                    <div class="col">
+                                                        <span class="h6"><%- auditor.name %></span>
+                                                        <span class="text-muted ml-1"><%- auditor.role %></span>
+                                                    </div>
+                                                    <div class="col">
+                                                        <% if (auditor.status === auditConst.status.checked) { %>
+                                                        <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                        <% } else if (auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre || auditor.status === auditConst.status.checkCancel) { %>
+                                                        <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                        <% } %>
+                                                    </div>
+                                                    <% if (auditor.opinion) { %>
+                                                    <div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i><%- auditor.opinion%></div>
+                                                    <% } %>
                                                 </div>
+                                                <% } %>
                                             </div>
-                                            <!--审批意见-->
-                                            <% if (auditor.opinion) { %>
-                                            <div class="card-body p-3 border-top">
-                                                <p style="margin: 0;"><%- auditor.opinion %></p>
-                                            </div>
-                                            <% } %>
                                         </div>
                                     </div>
                                 </li>
-                                <% } %>
                                 <% }) %>
                             </ul>
                         </div>
-
                         <% }) %>
                     </div>
                 </div>

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

@@ -261,4 +261,5 @@
     const settleStatus = JSON.parse('<%- JSON.stringify(settleStatus) %>');
     const tenderName = '<%- ctx.tender.name %>';
     const reviseComplete = <%- ctx.revise.status === audit.status.checked %>;
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
 </script>

+ 4 - 3
app/view/revise/info_modal.ejs

@@ -747,10 +747,11 @@
                         }
                         html.push('</div>');
                         html.push('<div class="col-auto">');
-                        // todo 添加会签或签时
-                        // html.push('<span class="badge badge-pill badge-primary badge-bg-small"><small></small></span>');
+                        if (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>`);
+                        }
                         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('<a href="javascript: void(0)" class="text-danger pull-right ml-1">移除</a>');
                         }
                         html.push('</div>');
                         html.push('</li>');

+ 108 - 162
app/view/revise/modal.ejs

@@ -48,21 +48,13 @@
 </div>
 <!--审批流程/结果-->
 <div class="modal fade" id="sp-list" data-backdrop="static">
-    <div class="modal-dialog modal-lg" role="document">
+    <div class="modal-dialog" 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">
-                        <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 class="modal-height-500 scroll-y" style="overflow: auto" id="audit-list">
                 </div>
             </div>
             <div class="modal-footer">
@@ -100,6 +92,7 @@
 <% } %>
 
 <script>
+    const auditType = JSON.parse('<%- JSON.stringify(auditType) %>');
     let dbClickFlag = true;
     function dbClick() {
         if(dbClickFlag){
@@ -111,164 +104,117 @@
     const auditConst = JSON.parse('<%- auditConst2 %>');
 
     $(function () {
+        const getAuditTypeText = function (type) {
+            if (type === auditType.key.common) return '';
+            return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
+        };
+        const loadStageHistory = function (result, auditConst2) {
+            const { auditHistory, user } = result;
+            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 pr-1 ${ 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 === auditConst2.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 === auditConst2.status.checked) {
+                        historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
+                    } else if (group.status === auditConst2.status.checkNo || group.status === auditConst2.status.checkNoPre || group.status === auditConst2.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 === auditConst2.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 === auditConst2.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">');
+                    const statuStr = group.status !== auditConst2.status.uncheck ?
+                        `<span class="pull-right ${auditConst2.auditStringClass[group.status]}">${auditConst2.statusString[group.status]}</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>`);
+                    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 === auditConst2.status.checked) {
+                            historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
+                        } if (auditor.status === auditConst2.status.checkNo || auditor.status === auditConst2.status.checkNoPre || auditor.status === auditConst2.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 === auditConst2.status.checking) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>');
+                        }  else if (auditor.status === auditConst2.status.checkAgain) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-check-circle"></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(''));
+        }
         // 获取审批流程
         $('a[data-target="#sp-list"]').on('click', function () {
             const data = {
                 id: $(this).attr('lr-id'),
             };
             postData('<%- preUrl + "/revise/auditors" %>', data, function (result) {
-                const { auditHistory, auditors, user } = result
-                let auditorsHTML = ''
-                let historyHTML = ''
-                auditors.forEach((auditor, idx) => {
-                    if (idx === 0) {
-                        auditorsHTML += `<li class="list-group-item">
-                            <i class="fa fa fa-play-circle fa-rotate-90"></i> ${auditor.name}
-                            <small class="text-muted">${auditor.role}</small>
-                            <span class="pull-right">原报</span>
-                        </li>`
-                    } else if(idx === auditors.length -1 && idx !== 0) {
-                        auditorsHTML += `<li class="list-group-item">
-                            <i class="fa fa fa-stop-circle"></i> ${auditor.name}
-                            <small class="text-muted">${auditor.role}</small>
-                            <span class="pull-right">终审</span>
-                        </li>`
-                    } else {
-                        auditorsHTML += `<li class="list-group-item">
-                            <i class="fa fa-chevron-circle-down"></i> ${auditor.name}
-                            <small class="text-muted">${auditor.role}</small>
-                            <span class="pull-right">${transFormToChinese(idx)}审</span>
-                        </li>`
-                    }
-                })
-                $('#auditor-list').empty()
-                $('#auditor-list').append(auditorsHTML)
-                auditHistory.forEach((auditors, idx) => {
-                    if(idx === auditHistory.length - 1 && auditHistory.length !== 1) {
-                        historyHTML += `<div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a></div>`
-                    }
-                    historyHTML += `<div class="${idx < auditHistory.length - 1 ? 'fold-card' : ''}">
-                    <div class="text-center text-muted">${idx + 1}#</div>
-                    <ul class="timeline-list list-unstyled mt-2">`
-                    auditors.forEach((auditor, index) => {
-                        if (index === 0) {
-                            historyHTML += `<li class="timeline-list-item pb-2">
-                                <div class="timeline-item-date">
-                                    ${formatDate(auditor.begin_time)}
-                                </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="card">
-                                        <div class="card-body p-3">
-                                            <div class="card-text">
-                                                <p class="mb-1"><span
-                                                        class="h5">${user.name}</span><span
-                                                        class="pull-right text-success">${idx !== 0 ? '重新' : ''}上报审批</span>
-                                                </p>
-                                                <p class="text-muted mb-0">${user.role}</p>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                            </li>
-                            <li class="timeline-list-item pb-2">
-                                <div class="timeline-item-date">
-                                    ${formatDate(auditor.end_time)}
-                                </div>`
-
-                                if(index < auditors.length - 1) {
-                                    historyHTML += `<div class="timeline-item-tail"></div>`
-                                }
-                                if(auditor.status === auditConst.status.checked) {
-                                    historyHTML += `<div class="timeline-item-icon bg-success text-light">
-                                        <i class="fa fa-check"></i>
-                                    </div>`
-
-                                } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {
-                                    historyHTML += `<div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-level-up"></i>
-                                    </div>`
-                                } else if(auditor.status === auditConst.status.checking) {
-                                    historyHTML += `<div class="timeline-item-icon bg-warning text-light">
-                                        <i class="fa fa-ellipsis-h"></i>
-                                    </div>`
-                                } else {
-                                    historyHTML += `<div class="timeline-item-icon bg-secondary text-light"></div>`
-
-                                }
-                                historyHTML += `<div class="timeline-item-content">
-                                    <div class="card">
-                                        <div class="card-body p-3">
-                                            <div class="card-text">
-                                                <p class="mb-1"><span class="h5">${auditor.name}</span><span
-                                                        class="pull-right ${auditConst.statusClass[auditor.status]}">${auditConst.statusString[auditor.status]}</span>
-                                                </p>
-                                                <p class="text-muted mb-0">${auditor.role}</p>
-                                            </div>
-                                        </div>`
-                                if (auditor.opinion) {
-                                historyHTML += `<div class="card-body p-3 border-top">
-                                        <p style="margin: 0;">${auditor.opinion}</p>
-                                    </div>`
-                                }
-                                historyHTML += `</div></div></li>`
-                        } else {
-                            historyHTML += `<li class="timeline-list-item pb-2">
-                            <div class="timeline-item-date">
-                                ${formatDate(auditor.end_time)}
-                            </div>`
-
-                            if(index < auditors.length - 1) {
-                                historyHTML += `<div class="timeline-item-tail"></div>`
-                            }
-                            if(auditor.status === auditConst.status.checked) {
-                                historyHTML += `<div class="timeline-item-icon bg-success text-light">
-                                    <i class="fa fa-check"></i>
-                                </div>`
-                            } else if(auditor.status === auditConst.status.checkNo || auditor.status === auditConst.status.checkNoPre) {
-                                historyHTML += `<div class="timeline-item-icon bg-warning text-light">
-                                    <i class="fa fa-level-up"></i>
-                                </div>`
-
-                            } else if(auditor.status === auditConst.status.checking) {
-                                historyHTML += `<div class="timeline-item-icon bg-warning text-light">
-                                    <i class="fa fa-ellipsis-h"></i>
-                                </div>`
-                            } else {
-                                historyHTML += `<div class="timeline-item-icon bg-secondary text-light"></div>`
-                            }
-                            historyHTML += `<div class="timeline-item-content">
-                            <div class="card">
-                                <div class="card-body p-3">
-                                    <div class="card-text">
-                                        <p class="mb-1"><span class="h5">${auditor.name}</span>
-                                            <span
-                                                class="pull-right
-                                                                ${auditConst.statusClass[auditor.status]}">${auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''}
-                                                ${auditor.status === auditConst.status.checkNo ? user.name : ''}
-                                                ${auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : ''}
-                                            </span>
-                                        </p>
-                                        <p class="text-muted mb-0">${auditor.role}</p>
-                                    </div>
-                                </div>`
-
-                            if (auditor.opinion) {
-                            historyHTML += `<div class="card-body p-3 border-top">
-                                <p style="margin: 0;">${auditor.opinion} </p>
-                            </div>`
-                            }
-                            historyHTML += `</div></div></li>`
-                        }
-                    })
-                    historyHTML += '</ul></div>'
-
-                })
-                $('#audit-list').empty()
-                $('#audit-list').append(historyHTML)
+                loadStageHistory(result, auditConst)
             })
         });
     });

+ 7 - 1
app/view/setting/fun.ejs

@@ -58,10 +58,15 @@
                                 <h5 class="card-title">合同支付</h5>
                                 <div class="form-group mb-4">
                                     <div>
-                                        <div class="form-check form-check-inline">
+                                        <div class="form-check">
                                             <input class="form-check-input" type="checkbox" id="lockPayExpr" name="lockPayExpr" <% if (funRela.lockPayExpr) { %>checked<% } %> onchange="updateSetting();">
                                             <label class="form-check-label" for="lockPayExpr">锁定往期带基数计算的合同支付项</label>
                                         </div>
+                                        <div class="form-check">
+                                            <input class="form-check-input" type="checkbox" id="showMinusCol" name="showMinusCol" <% if (funRela.showMinusCol) { %>checked<% } %> onchange="updateSetting();">
+                                            <label class="form-check-label" for="showMinusCol">显示扣款列</label>
+                                        </div>
+                                        <div class="alert-warning p-1"><i class="fa Example of exclamation-circle fa-exclamation-circle "></i> 隐藏此列不会修改本期应付计算,旧项目请谨慎修改,防止误解</div>
                                     </div>
                                 </div>
                             </div>
@@ -458,6 +463,7 @@
             banMinusChangeBills: $('[name=ban_minus_cb]')[0].checked,
             minusNoValue: $('[name=minusNoValue]')[0].checked,
             lockPayExpr: $('#lockPayExpr')[0].checked,
+            showMinusCol: $('#showMinusCol')[0].checked,
             needGcl: $('#need_gcl')[0].checked,
             openChangeProject: $('#openChangeProject')[0].checked,
             openChangeApply: $('#openChangeApply')[0].checked,

+ 1 - 0
app/view/stage/pay.ejs

@@ -70,5 +70,6 @@
     const preGatherTp = <%- (pre.gather_tp || 0) %>;
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
     const lockPayExpr = <%- lockPayExpr %>;
+    const showMinusCol = <%- showMinusCol %>;
     const deleteFilePermission = <%- deleteFilePermission %>;
 </script>

+ 0 - 1
app/view/tender/modal.ejs

@@ -202,7 +202,6 @@
                 historyHTML.push(`<div class="text-center text-muted">${idx+1}#</div>`);
                 historyHTML.push(`<ul class="timeline-list list-unstyled mt-2 pr-1 ${ idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'last-auditor-list' : '' }">`);
                 his.forEach((group, index) => {
-                    console.log(group);
                     if (index === 0) {
                         historyHTML.push(`<li class="timeline-list-item pb-2">
                                             <div class="timeline-item-date">