Forráskód Böngészése

资金统计提交

ellisran 7 hónapja
szülő
commit
2c442d3dfc

+ 50 - 0
app/controller/financial_controller.js

@@ -1049,6 +1049,56 @@ module.exports = app => {
                 }
             }
         }
+
+        async summary(ctx) {
+            try {
+                const financialPermission = await ctx.service.financialAudit.getPermission(ctx.subProject.id, ctx.session.sessionUser.accountId);
+                if (!financialPermission.transfer_show && !financialPermission.pay_show) {
+                    throw '没有查看权限';
+                }
+                const renderData = {
+                    financialPermission,
+                    usedList: financialConst.used,
+                    preUrl: '/financial',
+                    jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.financial.summary),
+                };
+                await this.layout('financial/summary.ejs', renderData);
+            } catch (err) {
+                this.log(err);
+                ctx.redirect('/financial');
+            }
+        }
+
+        async summaryLoad(ctx) {
+            try {
+                const responseData = {
+                    err: 0, msg: '', data: {},
+                };
+                const tid = parseInt(ctx.query.tid) || null;
+                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 filterTids = tid === null ? (ctx.session.sessionUser.is_admin ? null : fptAuditTids) : [tid];
+                const tenderCondition = { spid: ctx.subProject.id };
+                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;
+                }
+                responseData.data.tenders = hadTender ? await ctx.service.tender.getAllDataByCondition({ where: tenderCondition, columns: ['id', 'name'] }) : [];
+                responseData.data.transferList = tid === null ? await ctx.service.financialTransfer.getAllDataByCondition({ where: { spid: ctx.subProject.id } }) : [];
+                responseData.data.transferTenderList = tid === null ? await ctx.service.financialTransferTender.getAllDataByCondition({ where: { spid: ctx.subProject.id } }) : [];
+                responseData.data.payList = await ctx.service.financialPay.getListByStatus(ctx.subProject.id, 0, filterTids);
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: {} };
+            }
+        }
     }
 
     return FinancialController;

+ 279 - 0
app/public/js/financial_summary.js

