Procházet zdrojové kódy

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/YangHuCost

zhangweicheng před 6 roky
rodič
revize
b38664d67e

+ 1 - 0
config/gulpConfig.js

@@ -153,6 +153,7 @@ module.exports = {
         'web/building_saas/report/js/jpc_output_value_define.js',
         'web/building_saas/report/js/jpc_output.js',
         'web/building_saas/report/js/rpt_print.js',
+        'web/building_saas/report/js/rpt_jspdf.js',
         'web/building_saas/main/js/views/glj_view.js',
         'web/building_saas/main/js/views/zmhs_view.js',
         'web/building_saas/main/js/views/mbzm_view.js',

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 8 - 0
lib/jspdf/SmartSimsun-bold.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 8 - 0
lib/jspdf/SmartSimsun-normal.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 286 - 0
lib/jspdf/jspdf.min.js


+ 10 - 2
modules/pm/facade/pm_facade.js

@@ -682,7 +682,15 @@ function getBuildingArea(projFeature){
 function getSortedDataByTree(data) {
     // NextSiblingID-数据映射
     const mapping = {};
-    data.forEach(item => mapping[item.NextSiblingID] = item);
+    data.forEach(item => {
+        // 错误数据兼容处理
+        // 由于之前的导入建设项目,会导致最后的一个项目的NextSiblingID为空,为非正确的-1
+        // 因此把项目中NextSibling为空的数据设置为NextSiblingID为-1
+        if (!item.NextSiblingID) {
+            item.NextSiblingID = -1;
+        }
+        mapping[item.NextSiblingID] = item;
+    });
     let lastItem = data.find(item => +item.NextSiblingID === -1);
     if (!lastItem) {
         return data;
@@ -715,7 +723,7 @@ async function getSummaryInfoByTender(tenderID, summaryType) {
     // 汇总到建设项目层(没有单项工程层了)
     if (summaryType === projectType.project) {
         parentName = project.name ? project.name : '';
-        let tenders = await projectModel.find({ParentID: project.ID, $or: notDeleted});
+        let tenders = await projectModel.find({ParentID: project.ID, $or: notDeleted}).lean();
         tenders = getSortedDataByTree(tenders);
         for(let t of tenders){
             if(summaryInfo[t.ID]){

+ 52 - 26
modules/reports/rpt_component/jpc_flow_tab.js

@@ -361,12 +361,12 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 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]];
-                    }
-                    /*/
+                     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]];
+                     }
+                     /*/
                     let tab_field = me.auto_height_fields_idx[loop][1];
                     let data_field = null,
                         map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
@@ -620,7 +620,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     if ((ttlSegRecAmtNormal < ttlSegRecAmt) || (followTabEx !== null)) {
                         //有流水拓展,并且是follow mode
                         if (currentRecAmt + accAutoHeightAmt + exBuffer + maxRowRec > ttlSegRecAmtNormal) {
-                        // if (currentRecAmt + accAutoHeightAmt + adHocAutoHeightAmt + maxRowRec > ttlSegRecAmtNormal) {
+                            // if (currentRecAmt + accAutoHeightAmt + adHocAutoHeightAmt + maxRowRec > ttlSegRecAmtNormal) {
                             // if (currentRecAmt + adHocAutoHeightAmt >= ttlSegRecAmtNormal) {
                             if (currentRecAmt + accAutoHeightAmt + adHocAutoHeightAmt >= ttlSegRecAmtNormal) {
                                 //纯 followTabEx 数据
@@ -684,7 +684,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                             pageStatus[JV.STATUS_REPORT_END] = true;
                             private_resetBandArea();
                             let hasAdHocRow = ((adHocAutoHeightAmt > maxRowRec) || !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, handledRowAmt, maxRowRec, me.isEx));
-                                              // !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt, maxRowRec, me.isEx));
+                            // !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt, maxRowRec, me.isEx));
 
                             if (hasAdHocRow) {
                                 //add page info(pre segment end)
@@ -1115,7 +1115,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 me.pageSumValLst.push(rowGrandTotal);
                 //grouping content
-                let grpVal_Idx = 0;
+                let grpCntIdx = 0;
                 for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
                     if (contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_GROUP) {
                         for (let grpIdx = 0; grpIdx < rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length; grpIdx++) {
@@ -1131,11 +1131,11 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                         }
                                     }
                                 }
-                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx, grpVal_Idx, $CURRENT_RPT);
-                                grpVal_Idx++;
+                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx, grpCntIdx, $CURRENT_RPT);
                                 rst = rst.concat(lineRst);
                             }
                         }
+                        grpCntIdx++;
                     }
                 }
             }
@@ -1144,9 +1144,28 @@ JpcFlowTabSrv.prototype.createNew = function(){
         for (let idIdx = eliminateCells.length - 1; idIdx >= 0; idIdx--) {
             rst.splice(eliminateCells[idIdx], 1);
         }
+        me.checkCombineEvent(JV.RUN_TYPE_BEFORE_COMBINE, verticalCombinePos, horizonCombinePos, rst, $CURRENT_RPT);
         me.combinePageCells(rst, verticalCombinePos, horizonCombinePos);
+        me.checkCombineEvent(JV.RUN_TYPE_AFTER_COMBINE, verticalCombinePos, horizonCombinePos, rst, $CURRENT_RPT);
         return rst;
     };
