浏览代码

print/pdf code merge

TonyKang 5 年之前
父节点
当前提交
e4e265d980

+ 132 - 0
app/controller/report_controller.js

@@ -72,6 +72,33 @@ module.exports = app => {
         }
 
         /**
+         * 报表打印页面
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        async showPrintPage(ctx) {
+            try {
+                // const params = JSON.parse(ctx.request.body.params);
+                const pageSize = ctx.params.size;
+                // console.log('pageSize: ' + pageSize);
+                const renderData = {
+                    size: pageSize,
+                    // orientation: params.orientation,
+                };
+                if (pageSize === 'A3') {
+                    await ctx.render('report/rpt_printA3.ejs', renderData);
+                } else {
+                    await ctx.render('report/rpt_print.ejs', renderData);
+                    // await this.layout('report/rpt_test_print.ejs', renderData);
+                }
+            } catch (err) {
+                this.log(err);
+                console.log(err);
+            }
+        }
+
+        /**
          * 获取报表数据
          *
          * @param {Object} ctx - egg全局context
@@ -100,6 +127,27 @@ module.exports = app => {
                 this.setMessage(ex.toString(), this.messageType.ERROR);
             }
         }
+
+        /**
+         * 获取多批次报表数据
+         *
+         * @param {Object} ctx - egg全局context
+         * @return {void}
+         */
+        async getMultiReportsEx(ctx) {
+            // 原则说明:把所有报表模板集中获取,统一filter,只读一次数据!
+            const params = JSON.parse(ctx.request.body.params);
+            const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL);
+            // console.log(pageRstArr);
+            ctx.body = { data: pageRstArr };
+            ctx.status = 201;
+        }
+
+        async createExcelFiles(ctx) {
+            const params = JSON.parse(ctx.request.body.params);
+            const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL);
+        }
+
     }
     return ReportController;
 };
@@ -200,6 +248,90 @@ async function getAllPagesCommon(ctx, rptTpl, params, option, outputType) {
     }
 }
 
