Browse Source

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

MaiXinRong 7 years ago
parent
commit
dcee21829e
35 changed files with 2185 additions and 584 deletions
  1. 2 2
      gulpfile.js
  2. 1 1
      modules/glj/models/unit_price_file_model.js
  3. 1 1
      modules/main/models/project.js
  4. 54 43
      modules/pm/controllers/pm_controller.js
  5. 84 1
      modules/pm/models/project_model.js
  6. 7 0
      modules/pm/routes/pm_route.js
  7. 6 3
      modules/reports/controllers/rpt_controller.js
  8. 3 0
      modules/reports/controllers/rpt_tpl_controller.js
  9. 114 72
      modules/reports/util/rpt_construct_data_util.js
  10. 1 1
      public/calc_util.js
  11. 20 21
      public/web/sheet/sheet_common.js
  12. 1 1
      public/web/tree_table/tree_table.js
  13. 13 0
      test/calculation/testArrayCalc.js
  14. 337 0
      test/unit/reports/rpt_cfg.js
  15. 2 2
      web/building_saas/glj/html/glj_index.html
  16. 7 7
      web/building_saas/main/html/calc_program_manage.html
  17. 158 306
      web/building_saas/main/html/main.html
  18. 2 0
      web/building_saas/main/js/main.js
  19. 16 1
      web/building_saas/main/js/models/main_consts.js
  20. 0 66
      web/building_saas/main/js/rpt/rpt_main.js
  21. 14 12
      web/building_saas/main/js/views/calc_program_manage.js
  22. 12 9
      web/building_saas/main/js/views/calc_program_view.js
  23. 4 0
      web/building_saas/main/js/views/glj_view.js
  24. 3 0
      web/building_saas/main/js/views/main_tree_col.js
  25. 0 1
      web/building_saas/main/js/views/project_property_labour_coe_view.js
  26. 6 0
      web/building_saas/main/js/views/sub_view.js
  27. 67 0
      web/building_saas/pm/html/project-management-Recycle.html
  28. 38 30
      web/building_saas/pm/html/project-management.html
  29. 656 0
      web/building_saas/pm/js/pm_gc.js
  30. 5 0
      web/building_saas/pm/js/pm_main.js
  31. 160 0
      web/building_saas/report/html/rpt_main.html
  32. 209 0
      web/building_saas/report/js/jpc_output.js
  33. 49 0
      web/building_saas/report/js/jpc_output_value_define.js
  34. 5 4
      web/building_saas/main/js/rpt/rpt_cfg_const.js
  35. 128 0
      web/building_saas/report/js/rpt_main.js

+ 2 - 2
gulpfile.js

