浏览代码

Merge branch '1.0.0_online' of http://192.168.1.41:3000/SmartCost/ConstructionCost into 1.0.0_online

zhangweicheng 6 年之前
父节点
当前提交
9293d9bf8a
共有 39 个文件被更改,包括 1628 次插入358 次删除
  1. 3 1
      config/gulpConfig.js
  2. 8 0
      lib/jspdf/SmartSimsun-bold.js
  3. 8 0
      lib/jspdf/SmartSimsun-normal.js
  4. 286 0
      lib/jspdf/jspdf.min.js
  5. 88 0
      modules/complementary_glj_lib/models/gljModel.js
  6. 14 1
      modules/complementary_ration_lib/controllers/compleViewController.js
  7. 27 17
      modules/complementary_ration_lib/models/compleRationModel.js
  8. 6 0
      modules/complementary_ration_lib/models/sectionTreeModel.js
  9. 1 0
      modules/complementary_ration_lib/routes/routes.js
  10. 31 2
      modules/pm/facade/pm_facade.js
  11. 25 0
      modules/ration_glj/controllers/ration_glj_controller.js
  12. 13 0
      modules/ration_glj/facade/ration_glj_facade.js
  13. 1 0
      modules/ration_glj/routes/ration_glj_route.js
  14. 29 4
      modules/reports/rpt_component/jpc_flow_tab.js
  15. 20 3
      public/counter/counter.js
  16. 2 0
      public/web/rpt_value_define.js
  17. 51 0
      public/web/sheet/sheet_common.js
  18. 33 0
      test/unit/reports/rpt_cfg.js
  19. 15 6
      test/unit/reports/test_rpt_test_template.js
  20. 3 61
      web/building_saas/complementary_ration_lib/html/dinge.html
  21. 19 37
      web/building_saas/complementary_ration_lib/js/gljSelect.js
  22. 79 0
      web/building_saas/complementary_ration_lib/js/init.js
  23. 0 22
      web/building_saas/complementary_ration_lib/js/ration.js
  24. 9 16
      web/building_saas/complementary_ration_lib/js/ration_glj.js
  25. 11 17
      web/building_saas/complementary_ration_lib/js/ration_installation.js
  26. 18 50
      web/building_saas/complementary_ration_lib/js/section_tree.js
  27. 2 0
      web/building_saas/main/html/main.html
  28. 19 10
      web/building_saas/main/js/models/exportStandardInterface.js
  29. 1 1
      web/building_saas/main/js/models/exportStdInterfaceBase.js
  30. 8 3
      web/building_saas/main/js/models/importStandardInterface.js
  31. 9 0
      web/building_saas/main/js/models/main_consts.js
  32. 64 10
      web/building_saas/main/js/models/ration_glj.js
  33. 170 77
      web/building_saas/main/js/views/glj_view.js
  34. 15 16
      web/building_saas/main/js/views/glj_view_contextMenu.js
  35. 12 3
      web/building_saas/main/js/views/main_tree_col.js
  36. 6 0
      web/building_saas/report/html/rpt_main.html
  37. 4 0
      web/building_saas/report/js/jpc_output_value_define.js
  38. 441 0
      web/building_saas/report/js/rpt_jspdf.js
  39. 77 1
      web/building_saas/report/js/rpt_main.js

+ 3 - 1
config/gulpConfig.js

@@ -157,6 +157,7 @@ module.exports = {
         'public/web/treeDataHelper.js',
         'public/web/string_util_light.js',
         'public/web/ztree_common.js',
+        'web/building_saas/report/js/rpt_jspdf.js',
         'web/building_saas/report/js/rpt_main.js',
         'web/building_saas/report/js/rpt_cfg_const.js',
         'web/building_saas/report/js/jpc_output_value_define.js',
@@ -236,7 +237,8 @@ module.exports = {
         'web/building_saas/complementary_ration_lib/js/ration_assist.js',
         'web/building_saas/complementary_ration_lib/js/ration_installation.js.js',
         'public/web/slideResize.js',
-        'web/building_saas/complementary_ration_lib/js/coe.js'
+        'web/building_saas/complementary_ration_lib/js/coe.js',
+        'web/building_saas/complementary_ration_lib/js/init.js'
     ],
     compleRation_glj_css: [
     ],

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


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


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


+ 88 - 0
modules/complementary_glj_lib/models/gljModel.js

@@ -6,9 +6,14 @@ const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
 const compleClassModel = mongoose.model('complementary_glj_section');
+const _ = require('lodash');
 import counter from "../../../public/counter/counter";
 import async from "async";
 import STDGLJLibGLJListModel from "../../common/std/std_glj_lib_glj_list_model";
+const libType = {
+    stdGLJ: 1,
+    complementaryGLJs: 2
+};
 
 class GljDao {
     getGljTypes (gljLibId, callback){
@@ -40,6 +45,89 @@ class GljDao {
             }
         }
     }
+
+    async getQueryByType ({userID, compilationId, gljLibId, code, type, replace, location, classList, search}) {
+        let model = null,
+            query = {},
+            countQuery = {},
+            matchLocation = false;
+        if (type === libType.stdGLJ) {
+            model = stdGljModel;
+            query.repositoryId = gljLibId;
+        } else {
+            model = complementaryGljModel;
+            query.userId = userID;
+            query.compilationId = compilationId;
+        }
+        // 分类树
+        if (classList.length) {
+            query.gljClass = {$in: classList};
+        }
+        // 定位
+        if (location) {
+            // 替换定位,则先看看能不能找到替换的人材机,能找到的话就能定位要被替换人材机所在分类树
+            const replaceQuery = {...query, ...replace};
+            const replaceData = await model.findOne(replaceQuery);
+            if (replaceData) {
+                query.gljClass = replaceData.gljClass;
+                matchLocation = true;
+            }
+        }
+        // 替换过滤类型
+        if (replace) {
+            // 人材机类型是“混凝土、砂浆、配合比、商品混凝土、商品砂浆”时,筛选的可替换的人材机类型应是“混凝土、或砂浆、或配合比、或商品混凝土、或商品砂浆”。
+            const materialTypes = [202, 203, 204, 205, 206];
+            query.gljType = materialTypes.includes(replace.gljType) ? {$in: materialTypes} : replace.gljType;
+        }
+        // 搜索关键字
+        if (search) {
+            query.$or = [{code: {'$regex': search, $options: '$i'}}, {name: {'$regex': search, $options: '$i'}}];
+        }
+        countQuery = {...query};
+        // 上一次分页的最末人材机编码
+        if (code) {
+            query.code = {$gt: code};
+        }
+        return {
+            model,
+            query,
+            countQuery,
+            matchLocation
+        };
+    }
+
+    async getGLJPaging (condition) {
+        const queryData = await this.getQueryByType(condition);
+        // 定位(替换初始化)
+        // 替换触发的人材机选择界面,只有在初始化时才定位,其他操作下是正常的分页
+        if (queryData.matchLocation) {
+            // 返回的数据,为编码小于等于替换的编码,再加附加条数
+            const limitQuery = _.cloneDeep(queryData.query);
+            limitQuery.code = {$lte: condition.replace.code};
+            const lteLimit = await queryData.model.count(limitQuery);
+            const additionalLimit = 10;
+            const limit = lteLimit + additionalLimit;
+            // 显示的数据不能太少,否则数据没有占满整个表格区域(实际上数据条目应该超过表格显示区域),让人误以为数据只有那么点,不再滚动触发分页
+            condition.limit = limit > condition.limit ? limit : condition.limit;
+        }
+        //const gljs = await queryData.model.find(queryData.query).lean().sort({code: 1}).skip(condition.index).limit(condition.limit);
+        // 分页使用skip的话,跳过的条数多的话性能会下降,因此不使用
+        const gljs = await queryData.model.find(queryData.query).lean().sort({code: 1}).limit(condition.limit);
+        const total = await queryData.model.find(queryData.countQuery).count();
+        return condition.type === libType.stdGLJ
+            ? {stdGLJ: gljs, complementaryGLJs: [], total: total}
+            : {stdGLJ: [], complementaryGLJs: gljs, total: total}
+    }
+
+    async getGLJDataSync (gljLibId, userId, compilationId) {
+        const stdGljs = await stdGljModel.find({repositoryId: gljLibId}).lean();
+        const complementaryGljs = await complementaryGljModel.find({userId, compilationId}).lean();
+        return {
+            stdGljs,
+            complementaryGljs
+        }
+    }
+
     //获得用户的补充工料机和用户当前所在编办的标准工料机
     async getGljItems (stdGljLibId, userId, compilationId, projection, callback){
         let me = this;

+ 14 - 1
modules/complementary_ration_lib/controllers/compleViewController.js

@@ -6,8 +6,9 @@ import BaseController from '../../common/base/base_controller';
 import CompleViewModel from '../models/compleViewModel';
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
 let config = require("../../../config/config.js");
-
 let compleViewModel = new CompleViewModel();
+import CompleRationDao from '../models/compleRationModel';
+const compleRationDao = new CompleRationDao();
 let callback = function (req, res, err, msg, data) {
     res.json({error: err, message: msg, data: data});
 };
@@ -53,6 +54,18 @@ class CompleViewController extends BaseController{
         });
     }
 
+    async prepareInitData (req, res) {
+        try {
+            const gljLibId = await getGljLibId(req.session.sessionCompilation);
+            const userId = req.session.sessionUser.id;
+            const compilationId = req.session.sessionCompilation._id;
+            const initData = await compleRationDao.prepareInitData(userId, compilationId, gljLibId);
+            res.json({error: 0, message: 'success', data: initData});
+        } catch (err) {
+            res.json({error: 1, message: 'fail', data: null});
+        }
+    }
+
     async redirectGljList(req, res){
         const gljLibId = await getGljLibId(req.session.sessionCompilation);
         const redirectRation = `/complementaryRation/ration`;

+ 27 - 17
modules/complementary_ration_lib/models/compleRationModel.js

@@ -8,8 +8,14 @@ const installSectionModel = mongoose.model("std_ration_lib_installationSection")
 const installFeeItemModel = mongoose.model("std_ration_lib_installation");
 const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
+const stdgljutil = require('../../../public/cache/std_glj_type_util');
+const installFacade = require('../facades/compleInstallFacade');
 import async from 'async';
 let stdRationModel = require ('../../ration_repository/models/ration_item').Model;
+import SectionTreeDao from '../models/sectionTreeModel';
+const sectionTreeDao = new SectionTreeDao();
+import GljDao from "../../complementary_glj_lib/models/gljModel";
+const gljDao = new GljDao();
 let counter = require('../../../public/counter/counter');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let gljUtil = require('../../../public/gljUtil');
@@ -528,23 +534,27 @@ class CompleRatoinDao {
         });
     }
 
-    async getInstallation(rationRepId, callback){
-        try {
-            let feeItems = await installFeeItemModel.find({rationRepId: rationRepId, $or: [{deleted: false}, {deleted: null}]});
-            for(let feeItem of feeItems){
-                let sids = [];
-                for(let sec of feeItem.section){
-                    sids.push(sec.ID);
-                }
-                if(sids.length > 0){
-                    let sections = await installSectionModel.find({ID: {$in: sids}, $or: [{deleted: false}, {deleted: null}]});
-                    feeItem._doc.section = sections;
-                }
-            }
-            callback(0, feeItems);
-        }
-        catch(err){
-            callback(err, null);
+    async getCodes (userId, compilationId) {
+        const compleRations = await compleRationModel.find({userId, compilationId}, '-_id code').lean();
+        const codes = [];
+        compleRations.forEach(item => codes.push(item.code));
+        return codes;
+    }
+
+    async prepareInitData (userId, compilationId, gljLibId) {
+        const rationsCodes = await this.getCodes(userId, compilationId);
+        const gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray();
+        const installationData = await installFacade.getInstallation(userId, compilationId);
+        const rationTreeData = await sectionTreeDao.getComplementaryTree(userId, compilationId);
+        const mixedTreeData = await gljDao.getMixedTree(gljLibId, userId, compilationId);
+        const mixedGLJData = await gljDao.getGLJDataSync(gljLibId, userId, compilationId);
+        return {
+            rationsCodes,
+            gljDistTypeCache,
+            installationData,
+            rationTreeData,
+            mixedTreeData,
+            mixedGLJData
         }
     }
 }

+ 6 - 0
modules/complementary_ration_lib/models/sectionTreeModel.js

@@ -48,6 +48,12 @@ class SectionTreeDao {
         });
 
     }
