瀏覽代碼

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionOperation

zhongzewei 7 年之前
父節點
當前提交
e80ce300d5

+ 2 - 2
modules/reports/rpt_component/helper/jpc_helper_flow_tab.js

@@ -38,9 +38,9 @@ let JpcFlowTabHelper = {
         }
         return rst;
     },
-    chkSegEnd: function (bands, rptTpl, sortedSequence, segIdx, preRec, nextRec, isEx) {
+    chkSegEnd: function (bands, rptTpl, segmentLength, preRec, nextRec, isEx) {
         let me = this;
-        let remainAmt = preRec + nextRec - sortedSequence[segIdx].length;
+        let remainAmt = preRec + nextRec - segmentLength;
         return me.hasEnoughSpace(rptTpl, bands, remainAmt, isEx);
     },
     hasEnoughSpace: function (rptTpl, bands, remainAmt, isEx) {

+ 6 - 0
modules/reports/rpt_component/helper/jpc_helper_text.js

@@ -8,6 +8,12 @@ let JpcTextHelper = {
         //position
         rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(textNode[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, multiCols, multiColIdx, false, false);
         return rst;
+    },
+    outputDirectValue: function (textNode, value, band, unitFactor, rows, rowIdx, cols, colIdx, multiCols, multiColIdx) {
+        let rst = JpcCommonOutputHelper.createCommonOutput(textNode, value, null);
+        //position
+        rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(textNode[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, multiCols, multiColIdx, false, false);
+        return rst;
     }
 };
 

+ 12 - 10
modules/reports/rpt_component/jpc_ex.js

@@ -142,16 +142,15 @@ JpcExSrv.prototype.createNew = function(){
         let me = this, dftPagingOption = option||JV.PAGING_OPTION_NORMAL;
         if (me.flowTab) {
             if (me.isFollowMode) {
-                //
+                me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption, me, me.flowTabEx);
             } else {
-                //
-            }
-            me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
-            if (me.flowTabEx) {
-                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
-                //console.log('ad-hoc flow pages: ' + me.exTotalPages);
+                me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption, me, null);
+                if (me.flowTabEx) {
+                    me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption, me, null);
+                    //console.log('ad-hoc flow pages: ' + me.exTotalPages);
+                }
+                me.totalPages += me.exTotalPages;
             }
-            me.totalPages += me.exTotalPages;
         } else if (me.crossTab) {
             //me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, dftPagingOption);
             me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, JV.PAGING_OPTION_NORMAL); //infinity对交叉表来说无意义
@@ -166,7 +165,7 @@ JpcExSrv.prototype.createNew = function(){
                 let expression = me.formulas[i][JV.PROP_EXPRESSION];
                 if (expression) {
                     let $ME = me.formulas[i];
-                    console.log(expression);
+                    // console.log(expression);
                     eval(expression);
                 }
             }
@@ -224,8 +223,11 @@ JpcExSrv.prototype.createNew = function(){
                         adHocMergePos[JV.NODE_PAGE_SIZE] = JpcCommonHelper.getPageSize(rptTpl);
                         rst[JV.PAGE_SPECIAL_MERGE_POS] = adHocMergePos;
                     }
+
                 } else {
-                    rst.cells = me.flowTabEx.outputAsSimpleJSONPage(rptTpl, dataObj, page - (me.totalPages - me.exTotalPages), bands, controls, adHocMergePos, me);
+                    if (!me.isFollowMode) {
+                        rst.cells = me.flowTabEx.outputAsSimpleJSONPage(rptTpl, dataObj, page - (me.totalPages - me.exTotalPages), bands, controls, adHocMergePos, me);
+                    }
                 }
             } else if (me.crossTab) {
                 rst.cells = me.crossTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);

+ 442 - 31
modules/reports/rpt_component/jpc_flow_tab.js

@@ -11,14 +11,63 @@ let JpcCommonOutputHelper = require('./helper/jpc_helper_common_output');
 let JpcAreaHelper = require('./helper/jpc_helper_area');
 
 let JpcFlowTabSrv = function(){};
