Przeglądaj źródła

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

zhongzewei 6 lat temu
rodzic
commit
947486d4b8

+ 11 - 6
web/maintain/report/html/rpt_tpl_detail.html

@@ -12,6 +12,9 @@
         <li class="nav-item">
             <a class="nav-link p-1" data-toggle="tab" href="#rpttplfieldlocation" role="tab" onclick="dataInfoMapTreeOprObj.iniDataMap();">指标摆放</a>
         </li>
+        <li class="nav-item" style="display: none;">
+            <a class="nav-link p-1" data-toggle="tab" href="#rptvisual" role="tab" onclick="setTimeout(function(){visualJumbo.iniSpreadJs(); visualJumbo.setupTpl()}, 50)">可视化</a>
+        </li>
         <li class="nav-item">
             <a class="nav-link p-1" data-toggle="tab" href="#rpt_tpl_pre_handle_tab" role="tab">数据预处理</a>
         </li>
@@ -28,17 +31,19 @@
     </ul>
     <div class="tab-content">
         <!--模板信息-->
-        <%include ./rpt_tpl_detail_info.html %>
+        <%include ./rpt_tpl_dtl_info.html %>
         <!--模板布局-->
-        <%include ./rpt_tpl_detail_bands.html %>
+        <%include ./rpt_tpl_dtl_bands.html %>
         <!--指标映射-->
-        <%include ./rpt_tpl_detail_mapping_fields.html %>
+        <%include ./rpt_tpl_dtl_map_fields.html %>
         <!--指标摆放-->
-        <%include ./rpt_tpl_detail_field_location.html %>
+        <%include ./rpt_tpl_dtl_field_loc.html %>
+        <!--报表可视化-->
+        <%include ./rpt_tpl_vis_jumbo.html %>
         <!--报表数据预处理-->
-        <%include ./rpt_tpl_detail_pre_handle.html %>
+        <%include ./rpt_tpl_dtl_pre_hdl.html %>
         <!--计算式-->
-        <%include ./rpt_tpl_detail_calculation.html %>
+        <%include ./rpt_tpl_dtl_calc.html %>
         <!--java script 对象-->
         <%include ./rpt_tpl_script_text.html %>
         <!--预览-->

web/maintain/report/html/rpt_tpl_detail_bands.html → web/maintain/report/html/rpt_tpl_dtl_bands.html


+ 0 - 2
web/maintain/report/html/rpt_tpl_detail_calculation.html

@@ -9,11 +9,9 @@
         <div class="p-3" id="exprDetail">
             <div class="row">
                 <div class="form-group col-md-5">
-                    <label></label>
                     <select class="form-control" id="exprTemplatesSelect"></select>
                 </div>
                 <div class="form-group col-md-1">
-                    <label></label>
                     <button class="btn btn-primary" id="expr_tpl_select_btn" onclick="calculationTreeOprObj.setTemplateExpression(this)">套用</button>
                 </div>
             </div>

+ 3 - 3
web/maintain/report/html/rpt_tpl_detail_field_location.html

@@ -164,13 +164,13 @@
                 </div>
             </div>
             <div class="row" id="element_visual_div1" style="display: none">
-                <%include ./rpt_tpl_detail_virtual_column.html %>
+                <%include ./rpt_tpl_dtl_vis_column.html %>
             </div>
             <div class="row" id="element_visual_div2" style="display: none">
-                <%include ./rpt_tpl_detail_virtual_summary.html %>
+                <%include ./rpt_tpl_dtl_vis_sum.html %>
             </div>
             <div class="row" id="element_visual_div3" style="display: none">
-                <%include ./rpt_tpl_detail_virtual_discrete.html %>
+                <%include ./rpt_tpl_dtl_vis_discrete.html %>
             </div>
         </div>
     </div>

web/maintain/report/html/rpt_tpl_detail_info.html → web/maintain/report/html/rpt_tpl_dtl_info.html


web/maintain/report/html/rpt_tpl_detail_mapping_fields.html → web/maintain/report/html/rpt_tpl_dtl_map_fields.html


+ 5 - 5
web/maintain/report/html/rpt_tpl_detail_pre_handle.html

@@ -24,15 +24,15 @@
                 </div>
             </div>
             <!--排序处理-->
-            <%include ./rpt_tpl_detail_pre_handle_sort.html %>
+            <%include ./rpt_tpl_dtl_pre_hdl_sort.html %>
             <!--过滤处理-->
-            <%include ./rpt_tpl_detail_pre_handle_filter.html %>
+            <%include ./rpt_tpl_dtl_pre_hdl_filter.html %>
             <!--合计处理-->
-            <%include ./rpt_tpl_detail_pre_handle_summary.html %>
+            <%include ./rpt_tpl_dtl_pre_hdl_sum.html %>
             <!--调整处理-->
-            <%include ./rpt_tpl_detail_pre_handle_adjust.html %>
+            <%include ./rpt_tpl_dtl_pre_hdl_adjust.html %>
             <!--dummy数据处理-->
-            <%include ./rpt_tpl_detail_pre_handle_adddummy.html %>
+            <%include ./rpt_tpl_dtl_pre_hdl_addDummy.html %>
         </div>
     </div>
 </div>

web/maintain/report/html/rpt_tpl_detail_pre_handle_adddummy.html → web/maintain/report/html/rpt_tpl_dtl_pre_hdl_addDummy.html


web/maintain/report/html/rpt_tpl_detail_pre_handle_adjust.html → web/maintain/report/html/rpt_tpl_dtl_pre_hdl_adjust.html


web/maintain/report/html/rpt_tpl_detail_pre_handle_filter.html → web/maintain/report/html/rpt_tpl_dtl_pre_hdl_filter.html


web/maintain/report/html/rpt_tpl_detail_pre_handle_sort.html → web/maintain/report/html/rpt_tpl_dtl_pre_hdl_sort.html


web/maintain/report/html/rpt_tpl_detail_pre_handle_summary.html → web/maintain/report/html/rpt_tpl_dtl_pre_hdl_sum.html


web/maintain/report/html/rpt_tpl_detail_virtual_column.html → web/maintain/report/html/rpt_tpl_dtl_vis_column.html


web/maintain/report/html/rpt_tpl_detail_virtual_discrete.html → web/maintain/report/html/rpt_tpl_dtl_vis_discrete.html


web/maintain/report/html/rpt_tpl_detail_virtual_summary.html → web/maintain/report/html/rpt_tpl_dtl_vis_sum.html


+ 4 - 3
web/maintain/report/html/rpt_tpl_main.html

@@ -67,7 +67,7 @@
                         <div class="container-fluid">
                             <div class="row">
                                 <!-- 报表设置 -->
-                                <%include ./rpt_tpl_detail.html %>
+                                <%include ./rpt_tpl_dtl.html %>
                             </div>
                         </div>
                     </div>
@@ -92,9 +92,10 @@
     <script src="/web/maintain/report/js/rpt_tpl_calculation.js"></script>
     <script src="/web/maintain/report/js/rpt_tpl_helper.js"></script>
     <script src="/web/maintain/report/js/rpt_tpl_data_map.js"></script>
-    <script src="/web/maintain/report/js/rpt_tpl_virtual_common.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_vis_common.js"></script>
     <script src="/web/maintain/report/js/rpt_tpl_field_location.js"></script>
-    <script src="/web/maintain/report/js/rpt_tpl_virtual_summary.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_vis_sum.js"></script>
+    <script src="/web/maintain/report/js/rpt_tpl_vis_jumbo.js"></script>
     <script src="/web/maintain/report/js/rpt_tpl_pre_handle.js"></script>
     <script src="/web/maintain/report/js/cfg_const.js"></script>
     <script src="/web/maintain/report/js/rpt_tpl_preview_util.js"></script>

+ 25 - 0
web/maintain/report/html/rpt_tpl_vis_jumbo.html

@@ -0,0 +1,25 @@
+<div class="tab-pane" id="rptvisual" role="tabpanel">
+    <div class="main-data">
+        <div class="p-3">
+            <button class="btn btn-primary btn-sm" onclick="">应用</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.restoreTpl()">恢复</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.insertColumn()">插入列</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.addColumn()">新增列</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.deleteColumn()">删除列</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.addRow()">新增行</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.deleteRow()">删除行</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.mergeCells()">合并单元格</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.disMergeCells()">拆解单元格</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.fitTheWidth(1.0)">X 1.0</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.fitTheWidth(1.5)">X 1.5</button>
+            <button class="btn btn-primary btn-sm" onclick="visualJumbo.fitTheWidth(2.0)">X 2.0</button>
+
+            <div class="row" id="ele_visual_div_cfg1">
+            </div>
+            <div class="row" id="ele_visual_div_cfg2">
+            </div>
+            <div class="row" style="height: 360px" id="ele_visual_div_main3">
+            </div>
+        </div>
+    </div>
+</div>

+ 15 - 15
web/maintain/report/js/rpt_tpl_field_location.js