+async function getMultiRptsCommon(ctx, params, outputType) {
+    for (let idx = 0; idx < params.rpt_ids.length; idx++) {
+        params.rpt_ids[idx] = parseInt(params.rpt_ids[idx]); // 转换一下,以防万一
+    }
+    const rptTpls = await ctx.service.rptTpl.getTplById(params.rpt_ids);
+    // console.log(rptTpls);
+    for (let rtIdx = 0; rtIdx < rptTpls.length; rtIdx++) {
+        rptTpls[rtIdx] = JSON.parse(rptTpls[rtIdx].rpt_content);
+    }
+    const rptDataUtil = new rptDataExtractor();
+    const filterTables = [];
+    if (rptTpls.length > 1) {
+        rptTpls.sort(function(item1, item2) {
+            const i1 = (item1._doc) ? item1._doc : item1;
+            const i2 = (item2._doc) ? item2._doc : item2;
+            const ID1 = params.rpt_ids.indexOf(i1[JV.PROP_ID]);
+            const ID2 = params.rpt_ids.indexOf(i2[JV.PROP_ID]);
+            return ID1 - ID2;
+        });
+    }
+    for (const rptTpl of rptTpls) {
+        rptDataUtil.initialize(rptTpl);
+        const filter = rptDataUtil.getDataRequestFilter();
+        // console.log(filter);
+        for (const table of filter.tables) {
+            if (filterTables.indexOf(table) < 0) {
+                filterTables.push(table);
+            }
+        }
+    }
+
+    const rawDataObj = await getReportData(ctx, params, filterTables);
+    try {
+        const rptPageRstArray = [];
+        // 1. 这里只用一份数据,根据实际应用情况,先备份
+        const backupData = {};
+        for (let filterIdx = 0; filterIdx < filterTables.length; filterIdx++) {
+            backupData[filterTables[filterIdx]] = [];
+            Object.assign(backupData[filterTables[filterIdx]], rawDataObj[filterTables[filterIdx]]);
+        }
+        // 2. 一个一个模板创建数据
+        let defProperties = await ctx.service.rptPreDefineCfg.getCfgById('Administrator');
+        // console.log('defProperties: ');
+        // console.log(defProperties[0].defined_content);
+        defProperties = JSON.parse(defProperties[0].defined_content);
+        for (let tplIdx = 0; tplIdx < rptTpls.length; tplIdx++) {
+            const rptTpl = (rptTpls[tplIdx]._doc) ? rptTpls[tplIdx]._doc : rptTpls[tplIdx];
+            rptDataUtil.initialize(rptTpl);
+            const tplData = rptDataUtil.assembleData(rawDataObj);
+            const printCom = JpcEx.createNew();
+            rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = params.pageSize;
+
+            if (params.pageSize) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = params.pageSize;
+            if (params.orientation && (params.orientation !== 'null')) rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_ORIENTATION] = params.orientation;
+            if (params.custCfg) setupCustomizeCfg(params.custCfg, rptTpl, defProperties);
+            const dftOption = params.option || JV.PAGING_OPTION_NORMAL;
+
+            printCom.initialize(rptTpl);
+            printCom.analyzeData(rptTpl, tplData, defProperties, dftOption, outputType);
+            const maxPages = printCom.totalPages;
+            let pageRst = null;
+            if (maxPages > 0) {
+                pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, params.custCfg);
+            } else {
+                pageRst = printCom.outputAsPreviewPage(rptTpl, defProperties);
+            }
+            rptPageRstArray.push(pageRst);
+            // 注意:这里需要把备份数据assign回去!!!
+            if (tplIdx < rptTpls.length - 1) {
+                for (let filterIdx = 0; filterIdx < filterTables.length; filterIdx++) {
+                    backupData[filterTables[filterIdx]] = [];
+                    Object.assign(rawDataObj[filterTables[filterIdx]], backupData[filterTables[filterIdx]]);
+                }
+            }
+        }
+        return rptPageRstArray;
+    } catch (ex) {
+        console.log('报表数据异常(getMultiRptsCommon): project_id ' + params.project_id + ', tender_id: ' + params.tender_id + ', stage_id: ' + params.stage_id);
+        console.log(ex);
+    } finally {
+        //
+    }
+}
+
 function setupCustomizeCfg(customizeCfg, rptTpl, defProperties) {
     const tmpObj = {};
     // 1. 字体

文件差异内容过多而无法显示
+ 8 - 0
app/public/jspdf/SmartSimsun-bold.js


文件差异内容过多而无法显示
+ 8 - 0
app/public/jspdf/SmartSimsun-normal.js


文件差异内容过多而无法显示
+ 286 - 0
app/public/jspdf/jspdf.min.js


+ 4 - 0
app/public/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
app/public/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;
+        }
+    }
+}

+ 83 - 133
app/public/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,21 @@ let rptTplObj = {
             zTreeOprObj.canvas = document.getElementById("rptCanvas");
             // canvas.onclick = canvasOprObj.canvasOnClick;
             // canvas.onmousemove = canvasOprObj.canvasOnMouseMove;
+            dynamicLoadJs('/public/jspdf/SmartSimsun-normal.js');
+            dynamicLoadJs('/public/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');
     }
 }
 
@@ -405,42 +420,28 @@ let rptControlObj = {
             //other types if needed.
         }
     },
