Selaa lähdekoodia

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/YangHuCost

zhongzewei 6 vuotta sitten
vanhempi
commit
0f29f784f3

+ 8 - 6
modules/reports/rpt_component/jpc_cross_tab.js

@@ -195,6 +195,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
         me.dispSumValueLst_Col = [];
         me.page_seg_map = [];
         me.row_fields_idx = [];
+        me.row_fields_adhoc_idx = [];
         me.col_fields_idx = [];
         me.content_fields_idx = [];
         me.row_extension_fields_idx = [];
@@ -207,6 +208,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
         let me = this;
         //IMPORTANT: the data should be sorted in SQL/NoSQL level!
         me.sortedRowSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_ROW, me.row_fields_idx, $CURRENT_RPT);
+        private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_ROW_AD_HOC, me.row_fields_adhoc_idx, $CURRENT_RPT);
         me.sortedColSequence = private_SortAndOptimize(rptTpl, dataObj, dataSeq, JV.NODE_CROSS_COL, me.col_fields_idx, $CURRENT_RPT);
         me.sortedContentSequence = private_SortForDisplayContent(rptTpl, me.sortedRowSequence, me.sortedColSequence, me.content_fields_idx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_CROSS_INFO][JV.NODE_CROSS_COL_SUM][JV.PROP_CROSS_FIELDS], null, me.col_sum_fields_idx);
@@ -452,8 +454,8 @@ JpcCrossTabSrv.prototype.createNew = function(){
             //2. start to output detail-part
             //2.1 Row-Tab
             //tabRstLst.push(me.outputRowTab(rptTpl, dataObj, page, bands, unitFactor, controls, $CURRENT_RPT, customizeCfg));
-            tabRstLst.push(me.outputRowTabCommon(rptTpl, dataObj, page, bands, JV.NODE_CROSS_ROW, unitFactor, controls, $CURRENT_RPT, customizeCfg));
-            tabRstLst.push(me.outputRowTabCommon(rptTpl, dataObj, page, bands, JV.NODE_CROSS_ROW_AD_HOC, unitFactor, controls, $CURRENT_RPT, customizeCfg));
+            tabRstLst.push(me.outputRowTabCommon(rptTpl, dataObj, page, bands, JV.NODE_CROSS_ROW, me.row_fields_idx, unitFactor, controls, $CURRENT_RPT, customizeCfg));
+            tabRstLst.push(me.outputRowTabCommon(rptTpl, dataObj, page, bands, JV.NODE_CROSS_ROW_AD_HOC, me.row_fields_adhoc_idx, unitFactor, controls, $CURRENT_RPT, customizeCfg));
             //2.2 Col-Tab
             tabRstLst.push(me.outputColTab(rptTpl, dataObj, page, bands, unitFactor, controls, $CURRENT_RPT, customizeCfg));
             //2.3 Content-Tab
@@ -473,7 +475,7 @@ JpcCrossTabSrv.prototype.createNew = function(){
         }
         return rst;
     };
