Просмотр исходного кода

Merge branch '1.0.0_online' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost into 1.0.0_online

zhongzewei 6 лет назад
Родитель
Сommit
50ebf0debf

+ 41 - 23
modules/reports/controllers/rpt_controller.js

@@ -22,7 +22,7 @@ import rpt_pdf_util from "../util/rpt_pdf_util";
 import rpt_svg_util from "../util/rpt_svg_util";
 import fs from "fs";
 import strUtil from "../../../public/stringUtil";
-import rptDataExtractor from "../util/rpt_construct_data_util";
+import rptDataExtractor from "../util/rpt_yanghu_data_util";
 
 //统一回调函数
 let callback = function(req, res, err, data){
@@ -244,28 +244,34 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, orientation, custo
             rptTplDataFacade.prepareProjectData(user_id, prj_id, filter, function (err, msg, rawDataObj) {
                 if (!err) {
                     let buildPageData = function() {
-                        let tplData = rptDataUtil.assembleData(rawDataObj);
-                        let printCom = JpcEx.createNew();
-                        if (pageSize) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
-                        //console.log("orientation: " + (orientation === 'null'));
-                        if (orientation && (orientation !== 'null')) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] = orientation;
-                        let defProperties = rptUtil.getReportDefaultCache();
-                        if (customizeCfg) setupCustomizeCfg(customizeCfg, rptTpl, defProperties);
-                        let dftOption = option||JV.PAGING_OPTION_NORMAL;
-                        printCom.initialize(rptTpl);
-                        printCom.analyzeData(rptTpl, tplData, defProperties, dftOption, outputType);
-                        let maxPages = printCom.totalPages;
-                        let pageRst = null;
-                        if (maxPages > 0) {
-                            pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
-                        } else {
-                            pageRst = printCom.outputAsPreviewPage(rptTpl, defProperties);
-                        }
-                        if (pageRst) {
-                            // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.jsp");
-                            cb(null, pageRst);
-                        } else {
-                            cb('Have errors while on going...', null);
+                        try {
+                            let tplData = rptDataUtil.assembleData(rawDataObj);
+                            let printCom = JpcEx.createNew();
+                            if (pageSize) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pageSize;
+                            //console.log("orientation: " + (orientation === 'null'));
+                            if (orientation && (orientation !== 'null')) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] = orientation;
+                            let defProperties = rptUtil.getReportDefaultCache();
+                            if (customizeCfg) setupCustomizeCfg(customizeCfg, rptTpl, defProperties);
+                            let dftOption = option||JV.PAGING_OPTION_NORMAL;
+                            printCom.initialize(rptTpl);
+                            printCom.analyzeData(rptTpl, tplData, defProperties, dftOption, outputType);
+                            let maxPages = printCom.totalPages;
+                            let pageRst = null;
+                            if (maxPages > 0) {
+                                pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
+                            } else {
+                                pageRst = printCom.outputAsPreviewPage(rptTpl, defProperties);
+                            }
+                            if (pageRst) {
+                                // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.jsp");
+                                cb(null, pageRst);
+                            } else {
+                                cb('Have errors while on going...', null);
+                            }
+                        } catch (ex) {
+                            console.log("报表数据异常: userId " + user_id + ", project id: " + prj_id);
+                            console.log(ex);
+                            cb('Exception occurs while on going...', null);
                         }
                     };
                     //*/
@@ -372,6 +378,18 @@ module.exports = {
             }
         })
     },
