Browse Source

自动行高特性

TonyKang 7 năm trước cách đây
mục cha
commit
15ca0a1ba0

+ 43 - 35
modules/reports/rpt_component/helper/jpc_helper_common.js

@@ -21,25 +21,22 @@ let JpcCommonHelper = {
         return rst;
     },
     getFont: function(fontName, dftFonts, rptTpl) {
-        let me = this, rst = null, list = [];
+        let me = this, list = [];
         if (rptTpl) list.push(rptTpl[JV.NODE_FONT_COLLECTION]);
         list.push(dftFonts);
-        rst = me.getResultByID(fontName, list);
-        return rst;
+        return me.getResultByID(fontName, list);
     },
     getStyle: function(styleName, dftStyles, rptTpl) {
-        let me = this, rst = null, list = [];
+        let me = this, list = [];
         if (rptTpl) list.push(rptTpl[JV.NODE_STYLE_COLLECTION]);
         list.push(dftStyles);
-        rst = me.getResultByID(styleName, list);
-        return rst;
+        return me.getResultByID(styleName, list);
     },
     getControl: function(controlName, dftControls, rptTpl) {
-        let me = this, rst = null, list = [];
+        let me = this, list = [];
         if (rptTpl) list.push(rptTpl[JV.NODE_CONTROL_COLLECTION]);
         list.push(dftControls);
-        rst = me.getResultByID(controlName, list);
-        return rst;
+        return me.getResultByID(controlName, list);
     },
     getLayoutAlignment: function(alignStr) {
         let rst = JV.LAYOUT.indexOf(alignStr);
@@ -77,30 +74,30 @@ let JpcCommonHelper = {
         }
         return arrDPI;
     },
