Przeglądaj źródła

code sync - 多流水表

TonyKang 7 lat temu
rodzic
commit
250cbaffb3

+ 11 - 0
modules/reports/controllers/rpt_controller.js

@@ -80,6 +80,17 @@ function getAllPagesCommon(req, res, rpt_id, pageSize, cb) {
                 if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS] && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS].leng > 0) {
                     tplData[JV.DATA_DETAIL_DATA] = [];
                 }
+                //2. Ex主数据
+                if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX] && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX].leng > 0) {
+                    tplData[JV.DATA_MASTER_DATA_EX] = [];
+                }
+                //3. Ex从数据
+                if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX] && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX].leng > 0) {
+                    tplData[JV.DATA_DETAIL_DATA_EX] = [];
+                }
+                //4. 重点: 开始组装$PROJECT对象
+                let $PROJECT = {};
+                //let $PROJECT.COMMON = {};
                 //return demoTemplateData.getPromise(rptTpl.ID_KEY);
                 //return demoTemplateData.findOne({"Data_Key": rptTpl.ID_KEY}).exec();
 

+ 8 - 0
modules/reports/facade/rpt_tpl_data_facade.js

@@ -4,3 +4,11 @@
 
 let mongoose = require("mongoose");
 let rpt_tpl_mdl = mongoose.model("rpt_templates");
+
+module.exports = {
+
+}
+
+async function prepareProjectData(prjId, userId) {
+    //
+}

+ 8 - 1
modules/reports/models/rpt_template.js