+    JpcFlowTabResult.checkCombineEvent = function ($RUN_TYPE, $VER_COMB_ARRAY, $HOR_COMB_ARRAY, $CURRENT_CELL_ITEMS, $CURRENT_RPT) {
+        if ($CURRENT_RPT.formulas) {
+            for (let execFmlIdx = 0; execFmlIdx < $CURRENT_RPT.formulas.length; execFmlIdx++) {
+                if ($CURRENT_RPT.formulas[execFmlIdx][JV.PROP_RUN_TYPE] === $RUN_TYPE) {
+                    let expression = $CURRENT_RPT.formulas[execFmlIdx][JV.PROP_EXPRESSION];
+                    if (expression) {
+                        let $ME = $CURRENT_RPT.formulas[execFmlIdx];
+                        try {
+                            eval(expression);
+                        } catch (ex) {
+                            console.log(ex);
+                        }
+                    }
+                }
+            }
+        }
+    };
     JpcFlowTabResult.outputColumn = function (rptTpl, dataObj, page, segIdx, bands, unitFactor, multiColIdx) {
         let me = this, rst = [];
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
@@ -1278,7 +1297,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             return rst;
         }
     };
-    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx, grpVal_Idx, $CURRENT_RPT) {
+    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx, grpCntIdx, $CURRENT_RPT) {
         let me = this, rst = [];
         if (grp_line[JV.PROP_GROUP_SUM_KEYS]) {
             let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
@@ -1291,13 +1310,11 @@ JpcFlowTabSrv.prototype.createNew = function(){
             }
         }
         if (grp_line[JV.PROP_TEXTS]) {
-            for (let grpIdx = 0; grpIdx < grp_line[JV.PROP_TEXTS].length; grpIdx++) {
-                let txt = grp_line[JV.PROP_TEXTS][grpIdx];
-                let rstCell = JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx);
-                if ($CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]) {
-                    me.eventGrpOnCreate(rstCell, JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE], grpIdx, grpVal_Idx, $CURRENT_RPT);
-                }
-                rst.push(rstCell);
+            for (let txt of grp_line[JV.PROP_TEXTS]) {
+                me.checkGrpTxtOutEvent(JV.RUN_TYPE_BEFORE_GROUP_TEXT_OUT, txt, grpCntIdx, $CURRENT_RPT);
+                rst.push(JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx));
+                // me.combinePageCells(rst, verticalCombinePos, horizonCombinePos);
+                // 可能会有一个After,但意义不大,用不着
             }
         }
         if (grp_line[JV.PROP_DISCRETE_FIELDS]) {
@@ -1309,15 +1326,24 @@ JpcFlowTabSrv.prototype.createNew = function(){
         // console.log(rst);
         return rst;
     };
-    JpcFlowTabResult.eventGrpOnCreate = function (_$CELL, _$GRP_TYPE, _$GRP_OBJ_IDX, _$GRP_VAL_IDX, $CURRENT_RPT) {
-        if ($CURRENT_RPT.events && $CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]) {
-            try {
-                eval($CURRENT_RPT.events[JV.EVENT_TYPE[JV.EVENT_IDX_GRP_ON_CREATE]]);
-            } catch (ex) {
-                console.log(ex);
+    JpcFlowTabResult.checkGrpTxtOutEvent = function ($RUN_TYPE, $TEXT, $TIMES, $CURRENT_RPT) {
+        if ($CURRENT_RPT.formulas) {
+            for (let execFmlIdx = 0; execFmlIdx < $CURRENT_RPT.formulas.length; execFmlIdx++) {
+                if ($CURRENT_RPT.formulas[execFmlIdx][JV.PROP_RUN_TYPE] === $RUN_TYPE) {
+                    let expression = $CURRENT_RPT.formulas[execFmlIdx][JV.PROP_EXPRESSION];
+                    if (expression) {
+                        let $ME = $CURRENT_RPT.formulas[execFmlIdx];
+                        try {
+                            eval(expression);
+                        } catch (ex) {
+                            console.log(ex);
+                        }
+                    }
+                }
             }
         }
     };
+
     JpcFlowTabResult.commonTabRestOutput = function(dataObj, page, segIdx, bands, band, unitFactor, tab, multiColIdx){
         let me = this, rst = [];
         if (tab[JV.PROP_TEXT]) {
@@ -1374,7 +1400,7 @@ function setupControl(mergeCell, controls) {
         mergeCell[JV.PROP_CONTROL].Shrink = "T";
         mergeCell[JV.PROP_CONTROL].Vertical = "top";
         mergeCell[JV.PROP_CONTROL].Wrap = (mergeCell[JV.PROP_IS_AUTO_HEIGHT])?'T':'F',
-        mergeCell[JV.PROP_CONTROL].VerticalForExcel = "center";
+            mergeCell[JV.PROP_CONTROL].VerticalForExcel = "center";
         orgCtrl = mergeCell[JV.PROP_CONTROL];
     }
     if (mergeCell[JV.PROP_IS_AUTO_HEIGHT]) {

+ 4 - 0
public/web/rpt_value_define.js

@@ -207,6 +207,10 @@ const JV = {
     RUN_TYPE_BEFORE_ANALYZING: "before_analyzing",
     RUN_TYPE_BEFORE_PAGING: "before_paging",
     RUN_TYPE_BEFORE_OUTPUT: "before_output",
+    RUN_TYPE_BEFORE_COMBINE: "before_combine",
+    RUN_TYPE_AFTER_COMBINE: "after_combine",
+
+    RUN_TYPE_BEFORE_GROUP_TEXT_OUT: "before_group_text_output",
 
     PAGE_STATUS: ["EveryPage","FirstPage", "LastPage", "SegmentStart", "SegmentEnd", "Group", "CrossRowEnd", "CrossColEnd"],
 

+ 3 - 0
web/building_saas/main/html/main.html

@@ -1916,6 +1916,7 @@
     <script src="/lib/spreadjs/views/plugins/gc.spread.views.gridlayout.10.0.0.min.js" type="text/javascript"></script>
     <script src="/lib/js-xlsx/xlsx.core.min.js"></script>
     <script src="/lib/lz-string/lz-string.min.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/jspdf.min.js"></script>
     <!-- inject:js -->
     <!--<script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>-->
     <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
@@ -2039,6 +2040,8 @@
     <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/main.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/views/material_calc_view.js"></script>
     <script type="text/javascript" src="/public/web/storageUtil.js"></script>
+    <script type="text/javascript" src="/web/building_saas/report/js/rpt_jspdf.js"></script>
+
     <!-- endinject -->
 
     <% if (overWriteUrl != undefined) { %>

+ 3 - 0
web/building_saas/report/html/rpt_main.html

@@ -33,7 +33,10 @@
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.checkAndGetExcel()"><i class="fa fa-file-excel-o"></i> Excel <span class="badge badge-secondary">0</span></button>
                                 <button type="button" class="btn btn-outline-primary btn-sm" id="show_excel_output_cfg" data-toggle="modal" data-target="#export_excel" style="display:none"></button>
                                 <button type="button" class="btn btn-outline-primary btn-sm" id="show_project_folder" data-toggle="modal" data-target="#cpoj" style="display:none"></button>
+                                <!--
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.getPDF()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-secondary">0</span></button>
+                                -->
+                                <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.getPDFEx()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-secondary">0</span></button>
                             </div>
                         </div>
                         <div class="panel-foot text-muted">

+ 1 - 1
web/building_saas/report/html/rpt_select_projects.html

@@ -30,7 +30,7 @@
             </div>
             <div class="modal-footer" id="divReqCommonSummaryPDF" style="display:none">
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <a onclick="zTreeOprObj.requestSumAndNormalRptForPDF()" class="btn btn-primary" data-dismiss="modal">确定</a>
+                <a onclick="zTreeOprObj.requestSumAndNormalRptForPDF_Ex()" class="btn btn-primary" data-dismiss="modal">确定</a>
             </div>
         </div>
     </div>

+ 4 - 0
web/building_saas/report/js/jpc_output_value_define.js

@@ -56,6 +56,10 @@ let JV = {
     FONT_PROP_IDX_STRIKEOUT: 6,
     FONT_PROP_IDX_ANGLE: 7,
 
+    PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
+    PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],
+    PAGES_SIZE: [[11.69, 16.54], [8.27, 11.69], [5.83, 8.27], [6.93, 9.84], [8.5, 11.0], [8.5, 14.0], [7.25, 10.5], [7.25, 10.5]],
+
     OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,

+ 441 - 0
web/building_saas/report/js/rpt_jspdf.js

@@ -0,0 +1,441 @@
+/**
+ * Created by Tony on 2019/9/10.
+ */
+
+const PDF_SCALE = 0.75;
+// const DPI = getScreenDPI();
+
+let JpcJsPDFHelper = {
+    doc: null,
+    initialize: function (orientation, unit, format) {
+        let me = this;
+        me.doc = new jsPDF(orientation, unit, format);
+        return me.doc;
+    },
+    testFont: function () {
+        let me = this;
+        let doc = me.initialize('p', 'pt', 'a4');
+        console.log(me.doc.getFontList());
+        // console.log(me.doc.getFont());
+        // doc.setFont("SmartSimsun", "bold");
+        // doc.setFontSize(16);
+        // doc.text(20, 20, '小写字母总长度:' + doc.getTextWidth('abcdefghijklmnopqrstuvwxyz'));
+        //
+        // doc.setFont("SmartSimsun", "normal");
+        // doc.setFontSize(16);
+        // doc.text(20, 40, '大写字母总长度:' + doc.getTextWidth('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
+        //
+        // doc.line(20, 20, 60, 20); // horizontal line
+        // doc.line(20, 40, 60, 40); // horizontal line
+        //
+        // doc.save('Test.pdf');
+    },
+    outputAsPdf: function (pageData, paperSize, pdfName) {
+        let me = this;
+        let offsetX= 10;
+        let offsetY=10;
+        let newName = pdfName;
+        let pageObj = pageData;
+        let paperSizeIdx = JV.PAGES_SIZE_STR.indexOf(paperSize);
+        let size = JV.PAGES_SIZE[paperSizeIdx];
+        let orientation = '';
+        if (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] > pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1]) {
+            orientation = 'landscape';
+        } else {
+            orientation = 'portrait';
+        }
+        let doc = me.initialize(orientation, 'pt', paperSize.toLowerCase());
+        doc.setFont("SmartSimsun", "normal"); //目前只考虑宋体
+
+        function private_getIniPageMergeBorder(mergedBand) {
+            let rst = {};
+            rst[JV.PROP_LEFT] = mergedBand[JV.PROP_LEFT];
+            rst[JV.PROP_RIGHT] = mergedBand[JV.PROP_RIGHT];
+            rst[JV.PROP_TOP] = mergedBand[JV.PROP_TOP];
+            rst[JV.PROP_BOTTOM] = mergedBand[JV.PROP_BOTTOM];
+            rst[JV.PROP_STYLE] = mergedBand[JV.PROP_STYLE];
+            return rst;
+        }
+
+        let newPageMergeBand = private_getIniPageMergeBorder(pageObj[JV.BAND_PROP_MERGE_BAND]);
+        if (pageObj && pageObj.items.length > 0 ) {
+            for(let i = 0; i < pageObj.items.length; i++) {
+                if (i > 0) {
+                    doc.addPage(paperSize.toLowerCase(), orientation);
+                }
+                let ctx = doc.canvas.getContext();
+                let page = pageObj.items[i],
+                    fonts = pageObj[JV.NODE_FONT_COLLECTION],
+                    styles = pageObj[JV.NODE_STYLE_COLLECTION],
+                    controls = pageObj[JV.NODE_CONTROL_COLLECTION];
+
+                if (page[JV.PROP_PAGE_MERGE_BORDER]) {
+                    newPageMergeBand[JV.PROP_LEFT] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_LEFT];
+                    newPageMergeBand[JV.PROP_RIGHT] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_RIGHT];
+                    newPageMergeBand[JV.PROP_TOP] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_TOP];
+                    newPageMergeBand[JV.PROP_BOTTOM] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_BOTTOM];
+                }
+                for (let j = 0; j < page.cells.length; j++) {
+                    let cell = page.cells[j];
+                    private_drawCell(doc, ctx, cell, fonts, styles, controls, newPageMergeBand);
+                }
+            }
+        }
+        doc.save(newName + '.pdf');
+
+        function private_chkIfInMergedBand(mergedBand, cell) {
+            let rst = false;
+            if (mergedBand && cell) {
+                rst = mergedBand[JV.PROP_TOP] <= cell[JV.PROP_AREA][JV.PROP_TOP] && mergedBand[JV.PROP_BOTTOM] >= cell[JV.PROP_AREA][JV.PROP_BOTTOM] &&
+                    mergedBand[JV.PROP_LEFT] <= cell[JV.PROP_AREA][JV.PROP_LEFT] && mergedBand[JV.PROP_RIGHT] >= cell[JV.PROP_AREA][JV.PROP_RIGHT];
+            }
+            return rst;
+        }
+
+        function private_drawCell(doc, ctx, cell, fonts, styles, controls, mergedBand) {
+            ctx.beginPath();
+            let style = styles[cell[JV.PROP_STYLE]];
+            if (style) {
+                let isNeedMergeBand = private_chkIfInMergedBand(mergedBand, cell);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_TOP, [JV.PROP_LEFT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_RIGHT, [JV.PROP_RIGHT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_BOTTOM, [JV.PROP_RIGHT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_LEFT, [JV.PROP_LEFT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+            }
+            private_drawCellText(doc, ctx, cell, fonts, controls);
+            ctx.closePath();
+
+        }
+
+        function private_drawLine(cell, doc, ctx, style, styleBorderDest, startP, destP, mergedBand, styles, isNeedMergeBand) {
+            let destStyle = style;
+            if (mergedBand) {
+                if (isNeedMergeBand && parseFloat(mergedBand[styleBorderDest]) === parseFloat(cell[JV.PROP_AREA][styleBorderDest])) {
+                    destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
+                }
+            }
+            if (destStyle[styleBorderDest] && parseFloat(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) !== 0) {
+                doc.setDrawColor(destStyle[styleBorderDest][JV.PROP_COLOR]);
+                if (parseInt(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) === 2) {
+                    doc.setLineWidth(1 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]);
+                } else {
+                    doc.setLineWidth(0.1);
+                }
+                doc.line((cell[JV.PROP_AREA][startP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][startP[1]] + offsetY) * PDF_SCALE,
+                    (cell[JV.PROP_AREA][destP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][destP[1]] + offsetY) * PDF_SCALE);
+            }
+        }
+
+        function private_drawCellText(doc, ctx, cell, fonts, controls) {
+            if (cell[JV.PROP_VALUE]) {
+                let values = ("" + cell[JV.PROP_VALUE]).split('|');
+                // let font = fonts[cell[JV.PROP_FONT]];
+                let font = null;
+                if (typeof cell[JV.PROP_FONT] === "string") {
+                    font = fonts[cell[JV.PROP_FONT]];
+                } else {
+                    font = cell[JV.PROP_FONT];
+                }
+                if (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T') {
+                    doc.setFont("SmartSimsun", "bold");
+                    // doc.setFontStyle("bold");
+                } else {
+                    doc.setFont("SmartSimsun", "normal");
+                }
+                // let control = controls[cell[JV.PROP_CONTROL]];
+                let control = null;
+                if (typeof cell[JV.PROP_CONTROL] === "string") {
+                    control = controls[cell[JV.PROP_CONTROL]];
+                } else {
+                    control = cell[JV.PROP_CONTROL];
+                }
+                let height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+                let area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + offsetY];
+                let ah = height;
+                let restTopH = 0, restBottomH = 0;
+                if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_CLOSE_OUTPUT]] === 'T') {
+                    ah = (parseFloat(font[JV.FONT_PROPS[1]]) + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]) * values.length;
+                    let restH = height - ah;
+                    if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'center') {
+                        restTopH = restH / 2;
+                        restBottomH = restH / 2;
+                    } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'bottom') {
+                        restBottomH = restH;
+                    } else {
+                        restTopH = restH;
+                    }
+                }
+                let spaceIdxArr = [];
+                for (let i = 0; i < values.length; i++) {
+                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + offsetY + restTopH;
+                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restBottomH;
+                    if (values[i] === null || values[i] === undefined || values[i] === 'null') {
+                        values[i] = "";
+                    }
+                    // 因pdfkit输出空格只有浏览器的一半宽度,需要额外加空格补上,jspdf也有这个情况 -----------------------------
+                    if (typeof(values[i]) === "string") {
+                        for (let j = 0; j < values[i].length; j++) {
+                            if (values[i][j] === ' ') spaceIdxArr.push(j);
+                        }
+                    }
+                    for (let j = spaceIdxArr.length - 1; j >= 0; j--) {
+                        values[i] = values[i].slice(0, spaceIdxArr[j]) + ' ' + values[i].slice(spaceIdxArr[j]);
+                    }
+                    // -----------------------------
+                    private_drawText(doc, ctx, values[i], area, font, control);
+                    spaceIdxArr = [];
+                }
+            }
+        }
+
+        function private_drawText(doc, ctx, val, area, font, control) {
+            let dftFontHeight = 12;
+            let output = [];
+            if (font) {
+                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                doc.setFontSize(dftFontHeight);
+            }
+            // doc.font(fontFile);
+            let options={};
+            let inner_setupControl = function (outVal, inArea, inFontHeight, inOutput) {
+                if (control) {
+                    private_setupAreaH(outVal, inArea, control.Horizon, font.FontAngle, inFontHeight, inOutput, options);
+                    private_setupAreaV(outVal, inArea, control.Vertical, font.FontAngle, inFontHeight, inOutput);
+                } else {
+                    private_setupAreaH(outVal, inArea, "left", parseInt(font.FontAngle), inFontHeight, inOutput, options);
+                    private_setupAreaV(outVal, inArea, "bottom", parseInt(font.FontAngle), inFontHeight, inOutput);
+                }
+            };
+            inner_setupControl(val, area, dftFontHeight, output);
+            let validAreaTxtWidth = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+            let validTxtLines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
+            if (parseInt(font.FontAngle) !== 0) {
+                validAreaTxtWidth = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                validTxtLines = Math.floor((area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] + 4));
+            }
+
+            function private_drawUnderline(underLineVal, underLineArea) {
+                //A. 暂不支持角度; B. PDF输出时,坐标没有translate
+                // let ctx = doc;
+                //1. 计算下划线的相关坐标
+                let width = doc.getTextWidth(underLineVal);
+                if (width > underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT]) {
+                    width = underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT];
+                }
+                let height = dftFontHeight;
+                let startX = underLineArea[JV.IDX_LEFT], startY = underLineArea[JV.IDX_TOP], endX = underLineArea[JV.IDX_RIGHT], endY = underLineArea[JV.IDX_BOTTOM];
+                // let startX = 0, startY = 0, endX = width, endY = startY;
+                if (control.Horizon === "left") {
+                    startX = Math.round(underLineArea[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
+                } else if (control.Horizon === "right") {
+                    startX = Math.round(underLineArea[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
+                } else {
+                    startX = Math.round( underLineArea[JV.IDX_LEFT] + (underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT] - width) / 2);
+                }
+                endX = Math.round(startX + width);
+
+                if (control.Vertical === "top") {
+                    startY = Math.round(underLineArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height);
+                } else if (control.Vertical === "bottom") {
+                    startY = Math.round(underLineArea[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
+                } else {
+                    startY = Math.round( underLineArea[JV.IDX_TOP] + (underLineArea[JV.IDX_BOTTOM] - underLineArea[JV.IDX_TOP] + height) / 2) + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                }
+                endY = Math.round(startY);
+                //2. 画线
+                // ctx.save();
+                if ( output[1] !== Math.round(output[1])) {
+                    ctx.translate(0,0.5);
+                }
+
+                doc.setDrawColor("BLACK");
+                doc.setLineWidth(0.1);
+                doc.line(startX * PDF_SCALE, startY * PDF_SCALE, endX * PDF_SCALE, endY * PDF_SCALE);
+            }
+
+            let rotateOptions;
+            if (parseInt(font.FontAngle) !== 0) {
+                if (control){
+                    rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,control.Vertical,dftFontHeight, output);
+                } else {
+                    rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,"bottom",dftFontHeight, output);
+                }
+                doc.rotate(font.FontAngle,rotateOptions);
+            }
+            if (validAreaTxtWidth >= doc.getTextWidth(val) ||
+                (control && control.Shrink !== 'T' && validTxtLines < private_splitString(val, validAreaTxtWidth, doc)) ) {
+                options.width = validAreaTxtWidth * PDF_SCALE;
+                options.height = dftFontHeight * PDF_SCALE;
+                doc.setFontSize(dftFontHeight);
+                if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                    private_drawUnderline(val, area);
+                }
+                doc.setFontSize(dftFontHeight * PDF_SCALE);
+                doc.text(output[0] * PDF_SCALE, output[1] * PDF_SCALE, val);
+            } else {
+                while (true) {
+                    let lines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
+                    lines = (lines === 0 || (control.Shrink === 'T' && control.ShrinkFirst === 'T'))?1:lines;
+                    let actLines = private_splitString(val, validAreaTxtWidth, doc);
+                    if (actLines.length > lines && dftFontHeight >= 6) {
+                        dftFontHeight--;
+                        doc.setFontSize(dftFontHeight);
+                        options.width = validAreaTxtWidth * PDF_SCALE;
+                        options.height = dftFontHeight * PDF_SCALE;
+                    } else {
+                        let aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4;
+                        if ((aH * actLines.length) < (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) && (control && control.Vertical !== 'top')) {
+                            if (control.Vertical === 'bottom') {
+                                area[JV.IDX_TOP] = area[JV.IDX_BOTTOM] - (aH * actLines.length);
+                            } else {
+                                area[JV.IDX_TOP] = (area[JV.IDX_TOP] + area[JV.IDX_BOTTOM]) / 2 - (aH * actLines.length) / 2
+                                area[JV.IDX_BOTTOM] = area[JV.IDX_TOP] + (aH * actLines.length);
+                            }
+                        }
+                        let newArea = [], baseTop = area[JV.IDX_TOP];
+                        for (let ai = 0; ai < area.length; ai++) {
+                            newArea[ai] = area[ai];
+                        }
+                        options.width = validAreaTxtWidth * PDF_SCALE;
+                        options.height = dftFontHeight * PDF_SCALE;
+                        for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
+                            newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
+                            newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
+                            doc.setFontSize(dftFontHeight);
+                            inner_setupControl(actLines[lIdx], newArea, dftFontHeight, output);
+                            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                                private_drawUnderline(actLines[lIdx], newArea);
+                            }
+                            doc.setFontSize(dftFontHeight * PDF_SCALE);
+                            doc.text(output[0] * PDF_SCALE, output[1] * PDF_SCALE, actLines[lIdx]);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        function private_setupAreaH(outVal, area, type, fontAngle, dftFontHeight, outputPoint,options) {
+            //jspdf输出方式不同(但与H5的canvas处理方式有所不同,因为没有相关alignment属性,需要自己算,而且角度还暂时不支持)-------------------------------------------
+            let lType = type;
+            if (type !== "left" && type !== "right" && type !== "center") lType = "left";
+            switch (lType) {
+                case "left":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        // outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        // outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    }
+                    //ctx.textAlign="start";
+                    break;
+                case "right":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else {
+                        let width = doc.getTextWidth(outVal);
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - width;
+                    }
+                    //ctx.textAlign="end";
+                    break;
+                case "center":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT || fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
+                    } else {
+                        let width = doc.getTextWidth(outVal);
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2 - (width / 2);
+                    }
+                    //ctx.textAlign="center";
+                    break;
+            }
+        }
+
+        function private_setupAreaV(outVal, area, type, fontAngle, dftFontHeight, outputPoint) {
+            //jspdf输出方式不同(与H5的canvas一样处理)-------------------------------------------
+            let lType = type;
+            if (type !== "top" && type !== "bottom" && type !== "center") lType = "top";
+            switch (lType) {
+                case "top":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                        // if (fontName === "宋体") outputPoint[1] = outputPoint[1] - 1;
+                        outputPoint[1] = outputPoint[1] - 1; // 宋体需要提上一个像素点
+                    }
+                    break;
+                case "center":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
+                    } else {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
+                        // if (fontName === "宋体") outputPoint[1] = outputPoint[1] - 1;
+                        outputPoint[1] = outputPoint[1] - 1; // 宋体需要提上一个像素点
+                    }
+                    break;
+            }
+        }
+
+        function private_splitString(strVal, areaWidth, doc) {
+            let rst = [];
+            if (strVal) {
+                let preSIdx = 0, txtWidth = 0;
+                let currentW = 0;
+                let chnW = doc.getTextWidth('一'), otherW = doc.getTextWidth('_');
+                for (let sIdx = 0; sIdx < strVal.length; sIdx++) {
+                    currentW = (strVal.charCodeAt(sIdx) > 127)?chnW:otherW;
+                    txtWidth += currentW;
+                    if (txtWidth > areaWidth) {
+                        if (preSIdx < sIdx) {
+                            rst.push(strVal.substr(preSIdx, sIdx - preSIdx));
+                            preSIdx = sIdx;
+                        } else {
+                            rst.push(strVal.substr(preSIdx, 1));
+                            preSIdx = sIdx + 1;
+                        }
+                        txtWidth = currentW;
+                    }
+                    if (sIdx === strVal.length - 1) {
+                        rst.push(strVal.substr(preSIdx, strVal.length - preSIdx));
+                    }
+                }
+            }
+            if (rst.length === 0) rst.push(''); //什么都没有,也得整个空串
+            return rst;
+        }
+
+        function private_setupAreaRotateOption(area,w, type="top",dftFontHeight,outputPoint){
+            let x = (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT])/2+area[JV.IDX_LEFT];
+            let y =(area[JV.IDX_BOTTOM] - area[JV.IDX_TOP])/2+ area[JV.IDX_TOP];
+            let rotateOptions = {origin:[x,y]};
+            let h = area[JV.IDX_RIGHT] - area[JV.IDX_LEFT];
+            outputPoint[0]=x-w/2+JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+            switch (type) {
+                case "top":
+                    outputPoint[1] = y- h/2+ JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    outputPoint[1] = y+ h/2-JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]-dftFontHeight;
+                    break;
+                case "center":
+                    outputPoint[1] = y+dftFontHeight/2;
+                    break;
+            }
+            return rotateOptions;
+        }
+    }
+}