-    getScreenDPI_bk: function() {
-        let me = this, arrDPI = [];
-        if (!me.commonConstant.resolution) {
-            if (window) {
-                if (window.screen.deviceXDPI != undefined) {
-                    arrDPI.push(window.screen.deviceXDPI);
-                    arrDPI.push(window.screen.deviceYDPI);
-                } else {
-                    let tmpNode = document.createElement("DIV");
-                    tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
-                    document.body.appendChild(tmpNode);
-                    arrDPI.push(parseInt(tmpNode.offsetWidth));
-                    arrDPI.push(parseInt(tmpNode.offsetHeight));
-                    tmpNode.parentNode.removeChild(tmpNode);
-                }
-            } else {
-                arrDPI = [96,96];
-            }
-            me.commonConstant.resolution = arrDPI;
-        } else {
-            arrDPI = me.commonConstant.resolution;
-        }
-        return arrDPI;
-    },
+    // getBrowerScreenDPI: function() {
+    //     let me = this, arrDPI = [];
+    //     if (!me.commonConstant.resolution) {
+    //         if (window) {
+    //             if (window.screen.deviceXDPI != undefined) {
+    //                 arrDPI.push(window.screen.deviceXDPI);
+    //                 arrDPI.push(window.screen.deviceYDPI);
+    //             } else {
+    //                 let tmpNode = document.createElement("DIV");
+    //                 tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
+    //                 document.body.appendChild(tmpNode);
+    //                 arrDPI.push(parseInt(tmpNode.offsetWidth));
+    //                 arrDPI.push(parseInt(tmpNode.offsetHeight));
+    //                 tmpNode.parentNode.removeChild(tmpNode);
+    //             }
+    //         } else {
+    //             arrDPI = [96,96];
+    //         }
+    //         me.commonConstant.resolution = arrDPI;
+    //     } else {
+    //         arrDPI = me.commonConstant.resolution;
+    //     }
+    //     return arrDPI;
+    // },
     getUnitFactor: function(rptTpl) {
         let me = this;
         return me.translateUnit(rptTpl[JV.NODE_MAIN_INFO][JV.PROP_UNITS]);
@@ -120,7 +117,7 @@ let JpcCommonHelper = {
         return rst;
     },
     getPageSize: function (rptTpl) {
-        let me = this, size = null;
+        let size = null;
         let sizeStr = rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE];
         let sizeIdx = JV.PAGES_SIZE_STR.indexOf(sizeStr);
         if (sizeIdx >= 0) {
@@ -152,12 +149,23 @@ let JpcCommonHelper = {
     getSegIdxByPageIdx: function(page, page_seg_map) {
         let rst = -1;
         for (let pIdx = 0; pIdx < page_seg_map.length; pIdx++) {
-            if (page_seg_map[pIdx][0] == page) {
+            if (page_seg_map[pIdx][0] === page) {
                 rst = page_seg_map[pIdx][1];
                 break;
             }
         }
         return rst;
+    },
+    getStringLinesInArea: function(area, strVal, pdfDoc) {
+        let areaWidth = area[JV.PROP_RIGHT] - area[JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] - 2;
+        let txtWidth = pdfDoc.widthOfString(strVal);
+        let rst = parseInt(txtWidth / areaWidth);
+        if (txtWidth % areaWidth > 0) {
+            rst++;
+        }
+        if (rst === 0) rst = 1; //即使是空字符串,也得有一行啊
+        return rst;
+        //备注: 其实是想用canvas的,但node canvas装起来麻烦,暂时用PDF Kit来顶用一下,以后换新方法再用
     }
 };
 

+ 5 - 0
modules/reports/rpt_component/helper/jpc_helper_field.js

@@ -8,6 +8,11 @@ let JpcFieldHelper = {
         }
         return rst;
     },
+    setValue: function(dataField, valueIdx, newValue) {
+        if (dataField && (dataField.length > valueIdx) && (valueIdx >= 0)) {
+            dataField[valueIdx] = newValue;
+        }
+    },
     decorateValue: function (cell, controls) {
         if (controls) {
             let val = cell[JV.PROP_VALUE];

+ 6 - 5
modules/reports/rpt_component/helper/jpc_helper_flow_tab.js

@@ -38,10 +38,11 @@ let JpcFlowTabHelper = {
         }
         return rst;
     },
-    chkSegEnd: function (bands, rptTpl, segmentLength, preRec, nextRec, isEx) {
-        let me = this;
-        let remainAmt = preRec + nextRec - segmentLength;
-        return me.hasEnoughSpace(rptTpl, bands, remainAmt, isEx);
+    chkSegEnd: function (bands, rptTpl, segmentLength, preRec, pageRecAmt, isEx) {
+        let me = this, rst = false;
+        let remainAmt = preRec + pageRecAmt - segmentLength;
+        rst = me.hasEnoughSpace(rptTpl, bands, remainAmt, isEx);
+        return rst;
     },
     hasEnoughSpace: function (rptTpl, bands, remainAmt, isEx) {
         if (remainAmt < 0) return false;
@@ -54,7 +55,7 @@ let JpcFlowTabHelper = {
             measurement = 1.0 * tab[JV.PROP_CMN_HEIGHT] * unitFactor;
             let spareHeight = measurement * remainAmt;
             let douH = band.Bottom - band.Top;
-            rst = (spareHeight >= douH) || (spareHeight - douH <= douDiffForCompare);
+            rst = ((spareHeight >= douH) || ((spareHeight - douH) <= douDiffForCompare));
         }
         return rst;
     }

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

@@ -45,15 +45,18 @@ JpcExSrv.prototype.createNew = function(){
     }
     function private_buildDftStyles(rptTpl, dftStyleCollection) {
         let rst = {};
+        function private_CopyBorder(destItem, srcItem) {
+            destItem[JV.PROP_LINE_WEIGHT] = srcItem[JV.PROP_LINE_WEIGHT];
+            destItem[JV.PROP_DASH_STYLE] = srcItem[JV.PROP_DASH_STYLE];
+            destItem[JV.PROP_COLOR] = srcItem[JV.PROP_COLOR];
+        }
         if (dftStyleCollection) {
             for (let i = 0; i < dftStyleCollection.length; i++) {
                 let item = {};
                 if (dftStyleCollection[i][JV.PROP_BORDER_STYLE] && dftStyleCollection[i][JV.PROP_BORDER_STYLE].length > 0) {
                     for (let j = 0; j < dftStyleCollection[i][JV.PROP_BORDER_STYLE].length; j++) {
                         let borderItem = {};
-                        for (let k = 0; k < JV.BORDER_STYLE_PROPS.length; k++) {
-                            borderItem[JV.BORDER_STYLE_PROPS[k]] = dftStyleCollection[i][JV.PROP_BORDER_STYLE][j][JV.BORDER_STYLE_PROPS[k]];
-                        }
+                        private_CopyBorder(borderItem, dftStyleCollection[i][JV.PROP_BORDER_STYLE][j]);
                         item[dftStyleCollection[i][JV.PROP_BORDER_STYLE][j][JV.PROP_POSITION]] = borderItem;
                     }
                 }
@@ -63,15 +66,65 @@ JpcExSrv.prototype.createNew = function(){
                 for (let i = 0; i < rptTpl[JV.NODE_STYLE_COLLECTION].length; i++) {
                     let rptDftItem = rptTpl[JV.NODE_STYLE_COLLECTION][i];
                     if (rst[rptDftItem[JV.PROP_ID]] === undefined) {
-                        let item = {};
-                        for (let j = 0; j < rptDftItem[JV.PROP_BORDER_STYLE].length; j++) {
-                            let borderItem = {};
-                            for (let k = 0; k < JV.BORDER_STYLE_PROPS.length; k++) {
-                                borderItem[JV.BORDER_STYLE_PROPS[k]] = rptDftItem[JV.PROP_BORDER_STYLE][j][JV.BORDER_STYLE_PROPS[k]];
+                        if (rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Top') > 0) {
+                            let key = rptDftItem[JV.PROP_ID].substr(0, rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Top'));
+                            if (rst[key]) {
+                                let item = {};
+                                if (rst[key][JV.PROP_LEFT]) {
+                                    item[JV.PROP_LEFT] = {};
+                                    private_CopyBorder(item[JV.PROP_LEFT], rst[key][JV.PROP_LEFT]);
+                                }
+                                if (rst[key][JV.PROP_RIGHT]) {
+                                    item[JV.PROP_RIGHT] = {};
+                                    private_CopyBorder(item[JV.PROP_RIGHT], rst[key][JV.PROP_RIGHT]);
+                                }
+                                if (rst[key][JV.PROP_TOP]) {
+                                    item[JV.PROP_TOP] = {};
+                                    private_CopyBorder(item[JV.PROP_TOP], rst[key][JV.PROP_TOP]);
+                                }
+                                rst[rptDftItem[JV.PROP_ID]] = item;
+                            }
+                        } else if (rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Middle') > 0) {
+                            let key = rptDftItem[JV.PROP_ID].substr(0, rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Middle'));
+                            if (rst[key]) {
+                                let item = {};
+                                if (rst[key][JV.PROP_LEFT]) {
+                                    item[JV.PROP_LEFT] = {};
+                                    private_CopyBorder(item[JV.PROP_LEFT], rst[key][JV.PROP_LEFT]);
+                                }
+                                if (rst[key][JV.PROP_RIGHT]) {
+                                    item[JV.PROP_RIGHT] = {};
+                                    private_CopyBorder(item[JV.PROP_RIGHT], rst[key][JV.PROP_RIGHT]);
+                                }
+                                rst[rptDftItem[JV.PROP_ID]] = item;
                             }
-                            item[rptDftItem[JV.PROP_BORDER_STYLE][j][JV.PROP_POSITION]] = borderItem;
+                        } else if (rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Bottom') > 0) {
+                            let key = rptDftItem[JV.PROP_ID].substr(0, rptDftItem[JV.PROP_ID].indexOf('_AutoHeightMerge_Bottom'));
+                            if (rst[key]) {
+                                let item = {};
+                                if (rst[key][JV.PROP_LEFT]) {
+                                    item[JV.PROP_LEFT] = {};
+                                    private_CopyBorder(item[JV.PROP_LEFT], rst[key][JV.PROP_LEFT]);
+                                }
+                                if (rst[key][JV.PROP_RIGHT]) {
+                                    item[JV.PROP_RIGHT] = {};
+                                    private_CopyBorder(item[JV.PROP_RIGHT], rst[key][JV.PROP_RIGHT]);
+                                }
+                                if (rst[key][JV.PROP_BOTTOM]) {
+                                    item[JV.PROP_BOTTOM] = {};
+                                    private_CopyBorder(item[JV.PROP_BOTTOM], rst[key][JV.PROP_BOTTOM]);
+                                }
+                                rst[rptDftItem[JV.PROP_ID]] = item;
+                            }
+                        } else {
+                            let item = {};
+                            for (let j = 0; j < rptDftItem[JV.PROP_BORDER_STYLE].length; j++) {
+                                let borderItem = {};
+                                private_CopyBorder(borderItem, rptDftItem[JV.PROP_BORDER_STYLE][j]);
+                                item[rptDftItem[JV.PROP_BORDER_STYLE][j][JV.PROP_POSITION]] = borderItem;
+                            }
+                            rst[rptDftItem[JV.PROP_ID]] = item;
                         }
-                        rst[rptDftItem[JV.PROP_ID]] = item;
                     }
                 }
             }

+ 228 - 58
modules/reports/rpt_component/jpc_flow_tab.js

@@ -14,13 +14,13 @@ let PDFKit = require('pdfkit');
 let JpcFlowTabSrv = function(){};
 //let grpPageInfo = {"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null};
 JpcFlowTabSrv.prototype.createNew = function(){
-    function private_addPageValue(ValuedIdxLst, sortedSequence, grpSequenceInfo, startRecIdx, maxRecPerPage,page_seg_map, segIdx, pageIdx, grpPageInfo, isFollow) {
-        let vIdx = [], preAmt = 0, insertedGrpAmt = 0, grp_lines = 0;
+    function private_addPageValue(ValuedIdxLst, sortedSequence, grpSequenceInfo, startRecIdx, maxRecPerPage,page_seg_map, segIdx, pageIdx, grpPageInfo, isFollow, segAutoHeightInfo, prePageLeftAutoHeightRecAmt) {
+        let vIdx = [], preAmt = 0, insertedGrpAmt = 0, grp_lines = 0, followMode = (isFollow)?JV.TYPE_FOLLOW_MODE:-1, nextPageAutoHeightRecAmt = 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]);
+                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], grpLineIdx]);
                 }
                 grpPageInfo[JV.PROP_SEG_GRP_IDX]++;
             }
@@ -28,12 +28,35 @@ JpcFlowTabSrv.prototype.createNew = function(){
             grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
             grp_lines = grpPageInfo[JV.PROP_GRP_LINES];
         }
+        let autoHeightAmt = 0;
+        let private_addAutoHeightPageValue = function (vi) {
+            let couldBreak = false, startIdx = 0;
+            let ttlValAmt = 0;
+            if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
+                ttlValAmt = segAutoHeightInfo[segIdx][startRecIdx + vi];
+            }
+            if (prePageLeftAutoHeightRecAmt > 0 && vi === 0) {
+                // startIdx = ttlValAmt - prePageLeftAutoHeightRecAmt;
+                startIdx = prePageLeftAutoHeightRecAmt;
+                // autoHeightAmt += prePageLeftAutoHeightRecAmt;
+            }
+            for (let subValIdx = startIdx; subValIdx < ttlValAmt; subValIdx++) {
+                vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT, sortedSequence[startRecIdx + vi], subValIdx, ttlValAmt]);
+                autoHeightAmt++;
+                if (autoHeightAmt >= maxRecPerPage) {
+                    nextPageAutoHeightRecAmt = (subValIdx + 1) % ttlValAmt;
+                    couldBreak = true;
+                    break;
+                }
+            }
+            return couldBreak;
+        }
         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]]);
+                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
                     //2. 然后就要push grouping记录了
                     let hasFullGrp = true;
                     for (let i = 0; i < grp_lines; i++) {
@@ -45,7 +68,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                             hasFullGrp = false;
                             break;
                         } else {
-                            vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], i]);
+                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], i]);
                         }
                     }
                     //3. 进位下一个group信息所在位置