@@ -0,0 +1,279 @@
+$(document).ready(function() {
+    autoFlashHeight();
+
+    postData('/financial/' + spid + '/summary/load', {}, function (result) {
+        console.log(result);
+        tenders = result.tenders;
+        transferList = result.transferList;
+        transferTenderList = result.transferTenderList;
+        payList = result.payList;
+        summaryObj.setTenderSelect(result.tenders);
+        summaryObj.changeHtmlAndCharts(result.tenders, result.transferList, result.transferTenderList, result.payList);
+    });
+
+    $('#search-btn').click(function () {
+        const tenderSelect = parseInt($('#tender-select').val());
+        const startMonth = $('#start-month').val();
+        const endMonth = $('#end-month').val();
+        const condition = {};
+        let newTransferList = _.cloneDeep(transferList);
+        let newTransferTenderList = _.cloneDeep(transferTenderList);
+        let newPayList = _.cloneDeep(payList);
+        if (startMonth === '' && endMonth.length === '') {
+        } else if (startMonth !== '' && endMonth !== '') {
+            // 判断输入合法和endMonth大于startMonth
+            if (!/^\d{4}-\d{2}$/.test(startMonth) || !/^\d{4}-\d{2}$/.test(endMonth)) {
+                toastr.warning('请输入正确的日期格式');
+                toastr.options
+                return;
+            }
+            if (startMonth > endMonth) {
+                toastr.warning('结束日期不能小于开始日期');
+                return;
+            }
+            newTransferList = _.filter(newTransferList, function (item) {
+                return item.t_time >= startMonth && item.t_time <= endMonth;
+            });
+            newTransferTenderList = _.filter(newTransferTenderList, function (item) {
+                return _.includes(_.map(newTransferList, 'id'), item.trid);
+            });
+            newPayList = _.filter(newPayList, function (item) {
+                const thisMonth = moment(item.create_time).format('YYYY-MM');
+                return thisMonth >= startMonth && thisMonth <= endMonth;
+            });
+        } else {
+            toastr.warning('请选择开始和结束日期查询');
+            return;
+        }
+        newTransferTenderList = tenderSelect !== 0 ? _.filter(newTransferTenderList, { tid: tenderSelect }) : newTransferTenderList;
+        newPayList = tenderSelect !== 0 ? _.filter(newPayList, { tid: tenderSelect }) : newPayList;
+        const newTenders = tenderSelect !== 0 ? _.filter(tenders, condition) : tenders;
+        summaryObj.changeHtmlAndCharts(newTenders, newTransferList, newTransferTenderList, newPayList, tenderSelect);
+    });
+
+    const summaryObj = {
+        setTenderSelect: function (tenders) {
+            let tenderSelectHtml = '<option value="0">全部</option>';
+            for (const tender of tenders) {
+                tenderSelectHtml += `<option value="${tender.id}">${tender.name}</option>`;
+            }
+            $('#tender-select').html(tenderSelectHtml);
+        },
+        changeHtmlAndCharts: function (tenders, transferList, transferTenderList, payList, tenderSelect = 0) {
+            const transfer_price = tenderSelect !== 0 ? _.map(transferTenderList, 'hb_tp') : _.map(transferList, 'total_price');
+            const transfer_sum_price = ZhCalc.sum(transfer_price);
+            const pay_price = _.map(payList, 'total_price');
+            const pay_sum_price = ZhCalc.sum(pay_price);
+            const pend_sum_price = ZhCalc.sub(transfer_sum_price, pay_sum_price);
+            const small_expenses_tp = _.map(payList, 'small_expenses_tp');
+            const small_expenses_sum_price = ZhCalc.sum(small_expenses_tp);
+            // 金额概况
+            $('#transfer_price').text(transfer_sum_price.format2Str('#,##0.######'));
+            $('#pay_price').text(pay_sum_price.format2Str('#,##0.######'));
+            $('#pend_price').text(pend_sum_price.format2Str('#,##0.######'));
+            // 支付进度
+            const pay_progress = (ZhCalc.div(pay_sum_price, ZhCalc.add(pay_sum_price, pend_sum_price)) * 100).toFixed(0);
+            const pend_progress = 100 - pay_progress;
+            $('#pay_progress').html(`
+               <div class="progress-bar bg-success" style="width: ${pay_progress}%;" data-placement="bottom" data-toggle="tooltip" data-original-title="累计支付:¥${pay_sum_price.format2Str('#,##0.######')}">${pay_progress}%</div>
+               <div class="progress-bar bg-gray" style="width: ${pend_progress}%;" data-placement="bottom" data-toggle="tooltip" data-original-title="待支付:¥${pend_sum_price.format2Str('#,##0.######')}">${pend_progress}%</div>`);
+            $('[data-toggle="tooltip"]').tooltip();
+            // 资金支出明细
+            let pay_used_html = '';
+            payUsedOption.series[0].data = [];
+            for (const used of usedList) {
+                const usedPays = _.filter(payList, { used: used });
+                if (usedPays.length > 0) {
+                    const used_price = _.map(usedPays, 'total_price');
+                    const used_sum_price = ZhCalc.sum(used_price)
+                    pay_used_html += `<tr class="text-center"><td>${used}</td><td>${used_sum_price.format2Str('#,##0.######')}</td> <td>${(pay_sum_price ? ZhCalc.div(used_sum_price, pay_sum_price) * 100 : 0).toFixed(2)}%</td></tr>`;
+                    payUsedOption.series[0].data.push({ value: used_sum_price, name: used });
+                }
+            }
+            pay_used_html += `<tr class="text-center"><td><strong>合计</strong></td><td>${pay_sum_price.format2Str('#,##0.######')}</td> <td></td></tr>`;
+            pay_used_html += `<tr class="text-center"><td>其中:小额支出</td><td>${small_expenses_sum_price.format2Str('#,##0.######')}</td><td>${(pay_sum_price ? ZhCalc.div(small_expenses_sum_price, pay_sum_price) * 100 : 0).toFixed(2)}%</td></tr>`;
+            $('#pay_used_table').html(pay_used_html);
+
+            // 标段支出概况图表
+            tenderOption.xAxis[0].data = _.map(tenders, 'name');
+            tenderOption.series[0].data = [];
+            tenderOption.series[1].data = [];
+            for (const t of tenders) {
+                const transferTenders = _.filter(transferTenderList, { tid: t.id });
+                const transfer_tender_price = ZhCalc.sum(_.map(transferTenders, 'hb_tp'));
+                const payTenders = _.filter(payList, { tid: t.id });
+                const pay_tender_price = ZhCalc.sum(_.map(payTenders, 'total_price'));
+                tenderOption.series[0].data.push(transfer_tender_price);
+                tenderOption.series[1].data.push(pay_tender_price);
+            }
+            tenderChart.setOption(tenderOption);
+
+            // 支出明细占比图表
+            payUsedChart.setOption(payUsedOption);
+
+            // 小额支出占比
+            paySeOption.series[0].data = [
+                { value: small_expenses_sum_price, name: '小额支出' },
+                { value: ZhCalc.sub(pay_sum_price, small_expenses_sum_price), name: '其他' },
+            ];
+            paySeChart.setOption(paySeOption);
+        },
+    }
+
+    //标段占比
+    const tenderChart = echarts.init(document.getElementById('jlchart3'));
+    const tenderOption = {
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'shadow'
+            }
+        },
+        legend: {},
+        grid: {
+            left: '3%',
+            right: '4%',
+            bottom: '3%',
+            containLabel: true
+        },
+        xAxis: [
+            {
+                type: 'category',
+                data: []
+            }
+        ],
+        yAxis: [
+            {
+                type: 'value'
+            }
+        ],
+        series: [
+            {
+                name: '累计划拨',
+                type: 'bar',
+                emphasis: {
+                    focus: 'series'
+                },
+                data: []
+            },
+            {
+                name: '累计支付',
+                type: 'bar',
+                stack: 'Ad',
+                emphasis: {
+                    focus: 'series'
+                },
+                data: []
+            }
+
+        ]
+    };
+    // tenderChart.setOption(tenderOption);
+
+    //费用明细占比//
+    const payUsedChart = echarts.init(document.getElementById('jlchart1'));
+    const payUsedOption = {
+        color: ['#9489fa', '#f06464', '#f7af59', '#f0da49', '#71c16f', '#2aaaef', '#5690dd', '#bd88f5', '#009db2', '#0780cf'],
+        //backgroundColor: '#343a40 ',
+        tooltip: {
+            trigger: 'item'
+        },
+        legend: {
+            orient: 'vertical',
+            left:'60%',
+            right:'20%',
+            top: 'middle'
+        },
+        series: [
+            {
+                name: '金额',
+                type: 'pie',
+                top:'20',
+                bottom:'20',
+                right:'40%',
+                radius: ['80%'],
+                avoidLabelOverlap: false,
+                label: {
+                    show: false,
+                    position: 'right'
+                },
+                emphasis: {
+                    label: {
+                        show: true,
+                        fontSize: '40',
+                        fontWeight: 'bold'
+                    }
+                },
+                labelLine: {
+                    show: false
+                },
+                data: [],
+            }
+        ]
+    };
+
+    // 为echarts对象加载数据
+    // myChart1.setOption(option1);
+
+    //小额支出概况//
+    var paySeChart = echarts.init(document.getElementById('jlchart2'));
+    var paySeOption = {
+        color: [ '#71c16f', '#2aaaef'],
+        //backgroundColor: '#343a40 ',
+        tooltip: {
+            trigger: 'item'
+        },
+        legend: {
+            orient: 'vertical',
+            left:'60%',
+            right: '20%',
+            top: 'middle'
+        },
+        series: [
+            {
+                name: '金额',
+                type: 'pie',
+                top:'20',
+                bottom:'20',
+                right:'40%',
+                radius: ['80%'],
+                avoidLabelOverlap: false,
+                label: {
+                    show: false,
+                    position: 'right'
+                },
+                emphasis: {
+                    label: {
+                        show: true,
+                        fontSize: '40',
+                        fontWeight: 'bold'
+                    }
+                },
+                labelLine: {
+                    show: false
+                },
+                data: []
+            }
+        ]
+    };
+
+    // 为echarts对象加载数据
+    // myChart2.setOption(option2);
+
+    $.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();
+        }
+    });
+});