@@ -36,7 +36,7 @@ let fieldLocationOprObj = {
     setupColumn: function (rptTpl, columnParentNode, contentParentNode) {
         let me = this, yPos = [], xPos = [];
         me.columnFieldCtrls = [];
-        let selectedBand = virtualCommonOprObj.getBandEx(columnParentNode[JV.PROP_BAND_NAME], rptTpl);
+        let selectedBand = visualCommonOprObj.getBandEx(columnParentNode[JV.PROP_BAND_NAME], rptTpl);
         if (selectedBand !== null) {
             let sheet = me.columnWorkBook.getActiveSheet();
             sheet.suspendPaint();
@@ -60,10 +60,10 @@ let fieldLocationOprObj = {
             }
             if (columnParentNode.items && columnParentNode.items.length > 0) {
                 for (let itemNode of columnParentNode.items) {
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW, xPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH, yPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH, yPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW, xPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH, yPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH, yPos);
                 }
 
                 sheet.setRowCount(yPos.length, GC.Spread.Sheets.SheetArea.viewport);
@@ -73,7 +73,7 @@ let fieldLocationOprObj = {
                 }
                 // sheet.clear();
                 let cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
-                let selectableFields = virtualCommonOprObj.getSelectedFields(rptTpl);
+                let selectableFields = visualCommonOprObj.getSelectedFields(rptTpl);
                 cellType.items(selectableFields);
                 //设置 最后一行为 行数据选择combobox
                 let iSelectedRow = sheet.getRowCount() - 1;
@@ -90,7 +90,7 @@ let fieldLocationOprObj = {
                     return (y1 - y2);
                 });
                 for (let contentItemNode of contentParentNode.items) {
-                    let idxCol = xPos.indexOf(virtualCommonOprObj.getActPosEx(contentItemNode, contentItemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos));
+                    let idxCol = xPos.indexOf(visualCommonOprObj.getActPosEx(contentItemNode, contentItemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos));
                     sheet.getCell(iSelectedRow, idxCol).value(contentItemNode[JV.PROP_NAME]);
                     me.private_merge_ctrl(rptTpl, idxCol, contentItemNode, null);
                 }
@@ -102,14 +102,14 @@ let fieldLocationOprObj = {
                     sheet.getRange(idx - 1, -1, 1, -1).backColor(undefined);
                 }
                 for (let itemNode of columnParentNode.items) {
-                    virtualCommonOprObj.addSpan(itemNode, sheet, bandW, bandH, xPos, yPos, GC.Spread.Sheets.SheetArea.viewport);
+                    visualCommonOprObj.addSpan(itemNode, sheet, bandW, bandH, xPos, yPos, GC.Spread.Sheets.SheetArea.viewport);
                 }
             } else {
                 sheet.setRowCount(2);
                 sheet.setColumnCount(1);
                 me.columnFieldCtrls.push(me.private_create_dft_ctrl());
                 let cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
-                let selectableFields = virtualCommonOprObj.getSelectedFields(rptTpl);
+                let selectableFields = visualCommonOprObj.getSelectedFields(rptTpl);
                 cellType.items(selectableFields);
                 //设置 最后一行为 行数据选择combobox
                 let iSelectedRow = sheet.getRowCount() - 1;
@@ -141,7 +141,7 @@ let fieldLocationOprObj = {
         sheet.addRows(sheet.getRowCount() - 1, 1);
         let rc = sheet.getRowCount();
         for (let cc = 0; cc < sheet.getColumnCount(); cc++) {
-            virtualCommonOprObj.setupCellDft(sheet.getCell(rc - 2, cc));
+            visualCommonOprObj.setupCellDft(sheet.getCell(rc - 2, cc));
         }
     },
     deleteRow: function () {
@@ -164,14 +164,14 @@ let fieldLocationOprObj = {
         sheet.suspendPaint();
         sheet.addColumns(sheet.getColumnCount(), 1);
         let cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
-        let selectableFields = virtualCommonOprObj.getSelectedFields(rptTpl);
+        let selectableFields = visualCommonOprObj.getSelectedFields(rptTpl);
         cellType.items(selectableFields);
         //设置 最后一行为 行数据选择combobox
         // sheet.getRange(sheet.getRowCount() - 1, -1, 1, -1).locked(true);
         let colIdx = sheet.getColumnCount() - 1;
         sheet.getCell(sheet.getRowCount() - 1, colIdx).cellType(cellType);
         for (let iRow = 0; iRow < sheet.getRowCount() - 1; iRow++) {
-            virtualCommonOprObj.setupCellDft(sheet.getCell(iRow, colIdx));
+            visualCommonOprObj.setupCellDft(sheet.getCell(iRow, colIdx));
         }
         //
         me.columnFieldCtrls.push(me.private_create_dft_ctrl());
@@ -216,7 +216,7 @@ let fieldLocationOprObj = {
             {
                 for (let j = 0; j < selectedRanges.length; j++) {
                     if (spans[i].row >= selectedRanges[j].row && spans[i].col >= selectedRanges[j].col &&
-                        spans[i].row <= selectedRanges[j].row + selectedRanges[j].rowCount && spans[i].col <= selectedRanges[j].col + selectedRanges[j].colCount) {
+                        spans[i].row < selectedRanges[j].row + selectedRanges[j].rowCount && spans[i].col < selectedRanges[j].col + selectedRanges[j].colCount) {
                         selectedSpans.push(spans[i]);
                     }
                 }
@@ -492,7 +492,7 @@ let fieldLocationOprObj = {
             let sheet = me.columnWorkBook.getActiveSheet();
             if (sheet.getRowCount() > 1 && sheet.getColumnCount() > 0) {
                 let texts = [], colWidthArr = [], rowHeightArr = [];
-                virtualCommonOprObj.collectSheetTxt(sheet, texts, 1, colWidthArr, rowHeightArr);
+                visualCommonOprObj.collectSheetTxt(sheet, texts, 1, colWidthArr, rowHeightArr);
                 let nodes = [];
                 //表栏重置
                 //0. 先清除原先所有的column text
@@ -500,7 +500,7 @@ let fieldLocationOprObj = {
                 //1. 需要重新设置columnBand的高度
                 //2. 重新生成text节点
                 for (let text of texts) {
-                    let node = virtualCommonOprObj.createTxtNode(text, me.columnParentNode, colWidthArr, rowHeightArr);
+                    let node = visualCommonOprObj.createTxtNode(text, me.columnParentNode, colWidthArr, rowHeightArr);
                     nodes.push(node);
                 }
                 dataInfoMapTreeOprObj.treeObj.addNodes(me.columnParentNode, -1, nodes, true);

+ 0 - 263
web/maintain/report/js/rpt_tpl_virtual_common.js

@@ -1,263 +0,0 @@
-/**
- * Created by Tony on 2018/9/4.
- */
-
-let virtualCommonOprObj = {
-    getActPos: function (textNode, caclStr, typeStr, baseMea) {
-        let rst = 0;
-        if (caclStr === JV.CAL_TYPE[0]) {
-            //percentage
-            rst = Math.round(baseMea * textNode[JV.PROP_AREA][typeStr] / 100);
-        } else {
-            //abstract
-            rst = Math.round(textNode[JV.PROP_AREA][typeStr] / 2.54 * 96);
-        }
-        return rst;
-    },
-    getActPosEx: function (textNode, caclObj, typeStr, baseMea) {
-        let me = this;
-        if (typeof caclObj === 'string') {
-            return me.getActPos(textNode, caclObj, typeStr, baseMea);
-        } else {
-            return me.getActPos(textNode, caclObj[typeStr], typeStr, baseMea);
-        }
-    },
-    pushPos: function (textNode, caclObj, typeStr, baseMea, posArr) {
-        let me = this, pos = me.getActPosEx(textNode, caclObj, typeStr, baseMea);
-        if (posArr.indexOf(pos) < 0) posArr.push(pos);
-    },
-    getBandEx: function (bandName, rptTpl) {
-        let me = this, rst;
-        for (let band of rptTpl[JV.NODE_BAND_COLLECTION]) {
-            rst = me.getBand(bandName, band);
-            if (rst !== null) {
-                break;
-            }
-        }
-        return rst;
-    },
-    getBand: function (bandName, parentBand) {
-        let me = this, rst = null;
-        if (parentBand[JV.PROP_NAME] === bandName) {
-            rst = parentBand;
-        } else {
-            if (parentBand[JV.BAND_PROP_SUB_BANDS] && parentBand[JV.BAND_PROP_SUB_BANDS].length > 0) {
-                for (let subBand of parentBand[JV.BAND_PROP_SUB_BANDS]) {
-                    rst = me.getBand(bandName, subBand);
-                    if (rst !== null) {
-                        break;
-                    }
-                }
-            }
-        }
-        return rst;
-    },
-    checkInSpan: function (spans, row, col) {
-        let rst = false;
-        for (let span of spans) {
-            if (span.row <= row && row < (span.row + span.rowCount) && span.col <= col && col < (span.col + span.colCount)) {
-                rst = true;
-                break;
-            }
-        }
-        return rst;
-    },
-    setupHeightWidth: function (dest, text, colWidthArr, rowHeightArr) {
-        let width = colWidthArr[colWidthArr.length - 1], height = rowHeightArr[rowHeightArr.length - 1];
-        dest[JV.PROP_AREA][JV.PROP_RIGHT] = (colWidthArr[text.col + text.colCount - 1] / width * 100).toFixed(2);
-        if (text.col > 0) {
-            dest[JV.PROP_AREA][JV.PROP_LEFT] = (colWidthArr[text.col - 1] / width * 100).toFixed(2);
-        } else {
-            dest[JV.PROP_AREA][JV.PROP_LEFT] = 0;
-        }
-        dest[JV.PROP_AREA][JV.PROP_BOTTOM] = (rowHeightArr[text.row + text.rowCount - 1] / height * 100).toFixed(2);
-        if (text.row > 0) {
-            dest[JV.PROP_AREA][JV.PROP_TOP] = (rowHeightArr[text.row - 1] / height * 100).toFixed(2);
-        } else {
-            dest[JV.PROP_AREA][JV.PROP_TOP] = 0;
-        }
-    },
-    createTxtNode: function (text, parentNode, colWidthArr, rowHeightArr) {
-        let me = this, rst = dataInfoMapTreeOprObj.getDummyTextNode(parentNode);
-        me.setupHeightWidth(rst, text, colWidthArr, rowHeightArr);
-        if (stringUtil.isEmptyString(text[`text`])) {
-            rst[JV.PROP_NAME] = '';
-        } else {
-            rst[JV.PROP_NAME] = stringUtil.replaceAll(stringUtil.replaceAll(text[`text`].toString(), '\n', '|'), '\r', '');
-        }
-        rst[JV.PROP_LABEL] = rst[JV.PROP_NAME];
-        return rst;
-    },
-    collectSheetTxt: function (sheet, texts, reserveRows, colWidthArr, rowHeightArr) {
-        let spans= sheet.getSpans();
-        let private_build_pre_text = function (row, col, rowCount, colCount) {
-            let cell = sheet.getCell(row, col);
-            let textValue = sheet.getValue(row, col);
-            if (textValue && cell.cellType().typeName === '7') {
-                textValue = `{` + textValue + `}`;
-            }
-            texts.push({"row": row, "col": col, "rowCount": rowCount, "colCount": colCount, "text": textValue});
-        };
-        for (let span of spans) {
-            private_build_pre_text(span.row, span.col, span.rowCount, span.colCount);
-        }
-        for (let iRow = 0; iRow < sheet.getRowCount() - reserveRows; iRow++) {
-            rowHeightArr.push(sheet.getRowHeight(iRow));
-            if (iRow > 0) {
-                rowHeightArr[iRow] = rowHeightArr[iRow] + rowHeightArr[iRow - 1];
-            }
-            for (let jCol = 0; jCol < sheet.getColumnCount(); jCol++) {
-                if (iRow === 0) {
-                    colWidthArr.push(sheet.getColumnWidth(jCol));
-                    if (jCol > 0) {
-                        colWidthArr[jCol] = colWidthArr[jCol] + colWidthArr[jCol - 1];
-                    }
-                }
-                if (!virtualCommonOprObj.checkInSpan(spans, iRow, jCol)) {
-                    private_build_pre_text(iRow, jCol, 1, 1);
-                }
-            }
-        }
-        texts.sort(function(t1, t2){
-            if (t1.col === t2.col) {
-                return t1.row - t2.row;
-            } else {
-                return t1.col - t2.col;
-            }
-        });
-    },
-    addSpan: function (itemNode, sheet, bandW, bandH, xPos, yPos, sheetAreaType) {
-        let me = this;
-        let idx1 = xPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos));
-        let idx2 = xPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW, xPos));
-        let idy1 = yPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH, yPos));
-        let idy2 = yPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH, yPos));
-        if (idx2 - idx1 > 1 || idy2 - idy1 > 1) {
-            sheet.addSpan(idy1, idx1, idy2 - idy1, idx2 - idx1, sheetAreaType);
-        }
-        let cell = sheet.getCell(idy1, idx1, sheetAreaType);
-        if (sheetAreaType === GC.Spread.Sheets.SheetArea.viewport) {
-            if (itemNode.FieldID) {
-                me.changeCellType(cell, 'field');
-            } else {
-                me.changeCellType(cell, 'text');
-            }
-        }
-        me.setupCell(cell, itemNode);
-    },
-    changeBandHeight: function (bandName, newHeight) {
-        let nodes = bandTreeOprObj.treeObj.getNodes()[0][JV.BAND_PROP_SUB_BANDS];
-        let private_set_band_height = function(bNode) {
-            let rst = false;
-            if (bNode[JV.PROP_NAME] === bandName) {
-                bNode[JV.BAND_PROP_HEIGHT] = newHeight;
-                rst = true;
-            } else if (bNode[JV.BAND_PROP_SUB_BANDS] && bNode[JV.BAND_PROP_SUB_BANDS].length > 0){
-                for (let subNode of bNode[JV.BAND_PROP_SUB_BANDS]) {
-                    rst = private_set_band_height(subNode);
-                    if (rst) break;
-                }
-            }
-            return rst;
-        };
-        for (let bandNode of nodes) {
-            if (private_set_band_height(bandNode)) break;
-        }
-    },
-    changeCellType: function (cell, newType) {
-        switch (newType) {
-            case `field`:
-                let rptTpl = (zTreeOprObj.currentNode)?zTreeOprObj.currentNode.rptTpl:null;
-                let cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
-                let selectableFields = virtualCommonOprObj.getSelectedFields(rptTpl);
-                cellType.items(selectableFields);
-                cell.cellType(cellType);
-                cell.backColor("LightCyan");
-                break;
-            case `text`:
-            default:
-                cell.cellType(new GC.Spread.Sheets.CellTypes.Text());
-                cell.value(``);
-                cell.backColor(undefined);
-                break;
-        }
-    },
-    setupCell: function (cell, itemNode) {
-        let me = this;
-        me.private_setCellFont(cell, itemNode);
-        me.private_setCellControl(cell, itemNode);
-        me.private_setCellStyle(cell, itemNode);
-        let value = itemNode[JV.PROP_NAME];
-        if (itemNode[JV.PROP_NAME].indexOf(`|`) >= 0) {
-            value = itemNode[JV.PROP_NAME].split('|').join('\n');
-        }
-        cell.wordWrap(true);
-        cell.value(value);
-    },
-    private_setCellControl: function (cell, textNode) {
-        let ctrl = null;
-        if (typeof textNode[JV.PROP_CONTROL] === 'string') {
-            let idx = rpt_tpl_cfg_helper.reportCfg.controlArr.indexOf(textNode[JV.PROP_CONTROL]);
-            ctrl = rpt_tpl_cfg_helper.reportCfg.ctrls[idx];
-        } else {
-            ctrl = textNode[JV.PROP_CONTROL];
-        }
-        if (ctrl) {
-            switch (ctrl.Horizon) {
-                case `center`:
-                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
-                    break;
-                case `right`:
-                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
-                    break;
-                default:
-                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
-                    break;
-            }
-            switch (ctrl.Vertical) {
-                case `center`:
-                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.center);
-                    break;
-                case `bottom`:
-                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
-                    break;
-                default:
-                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.top);
-                    break;
-            }
-        }
-    },
-    private_setCellStyle: function (cell, textNode) {
-        //默认是normal,暂时不管
-    },
-    private_setCellFont: function (cell, textNode) {
-        for (let font of rpt_tpl_cfg_helper.reportCfg.fonts) {
-            if (font.ID === textNode[JV.PROP_FONT]) {
-                cell.font(Math.round(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]] * 3 / 4) + 'pt ' + font[JV.FONT_PROPS[JV.FONT_PROP_IDX_NAME]]);
-                break;
-            }
-        }
-    },
-    getSelectedFields: function (rptTpl) {
-        let rst = [];
-        if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS] !== undefined && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS].length > 0) {
-            for (let field of rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
-                rst.push(field[JV.PROP_NAME]);
-            }
-        }
-        if (rptTpl[JV.NODE_NO_MAPPING_FIELDS] !== undefined && rptTpl[JV.NODE_NO_MAPPING_FIELDS].length > 0) {
-            for (let field of rptTpl[JV.NODE_NO_MAPPING_FIELDS]) {
-                rst.push(field[JV.PROP_NAME]);
-            }
-        }
-        return rst;
-    },
-    setupCellDft: function (cell) {
-        cell.font(`9pt 宋体`);
-        cell.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
-        cell.vAlign(GC.Spread.Sheets.VerticalAlign.center);
-        cell.wordWrap(true);
-        cell.cellType(new GC.Spread.Sheets.CellTypes.Text());
-        cell.value(``);
-    }
-};