@@ -57,22 +80,42 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         break;
                     }
                 } else {
-                    if (sortedSequence.length > startRecIdx + vi) {
-                        vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    if (segAutoHeightInfo && segAutoHeightInfo.length > 0) {
+                        if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
+                            let couldBreak = private_addAutoHeightPageValue(vi);
+                            if (couldBreak) break;
+                        } else if (vIdx.length < maxRecPerPage) {
+                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                        }
                     } else {
-                        vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                        if (sortedSequence.length > startRecIdx + vi) {
+                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                        } else {
+                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                        }
                     }
                 }
             } else {
-                if (sortedSequence.length > startRecIdx + vi) {
-                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                if (segAutoHeightInfo && segAutoHeightInfo.length > 0) {
+                    if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
+                        let couldBreak = private_addAutoHeightPageValue(vi);
+                        if (couldBreak) break;
+                    } else if (vIdx.length < maxRecPerPage) {
+                        vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                    }
                 } else {
-                    vIdx.push([(isFollow)?JV.TYPE_FOLLOW_MODE:-1, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                    nextPageAutoHeightRecAmt = 0;
+                    if (sortedSequence.length > startRecIdx + vi) {
+                        vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    } else {
+                        vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                    }
                 }
             }
         }
         page_seg_map.push([pageIdx, segIdx]);
         ValuedIdxLst.push(vIdx);
+        return nextPageAutoHeightRecAmt;
     }
     let JpcFlowTabResult = {};
     JpcFlowTabResult.initialize = function(isEx) {
@@ -213,47 +256,93 @@ JpcFlowTabSrv.prototype.createNew = function(){
             }
         }
     };