+ 2 - 1
app/router.js

@@ -977,5 +977,6 @@ module.exports = app => {
     app.get('/financial/:spid/pay/:fpid/file/:fid/download', sessionAuth, financialCheck, financialPayCheck, financialPayAuditCheck, 'financialController.payDownloadFile');
     app.post('/financial/:spid/pay/:fpid/audit/start', sessionAuth, financialCheck, financialPayCheck, financialPayAuditCheck, 'financialController.startPayAudit');
     app.post('/financial/:spid/pay/:fpid/audit/check', sessionAuth, financialCheck, financialPayCheck, 'financialController.checkPayAudit');
-    // app.get('/financial/:spid/summary', sessionAuth, financialCheck, 'financialController.summary');
+    app.get('/financial/:spid/summary', sessionAuth, financialCheck, 'financialController.summary');
+    app.post('/financial/:spid/summary/load', sessionAuth, financialCheck, 'financialController.summaryLoad');
 };

+ 133 - 0
app/view/financial/summary.ejs

@@ -0,0 +1,133 @@
+<% 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-8 pl-0">
+                <div class="d-inline-block mr-2 col-sm-3">
+                    <div class="input-group input-group-sm pr-1">
+                        <select class="form-control form-control-sm" id="tender-select">
+                            <option value="0">全部</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="d-inline-block">
+                    <!-- <label for="">开始时间</label><input type="text"  class="form-control form-control-sm"> -->
+                    <div class="form-inline">
+                        <div class="form-group mx-sm-3 mb-2">
+                            <label for="inputPassword2" class="">开始日期:</label>
+                            <input class="datepicker-here form-control form-control-sm mt-0" placeholder="选择开始日期" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text" id="start-month">
+                            <label for="inputPassword2" class="ml-2">结束日期:</label>
+                            <input class="datepicker-here form-control form-control-sm  mt-0" placeholder="选择结束始日期" data-view="months" data-min-view="months" data-date-format="yyyy-MM" data-language="zh" type="text" id="end-month">
+                            <button class="btn btn-sm btn-primary ml-1" id="search-btn">查询</button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="d-inline-block ml-auto">
+            </div>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <div class="row mt-3 col-12">
+                    <div class="col-4 px-0">
+                        <div class="card ml-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>金额概况</div>
+                                <div class="mt-1">元</div>
+                            </div>
+                            <div class="card-body p-0">
+                                <div class="">
+                                    <table class="table table-middle">
+                                        <thead class="text-center thead-light">
+                                        <tr>
+                                            <th>累计划拨</th>
+                                            <th>累计支付</th>
+                                            <th>待支付</th>
+                                        </tr>
+                                        </thead>
+                                        <tbody class="text-center">
+                                        <tr>
+                                            <td id="transfer_price">-</td>
+                                            <td id="pay_price">-</td>
+                                            <td id="pend_price">-</td>
+                                        </tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="card ml-3 mt-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>支付进度</div>
+                                <div class="mt-1"></div>
+                            </div>
+                            <div class="card-body p-0">
+                                <div class="progress m-4" id="pay_progress">
+                                </div>
+                            </div>
+                        </div>
+                        <div class="card ml-3 mt-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>标段支出概况</div>
+                                <div class="mt-1"></div>
+                            </div>
+                            <div class="card-body p-0">
+                                <div id="jlchart3" style="height: 335%; width: 100%;"> </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="col-4 px-0">
+                        <div class="card ml-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>资金支出明细</div>
+                                <div class="mt-1">元</div>
+                            </div>
+                            <div class="card-body p-0">
+                                <table class="table table-middle">
+                                    <thead class="text-center thead-light">
+                                    <tr>
+                                        <th>支出类型</th>
+                                        <th>支出金额</th>
+                                        <th>占比%</th>
+                                    </tr>
+                                    </thead>
+                                    <tbody id="pay_used_table">
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="col-4 px-0">
+                        <div class="card ml-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>支出明细占比</div>
+                                <div class="mt-1"></div>
+                            </div>
+                            <div class="card-body p-0">
+                                <div id="jlchart1" style="height: 335%; width: 100%;"> </div>
+                            </div>
+                        </div>
+                        <div class="card ml-3 mt-3">
+                            <div class="card-header card-white d-flex justify-content-between">
+                                <div class="card-big-htext"><span class="card-icon mr-2"></span>小额支出占比</div>
+                                <div class="mt-1"></div>
+                            </div>
+                            <div class="card-body p-0">
+                                <div id="jlchart2" style="height: 335%; width: 100%;"> </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    const spid = '<%- ctx.subProject.id %>';
+    const usedList = JSON.parse(unescape('<%- escape(JSON.stringify(usedList)) %>'));
+    let tenders, transferList, transferTenderList, payList;
+</script>

+ 19 - 0
config/web.js

@@ -1709,6 +1709,25 @@ const JsFiles = {
                 ],
                 mergeFile: 'financial_pay_detail',
             },
+            summary: {
+                files: [
+                    '/public/js/echarts/echarts.min.js',
+                    '/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/shares/cs_tools.js',
+                    '/public/js/datepicker/datepicker.min.js',
+                    '/public/js/datepicker/datepicker.zh.js',
+                    '/public/js/financial_summary.js',
+                ],
+                mergeFile: 'financial_summary',
+            },
         },
     },
 };