+//let grpPageInfo = {"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null};
 JpcFlowTabSrv.prototype.createNew = function(){
-    function private_addPageValue(ValuedIdxLst, sortedSequence, preRec, nextRec,page_seg_map, segIdx, pageIdx) {
-        let vIdx = [];
-        for (let vi = 0; vi < nextRec; vi++) {
-            if (sortedSequence.length > preRec + vi) {
-                vIdx.push(sortedSequence[preRec + vi]);
+    function private_addPageValue(ValuedIdxLst, sortedSequence, grpSequenceInfo, startRecIdx, maxRecPerPage,page_seg_map, segIdx, pageIdx, grpPageInfo, isFollow) {
+        let vIdx = [], preAmt = 0, insertedGrpAmt = 0, grp_lines = 0;
+        if (grpSequenceInfo && grpPageInfo) {
+            //grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
+            if (grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].length > 0) {
+                for (let grpLineIdx of grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO]) {
+                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], grpLineIdx]);
+                }
+                grpPageInfo[JV.PROP_SEG_GRP_IDX]++;
+            }
+            preAmt = grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].length;
+            grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
+            grp_lines = grpPageInfo[JV.PROP_GRP_LINES];
+        }
+        for (let vi = 0; (vi + insertedGrpAmt * grp_lines) < maxRecPerPage - preAmt; vi++) {
+            if (grpSequenceInfo && grpPageInfo) {
+                if ((startRecIdx + vi) === grpSequenceInfo[grpPageInfo[JV.PROP_SEG_GRP_IDX]]) {
+                    //表示这里要插入grouping信息啦!
+                    //1. 首先push正常的记录
+                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    //2. 然后就要push grouping记录了
+                    let hasFullGrp = true;
+                    for (let i = 0; i < grp_lines; i++) {
+                        if ( ((vi + insertedGrpAmt * grp_lines) + i + 1) >= (maxRecPerPage - preAmt)) {
+                            for (let j = i; j < grp_lines; j++) {
+                                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].push(j);
+                            }
+                            //准备要跳出去了
+                            hasFullGrp = false;
+                            break;
+                        } else {
+                            vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], i]);
+                        }
+                    }
+                    //3. 进位下一个group信息所在位置
+                    if (hasFullGrp) {
+                        grpPageInfo[JV.PROP_INSERTED_GRP_REC]++;
+                        insertedGrpAmt++;
+                        grpPageInfo[JV.PROP_SEG_GRP_IDX]++;
+                    } else {
+                        break;
+                    }
+                } else {
+                    if (sortedSequence.length > startRecIdx + vi) {
+                        vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    } else {
+                        vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                    }
+                }
             } else {
-                vIdx.push(JV.BLANK_VALUE_INDEX);
+                if (sortedSequence.length > startRecIdx + vi) {
+                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                } else {
+                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                }
             }
         }
         page_seg_map.push([pageIdx, segIdx]);
@@ -36,7 +85,13 @@ JpcFlowTabSrv.prototype.createNew = function(){
         me.seg_sum_fields_idx = [];
         me.seg_sum_tab_fields = [];
         me.page_sum_fields_idx = [];
-        me.group_fields_idx = [];
+
+        me.group_fields = [];
+        me.group_sum_fields = [];
+        me.group_sum_values = null;
+        me.group_node_info = null; //记录在哪个seg及到哪条记录后有group sum信息
+        me.group_lines_amt = 0;    //每group一次占用多少行,计算page信息会用到
+
         me.pageStatusLst = [];
         me.groupSumValLst = [];
         me.segSumValLst = [];
@@ -48,7 +103,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_SEG_SUM][JV.PROP_SUM_FIELDS], me.seg_sum_tab_fields, me.seg_sum_fields_idx, me.isEx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_PAGE_SUM][JV.PROP_SUM_FIELDS], null, me.page_sum_fields_idx, me.isEx);
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], null, me.group_fields_idx, me.isEx);
+        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], me.group_fields, null, me.isEx);
+        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_SUM_FIELDS], me.group_sum_fields, null, me.isEx);
         for (let si = 0; si < dataSeq.length; si++) {
             me.segments.push(dataSeq[si].slice(0));
         }
@@ -74,8 +130,271 @@ JpcFlowTabSrv.prototype.createNew = function(){
 
         }
     };