@@ -8,9 +8,16 @@ let RptTemplateSchema = new Schema({
     "GROUP_KEY": String,
     "ID_KEY": String,
     "主信息": Schema.Types.Mixed,
-    "指标_数据_映射": Schema.Types.Mixed,
+    "指标_数据_映射": {
+        "离散指标_集合": Array,
+        "主数据指标_集合": Array,
+        "从数据指标_集合": Array,
+        "主数据指标_拓展集合": Array,
+        "从数据指标_拓展集合": Array
+    },
     "布局框_集合": Array,
     "流水式表_信息": Schema.Types.Mixed,
+    "流水式表_拓展信息": Schema.Types.Mixed,
     "账单式表_信息": Schema.Types.Mixed,
     "交叉表_信息": Schema.Types.Mixed,
     "无映射离散指标_集合": Schema.Types.Mixed,

+ 3 - 1
modules/reports/models/rpt_tpl_data_demo.js

@@ -9,7 +9,9 @@ let RptTemplateDataSchema = new Schema({
     "Data_Key": String,
     "discrete_data": Array,
     "master_data": Array,
-    "detail_data": Array
+    "detail_data": Array,
+    "master_data_ex": Array,
+    "detail_data_ex": Array
 });
 
 let TemplateData = mongoose.model("rpt_temp_tpl_data", RptTemplateDataSchema, "rpt_temp_tpl_data");

+ 18 - 4
modules/reports/rpt_component/helper/jpc_helper_band.js

@@ -7,18 +7,32 @@ let JpcBandHelper = {
         if (rst < 0) rst = JV.STATUS_NORMAL;
         return rst;
     },
-    setBandArea: function(bands, rptTpl, pageStatus) {
+    setBandArea: function(bands, rptTpl, pageStatus, isOnlyNormalStatus, isOnlyExStatus) {
         let me = this;
         if (rptTpl[JV.NODE_BAND_COLLECTION]) {
+            isOnlyNormalStatus = isOnlyNormalStatus||false;
+            isOnlyExStatus = isOnlyExStatus||false;
+
             let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
             let orgArea = JpcCommonHelper.getReportArea(rptTpl, unitFactor);
             for (let i = 0; i < rptTpl[JV.NODE_BAND_COLLECTION].length; i++) {
-                me.setBandPos(bands, rptTpl[JV.NODE_BAND_COLLECTION][i], orgArea, unitFactor, pageStatus);
+                me.setBandPos(bands, rptTpl[JV.NODE_BAND_COLLECTION][i], orgArea, unitFactor, pageStatus, isOnlyNormalStatus, isOnlyExStatus);
             }
         }
     },
-    setBandPos: function(bands, bandNode, orgArea, unitFactor, pageStatus) {
+    setBandPos: function(bands, bandNode, orgArea, unitFactor, pageStatus, isOnlyNormalStatus, isOnlyExStatus) {
         let me = this, band = bands[bandNode[JV.BAND_PROP_NAME]];
+        //0. for multi flow purpose
+        if (isOnlyNormalStatus) {
+            if (bandNode.hasOwnProperty(JV.PROP_BAND_EX_ONLY) && JpcCommonHelper.getBoolean(bandNode[JV.PROP_BAND_EX_ONLY])) {
+                return;
+            }
+        }
+        if (isOnlyExStatus) {
+            if (bandNode.hasOwnProperty(JV.PROP_BAND_NORMAL_ONLY) && !(JpcCommonHelper.getBoolean(bandNode[JV.PROP_BAND_NORMAL_ONLY]))) {
+                return;
+            }
+        }
         //1. initialize
         band[JV.PROP_LEFT] = orgArea[JV.IDX_LEFT];
         band[JV.PROP_TOP] = orgArea[JV.IDX_TOP];
@@ -64,7 +78,7 @@ let JpcBandHelper = {
             if (bandNode[JV.BAND_PROP_SUB_BANDS]) {
                 let bandArea = [band.Left, band.Top, band.Right, band.Bottom];
                 for (let i = 0; i < bandNode[JV.BAND_PROP_SUB_BANDS].length; i++) {
-                    me.setBandPos(bands, bandNode[JV.BAND_PROP_SUB_BANDS][i], bandArea, unitFactor, pageStatus);
+                    me.setBandPos(bands, bandNode[JV.BAND_PROP_SUB_BANDS][i], bandArea, unitFactor, pageStatus, isOnlyNormalStatus, isOnlyExStatus);
                 }
             }
         }

+ 15 - 0
modules/reports/rpt_component/helper/jpc_helper_common.js

@@ -51,6 +51,21 @@ let JpcCommonHelper = {
         if (rst < 0) rst = JV.CAL_TYPE_ABSTRACT;
         return rst;
     },
+    getBoolean: function(bStr) {
+        let rst = false;
+        if (bStr !== null && bStr !== undefined) {
+            let valType = typeof(bStr);
+            if (valType === "boolean") {
+                rst = bStr;
+            } else if (valType === "string") {
+                let tS = bStr.toUpperCase();
+                rst = (tS === "T" || tS === "TRUE" || tS === "YES" || tS === "Y");
+            } else if (valType === "number") {
+                rst = (bStr === 1);
+            }
+        }
+        return rst;
+    },
     getScreenDPI: function() {
         let me = this, arrDPI = [];
         if (!me.commonConstant.resolution) {

+ 3 - 2
modules/reports/rpt_component/helper/jpc_helper_field.js

@@ -19,9 +19,10 @@ let JpcFieldHelper = {
             }
         }
     },
-    findAndPutDataFieldIdx: function (rptTpl, tab_fields, rstFields, rstFieldsIdx) {
+    findAndPutDataFieldIdx: function (rptTpl, tab_fields, rstFields, rstFieldsIdx, isEx) {
         if (tab_fields) {
-            let detail_fields = rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS];
+            let DTL_STR = isEx?JV.NODE_DETAIL_FIELDS_EX:JV.NODE_DETAIL_FIELDS;
+            let detail_fields = rptTpl[JV.NODE_FIELD_MAP][DTL_STR];
             for (let i = 0; i < tab_fields.length; i++) {
                 let isFounded = false;
                 for (let j = 0; j < detail_fields.length; j++) {

+ 6 - 0
modules/reports/rpt_component/jpc_band.js

@@ -32,6 +32,12 @@ let JpcBand = {
             item[JV.BAND_PROP_DISPLAY_TYPE] = JpcBandHelper.getBandTypeValByString(bandNode[JV.BAND_PROP_DISPLAY_TYPE]);
             item[JV.BAND_PROP_ALIGNMENT] = JpcCommonHelper.getLayoutAlignment(bandNode[JV.BAND_PROP_ALIGNMENT]);
             item[JV.PROP_CALCULATION] = JpcCommonHelper.getPosCalculationType(bandNode[JV.PROP_CALCULATION]);
+            if (bandNode.hasOwnProperty(JV.PROP_BAND_NORMAL_ONLY)) {
+                item[JV.PROP_BAND_NORMAL_ONLY] = JpcCommonHelper.getBoolean(bandNode[JV.PROP_BAND_NORMAL_ONLY]);
+            }
+            if (bandNode.hasOwnProperty(JV.PROP_BAND_EX_ONLY)) {
+                item[JV.PROP_BAND_EX_ONLY] = JpcCommonHelper.getBoolean(bandNode[JV.PROP_BAND_EX_ONLY]);
+            }
 
             if (bandNode[JV.BAND_PROP_MERGE_BORDER]) {
                 item[JV.BAND_PROP_MERGE_BORDER] = bandNode[JV.BAND_PROP_MERGE_BORDER];

+ 93 - 0
modules/reports/rpt_component/jpc_data.js

@@ -3,9 +3,101 @@ let JpcData = {
     createNew: function() {
         let JpcDataRst = {};
         JpcDataRst.dataSeq = [];
+        JpcDataRst.exDataSeq = [];
         JpcDataRst.analyzeData = function(rptTpl, dataObj) {
             let me = this;
+            let private_analyse = function(MASTER_FIELD_STR, DETAIL_FIELD_STR, MASTER_DATA_STR, DETAIL_DATA_STR, dataSeqArr) {
+                //1. get ID fields
+                let masterIDs = [];
+                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR].length; i++) {
+                    let mstFieldObj = rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR][i];
+                    if ((mstFieldObj[JV.PROP_IS_ID]) && (mstFieldObj[JV.PROP_IS_ID] === 'T')) {
+                        masterIDs.push({"idx": i, "seq": mstFieldObj[JV.PROP_ID_SEQ]});
+                    }
+                }
+                let detailIDs = [];
+                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR].length; i++) {
+                    let dtlFieldObj = rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR][i];
+                    if ((dtlFieldObj[JV.PROP_IS_ID]) && (dtlFieldObj[JV.PROP_IS_ID] === 'T')) {
+                        detailIDs.push({"idx": i, "seq": dtlFieldObj[JV.PROP_ID_SEQ]});
+                    }
+                }
+                //2. sort the ID fields
+                if (masterIDs.length > 1) {
+                    masterIDs.sort(function(a, b) {
+                        return 1*a["seq"] - 1*b["seq"];
+                    })
+                }
+                if (detailIDs.length > 1) {
+                    detailIDs.sort(function(a, b) {
+                        return 1*a["seq"] - 1*b["seq"];
+                    })
+                }
+                //3. prepare data sequence
+                if (masterIDs.length > 0) {
+                    let mst_dt_len = 0, dtl_dt_len = 0, mst_fields = [];
+                    for (let i = 0; i < masterIDs.length; i++) {
+                        mst_fields.push(dataObj[MASTER_DATA_STR][masterIDs[i]["idx"]]);
+                        mst_dt_len = dataObj[MASTER_DATA_STR][masterIDs[i]["idx"]].length;
+                    }
+                    let dtl_fields = [];
+                    for (let i = 0; i < detailIDs.length; i++) {
+                        dtl_fields.push(dataObj[DETAIL_DATA_STR][detailIDs[i]["idx"]]);
+                        dtl_dt_len = dataObj[DETAIL_DATA_STR][detailIDs[i]["idx"]].length;
+                    }
+                    let sIdx = 0;
+                    let isEqual = true;
+                    for (let i = 0; i < mst_dt_len; i++) {
+                        dataSeqArr.push([]);
+                        //then compare the master/detail ID-field value
+                        for (let j = sIdx; j < dtl_dt_len; j++) {
+                            isEqual = true;
+                            for (let k = 0; k < mst_fields.length; k++) {
+                                if (!(mst_fields[k][i] === dtl_fields[k][j])) {
+                                    isEqual = false;
+                                    break;
+                                }
+                            }
+                            if (isEqual) {
+                                dataSeqArr[i].push(j);
+                            } else {
+                                sIdx = j;
+                                //below logic is for the data robustness purpose, to avoid those strange record(detail level) which could not match even one of the master record!
+                                if (i < mst_dt_len - 1 && j < dtl_dt_len - 1) {
+                                    for (let j1 = j; j1 < dtl_dt_len; j1++) {
+                                        isEqual = true;
+                                        for (let k = 0; k < mst_fields.length; k++) {
+                                            if (!(mst_fields[k][i + 1] === dtl_fields[k][j1])) {
+                                                isEqual = false;
+                                                break;
+                                            }
+                                        }
+                                        if (isEqual) {
+                                            sIdx = j1;
+                                            break;
+                                        }
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                } else { //if no master data
+                    let field = dataObj[DETAIL_DATA_STR][0];
+                    //dataSeqArr = [[]];
+                    dataSeqArr.push([]);
+                    for (let i = 0; i < field.length; i++) {
+                        dataSeqArr[0].push(i);
+                    }
+                }
+            };
             if ((rptTpl) && (dataObj)) {
+                //*
+                private_analyse(JV.NODE_MASTER_FIELDS, JV.NODE_DETAIL_FIELDS, JV.DATA_MASTER_DATA, JV.DATA_DETAIL_DATA, me.dataSeq);
+                if (rptTpl[JV.NODE_FLOW_INFO_EX]) {
+                    private_analyse(JV.NODE_MASTER_FIELDS_EX, JV.NODE_DETAIL_FIELDS_EX, JV.DATA_MASTER_DATA_EX, JV.DATA_DETAIL_DATA_EX, me.exDataSeq);
+                }
+                /*/
                 //1. get ID fields
                 let masterIDs = [];
                 for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS].length; i++) {
@@ -88,6 +180,7 @@ let JpcData = {
                         me.dataSeq[0].push(i);
                     }
                 }
+                //*/
             }
             //alert(3);
         };

+ 20 - 2
modules/reports/rpt_component/jpc_ex.js

@@ -86,7 +86,11 @@ JpcExSrv.prototype.createNew = function(){
         let me = this;
         if (rptTpl[JV.NODE_FLOW_INFO]) {
             me.flowTab = JpcFlowTab.createNew();
-            me.flowTab.initialize();
+            me.flowTab.initialize(false);
+        }
+        if (rptTpl[JV.NODE_FLOW_INFO_EX]) {
+            me.flowTabEx = JpcFlowTab.createNew();
+            me.flowTabEx.initialize(true);
         }
         if (rptTpl[JV.NODE_BILL_INFO]) {
             me.billTab = JpcBillTab.createNew();
@@ -98,6 +102,7 @@ JpcExSrv.prototype.createNew = function(){
             me.crossTab.initialize();
         }
         me.totalPages = 0;
+        me.exTotalPages = 0;
         me.runTimePageData = {};
         me.fields = JpcField.createNew(rptTpl);
         me.params = JpcParam.createNew(rptTpl);
@@ -114,6 +119,9 @@ JpcExSrv.prototype.createNew = function(){
         //let dt1 = new Date();
         if (me.flowTab) {
             me.flowTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
+            if (me.flowTabEx) {
+                me.flowTabEx.sorting(rptTpl, dataObj, dataHelper.exDataSeq.slice(0));
+            }
         }
         if (me.crossTab) {
             me.crossTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
@@ -132,6 +140,11 @@ JpcExSrv.prototype.createNew = function(){
         let me = this;
         if (me.flowTab) {
             me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties);
+            if (me.flowTabEx) {
+                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties);
+                //console.log('ad-hoc flow pages: ' + me.exTotalPages);
+            }
+            me.totalPages += me.exTotalPages;
         } else if (me.crossTab) {
             me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties);
         } else if (me.billTab) {
@@ -187,7 +200,12 @@ JpcExSrv.prototype.createNew = function(){
             rst[JV.PROP_PAGE_SEQ] = page;
             //rst.cells = [];
             if (me.flowTab) {
-                rst.cells = me.flowTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
+                if (me.totalPages - me.exTotalPages >= page) {
+                    rst.cells = me.flowTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
+                } else {
+                    rst.cells = me.flowTabEx.outputAsSimpleJSONPage(rptTpl, dataObj, page - me.exTotalPages, bands, controls, me);
+                }
+                //rst.cells = me.flowTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             } else if (me.crossTab) {
                 rst.cells = me.crossTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             } else if (me.billTab) {

+ 13 - 1
modules/reports/rpt_component/jpc_field.js

@@ -27,7 +27,19 @@ let JpcField = {
                 me.createSingle(rptTpl[JV.NODE_NO_MAPPING_FIELDS][i], JpcFieldResult[JV.NODE_NO_MAPPING_FIELDS], rptTpl, "NA", JV.BLANK_FIELD_INDEX);
             }
         }
-        //
+        JpcFieldResult[JV.NODE_MASTER_FIELDS_EX] = {};
+        if (rptTpl[JV.NODE_FIELD_MAP] && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX]) {
+            for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX].length; i++) {
+                me.createSingle(rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX][i], JpcFieldResult[JV.NODE_MASTER_FIELDS_EX], rptTpl, JV.DATA_MASTER_DATA_EX, i);
+            }
+        }
+        JpcFieldResult[JV.NODE_DETAIL_FIELDS_EX] = {};
+        if (rptTpl[JV.NODE_FIELD_MAP] && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX]) {
+            for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX].length; i++) {
+                me.createSingle(rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX][i], JpcFieldResult[JV.NODE_DETAIL_FIELDS_EX], rptTpl, JV.DATA_DETAIL_DATA_EX, i);
+            }
+        }
+        //NODE_MASTER_FIELDS_EX
         return JpcFieldResult;
     },
     createSingle: function(fieldNode, parentObj, rptTpl, dataNodeName, sequence) {

+ 27 - 15
modules/reports/rpt_component/jpc_flow_tab.js

@@ -25,8 +25,9 @@ JpcFlowTabSrv.prototype.createNew = function(){
         ValuedIdxLst.push(vIdx);
     }
     let JpcFlowTabResult = {};
-    JpcFlowTabResult.initialize = function() {
+    JpcFlowTabResult.initialize = function(isEx) {
         let me = this;
+        me.isEx = isEx;
         me.segments = [];
         me.dispValueIdxLst = [];
         me.page_seg_map = [];
@@ -39,17 +40,19 @@ JpcFlowTabSrv.prototype.createNew = function(){
         me.groupSumValLst = [];
         me.segSumValLst = [];
         me.multiCols = 1;
+        me.pagesAmt = 0;
     };
     JpcFlowTabResult.sorting = function(rptTpl, dataObj, dataSeq) {
         let me = this;
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_SEG_SUM][JV.PROP_SUM_FIELDS], me.seg_sum_tab_fields, me.seg_sum_fields_idx);
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_PAGE_SUM][JV.PROP_SUM_FIELDS], null, me.page_sum_fields_idx);
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], null, me.group_fields_idx);
+        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);
         for (let si = 0; si < dataSeq.length; si++) {
             me.segments.push(dataSeq[si].slice(0));
         }
         //pre-sum the data(for seg sum display)
-        let data_details = dataObj[JV.DATA_DETAIL_DATA],
+        let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA],
             data_fields = [];
         for (let i = 0; i < me.seg_sum_fields_idx.length; i++) {
             let data_field = data_details[me.seg_sum_fields_idx[i]];
@@ -72,14 +75,18 @@ JpcFlowTabSrv.prototype.createNew = function(){
     };
     JpcFlowTabResult.preSetupPages = function (rptTpl, dataOjb, defProperties) {
         let rst = 0, me = this, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx);
+        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);
         let bands = JpcBand.createNew(rptTpl, defProperties);
         let pageStatus = [true, true, false, false, false, false, false, false];
-        if (rptTpl[JV.NODE_FLOW_INFO][JV.PROP_MULTI_COLUMN]) {
-            me.multiCols = 1 * rptTpl[JV.NODE_FLOW_INFO][JV.PROP_MULTI_COLUMN];
+        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];
         }
         function private_resetBandArea() {
-            JpcBandHelper.setBandArea(bands, rptTpl, pageStatus);
+            JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
             maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl);
         }
         for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
@@ -106,13 +113,15 @@ JpcFlowTabSrv.prototype.createNew = function(){
             pageStatus[JV.STATUS_REPORT_START] = false;
         }
         rst = Math.ceil(1.0 * pageIdx / me.multiCols);
+        me.pagesAmt = rst;
         return rst;
     };
     JpcFlowTabResult.outputAsSimpleJSONPage = function (rptTpl, dataObj, page, bands, controls, $CURRENT_RPT) {
         let me = this, rst = [], tabRstLst = [];
+        let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
         //1 calculate the band position
-        JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1]);
+        JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1], !me.isEx, me.isEx);
         //2. start to output detail-part
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
         for (let pi = 0; pi < me.multiCols; pi++) {
@@ -126,7 +135,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             //2.4 Sum Page
             //2.5 Discrete
             if (pi == 0) {
-                tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[JV.NODE_FLOW_INFO][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT));
+                tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT));
             }
         }
         for (let i = 0; i < tabRstLst.length; i++) {
@@ -137,13 +146,14 @@ JpcFlowTabSrv.prototype.createNew = function(){
     };
     JpcFlowTabResult.outputContent = function(rptTpl, dataObj, page, bands, unitFactor, controls, multiColIdx, $CURRENT_RPT) {
         let me = this, rst = [];
-        let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
+        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 band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
             if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
                 let tab_fields = tab[JV.PROP_FLOW_FIELDS];
-                let data_details = dataObj[JV.DATA_DETAIL_DATA];
+                let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
                 let contentValuesIdx = me.dispValueIdxLst[page - 1];
                 for (let i = 0; i < tab_fields.length; i++) {
                     let tab_field = tab_fields[i];
@@ -168,7 +178,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
     };
     JpcFlowTabResult.outputColumn = function (rptTpl, dataObj, page, segIdx, bands, unitFactor, controls, multiColIdx) {
         let me = this, rst = [];
-        let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_COLUMN];
+        let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+        let tab = rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_COLUMN];
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
@@ -190,7 +201,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
     };
     JpcFlowTabResult.outputSegSum = function (rptTpl, dataObj, page, segIdx, bands, unitFactor, controls) {
         let me = this, rst = [];
-        let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_SEG_SUM];
+        let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+        let tab = rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_SEG_SUM];
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];