+ 599 - 0
web/maintain/report/js/rpt_tpl_vis_common.js

@@ -0,0 +1,599 @@
+/**
+ * Created by Tony on 2018/9/4.
+ */
+
+const BG_COLORS = ['#BFEFFF', '#C1FFC1', '#F5F5DC', '#B9D3EE', '#C1FFC1', '#EEE0E5', '#B4EEB4', '#CAE1FF', '#EED2EE', '#AEEEEE', '#76EEC6', '#CD8C95'],
+    unitFactor = 1.0 * 96 / 2.54;
+let visualCommonOprObj = {
+    getActPos: function (textNode, caclStr, typeStr, baseMea) {
+        let rst = 0;
+        if (caclStr === JV.CAL_TYPE[0]) {
+            //percentage
+            rst = Math.round(baseMea * textNode[JV.PROP_AREA][typeStr] / 100);
+        } else {
+            //abstract
+            rst = Math.round(textNode[JV.PROP_AREA][typeStr] / 2.54 * 96);
+        }
+        return rst;
+    },
+    getActPosEx: function (textNode, caclObj, typeStr, baseMea) {
+        let me = this;
+        if (typeof caclObj === 'string') {
+            return me.getActPos(textNode, caclObj, typeStr, baseMea);
+        } else {
+            return me.getActPos(textNode, caclObj[typeStr], typeStr, baseMea);
+        }
+    },
+    pushPos: function (textNode, caclObj, typeStr, baseMea, posArr) {
+        let me = this, pos = me.getActPosEx(textNode, caclObj, typeStr, baseMea);
+        if (posArr.indexOf(pos) < 0) posArr.push(pos);
+    },
+    getBandEx: function (bandName, rptTpl) {
+        let me = this, rst;
+        for (let band of rptTpl[JV.NODE_BAND_COLLECTION]) {
+            rst = me.getBand(bandName, band);
+            if (rst !== null) {
+                break;
+            }
+        }
+        return rst;
+    },
+    getBand: function (bandName, parentBand) {
+        let me = this, rst = null;
+        if (parentBand[JV.PROP_NAME] === bandName) {
+            rst = parentBand;
+        } else {
+            if (parentBand[JV.BAND_PROP_SUB_BANDS] && parentBand[JV.BAND_PROP_SUB_BANDS].length > 0) {
+                for (let subBand of parentBand[JV.BAND_PROP_SUB_BANDS]) {
+                    rst = me.getBand(bandName, subBand);
+                    if (rst !== null) {
+                        break;
+                    }
+                }
+            }
+        }
+        return rst;
+    },
+    checkInSpan: function (spans, row, col) {
+        let rst = false;
+        for (let span of spans) {
+            if (span.row <= row && row < (span.row + span.rowCount) && span.col <= col && col < (span.col + span.colCount)) {
+                rst = true;
+                break;
+            }
+        }
+        return rst;
+    },
+    setupHeightWidth: function (dest, text, colWidthArr, rowHeightArr) {
+        let width = colWidthArr[colWidthArr.length - 1], height = rowHeightArr[rowHeightArr.length - 1];
+        dest[JV.PROP_AREA][JV.PROP_RIGHT] = (colWidthArr[text.col + text.colCount - 1] / width * 100).toFixed(2);
+        if (text.col > 0) {
+            dest[JV.PROP_AREA][JV.PROP_LEFT] = (colWidthArr[text.col - 1] / width * 100).toFixed(2);
+        } else {
+            dest[JV.PROP_AREA][JV.PROP_LEFT] = 0;
+        }
+        dest[JV.PROP_AREA][JV.PROP_BOTTOM] = (rowHeightArr[text.row + text.rowCount - 1] / height * 100).toFixed(2);
+        if (text.row > 0) {
+            dest[JV.PROP_AREA][JV.PROP_TOP] = (rowHeightArr[text.row - 1] / height * 100).toFixed(2);
+        } else {
+            dest[JV.PROP_AREA][JV.PROP_TOP] = 0;
+        }
+    },
+    createTxtNode: function (text, parentNode, colWidthArr, rowHeightArr) {
+        let me = this, rst = dataInfoMapTreeOprObj.getDummyTextNode(parentNode);
+        me.setupHeightWidth(rst, text, colWidthArr, rowHeightArr);
+        if (stringUtil.isEmptyString(text[`text`])) {
+            rst[JV.PROP_NAME] = '';
+        } else {
+            rst[JV.PROP_NAME] = stringUtil.replaceAll(stringUtil.replaceAll(text[`text`].toString(), '\n', '|'), '\r', '');
+        }
+        rst[JV.PROP_LABEL] = rst[JV.PROP_NAME];
+        return rst;
+    },
+    collectSheetTxt: function (sheet, texts, reserveRows, colWidthArr, rowHeightArr) {
+        let me = this, spans= sheet.getSpans();
+        let private_build_pre_text = function (row, col, rowCount, colCount) {
+            let cell = sheet.getCell(row, col);
+            let textValue = sheet.getValue(row, col);
+            if (textValue && cell.cellType().typeName === '7') {
+                textValue = `{` + textValue + `}`;
+            }
+            texts.push({"row": row, "col": col, "rowCount": rowCount, "colCount": colCount, "text": textValue});
+        };
+        for (let span of spans) {
+            private_build_pre_text(span.row, span.col, span.rowCount, span.colCount);
+        }
+        for (let iRow = 0; iRow < sheet.getRowCount() - reserveRows; iRow++) {
+            rowHeightArr.push(sheet.getRowHeight(iRow));
+            if (iRow > 0) {
+                rowHeightArr[iRow] = rowHeightArr[iRow] + rowHeightArr[iRow - 1];
+            }
+            for (let jCol = 0; jCol < sheet.getColumnCount(); jCol++) {
+                if (iRow === 0) {
+                    colWidthArr.push(sheet.getColumnWidth(jCol));
+                    if (jCol > 0) {
+                        colWidthArr[jCol] = colWidthArr[jCol] + colWidthArr[jCol - 1];
+                    }
+                }
+                if (!me.checkInSpan(spans, iRow, jCol)) {
+                    private_build_pre_text(iRow, jCol, 1, 1);
+                }
+            }
+        }
+        texts.sort(function(t1, t2){
+            if (t1.col === t2.col) {
+                return t1.row - t2.row;
+            } else {
+                return t1.col - t2.col;
+            }
+        });
+    },
+    addSpan: function (itemNode, sheet, bandW, bandH, xPos, yPos, sheetAreaType) {
+        let me = this;
+        let idx1 = xPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW));
+        let idx2 = xPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW));
+        let idy1 = yPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH));
+        let idy2 = yPos.indexOf(me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH));
+        if (idx2 - idx1 > 1 || idy2 - idy1 > 1) {
+            sheet.addSpan(idy1, idx1, idy2 - idy1, idx2 - idx1, sheetAreaType);
+        }
+        let cell = sheet.getCell(idy1, idx1, sheetAreaType);
+        if (sheetAreaType === GC.Spread.Sheets.SheetArea.viewport) {
+            if (itemNode.FieldID) {
+                me.changeCellType(cell, 'field');
+            } else {
+                me.changeCellType(cell, 'text');
+            }
+        }
+        me.setupCell(cell, itemNode);
+    },
+    changeBandHeight: function (bandName, newHeight) {
+        let nodes = bandTreeOprObj.treeObj.getNodes()[0][JV.BAND_PROP_SUB_BANDS];
+        let private_set_band_height = function(bNode) {
+            let rst = false;
+            if (bNode[JV.PROP_NAME] === bandName) {
+                bNode[JV.BAND_PROP_HEIGHT] = newHeight;
+                rst = true;
+            } else if (bNode[JV.BAND_PROP_SUB_BANDS] && bNode[JV.BAND_PROP_SUB_BANDS].length > 0){
+                for (let subNode of bNode[JV.BAND_PROP_SUB_BANDS]) {
+                    rst = private_set_band_height(subNode);
+                    if (rst) break;
+                }
+            }
+            return rst;
+        };
+        for (let bandNode of nodes) {
+            if (private_set_band_height(bandNode)) break;
+        }
+    },
+    changeCellType: function (cell, newType, newColor) {
+        let me = this;
+        switch (newType) {
+            case `field`:
+                let rptTpl = (zTreeOprObj.currentNode)?zTreeOprObj.currentNode.rptTpl:null;
+                let cellType = new GC.Spread.Sheets.CellTypes.ComboBox();
+                let selectableFields = me.getSelectedFields(rptTpl);
+                cellType.items(selectableFields);
+                cell.cellType(cellType);
+                if (newColor) {
+                    cell.backColor(newColor);
+                } else {
+                    cell.backColor("LightCyan");
+                }
+                break;
+            case `text`:
+            default:
+                cell.cellType(new GC.Spread.Sheets.CellTypes.Text());
+                cell.value(``);
+                if (newColor) {
+                    cell.backColor(newColor);
+                } else {
+                    cell.backColor(undefined);
+                }
+                break;
+        }
+    },
+    setupCell: function (cell, itemNode) {
+        let me = this;
+        me.private_setCellFont(cell, itemNode);
+        me.private_setCellControl(cell, itemNode);
+        me.private_setCellStyle(cell, itemNode);
+        let value = itemNode[JV.PROP_NAME];
+        if (itemNode[JV.PROP_NAME].indexOf(`|`) >= 0) {
+            value = itemNode[JV.PROP_NAME].split('|').join('\n');
+        }
+        cell.wordWrap(true);
+        cell.value(value);
+    },
+    private_setCellControl: function (cell, textNode) {
+        let ctrl = null;
+        if (typeof textNode[JV.PROP_CONTROL] === 'string') {
+            let idx = rpt_tpl_cfg_helper.reportCfg.controlArr.indexOf(textNode[JV.PROP_CONTROL]);
+            ctrl = rpt_tpl_cfg_helper.reportCfg.ctrls[idx];
+        } else {
+            ctrl = textNode[JV.PROP_CONTROL];
+        }
+        if (ctrl) {
+            switch (ctrl.Horizon) {
+                case `center`:
+                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+                    break;
+                case `right`:
+                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.right);
+                    break;
+                default:
+                    cell.hAlign(GC.Spread.Sheets.HorizontalAlign.left);
+                    break;
+            }
+            switch (ctrl.Vertical) {
+                case `center`:
+                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+                    break;
+                case `bottom`:
+                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.bottom);
+                    break;
+                default:
+                    cell.vAlign(GC.Spread.Sheets.VerticalAlign.top);
+                    break;
+            }
+        }
+    },
+    private_setCellStyle: function (cell, textNode) {
+        //默认是normal,暂时不管
+    },
+    private_setCellFont: function (cell, textNode) {
+        for (let font of rpt_tpl_cfg_helper.reportCfg.fonts) {
+            if (font.ID === textNode[JV.PROP_FONT]) {
+                cell.font(Math.round(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]] * 3 / 4) + 'pt ' + font[JV.FONT_PROPS[JV.FONT_PROP_IDX_NAME]]);
+                break;
+            }
+        }
+    },
+    getSelectedFields: function (rptTpl) {
+        let rst = [];
+        if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS] !== undefined && rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS].length > 0) {
+            for (let field of rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+                rst.push(field[JV.PROP_NAME]);
+            }
+        }
+        if (rptTpl[JV.NODE_NO_MAPPING_FIELDS] !== undefined && rptTpl[JV.NODE_NO_MAPPING_FIELDS].length > 0) {
+            for (let field of rptTpl[JV.NODE_NO_MAPPING_FIELDS]) {
+                rst.push(field[JV.PROP_NAME]);
+            }
+        }
+        return rst;
+    },
+    setupCellDft: function (cell) {
+        cell.font(`9pt 宋体`);
+        cell.hAlign(GC.Spread.Sheets.HorizontalAlign.center);
+        cell.vAlign(GC.Spread.Sheets.VerticalAlign.center);
+        cell.wordWrap(true);
+        cell.cellType(new GC.Spread.Sheets.CellTypes.Text());
+        cell.value(``);
+    },
+
+    addBandPos: function (rptTpl, pageW, pageH, xPos, yPos, bandMappingObj) {
+        let left = 0, right = pageW, top = 0, bottom = pageH;
+        let orgArea = [left, top, right, bottom];
+        let colorIdx = 0;
+        bandMappingObj.items = [];
+        let private_setup_pos = function (band) {
+            left = orgArea[JV.IDX_LEFT];
+            top = orgArea[JV.IDX_TOP];
+            right = orgArea[JV.IDX_RIGHT];
+            bottom = orgArea[JV.IDX_BOTTOM];
+            if (xPos.indexOf(left) < 0) xPos.push(left);
+            if (xPos.indexOf(right) < 0) xPos.push(right);
+            if (yPos.indexOf(top) < 0) yPos.push(top);
+            if (yPos.indexOf(bottom) < 0) yPos.push(bottom);
+            switch (band[JV.BAND_PROP_ALIGNMENT]) {
+                case JV.LAYOUT_TOP:
+                case JV.LAYOUT[JV.LAYOUT_TOP]:
+                    bottom = Math.round(top + unitFactor * band[JV.BAND_PROP_HEIGHT]);
+                    orgArea[JV.IDX_TOP] = bottom;
+                    break;
+                case JV.LAYOUT_BOTTOM:
+                case JV.LAYOUT[JV.LAYOUT_BOTTOM]:
+                    top = Math.round(bottom - unitFactor * band[JV.BAND_PROP_HEIGHT]);
+                    orgArea[JV.IDX_BOTTOM] = top;
+                    break;
+                case JV.LAYOUT_LEFT:
+                case JV.LAYOUT[JV.LAYOUT_LEFT]:
+                    right = Math.round(left + unitFactor * band[JV.BAND_PROP_WIDTH]);
+                    orgArea[JV.IDX_LEFT] = right;
+                    break;
+                case JV.LAYOUT_RIGHT:
+                case JV.LAYOUT[JV.LAYOUT_RIGHT]:
+                    left = Math.round(right - unitFactor * band[JV.BAND_PROP_WIDTH]);
+                    orgArea[JV.IDX_RIGHT] = left;
+                    break;
+            }
+            let item = {};
+            bandMappingObj[band[JV.PROP_NAME]] = item;
+            item[JV.PROP_AREA] = {};
+            item[JV.PROP_AREA][JV.PROP_LEFT] = left;
+            item[JV.PROP_AREA][JV.PROP_RIGHT] = right;
+            item[JV.PROP_AREA][JV.PROP_TOP] = top;
+            item[JV.PROP_AREA][JV.PROP_BOTTOM] = bottom;
+            item[JV.PROP_COLOR] = BG_COLORS[colorIdx];
+            // item[JV.PROP_COLOR] = 'Blue';
+            bandMappingObj.items.push(item);
+            colorIdx++;
+            if (xPos.indexOf(left) < 0) xPos.push(left);
+            if (xPos.indexOf(right) < 0) xPos.push(right);
+            if (yPos.indexOf(top) < 0) yPos.push(top);
+            if (yPos.indexOf(bottom) < 0) yPos.push(bottom);
+
+            if (colorIdx >= BG_COLORS.length) colorIdx = 0;
+            if (band[JV.BAND_PROP_SUB_BANDS] && band[JV.BAND_PROP_SUB_BANDS].length > 0) {
+                item[JV.PROP_COLOR] = 'White';
+                // item[JV.PROP_COLOR] = null;
+                for (let subBand of band[JV.BAND_PROP_SUB_BANDS]) {
+                    private_setup_pos(subBand);
+                }
+            }
+        };
+        for (let band of rptTpl[JV.NODE_BAND_COLLECTION]) {
+            private_setup_pos(band);
+        }
+    },
+
+    pushAbsPos: function (bandMap, itemNode, xPos, yPos) {
+        let me = this;
+        if (bandMap) {
+            let bandW = bandMap[JV.PROP_AREA][JV.PROP_RIGHT] - bandMap[JV.PROP_AREA][JV.PROP_LEFT],
+                bandH = bandMap[JV.PROP_AREA][JV.PROP_BOTTOM] - bandMap[JV.PROP_AREA][JV.PROP_TOP];
+            let pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW) + bandMap[JV.PROP_AREA][JV.PROP_LEFT];
+            if (xPos.indexOf(pos) < 0) xPos.push(pos);
+            pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW) + bandMap[JV.PROP_AREA][JV.PROP_LEFT];
+            if (xPos.indexOf(pos) < 0) xPos.push(pos);
+            pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH) + bandMap[JV.PROP_AREA][JV.PROP_TOP];
+            if (yPos.indexOf(pos) < 0) yPos.push(pos);
+            pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH) + bandMap[JV.PROP_AREA][JV.PROP_TOP];
+            if (yPos.indexOf(pos) < 0) yPos.push(pos);
+        }
+    },
+    addTplTxtFldPos: function (rptTpl, tree, xPos, yPos, bandMappingObj) {
+        let me = this, nodes = tree.getNodes();
+        if (rptTpl[JV.NODE_FLOW_INFO]) {
+            //流水式
+            let contentBandMap, contentRowH, orgContentTop, lastContentBottom;
+            for (let node of nodes) {
+                if (node[JV.PROP_NAME].indexOf('_列') >= 0) {
+                    //1. 列
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    me.addNormalTxtFldPos(bandMap, node, xPos, yPos);
+                    bandMap[JV.PROP_COLOR] = 'LightGray';
+                } else if (node[JV.PROP_NAME].indexOf('数据') >= 0) {
+                    //2. 数据
+                    contentBandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    contentRowH = Math.round(unitFactor * rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT]);
+                    orgContentTop = contentBandMap[JV.PROP_AREA][JV.PROP_TOP];
+                    let bkBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = contentBandMap[JV.PROP_AREA][JV.PROP_TOP] + contentRowH;
+                    lastContentBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                    me.addNormalTxtFldPos(contentBandMap, node, xPos, yPos);
+                    contentBandMap[JV.PROP_AREA][JV.PROP_TOP] = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = bkBottom;
+                    contentBandMap[JV.PROP_COLOR] = 'LightCyan';
+                } else if (node[JV.PROP_NAME].indexOf('_页统计') >= 0) {
+                    //3. 页统计
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    for (let itemNode of node.items) {
+                        me.addNormalTxtFldPos(bandMap, itemNode, xPos, yPos);
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('_段统计') >= 0) {
+                    //4. 章统计
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    for (let itemNode of node.items) {
+                        me.addNormalTxtFldPos(bandMap, itemNode, xPos, yPos);
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('_分组') >= 0) {
+                    //5. 分组统计
+                    if (contentBandMap && contentRowH && node.items && node.items.length > 0) {
+                        for (let itemNode of node.items) {
+                            if (itemNode[JV.PROP_NAME] === `分组行`) {
+                                for (let subItemNode of itemNode.items) {
+                                    //行
+                                    let bkBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = contentBandMap[JV.PROP_AREA][JV.PROP_TOP] + contentRowH;
+                                    lastContentBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    for (let txtFldNode of subItemNode.items) {
+                                        //分组字段集 与 文本集
+                                        me.addNormalTxtFldPos(contentBandMap, txtFldNode, xPos, yPos);
+                                    }
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_TOP] = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = bkBottom;
+                                }
+                            }
+                        }
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('离散') >= 0) {
+                    //6. 离散信息
+                    me.addDiscreteTxtFldPos(node, xPos, yPos, bandMappingObj);
+                }
+            }
+            if (contentBandMap) {
+                contentBandMap[JV.PROP_AREA][JV.PROP_TOP] = orgContentTop;
+                contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = lastContentBottom;
+            }
+        } else if (rptTpl[JV.NODE_BILL_INFO]) {
+            //账单式
+            for (let node of nodes) {
+                if (node[JV.PROP_NAME].indexOf('数据') >= 0) {
+                    //1. 数据
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    me.addNormalTxtFldPos(bandMap, node, xPos, yPos);
+                } else if (node[JV.PROP_NAME].indexOf('离散') >= 0) {
+                    //2. 离散信息
+                    me.addDiscreteTxtFldPos(node, xPos, yPos, bandMappingObj);
+                }
+            }
+        } else if (rptTpl[JV.NODE_CROSS_INFO]) {
+            //交叉式
+            //目前暂缓
+        }
+    },
+    setupTplTxtFld: function (rptTpl, tree, sheet, xPos, yPos, bandMappingObj) {
+        let me = this, nodes = tree.getNodes();
+        if (rptTpl[JV.NODE_FLOW_INFO]) {
+            //流水式
+            let contentBandMap, contentRowH;
+            for (let node of nodes) {
+                if (node[JV.PROP_NAME].indexOf('_列') >= 0) {
+                    //1. 列
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    // me.addNormalTxtFldPos(bandMap, node, xPos, yPos);
+                    me.addSpanWholeArea(bandMap, node, sheet, xPos, yPos);
+                } else if (node[JV.PROP_NAME].indexOf('数据') >= 0) {
+                    //2. 数据
+                    contentBandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    contentRowH = Math.round(unitFactor * rptTpl[JV.NODE_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT]);
+                    let bkBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = contentBandMap[JV.PROP_AREA][JV.PROP_TOP] + contentRowH;
+                    // me.addNormalTxtFldPos(contentBandMap, node, xPos, yPos);
+                    me.addSpanWholeArea(contentBandMap, node, sheet, xPos, yPos);
+                    contentBandMap[JV.PROP_AREA][JV.PROP_TOP] = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = bkBottom;
+                } else if (node[JV.PROP_NAME].indexOf('_页统计') >= 0) {
+                    //3. 页统计
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    for (let itemNode of node.items) {
+                        // me.addNormalTxtFldPos(bandMap, itemNode, xPos, yPos);
+                        me.addSpanWholeArea(bandMap, itemNode, sheet, xPos, yPos);
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('_段统计') >= 0) {
+                    //4. 章统计
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    for (let itemNode of node.items) {
+                        // me.addNormalTxtFldPos(bandMap, itemNode, xPos, yPos);
+                        me.addSpanWholeArea(bandMap, itemNode, sheet, xPos, yPos);
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('_分组') >= 0) {
+                    //5. 分组统计
+                    if (contentBandMap && contentRowH && node.items && node.items.length > 0) {
+                        for (let itemNode of node.items) {
+                            if (itemNode[JV.PROP_NAME] === `分组行`) {
+                                for (let subItemNode of itemNode.items) {
+                                    //行
+                                    let bkBottom = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = contentBandMap[JV.PROP_AREA][JV.PROP_TOP] + contentRowH;
+                                    for (let txtFldNode of subItemNode.items) {
+                                        //分组字段集 与 文本集
+                                        // me.addNormalTxtFldPos(contentBandMap, txtFldNode, xPos, yPos);
+                                        me.addSpanWholeArea(contentBandMap, txtFldNode, sheet, xPos, yPos);
+                                    }
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_TOP] = contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM];
+                                    contentBandMap[JV.PROP_AREA][JV.PROP_BOTTOM] = bkBottom;
+                                }
+                            }
+                        }
+                    }
+                } else if (node[JV.PROP_NAME].indexOf('离散') >= 0) {
+                    //6. 离散信息
+                    // me.addDiscreteTxtFldPos(node, xPos, yPos, bandMappingObj);
+                    me.addDiscreteSpan(node, xPos, yPos, bandMappingObj, sheet);
+                }
+            }
+        } else if (rptTpl[JV.NODE_BILL_INFO]) {
+            //账单式
+            for (let node of nodes) {
+                if (node[JV.PROP_NAME].indexOf('数据') >= 0) {
+                    //1. 数据
+                    let bandMap = bandMappingObj[node[JV.PROP_BAND_NAME]];
+                    me.addSpanWholeArea(bandMap, node, sheet, xPos, yPos);
+                } else if (node[JV.PROP_NAME].indexOf('离散') >= 0) {
+                    //2. 离散信息
+                    me.addDiscreteSpan(node, xPos, yPos, bandMappingObj, sheet);
+                }
+            }
+        } else if (rptTpl[JV.NODE_CROSS_INFO]) {
+            //交叉式
+            //目前暂缓
+        }
+    },
+    brushSheet: function (bandMappingObj, sheet, xPos, yPos) {
+        for (let bandMap of bandMappingObj.items) {
+            let idxTop = yPos.indexOf(bandMap[JV.PROP_AREA][JV.PROP_TOP]);
+            let idxBottom = yPos.indexOf(bandMap[JV.PROP_AREA][JV.PROP_BOTTOM]);
+            if (idxTop >= 0 && idxBottom > idxTop) {
+                sheet.getRange(idxTop, -1, idxBottom - idxTop, -1).backColor(bandMap[JV.PROP_COLOR]);
+                let range = sheet.getRange(idxTop, -1, idxBottom - idxTop, -1);
+                if (bandMap[JV.PROP_COLOR] === 'White') {
+                    range.watermark("[Not Editable]");
+                } else {
+                    range.watermark(undefined);
+                }
+            }
+        }
+    },
+    addDiscreteTxtFldPos: function (discreteItemNode, xPos, yPos, bandMappingObj) {
+        let me = this;
+        for (let itemNode of discreteItemNode.items) {
+            //子项
+            let bandMap = bandMappingObj[itemNode[JV.PROP_BAND_NAME]];
+            if (bandMap) {
+                for (let subItemNode of itemNode.items) {
+                    for (let txtFldDtlNode of subItemNode.items) {
+                        me.pushAbsPos(bandMap, txtFldDtlNode, xPos, yPos);
+                    }
+                }
+            }
+        }
+    },
+    addNormalTxtFldPos: function (bandMap, parentNode, xPos, yPos) {
+        let me = this;
+        if (bandMap && parentNode.items && parentNode.items.length > 0) {
+            for (let itemNode of parentNode.items) {
+                me.pushAbsPos(bandMap, itemNode, xPos, yPos);
+            }
+        }
+    },
+    addSpanWholeArea: function (bandMap, parentNode, sheet, xPos, yPos) {
+        let me = this;
+        if (bandMap && parentNode.items && parentNode.items.length > 0) {
+            let bandW = bandMap[JV.PROP_AREA][JV.PROP_RIGHT] - bandMap[JV.PROP_AREA][JV.PROP_LEFT],
+                bandH = bandMap[JV.PROP_AREA][JV.PROP_BOTTOM] - bandMap[JV.PROP_AREA][JV.PROP_TOP];
+            for (let itemNode of parentNode.items) {
+                // me.pushAbsPos(bandMap, itemNode, xPos, yPos);
+                let pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW) + bandMap[JV.PROP_AREA][JV.PROP_LEFT];
+                let idxLeft = xPos.indexOf(pos);
+                pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW) + bandMap[JV.PROP_AREA][JV.PROP_LEFT];
+                let idxRight = xPos.indexOf(pos);
+                pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH) + bandMap[JV.PROP_AREA][JV.PROP_TOP];
+                let idxTop = yPos.indexOf(pos);
+                pos = me.getActPosEx(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH) + bandMap[JV.PROP_AREA][JV.PROP_TOP];
+                let idxBottom = yPos.indexOf(pos);
+
+                if (idxRight - idxLeft > 1 || idxBottom - idxTop > 1) {
+                    sheet.addSpan(idxTop, idxLeft, idxBottom - idxTop, idxRight - idxLeft, GC.Spread.Sheets.SheetArea.viewport);
+                }
+                let cell = sheet.getCell(idxTop, idxLeft, GC.Spread.Sheets.SheetArea.viewport);
+                if (itemNode.FieldID) {
+                    me.changeCellType(cell, 'field', bandMap[JV.PROP_COLOR]);
+                } else {
+                    me.changeCellType(cell, 'text', bandMap[JV.PROP_COLOR]);
+                }
+                me.setupCell(cell, itemNode);
+            }
+        }
+    },
+    addDiscreteSpan: function (discreteItemNode, xPos, yPos, bandMappingObj, sheet) {
+        let me = this;
+        for (let itemNode of discreteItemNode.items) {
+            //子项
+            let bandMap = bandMappingObj[itemNode[JV.PROP_BAND_NAME]];
+            if (bandMap) {
+                for (let subItemNode of itemNode.items) {
+                    me.addSpanWholeArea(bandMap, subItemNode, sheet, xPos, yPos);
+                }
+            }
+        }
+    },
+    setupBorder: function (cell, border) {
+        cell.borderLeft(border);
+        cell.borderRight(border);
+        cell.borderTop(border);
+        cell.borderBottom(border);
+    }
+};