-    JpcFlowTabResult.setupAutoHeightData = function(bands, segIdx, rptTpl, dataObj, $CURRENT_RPT) {
+    JpcFlowTabResult.setupAutoHeightData = function(bands, segIdx, rptTpl, dataObj, $CURRENT_RPT, defProperties) {
         let me = this;
-        let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
-        let band = bands[rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.BAND_PROP_NAME]];
-        let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
-        let reg1 = new RegExp('\n\r','g'), reg2 = new RegExp('\r\n','g'),
-            reg3 = new RegExp('\n','g'), reg4 = new RegExp('\r','g');
-        let doc = new PDFKit({autoFirstPage: false});
-        let private_get_max_lines_of_the_record = function(theRecIdx) {
-            let rst = 1;
-            for (let loop = 0; loop < me.auto_height_fields_idx.length; loop++) {
-                let data_field = null;
-                let tab_field = me.auto_height_fields_idx[loop][1];
-                if (me.auto_height_fields_idx[loop][0] !== JV.BLANK_FIELD_INDEX) {
-                    data_field = data_details[me.auto_height_fields_idx[loop][0]];
-                }
-                if (data_field) {
-                    let value = JpcFieldHelper.getValue(data_field, theRecIdx);
-                    let area = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, 1, 1, 0, 1, 0, 1, 0, false, false);
-                    if (value !== null && value !== undefined) {
-                        value = value.replace(reg1, '|').replace(reg2, '|').replace(reg3, '|').replace(reg4, '|');
-                    } else {
-                        value = '';
+        if (me.auto_height_fields_idx.length > 0) {
+            let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+            let band = bands[rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_BAND_NAME]];
+            let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
+            let tab_fields = rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS];
+            let adHocAutoHeightStyleStr = [];
+            let reg1 = new RegExp('\n\r','g'), reg2 = new RegExp('\r\n','g'),
+                reg3 = new RegExp('\n','g'), reg4 = new RegExp('\r','g');
+            let doc = new PDFKit({autoFirstPage: false});
+            let fonts = defProperties.fonts;
+            let fontCache = {};
+            let private_get_font = function (fontKey) {
+                let rst = null;
+                if (fontCache[fontKey]) {
+                    rst = fontCache[fontKey];
+                } else {
+                    for (let i = 0; i < fonts.length; i++) {
+                        if (fonts[i][JV.PROP_ID] === fontKey) {
+                            fontCache[fontKey] = fonts[i];
+                            rst = fonts[i];
+                            break;
+                        }
                     }
-                    let values = value.split('|');
-                    if (values.length > rst) rst = values.length;
                 }
+                return rst;
             }
-            return rst;
-        };
-        if (me.auto_height_fields_idx.length > 0 && me.auto_height_info.length === segIdx) {
-            //自动行高功能,需要考虑以下情况:
-            //1. 每一Segment的需要增加行的数量
-            me.auto_height_info.push([]);
-            //rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(textNode[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, multiCols, multiColIdx, false, false);
+            let private_get_max_lines_of_the_record = function(theRecIdx) {
+                let rst = 1;
+                for (let loop = 0; loop < me.auto_height_fields_idx.length; loop++) {
+                    let data_field = null;
+                    let tab_field = me.auto_height_fields_idx[loop][1];
+                    if (me.auto_height_fields_idx[loop][0] !== JV.BLANK_FIELD_INDEX) {
+                        data_field = data_details[me.auto_height_fields_idx[loop][0]];
+                    }
+                    if (data_field) {
+                        let value = JpcFieldHelper.getValue(data_field, theRecIdx);
+                        let area = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, 1, 1, 0, 1, 0, 1, 0, false, false);
+                        if (value !== null && value !== undefined) {
+                            value = value.replace(reg1, '|').replace(reg2, '|').replace(reg3, '|').replace(reg4, '|');
+                        } else {
+                            value = '';
+                        }
+                        JpcFieldHelper.setValue(data_field, theRecIdx, value);
+                        let values = value.split('|');
+                        if (values.length > rst) rst = values.length;
+                        let font = private_get_font(tab_field[JV.PROP_FONT]);
+                        if (font) {
+                            doc.font(__dirname.slice(0, __dirname.length - 14) + '/util/pdf_base_files/Smart.ttf');
+                            doc.fontSize(parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]));
+                        } else {
+                            doc.font(__dirname.slice(0, __dirname.length - 14) + '/util/pdf_base_files/Smart.ttf');
+                            doc.fontSize(12);
+                        }
+                        for (let i = 0; i < values.length; i++) {
+                            rst = rst + JpcCommonHelper.getStringLinesInArea(area, values[i], doc) - 1;
+                        }
+                    }
+                }
+                return rst;
+            };
+            for (let tabField of tab_fields) {
+                if (adHocAutoHeightStyleStr.indexOf(tabField[JV.PROP_STYLE]) < 0) {
+                    adHocAutoHeightStyleStr.push(tabField[JV.PROP_STYLE]);
+                }
+            }
+            if (adHocAutoHeightStyleStr.length > 0) {
+                if (!(rptTpl[JV.NODE_STYLE_COLLECTION])) {
+                    rptTpl[JV.NODE_STYLE_COLLECTION] = [];
+                }
+                for (let styleStr of adHocAutoHeightStyleStr) {
+                    let adHocStyle1 = {"ID": styleStr + "_AutoHeightMerge_Top"};
+                    let adHocStyle2 = {"ID": styleStr + "_AutoHeightMerge_Middle"};
+                    let adHocStyle3 = {"ID": styleStr + "_AutoHeightMerge_Bottom"};
+                    rptTpl[JV.NODE_STYLE_COLLECTION].push(adHocStyle1);
+                    rptTpl[JV.NODE_STYLE_COLLECTION].push(adHocStyle2);
+                    rptTpl[JV.NODE_STYLE_COLLECTION].push(adHocStyle3);
+                }
+            }
+            //这里先记录下来每一Segment里的每一条record占用行的数量(普通是1行高度,超过1就表示需要调整行数了)
+            let infoArr = [];
+            me.auto_height_info.push(infoArr);
             let segArr = me.segments[segIdx];
             for (let i = 0; i < segArr.length; i++) {
-                //
+                infoArr.push(private_get_max_lines_of_the_record(segArr[i]));
             }
