Jelajahi Sumber

前端导出PDF

TonyKang 6 tahun lalu
induk
melakukan
2c7d3bb67e

File diff ditekan karena terlalu besar
+ 8 - 0
lib/jspdf/SmartSimsun-bold.js


File diff ditekan karena terlalu besar
+ 8 - 0
lib/jspdf/SmartSimsun-normal.js


File diff ditekan karena terlalu besar
+ 286 - 0
lib/jspdf/jspdf.min.js


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

@@ -2039,6 +2039,10 @@
     <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="/lib/jspdf/jspdf.min.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/SmartSimsun-normal.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/SmartSimsun-bold.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;
+        }
+    }
+}

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

@@ -535,6 +535,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 +925,122 @@ 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 {
+                        let pageSize = rptControlObj.getCurrentPageSize();
+                        let pageData = zTreeOprObj.currentRptPageRst;
+                        JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[0]);
+                    }
+                    //me.currentRptPageRst
+                }
+            }
+        }
+        /*
+        if (zTreeOprObj.checkedRptTplNodes && zTreeOprObj.checkedRptTplNodes.length > 0) {
+            let rptIds = [], rpt_names = [];
+            let params = {};
+            params.pageSize = rptControlObj.getCurrentPageSize();
+            params.orientation = ((zTreeOprObj.checkedRptTplNodes.length > 1)?null:rptControlObj.getCurrentOrientation());
+            params.custCfg = zTreeOprObj.reportPageCfg;
+            params.prj_id = projectObj.project.projectInfo.ID;
+            for (let tplNode of zTreeOprObj.checkedRptTplNodes) {
+                rptIds.push(tplNode.refId);
+                rpt_names.push(tplNode.name);
+            }
+            params.rpt_ids = rptIds.join(",");
+            CommonAjax.postEx("report_api/getMultiReports", params, 30000, true,
+                function(result){
+                    // sessionStorage.multiRptsData = JSON.stringify(result);
+                    // sessionStorage.pageSize = rptControlObj.getCurrentPageSize();
+                    // sessionStorage.orientation = rptControlObj.getCurrentOrientation();
+                    // sessionStorage.scaleFactor = 1;
+                    // window.open('/rpt_print');
+                    // console.log(result);
+                    let pageSize = rptControlObj.getCurrentPageSize();
+                    for (let idx = 0; idx < result.length; idx++) {
+                        let pageData = result[idx];
+                        // let orientation = (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] < pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1])?"portrait":"landscape";
+                        // showPreviewData(svgArr, actArea, scaleFactor, sessionStorage.pageSize, orientation, orgPixelSize);
+                        JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[idx]);
+                    }
+                },
+                function(failRst){
+                    sessionStorage.currentPageData = null;
+                    console.log(failRst);
+                },
+                function(exceptionRst){
+                    sessionStorage.currentPageData = null;
+                    console.log(exceptionRst);
+                }
+            );
+        } else {
+            //不可能的branch
+        }
+        //*/
+    },
     firstPage: function(dom) {
         let canvas = document.getElementById("rptCanvas");
         zTreeOprObj.showPage(1, canvas);