-    JpcFlowTabResult.preSetupPages = function (rptTpl, dataOjb, defProperties, option) {
+    JpcFlowTabResult.sumUpGrp = function ($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx) {
+        let me = this, segDataIdx = me.segments[segIdx];
+        for (let j = 0; j < me.group_sum_fields.length; j++) {
+            let sum_field = JE.F(me.group_sum_fields[j][JV.PROP_FIELD_ID], $CURRENT_RPT);
+            if (sum_field) {
+                let data_field = null;
+                if (sum_field[JV.PROP_AD_HOC_DATA]) {
+                    data_field = sum_field[JV.PROP_AD_HOC_DATA]
+                } else {
+                    data_field = dataObj[sum_field.DataNodeName][sum_field.DataSeq];
+                }
+                let sumV = 0;
+                for (let si = preGrpIdx; si <= nexGrpIdx; si++) {
+                    sumV += JpcFieldHelper.getValue(data_field, segDataIdx[si]);
+                }
+                // me.group_sum_values[segIdx][j].push(sumV);
+                me.group_sum_values[segIdx][me.group_sum_fields[j][JV.PROP_SUM_KEY]].push(sumV);
+            }
+        }
+        me.group_node_info[segIdx].push(nexGrpIdx);
+    };
+    JpcFlowTabResult.setupGroupingData = function (rptTpl, dataObj, $CURRENT_RPT) {
+        let me = this;
+        if (me.group_fields.length > 0 && me.group_sum_fields.length > 0) {
+            me.group_sum_values = [];
+            me.group_node_info = [];
+            let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+            me.group_lines_amt = rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length;
+            //
+            let preGrpIdx = 0, nexGrpIdx = 0;
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                let segDataIdx = me.segments[segIdx];
+                // me.group_sum_values.push([]);
+                me.group_sum_values.push({});
+                me.group_node_info.push([]);
+                for (let j = 0; j < me.group_sum_fields.length; j++) {
+                    // me.group_sum_values[segIdx].push([]);
+                    me.group_sum_values[segIdx][me.group_sum_fields[j][JV.PROP_SUM_KEY]] = [];
+                    // me.group_node_info[segIdx].push([]);
+                }
+                for (let di = 0; di < segDataIdx.length; di++) {
+                    let hasDiff = false;
+                    if (di > 1) {
+                        for (let i = 0; i < me.group_fields.length; i++) {
+                            let grp_field = JE.F(me.group_fields[i][JV.PROP_FIELD_ID], $CURRENT_RPT);
+                            if (grp_field) {
+                                let data_field = null;
+                                if (grp_field[JV.PROP_AD_HOC_DATA]) {
+                                    data_field = grp_field[JV.PROP_AD_HOC_DATA]
+                                } else {
+                                    data_field = dataObj[grp_field.DataNodeName][grp_field.DataSeq];
+                                }
+                                let v1 = JpcFieldHelper.getValue(data_field, segDataIdx[di]), v2 = JpcFieldHelper.getValue(data_field, segDataIdx[di - 1]);
+                                if (v1 !== v2) {
+                                    hasDiff = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    if (hasDiff) {
+                        //then sum up the fields
+                        me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx);
+                        nexGrpIdx = di;
+                        preGrpIdx = di;
+                        if (di === segDataIdx.length - 1) {
+                            me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx);
+                        }
+                    } else if (di === segDataIdx.length - 1) {
+                        me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, di);
+                    } else {
+                        nexGrpIdx = di;
+                    }
+                }
+            }
+        }
+    };
+
+    JpcFlowTabResult.preSetupPages = function (rptTpl, dataObj, defProperties, option, $CURRENT_RPT, followTabEx) {
+        //换一种思路来整理流水式数据
+        let me = this, rst = 1, counterRowRec = 0, counterRowRecEx = 0, maxRowRec = 1, pageIdx = 0, currentRecAmt = 0;
+        me.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
+        if (followTabEx) {
+            followTabEx.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
+        }
+        me.paging_option = option||JV.PAGING_OPTION_NORMAL;
+        let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, me.isEx);
+        if (me.paging_option === JV.PAGING_OPTION_INFINITY) {
+            rst = me.segments.length;
+            let pageStatus = [true, true, false, true, true, true, false, false];
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                if (segIdx === me.segments.length - 1) {
+                    pageStatus[JV.STATUS_REPORT_END] = true;
+                }
+                if (segIdx > 0) {
+                    pageStatus[JV.STATUS_REPORT_START] = false;
+                }
+                me.pageStatusLst.push(pageStatus.slice(0));
+                pageIdx++;
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx, null, false);
+            }
+            //目前不支持flowTabEx
+        } else {
+            let bands = JpcBand.createNew(rptTpl, defProperties);
+            let pageStatus = [true, true, false, true, false, false, false, false];
+            if (me.isEx) {
+                pageStatus[JV.STATUS_REPORT_START] = false;
+            }
+            if (rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN]) {
+                me.multiCols = 1 * rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN];
+            }
+            let grpPageInfo = {};
+            function private_resetBandArea() {
+                JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
+                maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl, me.isEx);
+            }
+            function private_addPage(segIdx, grpSeqInfo, isFollow, isMix, mixSplitPoint) {
+                private_resetBandArea();
+                me.pageStatusLst.push(pageStatus.slice(0));
+                currentRecAmt += maxRowRec;
+                pageIdx++;
+                if (isMix) {
+                    //先处理上半部分
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, mixSplitPoint,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
+                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
+                    }
+                    //再处理下半部分
+                    private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec - mixSplitPoint, me.page_seg_map, segIdx, pageIdx, null, true);
+                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRecEx++;
+                    }
+                    //合并到一页中
+                    me.page_seg_map.splice(me.page_seg_map.length - 1, 1);
+                    let vl = me.dispValueIdxLst[me.dispValueIdxLst.length - 2];
+                    for (let item of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        vl.push(item);
+                    }
+                    me.dispValueIdxLst.splice(me.dispValueIdxLst.length - 1, 1);
+                } else if (isFollow) {
+                    private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec, me.page_seg_map, segIdx, pageIdx, null, true);
+                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRecEx++;
+                    }
+                } else {
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
+                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
+                    }
+                }
+            }
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                let grpRecAmt = (grpSeqInfo)?(grpSeqInfo.length*me.group_lines_amt):0;
+                let grpRecAmtEx = 0;
+                if (followTabEx && followTabEx.group_node_info) {
+                    grpRecAmtEx = followTabEx.group_node_info.length * followTabEx.group_lines_amt;
+                }
+                grpPageInfo[JV.PROP_SEG_GRP_IDX] = 0;
+                grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
+                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
+                grpPageInfo[JV.PROP_GRP_LINES] = me.group_lines_amt;
+                pageStatus[JV.STATUS_SEGMENT_START] = true;
+                private_resetBandArea();
+                let threshold = 0;
+                currentRecAmt = 0;
+                counterRowRec = 0;
+                counterRowRecEx = 0;
+                let ttlSegRecAmtNormal = me.segments[segIdx].length + grpRecAmt;
+                let ttlSegRecAmt = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt);
+                while (true) {
+                    if (currentRecAmt > 0) pageStatus[JV.STATUS_SEGMENT_START] = false;
+                    if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
+                    //开始判断各种scenarios
+                    if (ttlSegRecAmtNormal < ttlSegRecAmt) {
+                        if (currentRecAmt + maxRowRec > ttlSegRecAmtNormal) {
+                            if (currentRecAmt >= ttlSegRecAmtNormal) {
+                                //纯 followTabEx 数据
+                                if (currentRecAmt + maxRowRec >= ttlSegRecAmt) {
+                                    pageStatus[JV.STATUS_SEGMENT_END] = true;
+                                    private_resetBandArea();
+                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt, maxRowRec, me.isEx);
+                                    if (hasAdHocRow) {
+                                        //add page info(pre segment end)
+                                        pageStatus[JV.STATUS_SEGMENT_END] = false;
+                                        private_addPage(segIdx, null, true, false, -1);
+                                    }
+                                    //add page info
+                                    pageStatus[JV.STATUS_SEGMENT_END] = true;
+                                    private_addPage(segIdx, null, true, false, -1);
+                                } else {
+                                    private_addPage(segIdx, null, true, false, -1);
+                                }
+                            } else {
+                                //混合数据
+                                if (currentRecAmt + maxRowRec >= ttlSegRecAmt) {
+                                    pageStatus[JV.STATUS_SEGMENT_END] = true;
+                                    private_resetBandArea();
+                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt, maxRowRec, me.isEx);
+                                    if (hasAdHocRow) {
+                                        //add page info(pre segment end)
+                                        pageStatus[JV.STATUS_SEGMENT_END] = false;
+                                        private_addPage(segIdx, grpSeqInfo, false, true, ttlSegRecAmtNormal);
+                                    }
+                                    //add page info
+                                    pageStatus[JV.STATUS_SEGMENT_END] = true;
+                                    if (currentRecAmt >= ttlSegRecAmtNormal) {
+                                        //纯 followTabEx 数据啦
+                                        private_addPage(segIdx, null, true, false, -1);
+                                    } else {
+                                        private_addPage(segIdx, grpSeqInfo, false, true, ttlSegRecAmtNormal);
+                                    }
+                                } else {
+                                    private_addPage(segIdx, grpSeqInfo, false, true, ttlSegRecAmtNormal);
+                                }
+                            }
+                        } else {
+                            //纯followTab数据
+                            private_addPage(segIdx, grpSeqInfo, false, false, -1);
+                        }
+                    } else {
+                        if (currentRecAmt + maxRowRec >= ttlSegRecAmt) {
+                            pageStatus[JV.STATUS_SEGMENT_END] = true;
+                            private_resetBandArea();
+                            let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt, maxRowRec, me.isEx);
+                            if (hasAdHocRow) {
+                                //add page info(pre segment end)
+                                pageStatus[JV.STATUS_SEGMENT_END] = false;
+                                private_addPage(segIdx, grpSeqInfo, false, false, -1);
+                            }
+                            //add page info
+                            pageStatus[JV.STATUS_SEGMENT_END] = true;
+                            private_addPage(segIdx, grpSeqInfo, false, false, -1);
+                        } else {
+                            private_addPage(segIdx, grpSeqInfo, false, false, -1);
+                        }
+                    }
+                    //检测是否可退出
+                    if (currentRecAmt >= ttlSegRecAmt) {
+                        break;
+                    }
+                    //控制阀值,超过阀值则强制退出,防止死循环
+                    threshold++;
+                    if (threshold > 500) {
+                        console.log("Hey! There may be a dead loop here!!!");
+                        break;
+                    }
+                }
+            }
+            // console.log(me.dispValueIdxLst);
+            rst = Math.ceil(pageIdx / me.multiCols);
+        }
+        me.pagesAmt = rst;
+        return rst;
+    };
+
+    JpcFlowTabResult.preSetupPages_Org = function (rptTpl, dataObj, defProperties, option, $CURRENT_RPT, followTabEx) {
         let me = this, rst = 1, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
+        me.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
+        if (followTabEx) {
+            followTabEx.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
+        }
+        //console.log(me.group_sum_values);
         me.paging_option = option||JV.PAGING_OPTION_NORMAL;
         let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, me.isEx);