-            //2.
-            //rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length;
         }
     };
 
@@ -280,7 +369,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 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);
+                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx, null, false, me.auto_height_info, 0);
             }
             //目前不支持flowTabEx
         } else {
@@ -293,6 +382,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 me.multiCols = 1 * rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN];
             }
             let grpPageInfo = {};
+            let prePageLeftAutoHeightRecAmt = 0; //考虑自动行高的跨页情况
             function private_resetBandArea() {
                 JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
                 maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl, me.isEx);
@@ -300,18 +390,27 @@ JpcFlowTabSrv.prototype.createNew = function(){
             function private_addPage(segIdx, grpSeqInfo, isFollow, isMix, mixSplitPoint) {
                 private_resetBandArea();
                 me.pageStatusLst.push(pageStatus.slice(0));
-                currentRecAmt += maxRowRec;
+                currentRecAmt += maxRowRec; //在自动行高的场景下,currentRecAmt在后面还需要调整
+                let redundantRecAmt = 0;
                 pageIdx++;
+                function private_chk_handle_rec_amt(dv, isEx) {
+                    if ((dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) || (dv[1] === JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT && dv[3] === dv[4] - 1)) {
+                        if (isEx) counterRowRecEx++
+                        else counterRowRec++;
+                    } else if (dv[1] === JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT) {
+                        redundantRecAmt++;
+                    }
+                }
                 if (isMix) {
                     //先处理上半部分
-                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, mixSplitPoint,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, mixSplitPoint,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false, null, 0);
                     for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
-                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
+                        private_chk_handle_rec_amt(dv, false);
                     }
                     //再处理下半部分
-                    private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec - mixSplitPoint, me.page_seg_map, segIdx, pageIdx, null, true);
+                    private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec - mixSplitPoint, me.page_seg_map, segIdx, pageIdx, null, true, null, 0);
                     for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