-    getTplIdsCommon: function (refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, rpt_names, bill_rpt_names, glj_rpt_names) {
+    getTplIdsCommon: function (refRptTplIds, rpt_names) {
         for (let node of zTreeOprObj.checkedRptTplNodes) {
             if (node.hasOwnProperty('flags') && node.flags.hasOwnProperty('reportType') && node['flags']['reportType'] !== 'NA') {
-                if (node['flags']['reportType'] === 'billSummary') {
-                    refBillSumPrjsIds.push(node.refId);
-                    if (bill_rpt_names) bill_rpt_names.push(node.name);
-                } else if (node['flags']['reportType'] === 'gljSummary') {
-                    refGljSumPrjsIds.push(node.refId);
-                    if (glj_rpt_names) glj_rpt_names.push(node.name);
-                }
+                // 未来可能会有这些处理,目前空着
             } else {
                 refRptTplIds.push(node.refId);
                 if (rpt_names) rpt_names.push(node.name);
             }
         }
     },
-    creatCommonExportParam: function (refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds) {
-        let nodes = (zTreeOprObj.prjFolderTreeObj === null)?[]:zTreeOprObj.prjFolderTreeObj.getCheckedNodes(true);
+    creatCommonExportParam: function (refRptTplIds) {
         let rst = {};
-        rst.prj_id = projectObj.project.projectInfo.ID;
         rst.rpt_ids = refRptTplIds;
-        rst.rpt_bill_tpl_ids = refBillSumPrjsIds;
-        rst.rpt_glj_tpl_ids = refGljSumPrjsIds;
-        rst.prjIds = [];
-        zTreeOprObj.selectedPrjIDs = [];
-        for (let node of nodes) {
-            rst.prjIds.push(node.ID);
-            zTreeOprObj.selectedPrjIDs.push(node.ID);
-        }
-        // rst.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
-        // rst.rpt_names = rpt_names;
-        // rst.isOneSheet = true;
         rst.pageSize = rptControlObj.getCurrentPageSize();
         rst.orientation = ((zTreeOprObj.checkedRptTplNodes.length > 1)?null:rptControlObj.getCurrentOrientation());
+        rst.project_id = PROJECT_ID;
+        rst.tender_id = TENDER_ID;
+        rst.stage_id = getStageId();
+        rst.stage_order = getStageOrder();
+        rst.stage_times = getStageTimes();
         rst.custCfg = CUST_CFG;
-        rst.option = "normal";
+
         return rst;
     },
     getAllInOneBook: function () {
@@ -490,62 +491,27 @@ let rptControlObj = {
     getAllIndividualExcelBook: 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(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
-                params.prj_id = PROJECT_ID;
-                params.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
-                params.rpt_names = rpt_names;
-                params.isOneSheet = true;
-                params.rptName = projectObj.project.projectInfo.name;
-                CommonAjax.postEx("report_api/createExcelFiles", params, WAIT_TIME_EXPORT, true, function(result){
-                        if (result) {
-                            let uuIdUrls = [];
-                            for (let uuIdObj of result) {
-                                let uuIdUrl =  "/report_api/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/xlsx";
-                                uuIdUrls.push(uuIdUrl);
-                            }
-                            downloadReport(uuIdUrls);
-                        } else {
-                            //
+            let refRptTplIds = [];
+            let rpt_names = [];
+            rptControlObj.getTplIdsCommon(refRptTplIds, rpt_names);
+            let params = rptControlObj.creatCommonExportParam(refRptTplIds);
+            params.isOneSheet = true;
+            params.rpt_names = rpt_names;
+            params.rptName = 'All';
+            // CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken'),
+            CommonAjax.postEx("report_api/createExcelFiles", params, WAIT_TIME_EXPORT, true, function(result){
+                    if (result) {
+                        let uuIdUrls = [];
+                        for (let uuIdObj of result) {
+                            let uuIdUrl =  "/report_api/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/xlsx";
+                            uuIdUrls.push(uuIdUrl);
                         }
-                    }, null, null
-                );
-            } 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 = "";
-                    $("#divReqCommonSummaryPDF")[0].style.display = "none";
-                    zTreeOprObj.requestPrjFolderCommon(); //先处理需要汇总的报表,走另外一个分支
-                } else if (refRptTplIds.length > 0) {
-                    let params = {};
-                    params.prj_id = PROJECT_ID;
-                    params.rpt_ids = refRptTplIds;
-                    params.rpt_names = rpt_names;
-                    params.pageSize = me.getCurrentPageSize();
-                    params.orientation = ((zTreeOprObj.checkedRptTplNodes.length > 1)?null:me.getCurrentOrientation());
-                    params.isOneSheet = true;
-                    params.custCfg = CUST_CFG;
-                    params.option = "normal";
-                    CommonAjax.postEx("report_api/createExcelFiles", params, WAIT_TIME_EXPORT, true, function(result){
-                            if (result) {
-                                let uuIdUrls = [];
-                                for (let uuIdObj of result) {
-                                    let uuIdUrl =  "/report_api/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/xlsx";
-                                    uuIdUrls.push(uuIdUrl);
-                                }
-                                downloadReport(uuIdUrls);
-                            } else {
-                                //
-                            }
-                        }, null, null
-                    );
-                }
-            }
+                        downloadReport(uuIdUrls);
+                    } else {
+                        //
+                    }
+                }, null, null
+            );
         }
     },
     checkAndGetExcel: function () {
@@ -566,66 +532,34 @@ let rptControlObj = {
             me.getAllIndividualExcelBook();
         }
     },
-    getPDF: function () {
+    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 = PROJECT_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/createPdfFiles", params, WAIT_TIME_EXPORT, true, function(result){
-                        if (result) {
-                            let uuIdUrls = [];
-                            for (let uuIdObj of result) {
-                                let uuIdUrl =  "/report_api/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/pdf";
-                                uuIdUrls.push(uuIdUrl);
-                            }
-                            downloadReport(uuIdUrls);
-                        } else {
-                            //
+            let refRptTplIds = [];
+            let rpt_names = [];
+            rptControlObj.getTplIdsCommon(refRptTplIds, rpt_names);
+            if (refRptTplIds.length > 1) {
+                let params = rptControlObj.creatCommonExportParam(refRptTplIds);
+                CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken'),
+                    function(result){
+                        let pageSize = rptControlObj.getCurrentPageSize();
+                        for (let idx = 0; idx < result.data.length; idx++) {
+                            let pageData = result.data[idx];
+                            JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[idx]);
                         }
-                    }, null, null
+                    },
+                    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) {
-                    let params = {};
-                    params.prj_id = PROJECT_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 = CUST_CFG;
-                    params.option = "normal";
-                    CommonAjax.postEx("report_api/createPdfFiles", params, WAIT_TIME_EXPORT, true, function(result){
-                            if (result) {
-                                let uuIdUrls = [];
-                                for (let uuIdObj of result) {
-                                    let uuIdUrl =  "/report_api/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/pdf";
-                                    uuIdUrls.push(uuIdUrl);
-                                }
-                                downloadReport(uuIdUrls);
-                            } else {
-                                //
-                            }
-                        }, null, null
-                    );
-                }
+                //这个分支是为了减少请求,用户已经点过的表,又没有勾选,那么就直接导出成PDF
+                let pageSize = rptControlObj.getCurrentPageSize();
+                let pageData = zTreeOprObj.currentRptPageRst;
+                JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[0]);
             }
         }
     },