+    getMultiReportsEx: function (req, res) {
+        //原则说明:把所有报表模板集中获取,统一filter,只读一次数据!(有空再整)
+        let params = JSON.parse(req.body.params),
+            prj_id = params.prj_id,
+            rpt_ids = params.rpt_ids.split(','),
+            pageSize = params.pageSize,
+            orientation = params.orientation,
+            customizeCfg = params.custCfg,
+            option = params.option;
+        let user_id = req.session.sessionUser.id;
+        let dftOption = option||JV.PAGING_OPTION_NORMAL;
+    },
 
     getReportAllPagesSvg: function (req, res) {
         let params = JSON.parse(req.body.params),

+ 39 - 7
modules/reports/rpt_component/helper/jpc_helper_cross_tab.js

@@ -1,4 +1,5 @@
 let JV = require('../jpc_value_define');
+let JE = require('../jpc_rte');
 let JpcCommonHelper = require('./jpc_helper_common');
 
 let JpcCrossTabHelper = {
@@ -27,7 +28,7 @@ let JpcCrossTabHelper = {
     },
     sortFieldValue: function(sIDX, eIDX, sortOrder, dataField, dataValSeq) {
         let tmpSeq = [];
-        if ((sortOrder) && (sortOrder != JV.TAB_FIELD_PROP_SORT_VAL_NOSORT)) {
+        if ((sortOrder) && (sortOrder !== JV.TAB_FIELD_PROP_SORT_VAL_NOSORT)) {
             if (sIDX >= 0 && eIDX >= sIDX && dataValSeq.length > eIDX) {
                 let reversed = 1;
                 if (sortOrder === JV.TAB_FIELD_PROP_SORT_VAL_DESC) {
@@ -38,7 +39,8 @@ let JpcCrossTabHelper = {
                 }
                 tmpSeq.sort(function(idx1, idx2) {
                     let rst = 0;
-                    if (isNaN(parseFloat(dataField[idx1])) || isNaN(parseFloat(dataField[idx1]))) {
+                    // if (isNaN(parseFloat(dataField[idx1])) || isNaN(parseFloat(dataField[idx1]))) {
+                    if (typeof (dataField[idx1]) === 'string' || typeof (dataField[idx1]) === 'string' ) {
                         if (dataField[idx1] > dataField[idx2]) {
                             rst = reversed;
                         } else if (dataField[idx1] < dataField[idx2]) {
@@ -72,12 +74,12 @@ let JpcCrossTabHelper = {
         }
         return rst;
     },
-    sortTabFields: function(tabFields, fieldSeqs, data_details, dataSeq) {
+    sortTabFields: function(tabFields, fieldSeqs, data_details, dataSeq, $CURRENT_RPT) {
         let me = this;
         let sIDX = 0, eIDX = -1, isFirstSort = true;
         for (let i = 0; i < tabFields.length; i++) {
             let tabField = tabFields[i];
-            if (tabField[JV.TAB_FIELD_PROP_SORT] != JV.TAB_FIELD_PROP_SORT_VAL_NOSORT) {
+            if (tabField[JV.TAB_FIELD_PROP_SORT] !== JV.TAB_FIELD_PROP_SORT_VAL_NOSORT) {
                 if (isFirstSort) {
                     isFirstSort = false;
                     //first field, should sort all data items
@@ -85,14 +87,34 @@ let JpcCrossTabHelper = {
                         sIDX = 0;
                         eIDX = dataSeq[j].length - 1;
                         //sort the field value here
-                        me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
+                        if (typeof(fieldSeqs[i]) === "object") {
+                            let exFirstField = JE.F(fieldSeqs[i][JV.PROP_ID], $CURRENT_RPT);
+                            if (exFirstField) {
+                                me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT], exFirstField[JV.PROP_AD_HOC_DATA], dataSeq[j]);
+                            } else {
+                                //不排序(健壮性)
+                            }
+                        } else {
+                            me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
+                        }
+                        // me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
                     }
                 } else {
                     //then sort the rest fields one by one
                     for (let j = 0; j < dataSeq.length; j++) {
                         let chkFields = [];
                         for (let k = 0; k < i; k++) {
-                            chkFields.push(data_details[fieldSeqs[k]]);
+                            if (typeof(fieldSeqs[k]) === "object") {
+                                let exField = JE.F(fieldSeqs[k][JV.PROP_ID], $CURRENT_RPT);
+                                if (exField) {
+                                    chkFields.push(exField[JV.PROP_AD_HOC_DATA]);
+                                } else {
+                                    chkFields.push(null);
+                                }
+                            } else {
+                                chkFields.push(data_details[fieldSeqs[k]]);
+                            }
+                            // chkFields.push(data_details[fieldSeqs[k]]);
                         }
                         sIDX = 0, eIDX = -1;
                         for (let m = 1; m < dataSeq[j].length; m++) {
@@ -103,7 +125,17 @@ let JpcCrossTabHelper = {
                             };
                             if (eIDX >= sIDX) {
                                 if (eIDX != sIDX) {
-                                    me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
+                                    if (typeof(fieldSeqs[i]) === "object") {
+                                        let exOtherField = JE.F(fieldSeqs[i][JV.PROP_ID], $CURRENT_RPT);
+                                        if (exOtherField) {
+                                            me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT], exOtherField[JV.PROP_AD_HOC_DATA], dataSeq[j]);
+                                        } else {
+                                            //不排序(健壮性)
+                                        }
+                                    } else {
+                                        me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
+                                    }
+                                    // me.sortFieldValue(sIDX, eIDX, tabField[JV.TAB_FIELD_PROP_SORT],data_details[fieldSeqs[i]], dataSeq[j]);
                                 }
                                 sIDX = m;
                                 eIDX = m - 1; //for protection purpose

+ 155 - 65
modules/reports/rpt_component/jpc_cross_tab.js

@@ -102,7 +102,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
             }
         }
     }
-    function private_SortAndOptimize(rptTpl, dataObj, dataSeq, sortTab, rstFieldsIdx) {
+    function private_SortAndOptimize(rptTpl, dataObj, dataSeq, sortTab, rstFieldsIdx, $CURRENT_RPT) {
         let result = [];
         let tab = rptTpl[JV.NODE_CROSS_INFO][sortTab];
         if (tab) {
@@ -111,7 +111,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
             let fields = [];
             JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, tab[JV.PROP_CROSS_FIELDS], fields, rstFieldsIdx);
             let data_details = dataObj[JV.DATA_DETAIL_DATA];
-            JpcCrossTabHelper.sortTabFields(fields, rstFieldsIdx, data_details, dataSeq);
+            JpcCrossTabHelper.sortTabFields(fields, rstFieldsIdx, data_details, dataSeq, $CURRENT_RPT);
             //2. distinguish sort tab fields value
             let b1 = false;
             for (let i = 0; i < dataSeq.length; i++) {
@@ -123,9 +123,17 @@ JpcCrossTabSrv.prototype.createNew = function(){
                     for (let j = 1; j < dataSeq[i].length; j++) {
                         b1 = false;
                         for (let k = 0; k < rstFieldsIdx.length; k++) {
-                            if (data_details[rstFieldsIdx[k]][dataSeq[i][j - 1]] !== data_details[rstFieldsIdx[k]][dataSeq[i][j]]) {
-                                b1 = true;
-                                break;
+                            if (typeof(rstFieldsIdx[k]) === 'object') {
+                                let map_data_field = JE.F(rstFieldsIdx[k][JV.PROP_ID], $CURRENT_RPT);
+                                if (map_data_field[JV.PROP_AD_HOC_DATA][dataSeq[i][j - 1]] !== map_data_field[JV.PROP_AD_HOC_DATA][dataSeq[i][j]]) {
+                                    b1 = true;
+                                    break;
+                                }
+                            } else {
+                                if (data_details[rstFieldsIdx[k]][dataSeq[i][j - 1]] !== data_details[rstFieldsIdx[k]][dataSeq[i][j]]) {
+                                    b1 = true;
+                                    break;
+                                }
                             }
                         }
                         if (b1) {
@@ -195,18 +203,26 @@ JpcCrossTabSrv.prototype.createNew = function(){
         me.pageStatusLst = [];
         me.paging_option = JV.PAGING_OPTION_NORMAL;
     };
-    JpcCrossTabResult.sorting = function(rptTpl, dataObj, dataSeq) {
+    JpcCrossTabResult.sorting = function(rptTpl, dataObj, dataSeq, $CURRENT_RPT) {
         let me = this;
         //IMPORTANT: the data should be sorted in SQL/NoSQL level!
-        me.sortedRowSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_ROW, me.row_fields_idx);
-        me.sortedColSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_COL, me.col_fields_idx);
+        me.sortedRowSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_ROW, me.row_fields_idx, $CURRENT_RPT);
+        me.sortedColSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_COL, me.col_fields_idx, $CURRENT_RPT);
         me.sortedContentSequence = private_SortForDisplayContent(rptTpl, me.sortedRowSequence, me.sortedColSequence, me.content_fields_idx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_COL_SUM][JV.PROP_CROSS_FIELDS], null, me.col_sum_fields_idx);
         //pre-sum the data(for col sum display)
         let data_details = dataObj[JV.DATA_DETAIL_DATA],
             data_fields = [];
         for (let i = 0; i < me.col_sum_fields_idx.length; i++) {
-            let data_field = data_details[me.col_sum_fields_idx[i]];
+            let data_field = null;
+            if (typeof me.col_sum_fields_idx[i] === 'object') {
+                let exField = JE.F(me.col_sum_fields_idx[i][JV.PROP_ID], $CURRENT_RPT);
+                if (exField) {
+                    data_field = exField[JV.PROP_AD_HOC_DATA];
+                }
+            } else {
+                data_field = data_details[me.col_sum_fields_idx[i]];
+            }
             data_fields.push(data_field);
         }
         for (let i = 0; i < me.sortedRowSequence.length; i++) { //seg level
@@ -244,25 +260,25 @@ JpcCrossTabSrv.prototype.createNew = function(){
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW_SUM_EXT][JV.PROP_CROSS_FIELDS], null, me.row_sum_extension_fields_idx);
         if (me.paging_option === JV.PAGING_OPTION_INFINITY) {
             /*
-            rst = segCnt;
-            pageStatus[JV.STATUS_SEGMENT_START] = true;
-            pageStatus[JV.STATUS_SEGMENT_END] = true;
-            pageStatus[JV.STATUS_CROSS_ROW_END] = true;
-            pageStatus[JV.STATUS_CROSS_COL_END] = true;
-            for (let segIdx = 0; segIdx < segCnt; segIdx++) {
-                if (segIdx === segCnt - 1) {
-                    pageStatus[JV.STATUS_REPORT_END] = true;
-                }
-                if (segIdx > 0) {
-                    pageStatus[JV.STATUS_REPORT_START] = false;
-                }
-                me.pageStatusLst.push(pageStatus.slice(0));
-                pageIdx++;
-                private_addTabValue(me.dispValueIdxLst_Row, me.sortedRowSequence, segIdx, 0, me.sortedRowSequence[segIdx].length, me.dispSerialIdxLst_Row, me.col_sum_fields_value_total, me.dispSumValueLst_Col);
-                private_addTabValue(me.dispValueIdxLst_Col, me.sortedColSequence, segIdx, 0, me.sortedColSequence[segIdx].length, null, null, null);
-                private_addContentValue(me.dispValueIdxLst_Content, me.sortedContentSequence, segIdx, 0, me.sortedRowSequence[segIdx].length, 0, me.sortedColSequence[segIdx].length, me.page_seg_map, pageIdx);
-            }
-            //*/
+             rst = segCnt;
+             pageStatus[JV.STATUS_SEGMENT_START] = true;
+             pageStatus[JV.STATUS_SEGMENT_END] = true;
+             pageStatus[JV.STATUS_CROSS_ROW_END] = true;
+             pageStatus[JV.STATUS_CROSS_COL_END] = true;
+             for (let segIdx = 0; segIdx < segCnt; segIdx++) {
+             if (segIdx === segCnt - 1) {
+             pageStatus[JV.STATUS_REPORT_END] = true;
+             }
+             if (segIdx > 0) {
+             pageStatus[JV.STATUS_REPORT_START] = false;
+             }
+             me.pageStatusLst.push(pageStatus.slice(0));
+             pageIdx++;
+             private_addTabValue(me.dispValueIdxLst_Row, me.sortedRowSequence, segIdx, 0, me.sortedRowSequence[segIdx].length, me.dispSerialIdxLst_Row, me.col_sum_fields_value_total, me.dispSumValueLst_Col);
+             private_addTabValue(me.dispValueIdxLst_Col, me.sortedColSequence, segIdx, 0, me.sortedColSequence[segIdx].length, null, null, null);
+             private_addContentValue(me.dispValueIdxLst_Content, me.sortedContentSequence, segIdx, 0, me.sortedRowSequence[segIdx].length, 0, me.sortedColSequence[segIdx].length, me.page_seg_map, pageIdx);
+             }
+             //*/
         } else {
             for (let segIdx = 0; segIdx < segCnt; segIdx++) {
                 //2.1. seg level initialize
@@ -321,12 +337,78 @@ JpcCrossTabSrv.prototype.createNew = function(){
         bands = null;
         return rst;
     };
-    JpcCrossTabResult.outputAsPreviewPage = function (rptTpl, bands, controls, $CURRENT_RPT) {
+    JpcCrossTabResult.outputAsPreviewPage = function (rptTpl, bands, controls, $CURRENT_RPT, customizeCfg) {
         let me = this, rst = [];
         let pageStatus = [true, true, true, true, true, true, true, true];
         me.pageStatusLst.push(pageStatus);
         // JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, false);
         JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, true, false);
+        let maxRowRec = JpcCrossTabHelper.getMaxRowsPerPage(bands, rptTpl);
+        let maxColRec = JpcCrossTabHelper.getMaxColsPerPage(bands, rptTpl);
+        let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
+        //1. 交叉行
+        rst = rst.concat(me.outputPreviewRowTab(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor));
+        //2. 交叉列
+        rst = rst.concat(me.outputPreviewColTab(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxColRec, unitFactor));
+        //3. 交叉数据
+        rst = rst.concat(me.outputPreviewContent(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, maxColRec, unitFactor));
+        //4. 交叉行拓展
+        rst = rst.concat(me.outputPreviewTabExt(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor));
+        //5. 交叉行拓展合计
+        rst = rst.concat(me.outputPreviewSumTabExt(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor));
+        //6. 交叉列合计
+        rst = rst.concat(me.outputPreviewTabSum(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, JV.NODE_CROSS_COL_SUM, unitFactor));
+        //7. 离散
+        rst = rst.concat(JpcDiscreteHelper.outputPreviewDiscreteInfo(rptTpl[JV.NODE_CROSS_INFO][JV.NODE_DISCRETE_INFO], bands, unitFactor, pageStatus));
+        return rst;
+    };
+    JpcCrossTabResult.outputPreviewRowTab = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor) {
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, 1, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW], unitFactor);
+    };
+    JpcCrossTabResult.outputPreviewColTab = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxColRec, unitFactor) {
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, 1, maxColRec, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_COL], unitFactor);
+    };
+    JpcCrossTabResult.outputPreviewContent = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, maxColRec, unitFactor) {
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, maxColRec, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_CONTENT], unitFactor);
+    };
+    JpcCrossTabResult.outputPreviewTabSum = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, tabNodeName, unitFactor) {
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, 1, rptTpl[JV.NODE_CROSS_INFO][tabNodeName], unitFactor);
+    };
+    JpcCrossTabResult.outputPreviewTabExt = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor) {
+        //交叉行拓展
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, 1, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW_EXT], unitFactor);
+    };
+    JpcCrossTabResult.outputPreviewSumTabExt = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, unitFactor) {
+        //交叉行拓展合计
+        return this.private_OutputPreviewCommon(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, 1, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW_SUM_EXT], unitFactor);
+    };
+    JpcCrossTabResult.private_OutputPreviewCommon = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg, maxRowRec, maxColRec, tab, unitFactor) {
+        let me = this, rst = [];
+        let band = bands[tab[JV.PROP_BAND_NAME]];
+        if (band) {
+            let tab_fields = tab[JV.PROP_CROSS_FIELDS];
+            for (let rowIdx = 0; rowIdx < maxRowRec; rowIdx++) {
+                for (let i = 0; i < tab_fields.length; i++) {
+                    let tab_field = tab_fields[i];
+                    if (!(tab_field[JV.PROP_HIDDEN])) {
+                        for (let colIdx = 0; colIdx < maxColRec; colIdx++) {
+                            if (tab_field[JV.PROP_IS_SERIAL]) {
+                                rst.push(me.outputTabField(band, tab_field, [rowIdx + 1], 0, -1, maxRowRec, rowIdx, maxColRec, colIdx, unitFactor, false, controls));
+                            } else {
+                                rst.push(me.outputTabField(band, tab_field, null, -1, -1, maxRowRec, rowIdx, maxColRec, colIdx, unitFactor, false, controls));
+                            }
+                        }
+                    }
+                }
+                if (tab[JV.PROP_TEXTS]) {
+                    for (let j = 0; j < tab[JV.PROP_TEXTS].length; j++) {
+                        for (let colIdx = 0; colIdx < maxColRec; colIdx++) {
+                            rst.push(JpcTextHelper.outputText(tab[JV.PROP_TEXTS][j], band, unitFactor, maxRowRec, rowIdx, maxColRec, colIdx, 1, 0));
+                        }
+                    }
+                }
+            }
+        }
         return rst;
     };
     JpcCrossTabResult.outputAsSimpleJSONPage = function(rptTpl, dataObj, page, bands, controls, $CURRENT_RPT, customizeCfg) {
@@ -334,33 +416,33 @@ JpcCrossTabSrv.prototype.createNew = function(){
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
         if (me.paging_option === JV.PAGING_OPTION_INFINITY) {
             /*
-            let segIdx = page - 1;
-            //1 calculate the band position
-            JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1]);
-            //2. then reset the band height
-            let tab = rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_CONTENT];
-            let crossContentBand = bands[tab[JV.PROP_BAND_NAME]];
-            let actH = JpcCrossTabHelper.getActualRowsHeight(bands, rptTpl, me.sortedRowSequence, page);
-            let actW = JpcCrossTabHelper.getActualColsWidth(bands, rptTpl, me.sortedColSequence, page);
-            let offsetY = actH - (crossContentBand.Bottom - crossContentBand.Top);
-            let offsetX = actW - (crossContentBand.Right - crossContentBand.Left);
-            JpcBandHelper.resetBandPos(rptTpl[JV.NODE_BAND_COLLECTION], bands, crossContentBand, offsetX, offsetY);
+             let segIdx = page - 1;
+             //1 calculate the band position
+             JpcBandHelper.setBandArea(bands, rptTpl, me.pageStatusLst[page - 1]);
+             //2. then reset the band height
+             let tab = rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_CONTENT];
+             let crossContentBand = bands[tab[JV.PROP_BAND_NAME]];
+             let actH = JpcCrossTabHelper.getActualRowsHeight(bands, rptTpl, me.sortedRowSequence, page);
+             let actW = JpcCrossTabHelper.getActualColsWidth(bands, rptTpl, me.sortedColSequence, page);
+             let offsetY = actH - (crossContentBand.Bottom - crossContentBand.Top);
+             let offsetX = actW - (crossContentBand.Right - crossContentBand.Left);
+             JpcBandHelper.resetBandPos(rptTpl[JV.NODE_BAND_COLLECTION], bands, crossContentBand, offsetX, offsetY);
 
-            //2.1 Row-Tab
-            tabRstLst.push(me.outputRowTab(rptTpl, dataObj, page, bands, unitFactor, controls));
-            //2.2 Col-Tab
-            tabRstLst.push(me.outputColTab(rptTpl, dataObj, page, bands, unitFactor, controls));
-            //2.3 Content-Tab
-            tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls));
-            //2.4 Sum-Tab Row
-            //2.4 Sum-tab Col
-            tabRstLst.push(me.outputTabSum(rptTpl, dataObj, page, bands, unitFactor, JV.NODE_CROSS_COL_SUM, controls));
-            //2.x row tab ext
-            tabRstLst.push(me.outputTabExt(rptTpl, dataObj, page, bands, unitFactor, controls));
-            tabRstLst.push(me.outputSumTabExt(rptTpl, dataObj, page, bands, unitFactor, segIdx, controls));
-            //2.5 Discrete
-            tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[JV.NODE_CROSS_INFO][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[page - 1], segIdx, 1, 0, $CURRENT_RPT, customizeCfg));
-            //*/
+             //2.1 Row-Tab
+             tabRstLst.push(me.outputRowTab(rptTpl, dataObj, page, bands, unitFactor, controls));
+             //2.2 Col-Tab
+             tabRstLst.push(me.outputColTab(rptTpl, dataObj, page, bands, unitFactor, controls));
+             //2.3 Content-Tab
+             tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls));
+             //2.4 Sum-Tab Row
+             //2.4 Sum-tab Col
+             tabRstLst.push(me.outputTabSum(rptTpl, dataObj, page, bands, unitFactor, JV.NODE_CROSS_COL_SUM, controls));
+             //2.x row tab ext
+             tabRstLst.push(me.outputTabExt(rptTpl, dataObj, page, bands, unitFactor, controls));
+             tabRstLst.push(me.outputSumTabExt(rptTpl, dataObj, page, bands, unitFactor, segIdx, controls));
+             //2.5 Discrete
+             tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[JV.NODE_CROSS_INFO][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[page - 1], segIdx, 1, 0, $CURRENT_RPT, customizeCfg));
+             //*/
         } else {
             let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
             //1 calculate the band position
@@ -387,12 +469,6 @@ JpcCrossTabSrv.prototype.createNew = function(){
         }
         return rst;
     };
-    JpcCrossTabResult.outputPreviewRowTab = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg) {
-        //
-    };
-    JpcCrossTabResult.outputPreviewColTab = function(rptTpl, bands, controls, $CURRENT_RPT, customizeCfg) {
-        //
-    };
     JpcCrossTabResult.outputRowTab = function(rptTpl, dataObj, page, bands, unitFactor, controls, $CURRENT_RPT, customizeCfg) {
         let me = this, rst = [];
         let tab = rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_ROW];