+ 141 - 0
web/building_saas/report/js/rpt_main.js

@@ -14,6 +14,7 @@ let fontSuffixMapObj = {"表标题": "title", "列标题": "column", "正文内
 
 let rptTplObj = {
     hasInitialized: false,
+    pdfFont: {'SmartSimsun': [], 'simhei': [], 'simkai': []},
     iniPage: function() {
         let me = this;
         if (!me.hasInitialized) {
@@ -24,7 +25,24 @@ let rptTplObj = {
             let canvas = document.getElementById("rptCanvas");
             canvas.onclick = canvasOprObj.canvasOnClick;
             canvas.onmousemove = canvasOprObj.canvasOnMouseMove;
+            if (JpcJsPDFHelper.doc === null) {
+                JpcJsPDFHelper.initialize('p', 'pt', 'a4');
+            }
+            dynamicLoadJs('/lib/jspdf/SmartSimsun-normal.js');
+            dynamicLoadJs('/lib/jspdf/SmartSimsun-bold.js', me.pdfFontSimsunCallBack);
         }
+    },
+    pdfFontSimsunCallBack: function() {
+        rptTplObj.pdfFont['SmartSimsun'].push('normal');
+        rptTplObj.pdfFont['SmartSimsun'].push('bold');
+    },
+    pdfFontSimkaiCallBack: function() {
+        rptTplObj.pdfFont['simkai'].push('normal');
+        rptTplObj.pdfFont['simkai'].push('bold');
+    },
+    pdfFontSimheiCallBack: function() {
+        rptTplObj.pdfFont['simhei'].push('normal');
+        rptTplObj.pdfFont['simhei'].push('bold');
     }
 }
 
@@ -535,6 +553,30 @@ let zTreeOprObj = {
             }, null, null
         );
     },