-                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRecEx++;
+                        private_chk_handle_rec_amt(dv, true);
                     }
                     //合并到一页中
                     me.page_seg_map.splice(me.page_seg_map.length - 1, 1);
@@ -321,16 +420,17 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                     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);
+                    private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec, me.page_seg_map, segIdx, pageIdx, null, true, null, 0);
                     for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
-                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRecEx++;
+                        private_chk_handle_rec_amt(dv, true);
                     }
                 } else {
-                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
+                    prePageLeftAutoHeightRecAmt = private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false, me.auto_height_info, prePageLeftAutoHeightRecAmt);
                     for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
-                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
+                        private_chk_handle_rec_amt(dv, false);
                     }
                 }
+                currentRecAmt -= redundantRecAmt; //在自动行高调整场景下,需要减去冗余的数量
             }
             for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
                 let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
@@ -345,12 +445,22 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 grpPageInfo[JV.PROP_GRP_LINES] = me.group_lines_amt;
                 pageStatus[JV.STATUS_SEGMENT_START] = true;
                 private_resetBandArea();
+                me.setupAutoHeightData(bands, segIdx, rptTpl, dataObj, $CURRENT_RPT, defProperties);
                 let threshold = 0;
                 currentRecAmt = 0;
                 counterRowRec = 0;
                 counterRowRecEx = 0;
                 let ttlSegRecAmtNormal = me.segments[segIdx].length + grpRecAmt; //正常的segment下的数据长度累计(含grouping data)
                 let ttlSegRecAmt = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt); //所有的segment下的数据长度累计(包括ex部分)