-    JpcCrossTabResult.outputRowTabCommon = function(rptTpl, dataObj, page, bands, tabStr, unitFactor, controls, $CURRENT_RPT, customizeCfg) {
+    JpcCrossTabResult.outputRowTabCommon = function(rptTpl, dataObj, page, bands, tabStr, rowFieldsIdxArr, unitFactor, controls, $CURRENT_RPT, customizeCfg) {
         let me = this, rst = [];
         let tab = rptTpl[JV.NODE_CROSS_INFO][tabStr];
         let band = (tab)?bands[tab[JV.PROP_BAND_NAME]]:null;
@@ -485,13 +487,13 @@ JpcCrossTabSrv.prototype.createNew = function(){
                 let valuesIdx = me.dispValueIdxLst_Row[page - 1];
                 let serialsIdx = me.dispSerialIdxLst_Row[page - 1];
                 let flexiblePrecisionRefObj = null, flexibleRefField = null, precision_ref_data = null;
-                for (let i = 0; i < me.row_fields_idx.length; i++) {
+                for (let i = 0; i < rowFieldsIdxArr.length; i++) {
                     let tab_field = tab_fields[i];
                     if (!(tab_field[JV.PROP_HIDDEN])) {
                         let data_field = null;
                         let map_data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
-                        if (typeof me.row_fields_idx[i] !== 'object') {
-                            data_field = data_details[me.row_fields_idx[i]];
+                        if (typeof rowFieldsIdxArr[i] !== 'object') {
+                            data_field = data_details[rowFieldsIdxArr[i]];
                         } else {
                             if (map_data_field) {
                                 data_field = map_data_field[JV.PROP_AD_HOC_DATA];

+ 23 - 7
modules/reports/rpt_component/jpc_ex.js

@@ -249,6 +249,18 @@ JpcExSrv.prototype.createNew = function(){
         rst.items = [];
         let bands = JpcBand.createNew(rptTpl, defProperties);
         try {
+            function getPageMergeBorder() {
+                let mergeRst = null;
+                if (bands[JV.BAND_PROP_MERGE_BAND]) {
+                    let mergedBand = bands[JV.BAND_PROP_MERGE_BAND];
+                    mergeRst = {};
+                    mergeRst[JV.PROP_LEFT] = parseInt(mergedBand[JV.PROP_LEFT].toFixed(0));
+                    mergeRst[JV.PROP_RIGHT] = parseInt(mergedBand[JV.PROP_RIGHT].toFixed(0));
+                    mergeRst[JV.PROP_TOP] = parseInt(mergedBand[JV.PROP_TOP].toFixed(0));
+                    mergeRst[JV.PROP_BOTTOM] = parseInt(mergedBand[JV.PROP_BOTTOM].toFixed(0));
+                }
+                return mergeRst;
+            }
             //1.
             let rstPage = {};
             rstPage[JV.PROP_PAGE_SEQ] = 1;
@@ -259,6 +271,10 @@ JpcExSrv.prototype.createNew = function(){
             } else if (me.billTab) {
                 rstPage[JV.PROP_CELLS] = me.billTab.outputAsPreviewPage(rptTpl, bands, rst[JV.NODE_CONTROL_COLLECTION], me);
             }
+            let pageMergeBorder = getPageMergeBorder();
+            if (pageMergeBorder) {
+                rstPage[JV.PROP_PAGE_MERGE_BORDER] = pageMergeBorder;
+            }
             rst.items.push(rstPage);
             //2.
             if (bands[JV.BAND_PROP_MERGE_BAND]) {
@@ -315,16 +331,16 @@ JpcExSrv.prototype.createNew = function(){
     JpcResult.outputAsSimpleJSONPage = function(rptTpl, dataObj, bands, page, controls, customizeCfg) {
         let me = this, rst = null;
         function getPageMergeBorder() {
-            let rst = null;
+            let mergeRst = null;
             if (bands[JV.BAND_PROP_MERGE_BAND]) {
                 let mergedBand = bands[JV.BAND_PROP_MERGE_BAND];
-                rst = {};
-                rst[JV.PROP_LEFT] = parseInt(mergedBand[JV.PROP_LEFT].toFixed(0));
-                rst[JV.PROP_RIGHT] = parseInt(mergedBand[JV.PROP_RIGHT].toFixed(0));
-                rst[JV.PROP_TOP] = parseInt(mergedBand[JV.PROP_TOP].toFixed(0));
-                rst[JV.PROP_BOTTOM] = parseInt(mergedBand[JV.PROP_BOTTOM].toFixed(0));
+                mergeRst = {};
+                mergeRst[JV.PROP_LEFT] = parseInt(mergedBand[JV.PROP_LEFT].toFixed(0));
+                mergeRst[JV.PROP_RIGHT] = parseInt(mergedBand[JV.PROP_RIGHT].toFixed(0));
+                mergeRst[JV.PROP_TOP] = parseInt(mergedBand[JV.PROP_TOP].toFixed(0));
+                mergeRst[JV.PROP_BOTTOM] = parseInt(mergedBand[JV.PROP_BOTTOM].toFixed(0));
             }
-            return rst;
+            return mergeRst;
         }
         if (me.totalPages >= page) {
             rst = {};

+ 4 - 2
modules/reports/rpt_component/jpc_flow_tab.js

@@ -892,8 +892,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
             }
             if (removeCellIds.length > 0) {
-                //这次真的要排序了
-                removeCellIds.sort(); //默认方式即可
+                //排序,保证一定的顺序,不能用默认的方式(默认方式是针对字符串的简单排序)
+                removeCellIds.sort(function (idx1, idx2) {
+                    return idx1 - idx2;
+                });
                 for (let idx = removeCellIds.length - 1; idx >= 0; idx--) {
                     rstPageCells.splice(removeCellIds[idx], 1);
                 }

+ 21 - 10
modules/reports/util/rpt_yanghu_data_util.js

@@ -240,7 +240,7 @@ class Rpt_Data_Extractor {
         let tpl = this.rptTpl;
         this.COMMON.initialize(tpl, rawDataObj);
         $PROJECT.COMMON = this.COMMON;
-        if (rawDataObj.hasOwnProperty(`prj`)) {
+        if (rawDataObj.hasOwnProperty(`prj`) && rawDataObj.hasOwnProperty(`prjData`)) {
             setupMainFunc($PROJECT, `MAIN`, rawDataObj.prj._doc);
             // $PROJECT.MAIN["myOwnRawDataObj"] = rawDataObj.prj._doc;
             // $PROJECT.MAIN.getProperty = ext_mainGetPropety;
@@ -270,7 +270,8 @@ class Rpt_Data_Extractor {
             }
         }
         //还有汇总的...
-        if (rawDataObj.hasOwnProperty(`Construct`) || rawDataObj.hasOwnProperty(`ConstructDetail`) || rawDataObj.hasOwnProperty(`Segment`) || rawDataObj.hasOwnProperty(`SegmentDetail`)) {
+        if (rawDataObj.hasOwnProperty(`Construct`) || rawDataObj.hasOwnProperty(`ConstructDetail`) || rawDataObj.hasOwnProperty(`Segment`) || rawDataObj.hasOwnProperty(`SegmentDetail`)
+            || rawDataObj.hasOwnProperty(`SummaryAudit`) || rawDataObj.hasOwnProperty(`SummaryAuditDetail`)) {
             $PROJECT.SUMMARY = {};
             if (rawDataObj.Construct) {
                 setupMainFunc($PROJECT.SUMMARY, `Construct`, rawDataObj.Construct);
@@ -284,6 +285,12 @@ class Rpt_Data_Extractor {
             if (rawDataObj.SegmentDetail) {
                 setupFunc($PROJECT.SUMMARY, `SegmentDetail`, {"data": rawDataObj.SegmentDetail});
             }
+            if (rawDataObj.SummaryAudit) {
+                setupMainFunc($PROJECT.SUMMARY, `SummaryAudit`, rawDataObj.SummaryAudit);
+            }
+            if (rawDataObj.SummaryAuditDetail) {
+                setupFunc($PROJECT.SUMMARY, `SummaryAuditDetail`, {"data": rawDataObj.SummaryAuditDetail});
+            }
         }
         //综合费率
         let feeRate = getModuleDataByKey(rawDataObj.prjData, "feeRate");
@@ -330,7 +337,7 @@ class Rpt_Data_Extractor {
             }
         }
         //一些计算(不保存数据,需要动态计算的)
-        if (rawDataObj.hasOwnProperty(`prj`)) {
+        if (rawDataObj.hasOwnProperty(`prj`) && rawDataObj.hasOwnProperty(`prjData`)) {
             let calcOptions = rawDataObj.prj._doc.property.calcOptions;
             let decimalObj = rawDataObj.prj._doc.property.decimal;
             let labourCoeDatas =  getModuleDataByKey(rawDataObj.prjData, "labour_coe");
@@ -357,9 +364,11 @@ class Rpt_Data_Extractor {
         rptDataObj[JV.DATA_DETAIL_DATA] = [];
         rptDataObj[JV.DATA_MASTER_DATA_EX] = [];
         rptDataObj[JV.DATA_DETAIL_DATA_EX] = [];
-        rptDataObj.DecimalObj = {};
-        rptDataObj.DecimalObj.prjDecimal = $PROJECT.MAIN["myOwnRawDataObj"].decimal; //为函数 P_REF() 准备数据
-        rptDataObj.DecimalObj.unitDecimal = getUnitDecimal($PROJECT.MAIN["myOwnRawDataObj"].billsQuantityDecimal); //为函数 U_REF() 准备数据
+        if (rawDataObj.hasOwnProperty(`prj`) && rawDataObj.hasOwnProperty(`prjData`)) {
+            rptDataObj.DecimalObj = {};
+            rptDataObj.DecimalObj.prjDecimal = $PROJECT.MAIN["myOwnRawDataObj"].decimal; //为函数 P_REF() 准备数据
+            rptDataObj.DecimalObj.unitDecimal = getUnitDecimal($PROJECT.MAIN["myOwnRawDataObj"].billsQuantityDecimal); //为函数 U_REF() 准备数据
+        }
         assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS], rptDataObj[JV.DATA_DISCRETE_DATA], $PROJECT);
         // console.log(JV.DATA_DISCRETE_DATA);
         // console.log(rptDataObj[JV.DATA_DISCRETE_DATA]);
@@ -402,10 +411,12 @@ function getUnitDecimal(unitDecimalArr) {
 
 function getModuleDataByKey(prjData, key) {
     let rst = null;
-    for (let item of prjData) {
-        if (item.moduleName === key) {
-            rst = item;
-            break;
+    if (prjData) {
+        for (let item of prjData) {
+            if (item.moduleName === key) {
+                rst = item;
+                break;
+            }
         }
     }
     return rst;

+ 11 - 5
test/unit/reports/test_rpt_test_template.js

@@ -41,9 +41,10 @@ let demoPrjId = - 1;
 // let demoRptId = 49; //5.5
 // let demoRptId = 66; //5.4
 // let demoRptId = 67; //21-2
-let demoRptId = 31; //21-1
+// let demoRptId = 31; //21-1
 // let demoRptId = 37; //5.2.1 计日工劳务
 // let demoRptId = 68; //01-2
+let demoRptId = 71; //21-2
 
 let pagesize = "A4";
 //288: 11-2表(新)
@@ -60,8 +61,8 @@ let userId_Leng = "5c3ffa9aa0a92732f41216e0"; //小冷User Id (养护的)
 // demoPrjId = 455; //PROD:
 // demoPrjId = 776; //PROD:
 // demoPrjId = 671; //PROD:
-demoPrjId = 473; //UAT
-// demoPrjId = 653; //PROD:
+// demoPrjId = 473; //UAT
+demoPrjId = 1520; //PROD:
 // demoPrjId = 756; //PROD:
 // demoPrjId = 815; //PROD:
 // demoPrjId = 4107; //UAT:
@@ -94,7 +95,7 @@ test('测试 - 测试模板啦: ', function (t) {
         // filter.push('ration_coe'); //临时用2
         // filter.push('projectGLJ'); //临时用3
         // filter.push('calc_program'); //临时用4
-        console.log(filter);
+        // console.log(filter);
         //正常应该根据报表模板定义的数据类型来请求数据
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
@@ -113,7 +114,12 @@ test('测试 - 测试模板啦: ', function (t) {
                     printCom.analyzeData(rptTpl, tplData, defProperties, dftOption, JV.OUTPUT_TYPE_EXCEL);
                     let maxPages = printCom.totalPages;
                     let customizeCfg = {"fillZero": true};
-                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
+                    let pageRst = null;
+                    if (maxPages > 0) {
+                        pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
+                    } else {
+                        pageRst = printCom.outputAsPreviewPage(rptTpl, defProperties);
+                    }
                     if (pageRst) {
                         // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/testBuiltPageResult_测试模板" + dt.getTime() + ".jsp");
                         // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){

+ 44 - 2
test/unit/reports/test_summary_multi_prjs.js

@@ -14,7 +14,9 @@ let dbm = require("../../../config/db/db_manager");
 let rpt_cfg = require('./rpt_cfg');
 dbm.connect(process.env.NODE_ENV);
 
-let demoPrjs = [662, 664];
+let demoPrjs = [442, 472]; //UAT
+let demoRptId = 68; //01-2
+let pagesize = "A4";
 let userId_Leng = "5c3ffa9aa0a92732f41216e0"; //小冷User Id (养护的)
 // let userId_me = "5b6a60b1c4ba33000dd417c0"; //我的
 let userId_Dft = userId_Leng;
@@ -42,8 +44,48 @@ fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.j
 });
 
 test('测试 - 测试模板啦: ', function (t) {
-    //project_facade.getBudgetSummayDatas([517,521]);
+    rptTplDataFacade.getBudgetSummayDatas(demoPrjs).then(function(summaryRst) {
+        //console.log(summaryRst);
+        rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
+            try {
+                let dt = new Date();
+                // fsUtil.writeObjToFile(summaryRst, "D:/GitHome/YangHuCost/tmp/多清单汇总表(01_2)原始数据.jsp");
+                let rptDataUtil = new rptDataExtractor();
+                rptDataUtil.initialize(rptTpl._doc);
+                let tplData = rptDataUtil.assembleData(summaryRst);
+                // fsUtil.writeObjToFile(summaryRst, "D:/GitHome/YangHuCost/tmp/多清单汇总表(01_2)整理后数据.jsp");
+                // fsUtil.writeObjToFile(tplData, "D:/GitHome/YangHuCost/tmp/rptTplAssembledData_测试模板.jsp");
+                //it's time to build the report!!!
+                let printCom = JpcEx.createNew();
+                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                let defProperties = rpt_cfg;
+                let dftOption = JV.PAGING_OPTION_NORMAL;
+                printCom.initialize(rptTpl);
+                printCom.analyzeData(rptTpl, tplData, defProperties, dftOption, JV.OUTPUT_TYPE_EXCEL);
+                let maxPages = printCom.totalPages;
+                let customizeCfg = {"fillZero": true};
+                let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
+                if (pageRst) {
+                    // fsUtil.writeObjToFile(pageRst, "D:/GitHome/YangHuCost/tmp/多清单汇总表(01_2)page数据" + dt.getTime() + ".jsp");
+                    // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
+                    //     console.log("excel uuid: " + uuidName);
+                    // });
+                    // rpt_pdf_util.export_pdf_file(pageRst, pagesize, 'local_test_rpt_pdf', function(uuidName){
+                    //     console.log("pdf uuid: " + uuidName);
+                    // });
+                } else {
+                    console.log("oh! no pages were created!");
+                }
+            } catch (ex) {
+                console.log(ex);
+                t.pass('pass with exception!');
+                t.end();
+            }
 
+            t.pass('pass succeeded!');
+            t.end();
+        });
+    });
 });
 
 test('close the connection', function (t) {

+ 27 - 1
web/building_saas/main/html/main.html

@@ -46,7 +46,7 @@
     </script>
 </head>
 
-<body>
+<body oncontextmenu="return false;">  <!--屏蔽input鼠标右键-->
 <!--<div id="toolToastWrap" style="left: 20px; right: 30px; position: fixed; z-index: 10001; top: 100px;">
     <div id="toolToast" class="toolToast">
         <span id="tool-toast-content">右键不支持粘贴外部内容,请使用Ctrl+V粘贴。<span id="toolToastBtn">我知道了</span></span>
@@ -1033,11 +1033,37 @@
                 </div>
                 <div class="modal-footer">
                     <a href="javascript:void(0);" id="glj_selected_conf" class="btn btn-primary">确定</a>
+                    <a href="javascript:void(0);" id="replace_next_btn" class="btn btn-primary">下一步</a>
                     <button type="button" id="componentsCacnel" class="btn btn-secondary" data-dismiss="modal">取消</button>
                 </div>
             </div>
         </div>
     </div>
+
+<!--弹出 批量替换下一步-->
+<div class="modal fade" id="mreplace_next_div" data-backdrop="static" style="z-index: 1060">
+    <input type="hidden" id =''>
+    <div class="modal-dialog modal-lg"  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" style="padding: 0px">
+                <div class="row" style="height:400px"><!--sjs id设置在这个div-->
+                    <div class="col-12" style="overflow: hidden" id="scopeSpread"></div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button class="btn btn-primary" id="scope_position_confirm">确定</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
+</div>
+
     <!--工料机类型选择-->
     <div class="modal fade" id="glj_class_div" data-backdrop="static">
         <div class="modal-dialog modal-m" role="document" id="class_con">

+ 1 - 1
web/building_saas/pm/html/project-management.html

@@ -38,7 +38,7 @@
     </style>
 </head>
 
-<body>
+<body oncontextmenu="return false;">  <!--屏蔽input鼠标右键-->
 <img src="/web/dest/css/img/folder_open.png" id="folder_open_pic" style="display: none">
 <img src="/web/dest/css/img/folder_close.png" id="folder_close_pic" style="display: none">
 <img src="/web/dest/css/img/project.png" id="proj_pic" style="display: none">

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

@@ -29,6 +29,7 @@
                             <div class="btn-group" role="group" aria-label="Button group with nested dropdown" id="export_div">
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.checkAndGetExcel()"><i class="fa fa-file-excel-o"></i> Excel <span class="badge badge-secondary">0</span></button>
                                 <button type="button" class="btn btn-outline-primary btn-sm" id="show_excel_output_cfg" data-toggle="modal" data-target="#export_excel" style="display:none"></button>
+                                <button type="button" class="btn btn-outline-primary btn-sm" id="show_project_folder" data-toggle="modal" data-target="#cpoj" style="display:none"></button>
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.getPDF()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-secondary">0</span></button>
                             </div>
                         </div>
@@ -103,6 +104,8 @@
 <%include ./rpt_content_format.html %>
 <!--弹出导出Excel-->
 <%include ./rpt_export_excel.html %>
+<!--弹出-->
+<%include ./rpt_select_projects.html %>
 <script>
     const SCREEN_DPI = [];
     function getScreenDPI() {

+ 21 - 0
web/building_saas/report/html/rpt_select_projects.html

@@ -0,0 +1,21 @@
+<div class="modal fade" id="cpoj" 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="modal-auto-height">
+                    <ul id="prjFolderTree" class="ztree"></ul>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="" class="btn btn-primary">确定</a>
+            </div>
+        </div>
+    </div>
+</div>

+ 26 - 0
web/building_saas/report/js/rpt_cfg_const.js

@@ -29,3 +29,29 @@ let rpt_tpl_setting = {
         onClick: zTreeOprObj.onClick
     }
 };
+
+let rpt_prj_folder_setting = {
+    view: {
+        selectedMulti: false
+    },
+    check: {
+        enable: true
+    },
+    data: {
+        keep: {
+            parent:true,
+            leaf:true
+        },
+        key: {
+            children: "items"
+        },
+        simpleData: {
+            enable: true,
+            rootPId: -1
+        }
+    },
+    callback: {
+        // onCheck: zTreeOprObj.onCheck,
+        // onClick: zTreeOprObj.onClick
+    }
+};

+ 62 - 9
web/building_saas/report/js/rpt_main.js

@@ -27,6 +27,7 @@ let rptTplObj = {
 
 let zTreeOprObj = {
     treeObj: null,
+    prjFolderTreeObj: null,
     currentNode: null,
     checkedRptTplNodes: null,
     currentRptPageRst: null,
@@ -214,15 +215,21 @@ let zTreeOprObj = {
     onClick: function(event,treeId,treeNode) {
         let me = zTreeOprObj;
         if (treeNode.nodeType === TPL_TYPE_TEMPLATE && treeNode.refId > 0) {
-            let params = {};
-            let pageSize = rptControlObj.getCurrentPageSize();
-            params.pageSize = pageSize;
-            params.rpt_tpl_id = treeNode.refId;
-            params.prj_id = projectObj.project.projectInfo.ID;
-            params.custCfg = me.reportPageCfg;
-            me.currentNode = treeNode;
-            me.requestReport(params);
-            me.countChkedRptTpl();
+            if (treeNode.hasOwnProperty('flags') && treeNode.flags.hasOwnProperty('reportType')
+                && treeNode['flags']['reportType'] === 'billSummary') {
+                me.requestPrjFolder();
+                me.countChkedRptTpl();
+            } else {
+                let params = {};
+                let pageSize = rptControlObj.getCurrentPageSize();
+                params.pageSize = pageSize;
+                params.rpt_tpl_id = treeNode.refId;
+                params.prj_id = projectObj.project.projectInfo.ID;
+                params.custCfg = me.reportPageCfg;
+                me.currentNode = treeNode;
+                me.requestReport(params);
+                me.countChkedRptTpl();
+            }
         }
     },
     changePageSize: function(dom) {
@@ -296,6 +303,52 @@ let zTreeOprObj = {
             }
         );
     },
+    requestPrjFolder: function () {
+        //$("#show_project_folder").trigger("click");
+        let me = zTreeOprObj, params = {};
+        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);
+            }
+        });
+        // CommonAjax.postEx("/pm/api/getProjects", params, 15000, true,
+        //     function(result){
+        //         hintBox.unWaitBox();
+        //         $("#show_project_folder").trigger("click");
+        //         console.log(result);
+        //     }, function(err){
+        //         hintBox.unWaitBox();
+        //     }, function(ex){
+        //         hintBox.unWaitBox();
+        //     }
+        // );
+    },
     showPage: function (pageNum, canvas) {
         let me = zTreeOprObj;
         if (pageNum >= 1 && pageNum <= me.maxPages) {