+ 4 - 0
modules/reports/rpt_component/jpc_rte.js

@@ -10,6 +10,10 @@ let JE = {
             rst = $CURRENT_RPT.fields[JV.NODE_DETAIL_FIELDS][JV.PROP_ID + "_" + fID];
         } else if ($CURRENT_RPT && ($CURRENT_RPT.fields[JV.NODE_MASTER_FIELDS][JV.PROP_ID + "_" + fID])) {
             rst = $CURRENT_RPT.fields[JV.NODE_MASTER_FIELDS][JV.PROP_ID + "_" + fID];
+        } else if ($CURRENT_RPT && ($CURRENT_RPT.fields[JV.NODE_MASTER_FIELDS_EX][JV.PROP_ID + "_" + fID])) {
+            rst = $CURRENT_RPT.fields[JV.NODE_MASTER_FIELDS_EX][JV.PROP_ID + "_" + fID];
+        } else if ($CURRENT_RPT && ($CURRENT_RPT.fields[JV.NODE_DETAIL_FIELDS_EX][JV.PROP_ID + "_" + fID])) {
+            rst = $CURRENT_RPT.fields[JV.NODE_DETAIL_FIELDS_EX][JV.PROP_ID + "_" + fID];
         } else if ($CURRENT_RPT && ($CURRENT_RPT.fields[JV.NODE_DISCRETE_FIELDS][JV.PROP_ID + "_" + fID])) {
             rst = $CURRENT_RPT.fields[JV.NODE_DISCRETE_FIELDS][JV.PROP_ID + "_" + fID];
         } else if ($CURRENT_RPT && ($CURRENT_RPT.fields[JV.NODE_NO_MAPPING_FIELDS][JV.PROP_ID + "_" + fID])) {

+ 18 - 0
modules/reports/util/rpt_data_util.js

@@ -2,13 +2,31 @@
  * Created by Tony on 2017/7/14.
  * 报表数据提取class,是协助报表模板里指标字段自主提取数据的工具类
  */
+let JV = require('../rpt_component/jpc_value_define');
+let $JE = require('../rpt_component/jpc_rte');
+
 class Rpt_Common{
     initialize(Projects) {
         this.Projects = Projects;
     };
+
+    getSerialNo(fieldId, $CURRENT_RPT, $CURRENT_DATA){
+        let itemSerialNoRec = $JE.F(fieldId, $CURRENT_RPT);
+        if (itemSerialNoRec) {
+            itemSerialNoRec[JV.PROP_AD_HOC_DATA] = [];
+            for (var innerFmlIdx = 0; innerFmlIdx < $CURRENT_DATA[JV.DATA_DETAIL_DATA][0].length; innerFmlIdx++) {
+                itemSerialNoRec[JV.PROP_AD_HOC_DATA][innerFmlIdx] = (innerFmlIdx + 1);
+            }
+            itemSerialNoRec = null;
+        }
+    };
 };
 
 class Rpt_Data_Extractor {
+    constructor () {
+        this.COMMON = new Rpt_Common();
+    };
+
     initialize(Projects) {
         this.Projects = Projects;
         //Projects对象应该从前端传送过来,无需在后端重复查询及构建

+ 8 - 0
public/web/rpt_value_define.js

@@ -15,13 +15,16 @@ let JV = {
     NODE_NO_MAPPING_FIELDS: "无映射离散指标_集合",
     NODE_DISCRETE_PARAMS: "离散参数_集合",
     NODE_MASTER_FIELDS: "主数据指标_集合",
+    NODE_MASTER_FIELDS_EX: "主数据指标_拓展集合",
     NODE_DETAIL_FIELDS: "从数据指标_集合",
+    NODE_DETAIL_FIELDS_EX: "从数据指标_拓展集合",
     NODE_BAND_COLLECTION: "布局框_集合",
     NODE_FORMULAS: "计算式_集合",
     NODE_DISCRETE_INFO: "离散信息",
     NODE_BILL_INFO: "账单式表_信息",
     NODE_BILL_CONTENT : "账单式表_数据",
     NODE_FLOW_INFO: "流水式表_信息",
+    NODE_FLOW_INFO_EX: "流水式表_拓展信息",
     NODE_FLOW_GROUP: "流水式表_分组信息",
     NODE_FLOW_SEG_SUM: "流水式表_段统计信息",
     NODE_FLOW_PAGE_SUM: "流水式表_页统计信息",
@@ -43,6 +46,9 @@ let JV = {
     PROP_CMN_HEIGHT: "CommonHeight",
     PROP_CMN_WIDTH: "CommonWidth",
     PROP_BAND_NAME: "BandName",
+    PROP_BAND_NORMAL_ONLY: "normalOnly",
+    PROP_BAND_EX_ONLY: "exOnly",
+
     PROP_UNITS: "单位",
     PROP_PAGE_SIZE: "页规格",
     PROP_ORIENTATION: "方向",
@@ -119,6 +125,8 @@ let JV = {
     DATA_DISCRETE_DATA: "discrete_data",
     DATA_MASTER_DATA: "master_data",
     DATA_DETAIL_DATA: "detail_data",
+    DATA_MASTER_DATA_EX: "master_data_ex",
+    DATA_DETAIL_DATA_EX: "detail_data_ex",
 
     BLANK_FIELD_INDEX: -10,
     BLANK_VALUE_INDEX: -100,

+ 10 - 3
test/demo/stringTest.js

@@ -49,8 +49,15 @@ var strUtil = require('../../public/stringUtil');
 //     t.end();
 // });
 
-test('test 拼音', function(t){
-    t.equal(strUtil.getPinYinCamelChars("招标清单"), "ZBQD");
-    t.equal(strUtil.getPinYinCamelChars("1. 招标清单"), "1. ZBQD");
+// test('test 拼音', function(t){
+//     t.equal(strUtil.getPinYinCamelChars("招标清单"), "ZBQD");
+//     t.equal(strUtil.getPinYinCamelChars("1. 招标清单"), "1. ZBQD");
+//     t.end();
+// })
+
+test('test typeof', function(t){
+    t.equal(typeof(true), "boolean");
+    t.equal((typeof("abc")).toUpperCase(), "STRING");
+    t.equal(typeof(1), "number");
     t.end();
 })