+ 245 - 0
web/maintain/report/js/rpt_tpl_vis_jumbo.js

@@ -0,0 +1,245 @@
+/**
+ * Created by Tony on 2018/9/10.
+ */
+
+let visualJumbo = {
+    tplWorkBook: null,
+    iniSpreadJs: function () {
+        let me = this;
+        /*/
+        if (me.tplWorkBook === null) {
+            me.tplWorkBook = new GC.Spread.Sheets.Workbook($('#ele_visual_div_main3')[0], {sheetCount: 1});
+            me.tplWorkBook.options.tabStripVisible = false;
+            me.tplWorkBook.options.allowCopyPasteExcelStyle = false;
+            me.tplWorkBook.options.allowUserDragDrop = false;
+            me.tplWorkBook.options.allowContextMenu = false;
+            let sheet = me.tplWorkBook.getActiveSheet();
+            sheet.options.allowCellOverflow = false;
+            sheet.setRowCount(10, GC.Spread.Sheets.SheetArea.viewport);
+            // sheet.bind(GC.Spread.Sheets.Events.EnterCell, me.onCellEnter);
+        }
+        /*/
+        if (me.tplWorkBook !== null) {
+            me.tplWorkBook.destroy();
+            me.tplWorkBook = null;
+        }
+        me.tplWorkBook = new GC.Spread.Sheets.Workbook($('#ele_visual_div_main3')[0], {sheetCount: 1});
+        me.tplWorkBook.options.tabStripVisible = false;
+        me.tplWorkBook.options.allowCopyPasteExcelStyle = false;
+        me.tplWorkBook.options.allowUserDragDrop = false;
+        me.tplWorkBook.options.allowContextMenu = false;
+        let sheet = me.tplWorkBook.getActiveSheet();
+        sheet.options.allowCellOverflow = false;
+        sheet.options.clipBoardOptions = GC.Spread.Sheets.ClipboardPasteOptions.values;
+        // sheet.bind(GC.Spread.Sheets.Events.CellClick, me.onCellEnter);
+        //*/
+    },
+    setupTpl: function () {
+        let me = this;
+        let rptTpl = (zTreeOprObj.currentNode)?zTreeOprObj.currentNode.rptTpl:null;
+        if (rptTpl && me.tplWorkBook) {
+            let sheet  = me.tplWorkBook.getActiveSheet();
+            let border = new GC.Spread.Sheets.LineBorder;
+            border.color = "Black";
+            border.style = GC.Spread.Sheets.LineStyle.thin;
+            sheet.suspendPaint();
+            sheet.setRowCount(0);
+            sheet.setColumnCount(0);
+            //1. put the pos into array
+            let xPos = [0], yPos = [0];
+            let pageH, pageW;
+            let bandMappingObj = {};
+            let pIdx = JV.PAGES_SIZE_STR.indexOf(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE]);
+            pageW = Math.round(JV.PAGES_SIZE[pIdx][0] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT])) /2.54*96 );
+            pageH = Math.round(JV.PAGES_SIZE[pIdx][1] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_TOP]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM])) /2.54*96 );
+            if (rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE ||
+                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE_CHN) {
+                pageW = Math.round(JV.PAGES_SIZE[pIdx][1] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT])) /2.54*96 );
+                pageH = Math.round(JV.PAGES_SIZE[pIdx][0] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_TOP]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM])) /2.54*96 );
+            }
+            xPos.push(pageW);
+            // pageH = Math.round(pageH / 2);
+            yPos.push(pageH);
+            visualCommonOprObj.addBandPos(rptTpl, pageW, pageH, xPos, yPos, bandMappingObj);
+            visualCommonOprObj.addTplTxtFldPos(rptTpl, dataInfoMapTreeOprObj.treeObj, xPos, yPos, bandMappingObj);
+            //2. 设置spreadjs
+            xPos.sort(function(x1, x2){ return (x1 - x2); });
+            yPos.sort(function(y1, y2){ return (y1 - y2); });
+            sheet.setRowCount(yPos.length - 1);
+            sheet.setColumnCount(xPos.length - 1);
+            for (let idx = 1; idx < xPos.length; idx++) {
+                sheet.setColumnWidth(idx - 1, xPos[idx] - xPos[idx - 1]);
+            }
+            for (let idx = 1; idx < yPos.length; idx++) {
+                sheet.setRowHeight(idx - 1, yPos[idx] - yPos[idx - 1]);
+                sheet.getRange(idx - 1, -1, 1, -1).backColor(undefined);
+            }
+            visualCommonOprObj.brushSheet(bandMappingObj, sheet, xPos, yPos);
+            visualCommonOprObj.setupTplTxtFld(rptTpl, dataInfoMapTreeOprObj.treeObj, sheet, xPos, yPos, bandMappingObj)
+            for (let idx = 1; idx < yPos.length; idx++) {
+                let bkc = sheet.getCell(idx - 1, 0).backColor();
+                if (bkc === 'White') {
+                    sheet.setRowHeight(idx - 1, 30);
+                }
+            }
+            for (let iRow = 0; iRow < sheet.getRowCount(); iRow++) {
+                for (let iCol = 0; iCol < sheet.getColumnCount(); iCol++) {
+                    let cell = sheet.getCell(iRow, iCol);
+                    if (cell.backColor() === 'LightGray' || cell.backColor() === 'LightCyan') {
+                        visualCommonOprObj.setupBorder(sheet.getCell(iRow, iCol), border);
+                    }
+                }
+            }
+            sheet.clearSelection();
+            sheet.resumePaint();
+        }
+    },
+    restoreTpl: function () {
+        let me = visualJumbo;
+        if (me.tplWorkBook) {
+            me.setupTpl();
+        }
+    },
+    private_AddCols: function (sheet, col) {
+        sheet.suspendPaint();
+        sheet.addColumns(col, 1);
+        sheet.resumePaint();
+    },
+    insertColumn: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        if (selectedRanges.length > 0) {
+            me.private_AddCols(sheet, selectedRanges[0].col);
+        }
+    },
+    addColumn: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        me.private_AddCols(sheet, sheet.getColumnCount());
+    },
+    deleteColumn: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        let cc = sheet.getColumnCount();
+        if (cc > 1) {
+            if (selectedRanges.length > 0) {
+                sheet.deleteColumns(selectedRanges[0].col, 1);
+            }
+        } else {
+            alert('不能删除列!');
+        }
+    },
+    addRow: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        if (selectedRanges.length > 0) {
+            let cell = sheet.getCell(selectedRanges[0].row, selectedRanges[0].col);
+            let color = cell.backColor();
+            if (color !== 'White') {
+                let nextIdx = sheet.getRowCount();
+                for (let idx = selectedRanges[0].row + 1; idx < sheet.getRowCount(); idx++) {
+                    if (sheet.getCell(idx, selectedRanges[0].col).backColor() !== color) {
+                        nextIdx = idx;
+                        break;
+                    }
+                }
+                sheet.suspendPaint();
+                sheet.addRows(nextIdx, 1);
+                sheet.getRange(nextIdx, -1, 1, -1).backColor(color);
+                sheet.resumePaint();
+            }
+        }
+    },
+    deleteRow: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        if (selectedRanges.length > 0) {
+            let cell = sheet.getCell(selectedRanges[0].row, selectedRanges[0].col);
+            let color = cell.backColor();
+            if (color !== 'White') {
+                let amt = 0;
+                for (let idx = 0; idx < sheet.getRowCount(); idx++) {
+                    if (sheet.getCell(idx, selectedRanges[0].col).backColor() === color) {
+                        amt++
+                    }
+                }
+                if (amt > 1) {
+                    sheet.suspendPaint();
+                    sheet.deleteRows(selectedRanges[0].row, 1);
+                    sheet.resumePaint();
+                }
+            }
+        }
+    },
+    fitTheWidth: function (factor) {
+        let me = this, rptTpl = (zTreeOprObj.currentNode)?zTreeOprObj.currentNode.rptTpl:null;
+        let pIdx = JV.PAGES_SIZE_STR.indexOf(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE]);
+        let bandW = 700;
+        if (pIdx >= 0) {
+            bandW = Math.round(JV.PAGES_SIZE[pIdx][0] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT])) /2.54*96 );
+            if (rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE ||
+                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] === JV.ORIENTATION_LANDSCAPE_CHN) {
+                bandW = Math.round(JV.PAGES_SIZE[pIdx][1] * 96 - (parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]) + parseFloat(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_MARGINS][JV.PROP_RIGHT])) /2.54*96 );
+            }
+        }
+        bandW *= factor;
+        let currentWidth = 0;
+        let sheet = me.tplWorkBook.getActiveSheet();
+        for (let idx = 0; idx < sheet.getColumnCount(); idx++) {
+            currentWidth += sheet.getColumnWidth(idx);
+        }
+        let actFactor = bandW / currentWidth;
+        for (let idx = 0; idx < sheet.getColumnCount(); idx++) {
+            sheet.setColumnWidth(idx, Math.round(sheet.getColumnWidth(idx) * actFactor));
+        }
+    },
+    mergeCells: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        if (selectedRanges.length > 0) {
+            let cell = sheet.getCell(selectedRanges[0].row, selectedRanges[0].col);
+            let color = cell.backColor();
+            let isDifferent = false;
+            for (let idx = 1; idx < selectedRanges[0].rowCount; idx++) {
+                if (sheet.getCell(selectedRanges[0].row + idx, 0).backColor() !== color) {
+                    isDifferent = true;
+                    break;
+                }
+            }
+            if (!isDifferent) {
+                sheet.suspendPaint();
+                sheet.addSpan(selectedRanges[0].row, selectedRanges[0].col, selectedRanges[0].rowCount, selectedRanges[0].colCount);
+                sheet.resumePaint();
+            } else {
+                alert(`不能合并跨界单元格!`)
+            }
+        }
+    },
+    disMergeCells: function () {
+        let me = visualJumbo,
+            sheet = me.tplWorkBook.getActiveSheet();
+        let selectedRanges = sheet.getSelections();
+        let spans = sheet.getSpans();
+        if (selectedRanges.length > 0 && spans.length > 0) {
+            let selectedSpans = [];
+            for(let i = 0; i < spans.length; i++)
+            {
+                for (let j = 0; j < selectedRanges.length; j++) {
+                    if (spans[i].row >= selectedRanges[j].row && spans[i].col >= selectedRanges[j].col &&
+                        spans[i].row < selectedRanges[j].row + selectedRanges[j].rowCount && spans[i].col < selectedRanges[j].col + selectedRanges[j].colCount) {
+                        selectedSpans.push(spans[i]);
+                    }
+                }
+            }
+            for (let span of selectedSpans) {
+                sheet.removeSpan(span.row, span.col, GC.Spread.Sheets.SheetArea.viewport);
+            }
+        }
+    }
+
+};