@@ -91,7 +410,11 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 me.pageStatusLst.push(pageStatus.slice(0));
                 pageIdx++;
-                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx);
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx, null, false);
+                if (followTabEx) {
+                    //
+                }
             }
         } else {
             let bands = JpcBand.createNew(rptTpl, defProperties);
@@ -106,29 +429,53 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
                 maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl, me.isEx);
             }
+            let grpPageInfo = {};
             for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                grpPageInfo[JV.PROP_SEG_GRP_IDX] = 0;
+                grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
+                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
+                grpPageInfo[JV.PROP_GRP_LINES] = me.group_lines_amt;
                 private_resetBandArea();
                 let orgMaxRowRec = maxRowRec;
-                let rowSplitCnt = Math.ceil(1.0 * me.segments[segIdx].length / orgMaxRowRec);
+                let grpRecAmt = (grpSeqInfo)?(grpSeqInfo.length*me.group_lines_amt):0;
+                let grpRecAmtEx = 0;
+                let rowSplitCnt = Math.ceil(1.0 * (me.segments[segIdx].length + grpRecAmt) / orgMaxRowRec);
+                let rowSplitCntEx = rowSplitCnt;
+                if (followTabEx) {
+                    rowSplitCntEx = Math.ceil(1.0 * (me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx) / orgMaxRowRec);
+                }
                 pageStatus[JV.STATUS_SEGMENT_END] = true;
                 private_resetBandArea();