@@ -81,7 +81,7 @@ function minify(options) {
     if(options.jspaths){
         return gulp.src(options.jspaths)
             .pipe($.plumber())
-           // .pipe(uglify())
+            .pipe(uglify())
             .pipe($.concat(options.concatName+"."+version+".js"))
             .pipe(gulp.dest(scriptsDest));
     }
@@ -110,7 +110,7 @@ function inject(options) {
 
 function htmlmin(options) {
     return gulp.src(options.htmlDest+'/*.html')
-    //  .pipe($.htmlmin({collapseWhitespace: true}))
+       // .pipe($.htmlmin({collapseWhitespace: true}))
         .pipe(gulp.dest(options.htmlDest));
 }
 

+ 1 - 1
modules/glj/models/unit_price_file_model.js

@@ -133,7 +133,7 @@ class UnitPriceFileModel extends BaseModel {
      * @return {Promise}
      */
     async getGCUnitPriceFiles(userID){
-        let condition = {userID: userID, 'deleteInfo.deleted': true};
+        let condition = {user_id: userID, 'deleteInfo.deleted': true};
         let result = await this.findDataByCondition(condition, null, false);
         return result;
     }

+ 1 - 1
modules/main/models/project.js

@@ -147,7 +147,7 @@ Project.prototype.getFilterData = function (projectID, filter, callback) {
         functions.push(getModuleData(itemName));
     }
     asyncTool.parallel(functions, function (err, results) {
-        console.log(results);
+        //console.log(results);
         if (err) {
             throw '获取项目数据出错';
         } else {

+ 54 - 43
modules/pm/controllers/pm_controller.js

@@ -4,6 +4,7 @@
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
 let ProjectsData = require('../models/project_model').project;
 let projType = require('../models/project_model').projType;
+let fileType = require('../models/project_model').fileType;
 const engineering = require("../../common/const/engineering");
 let EngineeringLibModel = require("../../users/models/engineering_lib_model");
 let fee_rate_facade = require("../../fee_rates/facade/fee_rates_facade");
@@ -191,61 +192,71 @@ module.exports = {
             callback(request, response, error.err, error.msg, responseData);
         }
     },
-    //拼接获取回收站数据
+
     getGCDatas: async function(request, response) {
         let userID = req.session.sessionUser.ssoId;
-        let engIdsSet = new Set(), rootIdsSet = new Set(), rst = [];
+        let rst = [];
+        let _projs = Object.create(null), _engs = Object.create(null), prefix = 'ID_';
         try{
-            let gc_unitPriceFiles = await ProjectsData.getGCFiles('UnitPriceFile', userID);
-            let gc_feeRateFiles = await ProjectsData.getGCFiles('FeeRateFile', userID);
+            let gc_unitPriceFiles = await ProjectsData.getGCFiles(fileType.unitPriceFile, userID);
+            let gc_feeRateFiles = await ProjectsData.getGCFiles(fileType.feeRateFile, userID);
             let gc_tenderFiles = await ProjectsData.getGCFiles(projType.tender, userID);
-            if(gc_unitPriceFiles.length > 0){
-                gc_unitPriceFiles.forEach(function (obj) {
-                    rootIdsSet.add(obj.rootProjectID);
-                });
-            }
-            if(gc_feeRateFiles.length > 0){
-                gc_feeRateFiles.forEach(function (obj) {
-                    rootIdsSet.add(obj.rootProjectID);
-                });
-            }
+                for(let i = 0, len = gc_unitPriceFiles.length; i < len; i++){
+                    let gc_uf = gc_unitPriceFiles[i];
+                    let theProj = _projs[prefix + gc_uf.root_project_id] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + gc_uf.root_project_id] = await ProjectsData.getProjectsByIds([gc_uf.root_project_id]);
+                        buildProj(theProj);
+                    }
+                    theProj.unitPriceFiles.push(gc_uf);
+                }
+                for(let i = 0, len = gc_feeRateFiles.length; i < len; i++){
+                    let gc_ff = gc_feeRateFiles[i];
+                    let theProj = _projs[prefix + gc_ff.rootProjectID] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + gc_ff.rootProjectID] = await ProjectsData.getProjectsByIds([gc_ff.rootProjectID]);
+                        buildProj(theProj);
+                    }
+                    theProj.feeRateFiles.push(gc_ff);
+                }
             if(gc_tenderFiles.length > 0){
-                rst = rst.concat(gc_tenderFiles);
-                gc_tenderFiles.forEach(function (obj) {
-                    engIdsSet.add(obj.ParentID);
-                });
-            }
-            if(engIdsSet.size > 0){
-                let engineerings = await ProjectsData.getProjectsByIds(Array.from(engIdsSet));
-                engineerings.forEach(function (obj) {
-                    rst.push(obj);
-                    rootIdsSet.add(obj.ParentID);
-                });
-            }
-            if(rootIdsSet.size > 0){
-                let projects = await ProjectsData.getProjectsByIds(Array.from(rootIdsSet));
-                for(let i = 0, len = projects.length; i < len; i++){
-                    projects[i].unitPriceFiles = [];
-                    projects[i].feeRateFiles = [];
-                    for(let j = 0, jLen = gc_unitPriceFiles.length; j < jLen; j++){
-                        if(gc_unitPriceFiles[j].rootProjectID === projects[i].ID){
-                            projects[i].unitPriceFiles.push(gc_unitPriceFiles);
-                            break;
-                        }
+                for(let i = 0, len = gc_tenderFiles.length; i < len; i++){
+                    let gc_t = gc_tenderFiles[i];
+                    let theEng = _engs[prefix + gc_t.ParentID] || null;
+                    if(!theEng){
+                        theEng = _engs[prefix + gc_t.ParentID] = await ProjectsData.getProjectsByIds([gc_t.ParentID]);
+                        theEng.children = [];
                     }
-                    for(let j = 0, jLen = gc_feeRateFiles.length; j < jLen; j++){
-                        if(gc_feeRateFiles[j].rootProjectID === projects[i].ID){
-                            projects[i].feeRateFiles.push(gc_feeRateFiles[j]);
-                            break;
-                        }
+                    theEng.children.push(gc_t);
+                    let theProj = _projs[prefix + theEng.ParentID] || null;
+                    if(!theProj){
+                        theProj = _projs[prefix + theEng.ParentID] = await ProjectsData.getProjectsByIds([theEng.ParentID]);
+                        buildProj(theProj);
                     }
+                    theProj.children.push(theEng);
                 }
-                rst = rst.concat(projects);
+            }
+            for(let i of _projs){
+                rst.push(i);
+            }
+            function buildProj(proj){
+                proj.children = [];
+                proj.unitPriceFiles = [];
+                proj.feeRateFiles = [];
             }
             callback(request, response, null, 'success', rst);
         }
         catch (error){
-            callback(request, response, true, 'fail', null);
+            callback(request, response, true, error, null);
         }
+    },
+
+    recGC: function(request, response){
+        let userID = request.session.sessionUser.ssoId;
+        let nodes = JSON.parse(request.body.nodes);
+        ProjectsData.recGC(userID, nodes, function (err, msg, data) {
+            callback(request, response, err, msg, data);
+        });
     }
+
 };

+ 84 - 1
modules/pm/models/project_model.js

@@ -2,6 +2,10 @@
  * Created by Mai on 2017/1/18.
  */
 import UnitPriceFileModel from "../../glj/models/unit_price_file_model";
+import async_c from 'async';
+import UnitPriceFiles from '../../glj/models/schemas/unit_price_file';
+import mongoose from 'mongoose';
+let FeeRateFiles = mongoose.model('fee_rate_file');
 let counter = require("../../../public/counter/counter.js");
 
 let newProjController = require('../controllers/new_proj_controller');
@@ -18,6 +22,11 @@ let projectType = {
     project: 'Project',
     engineering: 'Engineering',
 };
+//回收站恢复级别
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
 
 let ProjectsDAO = function(){};
 
@@ -240,11 +249,84 @@ ProjectsDAO.prototype.getGCFiles = async function (fileType, userID){
         rst = await feeRateFacade.getGCFeeRateFiles(userID);
     }
     else {
+        let isExist = false;
+        for(let type of projectType){
+            if(type === fileType) isExist = true;
+            break;
+        }
+        if(!isExist) throw '不存在此项目类型!';
         rst = await Projects.find({projType: fileType, 'deleteInfo.deleted': true});
     }
     return rst;
 };
 
+ProjectsDAO.prototype.getFirstNodeID = async function (userID, projType) {
+    if(projType !== projectType.project) throw '只能为建设项目层';
+    let nodes = await Projects.find({userID: userID, projType: projType, deleteInfo: null});
+    if(nodes.length === 0){
+        return -1;
+    }
+    else {
+        let chain = Object.create(null);
+        for(let i = 0, len = nodes.length; i < len; i++){
+            let node = Object.create(null);
+            node.ID = nodes[i].ID;
+            node.NextSiblingID = nodes[i].NextSiblingID;
+            chain[node.ID] = node;
+        }
+        for(let i =0, len = nodes.length; i < len; i++){
+            let next = nodes[i].NextSiblingID > 0 ? chain[nodes[i].NextSiblingID] : null;
+            chain[nodes[i].ID].next = next;
+            if(next){
+                next.pre = chain[nodes[i].ID]
+            }
+        }
+        for(let node of chain){
+            let pre = node.pre || null;
+            if(!pre){
+                return node.ID;
+            }
+        }
+    }
+};
+
+ProjectsDAO.prototype.recGC = async function(userID, datas, callback){
+    let functions = [];
+    for(let i = 0, len = datas.length; i < len; i++){
+        if(datas[i].updateType === projectType.project && datas[i].updateData.NextSiblingID === undefined){//则为待查询NextSiblingID,前端无法查询
+            let firstNodeID = await this.getFirstNodeID(userID, projectType.project);
+            datas[i].updateData.NextSiblingID = firstNodeID;
+        }
+        functions.push((function(data){
+                return function (cb) {
+                    if(data.updateType === fileType.unitPriceFile){
+                        UnitPriceFiles.update(data.findData, data.updateData, function (err) {
+                            if(err) cb(err);
+                            else cb(false);
+                        })
+                    }
+                    else if(data.updateType === fileType.feeRateFile){
+                        FeeRateFiles.update(data.findData, data.updateData, function (err) {
+                            if(err) cb(err);
+                            else cb(false);
+                        });
+                    }
+                    else{
+                        Projects.update(data.findData, data.updateData, function (err) {
+                            if(err)cb(err);
+                            else cb(false);
+                        });
+                    }
+                }
+            }
+        )(datas[i]));
+    }
+    async_c.parallel(functions, function (err, results) {
+        if(err) callback(err, 'fail', null);
+        else callback(false, 'success', null);
+    });
+};
+
 /**
  * 整理工程专业对应标准库数据
  *
@@ -367,5 +449,6 @@ ProjectsDAO.prototype.changeUnitPriceFileInfo = async function(projectId, change
 
 module.exports ={
     project: new ProjectsDAO(),
-    projType: projectType
+    projType: projectType,
+    fileType: fileType
 };

+ 7 - 0
modules/pm/routes/pm_route.js

@@ -11,6 +11,10 @@ module.exports = function (app) {
 
     app.get('/pm', baseController.init, pmController.index);
 
+    app.get('/pm/gc',baseController.init, function (req, res) {
+        res.render('building_saas/pm/html/project-management-Recycle.html');
+    });
+
     let pmRouter = express.Router();
 
     pmRouter.use(function (req, res, next) {
@@ -43,6 +47,9 @@ module.exports = function (app) {
     pmRouter.post('/getNewProjectID', pmController.getNewProjectID);
     pmRouter.post('/getUnitFile', pmController.getUnitFileList);
     pmRouter.post('/getFeeRateFile', pmController.getFeeRateFileList);
+    //GC
+    pmRouter.post('/getGCDatas', pmController.getGCDatas);
+    pmRouter.post('/recGC', pmController.recGC);
 
     app.use('/pm/api', pmRouter);
 };

+ 6 - 3
modules/reports/controllers/rpt_controller.js

@@ -110,9 +110,12 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, option, cb) {
 
 module.exports = {
     getReportAllPages: function (req, res) {
-        let rpt_id = req.body.rpt_tpl_id, prj_id = req.body.prj_id,
-            user_id = req.body.user_id, pageSize = req.body.pageSize;
-        getAllPagesCommon(rpt_id, prj_id, user_id, pageSize, function (err, pageRst) {
+        let params = JSON.parse(req.body.params),
+            rpt_id = params.rpt_tpl_id,
+            prj_id = params.prj_id,
+            user_id = params.user_id,
+            pageSize = params.pageSize;
+        getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, null, function (err, pageRst) {
             callback(req, res, err, pageRst);
         });
     },

+ 3 - 0
modules/reports/controllers/rpt_tpl_controller.js

@@ -52,6 +52,9 @@ let mExport = {
             compilationId = params.compilationId,
             userId = params.userId,
             engineerId = params.engineerId;
+        if (!compilationId) {
+            compilationId = req.session.sessionCompilation._id;
+        }
         rttFacade.findTplTree(compilationId, engineerId, userId).then(function(result) {
             if (result) {
                 callback(req,res,false,"", result);

+ 114 - 72
modules/reports/util/rpt_construct_data_util.js

@@ -13,19 +13,57 @@ let projectConst = consts.projectConst;
 let projectConstList = consts.projectConstList;
 
 class Rpt_Common{
-    initialize(Projects) {
-        this.Projects = Projects;
+    initialize(rpt_tpl, currentDataObj) {
+        this.template = rpt_tpl;
+        this.currentDataObj = currentDataObj;
     };
-
-    getSerialNo(fieldId, $CURRENT_RPT, $CURRENT_DATA){
-        let itemSerialNoRec = $JE.F(fieldId, $CURRENT_RPT);
-        if (itemSerialNoRec) {
-            itemSerialNoRec[JV.PROP_AD_HOC_DATA] = [];
-            for (var innerFmlIdx = 0; innerFmlIdx < $CURRENT_DATA[JV.DATA_DETAIL_DATA][0].length; innerFmlIdx++) {
-                itemSerialNoRec[JV.PROP_AD_HOC_DATA][innerFmlIdx] = (innerFmlIdx + 1);
-            }
-            itemSerialNoRec = null;
+    Multiply(val1, val2, fixFormat) {
+        let rst = [], maxLen = val1.length, minLen = val2.length;
+        if (minLen > maxLen) {
+            maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
+        }
+        for (let i = 0; i < maxLen; i++) {
+            let value = ((i < val1.length)?val1[i]:val1[minLen - 1]) * ((i < val2.length)?val2[i]:val2[minLen - 1]);
+            if (fixFormat) value = value.toFixed(fixFormat);
+            rst.push(value);
+        }
+        return rst;
+    };
+    Divide(val1, val2, fixFormat) {
+        let rst = [], maxLen = val1.length, minLen = val2.length;
+        if (minLen > maxLen) {
+            maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
+        }
+        for (let i = 0; i < maxLen; i++) {
+            let value = ((i < val1.length)?val1[i]:val1[minLen - 1]) / ((i < val2.length)?val2[i]:val2[minLen - 1]);
+            if (fixFormat) value = value.toFixed(fixFormat);
+            rst.push(value);
+        }
+        return rst;
+    };
+    Plus(val1, val2, fixFormat) {
+        let rst = [], maxLen = val1.length, minLen = val2.length;
+        if (minLen > maxLen) {
+            maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
+        }
+        for (let i = 0; i < maxLen; i++) {
+            let value = ((i < val1.length)?val1[i]:val1[minLen - 1]) + ((i < val2.length)?val2[i]:val2[minLen - 1]);
+            if (fixFormat) value = value.toFixed(fixFormat);
+            rst.push(value);
         }
+        return rst;
+    };
+    Minus(val1, val2, fixFormat) {
+        let rst = [], maxLen = val1.length, minLen = val2.length;
+        if (minLen > maxLen) {
+            maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
+        }
+        for (let i = 0; i < maxLen; i++) {
+            let value = ((i < val1.length)?val1[i]:val1[minLen - 1]) - ((i < val2.length)?val2[i]:val2[minLen - 1]);
+            if (fixFormat) value = value.toFixed(fixFormat);
+            rst.push(value);
+        }
+        return rst;
     };
 }
 
@@ -38,6 +76,7 @@ class Rpt_Data_Extractor {
         this.rptTpl = tpl;
     };
 
+    //-- 根据报表模板映射指标(非离散指标)的定义,罗列出所有需要用到的data对象key,作为数据请求的过滤依据
     getDataRequestFilter() {
         let rst = [];
         let tpl = this.rptTpl;
@@ -48,7 +87,7 @@ class Rpt_Data_Extractor {
                         if (field[JV.PROP_FIELD_EXP_MAP].indexOf('.' + key + '.') >= 0) {
                             rst.push(key);
                             if (key === projectConst.RATION_GLJ && (rst.indexOf(projectConst.PROJECTGLJ) < 0)) {
-                                //rst.push(projectConst.PROJECTGLJ);
+                                rst.push(projectConst.PROJECTGLJ);
                             }
                             if (key === projectConst.PROJECTGLJ && (rst.indexOf(projectConst.RATION_GLJ) < 0)) {
                                 rst.push(projectConst.RATION_GLJ);
@@ -58,42 +97,30 @@ class Rpt_Data_Extractor {
                 }
             }
         };
-        if (tpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS]) {
-            for (let field of tpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS]) {
-                pri_func_chk_filter(field);
-            }
-        }
-        if (tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
-            for (let field of tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
-                pri_func_chk_filter(field);
-            }
-        }
-        if (tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
-            for (let field of tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
-                pri_func_chk_filter(field);
-            }
-        }
-        if (tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX]) {
-            for (let field of tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX]) {
-                pri_func_chk_filter(field);
-            }
-        }
-        if (tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX]) {
-            for (let field of tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX]) {
-                pri_func_chk_filter(field);
+        let pri_setup_filter = function (FIELD_LIST_KEY) {
+            if (tpl[JV.NODE_FIELD_MAP][FIELD_LIST_KEY]) {
+                for (let field of tpl[JV.NODE_FIELD_MAP][FIELD_LIST_KEY]) {
+                    pri_func_chk_filter(field);
+                }
             }
-        }
+        };
+        pri_setup_filter(JV.NODE_DISCRETE_FIELDS);
+        pri_setup_filter(JV.NODE_MASTER_FIELDS);
+        pri_setup_filter(JV.NODE_DETAIL_FIELDS);
+        pri_setup_filter(JV.NODE_MASTER_FIELDS_EX);
+        pri_setup_filter(JV.NODE_DETAIL_FIELDS_EX);
         return rst;
     };
 
     //--- 装配数据(把收集到的数据,依据报表模板的指示,预处理(如:排序、过滤、合计)及装配到相关指标) ---//
     assembleData(rawDataObj) {
-        let $PROJECT = {"COMMON": {}, "MAIN": {}, "DETAIL": {}};
+        let $PROJECT = {"COMMON": null, "MAIN": {}, "DETAIL": {}};
         let tpl = this.rptTpl;
+        this.COMMON.initialize(tpl, rawDataObj);
+        $PROJECT.COMMON = this.COMMON;
         $PROJECT.MAIN["myOwnRawDataObj"] = rawDataObj.prj._doc;
         $PROJECT.MAIN.getProperty = ext_mainGetPropety;
         $PROJECT.MAIN.getFee = ext_mainGetFee;
-        $PROJECT.DETAIL.getRationPropertyByID = ext_getRationPropertyByID;
         if (tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
             for (let preHandle of tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
                 let srcData = getModuleDataByKey(rawDataObj.prjData, preHandle[JV.PROP_DATA_KEY]);
@@ -134,8 +161,8 @@ class Rpt_Data_Extractor {
         // console.log(JV.DATA_MASTER_DATA_EX);
         // console.log(rptDataObj[JV.DATA_MASTER_DATA_EX]);
         assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX], rptDataObj[JV.DATA_DETAIL_DATA_EX], $PROJECT);
-        // console.log(JV.DATA_DETAIL_DATA_EX);
-        // console.log(rptDataObj[JV.DATA_DETAIL_DATA_EX]);
+        console.log(JV.DATA_DETAIL_DATA_EX);
+        console.log(rptDataObj[JV.DATA_DETAIL_DATA_EX]);
         return rptDataObj;
     };
 
@@ -316,6 +343,7 @@ function setupFunc(obj, prop, ownRawObj) {
     obj[prop]["myOwnRawDataObj"] = ownRawObj;
     obj[prop].getProperty = ext_getPropety;
     obj[prop].getFee = ext_getFee;
+    obj[prop].getPropertyByForeignId = ext_getPropertyByForeignId;
 }
 
 function assembleFields(fieldList, rstDataArr, $PROJECT) {
@@ -333,11 +361,9 @@ function shielded_exec_env($PROJECT, $ME, rptDataItemObj) {
 }
 
 function ext_mainGetPropety(propKey) {
-    let rst = [];
-    let parentObj = this;
-    //console.log(this);
+    let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
-    if ((dtObj) && (propKey)) {
+    if (propKey && dtObj) {
         if (dtObj.hasOwnProperty("property")) {
             rst.push(dtObj["property"][propKey]);
         } else  {
@@ -347,6 +373,24 @@ function ext_mainGetPropety(propKey) {
     return rst;
 }
 
+function ext_getPropety(propKey) {
+    let rst = [], parentObj = this;
+    let dtObj = parentObj["myOwnRawDataObj"];
+    if (propKey && dtObj) {
+        for (let dItem of dtObj.data) {
+            let doc = (dItem._doc === null || dItem._doc === undefined)?dItem:dItem._doc;
+            if (doc.hasOwnProperty("property")) {
+                rst.push(doc["property"][propKey]);
+            } else if (doc.hasOwnProperty(propKey)) {
+                rst.push(doc[propKey]);
+            } else {
+                rst.push('');
+            }
+        }
+    }
+    return rst;
+}
+
 function ext_mainGetFee(feeKey, dtlFeeKey) {
     let rst = [];
     let parentObj = this;
@@ -372,24 +416,6 @@ function ext_mainGetFee(feeKey, dtlFeeKey) {
     return rst;
 }
 
-function ext_getPropety(propKey) {
-    let rst = [], parentObj = this;
-    let dtObj = parentObj["myOwnRawDataObj"];
-    if (propKey && dtObj) {
-        for (let dItem of dtObj.data) {
-            let doc = (dItem._doc === null || dItem._doc === undefined)?dItem:dItem._doc;
-            if (doc.hasOwnProperty("property")) {
-                rst.push(doc["property"][propKey]);
-            } else if (doc.hasOwnProperty(propKey)) {
-                rst.push(doc[propKey]);
-            } else {
-                rst.push('');
-            }
-        }
-    }
-    return rst;
-}
-
 function ext_getFee(feeKey, dtlFeeKey) {
     let rst = [], parentObj = this;
     let dtObj = parentObj["myOwnRawDataObj"];
@@ -423,16 +449,32 @@ function ext_getFee(feeKey, dtlFeeKey) {
     return rst;
 }
 
-function ext_getRationPropertyByID(IdVal, propKey) {
-    let rst = [], me = this;
-    if (IdVal !== null && IdVal !== undefined && me[projectConst.RATION]) {
+function ext_getPropertyByForeignId(foreignIdVal, adHocIdKey, propKey) {
+    let rst = [], parentObj = this;
+    let IdKey = (adHocIdKey)?adHocIdKey:"ID";
+    let dtObj = parentObj["myOwnRawDataObj"];
+    if (foreignIdVal !== null && foreignIdVal !== undefined) {
         let isFound = false;
-        if (IdVal instanceof Array) {
-            for (let id of IdVal) {
+        if (foreignIdVal instanceof Array) {
+            for (let idVal of foreignIdVal) {
                 isFound = false;
-                for (let item of me[projectConst.RATION]["myOwnRawDataObj"].data) {
-                    if (item.ID === id) {
-                        rst.push(item[propKey]);
+                for (let i = 0; i < dtObj.data.length; i++) {
+                    let item = (dtObj.data[i]._doc)?dtObj.data[i]._doc:dtObj.data[i];
+                    if (item[IdKey] === idVal) {
+                        let splitPKey = propKey.split(".");
+                        if (splitPKey.length > 1) {
+                            let rstP = null;
+                            for (let i = 0; i < splitPKey.length; i++) {
+                                if (i === 0) {
+                                    rstP = item[splitPKey[i]];
+                                } else {
+                                    rstP = rstP[splitPKey[i]];
+                                }
+                            }
+                            rst.push(rstP);
+                        } else {
+                            rst.push(item[propKey]);
+                        }
                         isFound = true;
                         break;
                     }
@@ -440,8 +482,8 @@ function ext_getRationPropertyByID(IdVal, propKey) {
                 // if (!isFound) rst.push[null];
             }
         } else {
-            for (let item of me[projectConst.RATION]["myOwnRawDataObj"].data) {
-                if (item.ID === IdVal) {
+            for (let item of dtObj.data) {
+                if (item[IdKey] === foreignIdVal) {
                     rst.push(item[propKey]);
                     isFound = true;
                     break;

+ 1 - 1
public/calc_util.js

@@ -374,7 +374,7 @@ class Calculation {
 
     calculate($treeNode){
         let me = this;
-        let templateID = $treeNode.data.calcTemplateID;
+        let templateID = $treeNode.data.programID;
         if (!templateID) templateID = 1;
         let template = me.compiledTemplates[templateID];
         $treeNode.data.calcTemplate = template;

+ 20 - 21
public/web/sheet/sheet_common.js

@@ -4,12 +4,11 @@
 var sheetCommonObj = {
     // CSL.2017.06.05
     // createSpread、initSheet 在一个Spread多个Sheet分别调用时的情况下使用。
-    // buildSheet 在一个Spread、一个Sheet的情况下使用。
     createSpread: function(container, SheetCount){
         var me = this;
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: SheetCount });
         spreadBook.options.tabStripVisible = false;
-         spreadBook.options.showHorizontalScrollbar = true;
+        spreadBook.options.showHorizontalScrollbar = true;
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.allowUserDragDrop = true;
         return spreadBook;
@@ -20,10 +19,24 @@ var sheetCommonObj = {
         var spreadNS = GC.Spread.Sheets;
         sheet.suspendPaint();
         sheet.suspendEvent();
+
         sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
         sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+
+        if (setting && setting.view && setting.view.colHeaderHeight) {
+            sheet.setRowHeight(0, setting.view.colHeaderHeight, spreadNS.SheetArea.colHeader);
+        };
+        if (setting && setting.view && setting.view.rowHeaderWidth) {
+            sheet.setColumnWidth(0, setting.view.rowHeaderWidth, spreadNS.SheetArea.rowHeader);
+        };
+
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+
+        sheet.options.protectionOptions = {
+            allowResizeColumns: true
+        };
+
         sheet.showRowOutline(false);
         me.buildHeader(sheet, setting);
         if (rowCount > 0) sheet.setRowCount(rowCount);
@@ -31,29 +44,15 @@ var sheetCommonObj = {
         sheet.resumePaint();
     },
 
+    // buildSheet 在一个Spread、一个Sheet的情况下使用。
     buildSheet: function(container, setting, rowCount) {
         var me = this;
-        var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
-        spreadBook.options.tabStripVisible = false;
-        spreadBook.options.showHorizontalScrollbar = true;
-        var spreadNS = GC.Spread.Sheets;
+        var spreadBook = me.createSpread(container, { sheetCount: 1 });
         var sheet = spreadBook.getSheet(0);
-        sheet.suspendPaint();
-        sheet.suspendEvent();
-        //Set rowHeader count and columnHeader count.
-        sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
-        sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
-        sheet.options.colHeaderAutoTextIndex = 1;
-        sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
-        sheet.showRowOutline(false);
-        //setup column header
-        me.buildHeader(sheet, setting);
-        //setup cells
-        if (rowCount > 0) sheet.setRowCount(rowCount);
-        sheet.resumeEvent();
-        sheet.resumePaint();
+        me.initSheet(sheet, setting, rowCount);
         return spreadBook;
     },
+
     buildHeader: function(sheet, setting){
         var me = this, ch = GC.Spread.Sheets.SheetArea.colHeader;
         for (var i = 0; i < setting.header.length; i++) {
@@ -194,7 +193,7 @@ var sheetCommonObj = {
             sheet.options.isProtected = true;
             sheet.getRange(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport).locked(false);
             for (var i = 0; i < setting.view.lockColumns.length; i++) {
-                sheet.getRange(-1,setting.view.lockColumns[i] , -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+                sheet.getRange(-1,setting.view.lockColumns[i], -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
             }
         }
     },

+ 1 - 1
public/web/tree_table/tree_table.js

@@ -270,7 +270,7 @@
  					} else {
  						parent.children.splice(parent.childIndex(next), 0, node);
  					}
- 				} else if (parent.childIndex(node) !== parent.childIndex(node.next) - 1) {
+ 				} else if (node.nextSibling && parent.childIndex(node) !== parent.childIndex(node.nextSibling) - 1) {
 					parent.children.splice(parent.childIndex(node), 1);
 					parent.children.splice(parent.childIndex(next), 0, node);
 				};

+ 13 - 0
test/calculation/testArrayCalc.js

@@ -0,0 +1,13 @@
+/**
+ * Created by Tony on 2017/10/31.
+ */
+
+var test = require('tape');
+
+test('测试数组运算', function(t){
+    let demo = [1, 2, 3];
+    let rst = demo*3; //failed!
+    console.log(rst);
+    t.pass('just pass');
+    t.end('just end');
+});

+ 337 - 0
test/unit/reports/rpt_cfg.js

@@ -0,0 +1,337 @@
+module.exports = {
+    "fonts" : [
+        {
+            "ID" : "ReportTitle_Main",
+            "CfgDispName" : "主标题",
+            "Name" : "smartSimSun",
+            "FontHeight" : "27",
+            "FontColor" : "BLACK",
+            "FontBold" : "T",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "ReportTitle_Vice_1",
+            "CfgDispName" : "副标题",
+            "Name" : "smartSimSun",
+            "FontHeight" : "20",
+            "FontColor" : "BLACK",
+            "FontBold" : "T",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "HeaderColumn",
+            "CfgDispName" : "栏头",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "Header",
+            "CfgDispName" : "表头",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "FooterColumn",
+            "CfgDispName" : "栏尾",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "Footer",
+            "CfgDispName" : "表尾",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "GramdTotal",
+            "CfgDispName" : "总合计",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "SectionTotal",
+            "CfgDispName" : "章合计",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "Content",
+            "CfgDispName" : "正文内容",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "0"
+        },
+        {
+            "ID" : "Header_V1",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "90"
+        },
+        {
+            "ID" : "Header_V2",
+            "Name" : "smartSimSun",
+            "FontHeight" : "12",
+            "FontColor" : "BLACK",
+            "FontBold" : "F",
+            "FontItalic" : "F",
+            "FontUnderline" : "F",
+            "FontStrikeOut" : "F",
+            "FontAngle" : "-90"
+        }
+    ],
+    "styles" : [
+        {
+            "ID" : "Default_None",
+            "CfgDispName" : "空白",
+            "border_style" : []
+        },
+        {
+            "ID" : "Default",
+            "CfgDispName" : "默认",
+            "border_style" : []
+        },
+        {
+            "ID" : "Default_Normal",
+            "CfgDispName" : "正常",
+            "border_style" : [
+                {
+                    "Position" : "Left",
+                    "LineWeight" : "1",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Right",
+                    "LineWeight" : "1",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Top",
+                    "LineWeight" : "1",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Bottom",
+                    "LineWeight" : "1",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                }
+            ]
+        },
+        {
+            "ID" : "Label_Underline",
+            "CfgDispName" : "字符底线",
+            "border_style" : [
+                {
+                    "Position" : "Left",
+                    "LineWeight" : "0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Right",
+                    "LineWeight" : "0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Top",
+                    "LineWeight" : "0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Bottom",
+                    "LineWeight" : "1",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                }
+            ]
+        },
+        {
+            "ID" : "BORDER_ALL_AROUND",
+            "CfgDispName" : "报表边框",
+            "border_style" : [
+                {
+                    "Position" : "Left",
+                    "LineWeight" : "0.0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Right",
+                    "LineWeight" : "0.0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Top",
+                    "LineWeight" : "2.0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                },
+                {
+                    "Position" : "Bottom",
+                    "LineWeight" : "2.0",
+                    "DashStyle" : "SOLID",
+                    "Color" : "BLACK"
+                }
+            ]
+        }
+    ],
+    "ctrls" : [
+        {
+            "ID" : "Default",
+            "CfgDispName" : "默认",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "left",
+            "Vertical" : "bottom",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Title",
+            "CfgDispName" : "标题",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "center",
+            "Vertical" : "center",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Header",
+            "CfgDispName" : "表头",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "left",
+            "Vertical" : "center",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Footer",
+            "CfgDispName" : "表尾",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "left",
+            "Vertical" : "center",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Column",
+            "CfgDispName" : "表栏",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "center",
+            "Vertical" : "center",
+            "Wrap" : "false",
+            "FillAfterWrap" : "true"
+        },
+        {
+            "ID" : "Column_Left",
+            "CfgDispName" : "表栏_左",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "left",
+            "Vertical" : "center",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Column_Right",
+            "CfgDispName" : "表栏_右",
+            "Shrink" : "T",
+            "ShowZero" : "T",
+            "Horizon" : "right",
+            "Vertical" : "center",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Content_Left",
+            "CfgDispName" : "正文内容",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "left",
+            "Vertical" : "bottom",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Content_Right",
+            "CfgDispName" : "正文内容_右",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "right",
+            "Vertical" : "bottom",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Content_Center",
+            "CfgDispName" : "正文内容_中",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "center",
+            "Vertical" : "bottom",
+            "Wrap" : "false"
+        },
+        {
+            "ID" : "Numeric",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "right",
+            "Vertical" : "bottom",
+            "Wrap" : "false"
+        }
+    ]
+}

+ 2 - 2
web/building_saas/glj/html/glj_index.html

@@ -21,7 +21,7 @@
             <div class="bottom-content">
                 <ul class="nav nav-tabs" role="tablist">
                     <li class="nav-item">
-                        <a class="nav-link active" data-toggle="tab" data-name="ration" href="#de" role="tab">相关定额</a>
+                        <a class="nav-link active" data-toggle="tab" data-name="ration" href="#glj_de" role="tab">相关定额</a>
                     </li>
                     <li class="nav-item">
                         <a class="nav-link" data-toggle="tab" data-name="mix-ratio" href="#ph" role="tab">配合比表</a>
@@ -32,7 +32,7 @@
                 </ul>
                 <!-- Tab panes -->
                 <div class="tab-content">
-                    <div class="tab-pane active" id="de" role="tabpanel">
+                    <div class="tab-pane active" id="glj_de" role="tabpanel">
                         <div class="main-data-bottom ovf-hidden">
                             相关定额
                         </div>

+ 7 - 7
web/building_saas/main/html/calc_program_manage.html

@@ -9,22 +9,22 @@
 
 <body>
 <div style="">
-    <img id="f_btn" src="/web/dest/css/img/feeRate_btn.jpg" alt="" style="display: none" />
+    <img id="f_btn" src="/web/dest/css/img/feeRate_btn.jpg" alt="" style="display: block" />
 </div>
     <div class="toolsbar px-1">
     </div>
     <div class="container-fluid">
         <div class="row">
-        <div class="col-lg-3 p-0">
-            <div class="main-data-not" id="mainSpread">
+            <div class="col-lg-2 p-0">
+                <div class="main-data-not" id="mainSpread">
+                </div>
             </div>
-        </div>
-        <div class="col-lg-9 p-0">
-            <div class="main-data-not" id="detailSpread">
+            <div class="col-lg-10 p-0">
+                <div class="main-data-not" id="detailSpread">
+                </div>
             </div>
         </div>
     </div>
-    </div>
 
     <!--弹出 计算基数-->
 <div class="modal fade" id="jsjs" data-backdrop="static">

File diff suppressed because it is too large
+ 158 - 306
web/building_saas/main/html/main.html


+ 2 - 0
web/building_saas/main/js/main.js

@@ -14,6 +14,8 @@ $(function () {
 
     $('#tab_zaojiashu').on('shown.bs.tab', function (e) {
         $(e.relatedTarget.hash).removeClass('active');
+        $("#subItems").addClass('active');
+        $(gljOprObj.activeTab).addClass('active');
         // do something
     });
 

+ 16 - 1
web/building_saas/main/js/models/main_consts.js

@@ -16,6 +16,21 @@ const ModuleNames = {
     labour_coe: 'labour_coe',
     calc_program: 'calc_program'
 };
+
 const feeRate_consts={
     decimal:3
-}
+};
+
+const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
+    rowHeader: 30,
+    colHeader: 30,              // 这个是标题栏高度不是宽度,也写在一起
+    code: 70,
+    name: 200,
+    dispExprUser: 180,
+    feeRate: 60,
+    displayFieldName: 120,
+    statement: 380,
+    memo: 110,
+    unitFee: 90,
+    totalFee: 90
+};

+ 0 - 66
web/building_saas/main/js/rpt/rpt_main.js

@@ -1,66 +0,0 @@
-/**
- * Created by Tony on 2017/6/26.
- */
-'use strict'
-
-let rptTplObj = {
-    iniPage: function() {
-        let me = this
-        zTreeOprObj.getReportTemplateTree(RT.GrpType.CONSTRUCT);
-    }
-}
-
-let zTreeOprObj = {
-    treeObj: null,
-    currentNode: null,
-    getReportTemplateTree: function(grpType) {
-        let me = zTreeOprObj, params = {};
-        params.grpType = grpType;
-        params.userId = userID;
-        params.tplType = RT.TplType.ALL;
-        CommonAjax.postEx("report_tpl_api/getRptTplTree", params, 20000, true, function(result){
-                zTreeHelper.createTree(result, setting, "rptTplTree", me);
-                me.refreshNodes();
-            }, null, null
-        );
-    },
-    refreshNodes: function() {
-        let me = this;
-        let private_setupIsParent = function(node){
-            if (node.nodeType == RT.NodeType.NODE) {
-                node.isParent = true;
-            } else {
-                node.isParent = false;
-            }
-            if (node.items && node.items.length) {
-                for (let i = 0; i < node.items.length; i++) {
-                    private_setupIsParent(node.items[i]);
-                }
-            }
-        };
-        let topNodes = me.treeObj.getNodes();
-        for (let i = 0; i < topNodes.length; i++) {
-            private_setupIsParent(topNodes[i]);
-        }
-        me.treeObj.refresh();
-    },
-    onCheck: function() {
-        //count();
-        //if (clearFlag) {
-        //    clearCheckedOldNodes();
-        //}
-    },
-    onClick: function(event,treeId,treeNode) {
-        let me = zTreeOprObj;
-        if (treeNode.nodeType == RT.NodeType.NODE) {
-            me.currentNode = treeNode;
-            $("#rpt_tpl_display_label")[0].innerText = "...";
-        } else if (treeNode.nodeType == RT.NodeType.TEMPLATE) {
-            me.currentNode = null;
-            $("#rpt_tpl_display_label")[0].innerText = treeNode.name;
-            if (treeNode.refId < 0) {
-                //创建新报表模板
-            }
-        }
-    }
-}

+ 14 - 12
web/building_saas/main/js/views/calc_program_manage.js

@@ -14,24 +14,28 @@ let rationPM = {
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1]
+            lockColumns:[0,1],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 
     detailSetting: {
         header:[
             // {headerName:"ID",headerWidth:80,dataCode:"ID", hAlign: "center"},
-            {headerName:"费用代号",headerWidth:80,dataCode:"code", dataType: "String"},
-            {headerName:"费用名称",headerWidth:200,dataCode:"name", dataType: "String"},
-            {headerName:"计算基数",headerWidth:180,dataCode:"dispExprUser", dataType: "String"},
-            {headerName:"基数说明",headerWidth:300,dataCode:"statement", dataType: "String"},
-            {headerName:"费率",headerWidth:80,dataCode:"feeRate", dataType: "Number",hAlign: "left",tofix:feeRate_consts.decimal},
-            {headerName:"字段名称",headerWidth:140,dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
-            {headerName:"备注",headerWidth:100,dataCode:"memo", dataType: "String"}
+            {headerName:"费用代号",headerWidth:CP_Col_Width.code, dataCode:"code", dataType: "String"},
+            {headerName:"费用名称",headerWidth:CP_Col_Width.name, dataCode:"name", dataType: "String"},
+            {headerName:"计算基数",headerWidth:CP_Col_Width.dispExprUser, dataCode:"dispExprUser", dataType: "String"},
+            {headerName:"费率",headerWidth:CP_Col_Width.feeRate, dataCode:"feeRate", dataType: "Number",hAlign: "right",tofix: feeRate_consts.decimal},
+            {headerName:"费用类别",headerWidth:CP_Col_Width.displayFieldName, dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
+            {headerName:"基数说明",headerWidth:CP_Col_Width.statement, dataCode:"statement", dataType: "String"},
+            {headerName:"备注",headerWidth:CP_Col_Width.memo, dataCode:"memo", dataType: "String"}
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1,2,3,6]
+            lockColumns:[0,1,2,3,5,6],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 
@@ -51,8 +55,7 @@ let rationPM = {
 
         var fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
         fieldName.items(projectObj.project.calcProgram.calc.compiledFeeTypeNames);
-        // fieldName.items(["直接费","人工费","材料费","机械费","主材费","企业管理费","利润","风险费","人工价差","材料价差","机械价差","工程造价","调整人工费","调整机上人工费","甲供材料费"]);
-        me.detailSpread.getSheet(0).getRange(-1, 5, -1, 1).cellType(fieldName);
+        me.detailSpread.getSheet(0).getRange(-1, 4, -1, 1).cellType(fieldName);
 
         me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
         me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.CellChanged, me.onDetailCellChanged);
@@ -64,7 +67,6 @@ let rationPM = {
         feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
         dSheet.name('calc_detail');
         sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
-
     },
     onMainEnterCell: function(sender, args) {
         var me = rationPM;

+ 12 - 9
web/building_saas/main/js/views/calc_program_view.js

@@ -201,18 +201,21 @@ let calcProgramObj = {
 
     setting: {
         header: [
-            {headerName: "费用代号", headerWidth: 75, dataCode: "code", dataType: "String", hAlign: "left"},
-            {headerName: "费用名称", headerWidth: 200, dataCode: "name", dataType: "String"},
-            {headerName: "计算基数", headerWidth: 200, dataCode: "dispExprUser", dataType: "String"},
-            {headerName: "基数说明", headerWidth: 400, dataCode: "statement", dataType: "String"},
-            {headerName: "费率", headerWidth: 80, dataCode: "feeRate", dataType: "Number"},   // precision: 3
-            {headerName: "单价", headerWidth: 100, dataCode: "unitFee", dataType: "Number"},  // execRst
-            {headerName: "合价", headerWidth: 100, dataCode: "totalFee", dataType: "Number"},
-            {headerName: "备注", headerWidth: 120, dataCode: "memo", dataType: "String"}
+            {headerName: "费用代号", headerWidth: CP_Col_Width.code, dataCode: "code", dataType: "String", hAlign: "left"},
+            {headerName: "费用名称", headerWidth: CP_Col_Width.name, dataCode: "name", dataType: "String"},
+            {headerName: "计算基数", headerWidth: CP_Col_Width.dispExprUser, dataCode: "dispExprUser", dataType: "String"},
+            {headerName: "费率", headerWidth: CP_Col_Width.feeRate, dataCode: "feeRate", dataType: "Number"},   // precision: 3
+            {headerName:"费用类别", headerWidth:CP_Col_Width.displayFieldName, dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
+            {headerName: "基数说明", headerWidth: CP_Col_Width.statement, dataCode: "statement", dataType: "String"},
+            {headerName: "单价", headerWidth: CP_Col_Width.unitFee, dataCode: "unitFee", dataType: "Number"},  // execRst
+            {headerName: "合价", headerWidth: CP_Col_Width.totalFee, dataCode: "totalFee", dataType: "Number"},
+            {headerName: "备注", headerWidth: CP_Col_Width.memo, dataCode: "memo", dataType: "String"}
         ],
         view: {
             comboBox: [],
-            lockColumns: [0, 1, 2, 3, 4, 5, 6, 7]
+            lockColumns: [0,1,2,3,4,5,6,7,8],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 

+ 4 - 0
web/building_saas/main/js/views/glj_view.js

@@ -16,6 +16,7 @@ var gljOprObj = {
     detailData:[],
     GLJSelection:[],
     parentNodeIds:{},
+    activeTab:'#linkGLJ',
     setting: {
         header: [
             {headerName: "编码", headerWidth: 100, dataCode: "code", dataType: "String", formatter: "@"},
@@ -582,6 +583,9 @@ var gljOprObj = {
         details=_.sortBy(details,'seq');
         sheetCommonObj.showData(this.detailSheet,this.detailSetting,details);
         this.detailData = details;
+        if(MainTreeCol.readOnly.forQuantifyDetail(node)){
+            this.detailSheet.getRange(-1,0,-1,this.detailSetting.header.length).locked(true);
+        }
     },
     clearSheetData:function () {
         sheetCommonObj.showData(this.sheet,this.setting,[]);

+ 3 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -50,6 +50,9 @@ let MainTreeCol = {
         },
         forTotalFee: function (node) {
             return MainTreeCol.readOnly.non_bills(node) || MainTreeCol.readOnly.billsParent(node) || (MainTreeCol.readOnly.leafBillsWithDetail(node));
+        },
+        forQuantifyDetail:function (node) {
+            return !(node.sourceType==ModuleNames.ration||!MainTreeCol.readOnly.billsParent(node));
         }
     },
     cellType: {

+ 0 - 1
web/building_saas/main/js/views/project_property_labour_coe_view.js

@@ -37,7 +37,6 @@ let labourCoeView = {
         me.spread.options.tabStripVisible = false;
         me.spread.options.showVerticalScrollbar = false;
         me.spread.options.showHorizontalScrollbar = false;
-        me.spread.options.rowHeight = 50;
         let sheetArea = GC.Spread.Sheets.SheetArea;
         let sheet = me.spread.getSheet(0);
         me.sheet = sheet;

+ 6 - 0
web/building_saas/main/js/views/sub_view.js

@@ -40,6 +40,7 @@ $("#linkGLJ").click(function(){
     subSpread.setActiveSheetIndex(0);
     $.contextMenu( 'destroy', "#subSpread" );
     gljContextMenu.loadGLJSpreadContextMenu();
+    gljOprObj.activeTab='#linkGLJ';
     // for test
     //subSpread.getActiveSheet().setValue(0, 0, "工料机");
 });
@@ -51,6 +52,7 @@ $("#linkFZDE").click(function(){
     refreshSubSpread();
     subSpread.setActiveSheetIndex(1);
     $.contextMenu( 'destroy', "#subSpread" );
+    gljOprObj.activeTab='#linkFZDE';
     // for test
   //  subSpread.getActiveSheet().setValue(0, 0, "辅助定额");
 });
@@ -61,6 +63,7 @@ $("#linkFZTJ").click(function(){
     refreshSubSpread();
     subSpread.setActiveSheetIndex(2);
     $.contextMenu( 'destroy', "#subSpread" );
+    gljOprObj.activeTab='#linkFZTJ';
     // for test
     //subSpread.getActiveSheet().setValue(0, 0, "附注条件");
 });
@@ -73,6 +76,7 @@ $("#linkGCLMX").click(function(){
     subSpread.setActiveSheetIndex(3);
     $.contextMenu( 'destroy', "#subSpread" );
     gljContextMenu.loadQuantityDetailMenu();
+    gljOprObj.activeTab='#linkGCLMX';
     // for test
     //subSpread.getActiveSheet().setValue(0, 0, "工程量明细");
 });
@@ -93,6 +97,7 @@ $("#linkJSCX").click(function(){        // 计算程序
     } else {
         calcProgramObj.clearData();
     };
+    gljOprObj.activeTab='#linkJSCX';
 });
 
 //特征及内容
@@ -109,6 +114,7 @@ $("#linkTZJNR").click(function () {
     else{
         pageCCOprObj.clearData();
     }
+    gljOprObj.activeTab='#linkTZJNR';
 });
 function SubActiveSheetNameIs(sheetName){
     let rst = subSpread.getActiveSheet().name() == sheetName;

+ 67 - 0
web/building_saas/pm/html/project-management-Recycle.html

@@ -0,0 +1,67 @@
+<div class="toolsbar">
+    <legend class="m-0 pb-1">全部</legend>
+</div>
+<div class="poj-list">
+    <table class="table table-hover table-sm mb-5" id="gcTree">
+        <thead>
+        <tr>
+            <th width="50%">工程列表</th>
+            <th width="10%">删除日期</th>
+            <th width="10%">创建日期</th>
+            <th width="10%">恢复</th>
+            <th width="10%">单价文件</th>
+            <th width="10%">费率文件</th>
+        </tr>
+        </thead>
+        <tbody>
+        </tbody>
+    </table>
+</div>
+<!--弹出恢复项目-->
+<div class="modal fade" id="rePoj" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">恢复 <i class="fa fa-cubes"></i> 建设项目</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <p><i class="fa fa-cubes"></i> 汽车生产车间 下的单位工程都将恢复都将恢复,恢复后将重命名为</p>
+                <p><b>建筑工程2(10-25 14:33:15恢复)</b>、<b>建筑工程3(10-25 14:33:15恢复)</b></p>
+                <p> 点“确定”按钮,确认从回收站中恢复。</p>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" data-dismiss="modal" id="rePojBtn">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
+<!--弹出恢复文件-->
+<div class="modal fade" id="reFile" 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 modal-fixed-height">
+                <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>
+                <table class="table table-hover table-sm mb-5">
+                    <thead><tr><th>名称</th><th>删除时间</th><th>勾选</th></tr></thead>
+                    <tbody>
+                    <tr><td>XX单价文件</td><td>2017-11-01<br>12:11:43</td><td><input type="checkbox"></td></tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" id="reFileBtn" data-dismiss="modal">确定</a>
+            </div>
+        </div>
+    </div>
+</div>

+ 38 - 30
web/building_saas/pm/html/project-management.html

@@ -91,7 +91,7 @@
                         <input type="text" class="my-2 form-control form-control-sm" placeholder="搜索所有工程">
                         <ul class="nav nav-pills flex-column">
                             <li class="nav-item">
-                                <a class="nav-link active" href="#">全部</a>
+                                <a class="nav-link active" data-toggle="tab" href="#pm_all" role="tab" id="tab_pm_all">全部</a>
                             </li>
                             <li class="nav-item">
                                 <a class="nav-link" href="#">最近使用</a>
@@ -106,42 +106,49 @@
                                 <a class="nav-link" href="#">归档</a>
                             </li>
                             <li class="nav-item">
-                                <a class="nav-link" href="#">回收站</a>
+                                <a class="nav-link" data-toggle="tab" role="tab" href="#pm_gc" id="tab_pm_gc">回收站</a>
                             </li>
                         </ul>
                     </div>
                 </div>
                 <div class="col-lg-10">
-                <div class="toolsbar">
-                    <div class="tools-btn btn-group align-top">
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>
-                        <a href="javascript:void(0);" class="btn btn-sm" id="copy-to-btn">复制到...</a>
-                        <a href="" class="btn btn-sm" id="share-btn">共享</a>
-                        <a href="" class="btn btn-sm" id="cooperate-btn">协同</a>
+                    <div class="tab-content">
+                        <div class="tab-pane active" id="pm_all" role="tabpanel">
+                        <div class="toolsbar">
+                            <div class="tools-btn btn-group align-top">
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-project-btn"><i class="fa fa-cubes"></i>&nbsp;新建建设项目</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-engineering-btn"><i class="fa fa-cube"></i>&nbsp;新建单项工程</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-tender-btn"><i class="fa fa-sticky-note-o"></i>&nbsp;新建单位工程</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="add-folder-btn"><i class="fa fa-folder-o"></i>&nbsp;新建文件夹</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="rename-btn">重命名</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="del-btn">删除</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="move-to-btn">移动到...</a>
+                                <a href="javascript:void(0);" class="btn btn-sm" id="copy-to-btn">复制到...</a>
+                                <a href="" class="btn btn-sm" id="share-btn">共享</a>
+                                <a href="" class="btn btn-sm" id="cooperate-btn">协同</a>
+                            </div>
+                        </div>
+                        <div class="poj-list">
+                            <legend>全部</legend>
+                            <table class="table table-hover table-sm" id="ProjTree">
+                                <thead>
+                                <tr>
+                                    <th width="40"></th>
+                                    <th width="78%">工程列表</th>
+                                    <th width="10%">最近使用</th>
+                                    <th width="10%">创建日期</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                </tbody>
+                            </table>
+                        </div>
+                        </div>
+                        <div class="tab-pane" role="tabpanel" id="pm_gc">
+                            <%include project-management-Recycle.html %>
+                        </div>
                     </div>
                 </div>
-                <div class="poj-list">
-                    <legend>全部</legend>
-                    <table class="table table-hover table-sm" id="ProjTree">
-                        <thead>
-                        <tr>
-                            <th width="40"></th>
-                            <th width="78%">工程列表</th>
-                            <th width="10%">最近使用</th>
-                            <th width="10%">创建日期</th>
-                        </tr>
-                        </thead>
-                        <tbody>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
         </div>
     </div>
     <div class="slide-sidebar">
@@ -505,6 +512,7 @@
 <script type="text/javascript" src="/public/web/common_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_ajax.js"></script>
 <script src="/web/building_saas/pm/js/pm_main.js" charset="UTF-8"></script>
+<script src="/web/building_saas/pm/js/pm_gc.js"></script>
 <!-- zTree -->
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.core.js"></script>
 <script type="text/javascript" src="/lib/ztree/jquery.ztree.excheck.js"></script>

+ 656 - 0
web/building_saas/pm/js/pm_gc.js

@@ -0,0 +1,656 @@
+/**
+ * Created by Zhong on 2017/10/30.
+ */
+//测试数据
+let deleteInfo = {deleteBy: 76075, deleteDateTime: '2017-10-31', deleted: true};
+let temp_gc_datas = [
+    {ID: 1, ParentID: -1, NextSiblingID: 7, name: 'testTreeA', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo,
+        unitPriceFiles: [{name: 'uA', id: 100, root_project_id: 1, user_id: 76075, deleteInfo: deleteInfo}, {name: 'uB', id: 101, root_project_id: 1, user_id: 76075, deleteInfo: deleteInfo}],
+        feeRateFiles: [{name: 'fA', ID: 'fr-1', rootProjectID: 1, userID: 76075, deleteInfo: deleteInfo}, {name: 'fB', ID: 'fr-2', rootProjectID: 1, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 2, ParentID: 1, NextSiblingID: 3, name: 'enA', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 3, ParentID: 1, NextSiblingID: -1, name: 'enB', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 4, ParentID: 3, NextSiblingID: 5, name: 'tenderA', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-1', name: 'fA'}, unitPriceFile: {id: 100, name: 'uA'}}},
+    {ID: 5, ParentID: 3, NextSiblingID: 6, name: 'tenderB', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'unD-1', name: 'unDF'}, unitPriceFile: {id: 100, name: 'uA'}}},
+    {ID: 6, ParentID: 3, NextSiblingID: -1, name: 'tenderC', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-2', name: 'fB'}, unitPriceFile: {id: 101, name: 'uB'}}},
+    {ID: 7, ParentID: -1, NextSiblingID: 10, name: 'testTreeB', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo,
+        unitPriceFiles: [{name: 'uC', id: 102, root_project_id: 7, user_id: 76075, deleteInfo: deleteInfo}, {name: 'uD', id: 103, root_project_id: 7, user_id: 76075, deleteInfo: deleteInfo}],
+        feeRateFiles: [{name: 'fC', ID: 'fr-3', rootProjectID: 7, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 8, ParentID: 7, NextSiblingID: -1, name: 'enC', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo},
+    {ID: 9, ParentID: 8, NextSiblingID: -1, name: 'tenderD', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 10, ParentID: -1, NextSiblingID: -1, name: 'testTreeC', projType: 'Project', userID: 76075, createDateTime: '2017-10-30', unitPriceFiles: [], feeRateFiles: [{name: 'fC', ID: 'fr-3', rootProjectID: 7, userID: 76075, deleteInfo: deleteInfo}]},
+    {ID: 11, ParentID: 10, NextSiblingID: -1, name: 'enD', projType: 'Engineering', userID: 76075, createDateTime: '2017-10-30'},
+    {ID: 12, ParentID: 11, NextSiblingID: -1, name: 'tenderE', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 103, name: 'uD'}}},
+    {ID: 13, ParentID: 2, NextSiblingID: 14, name: 'tenderF', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'unD-2', name: 'unDF2'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 14, ParentID: 2, NextSiblingID: 15, name: 'tenderG', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'fr-3', name: 'fC'}, unitPriceFile: {id: 102, name: 'uC'}}},
+    {ID: 15, ParentID: 2, NextSiblingID: -1, name: 'tenderH', projType: 'Tender', userID: 76075, createDateTime: '2017-10-30', deleteInfo: deleteInfo, property: {feeFile: {id: 'qwqw', name: 'qweq'}, unitPriceFile: {id: 300, name: 'u30'}}}
+
+];
+
+/*function getTestDatas(){
+    let rst = [];
+    for(let i = 0; i < 1000; i ++){
+        let nid = i + 1 < 1000 ? i + 1 : -1;
+        let obj = {ID: i, ParentID: -1, NextSiblingID: nid, name : 'test' + i, projType: 'Project', userID: 76075, createDateTime: '2017-11-3', deleteInfo: deleteInfo,
+            unitPriceFiles: [{name: 'up' + i, id: i + 10000, deleteInfo: deleteInfo}], feeRateFiles: [{name: 'ff' + i, id: 'fr-' + i, deleteInfo: deleteInfo}]};
+        rst.push(obj);
+    }
+    return rst;
+}*/
+let gcTree = null;
+let decDate = null;//恢复后的名称后缀(时间+恢复)
+/*let projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering'
+};*/
+let fileType = {
+    unitPriceFile: 'UnitPriceFile',
+    feeRateFile: 'FeeRateFile'
+};
+//恢复路径t = tender, e = engineering, p = project
+let recPath = {t: 'T', t_e: 'T_E', t_e_p: 'T_E_P', e: 'E', e_p: 'E_P', p: 'P'};
+let gcTreeSetting = {
+    tree: {
+        id: 'ID',
+        pid: 'ParentID',
+        nid: 'NextSiblingID',
+        btnColumn: 1,
+        nullId: -1
+    },
+    columns: [
+        {
+            head: '',
+            data: '',
+            width: '40',
+            event: {}
+        },
+        {
+            head: '工程列表',
+            data: 'name',
+            width: '50%',
+            event: {
+                getText: function (html, node, text) {
+                    let className = '';
+                    switch (node.data.projType) {
+                        case projectType.folder:
+                            className = "fa fa-folder-open-o";
+                            break;
+                        case projectType.tender:
+                            className = "fa fa-sticky-note-o";
+                            break;
+                        case projectType.project:
+                            className = "fa fa-cubes";
+                            break;
+                        case projectType.engineering:
+                            className = "fa fa-cube";
+                            break;
+                    }
+                    let icon = '<i class ="tree-icon '+ className +'"></i>';
+                    html.push(icon, '&nbsp;', text);
+                },
+                getIcon: function (html, node) {
+                    if (node.data.projType === projectType.tender) {
+                        html.push('<span class="poj-icon">└</span>');
+                    }
+                }
+            }
+        },
+        {
+            head: '删除日期',
+            data: 'deleteDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === projectType.tender) {
+                        html.push(deleted(node) ?
+                            node.data.deleteInfo.deleteDateTime : '');
+                     //   html.push(text ? new Date(text).Format('yyyy-MM-dd') : '');
+                    }
+                }
+            }
+        },
+        {
+            head: '创建日期',
+            data: 'createDateTime',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if (node.data.projType === projectType.tender) {
+                      html.push(text ? text : '');
+                    }
+                }
+            }
+        },
+        {
+            head: '恢复',
+            data: 'recovery',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else if(node.data.projType === projectType.engineering && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else if(node.data.projType === projectType.tender && deleted(node)){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#rePoj">恢复</a>');
+                    }
+                    else {
+                        html.push('');
+                    }
+                },
+                tdBindEvent: function(td, node){
+                    $('a:eq(0)' ,td).bind('click', function () {
+                        let tenderNodes = m_getTenders(node);
+                        $('#rePoj .modal-header').empty();
+                        $('p', '#rePoj .modal-body').remove();
+                        $('#rePoj .modal-header').html(v_getTitle(node));
+                        $('#rePoj .modal-body').html(v_getMoBody(node, tenderNodes));
+                        console.log(node);
+                        console.log(node.preSibling());
+                        //test 获取更新的数据
+                        /*let updateDatas = m_getRecDatas(node);
+                        console.log(updateDatas);*/
+                    });
+                }
+            }
+        },
+        {
+            head: '单价文件',
+            data: 'unitPriceFiles',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && node.data.unitPriceFiles !== undefined && node.data.unitPriceFiles.length > 0){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#reFile">恢复</a>');
+                    }
+                },
+                tdBindEvent: function (td, node) {
+                    $('a:eq(0)', td).bind('click', function () {
+                        let unitPriceFiles = node.data.unitPriceFiles;
+                        $('#reFile h5').text('恢复单价文件');
+                        $('tr', '#reFile tbody').remove();
+                        $('#reFile tbody').html(v_getFiles(fileType.unitPriceFile, unitPriceFiles));
+                    });
+                }
+            }
+        },
+        {
+            head: '费率文件',
+            data: 'feeRateFiles',
+            width: '10%',
+            event: {
+                getText: function (html, node, text) {
+                    if(node.data.projType === projectType.project && node.data.feeRateFiles !== undefined && node.data.feeRateFiles.length > 0){
+                        html.push('<a href="javascript:void(0);" data-toggle="modal" data-target="#reFile">恢复</a>');
+                    }
+                },
+                tdBindEvent: function (td, node) {
+                    $('a:eq(0)', td).bind('click', function () {
+                        let feeRateFiles = node.data.feeRateFiles;
+                       $('#reFile h5').text('恢复费率文件');
+                        $('tr', '#reFile tbody').remove();
+                        $('#reFile tbody').html(v_getFiles(fileType.feeRateFile, feeRateFiles));
+                    });
+                }
+            }
+        }
+    ]
+};
+
+$(document).ready(function () {
+    $('#tab_pm_gc').on('show.bs.tab', function () {
+        gc_init();
+        Tree = null;
+    });
+    e_recFiles($('#reFileBtn'));
+    e_recProj($('#rePojBtn'));
+});
+
+function gc_init(){
+    let table = $('#gcTree');
+    $('thead', table).remove();
+    $('tbody', table).remove();
+    m_buildVirtualTree(temp_gc_datas);
+    gcTree = $.fn.treeTable.init(table, gcTreeSetting, temp_gc_datas);
+    //gcTree = $.fn.treeTable.init(table, gcTreeSetting, getTestDatas());
+}
+
+//项目恢复模态框标题
+function v_getTitle(node){
+    let html = '';
+    html += '<h5 class="modal-title">恢复 ';
+    if(node.data.projType === projectType.project){
+        html += '<i class="fa fa-cubes"></i>建设项目</h5>';
+    }
+    else if(node.data.projType === projectType.engineering){
+        html += '<i class="fa fa-cube"></i>单项工程</h5>';
+    }
+    else if(node.data.projType === projectType.tender){
+        html += '<i class="fa fa-sticky-note-o"></i>单位工程</h5>';
+    }
+    html += '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>';
+    return html;
+}
+
+//项目恢复模态框主体
+function v_getMoBody(oprNode, nodes){
+    let html = '';
+    if(oprNode.data.projType === projectType.tender){
+        decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
+        let recName = oprNode.data.name + decDate;
+        html += '<p>恢复后将重命名为 <b>' + recName + '</b></p>';
+    }
+    else {
+        if(oprNode.data.projType === projectType.project){
+            html += '<p><i class="fa fa-cubes"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+        }
+        else if(oprNode.data.projType === projectType.engineering){
+            html += '<p><i class="fa fa-cube"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+        }
+        html += ('<p>');
+        for(let i = 0, len = nodes.length; i < len; i++){
+            let recName = nodes[i].data.name + '(' + new Date().Format('MM-dd hh:mm:ss') +'恢复)';
+            html += '<b>' + recName + '</b>、';
+        }
+        html = html.slice(0, html.length - 1);
+        html += ('</p>');
+    }
+
+    html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
+    return html;
+}
+
+//单价、费率文件恢复弹出框数据
+function v_getFiles(type, files){
+    let html = '';
+    for(let i = 0, len = files.length; i < len; i ++){
+        let recName = type === fileType.unitPriceFile ?  files[i].name + '单价文件' : files[i].name + '费率文件';
+        let fileId = type === fileType.unitPriceFile ? files[i].id : files[i].ID;
+        let recTime = new Date();
+        let recTimeA = recTime.Format('yyyy-MM-dd');
+        let recTimeB = recTime.Format('hh:mm:ss');
+        html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+    }
+    return html;
+}
+
+//恢复单价、费率文件后前端显示变化
+function v_recFiles(project, fileIds, type){
+    let projFiles;
+    if(type === fileType.unitPriceFile){
+        projFiles = project.data.unitPriceFiles;
+    }
+    else if(type === fileType.feeRateFile){
+        projFiles = project.data.feeRateFiles;
+    }
+    if(projFiles && projFiles.length > 0){
+        let tempFiles = [];
+        for(let i = 0, len = projFiles.length; i < len; i++){
+            let isExist = false;
+            for(let j = 0, jLen = fileIds.length; j < jLen; j++){
+                let id = projFiles[i].id || projFiles[i].ID || null;
+                if(id && id === fileIds[j]){
+                    isExist = true;
+                }
+            }
+            if(!isExist){
+                tempFiles.push(projFiles[i]);
+            }
+        }
+        if(type === fileType.unitPriceFile){
+            project.data.unitPriceFiles = tempFiles;
+        }
+        else if(type === fileType.feeRateFile){
+           project.data.feeRateFiles = tempFiles;
+        }
+    }
+}
+
+function v_removeNode(node){
+    gcTree.removeNode(node);
+    let parent = node.parent || null;
+    if(parent && parent.children.length === 0 && parent.data !== undefined){
+        v_removeNode(parent);
+    }
+}
+
+function v_refreshNode(node){
+    if(deleted(node)){
+        delete node.data.deleteInfo;
+    }
+    gcTree.refreshNodesDom([node]);
+    let parent = node.parent || null;
+    if(parent && parent.data !== undefined){
+        v_refreshNode(parent);
+    }
+}
+
+//将获取的回收站中的数据建虚拟树
+function m_buildVirtualTree(datas){
+    for(let i = 0, len = datas.length; i < len; i++){
+        let children = datas[i].children || null;
+        if(children){
+            m_buildVirtualTree(children);
+        }
+        let next = datas[i+1] || null;
+        if(next){
+            datas[i].NextSiblingID = next.ID;
+        }
+        else {
+            datas[i].NextSiblingID = -1;
+        }
+    }
+}
+
+//获得当前节点的tenders数据,模态提示框用
+function m_getTenders(node){
+    if(node.data.projType === projectType.tender) return [node];
+    else {
+        let rst = [];
+        if(node.children.length > 0){
+            node.children.forEach(function (cNode) {
+                if(cNode.children.length > 0){
+                    cNode.children.forEach(function (ccNode) {
+                       if(ccNode.data.projType === projectType.tender) rst.push(ccNode);
+                    });
+                }
+                else if(cNode.children.length === 0 && cNode.data.projType === projectType.tender){
+                    rst.push(cNode);
+                }
+            });
+        }
+        return rst;
+    }
+}
+
+//获得要更新的数据(包含恢复的数据,维护项目管理树的数据)
+function m_getRecDatas(oprNode){
+    let rst = Object.create(null);
+    let rstProj = [], rstFile = [];
+    let path;
+    if(oprNode.data.projType === projectType.tender){
+        path = recPath.t;
+        let engineering = oprNode.parent || null;
+        if(!engineering) return null;
+        let project = engineering.parent || null;
+        if(!project) return null;
+        if(engineering && deleted(engineering)){
+            path = recPath.t_e;
+        }
+        //恢复建设项目
+        if(project && deleted(project)){
+            path = recPath.t_e_p;
+        }
+        //恢复单价、费率文件
+        rstFile = rstFile.concat(getUpdateFiles([oprNode], project));
+        if(path === recPath.t){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, true));
+        }
+        else if(path === recPath.t_e){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineering, true, true));
+        }
+        else if(path === recPath.t_e_p){
+            rstProj = rstProj.concat(getUpdateDatas(projectType.tender, oprNode, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineering, true, false));
+            rstProj = rstProj.concat(getUpdateDatas(projectType.project, project, true, false));
+        }
+    }
+    else if(oprNode.data.projType === projectType.engineering){
+        path = recPath.e;
+        let project = oprNode.parent || null;
+        if(!project) return null;
+        //恢复建设项目
+        if(project && deleted(project)){
+            path = recPath.e_p;
+        }
+        let tenders = oprNode.children;
+        if(tenders.length > 0){
+            for(let i = 0, len = tenders.length; i < len; i++){
+                rstProj = rstProj.concat(getUpdateDatas(projectType.tender, tenders[i], true, false));
+            }
+            //恢复单价、费率文件
+            rstFile = rstFile.concat(getUpdateFiles(tenders, project));
+        }
+        if(path === recPath.e){
+            rstProj= rstProj.concat(getUpdateDatas(projectType.engineering, oprNode, true, true));
+        }
+        else if(path === recPath.e_p){
+            rstProj= rstProj.concat(getUpdateDatas(projectType.engineering, oprNode, true, false));
+            rstProj= rstProj.concat(getUpdateDatas(projectType.project, project, true, false));
+        }
+    }
+    else if(oprNode.data.projType === projectType.project){
+        path = recPath.p;
+        let engineerings = oprNode.children;
+        if(engineerings.length > 0){
+            let allTenders = [];
+            for(let i = 0, len = engineerings.length; i < len; i++){
+                //恢复单项工程
+                rstProj = rstProj.concat(getUpdateDatas(projectType.engineering, engineerings[i], false, false));
+                let tenders = engineerings[i].children;
+                allTenders = allTenders.concat(tenders);
+                for(let j = 0, jLen = tenders.length; j < jLen; j++){
+                    //恢复单位工程
+                    rstProj = rstProj.concat(getUpdateDatas(projectType.tender, tenders[j], false, false));
+                }
+            }
+            //恢复单价、费率文件
+            rstFile = rstFile.concat(getUpdateFiles(allTenders, oprNode));
+        }
+        //恢复建设项目
+        rstProj = rstProj.concat(getUpdateDatas(projectType.project, oprNode, false, false));
+    }
+    console.log(path);
+    rst.proj = rstProj;
+    rst.file = rstFile;
+    return rst;
+}
+
+//获得勾选的单价、费率文件的id
+function m_getFilesIds(nodes){
+    let rstSet = new Set();
+    for(let i = 0, len = nodes.length; i < len; i++){
+        let fileId = $(nodes[i]).attr('fileId') || null;
+        if(fileId){
+            if($(nodes[i]).attr('fileType') === fileType.unitPriceFile){
+                fileId = parseInt(fileId);
+            }
+            rstSet.add(fileId);
+        }
+    }
+    return Array.from(rstSet);
+}
+
+function m_project(node){
+    if(node && node.data.projType === projectType.project) return node;
+    if(!node) return null;
+    let parent = node.parent || null;
+    if(!parent) return null;
+    if(parent && parent.data.projType === projectType.project) return parent;
+
+    let gParent = parent.parent || null;
+    if(!gParent) return null;
+    if(gParent && gParent.data.projType === projectType.project) return gParent;
+    return null;
+}
+
+//点击单价文件、费率文件下的恢复操作(确认)
+function e_recFiles(btn){
+    btn.bind('click', function () {
+        let recIds = m_getFilesIds($('[name = "fileItems"]:checked'));
+        let fileType = $('[name = "fileItems"]:checked').attr('fileType');
+        let selected = gcTree.selected();
+        //backend
+        let updateDatas = [];
+        for(let i = 0, len = recIds.length; i < len; i++){
+            updateDatas.push(getUpdateObj(fileType, {id: recIds[i]}, {deleteInfo: null}));
+        }
+        //front
+        if(recIds.length > 0){
+            v_recFiles(selected, recIds, fileType);
+            if(deleted(selected)){
+                delete selected.data.deleteInfo;
+            }
+            gcTree.refreshNodesDom([selected]);
+        }
+    });
+}
+
+//点击项目下的恢复操作(确认
+function e_recProj(btn){
+    btn.bind('click', function () {
+        let selected = gcTree.selected();
+        //backend
+        let updateObj = m_getRecDatas(selected);
+        let updateDatas = updateObj.proj.concat(updateObj.file);
+        let fileObj = getRecFileObj(updateObj.file);
+        console.log(updateObj);
+        //保存成功后回调front
+        //front
+        let project = m_project(selected);
+        if(project){
+            if(fileObj[fileType.unitPriceFile].length > 0){
+                v_recFiles(project, fileObj[fileType.unitPriceFile], fileType.unitPriceFile);
+            }
+            if(fileObj[fileType.feeRateFile].length > 0){
+                v_recFiles(project, fileObj[fileType.feeRateFile], fileType.feeRateFile);
+            }
+        }
+        v_removeNode(selected);
+        v_refreshNode(selected);
+    });
+}
+
+function a_getGC(callback){
+    $.ajax({
+        type: 'post',
+        url: '/pm/api/getGCDatas',
+        dataType: 'json',
+        timeout: 5000,
+        success: function (result) {
+            if(!result.error){
+                if(callback){
+                    callback(result.data);
+                }
+            }
+        }
+    })
+}
+
+function a_rec(nodes, callback){
+    $.ajax({
+        type: 'post',
+        url: '/pm/api/recGC',
+        data: {nodes: JSON.stringify(nodes)},
+        dataType: 'json',
+        timeout: 5000,
+        success: function (result) {
+            if(!result.error){
+                if(callback){
+                    callback();
+                }
+            }
+        }
+    })
+}
+
+function deleted(node){
+    return node.data.deleteInfo !== undefined && node.data.deleteInfo.deleted;
+}
+
+function fIsExist(files, id, type){
+    let isExist = false;
+    for(let i = 0, len = files.length; i < len; i++){
+        if((type === fileType.unitPriceFile && files[i].id === id) || (type === fileType.feeRateFile && files[i].ID === id)){
+            isExist = true;
+            break;
+        }
+    }
+    return isExist;
+}
+
+function getRecFileObj(files){
+    let rst = Object.create(null);
+    let rst_UF = [], rst_FF = [];
+    for(let i = 0, len = files.length; i < len; i++){
+        if(files[i].findData !== undefined && files[i].findData.id !== undefined){
+            if(files[i].updateType === fileType.unitPriceFile){
+                rst_UF.push(files[i].findData.id);
+            }
+            else if(files[i].updateType === fileType.feeRateFile){
+                rst_FF.push(files[i].findData.id);
+            }
+        }
+    }
+    rst[fileType.unitPriceFile] = rst_UF;
+    rst[fileType.feeRateFile] = rst_FF;
+    return rst;
+}
+
+function getUpdateObj(updateType, findData, updateData){
+    let obj = Object.create(null);
+    obj.updateType = updateType;
+    obj.findData = findData;
+    obj.updateData = updateData;
+    return obj;
+}
+
+function getUpdateDatas(updateType, node, mtNID, mtPM){
+    let rst = [];
+    if(!decDate){
+        decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
+    }
+    if(updateType === projectType.tender || updateType === projectType.engineering){
+        //维护回收站树
+     /*   if(mtGC){
+            rst.push(getUpdateObj(updateType, {NextSiblingID: node.data.ID, 'deleteInfo.deleted': true}, {NextSiblingID: node.data.NextSiblingID}));
+        }*/
+        //维护项目管理树
+        if(mtPM){
+            rst.push(getUpdateObj(updateType, {ParentID: node.data.ParentID, NextSiblingID: -1, deleteInfo: null}, {NextSiblingID: node.data.ID}));
+        }
+        //恢复
+        if(mtNID){
+            rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null, NextSiblingID: -1}));
+        }
+        else {
+            rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null}));
+        }
+    }
+    else if(updateType === projectType.project){
+       /* //维护回收站树
+        if(mtGC){
+            rst.push(getUpdateObj(updateType, {NextSiblingID: node.data.ID, 'deleteInfo.deleted': true}, {NextSiblingID: node.data.NextSiblingID}));
+        }*/
+        //恢复
+        rst.push(getUpdateObj(updateType, {ID: node.data.ID, name: node.data.name + decDate}, {deleteInfo: null}));//NextSibling为undefined,后端处理
+    }
+    return rst;
+}
+//unitPriceFile or feeRateFile
+function getUpdateFiles(tenders, project){
+    let unitFiles = [], feeFiles = [], rst = [];
+    for(let i = 0, len = tenders.length; i < len; i++){
+        //恢复单价文件
+        if(project && project.data.unitPriceFiles.length > 0 && fIsExist(project.data.unitPriceFiles, tenders[i].data.property.unitPriceFile.id, fileType.unitPriceFile)){
+            unitFiles.push(tenders[i].data.property.unitPriceFile.id);
+        }
+        //恢复费率文件
+        if(project && project.data.feeRateFiles.length > 0 && fIsExist(project.data.feeRateFiles, tenders[i].data.property.feeFile.id, fileType.feeRateFile)){
+            feeFiles.push(tenders[i].data.property.feeFile.id);
+        }
+    }
+    let ufIds = Array.from(new Set(unitFiles));
+    let ffIds = Array.from(new Set(feeFiles));
+    for(let i = 0, len = ufIds.length; i < len; i++){
+        rst.push(getUpdateObj(fileType.unitPriceFile, {id: ufIds[i]}, {deleteInfo: null}));
+    }
+    for(let i = 0, len = ffIds.length; i < len; i++){
+        rst.push(getUpdateObj(fileType.feeRateFile, {id: ffIds[i]}, {deleteInfo: null}));
+    }
+    return rst;
+}