+ 20 - 20
web/maintain/report/js/rpt_tpl_virtual_summary.js

@@ -30,7 +30,7 @@ let virtualSummaryOprObj = {
     },
     setupSummary: function (rptTpl, summaryParentNode) {
         let me = this, columnParentNode = null;
-        let selectedBand = virtualCommonOprObj.getBandEx(summaryParentNode[JV.PROP_BAND_NAME], rptTpl);
+        let selectedBand = visualCommonOprObj.getBandEx(summaryParentNode[JV.PROP_BAND_NAME], rptTpl);
         if (summaryParentNode && selectedBand) {
             me.private_setup_control_options(false);
             let preNode = summaryParentNode.getPreNode();
@@ -48,7 +48,7 @@ let virtualSummaryOprObj = {
                     // , xSummaryPos = [0]
                 ;
                 let sheet = me.summaryWorkBook.getActiveSheet();
-                let columnBand = virtualCommonOprObj.getBandEx(columnParentNode[JV.PROP_BAND_NAME], rptTpl);
+                let columnBand = visualCommonOprObj.getBandEx(columnParentNode[JV.PROP_BAND_NAME], rptTpl);
                 let bandH = Math.round(parseFloat(columnBand[JV.BAND_PROP_HEIGHT]) / 2.54 * 96);
                 let bandW = 700;
                 let pIdx = JV.PAGES_SIZE_STR.indexOf(rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE]);
@@ -61,10 +61,10 @@ let virtualSummaryOprObj = {
                 }
                 //1. 设置column位置(让用户知道位置,后期无需用户再调)
                 for (let itemNode of columnParentNode.items) {
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW, xPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH, yColumnPos);
-                    virtualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH, yColumnPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_LEFT, bandW, xPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_H_CALCULATION], JV.PROP_RIGHT, bandW, xPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, bandH, yColumnPos);
+                    visualCommonOprObj.pushPos(itemNode, itemNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, bandH, yColumnPos);
                 }
                 sheet.suspendPaint();
                 sheet.clearSelection();