-                let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments, segIdx, (rowSplitCnt - 1) * orgMaxRowRec, maxRowRec, me.isEx);
-                if (hasAdHocRow) rowSplitCnt++;
-                if (rowSplitCnt % me.multiCols > 0) {
-                    rowSplitCnt++
+                let len = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt);
+                //let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments[segIdx].length, (rowSplitCntEx - 1) * orgMaxRowRec, maxRowRec, me.isEx);
+                let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, len, (rowSplitCntEx - 1) * orgMaxRowRec, maxRowRec, me.isEx);
+                if (hasAdHocRow) rowSplitCntEx++;
+                if (rowSplitCntEx % me.multiCols > 0) {
+                    rowSplitCntEx++
                 }
-                for (let rowIdx = 0; rowIdx < rowSplitCnt; rowIdx++) {
-                    pageStatus[JV.STATUS_SEGMENT_END] = (rowIdx === (rowSplitCnt - 1));
+                counterRowRec = 0;
+                for (let segPageIdx = 0; segPageIdx < rowSplitCntEx; segPageIdx++) {
+                    pageStatus[JV.STATUS_SEGMENT_END] = (segPageIdx === (rowSplitCntEx - 1));
                     if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
                     private_resetBandArea();
                     me.pageStatusLst.push(pageStatus.slice(0));
                     pageIdx++;
-                    counterRowRec = orgMaxRowRec * rowIdx;
-                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx);
+                    if (followTabEx) {
+                        //
+                    } else {
+                        //
+                    }
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
+                    //备注: 考虑到分组数据是临时融入的,所以需要知道这一页的数据融入了多少条group数据,并且得考虑边界条件情况(group数据可能跨页!)
+                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
+                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
+                    }
                 }
                 pageStatus[JV.STATUS_SEGMENT_END] = false;
                 pageStatus[JV.STATUS_REPORT_START] = false;
             }
