Browse Source

电子签名导出excel

TonyKang 5 years ago
parent
commit
6d003245e6

+ 22 - 7
app/controller/report_controller.js

@@ -153,19 +153,34 @@ module.exports = app => {
         async createExcelFilesEx(ctx) {
         async createExcelFilesEx(ctx) {
             const params = JSON.parse(ctx.request.body.params);
             const params = JSON.parse(ctx.request.body.params);
             const baseDir = this.app.baseDir;
             const baseDir = this.app.baseDir;
-            function getExcelByPageData(pageRst, rpt_name) {
+            function getExcelByPageData(pageRst, rpt_name, innerRoleRel) {
+                // console.log('in getExcelByPageData!');
+                // console.log(innerRoleRel);
+                // console.log('rpt_name: ' + rpt_name);
                 return new Promise(function(resolve, reject) {
                 return new Promise(function(resolve, reject) {
-                    rpt_xl_util.exportExcel(pageRst, params.pageSize, rpt_name, params.isOneSheet, null, null, baseDir, (err, uuidName) => {
-                        if (err) return reject(err);
-                        const fileRst = { uuid: uuidName, reportName: rpt_name };
-                        resolve(fileRst);
-                    });
+                    rpt_xl_util.exportExcel(pageRst, params.pageSize, rpt_name, params.isOneSheet, null, null, baseDir, innerRoleRel,
+                        (err, uuidName) => {
+                            if (err) return reject(err);
+                            const fileRst = { uuid: uuidName, reportName: rpt_name };
+                            resolve(fileRst);
+                        }
+                    );
                 });
                 });
             }
             }
+            const roleRelArr = await ctx.service.roleRptRel.getRoleRptRelByDetailIds(params.tender_id, params.rpt_ids);
             const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL);
             const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL);
             const runnableRst = [];
             const runnableRst = [];
             for (let idx = 0; idx < pageRstArr.length; idx++) {
             for (let idx = 0; idx < pageRstArr.length; idx++) {
-                runnableRst.push(getExcelByPageData(pageRstArr[idx], params.rpt_names[idx]));
+                let roleRel = null;
+                for (const roleR of roleRelArr) {
+                    if (roleR.rpt_id === params.rpt_ids[idx]) {
+                        roleRel = JSON.parse(roleR.rel_content);
+                        break;
+                    }
+                }
+                // console.log('roleRel.rel_content: ' + roleRel.rel_content);
+                fsUtil.writeObjToFile(pageRstArr, 'D:/GitHome/temp/testBuiltPageResult.jsp');
+                runnableRst.push(getExcelByPageData(pageRstArr[idx], params.rpt_names[idx], roleRel));
             }
             }
             const uuidRst = await Promise.all(runnableRst);
             const uuidRst = await Promise.all(runnableRst);
             ctx.body = { data: uuidRst };
             ctx.body = { data: uuidRst };

+ 3 - 0
app/reports/rpt_component/helper/jpc_helper_discrete.js

@@ -11,6 +11,9 @@ const JpcDiscreteHelper = {
     outputDiscreteInfo: function(discreteArray, bands, dataObj, unitFactor, pageStatus, segIdx, multiCols, multiColIdx, $CURRENT_RPT, customizeCfg, signatureRst, signatureDateRst) {
     outputDiscreteInfo: function(discreteArray, bands, dataObj, unitFactor, pageStatus, segIdx, multiCols, multiColIdx, $CURRENT_RPT, customizeCfg, signatureRst, signatureDateRst) {
         const rst = [];
         const rst = [];
         if (discreteArray && dataObj) {
         if (discreteArray && dataObj) {
+            if (Array.isArray(signatureRst)) {
+                signatureRst.splice(0, signatureRst.length);
+            }
             for (let i = 0; i < discreteArray.length; i++) {
             for (let i = 0; i < discreteArray.length; i++) {
                 const band = bands[discreteArray[i][JV.PROP_BAND_NAME]];
                 const band = bands[discreteArray[i][JV.PROP_BAND_NAME]];
                 if (band && pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] === true) {
                 if (band && pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] === true) {

+ 2 - 0
app/reports/rpt_component/jpc_flow_tab.js

@@ -827,6 +827,8 @@ JpcFlowTabSrv.prototype.createNew = function() {
                 // 2.6 Discrete
                 // 2.6 Discrete
                 if (pi === 0) {
                 if (pi === 0) {
                     tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT, customizeCfg, me.signatureRst, me.signatureDateRst));
                     tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[FLOW_NODE_STR][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, me.pageStatusLst[actualPage - 1], segIdx, 1, pi, $CURRENT_RPT, customizeCfg, me.signatureRst, me.signatureDateRst));
+                    // console.log('current page: ' + page);
+                    // console.log(me.signatureRst);
                 }
                 }
             }
             }
         }
         }

+ 320 - 92
app/reports/util/rpt_excel_util.js

@@ -386,61 +386,132 @@ function writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage
     }
     }
     return rst;
     return rst;
 }
 }