@@ -86,27 +86,27 @@ let virtualSummaryOprObj = {
                     sheet.getRange(idx - 1, -1, 1, -1).backColor(undefined);
                 }
                 for (let itemNode of columnParentNode.items) {
-                    virtualCommonOprObj.addSpan(itemNode, sheet, bandW, bandH, xPos, yColumnPos, GC.Spread.Sheets.SheetArea.colHeader);
+                    visualCommonOprObj.addSpan(itemNode, sheet, bandW, bandH, xPos, yColumnPos, GC.Spread.Sheets.SheetArea.colHeader);
                 }
                 //2. 设置已有的统计信息
                 let sumBandH = Math.round(parseFloat(selectedBand[JV.BAND_PROP_HEIGHT]) / 2.54 * 96);
                 for (let fNode of fieldNode.items) {
-                    virtualCommonOprObj.pushPos(fNode, fNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, sumBandH, ySummaryPos);
-                    virtualCommonOprObj.pushPos(fNode, fNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, sumBandH, ySummaryPos);
+                    visualCommonOprObj.pushPos(fNode, fNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, sumBandH, ySummaryPos);
+                    visualCommonOprObj.pushPos(fNode, fNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, sumBandH, ySummaryPos);
                 }
                 for (let tNode of textNode.items) {
-                    virtualCommonOprObj.pushPos(tNode, tNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, sumBandH, ySummaryPos);
-                    virtualCommonOprObj.pushPos(tNode, tNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, sumBandH, ySummaryPos);
+                    visualCommonOprObj.pushPos(tNode, tNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_TOP, sumBandH, ySummaryPos);
+                    visualCommonOprObj.pushPos(tNode, tNode[JV.PROP_AREA][JV.PROP_V_CALCULATION], JV.PROP_BOTTOM, sumBandH, ySummaryPos);
                 }
                 sheet.setRowCount(ySummaryPos.length - 1, GC.Spread.Sheets.SheetArea.viewport);
                 for (let idx = 1; idx < ySummaryPos.length; idx++) {
                     sheet.setRowHeight(idx - 1, ySummaryPos[idx] - ySummaryPos[idx - 1]);
                 }
                 for (let tNode of textNode.items) {
-                    virtualCommonOprObj.addSpan(tNode, sheet, bandW, sumBandH, xPos, ySummaryPos, GC.Spread.Sheets.SheetArea.viewport);
+                    visualCommonOprObj.addSpan(tNode, sheet, bandW, sumBandH, xPos, ySummaryPos, GC.Spread.Sheets.SheetArea.viewport);
                 }
                 for (let fNode of fieldNode.items) {
-                    virtualCommonOprObj.addSpan(fNode, sheet, bandW, sumBandH, xPos, ySummaryPos, GC.Spread.Sheets.SheetArea.viewport);
+                    visualCommonOprObj.addSpan(fNode, sheet, bandW, sumBandH, xPos, ySummaryPos, GC.Spread.Sheets.SheetArea.viewport);
                 }
                 sheet.resumePaint();
             }