+            // console.log(me.dispValueIdxLst);
             rst = Math.ceil(pageIdx / me.multiCols);
         }
         me.pagesAmt = rst;
@@ -205,27 +552,66 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let me = this, rst = [];
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         let tab = rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_CONTENT];
+        let tabEx = (rptTpl[JV.NODE_FLOW_INFO_EX])?rptTpl[JV.NODE_FLOW_INFO_EX][JV.NODE_FLOW_CONTENT]:null;
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
             if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 let tab_fields = tab[JV.PROP_FLOW_FIELDS];
+                let tab_fields_ex = tabEx?tabEx[JV.PROP_FLOW_FIELDS]:null;
                 let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
+                let data_details_ex = $CURRENT_RPT.isFollowMode?dataObj[JV.DATA_DETAIL_DATA_EX]:null;
                 let contentValuesIdx = me.dispValueIdxLst[page - 1];
-                for (let i = 0; i < tab_fields.length; i++) {
-                    let tab_field = tab_fields[i];
-                    let data_field = null;
-                    if (me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
-                        data_field = data_details[me.disp_fields_idx[i]];
-                    } else {
-                        data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
-                        if (data_field) {
-                            data_field = data_field[JV.PROP_AD_HOC_DATA];
+                //normal content
+                for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
+                    for (let i = 0; i < tab_fields.length; i++) {
+                        let tab_field = tab_fields[i];
+                        let data_field = null;
+                        if (me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
+                            data_field = data_details[me.disp_fields_idx[i]];
+                        } else {
+                            data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
+                            if (data_field) {
+                                data_field = data_field[JV.PROP_AD_HOC_DATA];
+                            }
+                        }
+                        if (!(tab_field[JV.PROP_HIDDEN])) {
+                            // rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                            //测试中
+                            if (contentValuesIdx[rowIdx][0] !== JV.TYPE_FOLLOW_MODE && contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_NORMAL) {
+                                rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx][2], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                            }
                         }
                     }
-                    if (!(tab_field[JV.PROP_HIDDEN])) {
-                        for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
-                            rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                    if (contentValuesIdx[rowIdx][0] === JV.TYPE_FOLLOW_MODE) {
+                        for (let i = 0; i < tab_fields_ex.length; i++) {
+                            let tab_field = tab_fields_ex[i];
+                            let data_field = null;
+                            if (me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
+                                data_field = data_details_ex[me.disp_fields_idx[i]];
+                            } else {
+                                data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
+                                if (data_field) {
+                                    data_field = data_field[JV.PROP_AD_HOC_DATA];
+                                }
+                            }
+                            if (!(tab_field[JV.PROP_HIDDEN])) {
+                                if (contentValuesIdx[rowIdx][0] === JV.TYPE_FOLLOW_MODE && contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_NORMAL) {
+                                    rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx][2], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                                }
+                            }
+                        }
+                    }
+                }
+                //grouping content
+                for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
+                    if (contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_GROUP) {
+                        for (let grpIdx = 0; grpIdx < rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length; grpIdx++) {
+                            if (contentValuesIdx[rowIdx][3] === grpIdx) {
+                                let grp_line = rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES][grpIdx];
+                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx)
+                                rst = rst.concat(lineRst);
+                            }
                         }
                     }
                 }
@@ -291,6 +677,31 @@ JpcFlowTabSrv.prototype.createNew = function(){
         rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx, true, false);
         return rst;
     };