+    requestSumAndNormalRptForPDF_Ex: function () {
+        let rpt_names = [], bill_rpt_names = [], glj_rpt_names = [];
+        let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
+        rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, rpt_names, bill_rpt_names, glj_rpt_names);
+        let params = rptControlObj.creatCommonExportParam(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
+        params.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
+        params.rpt_names = rpt_names;
+        params.isOneSheet = true;
+        CommonAjax.postEx("report_api/getMultiReports", params, 30000, true,
+            function(result){
+                let pageSize = rptControlObj.getCurrentPageSize();
+                for (let idx = 0; idx < result.length; idx++) {
+                    let pageData = result[idx];
+                    JpcJsPDFHelper.outputAsPdf(pageData, pageSize, result[idx][JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
+                }
+            },
+            function(failRst){
+                console.log(failRst);
+            },
+            function(exceptionRst){
+                console.log(exceptionRst);
+            }
+        );
+    },
     requestSumAndNormalRptForMultiExcel: function () {
         let rpt_names = [], bill_rpt_names = [], glj_rpt_names = [];
         let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
@@ -901,6 +943,80 @@ let rptControlObj = {
             }
         }
     },
+    getPDFEx: function () {
+        let me = rptControlObj;
+        if (zTreeOprObj.checkedRptTplNodes && zTreeOprObj.checkedRptTplNodes.length > 0) {
+            let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
+            let rpt_names = [], bill_rpt_names = [], glj_rpt_names = [];
+            rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, rpt_names, bill_rpt_names, glj_rpt_names);
+            if (zTreeOprObj.selectedPrjIDs.length > 0 && (glj_rpt_names.length > 0 || bill_rpt_names.length > 0)) {
+                let params = rptControlObj.creatCommonExportParam();
+                params.prj_id = projectObj.project.projectInfo.ID;
+                params.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
+                params.rpt_ids = refRptTplIds;
+                params.rpt_bill_tpl_ids = refBillSumPrjsIds;
+                params.rpt_glj_tpl_ids = refGljSumPrjsIds;
+                params.rpt_names = rpt_names;
+                params.isOneSheet = true;
+                params.rptName = projectObj.project.projectInfo.name;
+                CommonAjax.postEx("report_api/getMultiReports", params, 30000, true,
+                    function(result){
+                        let pageSize = rptControlObj.getCurrentPageSize();
+                        for (let idx = 0; idx < result.length; idx++) {
+                            let pageData = result[idx];
+                            JpcJsPDFHelper.outputAsPdf(pageData, pageSize, result[idx][JV.NODE_PAGE_INFO][JV.NODE_MAIN_INFO_RPT_NAME]);
+                        }
+                    },
+                    function(failRst){
+                        console.log(failRst);
+                    },
+                    function(exceptionRst){
+                        console.log(exceptionRst);
+                    }
+                );
+            } else {
+                if (refBillSumPrjsIds.length > 0 || refGljSumPrjsIds.length > 0) {
+                    $("#divReqBillSummary")[0].style.display = "none";
+                    $("#divReqGljSummary")[0].style.display = "none";
+                    $("#divReqCommonSummaryExcel")[0].style.display = "none";
+                    $("#divReqCommonSummaryMultiExcel")[0].style.display = "none";
+                    $("#divReqCommonSummaryPDF")[0].style.display = "";
+                    zTreeOprObj.requestPrjFolderCommon(); //先处理需要汇总的报表,走另外一个分支
+                } else if (refRptTplIds.length > 0) {
+                    if (refRptTplIds.length > 1) {
+                        let params = {};
+                        params.prj_id = projectObj.project.projectInfo.ID;
+                        params.rpt_ids = refRptTplIds;
+                        params.rpt_names = rpt_names;
+                        params.pageSize = me.getCurrentPageSize();
+                        params.orientation = ((zTreeOprObj.checkedRptTplNodes.length > 1)?null:me.getCurrentOrientation());
+                        params.custCfg = zTreeOprObj.reportPageCfg;
+                        params.option = "normal";
+                        CommonAjax.postEx("report_api/getMultiReports", params, 30000, true,
+                            function(result){
+                                let pageSize = rptControlObj.getCurrentPageSize();
+                                for (let idx = 0; idx < result.length; idx++) {
+                                    let pageData = result[idx];
+                                    JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[idx]);
+                                }
+                            },
+                            function(failRst){
+                                console.log(failRst);
+                            },
+                            function(exceptionRst){
+                                console.log(exceptionRst);
+                            }
+                        );
+                    } else {
+                        //这个分支是为了减少请求,用户已经点过的表,又没有勾选,那么就直接导出成PDF
+                        let pageSize = rptControlObj.getCurrentPageSize();
+                        let pageData = zTreeOprObj.currentRptPageRst;
+                        JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[0]);
+                    }
+                }
+            }
+        }
+    },
     firstPage: function(dom) {
         let canvas = document.getElementById("rptCanvas");
         zTreeOprObj.showPage(1, canvas);
@@ -1014,3 +1130,28 @@ function downloadReport(urls) {
     }
     private_download();
 }
+
+function dynamicLoadJs(url, callback) {
+    let head = document.getElementsByTagName('head')[0];
+    let script = document.createElement('script');
+    script.type = 'text/javascript';
+    script.src = url;
+    if(callback) {
+        script.onload = script.onreadystatechange = function () {
+            if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete"){
+                callback();
+                script.onload = script.onreadystatechange = null;
+            }
+        };
+    }
+    head.appendChild(script);
+}
+
+function dynamicLoadCss(url) {
+    let head = document.getElementsByTagName('head')[0];
+    let link = document.createElement('link');
+    link.type='text/css';
+    link.rel = 'stylesheet';
+    link.href = url;
+    head.appendChild(link);
+}