+
+    async getComplementaryTree (userId, compilationId) {
+        const treeData = await compleRationSectionTreeModel.find({userId, compilationId}).lean();
+        return treeData;
+    }
+
     async getRationTree(userId, compilationId, rationRepId, type, callback) {
         //区分要获取的是标准的数据还是补充的数据
         const rationLibType = {

+ 1 - 0
modules/complementary_ration_lib/routes/routes.js

@@ -21,6 +21,7 @@ module.exports = function (app) {
     app.get('/complementaryRation/glj', compleViewController.init, compleViewController.redirectGljList);
     app.get('/complementaryRation/coe', compleViewController.init, compleViewController.redirectCoeList);
     app.get('/complementaryRation/installation', compleViewController.init, compleViewController.redirectInstallation);
+    router.get('/initData', compleViewController.init, compleViewController.prepareInitData);
 
     router.post('/getRationLib', compleViewController.init, compleViewController.getRationLib);
     router.post('/getRationLibs', compleViewController.init, compleViewController.getRationLibs);

+ 31 - 2
modules/pm/facade/pm_facade.js

@@ -730,6 +730,33 @@ async function getIndexReportData(prj_id, filters) {
     return await project_facade.getIndexReportData(prj_id, filters);
 }
 
+// 根据树结构数据排序
+function getSortedDataByTree(data) {
+    // NextSiblingID-数据映射
+    const mapping = {};
+    data.forEach(item => {
+        // 错误数据兼容处理
+        // 由于之前的导入建设项目,会导致最后的一个项目的NextSiblingID为空,为非正确的-1
+        // 因此把项目中NextSibling为空的数据设置为NextSiblingID为-1
+        if (!item.NextSiblingID) {
+            item.NextSiblingID = -1;
+        }
+        mapping[item.NextSiblingID] = item;
+    });
+    let lastItem = data.find(item => +item.NextSiblingID === -1);
+    if (!lastItem) {
+        return data;
+    }
+    const rst = [lastItem];
+    let preItem = mapping[lastItem.ID];
+    while (preItem) {
+        rst.unshift(preItem);
+        preItem = mapping[preItem.ID];
+    }
+    // 根据树结构排序形成的新数组与旧数组项数不同,说明树结构数据有问题(断链),则返回原本数据。
+    return rst.length === data.length ? rst : data;
+}
+
 //根据单位工程ID获取汇总信息
 //@param {Number}tenderID {String}summaryType @return {Object}
 async function getSummaryInfoByTender(tenderID, summaryType) {
@@ -753,7 +780,8 @@ async function getSummaryInfoByTender(tenderID, summaryType) {
     let summaryInfo = await getSummaryInfo([project.ID]);
     if(summaryType === projectType.engineering){ // 汇总到单项工程级别
         parent = engineering;
-        let tenders = await projectModel.find({ParentID: engineering.ID, $or: notDeleted});
+        let tenders = await projectModel.find({ParentID: engineering.ID, $or: notDeleted}).lean();
+        tenders = getSortedDataByTree(tenders);
         for(let t of tenders){
             if(summaryInfo[t.ID]){
                 summaryInfo[t.ID]['name'] = t.name ? t.name : '';
@@ -762,7 +790,8 @@ async function getSummaryInfoByTender(tenderID, summaryType) {
         }
     } else { // 汇总到建设项目级别
         parent = project;
-        let engs = await projectModel.find({ParentID: project.ID, $or: notDeleted});
+        let engs = await projectModel.find({ParentID: project.ID, $or: notDeleted}).lean();
+        engs = getSortedDataByTree(engs);
         for(let e of engs){
             if(summaryInfo[e.ID]){
                 summaryInfo[e.ID]['name'] = e.name ? e.name : '';

+ 25 - 0
modules/ration_glj/controllers/ration_glj_controller.js

@@ -10,6 +10,7 @@ module.exports={
     createRationGLJ:createRationGLJ,
     testGetQuantify:testGetQuantify,
     getGLJData:getGLJData,
+    getGLJDataPaging: getGLJDataPaging,
     getGLJDataByCodes:getGLJDataByCodes,
     addGLJ:addGLJ,
     replaceGLJ:replaceGLJ,
@@ -56,6 +57,30 @@ async function getGLJDataByCodes(req,res){
     res.json(result);
 }
 
+async function getGLJDataPaging(req, res) {
+    let result={
+        error:0
+    };
+    let data = JSON.parse(req.body.data);
+    try {
+        let gljLibId = await ration_glj_facade.getGLJLibByEngineerID(data.engineerID);
+        let info = {
+            gljLibId,
+            userID: req.session.sessionUser.id,
+            compilationId: req.session.sessionCompilation._id
+        };
+        result.data = await ration_glj_facade.getGLJDataPaging(info, data.condition);
+        if (req.session.sessionCompilation.priceProperties) {
+            result.data.priceProperties = req.session.sessionCompilation.priceProperties
+        }
+        res.json(result);
+    } catch (err) {
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+        res.json(result);
+    }
+}
 
 async function getGLJData(req, res) {
     let result={

+ 13 - 0
modules/ration_glj/facade/ration_glj_facade.js

@@ -8,6 +8,7 @@ module.exports = {
     getQuantityByProjectGLJ: getQuantityByProjectGLJ,
     getLibInfo: getLibInfo,
     getGLJData: getGLJData,
+    getGLJDataPaging: getGLJDataPaging,
     getGLJDataByCodes:getGLJDataByCodes,
     addGLJ: addGLJ,
     deleteGLJ:deleteGLJ,
@@ -539,6 +540,18 @@ async function getGLJLibByEngineerID  (engineerID) {
     return gljLibId
 }
 
+async function getGLJDataPaging(info, condition) {
+    let gljDao = new GljDao();
+    let rst = {};
+    // 初始化,需要生成分类树和类型数据
+    if (condition.init) {
+        rst.treeData = await gljDao.getMixedTree(info.gljLibId, info.userID, info.compilationId);
+        rst.distTypeTree = stdgljutil.getStdGljTypeCacheObj().toArray();
+    }
+    let gljData = await gljDao.getGLJPaging({...info, ...condition});
+    Object.assign(rst, gljData);
+    return rst;
+}
 
 function getGLJData(info, callback) {
     let gljDao = new GljDao();

+ 1 - 0
modules/ration_glj/routes/ration_glj_route.js

@@ -9,6 +9,7 @@ module.exports = function (app) {
 
     var rgRouter = express.Router();
     rgRouter.get('/getGLJData/:engineerID', rgController.getGLJData);
+    rgRouter.post('/getGLJDataPaging', rgController.getGLJDataPaging);
     rgRouter.post('/getGLJDataByCodes',rgController.getGLJDataByCodes);
     rgRouter.post('/addGLJ',rgController.addGLJ);
     rgRouter.post('/replaceGLJ',rgController.replaceGLJ);

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

@@ -1115,6 +1115,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 me.pageSumValLst.push(rowGrandTotal);
                 //grouping content
+                let grpCntIdx = 0;
                 for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
                     if (contentValuesIdx[rowIdx][1] === JV.DISPLAY_VAL_TYPE_GROUP) {
                         for (let grpIdx = 0; grpIdx < rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length; grpIdx++) {
@@ -1130,10 +1131,11 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                         }
                                     }
                                 }
-                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx);
+                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx, grpCntIdx, $CURRENT_RPT);
                                 rst = rst.concat(lineRst);
                             }
                         }
+                        grpCntIdx++;
                     }
                 }
             }
@@ -1295,7 +1297,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             return rst;
         }
     };
-    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx) {
+    JpcFlowTabResult.outputTabGrpLine = function (band, grp_line, page, grpValueIdx, rows, rowIdx, cols, colIdx, unitFactor, isRow, controls, multiColIdx, grpCntIdx, $CURRENT_RPT) {
         let me = this, rst = [];
         if (grp_line[JV.PROP_GROUP_SUM_KEYS]) {
             let segIdx = JpcCommonHelper.getSegIdxByPageIdx(page, me.page_seg_map);
@@ -1309,7 +1311,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
         }
         if (grp_line[JV.PROP_TEXTS]) {
             for (let txt of grp_line[JV.PROP_TEXTS]) {
+                me.checkGrpTxtOutEvent(JV.RUN_TYPE_BEFORE_GROUP_TEXT_OUT, txt, grpCntIdx, $CURRENT_RPT);
                 rst.push(JpcTextHelper.outputText(txt, band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx));
+                // me.combinePageCells(rst, verticalCombinePos, horizonCombinePos);
+                // 可能会有一个After,但意义不大,用不着
             }
         }
         if (grp_line[JV.PROP_DISCRETE_FIELDS]) {
@@ -1321,6 +1326,24 @@ JpcFlowTabSrv.prototype.createNew = function(){
         // console.log(rst);
         return rst;
     };
+    JpcFlowTabResult.checkGrpTxtOutEvent = function ($RUN_TYPE, $TEXT, $TIMES, $CURRENT_RPT) {
+        if ($CURRENT_RPT.formulas) {
+            for (let execFmlIdx = 0; execFmlIdx < $CURRENT_RPT.formulas.length; execFmlIdx++) {
+                if ($CURRENT_RPT.formulas[execFmlIdx][JV.PROP_RUN_TYPE] === $RUN_TYPE) {
+                    let expression = $CURRENT_RPT.formulas[execFmlIdx][JV.PROP_EXPRESSION];
+                    if (expression) {
+                        let $ME = $CURRENT_RPT.formulas[execFmlIdx];
+                        try {
+                            eval(expression);
+                        } catch (ex) {
+                            console.log(ex);
+                        }
+                    }
+                }
+            }
+        }
+    };
+
     JpcFlowTabResult.commonTabRestOutput = function(dataObj, page, segIdx, bands, band, unitFactor, tab, multiColIdx){
         let me = this, rst = [];
         if (tab[JV.PROP_TEXT]) {
@@ -1365,16 +1388,18 @@ function setupControl(mergeCell, controls) {
         orgCtrl = controls[mergeCell[JV.PROP_CONTROL]];
         mergeCell[JV.PROP_CONTROL] = {
             "Shrink": "T",
+            "ShrinkFirst": orgCtrl.ShrinkFirst,
+            "CloseOutput": orgCtrl.CloseOutput,
             "ShowZero": orgCtrl.ShowZero,
             "Horizon": orgCtrl.Horizon,
             "Vertical": orgCtrl.Vertical,
-            "Wrap": "T",
+            "Wrap": (mergeCell[JV.PROP_IS_AUTO_HEIGHT])?'T':'F',
             "VerticalForExcel": "center"
         };
     } else {
         mergeCell[JV.PROP_CONTROL].Shrink = "T";
         mergeCell[JV.PROP_CONTROL].Vertical = "top";
-        mergeCell[JV.PROP_CONTROL].Wrap = "T";
+        mergeCell[JV.PROP_CONTROL].Wrap = (mergeCell[JV.PROP_IS_AUTO_HEIGHT])?'T':'F',
         mergeCell[JV.PROP_CONTROL].VerticalForExcel = "center";
         orgCtrl = mergeCell[JV.PROP_CONTROL];
     }

+ 20 - 3
public/counter/counter.js

@@ -36,14 +36,21 @@ var counterDAO = function(){};
  *     result.value.sequence_value Ϊ�޸ĺ��id
  * }
  */
-counterDAO.prototype.getIDAfterCount = function(moduleName, stepCount, callback) {
+counterDAO.prototype.getIDAfterCount =async function(moduleName, stepCount, callback) {
     var sc = stepCount;
     if (isNaN(stepCount) || (stepCount < 0)) {
         sc = 1;
     } else if (!(/^-?\d+$/.test(stepCount))) {
         sc = Math.round(stepCount + 0.5);
     }
-    counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true}, callback);//findOneAndUpdate
+    if (callback === null) {
+        let result = await counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true});
+        return await checkIDResult(result,moduleName,null)
+    } else {
+        counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true}, function (err,result) {
+            checkIDResult(result,moduleName,callback,err)
+        });
+    }
 }
 
 counterDAO.prototype.getIDAfterCountSync = async function (moduleName, stepCount) {
@@ -53,9 +60,19 @@ counterDAO.prototype.getIDAfterCountSync = async function (moduleName, stepCount
     } else if (!(/^-?\d+$/.test(stepCount))) {
         sc = Math.round(stepCount + 0.5);
     }
-    return await counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true});//findOneAndUpdate
+    let result = await counterModel.findOneAndUpdate({_id: moduleName}, { $inc: { sequence_value: sc } }, {'new':true});
+    return await checkIDResult(result,moduleName,null)
 };
 
+async function checkIDResult(result,moduleName,callback,err){
+    if(result){
+        return callback?callback(err,result):result;
+    }else {
+        return callback?counterModel.create({_id: moduleName,sequence_value:1},callback): await counterModel.create({_id: moduleName,sequence_value:1});
+    }
+
+}
+
 counterDAO.prototype.getCurrentID = function(moduleName, callback) {
     if (callback) {
         counterModel.findOne({_id: moduleName}).exec()

+ 2 - 0
public/web/rpt_value_define.js

@@ -210,6 +210,8 @@ const JV = {
     RUN_TYPE_BEFORE_COMBINE: "before_combine",
     RUN_TYPE_AFTER_COMBINE: "after_combine",
 
+    RUN_TYPE_BEFORE_GROUP_TEXT_OUT: "before_group_text_output",
+
     PAGE_STATUS: ["EveryPage","FirstPage", "LastPage", "SegmentStart", "SegmentEnd", "Group", "CrossRowEnd", "CrossColEnd"],
 
     CONTROL_PROPS: ["Shrink", "ShowZero", "Horizon", "Vertical", "Wrap", "VerticalForExcel", "ShrinkFirst", "CloseOutput"],

+ 51 - 0
public/web/sheet/sheet_common.js

@@ -175,6 +175,48 @@ var sheetCommonObj = {
             }
         }
     },
+    setSheetBySetting: function (sheet, setting) {
+        function setCellType(range, cellType) {
+            let type;
+            if (cellType === 'checkBox') {
+                type = new GC.Spread.Sheets.CellTypes.CheckBox();
+            }
+            range.cellType(type);
+        }
+        setting.header.forEach((item, index) => {
+            const range = sheet.getRange(-1, index, -1, 1);
+            this.setAreaAlign(range, item.hAlign, item.vAlign);
+            if (item.cellType) {
+                console.log(item);
+                setCellType(range, item.cellType);
+            }
+            if (item.formatter) {
+                range.formatter(item.formatter)
+            }
+        });
+    },
+    appendData: function (sheet, index, rowIndex, setting, data) {
+        /*const viewport = GC.Spread.Sheets.SheetArea.viewport;
+        const rowHeader = GC.Spread.Sheets.SheetArea.rowHeader;*/
+        if (!index) {
+            sheet.setRowCount(0);
+        }
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        // 追加空行
+        sheet.addRows(index, data.length);
+        // 显示数据
+        data.forEach((item, rIdx) => {
+            const row = index + rIdx;
+            setting.header.forEach((hItem, cIdx) => {
+                const dataCode = hItem.dataCode;
+                const val = gljUtil.isDef(item[dataCode]) ? item[dataCode] : '';
+                sheet.setValue(row, cIdx, val);
+            });
+        });
+        sheet.resumeEvent();
+        sheet.resumePaint();
+    },
     showData: function(sheet, setting, data,distTypeTree,callback) {
         var me = this, ch = GC.Spread.Sheets.SheetArea.viewport;
         sheet.suspendPaint();
@@ -395,6 +437,15 @@ var sheetCommonObj = {
         c.isThreeState(threeState);
         return c
     },
+    // 无法勾选的复选框
+    getReadOnlyCheckBox () {
+        function ReadOnlyCheckBox() {}
+        ReadOnlyCheckBox.prototype = new GC.Spread.Sheets.CellTypes.CheckBox();
+        ReadOnlyCheckBox.prototype.processMouseUp = function () {
+            return;
+        };
+        return new ReadOnlyCheckBox();
+    },
     setComboBox(row,col,sheet,options,editorValueType,editable,maxDropDownItems){
         //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
         let dynamicCombo = sheetCommonObj.getDynamicCombo(true);

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

@@ -414,6 +414,39 @@ module.exports = {
             "Wrap" : "false"
         },
         {
+            "ID" : "NewContent_Left",
+            "CfgDispName" : "正文内容(新)",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "left",
+            "Vertical" : "center",
+            "Wrap" : "F",
+            "ShrinkFirst" : "F",
+            "CloseOutput" : "T"
+        },
+        {
+            "ID" : "NewContent_Right",
+            "CfgDispName" : "正文内容(新)_右",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "right",
+            "Vertical" : "center",
+            "Wrap" : "F",
+            "ShrinkFirst" : "F",
+            "CloseOutput" : "T"
+        },
+        {
+            "ID" : "NewContent_Center",
+            "CfgDispName" : "正文内容(新)_中",
+            "Shrink" : "T",
+            "ShowZero" : "F",
+            "Horizon" : "center",
+            "Vertical" : "center",
+            "Wrap" : "F",
+            "ShrinkFirst" : "F",
+            "CloseOutput" : "T"
+        },
+        {
             "ID" : "Currency",
             "CfgDispName" : "金额型",
             "Shrink" : "T",

+ 15 - 6
test/unit/reports/test_rpt_test_template.js

@@ -35,7 +35,7 @@ let demoPrjId = - 1;
 // let demoRptId = 450; //09
 // let demoRptId = 704; //05
 // let demoRptId = 626; //06
-// let demoRptId = 451; //09-1
+// let demoRptId = 743; //09-1
 // let demoRptId = 452; //04
 // let demoRptId = 612; //09-3
 // let demoRptId = 530; //封2
@@ -51,9 +51,12 @@ let demoPrjId = - 1;
 // let demoRptId = 931; //qa 内蒙古2017 【扉-1】招标工程量清单扉页
 // let demoRptId = 957; //qa 内蒙古2017 12-4
 // let demoRptId = 1006; //qa 重庆2018 A03
-let demoRptId = 1007; //qa 重庆2018 A01
+// let demoRptId = 1007; //qa 重庆2018 A01
 // let demoRptId = 475; //计日工
 // let demoRptId = 551; //表05
+
+let demoRptId = 510;
+
 let pagesize = "A4";
 
 //288: 11-2表(新)
@@ -68,7 +71,7 @@ let userId_me = "5b6a60b1c4ba33000dd417c0"; //我的
 // demoPrjId = 2260; //QA:
 // demoPrjId = 5029; //
 // demoPrjId = 5029; //项目名称过长
-demoPrjId = 8522; //
+demoPrjId = 7542; //
 // demoPrjId = 4107; //UAT:
 //*/
 let userId_Dft = userId_Leng;
@@ -94,15 +97,21 @@ test('测试 - 测试模板啦: ', function (t) {
     rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
         let rptDataUtil = new rptDataExtractor();
         rptDataUtil.initialize(rptTpl._doc);
+
+        // fsUtil.writeObjToFile(rptTpl._doc, "D:/GitHome/建筑造价支持文件/报表模板/重庆市2018建筑工程_【表-09-4】施工技术措施项目清单计价表_招投标1.js");
+        // t.pass('pass : only save the template!');
+        // t.end();
+        // return;
+
         let filter = rptDataUtil.getDataRequestFilter();
         // console.log(filter);
         //正常应该根据报表模板定义的数据类型来请求数据
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_测试模板.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject_测试模板.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
-                    fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataAfterCacl_测试模板.jsp");
                     // fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptTplAssembledData_测试模板.jsp");
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();
@@ -115,7 +124,7 @@ test('测试 - 测试模板啦: ', function (t) {
                     let customizeCfg = {"fillZero": true};
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties, customizeCfg);
                     if (pageRst) {
-                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult_测试模板.jsp");
+                        fsUtil.writeObjToFile(pageRst, "D:/Temp/testBuiltPageResult_测试模板.jsp");
                         // rpt_xl_util.exportExcel(pageRst, pagesize, "local_test_rpt_excel", true, null, null, function(uuidName){
                         //     console.log("excel uuid: " + uuidName);
                         // });

+ 3 - 61
web/building_saas/complementary_ration_lib/html/dinge.html

@@ -52,7 +52,8 @@
         }
     </style>
     <script>
-        let gljLibId = '<%= gljLibId %>';
+        const gljLibId = '<%= gljLibId %>';
+        const userID = '<%=userID %>';
     </script>
 </head>
 <body>
@@ -630,67 +631,8 @@
 <script type="text/javascript" src="/web/building_saas/complementary_ration_lib/js/ration_installation.js"></script>
 <script src="/public/web/slideResize.js"></script>
 <script src="/web/building_saas/complementary_ration_lib/js/coe.js"></script>
+<script src="/web/building_saas/complementary_ration_lib/js/init.js"></script>
 <!--endinject-->
-<script type="text/javascript">
-    let userID = '<%=userID %>';
-    $(document).ready(function(){
-        rationOprObj.buildSheet($("#rationItemsSheet")[0]);
-
-        // tabPanel 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
-        var rdSpread = sheetCommonObj.createSpread($("#rdSpread")[0], 4);
-        rdSpread.options.allowUserDragFill = false;
-        rdSpread.options.allowUserDragDrop = false;
-        sheetCommonObj.spreadDefaultStyle(rdSpread);
-        rationGLJOprObj.buildSheet(rdSpread.getSheet(0));
-
-        rationAssistOprObj.buildSheet(rdSpread.getSheet(1));
-
-        rationCoeOprObj.buildSheet(rdSpread.getSheet(2));
-
-        rationInstObj.buildSheet(rdSpread.getSheet(3));
-        rationInstObj.getInstallation(parseInt(getQueryString("repository")), function () {
-            //rationInstObj.buildSheet(rdSpread.getSheet(3));
-        });
-        let rdSpreadEscSheets = [];
-        rdSpreadEscSheets.push({sheet: rdSpread.getSheet(0), editStarting: rationGLJOprObj.onEditStarting, editEnded: rationGLJOprObj.onCellEditEnd});
-        rdSpreadEscSheets.push({sheet: rdSpread.getSheet(1), editStarting: rationAssistOprObj.onEditStarting, editEnded: rationAssistOprObj.onEditEnded});
-        rdSpreadEscSheets.push({sheet: rdSpread.getSheet(2), editStarting: rationCoeOprObj.onEditStarting, editEnded: rationCoeOprObj.onEditEnded});
-        rdSpreadEscSheets.push({sheet: rdSpread.getSheet(3), editStarting: rationInstObj.onEditStarting, editEnded: rationInstObj.onEditEnded});
-        sheetCommonObj.bindEscKey(rdSpread, rdSpreadEscSheets);
-        pageOprObj.initPage();
-
-        $("#linkGLJ").click(function(){
-            rationGLJOprObj.bindRationGljDelOpr();
-            rdSpread.setActiveSheetIndex(0);
-        });
-
-        $("#linkFZDE").click(function(){
-            rationAssistOprObj.bindRationAssDel();
-            rdSpread.setActiveSheetIndex(1);
-        });
-
-        $("#linkFZTJ").click(function(){
-            rationCoeOprObj.bindRationCoeDel();
-            rdSpread.setActiveSheetIndex(2);
-        });
-
-        $("#linkAZZJ").click(function(){
-            rationInstObj.bindRationInstDel();
-            rdSpread.setActiveSheetIndex(3);
-        });
-        //解决spreadjs sheet初始化没高度宽度
-        $('#modalCon').width($(window).width()*0.5);
-        $('#gljSelTreeDiv').height($(window).height() - 300);
-        $("#gljSelSheet").height($("#gljSelTreeDiv").height()-21.6);
-        $("#gljSelSheet").width($('#modalCon').width() * 0.63);
-        $(window).resize(function () {
-            $('#modalCon').width($(window).width()*0.5);
-            $('#gljSelTreeDiv').height($(window).height() - 300);
-            $("#gljSelSheet").height($("#gljSelTreeDiv").height()-21.6);
-            $("#gljSelSheet").width($('#modalCon').width()* 0.63);
-        });
-    });
-</script>
 </body>
 <script type="text/javascript">
     autoFlashHeight();

+ 19 - 37
web/building_saas/complementary_ration_lib/js/gljSelect.js

@@ -39,28 +39,22 @@ let gljSelOprObj = {
             delete glj.ID;
         }
     },
-    getSelGljItems: function(stdGljLibId, callback) {
-        let me = this;
-        CommonAjax.post('/complementartGlj/api/getGljItems', {stdGljLibId: stdGljLibId}, function (rstData) {
-            me.stdGljList = rstData.stdGljs;
-            //兼容多单价,计算补充定额价格时,套多单价人材机的时候,默认取第一个价格
-            for(let sGlj of me.stdGljList){
-                if(sGlj.priceProperty && typeof sGlj.priceProperty.price1 !== 'undefined'){
-                    sGlj.basePrice = sGlj.priceProperty.price1;
-                }
+    getSelGljItems: function(gljData) {
+        this.stdGljList = gljData.stdGljs;
+        //兼容多单价,计算补充定额价格时,套多单价人材机的时候,默认取第一个价格
+        for(let sGlj of this.stdGljList){
+            if(sGlj.priceProperty && typeof sGlj.priceProperty.price1 !== 'undefined'){
+                sGlj.basePrice = sGlj.priceProperty.price1;
             }
-            me.complementaryGljList = rstData.complementaryGljs;
-            me.switchToGljId(me.stdGljList);
-            me.switchToGljId(me.complementaryGljList);
-            me.setProp('type', 'std', me.stdGljList);
-            me.setProp('type', 'complementary', me.complementaryGljList);
-            me.sortGlj(me.stdGljList);
-            me.sortGlj(me.complementaryGljList);
-            gljAdjOprObj.gljList = me.stdGljList.concat(me.complementaryGljList);
-            if(callback){
-                callback();
-            }
-        });
+        }
+        this.complementaryGljList = gljData.complementaryGljs;
+        this.switchToGljId(this.stdGljList);
+        this.switchToGljId(this.complementaryGljList);
+        this.setProp('type', 'std', this.stdGljList);
+        this.setProp('type', 'complementary', this.complementaryGljList);
+        this.sortGlj(this.stdGljList);
+        this.sortGlj(this.complementaryGljList);
+        gljAdjOprObj.gljList = this.stdGljList.concat(this.complementaryGljList);
     },
     initClassTree: function (type, treeData) {
         let me = this;
@@ -81,22 +75,10 @@ let gljSelOprObj = {
             }
         }
     },
-    getGljClassTree: function (gljLibId, callback) {
-        let me = this;
-        let url = '/complementartGlj/api/getMixedTree';
-        let postData = {gljLibId: gljLibId};
-        let sucFunc = function (rstData) {
-            me.treeData = rstData;
-            me.initClassTree('std', me.treeData.std);
-            gljSelOprObj.buildSheet($('#gljSelSheet')[0]);
-            if(callback){
-                callback();
-            }
-        };
-        let errFunc = function () {
-
-        };
-        CommonAjax.post(url, postData, sucFunc, errFunc);
+    getGljClassTree: function (mixedTreeData) {
+        this.treeData = mixedTreeData;
+        this.initClassTree('std', this.treeData.std);
+        gljSelOprObj.buildSheet($('#gljSelSheet')[0]);
     },
     buildSheet: function (container) {
         let me = gljSelOprObj;

+ 79 - 0
web/building_saas/complementary_ration_lib/js/init.js

@@ -0,0 +1,79 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author CaiAoLin
+ * @date 2019/9/24
+ * @version
+ */
+const initialization = (() => {
+    $(document).ready(function () {
+        $.bootstrapLoading.start();
+        CommonAjax.get('/complementaryRation/api/initData', {}, res => {
+            if (res.error) {
+                alert('数据初始化失败,请重试。');
+                setTimeout(() => {
+                    window.location.href = '/'
+                }, 1200);
+            } else {
+                const data = res.data;
+                pageOprObj.rationTreeData = data.rationTreeData;
+                pageOprObj.mixedTreeData = data.mixedTreeData;
+                pageOprObj.mixedGLJData = data.mixedGLJData;
+                rationGLJOprObj.distTypeTree = data.gljDistTypeCache;
+                rationOprObj.rationsCodes = data.rationsCodes;
+                rationOprObj.buildSheet($("#rationItemsSheet")[0]);
+                // tabPanel 下有多个Spread时,相互之间不能正确显示。改成一个Spread下多个Sheet。
+                var rdSpread = sheetCommonObj.createSpread($("#rdSpread")[0], 4);
+                rdSpread.options.allowUserDragFill = false;
+                rdSpread.options.allowUserDragDrop = false;
+                sheetCommonObj.spreadDefaultStyle(rdSpread);
+                rationGLJOprObj.buildSheet(rdSpread.getSheet(0));
+                rationAssistOprObj.buildSheet(rdSpread.getSheet(1));
+                rationCoeOprObj.buildSheet(rdSpread.getSheet(2));
+                rationInstObj.buildSheet(rdSpread.getSheet(3));
+                rationInstObj.getInstallation(data.installationData);
+                let rdSpreadEscSheets = [];
+                rdSpreadEscSheets.push({sheet: rdSpread.getSheet(0), editStarting: rationGLJOprObj.onEditStarting, editEnded: rationGLJOprObj.onCellEditEnd});
+                rdSpreadEscSheets.push({sheet: rdSpread.getSheet(1), editStarting: rationAssistOprObj.onEditStarting, editEnded: rationAssistOprObj.onEditEnded});
+                rdSpreadEscSheets.push({sheet: rdSpread.getSheet(2), editStarting: rationCoeOprObj.onEditStarting, editEnded: rationCoeOprObj.onEditEnded});
+                rdSpreadEscSheets.push({sheet: rdSpread.getSheet(3), editStarting: rationInstObj.onEditStarting, editEnded: rationInstObj.onEditEnded});
+                sheetCommonObj.bindEscKey(rdSpread, rdSpreadEscSheets);
+                pageOprObj.initPage();
+
+                $("#linkGLJ").click(function(){
+                    rationGLJOprObj.bindRationGljDelOpr();
+                    rdSpread.setActiveSheetIndex(0);
+                });
+
+                $("#linkFZDE").click(function(){
+                    rationAssistOprObj.bindRationAssDel();
+                    rdSpread.setActiveSheetIndex(1);
+                });
+
+                $("#linkFZTJ").click(function(){
+                    rationCoeOprObj.bindRationCoeDel();
+                    rdSpread.setActiveSheetIndex(2);
+                });
+
+                $("#linkAZZJ").click(function(){
+                    rationInstObj.bindRationInstDel();
+                    rdSpread.setActiveSheetIndex(3);
+                });
+            }
+            $.bootstrapLoading.end();
+        });
+        //解决spreadjs sheet初始化没高度宽度
+        $('#modalCon').width($(window).width()*0.5);
+        $('#gljSelTreeDiv').height($(window).height() - 300);
+        $("#gljSelSheet").height($("#gljSelTreeDiv").height()-21.6);
+        $("#gljSelSheet").width($('#modalCon').width() * 0.63);
+        $(window).resize(function () {
+            $('#modalCon').width($(window).width()*0.5);
+            $('#gljSelTreeDiv').height($(window).height() - 300);
+            $("#gljSelSheet").height($("#gljSelTreeDiv").height()-21.6);
+            $("#gljSelSheet").width($('#modalCon').width()* 0.63);
+        });
+    });
+})();

+ 0 - 22
web/building_saas/complementary_ration_lib/js/ration.js

@@ -95,7 +95,6 @@ let rationOprObj = {
         let me = rationOprObj;
         me.workBook = sheetCommonObj.buildSheet(container, me.setting, 30);
         sheetCommonObj.bindEscKey(me.workBook, [{sheet: me.workBook.getSheet(0), editStarting: me.onCellEditStart, editEnded: me.onCellEditEnd}]);
-        me.getRationsCodes(rationRepId);
         me.onContextmenuOpr();
         me.rationDelOpr();
         me.setCombo(me.workBook.getSheet(0), 'dynamic');
@@ -615,27 +614,6 @@ let rationOprObj = {
         obj.machinePrice = 0;
         obj.basePrice = 0;
     },
-    isValidUnit: function (rationObj, validUnits) {
-        let rst = true;
-        if(typeof rationObj.unit !== 'undefined' && rationObj.unit && validUnits.indexOf(rationObj.unit) === -1){//无效
-            rst = false;
-        }
-        return rst;
-    },
-    getRationsCodes: function (repId) {
-        let me = rationOprObj;
-        $.ajax({
-            type: 'post',
-            url: 'api/getRationsCodes',
-            data: {data: JSON.stringify({repId: repId})},
-            dataType: 'json',
-            success: function (result) {
-                if(!result.error){
-                    me.rationsCodes = result.data;
-                }
-            }
-        })
-    },
     mixUpdateRequest: function(updateArr, addArr, removeIds, callback) {
         let me = rationOprObj;
         me.saveInString(updateArr);

+ 9 - 16
web/building_saas/complementary_ration_lib/js/ration_glj.js

@@ -25,7 +25,6 @@ var rationGLJOprObj = {
         }
     },
     getDistTypeTree: function (gljDistType) {
-        let me = this;
         let distType;
         let distTypeTree = {
             prefix : 'gljDistType',
@@ -76,21 +75,15 @@ var rationGLJOprObj = {
         })
     },
     buildSheet: function(sheet) {
-        var me = this;
-        me.sheet = sheet;
-        me.getGljDistType(function () {
-           // gljSelOprObj.getGljClassTree(pageOprObj.gljLibId, function () {
-              //  gljSelOprObj.getSelGljItems(pageOprObj.gljLibId, function () {
-                    sheetCommonObj.initSheet(me.sheet, me.setting, 30);
-                    me.onContextmenuOpr();
-                    me.bindRationGljDelOpr();
-                    me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, me.onClipboardPasting);
-                    me.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, me.onClipboardPasted);
-                    me.sheet.bind(GC.Spread.Sheets.Events.EditStarting, me.onEditStarting);
-                    me.sheet.bind(GC.Spread.Sheets.Events.EditEnded, me.onCellEditEnd);
-                });
-          //  });
-        //});
+        this.sheet = sheet;
+        this.distTypeTree = this.getDistTypeTree(this.distTypeTree);
+        sheetCommonObj.initSheet(this.sheet, this.setting, 30);
+        this.onContextmenuOpr();
+        this.bindRationGljDelOpr();
+        this.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasting, this.onClipboardPasting);
+        this.sheet.bind(GC.Spread.Sheets.Events.ClipboardPasted, this.onClipboardPasted);
+        this.sheet.bind(GC.Spread.Sheets.Events.EditStarting, this.onEditStarting);
+        this.sheet.bind(GC.Spread.Sheets.Events.EditEnded, this.onCellEditEnd);
     },
     onContextmenuOpr: function () {//右键菜单
         let me = this;

+ 11 - 17
web/building_saas/complementary_ration_lib/js/ration_installation.js

@@ -42,24 +42,18 @@ let rationInstObj = {
     isDef: function (v) {
         return v !== undefined && v !== null;
     },
-    getInstallation: function (callback) {
-        let me = this;
-        CommonAjax.post('api/getInstallation', {}, function (rstData) {
-            //建立name - ID 映射, ID - name 映射
-            me.feeItem = {};
-            me.IDMapping = {feeItem: {}, section: {}};
-            for(let feeItem of rstData){
-                me.feeItem[feeItem.feeItem] = {ID: feeItem.ID, section: {}};
-                me.IDMapping['feeItem'][feeItem.ID] = feeItem.feeItem;
-                for(let section of feeItem.section){
-                    me.feeItem[feeItem.feeItem]['section'][section.name] = section.ID;
-                    me.IDMapping['section'][section.ID] = section.name;
-                }
-            }
-            if(callback){
-                callback(rstData);
+    getInstallation: function (installationData) {
+        //建立name - ID 映射, ID - name 映射
+        this.feeItem = {};
+        this.IDMapping = {feeItem: {}, section: {}};
+        for(let feeItem of installationData){
+            this.feeItem[feeItem.feeItem] = {ID: feeItem.ID, section: {}};
+            this.IDMapping['feeItem'][feeItem.ID] = feeItem.feeItem;
+            for(let section of feeItem.section){
+                this.feeItem[feeItem.feeItem]['section'][section.name] = section.ID;
+                this.IDMapping['section'][section.ID] = section.name;
             }
-        });
+        }
     },
     getFeeItemCombo: function () {
         let feeItemArr = [];

+ 18 - 50
web/building_saas/complementary_ration_lib/js/section_tree.js

@@ -2,31 +2,14 @@
  * Created by Zhong on 2017/12/18.
  */
 let pageOprObj = {
-    refreshAllBooks: function () {
-        if (sectionTreeObj.workBook) {
-            sectionTreeObj.workBook.refresh();
-        }
-        if (rationOprObj.workBook) {
-            rationOprObj.workBook.refresh();
-        }
-        if (coeOprObj.workBook) {
-            coeOprObj.workBook.refresh();
-        } else {
-            pageObj.initPage();
-        }
-        if (gljAdjOprObj.workBook) {
-            gljAdjOprObj.workBook.refresh();
-        }
-        if (rationGLJOprObj.sheet.getParent()) {
-            rationGLJOprObj.sheet.getParent().refresh();
-        }
-    },
     rationLibName : null,
     rationLibId : null,
     gljLibId: gljLibId,
+    rationTreeData: null,
+    mixedTreeData: null,
+    mixedGLJData: null,
     initPage : function() {
-        let me = this;
-        sectionTreeObj.getSectionTree();
+        sectionTreeObj.getSectionTree(this.rationTreeData);
         //job
         jobContentOprObj.radiosChange(jobContentOprObj.radios, jobContentOprObj.tableAll, jobContentOprObj.tablePartial);
         $('#addConBtn').click(jobContentOprObj.bindAddConBtn());
@@ -37,9 +20,8 @@ let pageOprObj = {
         $('#fzAddConBtn').click(annotationOprObj.bindAddConBtn());
         $('#fzUpdateConBtn').click(annotationOprObj.bindUpdateConBtn());
         annotationOprObj.bindAllEvents($('#fzTxtareaAll'));
-        gljSelOprObj.getGljClassTree(gljLibId, function () {
-            gljSelOprObj.getSelGljItems(gljLibId);
-        });
+        gljSelOprObj.getGljClassTree(this.mixedTreeData);
+        gljSelOprObj.getSelGljItems(this.mixedGLJData);
     },
     getRationLibInfo: function (rationLibId, callback) {
         CommonAjax.post('api/getRationLib', {rationRepId: rationLibId}, callback);
@@ -223,32 +205,18 @@ let sectionTreeObj = {
             sheetCommonObj.setColumnWidthByRate($('#sectionSpread').width() - 65, this.workBook, [{rateWidth: 1}]);//65: 列头宽度和垂直滚动条宽度和
         }
     },
-    getSectionTree: function () {
-        let me = sectionTreeObj;
-        let url = 'api/getRationTree';
-        //type: 0-补充库 1-标准库
-        let postData = {type: 0};
-        let sucFunc = function (rstData) {
-            if(rstData.length > 0){
-                storageUtil.setSessionCache("RationGrp","repositoryID",rstData[0].rationRepId);
-            }
-            //init
-            me.buildSheet();
-            me.initTree(rstData);
-            me.cache = me.tree.items;
-            me.bindBtn();
-            me.initController(me.tree, me.sheet, me.setting.sheet);
-            me.controller.showTreeData();
-            me.setColor(me.cache);
-            me.sheet.setFormatter(-1, 0, '@');
-            me.initSelection(me.tree.selected);
-            me.loadRateWidth();
-            //explanatoryOprObj.bindEvents($('#explanationShow'), $('#ruleTextShow'));
-        };
-        let errFunc = function () {
-
-        };
-        CommonAjax.post(url, postData, sucFunc, errFunc);
+    getSectionTree: function (treeData) {
+        //init
+        this.buildSheet();
+        this.initTree(treeData);
+        this.cache = this.tree.items;
+        this.bindBtn();
+        this.initController(this.tree, this.sheet, this.setting.sheet);
+        this.controller.showTreeData();
+        this.setColor(this.cache);
+        this.sheet.setFormatter(-1, 0, '@');
+        this.initSelection(this.tree.selected);
+        this.loadRateWidth();
     },
 
     setColor: function (nodes) {

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

@@ -2204,6 +2204,7 @@
     <script src="/lib/lz-string/lz-string.min.js"></script>
     <script src="/lib/fileSaver/FileSaver.min.js"></script>
     <script src="/lib/js-zip/jszip.min.js"></script>
+    <script type="text/javascript" src="/lib/jspdf/jspdf.min.js"></script>
     <!-- inject:js -->
     <!--<script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>-->
     <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
@@ -2315,6 +2316,7 @@
     <script type="text/javascript" src="/public/web/treeDataHelper.js"></script>
     <script type="text/javascript" src="/public/web/string_util_light.js"></script>
     <script type="text/javascript" src="/public/web/ztree_common.js"></script>
+    <script type="text/javascript" src="/web/building_saas/report/js/rpt_jspdf.js"></script>
     <script type="text/javascript" src="/web/building_saas/report/js/rpt_main.js"></script>
     <script type="text/javascript" src="/web/building_saas/report/js/rpt_cfg_const.js"></script>
     <script type="text/javascript" src="/web/building_saas/report/js/jpc_output_value_define.js"></script>

+ 19 - 10
web/building_saas/main/js/models/exportStandardInterface.js

@@ -69,6 +69,7 @@ const XMLStandard = (function () {
         '{其他项目费}': 'QTXMHJ',
         '{规费}': 'GF',
         '{税金}': 'SJ',
+        '{税前工程造价}': 'SQGCZJ',
         '{分部分项定额人工费}': 'RGF',
         '{分部分项定额材料费}': 'CLF',
         '{分部分项定额施工机具使用费}': 'JXF',
@@ -106,6 +107,7 @@ const XMLStandard = (function () {
         'QTXMHJ': '其他项目费',
         'GF': '规费',
         'SJ': '税金',
+        'SQGCZJ': '税前工程造价',
         'RGF': '分部分项定额人工费',
         'CLF': '分部分项定额材料费',
         'JXF': '分部分项定额施工机具使用费',
@@ -791,7 +793,8 @@ const XMLStandard = (function () {
         //如果是“投标”,且采用了信息价差额法,则导出;如果采用了指数法,则导出,但数量、风险系数、基准单价、投标单价,都取0。
         function DifferentiaGljDetail(adjustType, source) {
             let attrs = [
-                {name: '关联材料号', value: getGljCode(source.id), minLen: 1, maxLen: 20, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
+                //getGljCode(source.id)
+                {name: '关联材料号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
                 {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
                 {name: '规格', value: source.specs, maxLen: 255, whiteSpace: _config.WHITE_SPACE.COLLAPSE},
                 {name: '单位', value: source.unit, minLen: 1, maxLen: 20, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
@@ -817,7 +820,8 @@ const XMLStandard = (function () {
         //如果是“投标”,且采用了指数法,则导出;如果采用了信息价差额法,则导出,但定值权重A取1,变值权重B、基本价格指数、现行价格指数取0。
         function ExponentialGljDetail(adjustType, source) {
             let attrs = [
-                {name: '关联材料号', value: getGljCode(source.id), minLen: 1, maxLen: 20, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
+                // getGljCode(source.id)
+                {name: '关联材料号', value: source.code, minLen: 1, maxLen: 20, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
                 {name: '名称', value: source.name, minLen: 1, maxLen: 255, whiteSpace: _config.WHITE_SPACE.COLLAPSE, required: true},
                 {name: '规格', value: source.specs, maxLen: 255, whiteSpace: _config.WHITE_SPACE.COLLAPSE},
                 {name: '变值权重B', value: adjustType === _config.ADJUST_TYPE.coe ? source.varWeight : '0', type: _config.TYPE.DECIMAL, required: true},
@@ -1391,8 +1395,8 @@ const XMLStandard = (function () {
                         continue;
                     }
                     let gljSource = {
-                        //code: rGlj.code,
-                        code: getGljCode(rGlj.projectGLJID),
+                        code: rGlj.code,
+                        //code: getGljCode(rGlj.projectGLJID),
                         quantity: rGlj.quantity,
                         totalQuantity: gljUtil.getTotalQuantity(rGlj,  rationData, decimal.glj.quantity, decimal.ration.quantity)
                     };
@@ -1931,9 +1935,9 @@ const XMLStandard = (function () {
                         continue;
                     }
                     // 总消耗量为0不导出
-                    /*if (!+glj.quantity) {
+                    if (!+glj.quantity) {
                         continue;
-                    }*/
+                    }
                     let price = gljUtil.getGLJPrice(glj, detail.projectGLJ.datas,
                         detail.projectInfo.property.calcOptions, detail.labourCoe.datas, detail.projectInfo.property.decimal, false, _, scMathUtil);
                     //调整价
@@ -1946,8 +1950,8 @@ const XMLStandard = (function () {
                         feeType = '4';
                     }
                     let gljSource = {
-                        //code: glj.code,
-                        code: getGljCode(glj.id),
+                        code: glj.code,
+                        //code: getGljCode(glj.id),
                         name: glj.name,
                         specs: glj.specs,
                         unit: glj.unit,
@@ -1980,7 +1984,11 @@ const XMLStandard = (function () {
                         for (let ratio of ratioData) {
                             let pGLJ = detail.projectGLJ.datas.gljList.find(d => d.original_code === ratio.code);
                             if (pGLJ) {
-                                let gljRatio = new GljRatio({code: getGljCode(pGLJ.id), quantity: ratio.consumption});
+                                let gljRatio = new GljRatio({
+                                    code: pGLJ.code,
+                                    //code: getGljCode(pGLJ.id),
+                                    quantity: ratio.consumption
+                                });
                                 gljEle.children.push(gljRatio);
                             }
                         }
@@ -1988,7 +1996,8 @@ const XMLStandard = (function () {
                     gljSummary.children.push(gljEle);
                     gljSource.totalPrice = scMathUtil.roundForObj(gljSource.quantity * gljSource.marketPrice,
                         detail.projectInfo.property.decimal.bills.totalPrice);
-                    //评标和暂估材料表下的材料明细中的人材机代码,要求单位工程内唯一,由于人材机汇总也有这个限制,所以这里不再处理
+                    //评标和暂估材料表下的材料明细中的人材机代码,要求单位工程内唯一,由于人材机汇总也有这个限制,所以
+                    // 这里不再处理
                     if (glj.is_eval_material) { //评标
                         gljSource.serialNo = evalBidSeq++;
                         evalBidMaterial.children.push(new MaterialDetail('evalBidMaterial', gljSource));

+ 1 - 1
web/building_saas/main/js/models/exportStdInterfaceBase.js

@@ -547,7 +547,7 @@ const XML_EXPORT_BASE = (() => {
                 } else {
                     let totalFee = getFee(node.data.fees, 'common.totalFee'),
                         feeRate = node.data.feeRate;
-                    return feeRate && !isNaN(feeRate) ? scMathUtil.roundTo(totalFee/feeRate, -2) : totalFee
+                    return +feeRate ? scMathUtil.roundTo(totalFee/(feeRate/100), -2) : totalFee
                 }
             }
             return expr;

+ 8 - 3
web/building_saas/main/js/models/importStandardInterface.js

@@ -1213,6 +1213,11 @@ const ImportXML = (() => {
             addFixedBlock(fixedFlag.PROVISIONAL, tenderData.other.provisional.items, tenderData.other.provisional.fees);
             //专业工程暂估价
             addFixedBlock(fixedFlag.ENGINEERING_ESITIMATE, tenderData.other.engineeringPro.items, tenderData.other.engineeringPro.fees);
+            // 专业工程暂估价汇总金额设置为暂估价清单金额
+            let estimateFixedBills = billsTarget.find(d => getFlag(d) === fixedFlag.ESTIMATE);
+            if (estimateFixedBills) {
+                estimateFixedBills.fees = tenderData.other.engineeringPro.fees;
+            }
             //计日工
             addFixedBlock(fixedFlag.DAYWORK, null, tenderData.other.dayWork.fees);
             //人工
@@ -1326,6 +1331,7 @@ const ImportXML = (() => {
             GF: '{规费}',
             SJ: '{税金}',
             SJHJ: '{税金}',
+            SQGCZJ: '{税前工程造价}'
         };
         //转换计算基数
         //1.有子项数据,则清空基数
@@ -1446,7 +1452,6 @@ const ImportXML = (() => {
                 });
             });
             // 模板映射:{[templateLibID]: data}
-            debugger;
             let templateMapping = await ajaxPost('/template/bills/api/getNeedfulTemplate', {allTemplateLibIDs});
             for (let i = 0; i < xmlObj.engs.length; i++) {
                 let curEng = xmlObj.engs[i],
@@ -1656,7 +1661,8 @@ const ImportXML = (() => {
                         if (!bills.quantity || !ration.quantity){
                             ration.contain = '0';
                         } else {
-                            ration.contain = scMathUtil.roundForObj(ration.quantity / bills.quantity, 6);
+                            let tempV = ration.quantity / bills.quantity;
+                            ration.contain = isFinite(tempV) ? scMathUtil.roundForObj(tempV, 6) : '0';
                         }
                         //工程量表达式:工程量 * 单位前的量
                         /*if (!ration.unit) {
@@ -1670,7 +1676,6 @@ const ImportXML = (() => {
                                 : ration.quantity;
                         }*/
                         // 问题
-                        debugger;
                         //处理定额人材机,添加需要的数据
                         ration.rationGljs.forEach(rGLJ => {
                             let matchGLJ = projectGLJMap[rGLJ.code];

+ 9 - 0
web/building_saas/main/js/models/main_consts.js

@@ -404,6 +404,15 @@ const filterType = {
     ZYCL:'11',
     AMAE:'12'
 };
+// 文件类型
+const _fileKind = {
+    // 投标
+    tender: 1,
+    // 招标
+    bid: 2,
+    // 控制价
+    control: 3
+};
 const filterTypeArray = ['1','2','3','4','5'];
 
 const installFeeType = ['子目费用','分项费用','措施费用'];

+ 64 - 10
web/building_saas/main/js/models/ration_glj.js

@@ -497,6 +497,60 @@ let ration_glj = {
             }
            return node
         };
+        ration_glj.prototype.getGLJDataPaging = function (condition, cb) {
+            gljOprObj.loadingPagination = true;
+            const property = projectObj.project.projectInfo.property;
+            const engineerID = property.engineering_id;
+            CommonAjax.post('/rationGlj/getGLJDataPaging', {engineerID, condition}, function (data) {
+                gljOprObj.curPageTotal = data.total;
+                data.complementaryGLJs.forEach(glj => {
+                    glj.isComplementary = true;
+                });
+                const gljType = condition.type === gljOprObj.pagingType.stdGLJ
+                    ? 'stdGLJ'
+                    : 'complementaryGLJs';
+                const newData = data[gljType];
+                if (condition.init) {
+                    gljOprObj.treeData = data.treeData;
+                    gljOprObj.distTypeTree = gljOprObj.getComboData(data.distTypeTree);
+                }
+                // 需要重置当前页面数据(点击了分类树、搜索等等)
+                if (condition.reset) {
+                    gljOprObj.stdGLJ = data.stdGLJ;
+                    gljOprObj.complementaryGLJs = data.complementaryGLJs;
+                    gljOprObj.AllRecode = [...gljOprObj.stdGLJ, ...gljOprObj.complementaryGLJs];
+                } else {
+                    gljOprObj[gljType].splice(condition.index, 0, ...newData);
+                    gljOprObj.AllRecode.splice(condition.index, 0, ...newData);
+                }
+                // 根据缓存选中数据,设置人材机是否选中
+                newData.forEach(item => {
+                    const connectKey = gljOprObj.getIndex(item, gljLibKeyArray);
+                    if (gljOprObj.GLJSelection.includes(connectKey)) {
+                        item.select = 1;
+                    }
+                });
+                // 设置人材机类型名称
+                gljOprObj.setTypeName(gljOprObj.distTypeTree.comboDatas, newData);
+                if (data.priceProperties && data.priceProperties.length > 0) {
+                    let tmp = _.find(data.priceProperties, {region: property.region, taxModel: parseInt(property.taxType)});
+                    if (tmp) {
+                        let dataCode = tmp.price.dataCode;
+                        for (let glj of data.stdGLJ) {
+                            if (glj.priceProperty && gljUtil.isDef(glj.priceProperty[dataCode])) {
+                                glj.basePrice = glj.priceProperty[dataCode];
+                            }
+                        }
+                    }
+                }
+                cb(data[gljType]);
+                gljOprObj.loadingPagination = false;
+            }, function () {
+                if ($.bootstrapLoading.isLoading()) {
+                    $.bootstrapLoading.end();
+                }
+            });
+        };
         ration_glj.prototype.getGLJData = function (cb) {
             let property = projectObj.project.projectInfo.property;
             let engineerID = property.engineering_id;
@@ -661,19 +715,19 @@ let ration_glj = {
 
 
         ration_glj.prototype.addGLJByLib = function (GLJSelection, ration, callback) {
-            let me=this,gljList = [];
-            let allGLJ = gljOprObj.AllRecode;
+            const me = this,
+                  gljList = [],
+                  allGLJ = gljOprObj.AllRecode;
             GLJSelection.sort();
-            _.forEach(GLJSelection, function (g) {
-                let glj = _.find(allGLJ, function (item) {
-                    let i_key = gljOprObj.getIndex(item, gljLibKeyArray);
-                    return i_key == g;
-                });
-                let ration_glj = me.getAddDataByStd(glj,ration.ID,ration.billsItemID,ration.projectID);
-                gljList.push(ration_glj);
+            GLJSelection.forEach(selKey => {
+                const glj = allGLJ.find(item => gljOprObj.getIndex(item, gljLibKeyArray) === selKey);
+                if (glj) {
+                    const rationGLJ = me.getAddDataByStd(glj, ration.ID, ration.billsItemID, ration.projectID);
+                    gljList.push(rationGLJ);
+                }
             });
             $.bootstrapLoading.start();
-            CommonAjax.post("/rationGlj/addGLJ", gljList, callback, function () {
+            CommonAjax.post('/rationGlj/addGLJ', gljList, callback, function () {
                 $.bootstrapLoading.end();
             });
         };

+ 170 - 77
web/building_saas/main/js/views/glj_view.js

@@ -14,6 +14,14 @@ var gljOprObj = {
     detailSheet: null,
     detailData: [],
     GLJSelection: [],
+    pagingType: {
+        stdGLJ: 1,
+        complementaryGLJs: 2
+    },
+    // 是否正在分页
+    loadingPagination: false,
+    // 当前筛选条件下总数据数,用于判断是否需要继续分页
+    curPageTotal: 0,
     selectedGLJClass: null,
     parentNodeIds: {},
     preActiveTab: '', //提升焦点变换性能 2019年4月12日
@@ -68,9 +76,10 @@ var gljOprObj = {
                     let me = gljOprObj, gljTypeId = treeNode.ID;
                     if (treeNode.ID) {
                         me.gljCurTypeId = treeNode.ID;
-                        me.filterLibGLJSheetData();
-                        me.showLibGLJSheetData();
-                        gljOprObj.initSelection({row: me.gljLibSheet.getActiveRowIndex()});
+                        /* me.filterLibGLJSheetData();
+                         me.showLibGLJSheetData();*/
+                        me.loadPageData(gljOprObj.gljLibSheet, true, 0);
+                        //gljOprObj.initSelection({row: me.gljLibSheet.getActiveRowIndex()});
                     }
                 } else {
                     if (treeNode.isParent) {
@@ -81,7 +90,6 @@ var gljOprObj = {
                         $('#selected_class').val(treeNode.ID);
                     }
                 }
-
             }
         }
     },
@@ -94,8 +102,8 @@ var gljOprObj = {
             {headerName: "规格型号", headerWidth: 160, dataCode: "specs", dataType: "String", hAlign: "left", vAlign: "center"},
             {headerName: "单位", headerWidth: 40, dataCode: "unit", dataType: "String", hAlign: "center", vAlign: "center"},
             {headerName: "单价", headerWidth: 55, dataCode: "basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
-            {headerName: "类型", headerWidth: 60, dataCode: "gljType", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName: "新增", headerWidth: 40, dataCode: "isComplementary", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox"}
+            {headerName: "类型", headerWidth: 60, dataCode: "typeName", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName: "新增", headerWidth: 40, dataCode: "isComplementary", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox", readOnly: true}
         ],
         view: {
             lockColumns: [0, 1, 2, 3, 4, 5, 6]
@@ -310,6 +318,29 @@ var gljOprObj = {
         let me = gljOprObj;
         me.initSelection(args.newSelections.length > 0 ? {row: args.newSelections[0].row} : {row: 0});
     },
+    onTopRowChanged: function (sender, args) {
+        const me = gljOprObj;
+        const topRow = args.newTopRow;
+        const bottomRow = args.sheet.getViewportBottomRow(1);
+        const radioType = $("input[name='glj']:checked").val();
+        const curRecord = radioType === 'stdGLJ' ? me.stdGLJ : me.complementaryGLJs;
+        // 当前表显示数据数大于等于当前筛选情况下最大数据数,不获取下一分页
+        if (curRecord.length >= me.curPageTotal ||
+            me.loadingPagination) {
+            return;
+        }
+        if (curRecord.length -1 === bottomRow) {
+            // 获取第curRecord.length行开始的数据
+            me.loadPageData(args.sheet, false, curRecord.length);
+        }
+    },
+    loadPageData: function (sheet, reset, index) {
+        let condition = this.getPagingCondition(false, reset, false, index);
+        projectObj.project.ration_glj.getGLJDataPaging(condition, function (data) {
+            sheetCommonObj.appendData(sheet, condition.index, 0, gljOprObj.gljLibSheetSetting, data);
+            gljOprObj.initSelection({row: gljOprObj.gljLibSheet.getActiveRowIndex()});
+        });
+    },
     getSelStyle: function (selected,settingStyle) {
         let style = new GC.Spread.Sheets.Style();
         if(settingStyle){
@@ -372,6 +403,10 @@ var gljOprObj = {
         }  else if (args.sheetName == 'quantity_detail') {
             projectObj.project.quantity_detail.isSummationUpdate(args, gljOprObj.detailData, newval);
         } else if (args.sheetName == 'glj_lib') {
+            if (gljOprObj.gljLibSheetSetting.header[args.col].readOnly) {
+                args.sheet.getCell(args.row, args.col).value(checkboxValue);
+                return;
+            }
             if(gljOprObj.gljLibSheetSetting.header[args.col].dataCode === 'select'){
                 gljOprObj.setGLJSelection(args, newval);
             }
@@ -978,6 +1013,89 @@ var gljOprObj = {
         sheetCommonObj.showData(this.gljLibSheet, this.gljLibSheetSetting, this.gljLibSheetData, gljOprObj.distTypeTree);
         this.gljLibSheet.setRowCount(this.gljLibSheetData.length);
     },
+    // 根据人材机类型,设置人材机类型显示名称
+    setTypeName: function (distTypeData, data) {
+        data.forEach(item => {
+            let typeData = distTypeData.find(typeItem => typeItem.value === item.gljType);
+            if (typeData) {
+                item.typeName = typeData.text;
+            }
+        });
+    },
+    /*
+    * 获取分页查询所需要的条件数据
+    * @param  {Boolean}init 是否是初始化
+    *         {Boolean}reset 是否重置数据 (点击分类树等)
+    *         {Boolean}location 是否定位(替换初始化)
+    *         {Number}index 分页数据开始索引
+    * @return {Object}
+    * */
+    getPagingCondition: function (init, reset, location, index) {
+        // 上一次分页的最末人材机编码,index为0时,code为空
+        const code = gljOprObj.AllRecode && gljOprObj.AllRecode[index - 1] ? gljOprObj.AllRecode[index - 1].code : '';
+        // 初始化情况下的条件
+        let condition = {
+            code,
+            // 是否重置数据
+            reset,
+            // 是否定位
+            location,
+            // 开始取数据的位置
+            index,
+            // 限制条数
+            limit: 50,
+            // 初始化
+            init: init,
+            // 所在部分(标准、补充)
+            type: this.pagingType.stdGLJ,
+            // 替换数据,替换操作下有数据:编码、名称、规格、单位、类型
+            replace: null,
+            // 所在分类节点
+            classList: [],
+            // 搜索文本
+            search: ''
+        };
+        // 触发入口(添加、替换、批量替换)
+        const actionType = $('#actionType').val();
+        const replaceActions = ['replace', 'm_replace'];
+        // 替换相关
+        if (replaceActions.includes(actionType)) {
+            // 定额人材机界面选中的人材机
+            const selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+            condition.replace = {
+                code: selected.code,
+                name: selected.name,
+                specs: selected.specs,
+                unit: selected.unit,
+                gljType: selected.type
+            };
+        }
+        if (init) {
+            return condition;
+        }
+        condition.init = false;
+        // 标准、补充的选择
+        if ($('#glj_tree_div').is(':visible')) {
+            let radioType = $("input[name='glj']:checked").val();
+            condition.type = this.pagingType[radioType];
+        }
+        // 选中的分类
+        if (this.treeObj) {
+            let selNode = this.treeObj.getNodeByParam('ID', this.gljCurTypeId);
+            // 不为最顶层节点时,才赋值给withinClass
+            if (selNode && selNode.ParentID !== -1) {
+                const classList = this.parentNodeIds['_pNodeId_' + this.gljCurTypeId];
+                condition.classList = classList ? classList : [this.gljCurTypeId];
+            }
+        }
+        // 搜索文本
+        let searchStr = $('#gljSearchKeyword').val().trim();
+        if(searchStr){
+            condition.search = searchStr;
+        }
+        return condition;
+
+    },
     filterLibGLJSheetData: function () {
         let me = this;
         let val = $("input[name='glj']:checked").val();
@@ -1018,13 +1136,12 @@ var gljOprObj = {
         }
     },
     addGLJsSelection: function (args, newVal) {
-        var con_key = this.getIndex(this.gljLibSheetData[args.row], gljLibKeyArray);
+        const curGLJ = this.AllRecode[args.row];
+        const con_key = this.getIndex(curGLJ, gljLibKeyArray);
         if (newVal == 1) {
             this.GLJSelection.push(con_key);
-            this.gljLibSheetData[args.row].select = 1;
         } else if (newVal == 0) {
             _.pull(this.GLJSelection, con_key);
-            this.gljLibSheetData[args.row].select = 0;
         }
     },
     replaceGLJSelection: function (args, newVal) {
@@ -1034,21 +1151,20 @@ var gljOprObj = {
             args.sheet.getCell(args.row, args.col).value(1);
             return;
         }
-        this.GLJSelection = [me.getIndex(this.gljLibSheetData[args.row], gljLibKeyArray)];
-        this.gljLibSheetData[args.row].select = 1;
-        var oindex = _.findIndex(this.gljLibSheetData, function (item) {
+        const curGLJ = this.AllRecode[args.row];
+        const connectKey = this.getIndex(curGLJ, gljLibKeyArray);
+        this.GLJSelection = [connectKey];
+        var oindex = _.findIndex(this.AllRecode, function (item) {
             var i_key = me.getIndex(item, gljLibKeyArray);
             return oldSelection == i_key;
         });
         if (oindex != -1) {
             args.sheet.getCell(oindex, args.col).value(0);
-            this.gljLibSheetData[oindex].select = 0;
         } else {
             var oldData = _.find(gljOprObj.AllRecode, function (item) {
                 var i_key = me.getIndex(item, gljLibKeyArray);
                 return oldSelection == i_key;
             });
-            oldData ? oldData.select = 0 : "";
         }
     },
     filterLibGLJByType: function () {
@@ -1092,7 +1208,6 @@ var gljOprObj = {
                 distTypeTree.comboDatas.push({text: distTypeObj.data.fullName, value: distTypeObj.data.ID});
             }
         });
-        console.log(distTypeTree);
         return distTypeTree;
     },
     doInsertGLJ: function () {
@@ -1391,8 +1506,8 @@ var gljOprObj = {
         if (!node) node = zTree.getNodeByTId('gljTree_1');
         zTree.selectNode(node);
         gljOprObj.gljCurTypeId = ID;
-        gljOprObj.filterLibGLJSheetData();
-        gljOprObj.showLibGLJSheetData();
+        //--gljOprObj.filterLibGLJSheetData();
+        //--gljOprObj.showLibGLJSheetData();
     },
     isExtraType:function (type) {
         return _.includes(gljUtil.extraType,type)
@@ -1491,7 +1606,14 @@ var gljOprObj = {
     }
 }
 
+// 人材机选择界面的功能进行了适合分页的重构
+// 重构时,只有添加、替换、批量替换的入口。因此只对这三个入口相关的地方进行重构,其他入口的代码没有变更
+// 若以后放开其他入口,需要将其他入口的相应方法进行重构
 $(function () {
+    $('#glj_tree_div').on('hidden.bs.modal', function () {
+        // 清空搜索框
+        $('#gljSearchKeyword').val('');
+    });
     $('#glj_tree_div').on('shown.bs.modal', function (e) {
         if (gljOprObj.gljLibSpresd == undefined) {
             gljOprObj.gljLibSpresd = sheetCommonObj.buildSheet($('#gljLibSheet')[0], gljOprObj.gljLibSheetSetting, gljOprObj.stdGLJ.length + gljOprObj.complementaryGLJs.length);
@@ -1499,53 +1621,50 @@ $(function () {
             gljOprObj.gljLibSpresd.bind(GC.Spread.Sheets.Events.ButtonClicked, gljOprObj.onButtonClick);
             gljOprObj.gljLibSheet = gljOprObj.gljLibSpresd.getSheet(0);
             gljOprObj.gljLibSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, gljOprObj.onSelectionChanged);
+            gljOprObj.gljLibSheet.bind(GC.Spread.Sheets.Events.TopRowChanged, _.debounce(gljOprObj.onTopRowChanged, 100));
             gljOprObj.gljLibSheet.setColumnWidth(0, 20, GC.Spread.Sheets.SheetArea.rowHeader);
             gljOprObj.gljLibSheet.options.isProtected = true;
             gljOprObj.gljLibSheet.name('glj_lib');
+            sheetCommonObj.setSheetBySetting(gljOprObj.gljLibSheet, gljOprObj.gljLibSheetSetting);
         }
-        gljOprObj.gljLibSheetData = gljOprObj.AllRecode;
-        let gljClass = 0, selectMap = {};
+        let gljClass = 0,
+            selected,
+            connect_key;
         if ($('#actionType').val() == 'add' || $('#actionType').val() == 'insert') {//插入,添加
             gljOprObj.GLJSelection = [];
         } else if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){//替换、批量替换
-            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
-            let connect_key = gljOprObj.getIndex(selected, gljKeyArray);
+            selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
+            connect_key = gljOprObj.getIndex(selected, gljKeyArray);
             gljOprObj.GLJSelection = [connect_key];
-            selectMap[connect_key] = true;
-            gljOprObj.filterLibGLJByType();
-        }else if($('#actionType').val() =='addMix'){//添加组成物
+            // 找到定位的分类树
+            const locatedItem = gljOprObj.AllRecode.find(item => gljOprObj.getIndex(item, gljLibKeyArray) === connect_key);
+            if (locatedItem) {
+                gljClass = locatedItem.gljClass;
+                locatedItem.select = 1;
+            }
+        } else if($('#actionType').val() =='addMix'){//添加组成物
             gljOprObj.GLJSelection = [];
             projectGljObject.filterLibGLJForMixRatio();
-            /*selections = projectGljObject.mixRatioData;  添加组成物的时候先不选中
-            gljOprObj.GLJSelection = [];
-            for(let s of selections){
-                let s_key = gljOprObj.getIndex(s, gljKeyArray);
-                selectMap[s_key] = true;
-                gljOprObj.GLJSelection.push(s_key);
-            }*/
-        }
-        for(let item of gljOprObj.gljLibSheetData){
-            let item_key = gljOprObj.getIndex(item, gljLibKeyArray);
-            if(selectMap[item_key]){
-                item.select = 1 ;
-                gljClass = item.gljClass;
-            }
         }
         //替换,焦点定位至当前选中人材机
-        if($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace'){
+        if ($('#actionType').val() =='m_replace' || $('#actionType').val() == 'replace') {
             gljOprObj.locateZTree(gljClass);
-            let selected = gljOprObj.sheetData[gljContextMenu.selectedRow];
-            let index = _.findIndex(gljOprObj.gljLibSheetData, {code: selected.code});
+            sheetCommonObj.appendData(gljOprObj.gljLibSheet, 0, 0, gljOprObj.gljLibSheetSetting, gljOprObj.AllRecode);
+            const index = gljOprObj.AllRecode.findIndex(item => gljOprObj.getIndex(item, gljLibKeyArray) === connect_key);
             gljOprObj.gljLibSheet.showRow(index, GC.Spread.Sheets.VerticalPosition.center);
             gljOprObj.gljLibSheet.setActiveCell(index, 0);
             gljOprObj.initSelection({row: index});
             gljOprObj.gljLibSpresd.focus(true);
         } else if ($('#actionType').val() === 'add') {
             gljOprObj.locateZTree(null);
+            sheetCommonObj.appendData(gljOprObj.gljLibSheet, 0, 0, gljOprObj.gljLibSheetSetting, gljOprObj.AllRecode);
             gljOprObj.gljLibSheet.showRow(0, GC.Spread.Sheets.VerticalPosition.top);
             gljOprObj.gljLibSheet.setActiveCell(0, 0);
             gljOprObj.initSelection({row: 0});
-        } else gljOprObj.showLibGLJSheetData();
+        } else {
+            gljOprObj.showLibGLJSheetData();
+        }
+        console.timeEnd('getGLJData');
     });
 
     $('#mreplace_next_div').on('shown.bs.modal', function (e) {
@@ -1553,46 +1672,20 @@ $(function () {
         gljOprObj.showScopeDatas();
     });
 
-
-    $('#glj_tree_div').on('hidden.bs.modal', function () {
-        $('#gljSearchKeyword').val('');
-    });
-
+    // 人材机选择界面标准、补充单选
     $('.glj-radio').change(function () {
-        let val = $("input[name='glj']:checked").val();
-        if (val == 'allGljs') {
-            gljOprObj.gljLibSheetData = gljOprObj.AllRecode;
-            gljOprObj.filterLibGLJSheetData();
-            gljOprObj.showLibGLJSheetData();
+        const val = $("input[name='glj']:checked").val();
+        if (val === 'stdGLJ') {
+            gljOprObj.initClassTree('std', gljOprObj.treeData.std, true);
         } else {
-            if(val === 'stdGLJ') {
-                gljOprObj.initClassTree('std', gljOprObj.treeData.std, true);
-            } else {
-                gljOprObj.initClassTree('comple', gljOprObj.treeData.comple, true);
-            }
-            gljOprObj.initSelection({row: 0});
-            //gljOprObj.gljLibSheetData = gljOprObj[val];
-            /*gljOprObj.filterLibGLJSheetData();
-            gljOprObj.showLibGLJSheetData();*/
-        }
-    });
-/*    //工料机搜索
-    $('#gljSearchKeyword').change(function () {
-        gljOprObj.filterLibGLJSheetData();
-        gljOprObj.showLibGLJSheetData();
-    });
-     $('#gljSearchKeyword').bind('keypress', function (e) {
-        if(e.keyCode === 13){
-            alert('2');
-            $(this).blur();
-            return false;
+            gljOprObj.initClassTree('comple', gljOprObj.treeData.comple, true);
         }
-    });*/
-    $('#gljSearchKeyword').bind('keyup', function (e) {
-        gljOprObj.filterLibGLJSheetData();
-        gljOprObj.showLibGLJSheetData();
         gljOprObj.initSelection({row: 0});
     });
+    // 人材机选择页面搜索框
+    $('#gljSearchKeyword').bind('keyup', _.debounce(function() {
+        gljOprObj.loadPageData(gljOprObj.gljLibSheet, true, 0);
+    }, 500));
 
     $('#glj_selected_conf').click(function () {
         if (gljOprObj.GLJSelection.length < 1) {

+ 15 - 16
web/building_saas/main/js/views/glj_view_contextMenu.js

@@ -375,36 +375,35 @@ var gljContextMenu = {
 
 function getGLJData(actionType) {
     $('#actionType').val(actionType);
+    // 清除选中人材机缓存数据
+    gljOprObj.GLJSelection = [];
     $.bootstrapLoading.start();
-    projectObj.project.ration_glj.getGLJData(function (result) {
-        console.log(+new Date());
-        gljOprObj.treeData =  result.datas.treeData;
-        //zTreeHelper.createTree(result.datas.treeData, gljOprObj.gljTreeSetting, "gljTree", gljOprObj);
+    let location = false;
+    const replaceActions = ['replace', 'm_replace'];
+    if (replaceActions.includes(actionType)) {
+        location = true;
+    }
+    const init = true;
+    const reset = true;
+    const condition = gljOprObj.getPagingCondition(init, reset, location, 0);
+    console.time('getGLJData');
+    projectObj.project.ration_glj.getGLJDataPaging(condition, function (result) {
         gljOprObj.initClassTree('std', gljOprObj.treeData.std);
-        gljOprObj.stdGLJ=result.datas.stdGLJ;
-        gljOprObj.complementaryGLJs=result.datas.complementaryGLJs;
-        for(let compleGlj of gljOprObj.complementaryGLJs){
-            //是否新增
-            compleGlj.isComplementary = true;
-        }
-        gljOprObj.AllRecode=gljOprObj.stdGLJ.concat(gljOprObj.complementaryGLJs);
-        //gljOprObj.AllRecode=gljOprObj.stdGLJ;
-        gljOprObj.distTypeTree=gljOprObj.getComboData(result.datas.distTypeTree);
         $('#modalCon').width($(window).width()*0.5);
         $("input[name='glj']").get(0).checked=true;
         $.bootstrapLoading.end();
         if(actionType == "m_replace"){
             $('#glj_selected_conf').hide();
             $('#replace_next_btn').show();
-        }else {
+        } else {
             $('#glj_selected_conf').show();
             $('#replace_next_btn').hide();
         }
         $("#glj_tree_div").modal({show:true});
         setTimeout(function(){
-            gljOprObj.gljLibSpresd?gljOprObj.gljLibSpresd.refresh():'';
+            gljOprObj.gljLibSpresd ? gljOprObj.gljLibSpresd.refresh() : '';
         }, 200);
-    })
+    });
 }
 
 function showGLJClassTree(record) {

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

@@ -304,8 +304,11 @@ let MainTreeCol = {
             return true;
         },
         maxPrice:function (node) {
-            if($("#fileKind").val() == '1') return true;//对于投标项目只读
-            return   node.data.outPutMaxPrice!==true;
+            // 对于投标项目只读
+            if(+$('#fileKind').val() === _fileKind.tender) {
+                return true;
+            }
+            return node.data.outPutMaxPrice !== true;
         }
     },
     cellType: {
@@ -410,7 +413,13 @@ let MainTreeCol = {
             if(MainTreeCol.mainBillsEnable(node)) return sheetCommonObj.getCheckBox(true);
         },
         outPutMaxPrice:function (node) {
-            if(MainTreeCol.mainBillsEnable(node) && $("#fileKind").val() != '1') return sheetCommonObj.getCheckBox(true);
+            if(MainTreeCol.mainBillsEnable(node)) {
+                // 投标项目,复选框不可改变
+                const checkBox = +$('#fileKind').val() === _fileKind.tender
+                    ? sheetCommonObj.getReadOnlyCheckBox()
+                    : sheetCommonObj.getCheckBox(true);
+                return checkBox;
+            }
         }
     },
     mainBillsEnable:function (node) {

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

@@ -29,7 +29,10 @@
                             <div class="btn-group" role="group" aria-label="Button group with nested dropdown" id="export_div">
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.checkAndGetExcel()"><i class="fa fa-file-excel-o"></i> Excel <span class="badge badge-secondary">0</span></button>
                                 <button type="button" class="btn btn-outline-primary btn-sm" id="show_excel_output_cfg" data-toggle="modal" data-target="#export_excel" style="display:none"></button>
+                                <!--
                                 <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.getPDF()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-secondary">0</span></button>
+                                -->
+                                <button type="button" class="btn btn-outline-primary btn-sm" onclick="rptControlObj.getPDFEx()"><i class="fa fa-file-pdf-o"></i> PDF <span class="badge badge-secondary">0</span></button>
                             </div>
                         </div>
                         <div class="panel-foot text-muted">
@@ -79,6 +82,9 @@
                                 <span class="input-group-btn">
                                     <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="下一页" onclick="rptControlObj.nextPage(this)"><i class="fa fa-angle-right"></i></button>
                                     <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="尾页" onclick="rptControlObj.lastPage(this)"><i class="fa fa-angle-double-right"></i></button>
+                                    <!--
+                                    <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="tooltip" data-placement="bottom" title="测试jspdf" onclick="JpcJsPDFHelper.testFont()"><i class="fa fa-angle-double-right"></i></button>
+                                    -->
                                 </span>
                             </div>
                         </div>

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

@@ -53,6 +53,10 @@ let JV = {
     FONT_PROP_IDX_STRIKEOUT: 6,
     FONT_PROP_IDX_ANGLE: 7,
 
+    PAGES_SIZE_STR: ["A3", "A4", "A5", "B5", "LETTER", "LEGAL", "EXECUTIVE", "16K"],
+    PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],
+    PAGES_SIZE: [[11.69, 16.54], [8.27, 11.69], [5.83, 8.27], [6.93, 9.84], [8.5, 11.0], [8.5, 14.0], [7.25, 10.5], [7.25, 10.5]],
+
     OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,

+ 441 - 0
web/building_saas/report/js/rpt_jspdf.js

@@ -0,0 +1,441 @@
+/**
+ * Created by Tony on 2019/9/10.
+ */
+
+const PDF_SCALE = 0.75;
+const DPI = getScreenDPI();
+
+let JpcJsPDFHelper = {
+    doc: null,
+    initialize: function (orientation, unit, format) {
+        let me = this;
+        me.doc = new jsPDF(orientation, unit, format);
+        return me.doc;
+    },
+    testFont: function () {
+        let me = this;
+        let doc = me.initialize('p', 'pt', 'a4');
+        console.log(me.doc.getFontList());
+        // console.log(me.doc.getFont());
+        // doc.setFont("SmartSimsun", "bold");
+        // doc.setFontSize(16);
+        // doc.text(20, 20, '小写字母总长度:' + doc.getTextWidth('abcdefghijklmnopqrstuvwxyz'));
+        //
+        // doc.setFont("SmartSimsun", "normal");
+        // doc.setFontSize(16);
+        // doc.text(20, 40, '大写字母总长度:' + doc.getTextWidth('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));
+        //
+        // doc.line(20, 20, 60, 20); // horizontal line
+        // doc.line(20, 40, 60, 40); // horizontal line
+        //
+        // doc.save('Test.pdf');
+    },
+    outputAsPdf: function (pageData, paperSize, pdfName) {
+        let me = this;
+        let offsetX= 10;
+        let offsetY=10;
+        let newName = pdfName;
+        let pageObj = pageData;
+        let paperSizeIdx = JV.PAGES_SIZE_STR.indexOf(paperSize);
+        let size = JV.PAGES_SIZE[paperSizeIdx];
+        let orientation = '';
+        if (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][0] > pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1]) {
+            orientation = 'landscape';
+        } else {
+            orientation = 'portrait';
+        }
+        let doc = me.initialize(orientation, 'pt', paperSize.toLowerCase());
+        doc.setFont("SmartSimsun", "normal"); //目前只考虑宋体
+
+        function private_getIniPageMergeBorder(mergedBand) {
+            let rst = {};
+            rst[JV.PROP_LEFT] = mergedBand[JV.PROP_LEFT];
+            rst[JV.PROP_RIGHT] = mergedBand[JV.PROP_RIGHT];
+            rst[JV.PROP_TOP] = mergedBand[JV.PROP_TOP];
+            rst[JV.PROP_BOTTOM] = mergedBand[JV.PROP_BOTTOM];
+            rst[JV.PROP_STYLE] = mergedBand[JV.PROP_STYLE];
+            return rst;
+        }
+
+        let newPageMergeBand = private_getIniPageMergeBorder(pageObj[JV.BAND_PROP_MERGE_BAND]);
+        if (pageObj && pageObj.items.length > 0 ) {
+            for(let i = 0; i < pageObj.items.length; i++) {
+                if (i > 0) {
+                    doc.addPage(paperSize.toLowerCase(), orientation);
+                }
+                let ctx = doc.canvas.getContext();
+                let page = pageObj.items[i],
+                    fonts = pageObj[JV.NODE_FONT_COLLECTION],
+                    styles = pageObj[JV.NODE_STYLE_COLLECTION],
+                    controls = pageObj[JV.NODE_CONTROL_COLLECTION];
+
+                if (page[JV.PROP_PAGE_MERGE_BORDER]) {
+                    newPageMergeBand[JV.PROP_LEFT] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_LEFT];
+                    newPageMergeBand[JV.PROP_RIGHT] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_RIGHT];
+                    newPageMergeBand[JV.PROP_TOP] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_TOP];
+                    newPageMergeBand[JV.PROP_BOTTOM] = page[JV.PROP_PAGE_MERGE_BORDER][JV.PROP_BOTTOM];
+                }
+                for (let j = 0; j < page.cells.length; j++) {
+                    let cell = page.cells[j];
+                    private_drawCell(doc, ctx, cell, fonts, styles, controls, newPageMergeBand);
+                }
+            }
+        }
+        doc.save(newName + '.pdf');
+
+        function private_chkIfInMergedBand(mergedBand, cell) {
+            let rst = false;
+            if (mergedBand && cell) {
+                rst = mergedBand[JV.PROP_TOP] <= cell[JV.PROP_AREA][JV.PROP_TOP] && mergedBand[JV.PROP_BOTTOM] >= cell[JV.PROP_AREA][JV.PROP_BOTTOM] &&
+                    mergedBand[JV.PROP_LEFT] <= cell[JV.PROP_AREA][JV.PROP_LEFT] && mergedBand[JV.PROP_RIGHT] >= cell[JV.PROP_AREA][JV.PROP_RIGHT];
+            }
+            return rst;
+        }
+
+        function private_drawCell(doc, ctx, cell, fonts, styles, controls, mergedBand) {
+            ctx.beginPath();
+            let style = styles[cell[JV.PROP_STYLE]];
+            if (style) {
+                let isNeedMergeBand = private_chkIfInMergedBand(mergedBand, cell);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_TOP, [JV.PROP_LEFT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_RIGHT, [JV.PROP_RIGHT, JV.PROP_TOP],[JV.PROP_RIGHT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_BOTTOM, [JV.PROP_RIGHT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_BOTTOM], mergedBand, styles, isNeedMergeBand);
+                private_drawLine(cell, doc, ctx, style, JV.PROP_LEFT, [JV.PROP_LEFT, JV.PROP_BOTTOM],[JV.PROP_LEFT, JV.PROP_TOP], mergedBand, styles, isNeedMergeBand);
+            }
+            private_drawCellText(doc, ctx, cell, fonts, controls);
+            ctx.closePath();
+
+        }
+
+        function private_drawLine(cell, doc, ctx, style, styleBorderDest, startP, destP, mergedBand, styles, isNeedMergeBand) {
+            let destStyle = style;
+            if (mergedBand) {
+                if (isNeedMergeBand && parseFloat(mergedBand[styleBorderDest]) === parseFloat(cell[JV.PROP_AREA][styleBorderDest])) {
+                    destStyle = styles[mergedBand[JV.PROP_STYLE][JV.PROP_ID]];
+                }
+            }
+            if (destStyle[styleBorderDest] && parseFloat(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) !== 0) {
+                doc.setDrawColor(destStyle[styleBorderDest][JV.PROP_COLOR]);
+                if (parseInt(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) === 2) {
+                    doc.setLineWidth(1 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]);
+                } else {
+                    doc.setLineWidth(0.1);
+                }
+                doc.line((cell[JV.PROP_AREA][startP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][startP[1]] + offsetY) * PDF_SCALE,
+                    (cell[JV.PROP_AREA][destP[0]] + offsetX) * PDF_SCALE, (cell[JV.PROP_AREA][destP[1]] + offsetY) * PDF_SCALE);
+            }
+        }
+
+        function private_drawCellText(doc, ctx, cell, fonts, controls) {
+            if (cell[JV.PROP_VALUE]) {
+                let values = ("" + cell[JV.PROP_VALUE]).split('|');
+                // let font = fonts[cell[JV.PROP_FONT]];
+                let font = null;
+                if (typeof cell[JV.PROP_FONT] === "string") {
+                    font = fonts[cell[JV.PROP_FONT]];
+                } else {
+                    font = cell[JV.PROP_FONT];
+                }
+                if (font[JV.FONT_PROPS[JV.FONT_PROP_IDX_BOLD]] === 'T') {
+                    doc.setFont("SmartSimsun", "bold");
+                    // doc.setFontStyle("bold");
+                } else {
+                    doc.setFont("SmartSimsun", "normal");
+                }
+                // let control = controls[cell[JV.PROP_CONTROL]];
+                let control = null;
+                if (typeof cell[JV.PROP_CONTROL] === "string") {
+                    control = controls[cell[JV.PROP_CONTROL]];
+                } else {
+                    control = cell[JV.PROP_CONTROL];
+                }
+                let height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
+                let area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + offsetY];
+                let ah = height;
+                let restTopH = 0, restBottomH = 0;
+                if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_CLOSE_OUTPUT]] === 'T') {
+                    ah = (parseFloat(font[JV.FONT_PROPS[1]]) + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]) * values.length;
+                    let restH = height - ah;
+                    if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'center') {
+                        restTopH = restH / 2;
+                        restBottomH = restH / 2;
+                    } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'bottom') {
+                        restBottomH = restH;
+                    } else {
+                        restTopH = restH;
+                    }
+                }
+                let spaceIdxArr = [];
+                for (let i = 0; i < values.length; i++) {
+                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + offsetY + restTopH;
+                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restBottomH;
+                    if (values[i] === null || values[i] === undefined || values[i] === 'null') {
+                        values[i] = "";
+                    }
+                    // 因pdfkit输出空格只有浏览器的一半宽度,需要额外加空格补上,jspdf也有这个情况 -----------------------------
+                    if (typeof(values[i]) === "string") {
+                        for (let j = 0; j < values[i].length; j++) {
+                            if (values[i][j] === ' ') spaceIdxArr.push(j);
+                        }
+                    }
+                    for (let j = spaceIdxArr.length - 1; j >= 0; j--) {
+                        values[i] = values[i].slice(0, spaceIdxArr[j]) + ' ' + values[i].slice(spaceIdxArr[j]);
+                    }
+                    // -----------------------------
+                    private_drawText(doc, ctx, values[i], area, font, control);
+                    spaceIdxArr = [];
+                }
+            }
+        }
+
+        function private_drawText(doc, ctx, val, area, font, control) {
+            let dftFontHeight = 12;
+            let output = [];
+            if (font) {
+                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                doc.setFontSize(dftFontHeight);
+            }
+            // doc.font(fontFile);
+            let options={};
+            let inner_setupControl = function (outVal, inArea, inFontHeight, inOutput) {
+                if (control) {
+                    private_setupAreaH(outVal, inArea, control.Horizon, font.FontAngle, inFontHeight, inOutput, options);
+                    private_setupAreaV(outVal, inArea, control.Vertical, font.FontAngle, inFontHeight, inOutput);
+                } else {
+                    private_setupAreaH(outVal, inArea, "left", parseInt(font.FontAngle), inFontHeight, inOutput, options);
+                    private_setupAreaV(outVal, inArea, "bottom", parseInt(font.FontAngle), inFontHeight, inOutput);
+                }
+            };
+            inner_setupControl(val, area, dftFontHeight, output);
+            let validAreaTxtWidth = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+            let validTxtLines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
+            if (parseInt(font.FontAngle) !== 0) {
+                validAreaTxtWidth = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                validTxtLines = Math.floor((area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] + 4));
+            }
+
+            function private_drawUnderline(underLineVal, underLineArea) {
+                //A. 暂不支持角度; B. PDF输出时,坐标没有translate
+                // let ctx = doc;
+                //1. 计算下划线的相关坐标
+                let width = doc.getTextWidth(underLineVal);
+                if (width > underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT]) {
+                    width = underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT];
+                }
+                let height = dftFontHeight;
+                let startX = underLineArea[JV.IDX_LEFT], startY = underLineArea[JV.IDX_TOP], endX = underLineArea[JV.IDX_RIGHT], endY = underLineArea[JV.IDX_BOTTOM];
+                // let startX = 0, startY = 0, endX = width, endY = startY;
+                if (control.Horizon === "left") {
+                    startX = Math.round(underLineArea[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
+                } else if (control.Horizon === "right") {
+                    startX = Math.round(underLineArea[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
+                } else {
+                    startX = Math.round( underLineArea[JV.IDX_LEFT] + (underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT] - width) / 2);
+                }
+                endX = Math.round(startX + width);
+
+                if (control.Vertical === "top") {
+                    startY = Math.round(underLineArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height);
+                } else if (control.Vertical === "bottom") {
+                    startY = Math.round(underLineArea[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
+                } else {
+                    startY = Math.round( underLineArea[JV.IDX_TOP] + (underLineArea[JV.IDX_BOTTOM] - underLineArea[JV.IDX_TOP] + height) / 2) + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                }
+                endY = Math.round(startY);
+                //2. 画线
+                // ctx.save();
+                if ( output[1] !== Math.round(output[1])) {
+                    ctx.translate(0,0.5);
+                }
+
+                doc.setDrawColor("BLACK");
+                doc.setLineWidth(0.1);
+                doc.line(startX * PDF_SCALE, startY * PDF_SCALE, endX * PDF_SCALE, endY * PDF_SCALE);
+            }
+
+            let rotateOptions;
+            if (parseInt(font.FontAngle) !== 0) {
+                if (control){
+                    rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,control.Vertical,dftFontHeight, output);
+                } else {
+                    rotateOptions = private_setupAreaRotateOption(area,validAreaTxtWidth,"bottom",dftFontHeight, output);
+                }
+                doc.rotate(font.FontAngle,rotateOptions);
+            }
+            if (validAreaTxtWidth >= doc.getTextWidth(val) ||
+                (control && control.Shrink !== 'T' && validTxtLines < private_splitString(val, validAreaTxtWidth, doc)) ) {
+                options.width = validAreaTxtWidth * PDF_SCALE;
+                options.height = dftFontHeight * PDF_SCALE;
+                doc.setFontSize(dftFontHeight);
+                if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                    private_drawUnderline(val, area);
+                }
+                doc.setFontSize(dftFontHeight * PDF_SCALE);
+                doc.text(output[0] * PDF_SCALE, output[1] * PDF_SCALE, val);
+            } else {
+                while (true) {
+                    let lines = Math.floor((area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4));
+                    lines = (lines === 0 || (control.Shrink === 'T' && control.ShrinkFirst === 'T'))?1:lines;
+                    let actLines = private_splitString(val, validAreaTxtWidth, doc);
+                    if (actLines.length > lines && dftFontHeight >= 6) {
+                        dftFontHeight--;
+                        doc.setFontSize(dftFontHeight);
+                        options.width = validAreaTxtWidth * PDF_SCALE;
+                        options.height = dftFontHeight * PDF_SCALE;
+                    } else {
+                        let aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4;
+                        if ((aH * actLines.length) < (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) && (control && control.Vertical !== 'top')) {
+                            if (control.Vertical === 'bottom') {
+                                area[JV.IDX_TOP] = area[JV.IDX_BOTTOM] - (aH * actLines.length);
+                            } else {
+                                area[JV.IDX_TOP] = (area[JV.IDX_TOP] + area[JV.IDX_BOTTOM]) / 2 - (aH * actLines.length) / 2
+                                area[JV.IDX_BOTTOM] = area[JV.IDX_TOP] + (aH * actLines.length);
+                            }
+                        }
+                        let newArea = [], baseTop = area[JV.IDX_TOP];
+                        for (let ai = 0; ai < area.length; ai++) {
+                            newArea[ai] = area[ai];
+                        }
+                        options.width = validAreaTxtWidth * PDF_SCALE;
+                        options.height = dftFontHeight * PDF_SCALE;
+                        for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
+                            newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
+                            newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
+                            doc.setFontSize(dftFontHeight);
+                            inner_setupControl(actLines[lIdx], newArea, dftFontHeight, output);
+                            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                                private_drawUnderline(actLines[lIdx], newArea);
+                            }
+                            doc.setFontSize(dftFontHeight * PDF_SCALE);
+                            doc.text(output[0] * PDF_SCALE, output[1] * PDF_SCALE, actLines[lIdx]);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        function private_setupAreaH(outVal, area, type, fontAngle, dftFontHeight, outputPoint,options) {
+            //jspdf输出方式不同(但与H5的canvas处理方式有所不同,因为没有相关alignment属性,需要自己算,而且角度还暂时不支持)-------------------------------------------
+            let lType = type;
+            if (type !== "left" && type !== "right" && type !== "center") lType = "left";
+            switch (lType) {
+                case "left":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        // outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        // outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    } else {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                    }
+                    //ctx.textAlign="start";
+                    break;
+                case "right":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+                    } else {
+                        let width = doc.getTextWidth(outVal);
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - width;
+                    }
+                    //ctx.textAlign="end";
+                    break;
+                case "center":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT || fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
+                    } else {
+                        let width = doc.getTextWidth(outVal);
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2 - (width / 2);
+                    }
+                    //ctx.textAlign="center";
+                    break;
+            }
+        }
+
+        function private_setupAreaV(outVal, area, type, fontAngle, dftFontHeight, outputPoint) {
+            //jspdf输出方式不同(与H5的canvas一样处理)-------------------------------------------
+            let lType = type;
+            if (type !== "top" && type !== "bottom" && type !== "center") lType = "top";
+            switch (lType) {
+                case "top":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                    } else {
+                        outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
+                        // if (fontName === "宋体") outputPoint[1] = outputPoint[1] - 1;
+                        outputPoint[1] = outputPoint[1] - 1; // 宋体需要提上一个像素点
+                    }
+                    break;
+                case "center":
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
+                        outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
+                    } else {
+                        outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
+                        // if (fontName === "宋体") outputPoint[1] = outputPoint[1] - 1;
+                        outputPoint[1] = outputPoint[1] - 1; // 宋体需要提上一个像素点
+                    }
+                    break;
+            }
+        }
+
+        function private_splitString(strVal, areaWidth, doc) {
+            let rst = [];
+            if (strVal) {
+                let preSIdx = 0, txtWidth = 0;
+                let currentW = 0;
+                let chnW = doc.getTextWidth('一'), otherW = doc.getTextWidth('_');
+                for (let sIdx = 0; sIdx < strVal.length; sIdx++) {
+                    currentW = (strVal.charCodeAt(sIdx) > 127)?chnW:otherW;
+                    txtWidth += currentW;
+                    if (txtWidth > areaWidth) {
+                        if (preSIdx < sIdx) {
+                            rst.push(strVal.substr(preSIdx, sIdx - preSIdx));
+                            preSIdx = sIdx;
+                        } else {
+                            rst.push(strVal.substr(preSIdx, 1));
+                            preSIdx = sIdx + 1;
+                        }
+                        txtWidth = currentW;
+                    }
+                    if (sIdx === strVal.length - 1) {
+                        rst.push(strVal.substr(preSIdx, strVal.length - preSIdx));
+                    }
+                }
+            }
+            if (rst.length === 0) rst.push(''); //什么都没有,也得整个空串
+            return rst;
+        }
+
+        function private_setupAreaRotateOption(area,w, type="top",dftFontHeight,outputPoint){
+            let x = (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT])/2+area[JV.IDX_LEFT];
+            let y =(area[JV.IDX_BOTTOM] - area[JV.IDX_TOP])/2+ area[JV.IDX_TOP];
+            let rotateOptions = {origin:[x,y]};
+            let h = area[JV.IDX_RIGHT] - area[JV.IDX_LEFT];
+            outputPoint[0]=x-w/2+JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+            switch (type) {
+                case "top":
+                    outputPoint[1] = y- h/2+ JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+                    break;
+                case "bottom":
+                    outputPoint[1] = y+ h/2-JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]-dftFontHeight;
+                    break;
+                case "center":
+                    outputPoint[1] = y+dftFontHeight/2;
+                    break;
+            }
+            return rotateOptions;
+        }
+    }
+}

+ 77 - 1
web/building_saas/report/js/rpt_main.js

@@ -21,7 +21,24 @@ let rptTplObj = {
             let canvas = document.getElementById("rptCanvas");
             canvas.onclick = canvasOprObj.canvasOnClick;
             canvas.onmousemove = canvasOprObj.canvasOnMouseMove;
+            if (JpcJsPDFHelper.doc === null) {
+                JpcJsPDFHelper.initialize('p', 'pt', 'a4');
+            }
+            dynamicLoadJs('/lib/jspdf/SmartSimsun-normal.js');
+            dynamicLoadJs('/lib/jspdf/SmartSimsun-bold.js', me.pdfFontSimsunCallBack);
         }
+    },
+    pdfFontSimsunCallBack: function() {
+        rptTplObj.pdfFont['SmartSimsun'].push('normal');
+        rptTplObj.pdfFont['SmartSimsun'].push('bold');
+    },
+    pdfFontSimkaiCallBack: function() {
+        rptTplObj.pdfFont['simkai'].push('normal');
+        rptTplObj.pdfFont['simkai'].push('bold');
+    },
+    pdfFontSimheiCallBack: function() {
+        rptTplObj.pdfFont['simhei'].push('normal');
+        rptTplObj.pdfFont['simhei'].push('bold');
     }
 }
 
@@ -467,7 +484,7 @@ let rptControlObj = {
             let rpt_ids = [], rpt_names = [];
             for (let tplNode of zTreeOprObj.checkedRptTplNodes) {
                 rpt_ids.push(tplNode.refId);
-                rpt_names.push(tplNode.name)
+                rpt_names.push(tplNode.name);
             }
             let params = {};
             params.prj_id = projectObj.project.projectInfo.ID;
@@ -492,6 +509,40 @@ let rptControlObj = {
             );
         }
     },
+    getPDFEx: function () {
+        if (zTreeOprObj.checkedRptTplNodes && zTreeOprObj.checkedRptTplNodes.length > 0) {
+            let rptIds = [], rpt_names = [];
+            let params = {};
+            params.pageSize = rptControlObj.getCurrentPageSize();
+            params.orientation = ((zTreeOprObj.checkedRptTplNodes.length > 1)?null:rptControlObj.getCurrentOrientation());
+            params.custCfg = zTreeOprObj.reportPageCfg;
+            params.prj_id = projectObj.project.projectInfo.ID;
+            for (let tplNode of zTreeOprObj.checkedRptTplNodes) {
+                rptIds.push(tplNode.refId);
+                rpt_names.push(tplNode.name);
+            }
+            params.rpt_ids = rptIds.join(",");
+            CommonAjax.postEx("report_api/getMultiReports", params, 30000, true,
+                function(result){
+                    let pageSize = rptControlObj.getCurrentPageSize();
+                    for (let idx = 0; idx < result.length; idx++) {
+                        let pageData = result[idx];
+                        JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rpt_names[idx]);
+                    }
+                },
+                function(failRst){
+                    sessionStorage.currentPageData = null;
+                    console.log(failRst);
+                },
+                function(exceptionRst){
+                    sessionStorage.currentPageData = null;
+                    console.log(exceptionRst);
+                }
+            );
+        } else {
+            //不可能的branch
+        }
+    },
     firstPage: function(dom) {
         let canvas = document.getElementById("rptCanvas");
         zTreeOprObj.showPage(1, canvas);
@@ -614,3 +665,28 @@ function downloadReport(urls) {
     }
     private_download();
 }
+
+function dynamicLoadJs(url, callback) {
+    let head = document.getElementsByTagName('head')[0];
+    let script = document.createElement('script');
+    script.type = 'text/javascript';
+    script.src = url;
+    if(callback) {
+        script.onload = script.onreadystatechange = function () {
+            if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete"){
+                callback();
+                script.onload = script.onreadystatechange = null;
+            }
+        };
+    }
+    head.appendChild(script);
+}
+
+function dynamicLoadCss(url) {
+    let head = document.getElementsByTagName('head')[0];
+    let link = document.createElement('link');
+    link.type='text/css';
+    link.rel = 'stylesheet';
+    link.href = url;
+    head.appendChild(link);
+}