+    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx) {
+        let me = this, rst = [];
+        if (grp_line[JV.PROP_GROUP_SUM_KEYS]) {
+            let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
+            let curSegGrpSum = me.group_sum_values[segIdx];
+            for (let sumFieldNode of grp_line[JV.PROP_GROUP_SUM_KEYS]) {
+                let value = curSegGrpSum[sumFieldNode[JV.PROP_SUM_KEY]][grpValueIdx[2]];
+                let sumFldRst = JpcTextHelper.outputDirectValue(sumFieldNode, value,  band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx)
+                rst.push(sumFldRst);
+            }
+        }
+        if (grp_line[JV.PROP_TEXTS]) {
+            for (let txt of grp_line[JV.PROP_TEXTS]) {
+                rst.push(JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx));
+            }
+        }
+        if (grp_line[JV.PROP_DISCRETE_FIELDS]) {
+            //
+        }
+        if (grp_line[JV.PROP_PARAMS]) {
+            //
+        }
+        // console.log(rst);
+        return rst;
+    };
 
     return JpcFlowTabResult;
 };

+ 24 - 11
modules/reports/rpt_component/jpc_rte.js

@@ -65,18 +65,31 @@ let JE = {
     },
     getFieldValue: function (field, dataObj, valIdx, dftVal) {
         let rst = dftVal;
-        if (!field.DataNodeName) {
-            //that means this is a self-defined discrete field!
-            field.DataNodeName = JV.DATA_DISCRETE_DATA;
-            let len = dataObj[JV.DATA_DISCRETE_DATA];
-            field.DataSeq = len;
-            dataObj[JV.DATA_DISCRETE_DATA].push([]);
-        }
-        if (dataObj[field.DataNodeName][field.DataSeq].length > valIdx) {
-            rst = dataObj[field.DataNodeName][field.DataSeq][valIdx];
+        if (field.DataNodeName === "NA") {
+            if (!field[JV.PROP_AD_HOC_DATA]) {
+                field[JV.PROP_AD_HOC_DATA] = [];
+            }
+            if (field[JV.PROP_AD_HOC_DATA].length > valIdx) {
+                rst = field[JV.PROP_AD_HOC_DATA][valIdx];
+            } else {
+                if (dftVal === null && field[JV.PROP_AD_HOC_DATA].length > 0) {
+                    rst = field[JV.PROP_AD_HOC_DATA][field[JV.PROP_AD_HOC_DATA].length - 1];
+                }
+            }
         } else {
-            if (dftVal === null && dataObj[field.DataNodeName][field.DataSeq].length > 0) {
-                rst = dataObj[field.DataNodeName][field.DataSeq][dataObj[field.DataNodeName][field.DataSeq].length - 1];
+            if (!field.DataNodeName) {
+                //that means this is a self-defined discrete field!
+                field.DataNodeName = JV.DATA_DISCRETE_DATA;
+                let len = dataObj[JV.DATA_DISCRETE_DATA];
+                field.DataSeq = len;
+                dataObj[JV.DATA_DISCRETE_DATA].push([]);
+            }
+            if (dataObj[field.DataNodeName][field.DataSeq].length > valIdx) {
+                rst = dataObj[field.DataNodeName][field.DataSeq][valIdx];
+            } else {
+                if (dftVal === null && dataObj[field.DataNodeName][field.DataSeq].length > 0) {
+                    rst = dataObj[field.DataNodeName][field.DataSeq][dataObj[field.DataNodeName][field.DataSeq].length - 1];
+                }
             }
         }
         return rst;

+ 29 - 0
modules/reports/util/rpt_construct_data_util.js

@@ -53,6 +53,32 @@ class Rpt_Common{
         }
         return rst;
     };
+    MultiPlus(arrVal, fixFormat) {
+        let rst = [];
+        for (let i = 0; i < arrVal.length; i++) {
+            let valItem = arrVal[i];
+            if (i === 0) {
+                for (let dtl of valItem) {
+                    let value = parseFloat(dtl);
+                    if (fixFormat) value = value.toFixed(fixFormat);
+                    rst.push(value);
+                }
+            } else {
+                for (let j = 0; j < valItem.length; j++) {
+                    if (j < rst.length) {
+                        let value = rst[j] + valItem[j];
+                        if (fixFormat) value = value.toFixed(fixFormat);
+                        rst[j] = value;
+                    } else {
+                        let value = parseFloat(valItem[j]);
+                        if (fixFormat) value = value.toFixed(fixFormat);
+                        rst.push(value);
+                    }
+                }
+            }
+        }
+        return rst;
+    };
     Minus(val1, val2, fixFormat) {
         let rst = [], maxLen = val1.length, minLen = val2.length;
         if (minLen > maxLen) {
@@ -454,6 +480,9 @@ function ext_getFee(feeKey, dtlFeeKey) {
             }
         }
     }
+    for (let i = 0; i < rst.length; i++) {
+        rst[i] = parseFloat(rst[i]);
+    }
     return rst;
 }
 

+ 31 - 2
public/web/rpt_value_define.js

@@ -35,7 +35,6 @@ const JV = {
     DISPLAY_MODE_INDEPENDENT: "单独模式",
     DISPLAY_MODE_FOLLOW: "紧随模式",
 
-
     NODE_MAIN_INFO: "主信息",
     NODE_MAIN_INFO_RPT_NAME: "报表名称",
     NODE_PAGE_INFO: "打印页面_信息",
@@ -46,6 +45,23 @@ const JV = {
     NODE_BIZ_TYPE_SUM: "汇总类型",
     NODE_BIZ_TYPE_DETAIL: "明细类型",
 
+    NODE_MAP_DATA_HANDLE_INFO: "映射数据预处理",
+    PROP_DATA_KEY: "映射数据对象",
+    PROP_HANDLE_TYPE: "预处理类型",
+    PROP_FILTER_KEY: "过滤键值集",
+    PROP_FILTER_COMPARE_OBJ: "compareObjKey",
+    PROP_FILTER_COMPARE_OBJ_KEY: "compareObjIdKey",
+    PROP_FILTER_COMPARE_VAL: "compareValue",
+    PROP_FILTER_CONDITION: "判断条件",
+    PROP_HANDLE_TYPE_FILTER: "过滤",
+    PROP_HANDLE_TYPE_SUM: "合计",
+    PROP_HANDLE_TYPE_SORT: "排序",
+    PROP_SORT_TYPE: "排序方式",
+    PROP_SORT_KEYS: "排序键值集",
+    PROP_SUM_GROUP_KEYS: "分组键值集",
+    PROP_SUM_SUM_KEYS: "统计键值集",
+    PROP_FIELD_EXP_MAP: "mapExpression",
+
     NODE_FONT_COLLECTION: "font_collection",
     NODE_STYLE_COLLECTION: "style_collection",
     NODE_CONTROL_COLLECTION: "control_collection",
@@ -84,7 +100,10 @@ const JV = {
     PROP_DISCRETE_FIELDS: "discrete_field_s",
     PROP_FLOW_FIELDS: "flow_field_s",
     PROP_BILL_FIELDS: "bill_field_s",
-    PROP_GROUP_FIELDS: "group_field_s",
+    PROP_GROUP_FIELDS: "group_field_s", //用来分组的指标(如按清单、定额etc...)
+    PROP_GROUP_LINES: "group_lines",    //显示分组行,因分组的特殊性,分组的数据当成流水数据一样(行高相同),group_lines里的每一条数据占用流水的一整行,里面再细分(指标/text)
+    PROP_GROUP_SUM_KEYS: "SumKey_S",
+    PROP_SUM_KEY: "SumKey",
     PROP_SUM_FIELDS: "sum_field_s",
     PROP_TEXTS: "text_s",
     PROP_TEXT: "text",
@@ -143,6 +162,11 @@ const JV = {
     BLANK_VALUE_INDEX: -100,
     BLANK_PAGE_VALUE_INDEX: -200,
 
+    PROP_SEG_GRP_IDX: "segGrpRecStartIdx",
+    PROP_PRE_ADD_GRP_REC_INFO: "preAddPageGrpInfo",
+    PROP_INSERTED_GRP_REC: "insertedGrpRecAmt",
+    PROP_GRP_LINES: "me.group_lines_amt",
+
     RUN_TYPE_BEFORE_PAGING: "before_paging",
     RUN_TYPE_BEFORE_OUTPUT: "before_output",
 
@@ -208,6 +232,11 @@ const JV = {
     PAGING_OPTION_NORMAL: 'normal',
     PAGING_OPTION_INFINITY: 'infinity',
 
+    DISPLAY_VAL_TYPE_NORMAL: 0,
+    DISPLAY_VAL_TYPE_GROUP: 1,
+
+    TYPE_FOLLOW_MODE: 1,
+
     PAGE_SELF_DEFINE: "自定义",
     PAGE_SPECIAL_MERGE_POS: "page_merge_pos",