@@ -119,7 +119,7 @@ let virtualSummaryOprObj = {
         sheet.addRows(sheet.getRowCount() - 1, 1);
         let rc = sheet.getRowCount();
         for (let cc = 0; cc < sheet.getColumnCount(); cc++) {
-            virtualCommonOprObj.setupCellDft(sheet.getCell(rc - 2, cc));
+            visualCommonOprObj.setupCellDft(sheet.getCell(rc - 2, cc));
         }
         sheet.resumePaint();
     },
@@ -229,7 +229,7 @@ let virtualSummaryOprObj = {
         if (selectedRanges.length > 0) {
             sheet.suspendPaint();
             let cell = sheet.getCell(selectedRanges[0].row, selectedRanges[0].col);
-            virtualCommonOprObj.changeCellType(cell, newType);
+            visualCommonOprObj.changeCellType(cell, newType);
             sheet.resumePaint();
         }
     },
@@ -358,7 +358,7 @@ let virtualSummaryOprObj = {
             rst[JV.PROP_FONT] = "Content_Narrow";
         }
         //3. 上下左右位置
-        virtualCommonOprObj.setupHeightWidth(rst, text, colWidthArr, rowHeightArr);
+        visualCommonOprObj.setupHeightWidth(rst, text, colWidthArr, rowHeightArr);
         return rst;
     },
 