+                let adHocAutoHeightAmt = 0;
+                if (me.auto_height_fields_idx.length > 0) {
+                    for (let loop = 0; loop < me.auto_height_info[segIdx].length; loop++) {
+                        adHocAutoHeightAmt += (me.auto_height_info[segIdx][loop] - 1);
+                    }
+                    ttlSegRecAmtNormal += adHocAutoHeightAmt;
+                    ttlSegRecAmt += adHocAutoHeightAmt;
+                }
+                //自动行高调整暂时不支持多流水合并方式(后期需要再加)
                 while (true) {
                     if (currentRecAmt > 0) pageStatus[JV.STATUS_SEGMENT_START] = false;
                     if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
@@ -404,16 +514,35 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         }
                     } else {
                         //普通流水数据情况
-                        if (currentRecAmt + maxRowRec >= ttlSegRecAmt) {
+                        let adHocAutoHeightAmt = 0;
+                        let recAmtForAdHocAutoHeight = 0;
+                        if (me.auto_height_fields_idx.length > 0) {
+                            adHocAutoHeightAmt -= prePageLeftAutoHeightRecAmt;
+                            //for (let loop = currentRecAmt; loop < me.auto_height_info[segIdx].length; loop++) {
+                            for (let loop = currentRecAmt; loop < currentRecAmt + maxRowRec; loop++) {
+                                if (me.auto_height_info[segIdx].length > loop) {
+                                    adHocAutoHeightAmt += (me.auto_height_info[segIdx][loop] - 1);
+                                    recAmtForAdHocAutoHeight++;
+                                } else {
+                                    break;
+                                }
+                            }
+                        }
+                        if ((currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight + maxRowRec >= ttlSegRecAmt)
+                             && (recAmtForAdHocAutoHeight + adHocAutoHeightAmt < 2 * maxRowRec) ) {
+                            //备注: 理论上自动行高是没有上限的,有可能正常一页的数据可以拓展到3页及以上,在此极端情况下,必须做一些限制判断,否则会出现缺页情况。
                             pageStatus[JV.STATUS_SEGMENT_END] = true;
                             pageStatus[JV.STATUS_REPORT_END] = true;
                             private_resetBandArea();
-                            let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt, maxRowRec, me.isEx);
+                            let hasAdHocRow = ((recAmtForAdHocAutoHeight + adHocAutoHeightAmt > maxRowRec) ||
+                                              !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight, maxRowRec, me.isEx));
                             if (hasAdHocRow) {
                                 //add page info(pre segment end)
                                 pageStatus[JV.STATUS_SEGMENT_END] = false;
                                 pageStatus[JV.STATUS_REPORT_END] = false;
                                 private_addPage(segIdx, grpSeqInfo, false, false, -1);
+                                pageStatus[JV.STATUS_REPORT_START] = false;
+                                pageStatus[JV.STATUS_SEGMENT_START] = false;
                             }
                             //add page info
                             pageStatus[JV.STATUS_SEGMENT_END] = true;
@@ -424,7 +553,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         }
                     }
                     //检测是否可退出