@@ -738,6 +672,22 @@ 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 getStageId() {
     return current_stage_id;
 }

+ 2 - 2
app/public/report/js/rpt_preview_common.js

@@ -3,7 +3,7 @@
  */
 
 let G_OFFSET_X = 0, G_OFFSET_Y = 0;
-function loading() {
+function printPageLoading() {
     if (sessionStorage.multiRptsData) {
         let multiRptData = JSON.parse(sessionStorage.multiRptsData);
         let scaleFactor = parseInt(sessionStorage.scaleFactor);
@@ -102,7 +102,7 @@ function getActualArea(pageData) {
     }
     return rst;
 }
-function closing() {
+function printPageClosing() {
     //
 }
 

+ 7 - 19
app/public/report/js/rpt_print.js

@@ -5,23 +5,20 @@
 let rptPrintHelper = {
     preview: function () {
         if (zTreeOprObj.checkedRptTplNodes && zTreeOprObj.checkedRptTplNodes.length > 0) {
-            let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
-            rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, null, null, null);
-            let params = rptControlObj.creatCommonExportParam(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
-            params.rpt_ids = refRptTplIds;
-            params.rpt_bill_tpl_ids = refBillSumPrjsIds;
-            params.rpt_glj_tpl_ids = refGljSumPrjsIds;
-            CommonAjax.postEx("report_api/getMultiReports", params, 10000, true,
+            let refRptTplIds = [];
+            rptControlObj.getTplIdsCommon(refRptTplIds, null);
+            let params = rptControlObj.creatCommonExportParam(refRptTplIds);
+            CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken'),
                 function(result){
                     //sessionStorage.currentPageData = JSON.stringify(zTreeOprObj.currentRptPageRst);
-                    sessionStorage.multiRptsData = JSON.stringify(result);
+                    sessionStorage.multiRptsData = JSON.stringify(result.data);
                     sessionStorage.pageSize = rptControlObj.getCurrentPageSize();
                     sessionStorage.orientation = rptControlObj.getCurrentOrientation();
                     sessionStorage.scaleFactor = 1;
                     if (sessionStorage.pageSize === 'A3') {
-                        window.open('/rpt_printA3');
+                        window.open('/printReport/A3');
                     } else {
-                        window.open('/rpt_print');
+                        window.open('/printReport/A4');
                     }
                 },
                 function(failRst){
@@ -36,15 +33,6 @@ let rptPrintHelper = {
         } else {
             //不可能的branch
         }
-        // if (zTreeOprObj.currentRptPageRst) {
-        //     sessionStorage.currentPageData = JSON.stringify(zTreeOprObj.currentRptPageRst);
-        //     sessionStorage.pageSize = rptControlObj.getCurrentPageSize();
-        //     sessionStorage.orientation = rptControlObj.getCurrentOrientation();
-        //     sessionStorage.scaleFactor = 1;
-        //     window.open('/rpt_print');
-        // } else {
-        //     sessionStorage.currentPageData = null;
-        // }
     },
     previewSvgData: function() {
         //

+ 2 - 0
app/router.js

@@ -169,7 +169,9 @@ module.exports = app => {
     // 报表
     app.get('/tender/:id/report', sessionAuth, tenderCheck, 'reportController.index');
     app.get('/tender/:id/measure/stage/:order/report', sessionAuth, tenderCheck, stageCheck, 'reportController.index');
+    app.get('/printReport/:size', sessionAuth, 'reportController.showPrintPage');
     app.post('/tender/report_api/getReport', sessionAuth, 'reportController.getReport');
+    app.post('/tender/report_api/getMultiReports', sessionAuth, 'reportController.getMultiReportsEx');
     app.post('/tender/report_api/createSignatureRole', sessionAuth, 'signatureController.createSignatureRole');
     app.post('/tender/report_api/updateRoleRelationship', sessionAuth, 'signatureController.updateRoleRel');
     // 计量附件

+ 12 - 0
app/service/rpt_tpl.js

@@ -34,6 +34,18 @@ module.exports = app => {
             return list;
         }
 
+        async getAllTplByIds(rpt_ids) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('id', {
+                value: rpt_ids,
+                operate: 'in',
+            });
+            this.sqlBuilder.columns = ['id', 'rpt_type', 'rpt_tpl_name', 'rpt_content'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const list = await this.db.query(sql, sqlParam);
+            return list;
+        }
+
         async copyAndCreateTemplate(refTpl) {
             let rst = null;
             this.transaction = await this.db.beginTransaction();

+ 7 - 3
app/view/report/index.ejs

@@ -36,7 +36,7 @@
                         <div class="print-toolsbar">
                             <div class="panel">
                                 <div class="panel-body" id="print_div">
-                                    <button class="btn btn-outline-primary btn-sm" type="button">
+                                    <button class="btn btn-outline-primary btn-sm" type="button" onclick="rptPrintHelper.preview()">
                                         <i class="fa fa-print"></i><br>
                                         打印 <span id="checkCountPrint" class="badge badge-primary">0</span>
                                     </button>
@@ -45,8 +45,9 @@
                             <div class="panel">
                                 <div class="panel-body" id="export_div">
                                     <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
-                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#export_excel"><i class="fa fa-file-excel-o"></i> Excel <span class="badge badge-primary">0</span></button>
-                                        <button type="button" class="btn btn-outline-primary btn-sm"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-primary">0</span></button>
+                                        <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" onclick="rptControlObj.getPDFEx()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-primary">0</span></button>
                                     </div>
                                 </div>
                                 <div class="panel-foot text-muted">
@@ -156,6 +157,7 @@
 </script>
 
 <script type="text/javascript">  autoFlashHeight();</script>
+<script type="text/javascript" src="/public/jspdf/jspdf.min.js"></script>
 <script src="/public/js/datepicker/datepicker.min.js"></script>
 <script src="/public/js/datepicker/datepicker.zh.js"></script>
 
@@ -178,6 +180,7 @@
 <script type="text/javascript" src="/public/report/js/jpc_output.js"></script>
 <script type="text/javascript" src="/public/report/js/rpt_print.js"></script>
 <script type="text/javascript" src="/public/report/js/rpt_signature.js"></script>
+<script type="text/javascript" src="/public/report/js/rpt_jspdf.js"></script>
 
 <script type="text/javascript">
     const topTreeNodesValue = <%- rpt_tpl_data %>;
@@ -185,6 +188,7 @@
     CUST_CFG = JSON.parse(CUST_CFG[0].cfg_content);
     const PROJECT_ID = <%- project_id %>;
     const TENDER_ID = <%- tender_id %>;
+    const TENDER_INFO = <%- tenderInfo %>;
     const STAGE_ID = <%- stg_id %>;
     const STAGE_ORDER = <%- stg_order %>;
     const STAGE_TIMES = <%- stg_times %>;

+ 0 - 38
app/view/report/rpt_all_popup.ejs

@@ -105,44 +105,6 @@
         </div>
     </div>
 </div>
-<div class="modal fade" id="export" data-backdrop="static">
-    <div class="modal-dialog" role="document">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h5 class="modal-title">选择导出格式</h5>
-                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                    <span aria-hidden="true">&times;</span>
-                </button>
-            </div>
-            <div class="modal-body">
-                <div class="row">
-                    <div class="col-6">
-                        <a class="btn btn-block btn-outline-secondary" id="PDF_TYPE" onclick="rptControlObj.changeType('PDF')">
-                            <!-- <i class="fa fa-check-square pull-right"></i> -->
-                            <div class="card-body text-center">
-                                <h1 class="display-3"><i class="fa fa-file-pdf-o"></i></h1>
-                                <h1>PDF</h1>
-                            </div>
-                        </a>
-                    </div>
-                    <div class="col-6">
-                        <a class="btn btn-block btn-primary" id="EXCEL_TYPE" onclick="rptControlObj.changeType('Excel')">
-                            <!-- <i class="fa fa-check-square pull-right"></i> -->
-                            <div class="card-body text-center">
-                                <h1 class="display-3"><i class="fa fa-file-excel-o"></i></h1>
-                                <h1>Excel</h1>
-                            </div>
-                        </a>
-                    </div>
-                </div>
-            </div>
-            <div class="modal-footer">
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
-                <a onclick="rptControlObj.outputRpt();" class="btn btn-primary">确定</a>
-            </div>
-        </div>
-    </div>
-</div>
 <div class="modal fade" id="export_excel" data-backdrop="static">
     <div class="modal-dialog" role="document">
         <div class="modal-content">

+ 6 - 6
app/view/report/rpt_print.ejs

@@ -3,6 +3,11 @@
 <head>
     <meta charset="UTF-8">
     <title></title>
+    <script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="/public/report/js/jpc_output_value_define.js"></script>
+    <script type="text/javascript" src="/public/report/js/jpc_output.js"></script>
+    <script type="text/javascript" src="/public/report/js/rpt_print.js"></script>
+    <script type="text/javascript" src="/public/report/js/rpt_preview_common.js"></script>
 </head>
 <style type="text/css">
     .pageBreakOrg {
@@ -29,12 +34,7 @@
     @page horizon1 {size: A4 landscape;}
     @page vertical1 {size: A4 portrait;}
 -->
-<script type="text/javascript" src="/web/building_saas/report/js/jpc_output_value_define.js"></script>
-<script src="/lib/jquery/jquery-3.2.1.min.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/jpc_output.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/rpt_print.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/rpt_preview_common.js"></script>
-<body onload="loading()" onbeforeunload="closing()">
+<body onload="printPageLoading()" onbeforeunload="printPageClosing()">
     <canvas id="chkCanvas" style="display:none"></canvas>
 </body>
 <SCRIPT type="text/javascript">

+ 7 - 7
app/view/report/rpt_printA3.ejs

@@ -3,6 +3,11 @@
 <head>
     <meta charset="UTF-8">
     <title></title>
+    <script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+    <script type="text/javascript" src="/public/report/js/jpc_output_value_define.js"></script>
+    <script type="text/javascript" src="/public/report/js/jpc_output.js"></script>
+    <script type="text/javascript" src="/public/report/js/rpt_print.js"></script>
+    <script type="text/javascript" src="/public/report/js/rpt_preview_common.js"></script>
 </head>
 <style type="text/css">
     .pageBreak {
@@ -13,13 +18,8 @@
     body {page: page}
     div {page: page}
 </style>
-<script type="text/javascript" src="/web/building_saas/report/js/jpc_output_value_define.js"></script>
-<script src="/lib/jquery/jquery-3.2.1.min.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/jpc_output.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/rpt_print.js"></script>
-<script type="text/javascript" src="/web/building_saas/report/js/rpt_preview_common.js"></script>
-<body onload="loading()" onbeforeunload="closing()">
-<canvas id="chkCanvas" style="display:none"></canvas>
+<body onload="printPageLoading()" onbeforeunload="printPageClosing()">
+    <canvas id="chkCanvas" style="display:none"></canvas>
 </body>
 <SCRIPT type="text/javascript">
 </SCRIPT>

+ 2 - 0
app/view/report/rpt_test_print.ejs

@@ -0,0 +1,2 @@
+<div class="panel-content">
+</div>