@@ -371,7 +371,7 @@ let virtualSummaryOprObj = {
             if (rAmt > 0) {
                 let texts = [], colWidthArr = [], rowHeightArr = [];
                 //1. 收集text信息
-                virtualCommonOprObj.collectSheetTxt(sheet, texts, 0, colWidthArr, rowHeightArr);
+                visualCommonOprObj.collectSheetTxt(sheet, texts, 0, colWidthArr, rowHeightArr);
                 for (let node of me.summaryParentNode.items) {
                     dataInfoMapTreeOprObj.treeObj.removeChildNodes(node);
                 }
@@ -383,7 +383,7 @@ let virtualSummaryOprObj = {
                         fieldNodes.push(me.private_create_field_node(sheet, colWidthArr, rowHeightArr, text, rptTpl));
                     } else {
                         //创建文本
-                        let textNode = virtualCommonOprObj.createTxtNode(text, me.columnParentNode, colWidthArr, rowHeightArr);
+                        let textNode = visualCommonOprObj.createTxtNode(text, me.columnParentNode, colWidthArr, rowHeightArr);
                         let cell = sheet.getCell(text.row, text.col);
                         if (cell.font().indexOf('Narrow') < 0) {
                             textNode[JV.PROP_FONT] = "GrandTotal";
@@ -403,9 +403,9 @@ let virtualSummaryOprObj = {
                     dataInfoMapTreeOprObj.treeObj.addNodes(fieldNode, -1, fieldNodes, true);
                 }
                 //3. 重新设置band高度
-                // let selectedBand = virtualCommonOprObj.getBandEx(me.summaryParentNode[JV.PROP_BAND_NAME], rptTpl);
+                // let selectedBand = visualCommonOprObj.getBandEx(me.summaryParentNode[JV.PROP_BAND_NAME], rptTpl);
                 // selectedBand[JV.BAND_PROP_HEIGHT] = (rowHeightArr[rowHeightArr.length - 1] / 96 * 2.54).toFixed(2);
-                virtualCommonOprObj.changeBandHeight(me.summaryParentNode[JV.PROP_BAND_NAME], (rowHeightArr[rowHeightArr.length - 1] / 96 * 2.54).toFixed(2));
+                visualCommonOprObj.changeBandHeight(me.summaryParentNode[JV.PROP_BAND_NAME], (rowHeightArr[rowHeightArr.length - 1] / 96 * 2.54).toFixed(2));
                 displayMessage("应用提交成功!", "green", 5000, "id_summary_setup_lbl");
             } else {
                 displayMessage("模板行数量不足!", "red", 5000, "id_summary_setup_lbl");