+function getProperSignatureArea(cell, control) {
+    // 约定默认长宽比例是2:1,图片分辨率是600*300
+    const rst = [0, 0, 0, 0]; // left, top, right, bottom
+    if (cell && cell[JV.PROP_AREA]) {
+        let width = cell[JV.PROP_AREA][JV.PROP_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT],
+            height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+        if (width > height * 2) {
+            width = height * 2;
+        } else {
+            height = width / 2;
+        }
+        switch (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]]) {
+            case 'left':
+                rst[0] = cell[JV.PROP_AREA][JV.PROP_LEFT];
+                rst[1] = cell[JV.PROP_AREA][JV.PROP_TOP];
+                rst[2] = rst[0] + width;
+                rst[3] = rst[1] + height;
+                break;
+            case 'right':
+                rst[2] = cell[JV.PROP_AREA][JV.PROP_RIGHT];
+                rst[3] = cell[JV.PROP_AREA][JV.PROP_BOTTOM];
+                rst[0] = rst[2] - width;
+                rst[1] = rst[3] - height;
+                break;
+            default:
+                // center
+                rst[0] = (cell[JV.PROP_AREA][JV.PROP_LEFT] + cell[JV.PROP_AREA][JV.PROP_RIGHT] - width) / 2;
+                rst[1] = cell[JV.PROP_AREA][JV.PROP_TOP];
+                rst[2] = rst[0] + width;
+                rst[3] = rst[1] + height;
+                break;
+        }
+    }
+    // rst[0] = rst[0] + JpcCanvasOutput.offsetX;
+    // rst[2] = rst[2] + JpcCanvasOutput.offsetX;
+    // rst[1] = rst[1] + JpcCanvasOutput.offsetY;
+    // rst[3] = rst[3] + JpcCanvasOutput.offsetY;
+    return rst;
+}
+function preAnalyzePos(pageData, sheetData, xPos, yPos, yMultiPos) {
+    let cell;
+    let pos;
+    const private_array_sort = function(i1, i2) {
+        return (i1 - i2);
+    };
+    const private_set_cell_pos = function(theCell, theXPos, theYPos) {
+        pos = theCell[JV.PROP_AREA][JV.PROP_LEFT];
+        if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
+        pos = theCell[JV.PROP_AREA][JV.PROP_RIGHT];
+        if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
+        pos = theCell[JV.PROP_AREA][JV.PROP_TOP];
+        if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
+        pos = theCell[JV.PROP_AREA][JV.PROP_BOTTOM];
+        if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
+    };
+    const private_set_cell_pos2 = function(area, theXPos, theYPos) {
+        pos = area[0];
+        if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
+        pos = area[2];
+        if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
+        pos = area[1];
+        if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
+        pos = area[3];
+        if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
+    };
+    const self_analyze_sheet_pos = function(theShtData, theXPos, theYPos) {
+        for (let i = 0; i < theShtData[JV.PROP_CELLS].length; i++) {
+            cell = theShtData[JV.PROP_CELLS][i];
+            private_set_cell_pos(cell, theXPos, theYPos);
+        }
+        for (let i = 0; i < theShtData[JV.PROP_SIGNATURE_CELLS].length; i++) {
+            cell = theShtData[JV.PROP_SIGNATURE_CELLS][i];
+            private_set_cell_pos(cell, theXPos, theYPos);
+            let cellControl;
+            if (typeof cell[JV.PROP_CONTROL] === 'string') {
+                cellControl = pageData[JV.NODE_CONTROL_COLLECTION][cell[JV.PROP_CONTROL]];
+            } else {
+                cellControl = cell[JV.PROP_CONTROL];
+            }
+            const area = getProperSignatureArea(cell, cellControl);
+            private_set_cell_pos2(area, theXPos, theYPos);
+        }
+        for (let i = 0; i < theShtData[JV.PROP_SIGNATURE_DATE_CELLS].length; i++) {
+            cell = theShtData[JV.PROP_SIGNATURE_DATE_CELLS][i];
+            private_set_cell_pos(cell, theXPos, theYPos);
+        }
+    };
+    xPos.push(0);
+    if (sheetData) {
+        // current sheet data
+        console.log('preAnalyzePos not single');
+        yPos.push(0);
+        self_analyze_sheet_pos(sheetData, xPos, yPos);
+        xPos.sort(private_array_sort);
+        yPos.sort(private_array_sort);
+    } else {
+        // total data in one sheet
+        const marginBottomPos = Math.round((pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1] - parseFloat(pageData[JV.NODE_PAGE_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM]) / 2.54) * DPI);
+        // console.log('preAnalyzePos isSingle start');
+        for (const shtItemData of pageData.items) {
+            const tmpPos = [];
+            tmpPos.push(0);
+            self_analyze_sheet_pos(shtItemData, xPos, tmpPos);
+            tmpPos.sort(private_array_sort);
+            if (marginBottomPos - tmpPos[tmpPos.length - 1] > 10) {
+                // 此逻辑是为了防止打印跨页(假设有些报表模板高度设置离底部margin还好远,导出excel后预览时会发现跨页现象(即下一页的某几行数据会挪到前一页来预览))
+                tmpPos.push(marginBottomPos - 10);
+            }
+            // console.log('preAnalyzePos push to yMultiPos');
+            yMultiPos.push(tmpPos);
+        }
+        xPos.sort(private_array_sort);
+        yPos.splice(0, yPos.length);
+        for (const p of yMultiPos[0]) {
+            yPos.push(p);
+        }
+    }
+}
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, appointedMergeBand, hasSignature, sheetIdx) {
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, appointedMergeBand, hasSignature, sheetIdx) {
     const rst = [];
     const rst = [];
     const xPos = [];
     const xPos = [];
-    let yPos = [];
+    const yPos = [];
     const yMultiPos = [];
     const yMultiPos = [];
     let currentMergeBorder = null;
     let currentMergeBorder = null;
     const headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     const headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
     let currentPageMergePos = null; // 在 JV.PAGING_OPTION_INFINITY 场合应用
     let currentPageMergePos = null; // 在 JV.PAGING_OPTION_INFINITY 场合应用
-    const private_pre_analyze_pos = function() {
-        let cell;
-        let pos;
-        const private_array_sort = function(i1, i2) {
-            let rst = 0;
-            if (i1 > i2) { rst = 1; } else
-            if (i1 < i2) rst = -1;
-            return rst;
-        };
-        const self_analyze_sheet_pos = function(theShtData, theXPos, theYPos) {
-            for (let i = 0; i < theShtData.cells.length; i++) {
-                cell = theShtData.cells[i];
-                pos = cell[JV.PROP_AREA][JV.PROP_LEFT];
-                if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
-                pos = cell[JV.PROP_AREA][JV.PROP_RIGHT];
-                if (theXPos.indexOf(pos) < 0) theXPos.push(pos);
-                pos = cell[JV.PROP_AREA][JV.PROP_TOP];
-                if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
-                pos = cell[JV.PROP_AREA][JV.PROP_BOTTOM];
-                if (theYPos.indexOf(pos) < 0) theYPos.push(pos);
-            }
-        };
-        xPos.push(0);
-        if (sheetData) {
-            // current sheet data
-            yPos.push(0);
-            self_analyze_sheet_pos(sheetData, xPos, yPos);
-            xPos.sort(private_array_sort);
-            yPos.sort(private_array_sort);
-        } else {
-            // total data in one sheet
-            const marginBottomPos = Math.round((pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1] - parseFloat(pageData[JV.NODE_PAGE_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM]) / 2.54) * DPI);
-            for (const shtItemData of pageData.items) {
-                const tmpPos = [];
-                tmpPos.push(0);
-                self_analyze_sheet_pos(shtItemData, xPos, tmpPos);
-                tmpPos.sort(private_array_sort);
-                if (marginBottomPos - tmpPos[tmpPos.length - 1] > 10) {
-                    // 此逻辑是为了防止打印跨页(假设有些报表模板高度设置离底部margin还好远,导出excel后预览时会发现跨页现象(即下一页的某几行数据会挪到前一页来预览))
-                    tmpPos.push(marginBottomPos - 10);
-                }
-                yMultiPos.push(tmpPos);
-            }
-            xPos.sort(private_array_sort);
-            yPos = yMultiPos[0];
-        }
-    };
     const private_getCellIdxStr = function(idx) {
     const private_getCellIdxStr = function(idx) {
         let rst = 'A';
         let rst = 'A';
         if (idx < 26) {
         if (idx < 26) {
@@ -733,7 +804,7 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, ap
         const spanX = xPos.length - 2;
         const spanX = xPos.length - 2;
         let cellIdx = 0;
         let cellIdx = 0;
         let h = 0;
         let h = 0;
-        const self_setDataEx = function(theShtData, theYPos, offsetY) {
+        const self_setDataEx = function(theShtData, theYPos, rowOffset) {
             const rows = [];
             const rows = [];
             // 1. build full set of blank rows/cells
             // 1. build full set of blank rows/cells
             for (let i = 1; i < theYPos.length - 1; i++) {
             for (let i = 1; i < theYPos.length - 1; i++) {
@@ -741,13 +812,13 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, ap
                 h = (theYPos[i + 1] - theYPos[i]) / DPI * 25.4 / 0.3612;
                 h = (theYPos[i + 1] - theYPos[i]) / DPI * 25.4 / 0.3612;
                 h = Math.round(h * 1000) / 1000;
                 h = Math.round(h * 1000) / 1000;
                 rowObj.height = h;
                 rowObj.height = h;
-                rowObj.r = i + offsetY;
+                rowObj.r = i + rowOffset;
                 rowObj.items = [];
                 rowObj.items = [];
                 rows.push(rowObj);
                 rows.push(rowObj);
                 for (let j = 1; j < xPos.length - 1; j++) {
                 for (let j = 1; j < xPos.length - 1; j++) {
                     const colIdxStr = private_getCellIdxStr(j - 1);
                     const colIdxStr = private_getCellIdxStr(j - 1);
                     const cellObj = {};
                     const cellObj = {};
-                    cellObj.r = colIdxStr + (i + offsetY);
+                    cellObj.r = colIdxStr + (i + rowOffset);
                     cellObj.s = 0;
                     cellObj.s = 0;
                     cellObj.isBlank = true;
                     cellObj.isBlank = true;
                     rows[i - 1].items.push(cellObj);
                     rows[i - 1].items.push(cellObj);
@@ -786,7 +857,7 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, ap
             }
             }
             // 3. then fill up rst
             // 3. then fill up rst
             for (let i = 0; i < rows.length; i++) {
             for (let i = 0; i < rows.length; i++) {
-                rst.push('<row r="' + (i + 1 + offsetY) + '" spans="1:' + spanX + '" ht="' + rows[i].height + '" customHeight="1">');
+                rst.push('<row r="' + (i + 1 + rowOffset) + '" spans="1:' + spanX + '" ht="' + rows[i].height + '" customHeight="1">');
                 for (let j = 0; j < rows[i].items.length; j++) {
                 for (let j = 0; j < rows[i].items.length; j++) {
                     const cellObj = rows[i].items[j];
                     const cellObj = rows[i].items[j];
                     if (cellObj.v === undefined) {
                     if (cellObj.v === undefined) {
@@ -809,21 +880,23 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, ap
             self_setDataEx(sheetData, yPos, 0);
             self_setDataEx(sheetData, yPos, 0);
         } else {
         } else {
             // total data in one sheet
             // total data in one sheet
-            let cnt = 0;
+            let rowOffset = 0;
             for (let i = 0; i < pageData.items.length; i++) {
             for (let i = 0; i < pageData.items.length; i++) {
                 const shtItemData = pageData.items[i];
                 const shtItemData = pageData.items[i];
                 currentPageMergePos = shtItemData[JV.PAGE_SPECIAL_MERGE_POS];
                 currentPageMergePos = shtItemData[JV.PAGE_SPECIAL_MERGE_POS];
                 currentMergeBorder = shtItemData[JV.PROP_PAGE_MERGE_BORDER];
                 currentMergeBorder = shtItemData[JV.PROP_PAGE_MERGE_BORDER];
                 const tmpPos = yMultiPos[i];
                 const tmpPos = yMultiPos[i];
                 cellIdx = 0;
                 cellIdx = 0;
-                self_setDataEx(shtItemData, tmpPos, cnt);
-                cnt += tmpPos.length - 2;
+                self_setDataEx(shtItemData, tmpPos, rowOffset);
+                rowOffset += tmpPos.length - 2;
             }
             }
         }
         }
         rst.push('</sheetData>');
         rst.push('</sheetData>');
     };
     };
 
 
-    private_pre_analyze_pos();
+    preAnalyzePos(pageData, sheetData, xPos, yPos, yMultiPos);
+    // console.log('yMultiPos');
+    // console.log(yMultiPos);
     rst.push(dftHeadXml + '\r\n');
     rst.push(dftHeadXml + '\r\n');
     rst.push('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
     rst.push('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
     const colStr = private_getCellIdxStr(xPos.length - 3);
     const colStr = private_getCellIdxStr(xPos.length - 3);
@@ -857,7 +930,7 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj, ap
     rst.push('</worksheet>');
     rst.push('</worksheet>');
     return rst;
     return rst;
 }
 }
-function writeSheetRels(sheetIdx) {
+function writeWorkSheetRels(sheetIdx) {
     const rst = [];
     const rst = [];
     rst.push('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
     rst.push('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
     rst.push('<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">');
     rst.push('<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">');
@@ -878,19 +951,138 @@ function writeImage(path, pic, baseDir) {
 }
 }
 function writeDrawings(pageData, signKeyArr, signPathArr, isSinglePage) {
 function writeDrawings(pageData, signKeyArr, signPathArr, isSinglePage) {
     const rst = [];
     const rst = [];
-    let sheetIdx = 0;
+    console.log('isSinglePage: ' + isSinglePage);
     if (isSinglePage) {
     if (isSinglePage) {
-        rst.push(writeDrawing(pageData, null, signKeyArr, signPathArr, sheetIdx));
+        rst.push(writeDrawing(pageData, null, signKeyArr, signPathArr, 0));
     } else {
     } else {
         for (let i = 0; i < pageData.items.length; i++) {
         for (let i = 0; i < pageData.items.length; i++) {
-            rst.push(writeDrawing(pageData, pageData.items[i], signKeyArr, signPathArr, sheetIdx));
-            sheetIdx++;
+            rst.push(writeDrawing(pageData, pageData.items[i], signKeyArr, signPathArr, i));
         }
         }
     }
     }
     return rst;
     return rst;
 }
 }
 function writeDrawing(pageData, sheetData, signKeyArr, signPathArr, sheetIdx) {
 function writeDrawing(pageData, sheetData, signKeyArr, signPathArr, sheetIdx) {
-    //
+    const rst = [];
+    const xPos = [];
+    const yPos = [];
+    const yMultiPos = [];
+
+    const private_setSheetDrawingCellData = function(signCell, theYPos, startPicIdx, offsetRow) {
+        let cellControl;
+        if (typeof signCell[JV.PROP_CONTROL] === 'string') {
+            cellControl = pageData[JV.NODE_CONTROL_COLLECTION][signCell[JV.PROP_CONTROL]];
+        } else {
+            cellControl = signCell[JV.PROP_CONTROL];
+        }
+        const area = getProperSignatureArea(signCell, cellControl);
+
+        // 1. from
+        // let colIdx = xPos.indexOf(signCell[JV.PROP_AREA][JV.PROP_LEFT]);
+        // let rowIdx = theYPos.indexOf(signCell[JV.PROP_AREA][JV.PROP_TOP]) + offsetRow; // 这里要考虑Row的偏移量(多页在同同一个sheet输出)
+        let colIdx = xPos.indexOf(area[0]);
+        let rowIdx = theYPos.indexOf(area[1]) + offsetRow; // 这里要考虑Row的偏移量(多页在同同一个sheet输出)
+        // 因为 xPos, theYPos的首位是0,所以还需要减1
+        colIdx--;
+        rowIdx--;
+        rst.push('<xdr:twoCellAnchor editAs="oneCell">');
+        rst.push('<xdr:from>');
+        rst.push('<xdr:col>' + colIdx + '</xdr:col>');
+        rst.push('<xdr:colOff>0</xdr:colOff>');
+        rst.push('<xdr:row>' + rowIdx + '</xdr:row>');
+        rst.push('<xdr:rowOff>0</xdr:rowOff>');
+        rst.push('</xdr:from>');
+        // 2. to
+        colIdx = xPos.indexOf(area[2]);
+        rowIdx = theYPos.indexOf(area[3]) + offsetRow;
+        // 因为 xPos, theYPos的首位是0,所以还需要减1
+        colIdx--;
+        rowIdx--;
+        rst.push('<xdr:to>');
+        rst.push('<xdr:col>' + colIdx + '</xdr:col>');
+        rst.push('<xdr:colOff>0</xdr:colOff>');
+        rst.push('<xdr:row>' + rowIdx + '</xdr:row>');
+        rst.push('<xdr:rowOff>0</xdr:rowOff>');
+        rst.push('</xdr:to>');
+        // 3. pic
+        rst.push('<xdr:pic>');
+        // 3.1
+        rst.push('<xdr:nvPicPr>');
+        rst.push('<xdr:cNvPr id="' + startPicIdx + '" name="图片 ' + startPicIdx + '"/>');
+        rst.push('<xdr:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1"/></xdr:cNvPicPr>');
+        rst.push('</xdr:nvPicPr>');
+        // 3.2
+        rst.push('<xdr:blipFill>');
+        // 重点!!!
+        const picIdx = signKeyArr.indexOf(signCell.signature_name) + 1;
+        // 3.2.1
+        rst.push('<a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="rId' + picIdx + '" cstate="print">');
+        rst.push('<a:extLst>');
+        rst.push('<a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">'); // 参考excel本身,都是固定的uri
+        rst.push('<a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>');
+        rst.push('</a:ext>');
+        rst.push('</a:extLst>');
+        rst.push('</a:blip>');
+        // 3.2.2
+        rst.push('<a:srcRect/>');
+        // 3.2.3
+        rst.push('<a:stretch><a:fillRect/></a:stretch>');
+        rst.push('</xdr:blipFill>');
+        // 3.3
+        rst.push('<xdr:spPr bwMode="auto">');
+        // 3.3.1
+        rst.push('<a:xfrm>');
+        // 以下经过Excel及WPS的测试,这数据好像没什么意义,都设为0
+        rst.push('<a:off x="0" y="0"/>');
+        rst.push('<a:ext cx="0" cy="0"/>');
+        rst.push('</a:xfrm>');
+        // 3.3.2
+        rst.push('<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>')
+        // 3.3.3
+        rst.push('<a:noFill/>');
+        // 3.3.4
+        rst.push('<a:extLst>');
+        rst.push('<a:ext uri="{909E8E84-426E-40DD-AFC4-6F175D3DCCD1}">');
+        rst.push('<a14:hiddenFill xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">');
+        rst.push('<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>');
+        rst.push('</a14:hiddenFill>');
+        rst.push('</a:ext>');
+        rst.push('</a:extLst>');
+        // 收尾
+        rst.push('</xdr:spPr>');
+        rst.push('</xdr:pic>');
+        // 4. client Data
+        rst.push('<xdr:clientData/>');
+        rst.push('</xdr:twoCellAnchor>');
+    }
+    preAnalyzePos(pageData, sheetData, xPos, yPos, yMultiPos);
+    rst.push('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
+    rst.push('<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">');
+    if (sheetData) {
+        let startPicIdx = 2;
+        for (const sCell of sheetData[JV.PROP_SIGNATURE_CELLS]) {
+            if (signKeyArr.indexOf(sCell.signature_name) >= 0) {
+                private_setSheetDrawingCellData(sCell, yPos, startPicIdx, 0);
+                startPicIdx++;
+            }
+        }
+    } else {
+        // total data in one sheet
+        let rowOffset = 0;
+        for (let i = 0; i < pageData.items.length; i++) {
+            const shtItemData = pageData.items[i];
+            const tmpPos = yMultiPos[i];
+            let startPicIdx = 2;
+            for (const sCell of shtItemData[JV.PROP_SIGNATURE_CELLS]) {
+                if (signKeyArr.indexOf(sCell.signature_name) >= 0) {
+                    private_setSheetDrawingCellData(sCell, tmpPos, startPicIdx, rowOffset);
+                    startPicIdx++;
+                }
+            }
+            rowOffset += tmpPos.length - 2;
+        }
+    }
+    rst.push('</xdr:wsDr>');
+    return rst;
 }
 }
 function writeDrawingsRels(amt) {
 function writeDrawingsRels(amt) {
     const rst = [];
     const rst = [];
@@ -918,23 +1110,48 @@ function mergeProperties(orgObj, newObj) {
         }
         }
     }
     }
 }
 }
-function checkAndSetSignatureCache(pageData, signKeyArr, signPathArr) {
+function checkAndSetSignatureCache(pageData, signKeyArr, signPathArr, roleRel) {
     // 备注:电子签名是以图形的方式处理,一页可以有多个签名,多页的签名基本是引用同样的图片,在这里先处理一下,后期统一引用。
     // 备注:电子签名是以图形的方式处理,一页可以有多个签名,多页的签名基本是引用同样的图片,在这里先处理一下,后期统一引用。
     //      另:以后的图片(在电子签名(signature_cells)以外的图片)会单独处理(如计算图等)
     //      另:以后的图片(在电子签名(signature_cells)以外的图片)会单独处理(如计算图等)
     let rst = false;
     let rst = false;
+    let chkRoles = [];
+    if (roleRel instanceof Array) {
+        chkRoles = roleRel;
+    } else {
+        chkRoles.push(roleRel);
+    }
+    // console.log(chkRoles);
     for (const page of pageData.items) {
     for (const page of pageData.items) {
         if (page[JV.PROP_SIGNATURE_CELLS] && page[JV.PROP_SIGNATURE_CELLS].length > 0) {
         if (page[JV.PROP_SIGNATURE_CELLS] && page[JV.PROP_SIGNATURE_CELLS].length > 0) {
+            // console.log('has SignatureCells!');
             for (const signature of page[JV.PROP_SIGNATURE_CELLS]) {
             for (const signature of page[JV.PROP_SIGNATURE_CELLS]) {
                 if (signKeyArr.indexOf(signature.signature_name) < 0) {
                 if (signKeyArr.indexOf(signature.signature_name) < 0) {
-                    signKeyArr.push(signature.signature_name);
-                    const signPath = { path: null, pic: null };
-                    signPathArr.push(signPath);
                     if (signature.pic) {
                     if (signature.pic) {
-                        signPath.pic = signature.pic;
-                        rst = true;
-                    } else if (signature.path) {
-                        signPath.path = signature.path;
+                        const signPath = { path: null, pic: null };
+                        signPathArr.push(signPath);
+                        signPath.pic = signature.pic; // 历史报表
+                        signKeyArr.push(signature.signature_name);
                         rst = true;
                         rst = true;
+                    } else {
+                        for (const role of chkRoles) {
+                            if (signature.signature_name === role.signature_name) {
+                                // console.log('signature.signature_name: ' + signature.signature_name);
+                                if (role.sign_pic) {
+                                    const signPath = { path: null, pic: null };
+                                    signPathArr.push(signPath);
+                                    signPath.pic = role.sign_pic;
+                                    signKeyArr.push(signature.signature_name);
+                                    rst = true;
+                                } else if (role.sign_path) {
+                                    const signPath = { path: null, pic: null };
+                                    signPathArr.push(signPath);
+                                    signPath.path = role.sign_path;
+                                    signKeyArr.push(signature.signature_name);
+                                    rst = true;
+                                }
+                                break;
+                            }
+                        }
                     }
                     }
                 }
                 }
             }
             }
@@ -956,7 +1173,7 @@ function base64ToStream(dataurl) {
 
 
 
 
 module.exports = {
 module.exports = {
-    exportExcel: function(pageData, paperSize, fName, options, custSheetNames, custSheetMergeBands, baseDir, callback) {
+    exportExcel: function(pageData, paperSize, fName, options, custSheetNames, custSheetMergeBands, baseDir, roleRel, callback) {
         const rptOptions = ({ singlePage: false, fileName: 'report' });
         const rptOptions = ({ singlePage: false, fileName: 'report' });
         if (options === 'true' || options === true) {
         if (options === 'true' || options === true) {
             rptOptions.singlePage = true;
             rptOptions.singlePage = true;
@@ -965,8 +1182,11 @@ module.exports = {
         const sheets = [];
         const sheets = [];
         const signKeyArr = [];
         const signKeyArr = [];
         const signPathArr = [];
         const signPathArr = [];
-        // const hasSignature = checkAndSetSignatureCache(pageData, signKeyArr, signPathArr);
-        const hasSignature = false;
+        // console.log('in exportExcel!');
+        // console.log(roleRel);
+        const hasSignature = (roleRel !== null) ? checkAndSetSignatureCache(pageData, signKeyArr, signPathArr, roleRel) : false;
+        // const hasSignature = false;
+        console.log('hasSignature: ' + hasSignature);
         if (isSinglePage) {
         if (isSinglePage) {
             sheets.push({ sheetName: '全部页' });
             sheets.push({ sheetName: '全部页' });
         } else {
         } else {
@@ -1021,46 +1241,52 @@ module.exports = {
                 zip_media.file(file, data, { compression: 'DEFLATE' });
                 zip_media.file(file, data, { compression: 'DEFLATE' });
             }
             }
             // 5.2
             // 5.2
-            const zip_drawings = zip_xl.folder('drwaings');
-            data = writeDrawings(pageData, signKeyArr, signPathArr);
-            file = 'drawing1.xml.rels';
-            zip_drawings.file(file, data, { compression: 'DEFLATE' });
+            const zip_drawings = zip_xl.folder('drawings');
+            data = writeDrawings(pageData, signKeyArr, signPathArr, isSinglePage);
+            // console.log('isSinglePage: ' + isSinglePage);
+            // console.log(data);
+            for (let psIdx = 0; psIdx < data.length; psIdx++) {
+                file = 'drawing' + (psIdx + 1) + '.xml';
+                // console.log('drawing1' + (psIdx + 1) + '.xml data');
+                // console.log(data);
+                zip_drawings.file(file, data[psIdx].join(''), { compression: 'DEFLATE' });
+            }
             // 5.3
             // 5.3
             const zip_drawings_rels = zip_drawings.folder('_rels');
             const zip_drawings_rels = zip_drawings.folder('_rels');
-            data = writeDrawingsRels(signPathArr.length);
+            data = writeDrawingsRels(signPathArr.length); // 这个一个文件搞定算了,无需多个文件
+            // console.log('drawing1.xml.rels data');
+            // console.log(data);
             file = 'drawing1.xml.rels';
             file = 'drawing1.xml.rels';
-            zip_drawings_rels.file(file, data, { compression: 'DEFLATE' });
+            zip_drawings_rels.file(file, data.join(''), { compression: 'DEFLATE' });
         }
         }
         // 6.
         // 6.
-        const zip_worksheets = zip_xl.folder('worksheets');
+        const zip_xl_worksheets = zip_xl.folder('worksheets');
         const sharedStrList = [];
         const sharedStrList = [];
         const stylesObj = {};
         const stylesObj = {};
         data = writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage, custSheetMergeBands, hasSignature);
         data = writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage, custSheetMergeBands, hasSignature);
         if (isSinglePage) {
         if (isSinglePage) {
             for (let i = 0; i < 1; i++) {
             for (let i = 0; i < 1; i++) {
                 file = 'sheet' + (i + 1) + '.xml';
                 file = 'sheet' + (i + 1) + '.xml';
-                zip_worksheets.file(file, data[i].join(''), { compression: 'DEFLATE' });
+                zip_xl_worksheets.file(file, data[i].join(''), { compression: 'DEFLATE' });
             }
             }
         } else {
         } else {
             for (let i = 0; i < data.length; i++) {
             for (let i = 0; i < data.length; i++) {
                 file = 'sheet' + (i + 1) + '.xml';
                 file = 'sheet' + (i + 1) + '.xml';
-                zip_worksheets.file(file, data[i].join(''), { compression: 'DEFLATE' });
+                zip_xl_worksheets.file(file, data[i].join(''), { compression: 'DEFLATE' });
             }
             }
         }
         }
         // 7.
         // 7.
         if (hasSignature) {
         if (hasSignature) {
-            const zip_worksheets_rels = zip_xl.folder('_rels');
+            const zip_xl_worksheets_rels = zip_xl_worksheets.folder('_rels');
             if (isSinglePage) {
             if (isSinglePage) {
-                for (let i = 0; i < 1; i++) {
-                    data = writeSheetRels(0);
-                    file = 'sheet' + (i + 1) + '.xml.rels';
-                    zip_worksheets_rels.file(file, data[i].join(''), { compression: 'DEFLATE' });
-                }
+                data = writeWorkSheetRels(0);
+                file = 'sheet1.xml.rels';
+                zip_xl_worksheets_rels.file(file, data.join(''), { compression: 'DEFLATE' });
             } else {
             } else {
                 for (let i = 0; i < data.length; i++) {
                 for (let i = 0; i < data.length; i++) {
-                    data = writeSheetRels(0);
+                    data = writeWorkSheetRels(i);
                     file = 'sheet' + (i + 1) + '.xml.rels';
                     file = 'sheet' + (i + 1) + '.xml.rels';
-                    zip_worksheets_rels.file(file, data[i].join(''), { compression: 'DEFLATE' });
+                    zip_xl_worksheets_rels.file(file, data.join(''), { compression: 'DEFLATE' });
                 }
                 }
             }
             }
         }
         }
@@ -1090,7 +1316,7 @@ module.exports = {
         }
         }
     },
     },
 
 
-    exportExcelInOneBook: function(pageDataArray, paperSize, fName, baseDir, callback) {
+    exportExcelInOneBook: function(pageDataArray, paperSize, fName, baseDir, roleRelArr, callback) {
         const me = this;
         const me = this;
         const newPageData = {};
         const newPageData = {};
         // 1. 重新编排一下数据,把一份报表的pageData合并到一起作为一个Sheet输出(需要重新调整数据纵向坐标),多份报表数据就形成多个Sheet
         // 1. 重新编排一下数据,把一份报表的pageData合并到一起作为一个Sheet输出(需要重新调整数据纵向坐标),多份报表数据就形成多个Sheet
@@ -1179,7 +1405,9 @@ module.exports = {
                 newPageData.items.push(pageItem);
                 newPageData.items.push(pageItem);
             }
             }
             // 3. everything is ok, then call me
             // 3. everything is ok, then call me
-            me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, custMergeBands, baseDir, callback);
+            // let roleRel = null; // 未来调用的时候,这个属性要从外面给!!!
+            // roleRelArr
+            me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, custMergeBands, baseDir, null, callback);
             // fsUtil.writeObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
             // fsUtil.writeObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
         } catch (e) {
         } catch (e) {
             console.log(e);
             console.log(e);