瀏覽代碼

电子签名初步实现

TonyKang 5 年之前
父節點
當前提交
b856f8fe73

+ 2 - 0
app/controller/report_controller.js

@@ -32,6 +32,7 @@ module.exports = app => {
                 const treeNodes = await ctx.service.rptTreeNode.getNodesByProjectId([-1, tender.data.project_id]);
                 const custCfg = await ctx.service.rptCustomizeCfg.getCustomizeCfgByUserId('Administrator');
                 const stageList = await ctx.service.stage.getValidStagesShort(tender.id);
+                const prjAccList = await ctx.service.projectAccount.getAllAccountByProjectId(tender.data.project_id);
                 // console.log(maxStageAmt[0].maxAmt);
                 if (stage !== null && stage !== undefined) {
                     stage_id = stage.id;
@@ -51,6 +52,7 @@ module.exports = app => {
                     stg_times: stage_times,
                     stg_status: stage_status,
                     stage_list: JSON.stringify(stageList),
+                    prj_account_list: JSON.stringify(prjAccList),
                     tenderMenu,
                     preUrl: '/tender/' + tender.id,
                     measureType,

二進制
app/public/images/p1.png


二進制
app/public/images/p2.png


+ 12 - 8
app/public/report/js/jpc_output.js

@@ -355,15 +355,15 @@ let JpcCanvasOutput = {
             if (cell.path) {
                 const img = new Image();
                 img.src = cell.path;
-                img.onload(function() {
+                img.onload = function() {
                     private_drawImage(cell, control, img);
-                });
+                };
             } else if (cell.pic) {
                 const img = new Image();
                 img.src = cell.pic;
-                img.onload(function() {
+                img.onload = function() {
                     private_drawImage(cell, control, img);
-                });
+                };
             }
         }
         function private_getProperSignatureArea(cell, control) {
@@ -378,13 +378,13 @@ let JpcCanvasOutput = {
                     height = width / 2;
                 }
                 switch (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_HORIZON]]) {
-                    case JV.PROP_LEFT:
+                    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 JV.PROP_RIGHT:
+                    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;
@@ -399,6 +399,10 @@ let JpcCanvasOutput = {
                         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 private_drawImage(cell, control, imageData) {
@@ -435,12 +439,12 @@ let JpcCanvasOutput = {
                 private_drawCell(cell, fonts, styles, controls, newPageMergeBand);
             }
             //电子签名
-            for (let k = 0; k < page.signature_cells.length; j++) {
+            for (let k = 0; k < page.signature_cells.length; k++) {
                 let cell = page.signature_cells[k];
                 private_drawSignatureCell(cell, fonts, styles, controls, newPageMergeBand);
             }
             //电子签名日期(跟普通格子输出一样)
-            for (let k = 0; k < page.signature_date_cells.length; j++) {
+            for (let k = 0; k < page.signature_date_cells.length; k++) {
                 let cell = page.signature_date_cells[k];
                 private_drawCell(cell, fonts, styles, controls, newPageMergeBand);
             }

+ 132 - 204
app/public/report/js/rpt_main.js

@@ -21,7 +21,7 @@ let rptTplObj = {
             zTreeOprObj.getReportTemplateTree();
             zTreeOprObj.selectedPrjIDs = [];
             me.hasInitialized = true;
-            // let canvas = document.getElementById("rptCanvas");
+            zTreeOprObj.canvas = document.getElementById("rptCanvas");
             // canvas.onclick = canvasOprObj.canvasOnClick;
             // canvas.onmousemove = canvasOprObj.canvasOnMouseMove;
         }
@@ -32,11 +32,14 @@ let zTreeOprObj = {
     treeObj: null,
     prjFolderTreeObj: null,
     currentNode: null,
+    currentSelectedESignAccDom: null,
+    currentSelectedESignAccName: null,
     checkedRptTplNodes: null,
     currentRptPageRst: null,
     defReportPageCfg: null,
     currentPage: 1,
     maxPages: 0,
+    canvas: null,
     selectedPrjIDs: [],
     countChkedRptTpl: function () {
         let me = zTreeOprObj;
@@ -55,6 +58,9 @@ let zTreeOprObj = {
                 cnt++;
                 me.checkedRptTplNodes.push(me.currentNode);
             }
+            $("#print_div").find("span").each(function(cIdx,elementSpan){
+                elementSpan.innerText = cnt;
+            });
             $("#export_div").find("span").each(function(cIdx,elementSpan){
                 elementSpan.innerText = cnt;
             });
@@ -237,7 +243,7 @@ let zTreeOprObj = {
             function(result){
                 // hintBox.unWaitBox();
                 let pageRst = result.data;
-                let canvas = document.getElementById("rptCanvas");
+                let canvas = zTreeOprObj.canvas;
                 if (pageRst && pageRst.items && pageRst.items.length > 0) {
                     me.resetAfter(pageRst);
                     me.currentRptPageRst = pageRst;
@@ -251,6 +257,8 @@ let zTreeOprObj = {
                     } else {
                         canvas.height = size[1] + 50;
                     }
+                    me.resetESignature(pageRst);
+                    me.buildSelectableAccount();
                     me.showPage(1, canvas);
                 } else {
                     //返回了无数据表
@@ -264,9 +272,124 @@ let zTreeOprObj = {
             }
         );
     },
+    resetESignature: function (pageRst) {
+        let body = $('#eSignatureBodyDiv');
+        body.empty();
+        const signature_cells = [];
+        const singatureNameArr = [];
+        for (const page of pageRst.items) {
+            if (page.signature_cells) {
+                for (const sCell of page.signature_cells) {
+                    if (singatureNameArr.indexOf(sCell.signature_name) < 0) {
+                        signature_cells.push(sCell);
+                        singatureNameArr.push(sCell.signature_name);
+                    }
+                }
+            }
+        }
+        if (signature_cells.length > 0) {
+            const elementsStrArr = [];
+            for (const sCell of signature_cells) {
+                elementsStrArr.push('<div class="form-group row">');
+                elementsStrArr.push('<label for="staticEmail" class="col-sm-3 col-form-label pr-0">' + sCell.signature_name + '</label>');
+                elementsStrArr.push('<div class="col-sm-9">');
+                elementsStrArr.push('<ul class="list-group">');
+                elementsStrArr.push('<li class="list-group-item">');
+                if (sCell.path || sCell.pic) {
+                    //
+                } else {
+                    elementsStrArr.push('<a href="#add-sign" onclick="zTreeOprObj.currentSelectedESignAccDom = this; zTreeOprObj.currentSelectedESignAccName = \'' + sCell.signature_name + '\'" data-toggle="modal" data-target="#add-sign"><i class="fa fa-plus"></i> 添加签名</a>');
+                }
+                elementsStrArr.push('</li>');
+                elementsStrArr.push('</ul>');
+                elementsStrArr.push('</div>');
+                elementsStrArr.push('</div>');
+            }
+            body.append(elementsStrArr.join(' '));
+        }
+    },
+    buildSelectableAccount: function () {
+        //PRJ_ACCOUNT_LIST
+        //1. 清理所有选择项
+        // $("#project_account_select_div").empty();
+        let accDiv = $('#project_account_select_div');
+        accDiv.empty();
+        //2. 一个个加可选用户项
+        const prj_accounts = [];
+        const acc_role_keys = [];
+        for (const prjAccount of PRJ_ACCOUNT_LIST) {
+            let companyKey = prjAccount.company;
+            let roleKey = prjAccount.role;
+            if (companyKey === '') {
+                companyKey = '其他单位';
+            }
+            if (roleKey === '') {
+                roleKey = '工程师';
+            }
+            let keyIdx = acc_role_keys.indexOf(companyKey);
+            if (keyIdx < 0) {
+                acc_role_keys.push(companyKey);
+                prj_accounts.push([]);
+                keyIdx = prj_accounts.length - 1;
+                //这里先push一些 html prefix,在后面统一在push html suffix
+                prj_accounts[keyIdx].push('<ul class="list-group">');
+                prj_accounts[keyIdx].push('<li class="px-2 text-muted"><i class="fa fa-caret-down"></i> ' + companyKey + '</li>');
+            }
+            //push item
+            prj_accounts[keyIdx].push('<li class="add-sign-list-item"><a onclick="zTreeOprObj.drawEsignature(' + keyIdx + ')" class="btn-link pull-right" title="添加" data-dismiss="modal"><i class="fa fa-plus"></i></a>' +
+                prjAccount.name + '-<small class="text-muted">' + roleKey + '</small></li>');
+        }
+        for (const prjAccList of prj_accounts) {
+            prjAccList.push('</ul>');
+        }
+        for (let idx = 0; idx < prj_accounts.length; idx++) {
+            prj_accounts[idx] = prj_accounts[idx].join('');
+        }
+        accDiv.append(prj_accounts.join(''));
+    },
+    drawEsignature: function (accIdx) {
+        let dftSignSrc = '/public/images/user-sign.PNG';
+        if (PRJ_ACCOUNT_LIST[accIdx].sign_path !== '') {
+            dftSignSrc = PRJ_ACCOUNT_LIST[accIdx].sign_path;
+        }
+        //找到相关签名地方,stamp!
+        if (zTreeOprObj.currentSelectedESignAccName !== null) {
+            for (const page of zTreeOprObj.currentRptPageRst.items) {
+                if (page.signature_cells) {
+                    for (const sCell of page.signature_cells) {
+                        if (sCell.signature_name === zTreeOprObj.currentSelectedESignAccName) {
+                            sCell.path = dftSignSrc;
+                        }
+                    }
+                }
+            }
+            // 1. 删除不需要的child dom
+            let list = zTreeOprObj.currentSelectedESignAccDom.childNodes;
+            if (list && list.length > 0) {
+                for (let domIdx = list.length - 1; domIdx >= 0; domIdx--) {
+                    zTreeOprObj.currentSelectedESignAccDom.removeChild(list[domIdx]);
+                }
+            }
+            // 2. 创建已选择签名相关 dom
+            // let newDomArr = [];
+            // 2.1 canvas
+            let canvasNode = document.createElement("CANVAS");
+            canvasNode.height = "30";
+            canvasNode.style = "width: 100%";
+            //newDomArr.push('<canvas height="30" style="width: 100%"></canvas>');
+            zTreeOprObj.currentSelectedESignAccDom.appendChild(canvasNode);
+            let imgObj = new Image();
+            imgObj.src = dftSignSrc;
+            imgObj.onload = function(){
+                let ctx = canvasNode.getContext('2d');
+                ctx.drawImage(this, 0, 0, 60, 30);
+            }
+            // 2.2 date-picker
+        }
+    },
     scaleReport: function (accScale) {
         let me = zTreeOprObj;
-        let canvas = document.getElementById("rptCanvas");
+        let canvas = zTreeOprObj.canvas;
         if (accScale !== 0) {
             JpcCanvasOutput.scaleFactor += accScale;
             if (JpcCanvasOutput.scaleFactor < 0.5) JpcCanvasOutput.scaleFactor = 0.5;
@@ -278,197 +401,7 @@ let zTreeOprObj = {
         me.showPage(me.currentPage, canvas);
     },
     requestPrjFolderCommon: function () {
-        // let me = zTreeOprObj;
-        // hintBox.waitBox();
-        // $.ajax({
-        //     type:"POST",
-        //     url: '/pm/api/getProjects',
-        //     data: {'data': JSON.stringify({"user_id": userID, "compilation": projectObj.project.projectInfo.compilation})},
-        //     dataType: 'json',
-        //     cache: false,
-        //     timeout: 15000,
-        //     success: function(result){
-        //         hintBox.unWaitBox();
-        //         if (result.error === 0) {
-        //             //console.log(result.data);
-        //             let currPrjParentID = projectObj.project.projectInfo.ParentID;
-        //             let selectedProjects = [];
-        //             for (let prj of result.data) {
-        //                 if (currPrjParentID === prj.ParentID) {
-        //                     selectedProjects.push({name: prj.name, ID: prj.ID});
-        //                 }
-        //             }
-        //             $("#show_project_folder").trigger("click");
-        //             me.prjFolderTreeObj = $.fn.zTree.init($("#prjFolderTree"), rpt_prj_folder_setting, selectedProjects);
-        //             me.prjFolderTreeObj.expandAll(true);
-        //         } else {
-        //             alert('error: ' + result.message);
-        //         }
-        //     },
-        //     error: function(jqXHR, textStatus, errorThrown){
-        //         hintBox.unWaitBox();
-        //         alert('error ' + textStatus + " " + errorThrown);
-        //     }
-        // });
-    },
-    requestBillsSummaryRpt: function () {
-        let me = zTreeOprObj;
-        let nodes = me.prjFolderTreeObj.getCheckedNodes(true);
-        if (nodes.length > 0) {
-            hintBox.waitBox();
-            let params = {};
-            params.pageSize = rptControlObj.getCurrentPageSize();
-            params.rpt_tpl_id = me.currentNode.refId;
-            params.custCfg = CUST_CFG;
-            params.prjIds = [];
-            me.selectedPrjIDs = [];
-            for (let node of nodes) {
-                params.prjIds.push(node.ID);
-                me.selectedPrjIDs.push(node.ID);
-            }
-            CommonAjax.postEx("report_api/getBillsSummaryReport", params, 26000, true,
-                function(result){
-                    hintBox.unWaitBox();
-                    let pageRst = result;
-                    let canvas = document.getElementById("rptCanvas");
-                    if (pageRst && pageRst.items && pageRst.items.length > 0) {
-                        me.resetAfter(pageRst);
-                        me.currentRptPageRst = pageRst;
-                        me.maxPages = pageRst.items.length;
-                        me.currentPage = 1;
-                        me.displayPageValue();
-                        let size = JpcCanvasOutput.getReportSizeInPixel(me.currentRptPageRst, getScreenDPI());
-                        canvas.width = size[0] + 20;
-                        if (size[1] > size[0]) {
-                            canvas.height = size[1] + 100;
-                        } else {
-                            canvas.height = size[1] + 50;
-                        }
-                        me.showPage(1, canvas);
-                    } else {
-                        //返回了无数据表
-                        JpcCanvasOutput.cleanCanvas(canvas);
-                        JpcCanvasOutput.drawPageBorder(me.currentRptPageRst, canvas, getScreenDPI());
-                    }
-                }, function(err){
-                    hintBox.unWaitBox();
-                }, function(ex){
-                    hintBox.unWaitBox();
-                }
-            );
-        }
-    },
-    requestGljSummaryRpt: function () {
-        let me = zTreeOprObj;
-        let nodes = me.prjFolderTreeObj.getCheckedNodes(true);
-        if (nodes.length > 0) {
-            hintBox.waitBox();
-            let params = {};
-            params.pageSize = rptControlObj.getCurrentPageSize();
-            params.rpt_tpl_id = me.currentNode.refId;
-            params.custCfg = CUST_CFG;
-            params.prjIds = [];
-            zTreeOprObj.selectedPrjIDs = [];
-            for (let node of nodes) {
-                params.prjIds.push(node.ID);
-                zTreeOprObj.selectedPrjIDs.push(node.ID);
-            }
-            CommonAjax.postEx("report_api/getGljSummaryReport", params, 26000, true,
-                function(result){
-                    hintBox.unWaitBox();
-                    let pageRst = result;
-                    let canvas = document.getElementById("rptCanvas");
-                    if (pageRst && pageRst.items && pageRst.items.length > 0) {
-                        me.resetAfter(pageRst);
-                        me.currentRptPageRst = pageRst;
-                        me.maxPages = pageRst.items.length;
-                        me.currentPage = 1;
-                        me.displayPageValue();
-                        let size = JpcCanvasOutput.getReportSizeInPixel(me.currentRptPageRst, getScreenDPI());
-                        canvas.width = size[0] + 20;
-                        if (size[1] > size[0]) {
-                            canvas.height = size[1] + 100;
-                        } else {
-                            canvas.height = size[1] + 50;
-                        }
-                        me.showPage(1, canvas);
-                    } else {
-                        //返回了无数据表
-                        JpcCanvasOutput.cleanCanvas(canvas);
-                        JpcCanvasOutput.drawPageBorder(me.currentRptPageRst, canvas, getScreenDPI());
-                    }
-                }, function(err){
-                    hintBox.unWaitBox();
-                }, function(ex){
-                    hintBox.unWaitBox();
-                }
-            );
-        }
-    },
-    requestSumAndNormalRptForPDF: function () {
-        let rpt_names = [], bill_rpt_names = [], glj_rpt_names = [];
-        let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
-        rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, rpt_names, bill_rpt_names, glj_rpt_names);
-        let params = rptControlObj.creatCommonExportParam(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
-        params.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
-        params.rpt_names = rpt_names;
-        params.isOneSheet = true;
-
-        CommonAjax.postEx("report_api/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
-        );
-    },
-    requestSumAndNormalRptForMultiExcel: function () {
-        let rpt_names = [], bill_rpt_names = [], glj_rpt_names = [];
-        let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
-        rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, rpt_names, bill_rpt_names, glj_rpt_names);
-        let params = rptControlObj.creatCommonExportParam(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
-        params.sum_rpt_names = bill_rpt_names.concat(glj_rpt_names);
-        params.rpt_names = rpt_names;
-        params.isOneSheet = true;
-
-        CommonAjax.postEx("report_api/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
-        );
-    },
-    requestSumAndNormalRptForAllInOneExcel: function () {
-        let orgRptName = projectObj.project.projectInfo.name;
-        let refRptTplIds = [], refBillSumPrjsIds = [], refGljSumPrjsIds = [];
-        rptControlObj.getTplIdsCommon(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds, null, null, null);
-        let params = rptControlObj.creatCommonExportParam(refRptTplIds, refBillSumPrjsIds, refGljSumPrjsIds);
-        params.rptName = orgRptName;
-
-        CommonAjax.postEx("report_api/createExcelFilesInOneBook", params, WAIT_TIME_EXPORT, true, function(result){
-                if (result) {
-                    let uuIdUrls = [];
-                    let uuIdUrl =  "/report_api/getFileByUUID/" + result.uuid + "/" + stringUtil.replaceAll(result.reportName, "#", "_") + "/xlsx";
-                    uuIdUrls.push(uuIdUrl);
-                    downloadReport(uuIdUrls);
-                } else {
-                    //
-                }
-            }, null, null
-        );
+        //
     },
     showPage: function (pageNum, canvas) {
         let me = zTreeOprObj;
@@ -790,21 +723,17 @@ let rptControlObj = {
         }
     },
     firstPage: function(dom) {
-        let canvas = document.getElementById("rptCanvas");
-        zTreeOprObj.showPage(1, canvas);
+        zTreeOprObj.showPage(1, zTreeOprObj.canvas);
     },
     prePage: function(dom) {
-        let canvas = document.getElementById("rptCanvas");
-        zTreeOprObj.showPage(zTreeOprObj.currentPage - 1, canvas);
+        zTreeOprObj.showPage(zTreeOprObj.currentPage - 1, zTreeOprObj.canvas);
     },
     nextPage: function(dom) {
-        let canvas = document.getElementById("rptCanvas");
-        zTreeOprObj.showPage(zTreeOprObj.currentPage + 1, canvas);
+        zTreeOprObj.showPage(zTreeOprObj.currentPage + 1, zTreeOprObj.canvas);
     },
     lastPage: function(dom) {
         let me = zTreeOprObj;
-        let canvas = document.getElementById("rptCanvas");
-        zTreeOprObj.showPage(me.maxPages, canvas);
+        zTreeOprObj.showPage(me.maxPages, zTreeOprObj.canvas);
     },
     onKeydown: function (event, dom) {
         let me = zTreeOprObj, keyPressed = null;
@@ -820,13 +749,12 @@ let rptControlObj = {
             } catch (e) {
                 pageNum = 1;
             }
-            let canvas = document.getElementById("rptCanvas");
             if (pageNum < 1) {
                 pageNum = 1;
             } else if (pageNum > me.maxPages) {
                 pageNum = me.maxPages;
             }
-            zTreeOprObj.showPage(pageNum, canvas);
+            zTreeOprObj.showPage(pageNum, zTreeOprObj.canvas);
             return false;
         }
     },

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

@@ -32,6 +32,8 @@ const JpcDiscreteHelper = {
                                 if (Array.isArray(signatureRst)) {
                                     const map_data_field = JE.F(df[JV.PROP_FIELD_ID], $CURRENT_RPT);
                                     const signatureItem = { signature_name: map_data_field[JV.PROP_NAME], path: null, pic: null };
+                                    signatureItem[JV.PROP_CONTROL] = df[[JV.PROP_CONTROL]];
+                                    signatureItem[JV.PROP_STYLE] = df[[JV.PROP_STYLE]];
                                     signatureItem[JV.PROP_AREA] = JpcAreaHelper.outputArea(df[JV.PROP_AREA], band, unitFactor, 1, 0, 1, 0, 1, 0, false, false);
                                     signatureRst.push(signatureItem);
                                 }

+ 17 - 1
app/service/project_account.js

@@ -208,7 +208,7 @@ module.exports = app => {
          */
         async getAccountByProjectId(projectId) {
             const condition = {
-                columns: ['id', 'account', 'name', 'company', 'role', 'mobile', 'telephone', 'enable', 'permission'],
+                columns: ['id', 'account', 'name', 'company', 'role', 'mobile', 'telephone', 'enable', 'permission', 'sign_path'],
                 where: { project_id: projectId, is_admin: 0 },
             };
             const accountList = await this.getAllDataByCondition(condition);
@@ -217,6 +217,22 @@ module.exports = app => {
         }
 
         /**
+         * 根据项目id获取所有类型用户列表
+         *
+         * @param {Number} projectId - 项目id
+         * @return {Array} - 返回用户数据
+         */
+        async getAllAccountByProjectId(projectId) {
+            const condition = {
+                columns: ['id', 'account', 'name', 'company', 'role', 'mobile', 'telephone', 'enable', 'permission', 'sign_path'],
+                where: { project_id: projectId},
+            };
+            const accountList = await this.getAllDataByCondition(condition);
+
+            return accountList;
+        }
+
+        /**
          * 停用/启用
          *
          * @param {Number} accountId - 账号id

+ 25 - 18
app/view/report/index.ejs

@@ -35,28 +35,35 @@
                     <div class="toolsbar-f d-flex justify-content-between">
                         <div class="print-toolsbar">
                             <div class="panel">
-                                <div class="panel-body" id="export_div">
-                                    <button class="btn btn-secondary btn-sm" type="button">
+                                <div class="panel-body" id="print_div">
+                                    <button class="btn btn-outline-primary btn-sm" type="button">
                                         <i class="fa fa-print"></i><br>
-                                        打印 <span id="checkCountPrint" class="badge badge-light">0</span>
-                                    </button>
-                                    <button class="btn btn-secondary btn-sm" type="button" href="#export" data-toggle="modal" data-target="#export">
-                                        <i class="fa fa-share-square-o"></i><br>
-                                        导出 <span id="checkCountExport" class="badge badge-light">0</span>
+                                        打印 <span id="checkCountPrint" class="badge badge-primary">0</span>
                                     </button>
                                 </div>
                             </div>
                             <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>
+                                    </div>
+                                </div>
+                                <div class="panel-foot text-muted">
+                                    导出报表
+                                </div>
+                            </div>
+                            <div class="panel">
                                 <div class="panel-body">
                                     <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
                                         <div class="btn-group" role="group">
-                                            <button id="btnRptOrientation" type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">纵向</button>
+                                            <button id="btnRptOrientation" type="button" class="btn btn-outline-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">纵向</button>
                                             <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                                                 <a class="dropdown-item" id="hrefRptOrientation" style="cursor:pointer" onclick="zTreeOprObj.changeOrientation(this)">横向</a>
                                             </div>
                                         </div>
                                         <div class="btn-group" role="group">
-                                            <button id="btnRptPageSize"  type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">A4</button>
+                                            <button id="btnRptPageSize"  type="button" class="btn btn-outline-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">A4</button>
                                             <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                                                 <a class="dropdown-item" id="hrefRptPageSize" style="cursor:pointer" onclick="zTreeOprObj.changePageSize(this)">A3</a>
                                             </div>
@@ -70,9 +77,9 @@
                             <div class="panel">
                                 <div class="panel-body">
                                     <div class="btn-group" role="group">
-                                        <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="缩小" onclick="zTreeOprObj.scaleReport(-0.25)">-</button>
-                                        <button id="btnNormalScale" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="重置默认大小" onclick="zTreeOprObj.scaleReport(0)">100%</button>
-                                        <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="放大" onclick="zTreeOprObj.scaleReport(0.25)">+</button>
+                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="缩小" onclick="zTreeOprObj.scaleReport(-0.25)">-</button>
+                                        <button id="btnNormalScale" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="重置默认大小" onclick="zTreeOprObj.scaleReport(0)">100%</button>
+                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="放大" onclick="zTreeOprObj.scaleReport(0.25)">+</button>
                                     </div>
                                 </div>
                                 <div class="panel-foot text-muted">
@@ -82,9 +89,8 @@
                             <div class="panel">
                                 <div class="panel-body">
                                     <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
-                                        <button type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#paper"><i class="fa fa-file-o"></i> 纸张</button>
-                                        <button type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#format"><i class="fa fa-bold"></i> 格式</button>
-                                        <button type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#content"><i class="fa fa-file-text-o"></i> 内容</button>
+                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#paper"><i class="fa fa-file-o"></i> 纸张</button>
+                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#format"><i class="fa fa-bold"></i> 格式</button>
                                     </div>
                                 </div>
                                 <div class="panel-foot text-muted">
@@ -93,7 +99,7 @@
                             </div>
                             <div class="panel">
                                 <div class="panel-body">
-                                    <button class="btn btn-secondary btn-sm" type="button" data-toggle="modal" data-target="#sign">
+                                    <button class="btn btn-outline-primary btn-sm" type="button" data-toggle="modal" data-target="#eSignature">
                                         <i class="fa fa-pencil"></i><br>
                                         电子签名
                                     </button>
@@ -103,11 +109,11 @@
                                 <div class="panel-body">
                                     <div class="input-group input-group-sm">
                                         <div class="input-group-prepend">
-                                            <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上一页" onclick="rptControlObj.prePage(this)"><i class="fa fa-chevron-left"></i></button>
+                                            <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="上一页" onclick="rptControlObj.prePage(this)"><i class="fa fa-chevron-left"></i></button>
                                         </div>
                                         <input class="form-control" id="rpt_page_num" value="1/10" onKeydown="rptControlObj.onKeydown(event, this)" style="width:60px" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="输入页码按回车键,快速跳转">
                                         <div class="input-group-append">
-                                            <button type="button" class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下一页" onclick="rptControlObj.nextPage(this)"><i class="fa fa-chevron-right"></i></button>
+                                            <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="下一页" onclick="rptControlObj.nextPage(this)"><i class="fa fa-chevron-right"></i></button>
                                         </div>
                                     </div>
                                 </div>
@@ -176,6 +182,7 @@
     const STAGE_ORDER = <%- stg_order %>;
     const STAGE_TIMES = <%- stg_times %>;
     const STAGE_LIST = <%- stage_list %>;
+    const PRJ_ACCOUNT_LIST = <%- prj_account_list %>;
     const STAGE_STATUS = <%- stg_status %>;
     let current_stage_order = -1;
     let current_stage_id = -1;

+ 90 - 3
app/view/report/rpt_all_popup.ejs

@@ -156,7 +156,7 @@
                 <div class="row">
                     <div class="col-6">
                         <div class="card">
-                            <img class="card-img-top" src="/web/building_saas/img/p2.png">
+                            <img class="card-img-top" src="/public/images/p2.png">
                             <div class="card-body px-3">
                                 <div class="form-check">
                                     <input class="form-check-input" type="radio" name="excelExportTypeRadio" id="excelExportType_AllInOneBook" value="option1" checked>
@@ -169,7 +169,7 @@
                     </div>
                     <div class="col-6">
                         <div class="card">
-                            <img class="card-img-top" src="/web/building_saas/img/p1.png">
+                            <img class="card-img-top" src="/public/images/p1.png">
                             <div class="card-body px-3">
                                 <div class="form-check">
                                     <input class="form-check-input" type="radio" name="excelExportTypeRadio" id="excelExportType_IndividualBook" value="option2" checked>
@@ -188,4 +188,91 @@
             </div>
         </div>
     </div>
-</div>
+</div>
+<div class="modal fade" id="eSignature" 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" id="eSignatureBodyDiv">
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a onclick="zTreeOprObj.showPage(zTreeOprObj.currentPage, zTreeOprObj.canvas)" class="btn btn-primary" data-dismiss="modal">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
+<!--弹出添加签名人-->
+<div class="modal fade" id="add-sign" data-backdrop="static">
+    <div class="modal-dialog modal-sm" 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">
+                <ul class="nav nav-tabs justify-content-center mb-1" role="tablist">
+                    <li class="nav-item">
+                        <a class="nav-link active px-3 p-1" data-toggle="tab" href="#adst-1" role="tab">项目</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link px-3 p-1" data-toggle="tab" href="#adst-2" role="tab"><i class="fa fa-user"></i> 角色</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link px-3 p-1" data-toggle="tab" href="#adst-3" role="tab">最近使用</a>
+                    </li>
+                </ul>
+                <div class="tab-content">
+                    <div class="tab-pane fade show active" id="adst-1" role="tabpanel" aria-labelledby="home-tab">
+                        <div class="input-group input-group-sm mt-1 mb-2">
+                            <div class="input-group-prepend">
+                                <span class="input-group-text" id="inputGroup-sizing-sm"><i class="fa fa-search"></i></span>
+                            </div>
+                            <input type="text" class="form-control" placeholder="搜索...">
+                        </div>
+                        <div class="modal-height-300" id="project_account_select_div">
+                        </div>
+                    </div>
+                    <div class="tab-pane fade" id="adst-2" role="tabpanel" aria-labelledby="profile-tab">
+                        <a href="" class="btn btn-sm btn-link">添加角色</a>
+                        <div class="modal-height-300">
+                            <!--添加角色-->
+                            <div class="card">
+                                <div class="p-2">
+                                    <div class="input-group input-group-sm mb-1">
+                                        <div class="input-group-prepend">
+                                            <span class="input-group-text" id="inputGroup-sizing-sm">角色名称</span>
+                                        </div>
+                                        <input type="text" class="form-control" placeholder="最多10个字符">
+                                    </div>
+                                    <div class="input-group input-group-sm mb-1">
+                                        <div class="input-group-prepend">
+                                            <span class="input-group-text" id="inputGroup-sizing-sm">绑定成员</span>
+                                        </div>
+                                        <input type="text" class="form-control" placeholder="输入姓名检索">
+                                    </div>
+                                    <a href="" class="btn btn-sm btn-primary">添加角色</a>
+                                </div>
+                            </div>
+                            <ul class="list-group">
+                            </ul>
+                        </div>
+                    </div>
+                    <div class="tab-pane fade" id="adst-3" role="tabpanel" aria-labelledby="contact-tab">
+                        <div class="modal-height-300">
+                            <ul class="list-group">
+                            </ul>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>