Browse Source

单标段多期汇总

MaiXinRong 4 years ago
parent
commit
79a8def8d7

+ 1 - 0
app/const/report.js

@@ -16,6 +16,7 @@ rptCustomType[JV.NODE_CUS_COMPARE_SELECT] = 3;
 
 const rptDataType = {};
 rptDataType[JV.NODE_CUS_MATERIAL_SELECT] = 1;
+rptDataType[JV.NODE_CUS_STAGE_SELECT] = 2;
 
 module.exports = {
     rptCustomType,

+ 8 - 4
app/controller/report_controller.js

@@ -76,6 +76,8 @@ module.exports = app => {
                 }
                 customSelects.gather_select = await ctx.service.rptCustomDefine.getCustomSelectByRpt(cid,
                     reportConst.rptCustomType[JV.NODE_CUS_GATHER_SELECT], ctx.tender.id, -1);
+                customSelects.stage_select = await ctx.service.rptCustomDefine.getCustomSelectByRpt(cid,
+                    reportConst.rptCustomType[JV.NODE_CUS_STAGE_SELECT], ctx.tender.id, -1);
                 const dataSelects = {};
                 dataSelects.material_select = await ctx.service.rptCustomDefine.getDataSelectByRpt(cid,
                     reportConst.rptDataType[JV.NODE_CUS_MATERIAL_SELECT]);
@@ -164,6 +166,7 @@ module.exports = app => {
                     customSelects,
                     rptCustomType: reportConst.rptCustomType,
                     materialList,
+                    stages: stageList,
                     dataSelects
                 };
                 await this.layout('report/index.ejs', renderData, 'report/rpt_all_popup.ejs');
@@ -225,10 +228,11 @@ module.exports = app => {
             const customSelect = rptTpl[JV.NODE_CUSTOM_DEFINE] && rptTpl[JV.NODE_CUSTOM_DEFINE][JV.NODE_CUS_AUDIT_SELECT].enable
                 ? await ctx.service.rptCustomDefine.getCustomDefine(params.tender_id, params.stage_id, params.rpt_tpl_id)
                 : await ctx.service.rptCustomDefine.getCustomDefine(params.tender_id, -1, params.rpt_tpl_id);
+
             const copyCustomSelect = this.ctx.helper.clone(customSelect);
-            if (!params.gather_select && copyCustomSelect) {
-                delete copyCustomSelect.gather_select;
-            }
+            if (!params.gather_select && copyCustomSelect) delete copyCustomSelect.gather_select;
+            if (!params.stage_select && copyCustomSelect) delete copyCustomSelect.stage_select;
+
             const pageRst = await getAllPagesCommon(ctx, rptTpl, params, JV.PAGING_OPTION_NORMAL, JV.OUTPUT_TYPE_NORMAL, this.app.baseDir, copyCustomSelect);
             // console.log(pageRst);
             // const roleRel = (params.stage_status === 3) ? (await ctx.service.roleRptRel.getRoleRptRelByDetailIds(params.tender_id, params.rpt_tpl_id)) : [];
@@ -629,7 +633,7 @@ async function getAllPagesCommon(ctx, rptTpl, params, option, outputType, baseDi
     // console.log(filter.tables);
     const rawDataObj = await ctx.service.report.getReportData(params, filter.tables, filter.memFieldKeys,
         rptTpl[JV.NODE_CUSTOM_DEFINE], customSelect);
-    await ctx.helper.saveBufferFile(JSON.stringify(rawDataObj, '', '\t'), ctx.app.baseDir + '/mem.json');
+    //await ctx.helper.saveBufferFile(JSON.stringify(rawDataObj, '', '\t'), ctx.app.baseDir + '/mem.json');
     // console.log(rawDataObj);
     try {
         const printCom = JpcEx.createNew();

+ 46 - 0
app/lib/rpt_data_analysis.js

@@ -1331,6 +1331,51 @@ const splitXmjCode = {
         }
     }
 };
+const stageSelectConverse = {
+    name: '交叉多期汇总数据',
+    hint: '需搭配 用户交互--单标段多期汇总选择 一起使用',
+    defaultSetting: {
+        table: ['mem_stage_sum_bills'],
+    },
+    _commonConverse: function (helper, data, stages) {
+        const result = [];
+        const reg = new RegExp('^t_[0-9]+_');
+        for (const s of stages) {
+            const curReg = new RegExp('^s_' + s + '_');
+            for (const [i, d] of data.entries()) {
+                const nd = { cross_index: i + 1};
+                for (const prop in d) {
+                    if (reg.test(prop)) {
+                        if (curReg.test(prop)) {
+                            nd[prop.replace(curReg, 's_')] = d[prop];
+                        }
+                    } else {
+                        nd[prop] = d[prop];
+                    }
+                }
+                result.push(nd);
+            }
+        }
+        return result;
+    },
+    fun: function (ctx, data, fieldsKey, options, csRela) {
+        if (!csRela.tplDefine) return;
+
+        const gsDefine = csRela.tplDefine.stage_select;
+        if (!gsDefine || !gsDefine.enable || !gsDefine.setting || gsDefine.setting === '') return;
+        const gsCustom = csRela.cDefine ? csRela.cDefine.stage_select : null;
+
+        for (const t of options.table) {
+            switch (t) {
+                case 'mem_stage_sum_bills':
+                case 'mem_stage_sum_pay':
+                case 'mem_union_data':
+                    data[t] = this._commonConverse(ctx.helper, data[t], gsCustom.stages);
+                    break;
+            }
+        }
+    }
+};
 
 const analysisObj = {
     changeSort,
@@ -1346,6 +1391,7 @@ const analysisObj = {
     auditSelect,
     datetimeFormat,
     gatherSelectConverse,
+    stageSelectConverse,
     sortPos,
     unionPos,
     splitXmjCode,

+ 78 - 2
app/public/report/js/rpt_custom.js

@@ -25,6 +25,8 @@ const rptCustomObj = (function () {
 
         orgSelect: null,
     };
+    // 期选择
+    const sStageSelect = 'stage_select';
     const grSpreadSetting = {
         baseCols: [
             {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: true},
@@ -242,6 +244,25 @@ const rptCustomObj = (function () {
         $('#gather-select-ok').unbind('click');
         $('#gather-select-ok').bind('click', () => {rptCustomObj.resetGatherSelect(resolve);});
     };
+    const initStageSelect = function (gsSetting, gsSelect, rptName, resolve = null) {
+        const setting = JSON.parse(gsSetting);
+        $('#stage-select-count').html(gsSelect && gsSelect.stages ? gsSelect.stages.length : 0);
+        $('#stage-select-title').html(setting.title + (rptName ? '-' + rptName : ''));
+        // 初始化选择结果
+        $('#stage-select-hint').attr('min-select', setting.min).attr('max-select', setting.max).hide();
+        for (const sc of $('[name=stage-select-check]')) {
+            sc.checked = false;
+        }
+        if (gsSelect && gsSelect.stages) {
+            for (const s of gsSelect.stages) {
+                $('#stage-select-' + s)[0].checked = true;
+            }
+        }
+        $("#stage-select").modal('show');
+
+        $('#stage-select-ok').unbind('click');
+        $('#stage-select-ok').bind('click', () => {rptCustomObj.resetStageSelect(resolve);});
+    };
     const init = function (cDefine, sfData, cSelect, rptName, resolve = null) {
         stageFlow = sfData;
         if (cDefine && cDefine[sAuditSelect] && cDefine[sAuditSelect].enable && cDefine[sAuditSelect].setting) {
@@ -256,6 +277,12 @@ const rptCustomObj = (function () {
         } else {
             $('#pnl_gather_select').hide();
         }
+        if (cDefine && cDefine[sStageSelect] && cDefine[sStageSelect].enable && cDefine[sStageSelect].setting) {
+            $('#pnl_stage_select').show();
+            initStageSelect(cDefine[sStageSelect].setting, cSelect ? cSelect[sStageSelect] : null, rptName, resolve);
+        } else {
+            $('#pnl_stage_select').hide();
+        }
     };
 
     const reloadReportData = function (result) {
@@ -415,6 +442,40 @@ const rptCustomObj = (function () {
         }
     };
 
+    const resetStageSelect = function (resolve = null) {
+        const data = {}, hintObj = $('#stage-select-hint');
+        if (!resolve) getCommonParams(data);
+        data[sStageSelect] = {
+            stages: [],
+        };
+        for (const sc of $('[name=stage-select-check]:checked')) {
+            data[sStageSelect].stages.push(parseInt($(sc).attr('stage-order')));
+        }
+        if (data[sStageSelect].stages.length <= parseInt(hintObj.attr('min-select'))) {
+            hintObj.html('请至少选择' + hintObj.attr('min-select') + '期数据').show();
+            return;
+        } else if (data[sStageSelect].stages.length >= parseInt(hintObj.attr('max-select'))) {
+            hintObj.html('最多只能选择' + hintObj.attr('max-select') + '期数据').show();
+            return;
+        }
+        hintObj.hide();
+        if (resolve) {
+            resolve(data);
+        } else {
+            postData('/report/cDefine', data, function (result) {
+                reloadReportData(result);
+                const stage_select = customSelects.stage_select.find(function (x) {
+                    return x.id === zTreeOprObj.currentNode.refId;
+                });
+                if (stage_select) {
+                    stage_select.gather_select = data[sStageSelect];
+                }
+                $('#stage-select-count').html(data[sStageSelect].stages.length);
+                $('#stage-select').modal('hide');
+            });
+        }
+    };
+
     const initTenderTree = function (tenders, category) {
         const gsSpread = SpreadJsObj.createNewSpread($('#gather-source-spread')[0]);
         gsObj.gsSheet = gsSpread.getActiveSheet();
@@ -482,8 +543,23 @@ const rptCustomObj = (function () {
             } else {
                 params.customSelect.push(null);
             }
+
+            const stage_select = customSelects.stage_select.find(function (x) {
+                return x.id === rptId;
+            });
+            if (stage_select && stage_select.custom_define && stage_select.custom_define[sStageSelect].enable) {
+                if (rptId === currentRptId) {
+                    params.customSelect.push(stage_select[sStageSelect]);
+                } else {
+                    const chkNode = chkNodes.find(function (x) { return x.refId === rptId});
+                    params.customSelect.push(await comfirmSelectPromise(chkNode ? chkNode.name : '', stage_select));
+                }
+            } else {
+                params.customSelect.push(null);
+            }
         }
         $('#gather-select').modal('hide');
+        $('#stage-select').modal('hide');
     };
 
     const showMaterialSelect = function () {
@@ -513,9 +589,9 @@ const rptCustomObj = (function () {
 
     return {
         init,
-        resetAuditSelect, resetGatherSelect,
+        resetAuditSelect, resetGatherSelect, resetStageSelect,
         initTenderTree,
         getCustomSelect,
-        showMaterialSelect, changeMaterial
+        showMaterialSelect, changeMaterial,
     };
 })();

+ 10 - 0
app/public/report/js/rpt_main.js

@@ -223,6 +223,7 @@ let zTreeOprObj = {
     onCheck: function(event, treeId, treeNode) {
         zTreeOprObj.countChkedRptTpl();
         rptCustomObj.showMaterialSelect();
+        rptCustomObj.showStageSelect();
         if (treeNode.isParent) {
             zTreeOprObj.treeObj.expandNode(treeNode, true, true, false);
         }
@@ -252,6 +253,15 @@ let zTreeOprObj = {
                 return;
             }
 
+            const stage_select = customSelects.stage_select.find(function (x) {
+                return x.id === treeNode.refId;
+            });
+            if (stage_select) {
+                rptCustomObj.init(stage_select.custom_define, customSelects.stageFlow, stage_select);
+                return;
+            }
+
+
             me.requestNormalReport(params);
             me.countChkedRptTpl();
             rptCustomObj.showMaterialSelect();

+ 1 - 0
app/reports/rpt_component/jpc_value_define.js

@@ -54,6 +54,7 @@ module.exports = {
     NODE_CUS_GATHER_SELECT: 'gather_select',
     NODE_CUS_COMPARE_SELECT: 'compare_select',
     NODE_CUS_MATERIAL_SELECT: 'material_select',
+    NODE_CUS_STAGE_SELECT: 'stage_select',
 
     NODE_MAP_DATA_HANDLE_INFO: '映射数据预处理',
     PROP_DATA_KEY: '映射数据对象',

+ 8 - 2
app/service/report.js

@@ -148,8 +148,14 @@ module.exports = app => {
                             runnableRst.push(service.rptGatherMemory.getMaterialGl(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
-                        case 'mem_sum_stage_bills':
-                            runnableRst.push(service.rptGatherMemory.getSumStageBillsData(params.tender_id, memFieldKeys[filter]));
+                        case 'mem_stage_sum_bills':
+                            runnableRst.push(service.rptStageSumMemory.getStageSumBills(params.tender_id, memFieldKeys[filter],
+                                customDefine.stage_select, customSelect ? customSelect.stage_select : null));
+                            runnableKey.push(filter);
+                            break;
+                        case 'mem_stage_sum_pay':
+                            runnableRst.push(service.rptStageSumMemory.getStageSumPay(params.tender_id, memFieldKeys[filter],
+                                customDefine.stage_select, customSelect ? customSelect.stage_select : null));
                             runnableKey.push(filter);
                             break;
                         default:

+ 8 - 1
app/service/rpt_custom_define.js

@@ -30,6 +30,9 @@ module.exports = app => {
             if (data && data.gather_select) {
                 data.gather_select = JSON.parse(data.gather_select);
             }
+            if (data && data.stage_select) {
+                data.stage_select = JSON.parse(data.stage_select);
+            }
             return data;
         }
 
@@ -53,12 +56,13 @@ module.exports = app => {
         }
 
         async saveCustomSelect(data) {
-            const sid = data.gather_select ? -1 : data.stage_id;
+            const sid = data.gather_select || data.stage_select ? -1 : data.stage_id;
             const filter = {tid: data.tender_id, sid: sid, rid: data.rpt_tpl_id};
             const count = await this.count(filter);
             const updateData = {};
             if (data.audit_select) updateData.audit_select = JSON.stringify(data.audit_select);
             if (data.gather_select) updateData.gather_select = JSON.stringify(data.gather_select);
+            if (data.stage_select) updateData.stage_select = JSON.stringify(data.stage_select);
             if (count > 0) {
                 await this.update(updateData, filter);
             } else {
@@ -91,6 +95,9 @@ module.exports = app => {
                 if (cs.gather_select) {
                     r.gather_select = JSON.parse(cs.gather_select);
                 }
+                if (cs.stage_select) {
+                    r.stage_select = JSON.parse(cs.stage_select);
+                }
             }
             return result;
         }

+ 254 - 0
app/service/rpt_stage_sum_memory.js

@@ -0,0 +1,254 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const Ledger = require('../lib/ledger');
+const PayCalculator = require('../lib/pay_calc');
+
+const auditConst = require('../const/audit');
+const payConst = require('../const/deal_pay');
+
+const moment = require('moment');
+
+const indexPre = 'id_';
+
+
+const gatherUtils = {
+    completeStageSumData: function (datas, completeDatas) {
+        for (const data of datas) {
+            for (const cd of completeDatas) {
+                data[cd.prefix + 'order'] = cd.order;
+            }
+        }
+    },
+    gatherStage: function (tender, gatherNode, sourceNode, prefix, helper) {
+        gatherNode[prefix + 'id'] = tender.id;
+        gatherNode[prefix + 'name'] = tender.name;
+
+        gatherNode[prefix + "qty"] = helper.add(gatherNode[prefix + "qty"], sourceNode.quantity);
+        gatherNode[prefix + "tp"] = helper.add(gatherNode[prefix + "tp"], sourceNode.total_price);
+
+        gatherNode[prefix + "dgn_qty1"] = helper.add(gatherNode[prefix + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode[prefix + "dgn_qty2"] = helper.add(gatherNode[prefix + "dgn_qty2"], sourceNode.dgn_qty2);
+
+        gatherNode[prefix + "contract_qty"] = helper.add(gatherNode[prefix + "contract_qty"], sourceNode.contract_qty);
+        gatherNode[prefix + "contract_tp"] = helper.add(gatherNode[prefix + "contract_tp"], sourceNode.contract_tp);
+        gatherNode[prefix + "qc_qty"] = helper.add(gatherNode[prefix + "qc_qty"], sourceNode.qc_qty);
+        gatherNode[prefix + "qc_tp"] = helper.add(gatherNode[prefix + "qc_tp"], sourceNode.qc_tp);
+        gatherNode[prefix + "gather_qty"] = helper.add(gatherNode[prefix + "gather_qty"], sourceNode.gather_qty);
+        gatherNode[prefix + "gather_tp"] = helper.add(gatherNode[prefix + "gather_tp"], sourceNode.gather_tp);
+
+        gatherNode[prefix + "pre_contract_qty"] = helper.add(gatherNode[prefix + "pre_contract_qty"], sourceNode.pre_contract_qty);
+        gatherNode[prefix + "pre_contract_tp"] = helper.add(gatherNode[prefix + "pre_contract_tp"], sourceNode.pre_contract_tp);
+        gatherNode[prefix + "pre_qc_qty"] = helper.add(gatherNode[prefix + "pre_qc_qty"], sourceNode.pre_qc_qty);
+        gatherNode[prefix + "pre_qc_tp"] = helper.add(gatherNode[prefix + "pre_qc_tp"], sourceNode.pre_qc_tp);
+        gatherNode[prefix + "pre_gather_qty"] = helper.add(gatherNode[prefix + "pre_gather_qty"], sourceNode.pre_gather_qty);
+        gatherNode[prefix + "pre_gather_tp"] = helper.add(gatherNode[prefix + "pre_gather_tp"], sourceNode.pre_gather_tp);
+
+        gatherNode[prefix + "end_contract_qty"] = helper.add(gatherNode[prefix + "end_contract_qty"], sourceNode.end_contract_qty);
+        gatherNode[prefix + "end_contract_tp"] = helper.add(gatherNode[prefix + "end_contract_tp"], sourceNode.end_contract_tp);
+        gatherNode[prefix + "end_qc_qty"] = helper.add(gatherNode[prefix + "end_qc_qty"], sourceNode.end_qc_qty);
+        gatherNode[prefix + "end_qc_tp"] = helper.add(gatherNode[prefix + "end_qc_tp"], sourceNode.end_qc_tp);
+        gatherNode[prefix + "end_gather_qty"] = helper.add(gatherNode[prefix + "end_gather_qty"], sourceNode.end_gather_qty);
+        gatherNode[prefix + "end_gather_tp"] = helper.add(gatherNode[prefix + "end_gather_tp"], sourceNode.end_gather_tp);
+
+        gatherNode[prefix + "deal_dgn_qty1"] = helper.add(gatherNode[prefix + "deal_dgn_qty1"], sourceNode.deal_dgn_qty1);
+        gatherNode[prefix + "deal_dgn_qty2"] = helper.add(gatherNode[prefix + "deal_dgn_qty2"], sourceNode.deal_dgn_qty2);
+        gatherNode[prefix + "c_dgn_qty1"] = helper.add(gatherNode[prefix + "c_dgn_qty1"], sourceNode.c_dgn_qty1);
+        gatherNode[prefix + "c_dgn_qty2"] = helper.add(gatherNode[prefix + "c_dgn_qty2"], sourceNode.c_dgn_qty2);
+
+        gatherNode['s_' + "qty"] = helper.add(gatherNode['s_' + "qty"], sourceNode.quantity);
+        gatherNode['s_' + "tp"] = helper.add(gatherNode['s_' + "tp"], sourceNode.total_price);
+
+        gatherNode['s_' + "contract_qty"] = helper.add(gatherNode['s_' + "contract_qty"], sourceNode.contract_qty);
+        gatherNode['s_' + "contract_tp"] = helper.add(gatherNode['s_' + "contract_tp"], sourceNode.contract_tp);
+        gatherNode['s_' + "qc_qty"] = helper.add(gatherNode['s_' + "qc_qty"], sourceNode.qc_qty);
+        gatherNode['s_' + "qc_tp"] = helper.add(gatherNode['s_' + "qc_tp"], sourceNode.qc_tp);
+        gatherNode['s_' + "gather_qty"] = helper.add(gatherNode['s_' + "gather_qty"], sourceNode.gather_qty);
+        gatherNode['s_' + "gather_tp"] = helper.add(gatherNode['s_' + "gather_tp"], sourceNode.gather_tp);
+
+        gatherNode['s_' + "pre_contract_qty"] = helper.add(gatherNode['s_' + "pre_contract_qty"], sourceNode.pre_contract_qty);
+        gatherNode['s_' + "pre_contract_tp"] = helper.add(gatherNode['s_' + "pre_contract_tp"], sourceNode.pre_contract_tp);
+        gatherNode['s_' + "pre_qc_qty"] = helper.add(gatherNode['s_' + "pre_qc_qty"], sourceNode.pre_qc_qty);
+        gatherNode['s_' + "pre_qc_tp"] = helper.add(gatherNode['s_' + "pre_qc_tp"], sourceNode.pre_qc_tp);
+        gatherNode['s_' + "pre_gather_qty"] = helper.add(gatherNode['s_' + "pre_gather_qty"], sourceNode.pre_gather_qty);
+        gatherNode['s_' + "pre_gather_tp"] = helper.add(gatherNode['s_' + "pre_gather_tp"], sourceNode.pre_gather_tp);
+
+        gatherNode['s_' + "end_contract_qty"] = helper.add(gatherNode['s_' + "end_contract_qty"], sourceNode.end_contract_qty);
+        gatherNode['s_' + "end_contract_tp"] = helper.add(gatherNode['s_' + "end_contract_tp"], sourceNode.end_contract_tp);
+        gatherNode['s_' + "end_qc_qty"] = helper.add(gatherNode['s_' + "end_qc_qty"], sourceNode.end_qc_qty);
+        gatherNode['s_' + "end_qc_tp"] = helper.add(gatherNode['s_' + "end_qc_tp"], sourceNode.end_qc_tp);
+        gatherNode['s_' + "end_gather_qty"] = helper.add(gatherNode['s_' + "end_gather_qty"], sourceNode.end_gather_qty);
+        gatherNode['s_' + "end_gather_tp"] = helper.add(gatherNode['s_' + "end_gather_tp"], sourceNode.end_gather_tp);
+    },
+    gatherZone: function (tender, gatherNode, sourceNode, prefix, helper) {
+        gatherNode[prefix + 'id'] = tender.id;
+        gatherNode[prefix + 'name'] = tender.name;
+
+        gatherNode[prefix + "qty"] = helper.add(gatherNode[prefix + "qty"], sourceNode.quantity);
+        gatherNode[prefix + "tp"] = helper.add(gatherNode[prefix + "tp"], sourceNode.total_price);
+
+        gatherNode[prefix + "dgn_qty1"] = helper.add(gatherNode[prefix + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode[prefix + "dgn_qty2"] = helper.add(gatherNode[prefix + "dgn_qty2"], sourceNode.dgn_qty2);
+
+        gatherNode[prefix + "contract_qty"] = helper.add(gatherNode[prefix + "contract_qty"], sourceNode.contract_qty);
+        gatherNode[prefix + "contract_tp"] = helper.add(gatherNode[prefix + "contract_tp"], sourceNode.contract_tp);
+        gatherNode[prefix + "qc_qty"] = helper.add(gatherNode[prefix + "qc_qty"], sourceNode.qc_qty);
+        gatherNode[prefix + "qc_tp"] = helper.add(gatherNode[prefix + "qc_tp"], sourceNode.qc_tp);
+        gatherNode[prefix + "gather_qty"] = helper.add(gatherNode[prefix + "gather_qty"], sourceNode.gather_qty);
+        gatherNode[prefix + "gather_tp"] = helper.add(gatherNode[prefix + "gather_tp"], sourceNode.gather_tp);
+
+        gatherNode[prefix + "deal_dgn_qty1"] = helper.add(gatherNode[prefix + "deal_dgn_qty1"], sourceNode.deal_dgn_qty1);
+        gatherNode[prefix + "deal_dgn_qty2"] = helper.add(gatherNode[prefix + "deal_dgn_qty2"], sourceNode.deal_dgn_qty2);
+        gatherNode[prefix + "c_dgn_qty1"] = helper.add(gatherNode[prefix + "c_dgn_qty1"], sourceNode.c_dgn_qty1);
+        gatherNode[prefix + "c_dgn_qty2"] = helper.add(gatherNode[prefix + "c_dgn_qty2"], sourceNode.c_dgn_qty2);
+
+        gatherNode['s_' + "qty"] = helper.add(gatherNode['s_' + "qty"], sourceNode.quantity);
+        gatherNode['s_' + "tp"] = helper.add(gatherNode['s_' + "tp"], sourceNode.total_price);
+
+        gatherNode['s_' + "contract_qty"] = helper.add(gatherNode['s_' + "contract_qty"], sourceNode.contract_qty);
+        gatherNode['s_' + "contract_tp"] = helper.add(gatherNode['s_' + "contract_tp"], sourceNode.contract_tp);
+        gatherNode['s_' + "qc_qty"] = helper.add(gatherNode['s_' + "qc_qty"], sourceNode.qc_qty);
+        gatherNode['s_' + "qc_tp"] = helper.add(gatherNode['s_' + "qc_tp"], sourceNode.qc_tp);
+        gatherNode['s_' + "gather_qty"] = helper.add(gatherNode['s_' + "gather_qty"], sourceNode.gather_qty);
+        gatherNode['s_' + "gather_tp"] = helper.add(gatherNode['s_' + "gather_tp"], sourceNode.gather_tp);
+    },
+    gatherLedger: function (tender, gatherNode, sourceNode, prefix, helper) {
+        gatherNode[prefix + 'id'] = tender.id;
+        gatherNode[prefix + 'name'] = tender.name;
+
+        gatherNode[prefix + "qty"] = helper.add(gatherNode[prefix + "qty"], sourceNode.quantity);
+        gatherNode[prefix + "tp"] = helper.add(gatherNode[prefix + "tp"], sourceNode.total_price);
+
+        gatherNode[prefix + "dgn_qty1"] = helper.add(gatherNode[prefix + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode[prefix + "dgn_qty2"] = helper.add(gatherNode[prefix + "dgn_qty2"], sourceNode.dgn_qty2);
+
+        gatherNode['s_' + "qty"] = helper.add(gatherNode['s_' + "qty"], sourceNode.quantity);
+        gatherNode['s_' + "tp"] = helper.add(gatherNode['s_' + "tp"], sourceNode.total_price);
+    },
+    gatherSpecial: function (gatherNode, sourceNode, prefix, helper) {
+        gatherNode[prefix + "qty"] = helper.add(gatherNode[prefix + "qty"], sourceNode.quantity);
+        gatherNode[prefix + "tp"] = helper.add(gatherNode[prefix + "tp"], sourceNode.total_price);
+
+        gatherNode[prefix + "dgn_qty1"] = helper.add(gatherNode[prefix + "dgn_qty1"], sourceNode.dgn_qty1);
+        gatherNode[prefix + "dgn_qty2"] = helper.add(gatherNode[prefix + "dgn_qty2"], sourceNode.dgn_qty2);
+    },
+};
+
+module.exports = app => {
+    class RptStageSumMemory extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+        }
+
+        async getStageSumBills(tid, memFieldKeys, gsDefine, gsCustom) {
+            const self = this;
+            if (!gsDefine || !gsDefine.enable) return [];
+            if (!gsCustom || !gsCustom.stages || gsCustom.stages.length === 0) return [];
+
+            await this.ctx.service.tender.checkTender(tid);
+            const billsData = await this.ctx.service.ledger.getData(this.ctx.tender.id);
+            const calcFields = ['deal_tp', 'total_price'], calcPrefix = [];
+
+            const gsSetting = JSON.parse(gsDefine.setting);
+            for (const s of gsCustom.stages) {
+                const stage = await this.db.get(this.ctx.service.stage.tableName, { tid: this.ctx.tender.id, order: s });
+                if (!stage) continue;
+                await this.ctx.service.stage.doCheckStage(stage);
+
+                const prefix = 's_' + stage.order + '_';
+                calcFields.push(prefix + 'contract_tp');
+                calcFields.push(prefix + 'qc_tp');
+                calcFields.push(prefix + 'gather_tp');
+                calcPrefix.push(prefix);
+
+                const curStage = stage.readOnly
+                    ? await this.ctx.service.stageBills.getAuditorStageData(this.ctx.tender.id, stage.id, stage.curTimes, stage.curOrder)
+                    : await this.ctx.service.stageBills.getLastestStageData(this.ctx.tender.id, stage.id);
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp'], prefix: prefix, relaId: 'lid'}
+                ]);
+            }
+
+            const billsTree = new Ledger.billsTree(this.ctx, {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                keys: ['id', 'tender_id', 'ledger_id'],
+                stageId: 'id',
+                calcFields: calcFields,
+                calc: function (node) {
+                    for (const prefix of calcPrefix) {
+                        if (node.children && node.children.length === 0) {
+                            node[prefix + 'gather_qty'] = self.ctx.helper.add(node[prefix + 'contract_qty'], node[prefix + 'qc_qty']);
+                        }
+                        node[prefix + 'gather_tp'] = self.ctx.helper.add(node[prefix + 'contract_tp'], node[prefix + 'qc_tp']);
+                    }
+                }
+            });
+            billsTree.loadDatas(billsData);
+            billsTree.calculateAll();
+            return billsTree.getDefaultDatas();
+        }
+
+        /**
+         * 合同支付
+         */
+
+        async _checkStagePayCalc(tender, stage, dealPay) {
+            if (!stage.readOnly) {
+                // 计算 本期金额
+                const payCalculator = new PayCalculator(this.ctx, stage, tender.info);
+                await payCalculator.calculateAll(dealPay);
+            }
+        }
+
+        async _gatherStagePay(tender, stage, payData) {
+            if (stage) {
+                await this.ctx.service.stage.doCheckStage(stage);
+
+                const dealPay = await this.ctx.service.stagePay.getStagePays(stage);
+                await this._checkStagePayCalc(tender, stage, dealPay);
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: dealPay, fields: ['tp'], prefix: 's_' + stage.order + '_', relaId: 'pid'}
+                ]);
+            }
+        }
+
+        async getStageSumPay(tid, memFieldKeys, gsDefine, gsCustom) {
+            if (!gsDefine || !gsDefine.enable) return [];
+            if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
+
+            await this.ctx.service.tender.checkTender(tid);
+            const payData = await this.ctx.service.pay.getAllDataByCondition({
+                where: {tid: tid},
+                order: [['order', 'ASC']],
+            });
+
+            const gsSetting = JSON.parse(gsDefine.setting);
+            for (const s of gsCustom.stages) {
+                const stage = this.getSelectStage(gsSetting, s);
+                await this.ctx.service.stage.doCheckStage(stage);
+                await this._gatherStagePay(this.ctx.tender, stage, payData);
+
+            }
+        }
+    }
+
+    return RptStageSumMemory;
+};

+ 9 - 0
app/view/report/index.ejs

@@ -174,6 +174,15 @@
                                     </div>
                                 </div>
                             </div>
+                            <div class="panel" id="pnl_stage_select" style="display: none;">
+                                <div class="panel-body">
+                                    <div class="btn-group" role="group">
+                                        <button class="btn btn-primary btn-sm" type="button" data-toggle="modal" data-target="#stage-select">
+                                            选择期<br><span class="badge badge-light" id="stage-select-count">5</span>
+                                        </button>
+                                    </div>
+                                </div>
+                            </div>
                         </div>
                     </div>
                     <div class="sjs-height-4">

+ 29 - 0
app/view/report/rpt_all_popup.ejs

@@ -317,6 +317,35 @@
         </div>
     </div>
 </div>
+<div class="modal fade" id="stage-select" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="stage-select-title">选择期</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <% for (const s of stages) { %>
+                    <div class="col-3">
+                        <div class="custom-control custom-checkbox custom-control-inline">
+                            <input type="checkbox" id="stage-select-<%- s.order %>" name="stage-select-check" stage-order="<%- s.order %>" class="custom-control-input">
+                            <label class="custom-control-label" for="stage-select-<%- s.order %>">第<%- s.order %>期</label>
+                        </div>
+                    </div>
+                    <% } %>
+                </div>
+                <div class="alert alert-danger my-2 p-2" id="stage-select-hint">我是提示呀</div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button class="btn btn-sm btn-primary" id="stage-select-ok">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
 <!--管理通用报表-->
 <div class="modal fade" id="man-c" data-backdrop="static">
     <div class="modal-dialog" role="document">

+ 32 - 39
builder_report_index_define.js

@@ -1026,12 +1026,12 @@ const materialGl = {
     ],
 };
 
-const sum_stage_bills = {
-    name: '期汇总-清单数据表(mem_sum_stage_bills)',
+const stage_sum_bills = {
+    name: '期汇总-清单-交叉数据表(mem_stage_sum_bills)',
     remark: '',
     id: 42,
-    key: 'mem_sum_stage_bills',
-    prefix: '期汇总-清单数据',
+    key: 'mem_stage_sum_bills',
+    prefix: '期汇总-清单-交叉数据',
     cols: [
         { name: '台账ID', field: 'id', type: dataType.int },
         { name: '标段ID', field: 'tender_id', type: dataType.int },
@@ -1068,40 +1068,33 @@ const sum_stage_bills = {
         { name: '节点类型', field: 'node_type', type: dataType.int },
         { name: '总额计量', field: 'is_tp', type: dataType.int },
 
-        { name: '第1期-合同-数量', field: 's1_contract_qty', type: dataType.currency },
-        { name: '第1期-合同-金额', field: 's1_contract_tp', type: dataType.currency },
-        { name: '第1期-变更-数量', field: 's1_qc_qty', type: dataType.currency },
-        { name: '第1期-变更-金额', field: 's1_qc_tp', type: dataType.currency },
-        { name: '第1期-完成-数量', field: 's1_gather_qty', type: dataType.currency },
-        { name: '第1期-完成-金额', field: 's1_gather_tp', type: dataType.currency },
-
-        { name: '第2期-合同-数量', field: 's2_contract_qty', type: dataType.currency },
-        { name: '第2期-合同-金额', field: 's2_contract_tp', type: dataType.currency },
-        { name: '第2期-变更-数量', field: 's2_qc_qty', type: dataType.currency },
-        { name: '第2期-变更-金额', field: 's2_qc_tp', type: dataType.currency },
-        { name: '第2期-完成-数量', field: 's2_gather_qty', type: dataType.currency },
-        { name: '第2期-完成-金额', field: 's2_gather_tp', type: dataType.currency },
-
-        { name: '第3期-合同-数量', field: 's3_contract_qty', type: dataType.currency },
-        { name: '第3期-合同-金额', field: 's3_contract_tp', type: dataType.currency },
-        { name: '第3期-变更-数量', field: 's3_qc_qty', type: dataType.currency },
-        { name: '第3期-变更-金额', field: 's3_qc_tp', type: dataType.currency },
-        { name: '第3期-完成-数量', field: 's3_gather_qty', type: dataType.currency },
-        { name: '第3期-完成-金额', field: 's3_gather_tp', type: dataType.currency },
-
-        { name: '第4期-合同-数量', field: 's4_contract_qty', type: dataType.currency },
-        { name: '第4期-合同-金额', field: 's4_contract_tp', type: dataType.currency },
-        { name: '第4期-变更-数量', field: 's4_qc_qty', type: dataType.currency },
-        { name: '第4期-变更-金额', field: 's4_qc_tp', type: dataType.currency },
-        { name: '第4期-完成-数量', field: 's4_gather_qty', type: dataType.currency },
-        { name: '第4期-完成-金额', field: 's4_gather_tp', type: dataType.currency },
-
-        { name: '第5期-合同-数量', field: 's5_contract_qty', type: dataType.currency },
-        { name: '第5期-合同-金额', field: 's5_contract_tp', type: dataType.currency },
-        { name: '第5期-变更-数量', field: 's5_qc_qty', type: dataType.currency },
-        { name: '第5期-变更-金额', field: 's5_qc_tp', type: dataType.currency },
-        { name: '第5期-完成-数量', field: 's5_gather_qty', type: dataType.currency },
-        { name: '第5期-完成-金额', field: 's5_gather_tp', type: dataType.currency },
+        { name: '(期)-第几期', field: 's_order', type: dataType.int },
+        { name: '(期)-合同-数量', field: 's1_contract_qty', type: dataType.currency },
+        { name: '(期)-合同-金额', field: 's1_contract_tp', type: dataType.currency },
+        { name: '(期)-变更-数量', field: 's1_qc_qty', type: dataType.currency },
+        { name: '(期)-变更-金额', field: 's1_qc_tp', type: dataType.currency },
+        { name: '(期)-完成-数量', field: 's1_gather_qty', type: dataType.currency },
+        { name: '(期)-完成-金额', field: 's1_gather_tp', type: dataType.currency },
+
+        { name: '交叉排序', field: 'cross_index', type: dataType.int },
+    ],
+};
+const stage_sum_pay = {
+    name: '期汇总-合同支付 数据表(mem_stage_sum_pay)',
+    remark: '',
+    id: 43,
+    key: 'mem_stage_sum_pay',
+    prefix: '期汇总-合同支付',
+    cols: [
+        { name: '名称', field: 'name', type: dataType.str },
+        { name: '类型', field: 'ptype', type: dataType.int },
+        { name: '是否扣款项', field: 'minus', type: dataType.int },
+        { name: '是否参与本期应付计算', field: 'is_yf', type: dataType.int },
+
+        { name: '(期)第几期', field: 's_order', type: dataType.int },
+        { name: '(期)本期-金额', field: 't_tp', type: dataType.currency },
+
+        { name: '交叉排序', field: 'cross_index', type: dataType.int },
     ],
 };
 
@@ -1206,7 +1199,7 @@ const defines = [
     stage_im_zl, stage_im_tz, stage_im_tz_bills,
     gather_stage_bills, gather_tender_info, gather_stage_pay, gather_deal_bills,
     material, materialGl,
-    sum_stage_bills
+    stage_sum_bills, stage_sum_pay
 ];
 for (const d of defines) {
     exportTableDefine(d);

+ 3 - 0
sql/update.sql

@@ -96,3 +96,6 @@ ADD COLUMN `re_upload` INT NOT NULL DEFAULT 0 COMMENT '是否为审核通过后
 ALTER TABLE `zh_project_account` ADD `wx_openid` VARCHAR(50) NULL DEFAULT NULL COMMENT '微信绑定openid' AFTER `bind`;
 ALTER TABLE `zh_project_account` ADD `wx_name` VARCHAR(255) NULL DEFAULT NULL COMMENT '微信昵称' AFTER `wx_openid`;
 ALTER TABLE `zh_project_account` ADD `wx_type` TEXT NULL DEFAULT NULL COMMENT '微信通知类型' AFTER `sms_type`;
+
+ALTER TABLE `zh_rpt_custom_define`
+ADD COLUMN `stage_select`  text CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '用户定制信息 - 多期汇总表' AFTER `gather_select`;