Browse Source

资金支付汇总列表功能

ellisran 2 months ago
parent
commit
af97517cbe

+ 170 - 9
app/controller/financial_controller.js

@@ -749,12 +749,6 @@ module.exports = app => {
                     case 'set-pay-tender':
                         responseData.data = await ctx.service.financialPayTender.savePayTender(ctx.subProject.id, data.updateData);
                         break;
-                    case 'get-auditors':
-                        const fpInfo = await ctx.service.financialPay.getDataById(data.id);
-                        await ctx.service.financialPay.loadPayUser(fpInfo);
-                        await ctx.service.financialPay.loadFinancialPayAuditViewData(fpInfo);
-                        responseData.data = fpInfo;
-                        break;
                     default: throw '参数有误';
                 }
                 ctx.body = responseData;
@@ -775,14 +769,15 @@ module.exports = app => {
                 const status = parseInt(ctx.query.status) || 0;
                 const tid = parseInt(ctx.query.tid) || null;
                 const used = ctx.query.used || null;
-                await this._filterPay(ctx, status, tid, used);
+                const from = ctx.query.from || null;
+                await this._filterPay(ctx, status, tid, used, from);
             } catch (err) {
                 this.log(err);
                 ctx.redirect(`/sp/${ctx.subProject.id}/dashboard`);
             }
         }
 