-                    if ((currentRecAmt >= ttlSegRecAmt) && (pageIdx % me.multiCols === 0)) {
+                    if ((currentRecAmt + adHocAutoHeightAmt >= ttlSegRecAmt) && (pageIdx % me.multiCols === 0)) {
                         //备注:这里必须得考虑多栏的情况,否则会造成pageStatus出界的问题
                         break;
                     }
@@ -436,6 +565,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                 }
             }
+            console.log(me.auto_height_info);
             // console.log(me.dispValueIdxLst);
             rst = Math.ceil(pageIdx / me.multiCols);
         }
@@ -553,6 +683,23 @@ JpcFlowTabSrv.prototype.createNew = function(){
                             //测试中
                             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));
+                            } else if (contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT) {
+                                //vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT, sortedSequence[startRecIdx + vi]], subValIdx, ttlValAmt);
+                                if (contentValuesIdx[rowIdx][4] === 1) {
+                                    //等效于普通输出
+                                    rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx][2], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                                } else {
+                                    //这里需要做些style调整(中间的那些横杠线去掉)
+                                    let cellItem = me.outputAutoHeightTabField(band, tab_field, data_field, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx);
+                                    rst.push(cellItem);
+                                    if (contentValuesIdx[rowIdx][3] === 0 || rowIdx === 0) {
+                                        cellItem[JV.PROP_STYLE] = cellItem[JV.PROP_STYLE] + '_AutoHeightMerge_Top';
+                                    } else if (contentValuesIdx[rowIdx][3] === contentValuesIdx[rowIdx][4] - 1) {
+                                        cellItem[JV.PROP_STYLE] = cellItem[JV.PROP_STYLE] + '_AutoHeightMerge_Bottom';
+                                    } else {
+                                        cellItem[JV.PROP_STYLE] = cellItem[JV.PROP_STYLE] + '_AutoHeightMerge_Middle';
+                                    }
+                                }
                             }
                         }
                     }
@@ -684,6 +831,29 @@ 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.outputAutoHeightTabField = function (band, tab_field, data_field, contentValInfo, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx) {
+        let me = this;
+        let showText = JpcFieldHelper.getValue(data_field, contentValInfo[2]);
+        if (tab_field[JV.PROP_IS_AUTO_HEIGHT]) {
+            let textArr = [];
+            if (showText) {
+                textArr = textArr.concat(showText.split('|'));
+            }
+            if (contentValInfo[3] < textArr.length && contentValInfo[3] >= 0) {
+                showText = textArr[contentValInfo[3]];
+            } else {
+                showText = '';
+            }
+            let rst = JpcCommonOutputHelper.createCommonOutput(tab_field, showText, controls);
+            rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx, true, false);
+            return rst;
+        } else {
+            if (contentValInfo[3] > 0) showText = '';
+            let rst = JpcCommonOutputHelper.createCommonOutput(tab_field, showText, controls);
+            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]) {

+ 9 - 0
public/web/rpt_value_define.js

@@ -196,6 +196,14 @@ const JV = {
     PROP_DASH_STYLE: "DashStyle",
     PROP_COLOR: "Color",
     FONT_PROPS: ["Name", "FontHeight", "FontColor", "FontBold", "FontItalic", "FontUnderline", "FontStrikeOut", "FontAngle"],
+    FONT_PROP_IDX_NAME: 0,
+    FONT_PROP_IDX_HEIGHT: 1,
+    FONT_PROP_IDX_COLOR: 2,
+    FONT_PROP_IDX_BOLD: 3,
+    FONT_PROP_IDX_ITALIC: 4,
+    FONT_PROP_IDX_UNDERLINE: 5,
+    FONT_PROP_IDX_STRIKEOUT: 6,
+    FONT_PROP_IDX_ANGLE: 7,
 
     STATUS_NORMAL: 0,
     STATUS_REPORT_START: 1,
@@ -253,6 +261,7 @@ const JV = {
 
     DISPLAY_VAL_TYPE_NORMAL: 0,
     DISPLAY_VAL_TYPE_GROUP: 1,
+    DISPLAY_VAL_TYPE_AUTO_HEIGHT: 2,
 
     TYPE_FOLLOW_MODE: 1,
 

+ 1 - 1
test/unit/reports/test_tpl_09.js

@@ -138,7 +138,7 @@ test('测试 - 测试模板啦: ', function (t) {
                     let maxPages = printCom.totalPages;
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                     if (pageRst) {
-                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/rptPageResult.jsp");
+                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/rptPageResult.jsp");
                     } else {
                         console.log("oh! no pages were created!");
                     }