+ 5 - 0
web/building_saas/pm/js/pm_main.js

@@ -149,6 +149,11 @@ let ProjTreeSetting = {
 
 $(document).ready(function() {
     init();
+    Tree = null;
+    $('#tab_pm_all').on('show.bs.tab', function () {
+        gcTree = null;
+        init();
+    });
 
     // 侧滑数据
     $(".poj-list").on('click', ".open-sidebar", function() {

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

@@ -0,0 +1,160 @@
+
+<div class="container-fluid">
+    <div class="row">
+        <div class="col-lg-2 p-0">
+            <div class="print-list">
+                <div class="list-tools d-flex justify-content-center">
+                    <button class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#editForm"><i class="fa fa-cog"></i> 管理报表</button>
+                </div>
+                <div class="form-list">
+                    <ul id="rptTplTree" class="ztree"></ul>
+                </div>
+            </div>
+        </div>
+        <div class="col-lg-10 p-0">
+            <div class="toolsbar">
+                <div class="print-toolsbar">
+                    <div class="panel">
+                        <div class="panel-body">
+                            <button class="btn btn-secondary btn-sm" type="button">
+                                <i class="fa fa-print"></i><br>
+                                打印 <span id="checkCount" class="badge badge-primary">5</span>
+                            </button>
+                        </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="btnGroupDrop1" type="button" class="btn btn-secondary 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" href="#">横向</a>
+                                    </div>
+                                </div>
+                                <div class="btn-group" role="group">
+                                    <button id="btnGroupDrop2" type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                        A4
+                                    </button>
+                                    <div class="dropdown-menu" aria-labelledby="btnGroupDrop2">
+                                        <a class="dropdown-item" href="#">A3</a>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="panel-foot text-muted">
+                            预览设置
+                        </div>
+                    </div>
+                    <div class="panel">
+                        <div class="panel-body">
+                            <div class="btn-group" role="group">
+                                <button type="button" class="btn btn-secondary btn-sm">-</button>
+                                <a class="btn btn-secondary btn-sm" data-toggle="tooltip" data-placement="bottom" title="重置默认大小">1000%</a>
+                                <button type="button" class="btn btn-secondary btn-sm">+</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">
+                                <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>
+                            </div>
+                        </div>
+                        <div class="panel-foot text-muted">
+                            报表设置
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="print-view poj-list">
+                <div class="pageContainer">
+                    <canvas id="rptCanvas" height="820" width="920"></canvas>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<!--报表的弹窗-->
+<!--1弹出纸张-->
+<div class="modal fade" id="paper" 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>
+            <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>
+<!--2弹出页面-->
+<div class="modal fade" id="format" 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>
+            <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>
+<!--3弹出格式-->
+<div class="modal fade" id="content" 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>
+            <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>
+<script>
+    const SCREEN_DPI = [];
+    function getScreenDPI() {
+        if (SCREEN_DPI.length === 0) {
+            if (window.screen.deviceXDPI != undefined) {
+                SCREEN_DPI.push(window.screen.deviceXDPI);
+                SCREEN_DPI.push(window.screen.deviceYDPI);
+            } else {
+                let tmpNode = document.createElement("DIV");
+                tmpNode.style.cssText = "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
+                document.body.appendChild(tmpNode);
+                SCREEN_DPI.push(parseInt(tmpNode.offsetWidth));
+                SCREEN_DPI.push(parseInt(tmpNode.offsetHeight));
+                tmpNode.parentNode.removeChild(tmpNode);
+            }
+        }
+        return SCREEN_DPI;
+    }
+</script>

+ 209 - 0
web/building_saas/report/js/jpc_output.js

@@ -0,0 +1,209 @@
+/**
+ * Created by Tony on 2017/11/2.
+ */
+let JpcCanvasOutput = {
+    offsetX: 10,
+    offsetY: 10,
+    cleanCanvas: function (canvas) {
+        let ctx = canvas.getContext("2d");
+        ctx.save();
+        ctx.fillStyle="white";
+        ctx.clearRect(0,0, canvas.width, canvas.height);
+        ctx.restore();
+    },
+    drawToCanvas : function(pageObj, canvas, pageIdx) {
+        let me = this;
+        let ctx = canvas.getContext("2d");
+
+        function private_setupAreaH(area, type, fontAngle, dftFontHeight, outputPoint) {
+            let lType = type;
+            if (type != "left" && type != "right" && type != "center") lType = "left";
+            switch (lType) {
+                case "left":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    ctx.textAlign="start";
+                    break;
+                case "right":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    ctx.textAlign="end";
+                    break;
+                case "center":
+                    if (fontAngle == JV.VERTICAL_ANGLE || fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
+                    } else outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2;
+                    ctx.textAlign="center";
+                    break;
+            }
+        }
+        function private_setupAreaV(area, type, fontAngle, dftFontHeight, outputPoint) {
+            let lType = type;
+            if (type != "top" && type != "bottom" && type != "center") lType = "top";
+            switch (lType) {
+                case "top":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    break;
+                case "center":
+                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
+                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
+                    } else outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
+                    break;
+            }
+        }
+        function private_drawText(val, area, font, control) {
+            let dftFontHeight = 12;
+            let output = [];
+            if (font) {
+                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                let dftOthers = "";
+                let dftFontBold = font[JV.FONT_PROPS[3]];
+                if (dftFontBold && dftFontBold == 'T') {
+                    dftOthers = "bold " + dftOthers ;
+                }
+                let dftFontItalic = font[JV.FONT_PROPS[4]];
+                if (dftFontItalic && dftFontItalic == 'T') {
+                    dftOthers = dftOthers + "italic ";
+                }
+                ctx.font = dftOthers + dftFontHeight + "px " + font[JV.PROP_NAME];
+            }
+            if (control) {
+                private_setupAreaH(area, control.Horizon, font.FontAngle, dftFontHeight, output);
+                private_setupAreaV(area, control.Vertical, font.FontAngle, dftFontHeight, output);
+            } else {
+                private_setupAreaH(area, "left", font.FontAngle, dftFontHeight, output);
+                private_setupAreaV(area, "bottom", font.FontAngle, dftFontHeight, output);
+            }
+            let w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+            if (font.FontAngle != "0") {
+                w = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+            }
+            ctx.save();
+            ctx.translate(output[0], output[1]);
+            if (font.FontAngle === JV.VERTICAL_ANGLE) {
+                ctx.rotate(Math.PI/2);
+            } else if (font.FontAngle === JV.ANTI_VERTICAL_ANGLE) {
+                ctx.rotate(-Math.PI/2);
+            }
+            if (w >= ctx.measureText(val).width) {
+                ctx.fillText(val, 0, 0);
+            } else {
+                while (true) {
+                    dftFontHeight--;
+                    ctx.font = "" + dftFontHeight + "px " + font[JV.PROP_NAME];
+                    if (w >=  ctx.measureText(val).width || dftFontHeight < 6) {
+                        ctx.fillText(val, 0, 0);
+                        break;
+                    }
+                }
+            }
+            ctx.restore();
+        }
+        function private_drawCellText(cell, fonts, controls) {
+            if (cell[JV.PROP_VALUE]) {
+                let values = ("" + cell[JV.PROP_VALUE]).split('|');
+                let font = fonts[cell[JV.PROP_FONT]];
+                let control = controls[cell[JV.PROP_CONTROL]];
+                let height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+                let area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + me.offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + me.offsetY];
+                for (let i = 0; i < values.length; i++) {
+                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + me.offsetY;
+                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + me.offsetY;
+                    private_drawText(values[i], area, font, control);
+                }
+            }
+        }
+        function private_drawLine(cell, ctx, style, styleBorderDest, startP, destP, mergedBand, styles, isNeedMergeBand) {
+            ctx.beginPath();
+            let destStyle = style;
+            if (mergedBand) {
+                if (isNeedMergeBand && mergedBand[styleBorderDest] == cell[JV.PROP_AREA][styleBorderDest]) {
+                    destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
+                }
+            }
+            ctx.moveTo(cell[JV.PROP_AREA][startP[0]] + me.offsetX, cell[JV.PROP_AREA][startP[1]] + me.offsetY);
+            if (destStyle[styleBorderDest] && destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT] != 0) {
+                ctx.lineWidth = 1.0 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT];
+                ctx.strokeStyle = destStyle[styleBorderDest][JV.PROP_COLOR];
+                ctx.lineTo(cell[JV.PROP_AREA][destP[0]] + me.offsetX, cell[JV.PROP_AREA][destP[1]] + me.offsetY);
+            }
+            ctx.stroke();
+        }
+        function private_chkIfInMergedBand(mergedBand, cell) {
+            let rst = false;
+            if (mergedBand && cell) {
+                rst = mergedBand[JV.PROP_TOP] <= cell[JV.PROP_AREA][JV.PROP_TOP] && mergedBand[JV.PROP_BOTTOM] >= cell[JV.PROP_AREA][JV.PROP_BOTTOM] &&
+                    mergedBand[JV.PROP_LEFT] <= cell[JV.PROP_AREA][JV.PROP_LEFT] && mergedBand[JV.PROP_RIGHT] >= cell[JV.PROP_AREA][JV.PROP_RIGHT];
+            }
+            return rst;
+        }
+        function private_drawCell(cell, fonts, styles, controls, mergedBand) {
+            ctx.save();
+            ctx.translate(0.5,0.5);
+            let style = styles[cell[JV.PROP_STYLE]];
+            if (style) {
+                let isNeedMergeBand = private_chkIfInMergedBand(mergedBand, cell);
+                private_drawLine(cell, ctx, style, JV.PROP_TOP, [JV.PROP_LEFT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, ctx, style, JV.PROP_RIGHT, [JV.PROP_RIGHT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, ctx, style, JV.PROP_BOTTOM, [JV.PROP_RIGHT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, ctx, style, JV.PROP_LEFT, [JV.PROP_LEFT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+            }
+            private_drawCellText(cell, fonts, controls);
+            ctx.restore();
+        }
+
+        if (pageObj && pageObj.items.length > 0 && canvas && pageObj.items.length >= pageIdx) {
+            let page = pageObj.items[pageIdx - 1],
+                fonts = pageObj[JV.NODE_FONT_COLLECTION],
+                styles = pageObj[JV.NODE_STYLE_COLLECTION],
+                controls = pageObj[JV.NODE_CONTROL_COLLECTION],
+                mergedBand = pageObj[JV.BAND_PROP_MERGE_BAND];
+            for (let j = 0; j < page.cells.length; j++) {
+                let cell = page.cells[j];
+                private_drawCell(cell, fonts, styles, controls, mergedBand);
+            }
+        }
+    },
+    drawPageBorder: function(rptTpl, canvas, resolution) {
+        let me = this;
+        let size = rptTpl[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE].slice(0);
+        size[0] = Math.round(resolution[0] * size[0]);
+        size[1] = Math.round(resolution[0] * size[1]);
+
+        let ctx = canvas.getContext("2d");
+        ctx.save();
+        ctx.beginPath();
+        ctx.translate(0.5,0.5);
+        ctx.lineWidth = 1;
+        ctx.moveTo(me.offsetX, me.offsetY);
+        ctx.lineTo(size[0] + me.offsetX, me.offsetY);
+        ctx.lineTo(size[0] + me.offsetX, size[1] + me.offsetY);
+        ctx.lineTo(me.offsetX, size[1] + me.offsetY);
+        ctx.lineTo(me.offsetX, me.offsetY);
+        ctx.stroke();
+        ctx.restore();
+
+        ctx.fillStyle="black";
+        ctx.fillRect(size[0] + me.offsetX,10 + me.offsetY,10,size[1]);
+        ctx.fillRect(10 + me.offsetX,size[1] + me.offsetY,size[0],10);
+    }
+};

+ 49 - 0
web/building_saas/report/js/jpc_output_value_define.js

@@ -0,0 +1,49 @@
+/**
+ * Created by Tony on 2017/1/4.
+ */
+
+let JV = {
+    NODE_MAIN_INFO: "主信息",
+    NODE_PAGE_INFO: "打印页面_信息",
+    NODE_PAGE_SIZE: "纸张宽高",
+    NODE_MARGINS: "页边距",
+
+    NODE_FONT_COLLECTION: "font_collection",
+    NODE_STYLE_COLLECTION: "style_collection",
+    NODE_CONTROL_COLLECTION: "control_collection",
+
+    BAND_PROP_MERGE_BAND: "MergeBand",
+
+    PROP_NAME: "Name",
+    PROP_VALUE: "Value",
+    PROP_FONT: "font",
+    PROP_CONTROL: "control",
+    PROP_STYLE: "style",
+    PROP_AREA: "area",
+    PROP_ID: "ID",
+    PROP_LEFT: "Left",
+    PROP_RIGHT: "Right",
+    PROP_TOP: "Top",
+    PROP_BOTTOM: "Bottom",
+
+    IDX_LEFT: 0,
+    IDX_TOP: 1,
+    IDX_RIGHT: 2,
+    IDX_BOTTOM: 3,
+
+    CONTROL_PROPS: ["Shrink", "ShowZero", "Horizon", "Vertical", "Wrap"],
+    BORDER_STYLE_PROPS: ["LineWeight", "DashStyle", "Color"],
+    PROP_LINE_WEIGHT: "LineWeight",
+    PROP_DASH_STYLE: "DashStyle",
+    PROP_COLOR: "Color",
+    FONT_PROPS: ["Name", "FontHeight", "FontColor", "FontBold", "FontItalic", "FontUnderline", "FontStrikeOut", "FontAngle"],
+
+    OUTPUT_OFFSET: [2,1,2,3],
+    OFFSET_IDX_LEFT: 0,
+    OFFSET_IDX_RIGHT: 1,
+    OFFSET_IDX_TOP: 2,
+    OFFSET_IDX_BOTTOM: 3,
+
+    VERTICAL_ANGLE: "90",
+    ANTI_VERTICAL_ANGLE: "-90"
+};

+ 5 - 4
web/building_saas/main/js/rpt/rpt_cfg_const.js

@@ -2,7 +2,9 @@
  * Created by Tony on 2017/6/26.
  */
 
-let setting = {
+const   TPL_TYPE_NODE = 1,
+        TPL_TYPE_TEMPLATE = 2;
+let rpt_tpl_setting = {
     view: {
         selectedMulti: false
     },
@@ -19,12 +21,11 @@ let setting = {
         },
         simpleData: {
             enable: true,
-            idKey: "ID",
-            pIdKey: "ParentID",
             rootPId: -1
         }
     },
     callback: {
-        onCheck: zTreeOprObj.onCheck
+        //onCheck: zTreeOprObj.onCheck
+        onClick: zTreeOprObj.onClick
     }
 };

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

@@ -0,0 +1,128 @@
+/**
+ * Created by Tony on 2017/6/26.
+ */
+'use strict'
+
+let rptTplObj = {
+    hasInitialized: false,
+    iniPage: function() {
+        let me = this;
+        if (!me.hasInitialized) {
+            zTreeOprObj.getReportTemplateTree(userID);
+            me.hasInitialized = true;
+            let canvas = document.getElementById("rptCanvas");
+            canvas.onclick = canvasOprObj.cavansOnClick;
+            canvas.onmousemove = canvasOprObj.canvasOnMouseMove;
+        }
+    }
+}
+
+let zTreeOprObj = {
+    treeObj: null,
+    currentNode: null,
+    currentRptPageRst: null,
+    currentPage: 1,
+    maxPages: 0,
+    getReportTemplateTree: function(userId) {
+        let me = zTreeOprObj, params = {};
+        params.userId = [];
+        params.userId.push(userId);
+        params.userId.push(-100);
+        // let allEngIds = [];
+        // for (let item of engineeringList) {
+        //     allEngIds.push(item.value);
+        // }
+        // params.engineerId = allEngIds;
+        params.engineerId = projectInfoObj.projectInfo.property.engineering;
+        CommonAjax.postEx("report_tpl_api/getRptTplTree", params, 20000, true, function(result){
+                zTreeHelper.createTreeDirectly(result, rpt_tpl_setting, "rptTplTree", me);
+                me.refreshNodes();
+            }, null, null
+        );
+    },
+    refreshNodes: function() {
+        let me = this;
+        let private_setupIsParent = function(node){
+            node.isParent = (node.nodeType === RT.NodeType.NODE || node.level === 0);
+            if (node.items && node.items.length) {
+                for (let i = 0; i < node.items.length; i++) {
+                    private_setupIsParent(node.items[i]);
+                }
+            }
+        };
+        let topNodes = me.treeObj.getNodes();
+        for (let i = 0; i < topNodes.length; i++) {
+            private_setupIsParent(topNodes[i]);
+        }
+        me.treeObj.refresh();
+    },
+    onCheck: function() {
+        //count();
+        //if (clearFlag) {
+        //    clearCheckedOldNodes();
+        //}
+    },
+    onClick: function(event,treeId,treeNode) {
+        let me = zTreeOprObj;
+        let canvas = document.getElementById("rptCanvas");
+        if (treeNode.nodeType === TPL_TYPE_TEMPLATE && treeNode.refId > 0) {
+            let params = {};
+            let pageSize = "A4";
+            params.user_id = userID;
+            params.pageSize = pageSize;
+            params.rpt_tpl_id = treeNode.refId;
+            params.prj_id = projectInfoObj.projectInfo.ID;
+            CommonAjax.postEx("report_api/getReport", params, 5000, true, function(result){
+                    let pageRst = result;
+                    if (pageRst) {
+                        me.currentRptPageRst = pageRst;
+                        me.maxPages = pageRst.items.length;
+                        me.currentPage = 1;
+                        if (pageSize === "A4") {
+                            canvas.width = 1200;
+                            canvas.height = 900;
+                        } else if (pageSize === "A3") {
+                            canvas.width = 1880;
+                            canvas.height = 1200;
+                        }
+                        me.showPage(0, canvas);
+                    }
+                }, null, null
+            );
+        }
+    },
+    showPage: function (pageStep, canvas) {
+        let me = zTreeOprObj;
+        if (me.currentPage + pageStep >= 1 && me.currentPage + pageStep <= me.maxPages) {
+            me.currentPage = me.currentPage + pageStep;
+            JpcCanvasOutput.cleanCanvas(canvas);
+            JpcCanvasOutput.drawPageBorder(me.currentRptPageRst, canvas, getScreenDPI());
+            JpcCanvasOutput.drawToCanvas(me.currentRptPageRst, canvas, me.currentPage);
+        }
+    }
+};
+
+let canvasOprObj = {
+    canvasOnMouseMove: function (event) {
+        let x = event.offsetX - JpcCanvasOutput.offsetX,
+            canvas = event.originalTarget
+        ;
+        if (x < 300) {
+            canvas.style.cursor = "e-resize";
+        } else if ((canvas.width - x) < 300) {
+            canvas.style.cursor = "w-resize";
+        } else {
+            canvas.style.cursor = "";
+        }
+    },
+    cavansOnClick: function(event){
+        let x = event.offsetX - JpcCanvasOutput.offsetX,
+            //y = event.offsetY - JpcCanvasOutput.offsetY,
+            canvas = event.originalTarget;
+        if (x < 300) {
+            zTreeOprObj.showPage(-1, canvas);
+        } else if ((canvas.width - x) < 300) {
+            zTreeOprObj.showPage(1, canvas);
+        }
+    }
+};