-        async _filterPay(ctx, status = 0, tid = null, used = null) {
+        async _filterPay(ctx, status = 0, tid = null, used = null, from) {
             const financialPermission = await ctx.service.subProjPermission.getFinancailPermission(ctx.subProject.permission.fund_trans_permission, ctx.subProject.permission.fund_pay_permission);
             if (!financialPermission.pay_show) {
                 throw '没有查看权限';
@@ -895,6 +890,7 @@ module.exports = app => {
                 tid,
                 status,
                 used,
+                from,
                 payList,
                 payStage,
                 notStagePays,
@@ -903,7 +899,7 @@ module.exports = app => {
                 unitList,
                 moment,
                 auditType: auditConst.auditType,
-                // preUrl: '/financial',
+                preUrl: '/sp/' + ctx.subProject.id + '/financial/pay' + (from ? '/list' : '/stage'),
                 jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.financial.pay),
                 pageInfo,
             };
@@ -929,6 +925,168 @@ module.exports = app => {
                     throw '提交数据错误';
                 }
                 const payStage = await ctx.service.financialPayStage.getDataById(ctx.params.fpsid);
+                const fileds = ['batch-old-pays', 'add-pay'];
+                if (!payStage && fileds.indexOf(data.type) !== -1) {
+                    throw '资金支付单位期不存在';
+                }
+                switch (data.type) {
+                    case 'batch-old-pays':
+                        await ctx.service.financialPay.batchOldPays(ctx.subProject.id, payStage, data.postData.payIds);
+                        break;
+                    case 'add-pay':
+                        responseData.data = await ctx.service.financialPay.addPay(ctx.subProject.id, payStage, data.updateData);
+                        break;
+                    case 'del-pay':
+                        responseData.data = await ctx.service.financialPay.delPay(data.postData.node);
+                        break;
+                    case 'get-auditors':
+                        const fpInfo = await ctx.service.financialPay.getDataById(data.id);
+                        await ctx.service.financialPay.loadPayUser(fpInfo);
+                        await ctx.service.financialPay.loadFinancialPayAuditViewData(fpInfo);
+                        responseData.data = fpInfo;
+                        break;
+                    default: throw '参数有误';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: {} };
+            }
+        }
+
+        /**
+         * 变更管理 页面 (Get)
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async payList(ctx) {
+            try {
+                const company = ctx.query.company || null;
+                const qi = parseInt(ctx.query.qi) || null;
+                const status = parseInt(ctx.query.status) || 0;
+                const tid = parseInt(ctx.query.tid) || null;
+                const used = ctx.query.used || null;
+                await this._filterPayList(ctx, company, qi, status, tid, used);
+            } catch (err) {
+                this.log(err);
+                ctx.redirect(`/sp/${ctx.subProject.id}/dashboard`);
+            }
+        }
+
+        async _filterPayList(ctx, company = null, qi = null, status = 0, tid = null, used = null) {
+            const financialPermission = await ctx.service.subProjPermission.getFinancailPermission(ctx.subProject.permission.fund_trans_permission, ctx.subProject.permission.fund_pay_permission);
+            if (!financialPermission.pay_show) {
+                throw '没有查看权限';
+            }
+            const fptAudits = await ctx.service.financialPayTenderAudit.getAllDataByCondition({ where: { spid: ctx.subProject.id, uid: ctx.session.sessionUser.accountId } });
+            const fptAuditTids = ctx.helper._.map(fptAudits, 'tid');
+            const fptReportTids = ctx.helper._.map(ctx.helper._.filter(fptAudits, { is_report: 1 }), 'tid');
+            const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
+            const filterTids = tid === null ? (ctx.session.sessionUser.is_admin ? null : fptAuditTids) : [tid];
+            const tenderCondition = { spid: ctx.subProject.id, filter_fund: 0 };
+            let hadTender = false;
+            if (ctx.session.sessionUser.is_admin) {
+                hadTender = true;
+            } else if (fptAuditTids.length !== 0) {
+                hadTender = true;
+                tenderCondition.id = fptAuditTids;
+            } else {
+                hadTender = false;
+                tenderCondition.id = -1;
+            }
+            const categoryData = await this.ctx.service.category.getAllCategory(ctx.subProject);
+            const tenders = hadTender ? await ctx.service.tender.getAllDataByCondition({ where: tenderCondition, columns: ['id', 'name', 'category'] }) : [];
+            const accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject, ['id', 'account', 'name', 'company', 'company_id', 'role', 'enable', 'is_admin', 'account_group', 'mobile']);
+            const user = accountList.find(item => item.id === ctx.session.sessionUser.accountId) || null;
+            const userCompany = user ? ctx.helper._.find(unitList, { name: user.company }) : null;
+            if (!userCompany) {
+                throw '请联系管理员添加用户所在单位信息';
+            }
+            const userOrderList = await ctx.service.financialPayStage.getUserOrderList(ctx.subProject.id, userCompany ? userCompany.id : 0);
+            const userCompanyList = await ctx.service.financialPayStage.getUserCompanyList(ctx.subProject.id, userCompany ? userCompany.id : 0, unitList);
+            let fpsidList = [];
+            if (company || qi) {
+                const companyInfo = company ? ctx.helper._.find(unitList, { name: company }) : null;
+                const fpstageList = await ctx.service.financialPayStage.getListByStatus(ctx.subProject.id, companyInfo ? companyInfo.id : null, userCompany ? userCompany.id : 0, qi, 0);
+                fpsidList = ctx.helper._.map(fpstageList, 'id');
+            }
+            // const payList = await ctx.service.financialPayStage.getListByStatus(ctx.subProject.id, companyInfo ? companyInfo.id : null, userCompany ? userCompany.id : 0, qi);
+            const filter = JSON.parse(JSON.stringify(auditConst.financial.filter));
+            filter.count = [];
+            filter.count[filter.status.pending] = await ctx.service.financialPay.getCountByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, filter.status.pending, filterTids, used);
+            filter.count[filter.status.uncheck] = await ctx.service.financialPay.getCountByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, filter.status.uncheck, filterTids, used);
+            filter.count[filter.status.checking] = await ctx.service.financialPay.getCountByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, filter.status.checking, filterTids, used);
+            filter.count[filter.status.checked] = await ctx.service.financialPay.getCountByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, filter.status.checked, filterTids, used);
+            const payList = await ctx.service.financialPay.getListByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, status, filterTids, used, 1);
+            const total = await ctx.service.financialPay.getCountByStatus(ctx.subProject.id, fpsidList.length > 0 ? fpsidList : null, status, filterTids, used);
+            // 分页相关
+            const page = ctx.page;
+            const pageSize = ctx.pageSize;
+            const pageInfo = {
+                page,
+                pageSizeSelect: 1,
+                pageSize,
+                total_num: total,
+                total: Math.ceil(total / pageSize),
+                queryData: JSON.stringify(ctx.urlInfo.query),
+            };
+            for (const pay of payList) {
+                const t = ctx.helper._.find(tenders, { id: pay.tid });
+                pay.tenderName = t ? t.name : '';
+                const userInfo = ctx.helper._.find(accountList, { id: pay.uid });
+                pay.username = userInfo ? userInfo.name : '';
+                if (pay.status !== auditConst.financial.status.checked || !pay.final_auditor_str) {
+                    pay.curAuditors = await ctx.service.financialPayAudit.getAuditorsByStatus(pay.id, pay.status, pay.times);
+                    if (pay.status === auditConst.financial.status.checked && pay.curAuditors.length > 0) {
+                        const final_auditor_str = pay.curAuditors[0].audit_type === auditConst.auditType.key.common
+                            ? pay.curAuditors[0].name + (pay.curAuditors[0].role ? '-' + pay.curAuditors[0].role : '')
+                            : ctx.helper.transFormToChinese(pay.curAuditors[0].audit_order) + '审';
+                        await ctx.service.financialPay.defaultUpdate({ final_auditor_str }, { where: { id: pay.id } });
+                    }
+                }
+                if (pay.status !== auditConst.financial.status.checked) {
+                    pay.entities = await ctx.service.financialPayContract.getEntities(pay.id);
+                }
+                pay.stage = pay.fpsid ? await ctx.service.financialPayStage.getOnePayStage(pay.fpsid) : null;
+            }
+            const renderData = {
+                categoryData,
+                tenders,
+                financialPermission,
+                usedList: financialConst.used,
+                auditConst: auditConst.financial,
+                filter,
+                tid,
+                status,
+                used,
+                company,
+                qi,
+                userCompanyList,
+                userOrderList,
+                payList,
+                fptAuditTids,
+                fptReportTids,
+                unitList,
+                moment,
+                auditType: auditConst.auditType,
+                // preUrl: '/sp/' + ctx.subProject.id + '/financial/pay' + (from === 'list' ? '/list/?from=' + from : '/stage'),
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.financial.payList),
+                pageInfo,
+            };
+            await this.layout('financial/pay_list.ejs', renderData, 'financial/pay_list_modal.ejs');
+        }
+
+        async payListSave(ctx) {
+            try {
+                const responseData = {
+                    err: 0, msg: '', data: {},
+                };
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.type) {
+                    throw '提交数据错误';
+                }
+                const payStage = await ctx.service.financialPayStage.getDataById(ctx.params.fpsid);
                 if (!payStage) {
                     throw '资金支付单位期不存在';
                 }
@@ -968,6 +1126,7 @@ module.exports = app => {
                 }
                 await this._getFinancialAuditViewData(ctx);
                 // 获取附件列表
+                const from = ctx.query.from || null;
                 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;
@@ -980,8 +1139,10 @@ module.exports = app => {
                     auditType: auditConst.auditType,
                     whiteList: ctx.app.config.multipart.whitelist,
                     moment,
+                    from,
                     fileList,
                     authMobile: auth_mobile,
+                    returnUrl: `/sp/${ctx.subProject.id}/financial/pay/${from === 'list' ? 'list' : 'stage/' + ctx.financialPay.fpsid}`,
                     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),

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

@@ -27,6 +27,9 @@ $(function () {
 
     function setSelectValue(select, value) {
         const routes = [];
+        if (from) {
+            routes.push('from=' + from);
+        }
         const tid = select === 'tid' ? value : $('#tid_select').val();
         if (tid) {
             routes.push('tid=' + tid);
@@ -160,7 +163,7 @@ $(function () {
             type: 'get-auditors',
             id: $(this).attr('c-id'),
         };
-        postData(`/sp/${spid}/financial/pay/stage/save`, data, function (result) {
+        postData(`/sp/${spid}/financial/pay/save`, data, function (result) {
             const { auditHistory, auditors2, user } = result;
             let auditorsHTML = [];
             auditors2.forEach((group, idx) => {

+ 262 - 0
app/public/js/financial_pay_list.js

@@ -0,0 +1,262 @@
+'use strict';
+let auditUtils;
+$(function () {
+    autoFlashHeight();
+
+    $('#tid_select').select2({
+        language: 'zh-CN',
+        theme: 'bootstrap4',
+        selectOnClose: true,
+        // width: '150',
+    });
+
+    $('#company_select').change(function () {
+        const company_id = parseInt($(this).val()) || 0;
+        setSelectValue('company', company_id);
+    });
+
+    $('#order_select').change(function () {
+        const qi = parseInt($(this).val()) || 0;
+        setSelectValue('qi', qi);
+    });
+
+    $('#tid_select').change(function () {
+        const tid = parseInt($(this).val()) || 0;
+        setSelectValue('tid', tid);
+    });
+
+    $('#status_select .to-log-link').click(function () {
+        const status = parseInt($(this).data('val')) || null;
+        setSelectValue('status', status);
+    });
+
+    $('#used_select .to-log-link').click(function () {
+        const used = $(this).data('val') || null;
+        setSelectValue('used', used);
+    });
+
+    function setSelectValue(select, value) {
+        const routes = [];
+        const company_id = select === 'company' ? value : parseInt($('#company_select').val());
+        if (company_id) {
+            const companyInfo = _.find(userCompanyList, { id: company_id });
+            if (companyInfo) routes.push('company=' + companyInfo.name);
+        }
+        const qi = select === 'qi' ? value : parseInt($('#order_select').val());
+        if (qi) {
+            routes.push('qi=' + qi);
+        }
+        const tid = select === 'tid' ? value : $('#tid_select').val();
+        if (tid) {
+            routes.push('tid=' + tid);
+        }
+        const status = select === 'status' ? value : $('#status_selected').data('value');
+        if (status) {
+            routes.push('status=' + status);
+        }
+        const used = select === 'used' ? value : $('#used_selected').data('value');
+        if (used) {
+            routes.push('used=' + used);
+        }
+        if (getLocalCache('account-pageSize')) {
+            routes.push('pageSize=' + getLocalCache('account-pageSize'));
+        }
+        window.location.href = `/sp/${spid}/financial/pay/list` + (routes.length ? '?' + routes.join('&') : '');
+    }
+
+    $('body').on('click', '#pay-list .del-pay-btn', function () {
+        const fpid = $(this).data('id');
+        deleteAfterHint(function () {
+            postData(`/sp/${spid}/financial/pay/save`, {type: 'del-pay', postData: { node: fpid }}, function (result) {
+                window.location.reload();
+            })
+        }, '确认删除该资金支付?');
+    });
+
+    $('#audit-list').on('click', 'a', function() {
+        const type = $(this).data('target')
+        const auditCard = $(this).parent().parent()
+        if (type === 'show') {
+            $(this).data('target', 'hide')
+            auditCard.find('.fold-card').slideDown('swing', () => {
+                auditCard.find('#end-target').text($(this).data('idx') + '#')
+                auditCard.find('#fold-btn').text('收起历史审核记录')
+            })
+        } else {
+            $(this).data('target', 'show')
+            auditCard.find('.fold-card').slideUp('swing', () => {
+                auditCard.find('#end-target').text('1#')
+                auditCard.find('#fold-btn').text('展开历史审核记录')
+            })
+        }
+    });
+
+    // 获取审批流程
+    $('a[data-target="#sp-list" ]').on('click', function () {
+        const data = {
+            type: 'get-auditors',
+            id: $(this).attr('c-id'),
+        };
+        postData(`/sp/${spid}/financial/pay/save`, data, function (result) {
+            const { auditHistory, auditors2, user } = result;
+            let auditorsHTML = [];
+            auditors2.forEach((group, idx) => {
+                if (idx === 0) {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-play-circle fa-rotate-90"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <span class="badge badge-light badge-pill ml-auto"><small>原报</small></span>
+                    </li>`);
+                } else if(idx === auditors2.length -1 && idx !== 0) {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-stop-circle fa-rotate-90"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <div class="d-flex ml-auto">
+                    ${getAuditTypeHtml(group[0].audit_type)}
+                    <span class="badge badge-light badge-pill ml-auto"><small>终审</small></span>
+                    </div>
+                    </li>`);
+                } else {
+                    auditorsHTML.push(`<li class="list-group-item d-flex justify-content-between align-items-center">
+                        <span class="mr-1"><i class="fa fa fa-chevron-circle-down"></i></span>
+                    <span class="text-muted">${getGroupAuditHtml(group)}</span>
+                    <div class="d-flex ml-auto">
+                    ${getAuditTypeHtml(group[0].audit_type)}
+                    <span class="badge badge-light badge-pill"><small>${transFormToChinese(idx)}审</small></span>
+                    </div>
+                    </li>`);
+                }
+            });
+            $('#auditor-list').empty();
+            $('#auditor-list').append(auditorsHTML.join(''));
+
+            let historyHTML = [];
+            auditHistory.forEach((his, idx) => {
+                if (idx === auditHistory.length - 1 && auditHistory.length !== 1) {
+                    historyHTML.push(`<div class="text-right"><a href="javascript: void(0);" id="fold-btn" data-target="show">展开历史审批流程</a></div>`);
+                }
+                historyHTML.push(`<div class="${idx < auditHistory.length - 1 ? 'fold-card' : ''}">`);
+                historyHTML.push(`<div class="text-center text-muted">${idx+1}#</div>`);
+                historyHTML.push(`<ul class="timeline-list list-unstyled mt-2 ${ idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'last-auditor-list' : '' }">`);
+                his.forEach((group, index) => {
+                    if (index === 0) {
+                        historyHTML.push(`<li class="timeline-list-item pb-2">
+                                            <div class="timeline-item-date">
+                                                ${group.beginYear}
+                                                <span>${group.beginDate}</span>
+                                                <span>${group.beginTime}</span>
+                                            </div>
+                                            <div class="timeline-item-tail"></div>
+                                            <div class="timeline-item-icon bg-success text-light"><i class="fa fa-caret-down"></i></div>
+                                            <div class="timeline-item-content">
+                                                <div class="py-1">
+                                                    <span class="text-black-50">原报</span>
+                                                    <span class="pull-right text-success">${idx !== 0 ? '重新' : '' }上报审批</span>
+                                                </div>
+                                                <div class="card">
+                                                    <div class="card-body px-3 py-0">
+                                                        <div class="card-text p-2 py-3 row">
+                                                            <div class="col">
+                                                                <span class="h6">${user.name}</span>
+                                                                <span class="text-muted ml-1">${user.role}</span>
+                                                            </div>
+                                                            <div class="col">
+                                                                <span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                        </li>`);
+                    }
+                    historyHTML.push(`<li class="timeline-list-item pb-2 ${ group.status === auditConst.status.uncheck && idx === auditHistory.length - 1 && auditHistory.length !== 1 ? 'is_uncheck' : ''}">`);
+                    if (group.endYear) {
+                        historyHTML.push(`<div class="timeline-item-date">${group.endYear}<span>${group.endDate}</span><span>${group.endTime}</span></div>`);
+                    }
+                    if (index < his.length - 1) {
+                        historyHTML.push('<div class="timeline-item-tail"></div>');
+                    }
+                    if (group.status === auditConst.status.checked) {
+                        historyHTML.push('<div class="timeline-item-icon bg-success text-light"><i class="fa fa-check"></i></div>');
+                    } else if (group.status === auditConst.status.checkNo) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-level-up"></i></div>');
+                    } else if (group.status === auditConst.status.checking) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-ellipsis-h"></i></div>');
+                    } else if (group.status === auditConst.status.checkAgain) {
+                        historyHTML.push('<div class="timeline-item-icon bg-warning text-light"><i class="fa fa-check"></i></div>');
+                    } else {
+                        historyHTML.push('<div class="timeline-item-icon bg-secondary text-light"></div>');
+                    }
+
+                    historyHTML.push('<div class="timeline-item-content">');
+                    historyHTML.push('<div class="py-1">');
+                    const statuStr = group.status !== auditConst.status.uncheck ?
+                        `<span class="pull-right ${auditConst.statusClass[group.status]}">${auditConst.statusString[group.status]}</span>` : '';
+                    historyHTML.push(`
+                    <span class="text-black-50">
+                    ${ group.audit_order === 0 ? '原报' : !group.is_final ? group.audit_order + '审' : '终审' } ${getAuditTypeText(group.audit_type)}
+                    </span>
+                    ${statuStr}`);
+                    historyHTML.push('</div>');
+                    historyHTML.push('<div class="card"><div class="card-body px-3 py-0">');
+                    for (const [i, auditor] of group.auditors.entries()) {
+                        historyHTML.push(`<div class="card-text p-2 py-3 row ${ ( i > 0 ? 'border-top' : '') }">`);
+                        historyHTML.push(`<div class="col"><span class="h6">${auditor.name}</span><span class="text-muted ml-1">${auditor.role}</span></div>`);
+                        historyHTML.push('<div class="col">');
+                        if (auditor.status === auditConst.status.checked) {
+                            historyHTML.push('<span class="pull-right text-success"><i class="fa fa-check-circle"></i></span>');
+                        } else if (auditor.status === auditConst.status.checkNo) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-share-square fa-rotate-270"></i></span>');
+                        } else if (auditor.status === auditConst.status.checking) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-commenting"></i></span>');
+                        } else if (auditor.status === auditConst.status.checkAgain) {
+                            historyHTML.push('<span class="pull-right text-warning"><i class="fa fa-check"></i></span>');
+                        }
+                        historyHTML.push('</div>');
+                        if (auditor.opinion) {
+                            historyHTML.push(`<div class="col-12 py-1 bg-light"><i class="fa fa-commenting-o mr-1"></i>${auditor.opinion}</div>`);
+                        }
+                        historyHTML.push('</div>');
+                    }
+                    historyHTML.push('</div></div>');
+                    historyHTML.push('</div>');
+                    historyHTML.push('</li>');
+                });
+                historyHTML.push('</div>');
+                historyHTML.push('</ul>');
+            });
+            $('#audit-list').empty();
+            $('#audit-list').append(historyHTML.join(''));
+        });
+    });
+
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+        }
+    });
+});
+const getGroupAuditHtml = function (group) {
+    return group.map(u => { return `<small class="d-inline-block text-dark mx-1" title="${u.role}" data-auditorId="${u.aid}">${u.name}</small>`; }).join('');
+};
+
+const getAuditTypeHtml = function (type) {
+    if (type === auditType.key.common) return '';
+    return `<div class="li-subscript"><span class="badge badge-pill badge-${auditType.info[type].class} p-1 badge-bg-small"><small>${auditType.info[type].short}</small></span></div>`;
+};
+
+const getAuditTypeText = function (type) {
+    if (type === auditType.key.common) return '';
+    return `<span class="text-${auditType.info[type].class}">${auditType.info[type].long}</span>`;
+};

+ 7 - 1
app/public/js/global.js

@@ -124,7 +124,13 @@ $(function(){
 
     $('.account-page-size').each(function () {
         if (getLocalCache('account-pageSize')) {
-            $(this).attr('href', $(this).attr('href') + '?pageSize=' + getLocalCache('account-pageSize'));
+            // 判断是否有?,是则变成&,否则变成?
+            const href = $(this).attr('href');
+            if (href.indexOf('?') !== -1) {
+                $(this).attr('href', href + '&pageSize=' + getLocalCache('account-pageSize'));
+            } else {
+                $(this).attr('href', href + '?pageSize=' + getLocalCache('account-pageSize'));
+            }
         }
     });
 

+ 2 - 2
app/router.js

@@ -450,8 +450,8 @@ module.exports = app => {
     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/pay/field', sessionAuth, subProjectCheck, financialCheck, 'financialController.payCompany');
-    // app.post('/sp/:id/financial/pay/field/save', sessionAuth, subProjectCheck, financialCheck, 'financialController.payCompanySave');
+    app.get('/sp/:id/financial/pay/list', sessionAuth, subProjectCheck, financialCheck, 'financialController.payList');
+    app.post('/sp/:id/financial/pay/list/save', sessionAuth, subProjectCheck, financialCheck, 'financialController.payListSave');
     app.get('/sp/:id/financial/summary', sessionAuth, subProjectCheck, financialCheck, 'financialController.summary');
     app.post('/sp/:id/financial/summary/load', sessionAuth, subProjectCheck, financialCheck, 'financialController.summaryLoad');
 

+ 10 - 5
app/service/financial_pay.js

@@ -43,7 +43,8 @@ module.exports = app => {
         async getListByStatus(spid, fpsid = null, status = 0, tid = null, used = null, hadlimit = 0, sortBy = '', orderBy = '') {
             let addSql = '';
             if (fpsid) {
-                addSql += ' AND a.fpsid = ' + fpsid;
+                fpsid = fpsid instanceof Array ? fpsid : [fpsid];
+                addSql += ' AND a.fpsid in (' + this.ctx.helper.getInArrStrSqlFilter(fpsid) + ')';
             }
             if (tid !== null) {
                 if (tid.length === 0) {
@@ -115,10 +116,11 @@ module.exports = app => {
          * @param {int} status - 状态
          * @return {void}
          */
-        async getCountByStatus(spid, fpsid = null, status = 0, tid = null, used = null) {
+        async getCountByStatus(spid, fpsid = null, status = 0, tid = null, used = null, company_id = null, user_company_id, qi = null) {
             let addSql = '';
             if (fpsid) {
-                addSql += ' AND a.fpsid = ' + fpsid;
+                fpsid = fpsid instanceof Array ? fpsid : [fpsid];
+                addSql += ' AND a.fpsid in (' + this.ctx.helper.getInArrStrSqlFilter(fpsid) + ')';
             }
             if (tid !== null) {
                 if (tid.length === 0) {
@@ -226,7 +228,7 @@ module.exports = app => {
             }
         }
 
-        async delPay(payStage, fpid) {
+        async delPay(fpid) {
             if (!fpid) {
                 throw '参数有误';
             }
@@ -243,7 +245,10 @@ module.exports = app => {
                 await transaction.delete(this.ctx.service.financialPayAtt.tableName, { fpid });
                 await transaction.delete(this.ctx.service.financialPayAudit.tableName, { fpid });
                 await transaction.delete(this.ctx.service.financialPayContract.tableName, { fpid });
-                await this.ctx.service.financialPayStage.updatePayStageAndAfter(transaction, payStage.spid, payStage);
+                if (node.fpsid) {
+                    const payStage = await this.ctx.service.financialPayStage.getDataById(node.fpsid);
+                    await this.ctx.service.financialPayStage.updatePayStageAndAfter(transaction, payStage.spid, payStage);
+                }
                 await transaction.commit();
             } catch (err) {
                 console.log(err);

+ 2 - 1
app/view/financial/pay.ejs

@@ -4,7 +4,7 @@
         <div class="title-main  d-flex">
             <% include ./sub_mini_menu.ejs %>
             <div class="col-10 pl-0">
-                <div class="d-inline-block"><a href="/sp/<%- ctx.subProject.id %>/financial/pay/stage" class="account-page-size"><i class="fa fa-chevron-left "></i> <span>返回</span></a><span class="text-muted mx-2">|</span><span>第<%- payStage.order %>期 <%- payStage.company %></span><span class="text-muted mx-2">|</span></div>
+                <div class="d-inline-block"><a href="<%- preUrl %>" class="account-page-size"><i class="fa fa-chevron-left "></i> <span>返回</span></a><span class="text-muted mx-2">|</span><span>第<%- payStage.order %>期 <%- payStage.company %></span><span class="text-muted mx-2">|</span></div>
                 <div class="d-inline-block col-sm-3 pl-0">
                     <div class="input-group input-group-sm pr-1">
                         <select class="form-control form-control-sm col-auto" id="tid_select">
@@ -138,5 +138,6 @@
     const selfCategoryLevel = '';
     const pid = '<%- ctx.session.sessionProject.id %>';
     const subProid = '<%- ctx.subProject.id %>';
+    const from = '<%- ctx.query.from || '' %>';
     const uphlname = 'user_' + user_id + '_pro_' + pid + '_sub_' + subProid + '_pay_category_hide_list';
 </script>

+ 2 - 2
app/view/financial/pay_detail.ejs

@@ -4,8 +4,8 @@
         <div class="title-main  d-flex">
             <% include ./sub_mini_menu.ejs %>
             <div class="col-10 pl-0">
-                <% if (financialPay.payStage) { %>
-                <div class="d-inline-block"><a href="/sp/<%- ctx.subProject.id %>/financial/pay/stage/<%- financialPay.payStage.id %>" class="account-page-size"><i class="fa fa-chevron-left "></i> <span>返回</span></a><span class="text-muted mx-2">|</span></div>
+                <% if (financialPay.payStage || returnUrl.indexOf('/pay/list') !== -1) { %>
+                <div class="d-inline-block"><a href="<%- returnUrl %>" class="account-page-size"><i class="fa fa-chevron-left "></i> <span>返回</span></a><span class="text-muted mx-2">|</span></div>
                 <% } %>
 <!--                <div class="d-inline-block mr-3">-->
 <!--                    <div class="btn-group btn-group-toggle group-tab" data-toggle="buttons">-->

+ 197 - 0
app/view/financial/pay_list.ejs

@@ -0,0 +1,197 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex">
+            <% include ./sub_mini_menu.ejs %>
+            <div class="col-11 pl-0">
+                <div class="btn-group group-tab">
+                    <a class="btn btn-sm btn-light account-page-size" href="/sp/<%- ctx.subProject.id %>/financial/pay/stage">支付列表</a>
+                    <a class="btn btn-sm btn-light active" href="javascript:void(0);">汇总列表</a>
+                    <a class="btn btn-sm btn-light" href="/financial/pay">标段统计</a>
+                </div>
+                <div class="d-inline-block col-sm-2">
+                    <div class="input-group input-group-sm pr-1">
+                        <select class="form-control form-control-sm col-auto" id="company_select">
+                            <option value="0">筛选单位</option>
+                            <% for (const c of userCompanyList) { %>
+                                <option value="<%- c.id %>" <% if (c.name === company) { %>selected<% } %>><%- c.name %></option>
+                            <% } %>
+                        </select>
+                    </div>
+                </div>
+                <div class="d-inline-block col-sm-1 pl-0">
+                    <div class="input-group input-group-sm pr-1">
+                        <select class="form-control form-control-sm col-auto" id="order_select">
+                            <option selected="0">筛选期数</option>
+                            <% for (const uo of userOrderList) { %>
+                                <option value="<%- uo %>" <% if (uo === qi) { %>selected<% } %>>第<%- uo %>期</option>
+                            <% } %>>
+                        </select>
+                    </div>
+                </div>
+                <div class="d-inline-block col-sm-2 pl-0">
+                    <div class="input-group input-group-sm pr-1">
+                        <select class="form-control form-control-sm col-auto" id="tid_select">
+                            <option value="0">筛选标段</option>
+                            <% for (const t of tenders) { %>
+                            <option value="<%- t.id %>" <% if (t.id === tid) { %>selected<% } %> ><%- t.name %></option>
+                            <% } %>
+                        </select>
+                    </div>
+                </div>
+                <div class="d-inline-block">
+                    <div class="input-group input-group-sm pr-1">
+                        <div class="btn-group">
+                            <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" id="used_selected" data-value="<%- used %>">资金用途:<%- used ? used : '全部' %></button>
+                            <div class="dropdown-menu" aria-labelledby="used_selected" id="used_select">
+                                <% if (used !== null) { %><a class="dropdown-item to-log-link" data-val="" href="javascript:void(0);">全部</a><% } %>
+                                <% for (const u of usedList) { %>
+                                <% if (used !== u) { %>
+                                <a class="dropdown-item to-log-link" href="javascript:void(0)" data-val="<%- u %>"><%- u %></a>
+                                <% } %>
+                                <% } %>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="d-inline-block">
+                    <div class="input-group input-group-sm pr-1">
+                        <div class="btn-group">
+                            <button type="button" class="btn btn-sm btn-light text-primary dropdown-toggle" data-toggle="dropdown" id="status_selected" data-value="<%- status %>">审批状态:<% if (status !== 0) { %><%- filter.statusString[status] %>(<%- filter.count[status] %>)<% } else { %>全部<% } %></button>
+                            <div class="dropdown-menu" aria-labelledby="status_selected" id="status_select">
+                                <% if (status !== 0) { %><a class="dropdown-item to-log-link" data-val="0" href="javascript:void(0);">全部</a><% } %>
+                                <% for (const fs in filter.status) { %>
+                                    <% const f = filter.status[fs]; %>
+                                    <% if (f !== status) { %><a class="dropdown-item to-log-link" data-val="<%- f %>" href="javascript:void(0);"><%- filter.statusString[f] %>(<%- filter.count[f] %>)</a><% } %>
+                                <% } %>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="d-inline-block ml-auto">
+<!--                <a href="#batch-sp" data-toggle="modal" data-target="#batch-sp" class="btn btn-success btn-sm pull-right mr-2">批量审批</a>-->
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="sjs-height-0" style="background-color: #fff">
+                <table class="table table-bordered text-center">
+                    <thead>
+                    <tr>
+                        <th width="250px">申请单位</th>
+                        <th width="100px">关联期数</th>
+                        <th style="min-width: 150px;">标段名称</th>
+                        <th width="200px">支付编号</th>
+                        <th width="150px">申请时间</th>
+                        <th width="100px">申请人</th>
+                        <th width="200px">资金用途</th>
+                        <th width="300px">收款单位</th>
+                        <th width="150px">支付金额</th>
+                        <th width="200px">审批进度</th>
+                        <th width="150px">操作</th>
+                    </tr>
+                    </thead>
+                    <tbody id="pay-list">
+                    <% for (const pay of payList) { %>
+                        <tr class="text-center" data-tid="<%- pay.tid %>">
+                            <td class="text-left"><%- pay.stage ? pay.stage.company : '' %></td>
+                            <td class=""><% if (pay.stage) { %><a href="/sp/<%- ctx.subProject.id %>/financial/pay/stage/<%- pay.stage.id %>?from=list" class="account-page-size">第<%- pay.stage.order %>期</a><% } %></td>
+                            <td class="text-left"><%- pay.tenderName %></td>
+                            <td class=""><a href="/sp/<%- ctx.subProject.id %>/financial/pay/<%- pay.id %>/detail?from=list"><%- pay.code %></a></td>
+                            <td class=""><%- moment(pay.create_time).format('YYYY-MM-DD') %></td>
+                            <td class=""><%- pay.username %></td>
+                            <td class=""><%- pay.used %></td>
+                            <td class=""><%- pay.entities %></td>
+                            <td class="text-right"><%- pay.total_price %></td>
+                            <td class="text-left <%- auditConst.auditProgressClass[pay.status] %>">
+                                <% if (pay.status === auditConst.status.checked && pay.final_auditor_str) { %>
+                                    <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- pay.id %>"><%- pay.final_auditor_str %></a>
+                                <% } else if (pay.curAuditors.length > 0) { %>
+                                    <% if (pay.curAuditors[0].audit_type === auditType.key.common) { %>
+                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- pay.id %>"><%- pay.curAuditors[0].name %><%if (pay.curAuditors[0].role !== '' && pay.curAuditors[0].role !== null) { %>-<%- pay.curAuditors[0].role %><% } %></a>
+                                    <% } else { %>
+                                        <a href="#sp-list" data-toggle="modal" data-target="#sp-list" c-id="<%- pay.id %>"><%- ctx.helper.transFormToChinese(pay.curAuditors[0].audit_order) + '审' %></a>
+                                    <% } %>
+                                <% } %>
+                                <%- auditConst.auditProgress[pay.status] %>
+                            </td>
+                            <td>
+                                <% if (pay.status === auditConst.status.uncheck && pay.uid === ctx.session.sessionUser.accountId) { %>
+                                    <a href="/sp/<%- ctx.subProject.id %>/financial/pay/<%- pay.id %>/detail?from=list" class="btn <%- auditConst.statusButtonClass[pay.status] %> btn-sm"><%- auditConst.statusButton[pay.status] %></a>
+                                <% } else if (pay.status === auditConst.status.checkNo && pay.curAuditors && pay.uid === ctx.session.sessionUser.accountId) { %>
+                                    <a href="/sp/<%- ctx.subProject.id %>/financial/pay/<%- pay.id %>/detail?from=list" class="btn <%- auditConst.statusButtonClass[pay.status] %> btn-sm"><%- auditConst.statusButton[pay.status] %></a>
+                                <% } else if (pay.status === auditConst.status.checking && pay.curAuditors && pay.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                                    <% const curAudit = pay.curAuditors.find(x => { return x.aid === ctx.session.sessionUser.accountId; }); %>
+                                    <% if (curAudit.status === auditConst.status.checking) { %>
+                                        <a href="/sp/<%- ctx.subProject.id %>/financial/pay/<%- pay.id %>/detail?from=list" class="btn <%- auditConst.statusButtonClass[pay.status] %> btn-sm"><%- auditConst.statusButton[pay.status] %></a>
+                                    <% } else { %>
+                                        <span class="<%- auditConst.auditStringClass[curAudit.status] %>"><%- auditConst.auditString[curAudit.status] %></span>
+                                    <% } %>
+                                <% } else { %>
+                                    <span class="<%- auditConst.auditStringClass[pay.status] %>"><%- auditConst.auditString[pay.status] %></span>
+                                <% } %>
+                                <% if (pay.uid === ctx.session.sessionUser.accountId && (pay.status === auditConst.status.uncheck || pay.status === auditConst.status.checkNo)) { %><a href="javascript:void(0);" data-id="<%- pay.id %>" class="text-danger del-pay-btn">删除</a><% } %>
+                            </td>
+                        </tr>
+                    <% } %>
+                    </tbody>
+                </table>
+                <!--翻页-->
+                <% include ../layout/page.ejs %>
+            </div>
+    </div>
+</div>
+<link href="/public/css/bootstrap/select2.min.css" rel="stylesheet" />
+<link rel="stylesheet" href="/public/css/bootstrap/select2-bootstrap4.min.css">
+<script src="/public/js/bootstrap/select2.min.js"></script>
+<style>
+    .select2-container {
+        /*display: inline-block!important;*/
+        /*height: 27px;*/
+        width: 100% !important;
+    }
+    .select2-container--bootstrap4 .select2-selection--single {
+        height: calc(0.9em + .75rem) !important;
+    }
+    /*.select2-container--bootstrap4 .select2-selection {*/
+    /*    background-color: #f8f9fa;*/
+    /*    !*border-color: #f8f9fa;*!*/
+    /*    border: 1px solid #f8f9fa;*/
+    /*}*/
+    /*.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered:focus{*/
+    /*    box-shadow: 0 0 0 0.2rem rgba(216,217,219,.5);*/
+    /*}*/
+    /*.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered:hover {*/
+    /*    background-color: #e2e6ea;*/
+    /*    border-color: #dae0e5;*/
+    /*}*/
+    .select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered {
+        line-height: calc(0.9em + .75rem);
+        /*color: #007bff!important;*/
+        border-radius: 0.2rem;
+        /*background-color: #f8f9fa;*/
+        /*border-color: #f8f9fa;*/
+    }
+    .select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b {
+        border-color: #007bff transparent transparent transparent;
+        border-width: 4px 3.7px 0;
+    }
+    .select2-search--dropdown .select2-search__field {
+        padding: 0.175rem 0.5rem;
+    }
+</style>
+<script>
+    const user_id = <%- ctx.session.sessionUser.accountId %>;
+    const is_admin = <%- ctx.session.sessionUser.is_admin %>;
+    const category = JSON.parse(unescape('<%- escape(JSON.stringify(categoryData)) %>'));
+    const tenders = JSON.parse(unescape('<%- escape(JSON.stringify(tenders)) %>'));
+    const userCompanyList = JSON.parse(unescape('<%- escape(JSON.stringify(userCompanyList)) %>'));
+    const fptReportTids = JSON.parse(unescape('<%- escape(JSON.stringify(fptReportTids)) %>'));
+    const auditConst = JSON.parse(unescape('<%- escape(JSON.stringify(auditConst)) %>'));
+    const auditType = JSON.parse(unescape('<%- escape(JSON.stringify(auditType)) %>'));
+    const selfCategoryLevel = '';
+    const pid = '<%- ctx.session.sessionProject.id %>';
+    const subProid = '<%- ctx.subProject.id %>';
+    const uphlname = 'user_' + user_id + '_pro_' + pid + '_sub_' + subProid + '_pay_category_hide_list';
+</script>

+ 49 - 0
app/view/financial/pay_list_modal.ejs

@@ -0,0 +1,49 @@
+<% include ../shares/delete_hint_modal.ejs %>
+<!--批量审批-->
+<div class="modal fade" id="batch-sp" 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">
+                <table class="table table-bordered">
+                    <tr><th>选择</th><th>标段名称</th><th>支付编号</th><th>收款单位</th><th>支付金额</th></tr>
+                    <tr><td><input type="checkbox"></td><td>TJ01</td><td>TJ01-20231207001</td><td>中国交通物资有限公司</td><td class="text-right">12345678</td></tr>
+                    <tr><td><input type="checkbox"></td><td>TJ01</td><td>TJ01-20231207001</td><td>中国交通物资有限公司</td><td class="text-right">12345678</td></tr>
+                    <tr><td><input type="checkbox"></td><td>TJ01</td><td>TJ01-20231207001</td><td>中国交通物资有限公司</td><td class="text-right">12345678</td></tr>
+                    <tr><td><input type="checkbox"></td><td>TJ01</td><td>TJ01-20231207001</td><td>中国交通物资有限公司</td><td class="text-right">12345678</td></tr>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+                <button type="button" class="btn btn-sm btn-success">审批</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--审批流程/结果-->
+<div class="modal fade" id="sp-list" data-backdrop="static">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">审批流程</h5>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <div class="col-4 modal-height-500" style="overflow: auto">
+                        <div class="card mt-3">
+                            <ul class="list-group list-group-flush" id="auditor-list">
+                            </ul>
+                        </div>
+                    </div>
+                    <div class="col-8 modal-height-500" style="overflow: auto" id="audit-list">
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 1 - 1
app/view/financial/pay_stage.ejs

@@ -6,7 +6,7 @@
             <div class="col-10 pl-0">
                 <div class="btn-group group-tab">
                     <a class="btn btn-sm btn-light active" href="javascript:void(0);">支付列表</a>
-                    <a class="btn btn-sm btn-light" href="/financial/pay">汇总列表</a>
+                    <a class="btn btn-sm btn-light account-page-size" href="/sp/<%- ctx.subProject.id %>/financial/pay/list">汇总列表</a>
                     <a class="btn btn-sm btn-light" href="/financial/pay">标段统计</a>
                 </div>
                 <div class="d-inline-block col-sm-3">

+ 15 - 0
config/web.js

@@ -1945,6 +1945,21 @@ const JsFiles = {
                 ],
                 mergeFile: 'financial_pay',
             },
+            payList: {
+                files: [
+                    '/public/js/decimal.min.js',
+                    '/public/js/math.min.js',
+                    '/public/js/component/menu.js',
+                    '/public/js/moment/moment.min.js',
+                ],
+                mergeFiles: [
+                    '/public/js/sub_menu.js',
+                    '/public/js/div_resizer.js',
+                    '/public/js/zh_calc.js',
+                    '/public/js/financial_pay_list.js',
+                ],
+                mergeFile: 'financial_pay_list',
+            },
             payDetail: {
                 files: [
                     '/public/js/decimal.min.js',