@@ -407,9 +483,16 @@ JpcCrossTabSrv.prototype.createNew = function(){
                 let flexiblePrecisionRefObj = null, flexibleRefField = null, precision_ref_data = null;
                 for (let i = 0; i < me.row_fields_idx.length; i++) {
                     let tab_field = tab_fields[i];
-                    let data_field = data_details[me.row_fields_idx[i]];
-                    let map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
                     if (!(tab_field[JV.PROP_HIDDEN])) {
+                        let data_field = null;
+                        let map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
+                        if (typeof me.row_fields_idx[i] !== 'object') {
+                            data_field = data_details[me.row_fields_idx[i]];
+                        } else {
+                            if (map_data_field) {
+                                data_field = map_data_field[JV.PROP_AD_HOC_DATA];
+                            }
+                        }
                         let rows = valuesIdx.length;
                         for (let rowIdx = 0; rowIdx < rows; rowIdx++) {
                             if (map_data_field && map_data_field[JV.PROP_PRECISION] && map_data_field.flexiblePrecisionRefObj) {
@@ -446,9 +529,16 @@ JpcCrossTabSrv.prototype.createNew = function(){
                 let flexiblePrecisionRefObj = null, flexibleRefField = null, precision_ref_data = null;
                 for (let i = 0; i < me.col_fields_idx.length; i++) {
                     let tab_field = tab_fields[i];
-                    let data_field = data_details[me.col_fields_idx[i]];
-                    let map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
                     if (!(tab_field[JV.PROP_HIDDEN])) {
+                        let data_field = null;
+                        let map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
+                        if (typeof me.col_fields_idx[i] !== 'object') {
+                            data_field = data_details[me.col_fields_idx[i]];
+                        } else {
+                            if (map_data_field) {
+                                data_field = map_data_field[JV.PROP_AD_HOC_DATA];
+                            }
+                        }
                         let cols = valuesIdx.length;
                         for (let colIdx = 0; colIdx < cols; colIdx++) {
                             if (map_data_field && map_data_field[JV.PROP_PRECISION] && map_data_field.flexiblePrecisionRefObj) {

+ 21 - 17
modules/reports/rpt_component/jpc_ex.js

@@ -168,26 +168,30 @@ JpcExSrv.prototype.createNew = function(){
         let me = this, dftPagingOption = option||JV.PAGING_OPTION_NORMAL;
         //1. data object
         let dataHelper = JpcData.createNew();
-        dataHelper.analyzeData(rptTpl, dataObj);
-        //2. tab object
-        //pre-condition: the data should be sorted in SQL/NoSQL level!
-        //let dt1 = new Date();
-        if (me.flowTab) {
-            me.flowTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
-            if (me.flowTabEx) {
-                me.flowTabEx.sorting(rptTpl, dataObj, dataHelper.exDataSeq.slice(0));
-            }
-        }
-        if (me.billTab) {
-            me.billTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
-        }
+        me.executeFormulas(JV.RUN_TYPE_BEFORE_ANALYZING, rptTpl, dataObj, me); //在分析前运行,主要是增加灵活性,比如:重新编排数据的主从关系
         if (me.crossTab) {
+            me.executeFormulas(JV.RUN_TYPE_BEFORE_PAGING, rptTpl, dataObj, me);
+            dataHelper.analyzeData(rptTpl, dataObj);
             me.crossTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
+        } else {
+            dataHelper.analyzeData(rptTpl, dataObj);
+            //2. tab object
+            //pre-condition: the data should be sorted in SQL/NoSQL level!
+            //let dt1 = new Date();
+            if (me.flowTab) {
+                me.flowTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
+                if (me.flowTabEx) {
+                    me.flowTabEx.sorting(rptTpl, dataObj, dataHelper.exDataSeq.slice(0), me);
+                }
+            }
+            if (me.billTab) {
+                me.billTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
+            }
+            //let dt2 = new Date();
+            //alert(dt2 - dt1);
+            //3. formulas
+            me.executeFormulas(JV.RUN_TYPE_BEFORE_PAGING, rptTpl, dataObj, me);
         }
-        //let dt2 = new Date();
-        //alert(dt2 - dt1);
-        //3. formulas
-        me.executeFormulas(JV.RUN_TYPE_BEFORE_PAGING, rptTpl, dataObj, me);
         //4. paging
         me.paging(rptTpl, dataObj, defProperties, dftPagingOption, outputType);
         //alert('analyzeData was completed!');

+ 99 - 54
modules/reports/rpt_component/jpc_flow_tab.js

@@ -199,7 +199,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             if (typeof(me.seg_sum_fields_idx[i]) === "object") {
                 let exField = JE.F(me.seg_sum_fields_idx[i][JV.PROP_ID], $CURRENT_RPT);
                 if (exField) {
-                    data_fields.push(exField["data_field"]);
+                    data_fields.push(exField[JV.PROP_AD_HOC_DATA]);
                 } else {
                     data_fields.push(null);
                 }
@@ -737,59 +737,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
             vIdx.push([-1, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
         }
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
-        // me.multiCols = 1 * rptTpl[JV.NODE_FLOW_INFO][JV.PROP_MULTI_COLUMN];
-        let newMultiCols = 1 * rptTpl[JV.NODE_FLOW_INFO][JV.PROP_MULTI_COLUMN];
         // 2.2 Column tab
-        let private_colone_cells = function(orgCells) {
-            let newRst = [];
-            let newCopyCells = [];
-            newCopyCells.push(orgCells);
-            if (newMultiCols > 1) {
-                let minX = 10000, maxX = -10;
-                for (let cell of orgCells) {
-                    if (minX > parseInt(cell[JV.PROP_AREA][JV.PROP_LEFT])) minX = cell[JV.PROP_AREA][JV.PROP_LEFT];
-                    if (maxX < parseInt(cell[JV.PROP_AREA][JV.PROP_RIGHT])) maxX = cell[JV.PROP_AREA][JV.PROP_RIGHT];
-                }
-                let newW = maxX - minX, newSegW = newW / newMultiCols;
-                for (let i = 1; i < newMultiCols; i++) {
-                    let cells = [];
-                    for (let cell of orgCells) {
-                        let copyCell = {Value: cell.Value, area: {}, font: cell[JV.PROP_FONT], control: cell[JV.PROP_CONTROL], style: cell[JV.PROP_STYLE]};
-                        cells.push(copyCell);
-                        copyCell[JV.PROP_AREA][JV.PROP_LEFT] = cell[JV.PROP_AREA][JV.PROP_LEFT];
-                        copyCell[JV.PROP_AREA][JV.PROP_RIGHT] = cell[JV.PROP_AREA][JV.PROP_RIGHT];
-                        copyCell[JV.PROP_AREA][JV.PROP_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP];
-                        copyCell[JV.PROP_AREA][JV.PROP_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_BOTTOM];
-                    }
-                    newCopyCells.push(cells);
-                }
-                for (let ci = 0; ci < newCopyCells.length; ci++) {
-                    for (let cCell of newCopyCells[ci]) {
-                        cCell[JV.PROP_AREA][JV.PROP_LEFT] = Math.round(minX + newSegW * ci + (cCell[JV.PROP_AREA][JV.PROP_LEFT] - minX) / newMultiCols);
-                        cCell[JV.PROP_AREA][JV.PROP_RIGHT] = Math.round(minX + newSegW * ci + (cCell[JV.PROP_AREA][JV.PROP_RIGHT] - minX) / newMultiCols);
-                    }
-                }
-            }
-            for (let cCells of newCopyCells) {
-                for (let dCell of cCells) {
-                    newRst.push(dCell);
-                }
-            }
-            return newRst;
-        };
-        let tmpColCells = me.outputColumn(rptTpl, null, 1, 0, bands, unitFactor, 0);
-        if (newMultiCols > 1) {
-            tmpColCells = private_colone_cells(tmpColCells);
-        }
-        rst = rst.concat(tmpColCells);
+        rst = rst.concat(me.outputColumn(rptTpl, null, 1, 0, bands, unitFactor, 0));
         // 2.1 Content-Tab
-        let tmpContentCells = me.outputPreviewContent(rptTpl, bands, unitFactor, controls, pageStatus, maxRowRec);
-        if (newMultiCols > 1) {
-            tmpContentCells = private_colone_cells(tmpContentCells);
-        } else {
-            // rst = rst.concat(me.outputPreviewContent(rptTpl, bands, unitFactor, controls, pageStatus, maxRowRec));
-        }
-        rst = rst.concat(tmpContentCells);
+        rst = rst.concat(me.outputPreviewContent(rptTpl, bands, unitFactor, controls, pageStatus, maxRowRec));
         // 2.3 Sum Seg
         rst = rst.concat(me.outputPreviewSegSum(rptTpl, bands, unitFactor, controls, pageStatus));
         // 2.4 Sum Page
@@ -868,6 +819,87 @@ JpcFlowTabSrv.prototype.createNew = function(){
         }
         return rst;
     };
+    JpcFlowTabResult.combinePageCells = function (rstPageCells, verticalCombinePos, horizonCombinePos) {
+        // let me = this;
+        if (verticalCombinePos.length > 0 || horizonCombinePos.length > 1) {
+            let cacheObj = {vCache:{}, hCache: {}, hCacheStr: []};
+            let removeCellIds = [];
+            for (let vPosArr of verticalCombinePos) {
+                let pStr = "_" + vPosArr[0] + "_" + vPosArr[1];
+                cacheObj.vCache[pStr] = [];
+            }
+            //horizonCombinePos不需要预记
+            for (let idx = 0; idx < rstPageCells.length; idx++) {
+                let cell = rstPageCells[idx];
+                for (let vPosArr of verticalCombinePos) {
+                    if (cell[JV.PROP_AREA][JV.PROP_LEFT] === vPosArr[0] && cell[JV.PROP_AREA][JV.PROP_RIGHT] === vPosArr[1]) {
+                        cacheObj.vCache["_" + vPosArr[0] + "_" + vPosArr[1]].push(idx);
+                    }
+                }
+                for (let hPosArr of horizonCombinePos) {
+                    if (cell[JV.PROP_AREA][JV.PROP_LEFT] === hPosArr[0] && cell[JV.PROP_AREA][JV.PROP_RIGHT] === hPosArr[1]) {
+                        let hpStr = "_" + cell[JV.PROP_AREA][JV.PROP_TOP] + "_" + cell[JV.PROP_AREA][JV.PROP_BOTTOM];
+                        if (cacheObj.hCacheStr.indexOf(hpStr) < 0) {
+                            cacheObj.hCache[hpStr] = [];
+                            cacheObj.hCacheStr.push(hpStr);
+                        }
+                        cacheObj.hCache[hpStr].push(idx);
+                    }
+                }
+            }
+            if (verticalCombinePos.length > 0) {
+                for (let vPosArr of verticalCombinePos) {
+                    let pStr = "_" + vPosArr[0] + "_" + vPosArr[1];
+                    //rstPageCells的结果已经是按顺序排列了,这里不用再排序
+                    if (cacheObj.vCache[pStr] && cacheObj.vCache[pStr].length > 0) {
+                        let preCell = rstPageCells[cacheObj.vCache[pStr][0]];
+                        for (let cIdx = 1; cIdx < cacheObj.vCache[pStr].length; cIdx++) {
+                            if (preCell.Value === "") {
+                                preCell = rstPageCells[cacheObj.vCache[pStr][cIdx]];
+                            } else {
+                                if (preCell.Value === rstPageCells[cacheObj.vCache[pStr][cIdx]].Value) {
+                                    preCell[JV.PROP_AREA][JV.PROP_BOTTOM] = rstPageCells[cacheObj.vCache[pStr][cIdx]][JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    removeCellIds.push(cacheObj.vCache[pStr][cIdx]);
+                                } else {
+                                    preCell = rstPageCells[cacheObj.vCache[pStr][cIdx]];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (horizonCombinePos.length > 1) {
+                if (cacheObj.hCacheStr.length > 0) {
+                    for (let hStr of cacheObj.hCacheStr) {
+                        let preCell = rstPageCells[cacheObj.hCache[hStr][0]];
+                        for (let cIdx = 1; cIdx < cacheObj.hCache[hStr].length; cIdx++) {
+                            if (preCell.Value === "") {
+                                preCell = rstPageCells[cacheObj.hCache[hStr][cIdx]];
+                            } else {
+                                if (preCell.Value === rstPageCells[cacheObj.hCache[hStr][cIdx]].Value) {
+                                    if (preCell[JV.PROP_AREA][JV.PROP_RIGHT] < rstPageCells[cacheObj.hCache[hStr][cIdx]][JV.PROP_AREA][JV.PROP_RIGHT]) {
+                                        preCell[JV.PROP_AREA][JV.PROP_RIGHT] = rstPageCells[cacheObj.hCache[hStr][cIdx]][JV.PROP_AREA][JV.PROP_RIGHT];
+                                    } else {
+                                        preCell[JV.PROP_AREA][JV.PROP_LEFT] = rstPageCells[cacheObj.hCache[hStr][cIdx]][JV.PROP_AREA][JV.PROP_LEFT];
+                                    }
+                                    removeCellIds.push(cacheObj.hCache[hStr][cIdx]);
+                                } else {
+                                    preCell = rstPageCells[cacheObj.hCache[hStr][cIdx]];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (removeCellIds.length > 0) {
+                //这次真的要排序了
+                removeCellIds.sort(); //默认方式即可
+                for (let idx = removeCellIds.length - 1; idx >= 0; idx--) {
+                    rstPageCells.splice(removeCellIds[idx], 1);
+                }
+            }
+        }
+    };
     JpcFlowTabResult.outputPreviewContent = function(rptTpl, bands, unitFactor, controls, pageStatus, maxRec) {
         let me = this, rst = [];
         let tab = rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT];
@@ -892,6 +924,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
         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 verticalCombinePos = [], horizonCombinePos = []; //合并特性用
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
             let pageStatus = me.pageStatusLst[page - 1];
@@ -903,10 +936,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 let contentValuesIdx = me.dispValueIdxLst[page - 1];
                 let page_sum_data_fields = [];
                 for (let i = 0; i < me.page_sum_fields_idx.length; i++) {
-                    if (typeof(me.page_sum_fields_idx[i])=="object") {
+                    if (typeof(me.page_sum_fields_idx[i]) === "object") {
                         let exField = JE.F(me.page_sum_fields_idx[i][JV.PROP_ID], $CURRENT_RPT);
                         if (exField) {
-                            page_sum_data_fields.push(exField["data_field"]);
+                            page_sum_data_fields.push(exField[JV.PROP_AD_HOC_DATA]);
                         } else {
                             page_sum_data_fields.push(null);
                         }
@@ -968,6 +1001,17 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                 }
                             }
                         }
+                        if (rowIdx === 0 && tab_field[JV.PROP_COMBINE_TYPE] !== undefined && tab_field[JV.PROP_COMBINE_TYPE] !== null) {
+                            let rstCellItem = rst[rst.length - 1];
+                            let cbfPos = [];
+                            cbfPos.push(rstCellItem[JV.PROP_AREA][JV.PROP_LEFT]);
+                            cbfPos.push(rstCellItem[JV.PROP_AREA][JV.PROP_RIGHT]);
+                            if (tab_field[JV.PROP_COMBINE_TYPE] === 'vertical') {
+                                verticalCombinePos.push(cbfPos);
+                            } else if (tab_field[JV.PROP_COMBINE_TYPE] === 'horizon') {
+                                horizonCombinePos.push(cbfPos);
+                            }
+                        }
                     }
                     if (contentValuesIdx[rowIdx][0] === JV.TYPE_FOLLOW_MODE) {
                         for (let idx_ex = 0; idx_ex < tab_fields_ex.length; idx_ex++) {
@@ -1055,6 +1099,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
         for (let idIdx = eliminateCells.length - 1; idIdx >= 0; idIdx--) {
             rst.splice(eliminateCells[idIdx], 1);
         }
+        me.combinePageCells(rst, verticalCombinePos, horizonCombinePos);
         return rst;
     };
     JpcFlowTabResult.outputColumn = function (rptTpl, dataObj, page, segIdx, bands, unitFactor, multiColIdx) {

+ 15 - 4
modules/reports/util/rpt_excel_util.js

@@ -275,24 +275,35 @@ function writeStyles(stylesObj){
 }
 function writeSharedString(sharedStrList){
     let rst = [];
+    let pri_func_write = function(cellVal) {
+        if (cellVal !== null) {
+            if ((typeof cellVal === 'string') && cellVal.indexOf(' ') === 0) {
+                rst.push('<si><t xml:space="preserve">' + cellVal + '</t></si>');
+            } else {
+                rst.push('<si><t>' + cellVal + '</t></si>');
+            }
+        }
+    };
     if (sharedStrList && sharedStrList.length > 0) {
         rst.push(dftHeadXml + '\r\n');
         rst.push('<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="' + sharedStrList.length + '" uniqueCount="' + sharedStrList.length + '">');
         let regExp = new RegExp("<", "gm");
         for (let i = 0; i < sharedStrList.length; i++) {
-            //rst.push('<si><t>' + sharedStrList[i] + '</t></si>');
             if (typeof sharedStrList[i] === 'string') {
                 //转换特殊字符,如 < , 则需要转义一下
                 sharedStrList[i] = sharedStrList[i].replace(regExp, "&lt;");
                 if (sharedStrList[i].indexOf('|') >= 0) {
                     //rst.push('<si><t>' + sharedStrList[i].split('|').join('\r\n') + '</t></si>');
-                    rst.push('<si><t>' + sharedStrList[i].split('|').join('\n') + '</t></si>');
+                    // rst.push('<si><t>' + sharedStrList[i].split('|').join('\n') + '</t></si>');
+                    pri_func_write(sharedStrList[i].split('|').join('\n'));
                 } else {
-                    rst.push('<si><t>' + sharedStrList[i] + '</t></si>');
+                    // rst.push('<si><t>' + sharedStrList[i] + '</t></si>');
+                    pri_func_write(sharedStrList[i]);
                 }
                 // rst.push('<si><t>' + sharedStrList[i].replace('|','\r\n') + '</t></si>');
             } else {
-                rst.push('<si><t>' + sharedStrList[i] + '</t></si>');
+                // rst.push('<si><t>' + sharedStrList[i] + '</t></si>');
+                pri_func_write(sharedStrList[i]);
             }
         }
         rst.push('</sst>');

+ 5 - 1
public/scHintBox.html

@@ -148,7 +148,11 @@
             $("#hintBox_form").modal('show');
 
         },
-        valueBox: function (title, value, doOK) {
+        valueBox: function (title, value, doOK,row) {
+            if(row && row>0){//默认为input,如果有row说明是要多行输入,把input换成textarea.
+                $('#hintBox_value').remove();
+                $("#hintBox_error").before(` <textarea id="hintBox_value" class="form-control" rows="${row}"></textarea>`);
+            }
             this.init();
             $('#hintBox_title').text(title);
             this.value = value;

+ 2 - 0
public/web/rpt_value_define.js

@@ -120,6 +120,7 @@ const JV = {
     PROP_POSITION: "Position",
     PROP_HIDDEN: "Hidden",
     PROP_IS_SERIAL: "isSerial",
+    PROP_COMBINE_TYPE: "combineType",
     PROP_IS_AUTO_HEIGHT: "isAutoHeight",
     PROP_FONT: "font",
     PROP_CONTROL: "control",
@@ -198,6 +199,7 @@ const JV = {
     PROP_INSERTED_GRP_REC: "insertedGrpRecAmt",
     PROP_GRP_LINES: "group_lines_amt",
 
+    RUN_TYPE_BEFORE_ANALYZING: "before_analyzing",
     RUN_TYPE_BEFORE_PAGING: "before_paging",
     RUN_TYPE_BEFORE_OUTPUT: "before_output",
 

+ 11 - 10
public/web/tree_sheet/tree_sheet_controller.js

@@ -83,25 +83,26 @@ var TREE_SHEET_CONTROLLER = {
                 }
             }
         };
-        controller.prototype.m_delete = function (nodes, beginRow = null) {//删除选中的多行节点
+        controller.prototype.m_delete = function (nodes, beginRow = null,selectNew = true) {//删除选中的多行节点,selectNew 为false时删除后不改变tree的选中节点
             var that = this, sels = this.sheet.getSelections();
             if (this.tree.selected) {
                 if (this.tree.m_delete(nodes)) {
                     TREE_SHEET_HELPER.massOperationSheet(this.sheet, function () {
                         let rowCount = 0;
+                        let delRow = beginRow?beginRow:sels[0].row;
                         for(let node of nodes){
                             rowCount = rowCount+node.posterityCount() + 1;
                         }
-                        if(beginRow){
-                            sels[0].row = beginRow;
+                        that.sheet.deleteRows(delRow, rowCount);
+                        if(selectNew == true){
+                            if(beginRow) sels[0].row = beginRow;
+                            if(sels[0].row >=  that.tree.items.length){
+                                sels[0].row = that.tree.items.length-1;
+                                sels[0].colCount = 1;
+                            }
+                            that.setTreeSelected(that.tree.items[sels[0].row]);
+                            that.sheet.setSelection(sels[0].row,sels[0].col,1,sels[0].colCount);
                         }
-                        that.sheet.deleteRows(sels[0].row, rowCount);
-                        if(sels[0].row >=  that.tree.items.length){
-                            sels[0].row = that.tree.items.length-1;
-                            sels[0].colCount = 1;
-                        }
-                        that.setTreeSelected(that.tree.items[sels[0].row]);
-                        that.sheet.setSelection(sels[0].row,sels[0].col,1,sels[0].colCount);
                     });
                     if(typeof cbTools !== 'undefined'){
                         cbTools.refreshFormulaNodes();

BIN
web/building_saas/css/login-bgp.jpg


+ 37 - 4
web/building_saas/css/main.css

@@ -25,7 +25,40 @@ a{
 .text-indent {
     text-indent:26px;
 }
+.modal-header{
+    background:#f2f2f2;
+    border-bottom:1px solid #ccc;
+    padding:.8rem 1rem;
+}
+.modal-title{
+    font-size:1rem;
+}
+.modal-footer{
+    padding:.8rem 1rem;
+}
 /*自定义css*/
+.login-body,.login-html{
+    height:100%;
+}
+.login-bg{
+    width: 100%;
+    height: 100%;
+    background: #f2f6f5 url("login-bgp.jpg") bottom center no-repeat;
+    background-size: 100% auto;
+    display: inline-block;
+    position: absolute;
+}
+.login-panel {
+    width: 500px;
+    margin: 0 auto;
+    position: absolute;
+    left: 0;
+    right: 0;
+    top: 20%;
+    padding:30px;
+    background:#fff;
+    box-shadow:#333 1px 1px 5px
+}
 .header {
     border-bottom: 1px solid #ccc
 }
@@ -48,6 +81,10 @@ a{
     font-size:16px;
     color:#ff6501;
 }
+.header-logo div.b-title{
+    font-size:24px;
+    color:#ff6501;
+}
 .top-msg{
     position: fixed;
     top:10px;
@@ -366,10 +403,6 @@ a{
 .rn-nav .nav-tabs .nav-link.active span{
     display: inline-block;
 }
-.form-signin {
-    max-width: 500px;
-    margin: 150px auto;
-}
 .poj-list, .side-content ,.form-view{
     overflow: auto;
 }

BIN
web/building_saas/img/building.png


+ 1 - 1
web/building_saas/js/global.js

@@ -64,7 +64,7 @@ $(function () {
     /*工具提示*/
     $(function () {
         $('[data-toggle="tooltip"]').tooltip();
-        $('[data-submenu]').submenupicker();
+        if( $('[data-submenu]').submenupicker) $('[data-submenu]').submenupicker();
         $('[data-toggle="tooltip"]').click(function () {
             $(this).tooltip('hide');
         })

+ 1 - 1
web/building_saas/main/js/models/quantity_detail.js

@@ -746,7 +746,7 @@ var quantity_detail = {
                                 times = 1;
                             }
                             rationNode.data.quantity = scMathUtil.roundForObj(ration_value / times,getDecimal("quantity",rationNode));
-                            rationNode.data.contain = scMathUtil.roundForObj(rationNode.data.quantity/value,getDecimal("process"));
+                            rationNode.data.contain = value?scMathUtil.roundForObj(rationNode.data.quantity/value,getDecimal("process")):0;
                             rationNode.changed = true;
                             needUpdateChildren.push(rationNode);
                             if (rationNode.children.length>0){//如果有子工料机

+ 16 - 1
web/building_saas/main/js/views/mbzm_view.js

@@ -149,7 +149,8 @@ let mbzm_obj={
         let rations = {update:[],create:[],delete:[]},bills={update:[],create:[]};
         if(this.datas.length <= 0) return;
         for(let d of this.datas){
-            if((gljUtil.isDef(d.quantity)&& parseFloat(d.quantity)>0)||(d.coe && d.coe!="0")){
+            let ration = _.find(projectObj.project.Ration.datas,{'referenceRationID':selected.data.ID,'code':d.code});
+            if(ration||(gljUtil.isDef(d.quantity)&& parseFloat(d.quantity)>0)||(d.coe && d.coe!="0")){
                 if(this.positionChecking(createLocation,d) == false){//清单位置检查
                     alert(`请选择${d.code}生成的清单位置`);
                     return;
@@ -167,6 +168,19 @@ let mbzm_obj={
         console.log(data);
         $.bootstrapLoading.start();
         CommonAjax.post('/ration/applyTemplate',data,function (result) {
+            let parentsNodes = [];
+            //先删除旧的定额
+            if(data.rations.delete.length > 0){
+                for(let d of data.rations.delete){
+                    let dRaNode =  projectObj.project.mainTree.getNodeByID(d.ID);
+                    if(dRaNode){
+                        parentsNodes.push(dRaNode.parent);
+                        projectObj.project.Ration.deleteSubListOfRation({ID:d.ID});
+                        _.remove(projectObj.project.Ration.datas,{'ID':d.ID});
+                        projectObj.mainController.m_delete([dRaNode],dRaNode.serialNo(),false)//这里删除关联子目生成的定额因为是离散的树节点,所以要这样分开处理
+                    }
+                }
+            }
             let refreshNodes = projectObj.project.updateNodesCache(result.updateDatas);//更新要update的前端缓存,并返回要刷新的树节点
             let nodeDatas = {ration:{add:[]}, bills:{add:[]}};
             if(result.rationResult){
@@ -193,6 +207,7 @@ let mbzm_obj={
                 $.bootstrapLoading.end();
                 cbTools.refreshFormulaNodes();
                 //更新计算程序模板,并进行重新计算
+                if(parentsNodes.length > 0) calRations = calRations.concat(parentsNodes);//计算被删除的子目关联定额的父节点
                 projectObj.project.calcProgram.calcNodesAndSave(calRations,function () {
                     installationFeeObj.calcInstallationFee();
                 });

+ 1 - 1
web/building_saas/main/js/views/project_view.js

@@ -1936,7 +1936,7 @@ var projectObj = {
         hintBox.valueBox(infoText, node.data[fieldID], function () {
             let newValue = hintBox.value;
             projectObj.updateNodeField(node,newValue,fieldID);
-        });
+        },3);
     },
     ifItemCharHiden:function (setting) {//项目特征及内容列是否隐藏
         if(this.itemCol == null||this.itemCol == undefined){

BIN
web/dest/css/login-bgp.jpg


Разница между файлами не показана из-за своего большого размера
+ 8 - 4
web/users/html/login.html