瀏覽代碼

资金支付审批增加重新审批功能

ellisran 2 周之前
父節點
當前提交
c7cf4ae09b

+ 9 - 9
app/const/audit.js

@@ -1269,7 +1269,7 @@ const financial = (function() {
         // checkNo: 4,     // 审批终止
         checkNo: 5, // 退回到原报人重新上报
         // checkNoPre: 6, // 退回到上一个审批人
-        // checkAgain: 7, // 重新审批
+        checkAgain: 7, // 重新审批
         checkSkip: 8, // 跳过
         // revise: 9, // 修订变更
         // cancelRevise: 10, // 撤销修订
@@ -1281,7 +1281,7 @@ const financial = (function() {
     statusString[status.checked] = '审批通过';
     statusString[status.checkNo] = '审批退回';
     // statusString[status.checkNoPre] = '审批退回';
-    // statusString[status.checkAgain] = '重新审批';
+    statusString[status.checkAgain] = '重新审批';
     // statusString[status.revise] = '修订';
     // statusString[status.cancelRevise] = '撤销修订';
     // statusString[status.checkCancel] = '撤回';
@@ -1292,7 +1292,7 @@ const financial = (function() {
     statusClass[status.checked] = 'text-success';
     statusClass[status.checkNo] = 'text-warning';
     // statusClass[status.checkNoPre] = 'text-warning';
-    // statusClass[status.checkAgain] = 'text-warning';
+    statusClass[status.checkAgain] = 'text-warning';
     // statusClass[status.revise] = 'text-warning';
     // statusClass[status.cancelRevise] = 'text-success';
     // statusClass[status.checkCancel] = 'text-warning';
@@ -1305,7 +1305,7 @@ const financial = (function() {
     auditString[status.checked] = '审批通过';
     auditString[status.checkNo] = '审批退回';
     // auditString[status.checkNoPre] = '审批退回';
-    // auditString[status.checkAgain] = '重新审批';
+    auditString[status.checkAgain] = '重新审批';
     // auditString[status.revise] = '修订';
     // auditString[status.cancelRevise] = '撤销修订';
     // auditString[status.checkCancel] = '撤回';
@@ -1317,7 +1317,7 @@ const financial = (function() {
     auditStringClass[status.checked] = 'text-success';
     auditStringClass[status.checkNo] = 'text-warning';
     // auditStringClass[status.checkNoPre] = 'text-warning';
-    // auditStringClass[status.checkAgain] = 'text-warning';
+    auditStringClass[status.checkAgain] = 'text-warning';
     // auditStringClass[status.revise] = 'text-warning';
     // auditStringClass[status.cancelRevise] = 'text-success';
     // auditStringClass[status.checkCancel] = 'text-warning';
@@ -1328,8 +1328,8 @@ const financial = (function() {
     auditProgress[status.checking] = '审批中';
     auditProgress[status.checked] = '审批通过';
     auditProgress[status.checkNo] = '审批退回';
-    auditProgress[status.checkNoPre] = '审批退回';
-    // auditProgress[status.checkAgain] = '重新审批';
+    // auditProgress[status.checkNoPre] = '审批退回';
+    auditProgress[status.checkAgain] = '重新审批';
     // auditProgress[status.revise] = '修订中';
     // auditProgress[status.cancelRevise] = '撤销修订';
     // auditProgress[status.checkCancel] = '撤回';
@@ -1340,8 +1340,8 @@ const financial = (function() {
     auditProgressClass[status.checking] = 'text-warning';
     auditProgressClass[status.checked] = 'text-success';
     auditProgressClass[status.checkNo] = 'text-warning';
-    auditProgressClass[status.checkNoPre] = 'text-warning';
-    // auditProgressClass[status.checkAgain] = 'text-warning';
+    // auditProgressClass[status.checkNoPre] = 'text-warning';
+    auditProgressClass[status.checkAgain] = 'text-warning';
     // auditProgressClass[status.revise] = 'text-warning';
     // auditProgressClass[status.cancelRevise] = 'text-success';
     // auditProgressClass[status.checkCancel] = 'text-warning';

+ 53 - 0
app/controller/financial_controller.js

@@ -781,6 +781,8 @@ module.exports = app => {
                 await this._getFinancialAuditViewData(ctx);
                 // 获取附件列表
                 const fileList = await ctx.service.financialPayAtt.getAtt(ctx.financialPay.id);
+                const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+                const auth_mobile = pa.auth_mobile;
                 const renderData = {
                     financialPermission: ctx.financialPay.permission,
                     financialPay: ctx.financialPay,
@@ -791,6 +793,7 @@ module.exports = app => {
                     whiteList: ctx.app.config.multipart.whitelist,
                     moment,
                     fileList,
+                    authMobile: auth_mobile,
                     preUrl: `/sp/${ctx.subProject.id}/financial/pay`,
                     preUrl2: `/sp/${ctx.subProject.id}/financial/pay/` + ctx.financialPay.id,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.financial.payDetail),
@@ -860,6 +863,56 @@ module.exports = app => {
             }
         }
 
+        /**
+         * 变更立项重新审批
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async checkPayAgain(ctx) {
+            try {
+                // 获取终审
+                // const auditInfo = await this.ctx.service.changeProjectAudit.getAuditorByStatus(ctx.change.id, audit.changeProject.status.checked);
+                // if (ctx.change.status !== audit.changeProject.status.checked || ctx.session.sessionUser.accountId !== auditInfo.aid) {
+                if (ctx.financialPay.status !== auditConst.financial.status.checked) {
+                    throw '您无权进行该操作';
+                }
+                if (ctx.session.sessionUser.loginStatus === 0) {
+                    const code = ctx.request.body.code;
+                    const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+                    if (!pa.auth_mobile) {
+                        throw '未绑定手机号';
+                    }
+                    const cacheKey = 'smsCode:' + ctx.session.sessionUser.accountId;
+                    const cacheCode = await app.redis.get(cacheKey);
+                    // console.log(cacheCode);
+                    if (cacheCode === null || code === undefined || cacheCode !== (code + pa.auth_mobile)) {
+                        throw '验证码不正确!';
+                    }
+                }
+                if ((ctx.financialPay.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) && ctx.financialPay.status === auditConst.financial.status.checked) {
+                    // 重新审批
+                    const result = await ctx.service.financialPayAudit.checkAgain(ctx.financialPay);
+                    if (!result) {
+                        throw '重新审批失败';
+                    }
+                } else {
+                    throw '您无权进行该操作';
+                }
+                ctx.body = {
+                    err: 0,
+                    url: ctx.request.header.referer,
+                    msg: '',
+                };
+            } catch (err) {
+                console.log(err);
+                ctx.body = {
+                    err: 1,
+                    // url: ctx.request.header.referer,
+                    msg: err,
+                };
+            }
+        }
+
         async payDetailSave(ctx) {
             try {
                 const responseData = {

+ 4 - 0
app/public/js/financial_pay.js

@@ -853,6 +853,8 @@ $(function () {
                         historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>');
                     } else if (group.status === auditConst.status.checking) {
                         historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
+                    } else if (group.status === auditConst.status.checkAgain) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>');
                     } else {
                         historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
                     }
@@ -878,6 +880,8 @@ $(function () {
                             historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
                         } else if (auditor.status === auditConst.status.checking) {
                             historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>');
+                        } else if (auditor.status === auditConst.status.checkAgain) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-check"></i></span>');
                         }
                         historyHTML.push('</div>');
                         if (auditor.opinion) {

+ 1 - 0
app/router.js

@@ -440,6 +440,7 @@ module.exports = app => {
     app.get('/sp/:id/financial/pay/:fpid/file/:fid/download', sessionAuth, subProjectCheck, financialCheck, financialPayCheck, 'financialController.payDownloadFile');
     app.post('/sp/:id/financial/pay/:fpid/audit/start', sessionAuth, subProjectCheck, financialCheck, financialPayCheck, financialPayAuditCheck, 'financialController.startPayAudit');
     app.post('/sp/:id/financial/pay/:fpid/audit/check', sessionAuth, subProjectCheck, financialCheck, financialPayCheck, 'financialController.checkPayAudit');
+    app.post('/sp/:id/financial/pay/:fpid/audit/check/again', sessionAuth, subProjectCheck, financialCheck, financialPayCheck, 'financialController.checkPayAgain');
     app.get('/sp/:id/financial/summary', sessionAuth, subProjectCheck, financialCheck, 'financialController.summary');
     app.post('/sp/:id/financial/summary/load', sessionAuth, subProjectCheck, financialCheck, 'financialController.summaryLoad');
 

+ 63 - 0
app/service/financial_pay_audit.js

@@ -458,6 +458,69 @@ module.exports = app => {
         }
 
         /**
+         * 重新审批变更申请
+         * @param { string } cid - 查询的清单
+         * @return {Promise<*>} - 可用的变更令列表
+         */
+        async checkAgain(fp) {
+            const accountId = this.ctx.session.sessionUser.accountId;
+            // 初始化事务
+            const time = new Date();
+            const transaction = await this.db.beginTransaction();
+            let result = false;
+            try {
+                const noYbAuditors = fp.auditors.filter(x => { return x.audit_order !== 0; });
+                const noYbMaxOrder = noYbAuditors[noYbAuditors.length - 1].order;
+                const maxOrder = fp.auditors[fp.auditors.length - 1].order;
+                const audits = fp.auditors.filter(x => { return x.order === noYbMaxOrder; });
+                if (!audits || audits.length === 0 || maxOrder < 1) throw '审核数据错误';
+                const selfAudit = audits.find(x => { return x.aid === accountId; });
+                if (!selfAudit) throw '当前标段您无权审批';
+                // 当前审批人2次添加至流程中
+                const checkAgainAuditors = [];
+                audits.forEach(x => {
+                    checkAgainAuditors.push({
+                        spid: fp.spid, tid: fp.tid, fpid: fp.id, aid: x.aid,
+                        times: x.times, order: maxOrder + 1,
+                        status: !selfAudit || x.aid === selfAudit.aid ? auditConst.status.checkAgain : auditConst.status.checkSkip,
+                        begin_time: time, end_time: time, opinion: '',
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                    });
+                });
+                const checkingAuditors = [];
+                audits.forEach(x => {
+                    checkingAuditors.push({
+                        spid: fp.spid, tid: fp.tid, fpid: fp.id, aid: x.aid,
+                        times: x.times, order: maxOrder + 2,
+                        status: auditConst.status.checking,
+                        begin_time: time,
+                        audit_type: x.audit_type, audit_order: x.audit_order,
+                    });
+                });
+                await transaction.insert(this.tableName, checkAgainAuditors);
+                const checkingAuditors_result = await transaction.insert(this.tableName, checkingAuditors);
+                // 获取刚批量添加的所有list
+                // for (let j = 0; j < checkingAuditors.length; j++) {
+                //     checkingAuditors[j].id = checkingAuditors_result.insertId + j;
+                // }
+
+                // 设置审批中
+                await transaction.update(this.ctx.service.financialPay.tableName, {
+                    id: fp.id,
+                    status: auditConst.status.checking,
+                    entities: '',
+                    final_auditor_str: '',
+                });
+                await transaction.commit();
+                result = true;
+            } catch (error) {
+                await transaction.rollback();
+                result = false;
+            }
+            return result;
+        }
+
+        /**
          * 获取审核人需要审核的期列表
          *
          * @param auditorId

+ 4 - 0
app/view/financial/pay_detail.ejs

@@ -34,6 +34,10 @@
                     <% } %>
                 <% } else if (financialPay.status === auditConst.status.checked) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-success btn-sm">审批完成</a>
+                    <% if (financialPay.auditors !== undefined && financialPay.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
+                        <!--重新审批-->
+                        <a href="#sp-down-back" data-toggle="modal" data-target="#sp-down-back" class="btn btn-warning btn-sm ml-2">重新审批</a>
+                    <% } %>
                 <% } else if (financialPay.status === auditConst.status.checkNo) { %>
                     <a href="#sp-list" data-type="hide" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-warning btn-sm text-muted sp-list-btn">审批<% if (financialPay.status === auditConst.status.checkNo) { %>退回<% } %></a>
                     <% if (ctx.session.sessionUser.accountId === financialPay.uid) { %>

+ 159 - 0
app/view/financial/pay_detail_modal.ejs

@@ -285,6 +285,8 @@
                                                     <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 if (group.status === auditConst.status.checkAgain) {%>
+                                                    <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>
                                                 <% } else { %>
                                                     <div class="timeline-item-icon bg-secondary text-light"></div>
                                                 <% } %>
@@ -311,6 +313,8 @@
                                                                             <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
                                                                         <% } else if (ctx.helper._.includes([auditConst.status.checkNo], auditor.status)) { %>
                                                                             <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                                        <% } else if(auditor.status === auditConst.status.checkAgain) {%>
+                                                                            <span class="pull-right text-warning"><i class="fa fa-check-circle"></i></span>
                                                                         <% } else if (auditor.status === auditConst.status.checking) { %>
                                                                             <span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>
                                                                         <% } %>
@@ -462,6 +466,8 @@
                                                         <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 if(group.status === auditConst.status.checkAgain) {%>
+                                                        <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>
                                                     <% } else { %>
                                                         <div class="timeline-item-icon bg-secondary text-light"></div>
                                                     <% } %>
@@ -488,6 +494,8 @@
                                                                                 <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
                                                                             <% } else if (ctx.helper._.includes([auditConst.status.checkNo], auditor.status)) { %>
                                                                                 <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                                            <% } else if (auditor.status === auditConst.status.checkAgain) {%>
+                                                                                <span class="pull-right text-warning"><i class="fa fa-check-circle"></i></span>
                                                                             <% } else if (auditor.status === auditConst.status.checking) { %>
                                                                                 <span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>
                                                                             <% } %>
@@ -640,6 +648,8 @@
                                                         <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 if(group.status === auditConst.status.checkAgain) {%>
+                                                        <div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>
                                                     <% } else { %>
                                                         <div class="timeline-item-icon bg-secondary text-light"></div>
                                                     <% } %>
@@ -666,6 +676,8 @@
                                                                                 <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
                                                                             <% } else if (ctx.helper._.includes([auditConst.status.checkNo], auditor.status)) { %>
                                                                                 <span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>
+                                                                            <% } else if(auditor.status === auditConst.status.checkAgain) {%>
+                                                                                <span class="pull-right text-warning"><i class="fa fa-check-circle"></i></span>
                                                                             <% } else if (auditor.status === auditConst.status.checking) { %>
                                                                                 <span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>
                                                                             <% } %>
@@ -707,7 +719,62 @@
         </div>
     <% } %>
 <% } %>
+<% if (financialPay.status === auditConst.status.checked && financialPay.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0) { %>
+    <% if (!authMobile && ctx.session.sessionUser.loginStatus === 0) { %>
+        <!--终审重新审批-->
+        <div class="modal fade" id="sp-down-back" data-backdrop="static">
+            <div class="modal-dialog" role="document">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">重新审批</h5>
+                    </div>
+                    <div class="modal-body">
+                        <h5>重新审批需要您的手机短信验证</h5>
+                        <h5>您目前还没设置认证手机,请先设置。</h5>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                        <a href="/profile/sms" class="btn btn-sm btn-primary">去设置</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    <% } else { %>
+        <!--重新审批-->
+        <div class="modal fade" id="sp-down-back" data-backdrop="static">
+            <div class="modal-dialog" role="document">
+                <form id="againForm" class="modal-content" method="post" action="<%- preUrl2 %>/audit/check/again" onsubmit="return false;">
+                    <div class="modal-header">
+                        <h5 class="modal-title">重新审批</h5>
+                    </div>
+                    <div class="modal-body">
+                        <h5>确认重新审批「<%= financialPay.code %>」?</h5>
+                        <% if (ctx.session.sessionUser.loginStatus === 0) { %>
+                            <div class="form-group">
+                                <label>重审需要验证码确认,验证码将发送至尾号<%- authMobile.slice(-4) %>的手机</label>
+                                <div class="input-group input-group-sm mb-3">
+                                    <input class="form-control" type="text" readonly="readonly" name="code" placeholder="输入短信中的6位验证码" />
+                                    <div class="input-group-append">
+                                        <button class="btn btn-outline-secondary get-code" type="button">获取验证码</button>
+                                    </div>
+                                </div>
+                            </div>
+                        <% } %>
+                    </div>
+                    <div class="modal-footer">
+                        <input type="hidden" name="fpid" value="<%= financialPay.id %>">
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                        <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                        <button type="button" id="re-shenpi-btn" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定重审</button>
+                    </div>
+                </form>
+            </div>
+        </div>
+    <% } %>
+<% } %>
 <script>
+    const csrf = '<%= ctx.csrf %>';
+    const authMobile = '<%= authMobile %>';
     $(function () {
         $('.sp-location-list').on('shown.bs.modal', function () {
             const scrollBox = $(this).find('div[class="col-8 modal-height-500"]');
@@ -754,5 +821,97 @@
                 $('.modal-title').text('重新上报')
             }
         });
+
+        $('#re-shenpi-btn').click(function () {
+            const data = {
+                fpid: parseInt('<%- financialPay.id %>'),
+            };
+            <% if (ctx.session.sessionUser.loginStatus === 0) { %>
+            const code = $("#againForm input[name='code']").val();
+            if ($(this).hasClass('disabled')) {
+                return false;
+            }
+            if (code.length < 6) {
+                // alert('请填写正确的验证码');
+                toastr.error('请填写正确的验证码');
+                return false;
+            }
+            data.code = code;
+            <% } %>
+            $.ajax({
+                url: '<%- preUrl2 %>/audit/check/again?_csrf_j=' + csrf,
+                type: 'post',
+                data: data,
+                dataTye: 'json',
+                success: function(response) {
+                    if (response.err === 0) {
+                        window.location.href = response.url;
+                    } else {
+                        toastr.error(response.msg);
+                    }
+                }
+            });
+        })
+
+        <% if (ctx.session.sessionUser.loginStatus === 0) { %>
+        // 重新审批获取手机验证码
+        // 获取验证码
+        let isPosting = false;
+        $(".get-code").on('click', function() {
+            if (isPosting) {
+                return false;
+            }
+            const btn = $(this);
+
+            $.ajax({
+                url: '/profile/code?_csrf_j=' + csrf,
+                type: 'post',
+                data: { mobile: authMobile, type: 'shenpi' },
+                dataTye: 'json',
+                error: function() {
+                    isPosting = false;
+                },
+                beforeSend: function() {
+                    isPosting = true;
+                },
+                success: function(response) {
+                    isPosting = false;
+                    if (response.err === 0) {
+                        codeSuccess(btn);
+                        $("input[name='code']").removeAttr('readonly');
+                        $("#re-shenpi-btn").removeAttr('disabled');
+                        // $("#re-shenpi-btn2").removeAttr('disabled');
+                    } else {
+                        toastr.error(response.msg);
+                    }
+                }
+            });
+        });
+        <% } %>
     });
+    /**
+     * 获取成功后的操作
+     *
+     * @param {Object} btn - 点击的按钮
+     * @return {void}
+     */
+    function codeSuccess(btn) {
+        let counter = 60;
+        btn.addClass('disabled').text('重新获取 ' + counter + 'S');
+        btn.parent().siblings('input').removeAttr('readonly').attr('placeholder', '输入短信中的6位验证码');
+        const bindBtn = $("#bind-btn");
+        bindBtn.removeClass('btn-secondary disabled').addClass('btn-primary');
+
+        const countDown = setInterval(function () {
+            const countString = counter - 1 <= 0 ? '' : ' ' + (counter - 1) + 'S';
+            // 倒数结束后
+            if (countString === '') {
+                clearInterval(countDown);
+                btn.removeClass('disabled');
+            }
+            const text = '重新获取' + countString;
+            btn.text(text);
+            counter -= 1;
+        }, 1000);
+    }
 </script>